openocd-0.7.0/0000755000175000001440000000000012141414414010136 500000000000000openocd-0.7.0/HACKING0000644000175000001440000001534112137151330011051 00000000000000// This file is part of the Doxygen Developer Manual /** @page patchguide Patch Guidelines \attention If you're behind a corporate wall with http only access to the world, you can still use these instructions! \attention You can't send patches to the mailing list anymore at all. Nowadays you are expected to send patches to the OpenOCD Gerrit GIT server for a review. @section gerrit Submitting patches to the OpenOCD Gerrit server OpenOCD is to some extent a "self service" open source project, so to contribute, you must follow the standard procedures to have the best possible chance to get your changes accepted. The procedure to create a patch is essentially: - make the changes - create a commit - send the changes to the Gerrit server for review - correct the patch and re-send it according to review feedback Your patch (or commit) should be a "good patch": focus it on a single issue, and make it be easily reviewable. Don't make it so large that it's hard to review; split large patches into smaller ones. (That can also help track down bugs later on.) All patches should be "clean", which includes preserving the existing coding style and updating documentation as needed. Say in the commit message if it's a bugfix (describe the bug) or a new feature. Don't expect patches to merge immediately for the next release. Be ready to rework patches in response to feedback. Add yourself to the GPL copyright for non-trivial changes. @section stepbystep Step by step procedure -# Create a Gerrit account at: http://openocd.zylin.com - On subsequent sign ins, use the full URL prefaced with 'http://' For example: http://user_identifier.open_id_provider.com -# Add a username to your profile. After creating the Gerrit account and signing in, you will need to add a username to your profile. To do this, go to 'Settings', and add a username of your choice. Your username will be required in step 3 and substituted wherever the string 'USERNAME' is found. -# Create an SSH public key following the directions on github: https://help.github.com/articles/generating-ssh-keys . You can skip step 3 (adding key to Github account) and 4 (testing) - these are useful only if you actually use Github or want to test whether the new key works fine. -# Add this new SSH key to your Gerrit account: go to 'Settings' > 'SSH Public Keys', paste the contents of ~/.ssh/id_rsa.pub into the text field (if it's not visible click on 'Add Key ...' button) and confirm by clicking 'Add' button. -# Clone the git repository, rather than just download the source: @code git clone git://git.code.sf.net/p/openocd/code openocd @endcode or if you have problems with the "git:" protocol, use the slower http protocol: @code git clone http://git.code.sf.net/p/openocd/code openocd @endcode -# Set up Gerrit with your local repository. All this does it to instruct git locally how to send off the changes. -# Add a new remote to git using Gerrit username: @code git remote add review ssh://USERNAME@openocd.zylin.com:29418/openocd.git git config remote.review.push HEAD:refs/publish/master @endcode Or with http only: @code git remote add review http://USERNAME@openocd.zylin.com/p/openocd.git git config remote.review.push HEAD:refs/publish/master @endcode The http password is configured from your gerrit settings - http://openocd.zylin.com/#/settings/http-password. \note If you want to simplify http access you can also add your http password to the url as follows: @code git remote add review http://USERNAME:PASSWORD@openocd.zylin.com/p/openocd.git @endcode -# You will need to install this hook, we will look into a better solution: @code scp -p -P 29418 USERNAME@openocd.zylin.com:hooks/commit-msg .git/hooks/ @endcode Or with http only: @code wget http://openocd.zylin.com/tools/hooks/commit-msg mv commit-msg .git/hooks chmod +x .git/hooks/commit-msg @endcode \note A script exists to simplify the two items above. execute: @code tools/initial.sh @endcode With @ being your Gerrit username. -# Set up git with your name and email: @code git config --global user.name "John Smith" git config --global user.email "john@smith.org" @endcode -# Work on your patches. Split the work into multiple small patches that can be reviewed and applied seperately and safely to the OpenOCD repository. @code while(!done) { work - edit files using your favorite editor. run "git commit -s -a" to commit all changes. run tools/checkpatch.sh to verify your patch style is ok. } @endcode \note use "git add ." before commit to add new files. Comment template, notice the short first line w/topic. The topic field should identify the main part or subsystem the patch touches. Check git log for examples. @code topic: Short comment Longer comments over several lines, explaining (where applicable) the reason for the patch and the general idea the solution is based on, any major design decisions, etc... Signed-off-by: ... @endcode -# Next you need to make sure that your patches are on top of the latest stuff on the server and that there are no conflicts: @code git pull --rebase origin master @endcode -# Send the patches to the Gerrit server for review: @code git push review @endcode -# Forgot something, want to add more? Just make the changes and do: @code git commit --amend git push review @endcode Further reading: http://www.coreboot.org/Git @section timeline When can I expect my contribution to be committed? The code review is intended to take as long as a week or two to allow maintainers and contributors who work on OpenOCD only in their spare time oportunity to perform a review and raise objections. With Gerrit much of the urgency of getting things committed has been removed as the work in progress is safely stored in Gerrit and available if someone needs to build on your work before it is submitted to the official repository. Another factor that contributes to the desire for longer cool-off times (the time a patch lies around without any further changes or comments), it means that the chances of quality regression on the master branch will be much reduced. If a contributor pushes a patch, it is considered good form if another contributor actually approves and submits that patch. It should be noted that a negative review in Gerrit ("-1" or "-2") may (but does not have to) be disregarded if all conditions listed below are met: - the concerns raised in the review have been addressed (or explained), - reviewer does not re-examine the change in a month, - reviewer does not answer e-mails for another month. @section browsing Browsing Patches All OpenOCD patches can be reviewed here. */ /** @file This file contains the @ref patchguide page. */ openocd-0.7.0/README.Win320000644000175000001440000000647112134336410011650 00000000000000Building OpenOCD for Windows ---------------------------- For building on Windows, you have to use CygWin. Make sure that your PATH environment variable contains no other locations with Unix utilities (like UnxUtils). Those tools can't handle the CygWin paths, resulting in obscure dependency errors. This was an observation gathered from the logs of one user; please correct us if this is wrong. The following URL is a good reference if you want to build OpenOCD under CygWin: http://forum.sparkfun.com/viewtopic.php?t=11221 Alternatively you can build the Windows binary under Linux using MinGW cross compiler. The following documents some tips of using this cross build option. libusb-win32 ------------ You can choose to use the libusb-win32 binary distribution from its SourceForge page. As of this writing, the latest version is 0.1.12.2. This is the recommend version to use since it fixed an issue with USB composite device and this is important for FTDI based JTAG debuggers. http://sourceforge.net/projects/libusb-win32/ You need to download the libusb-win32-device-bin-0.1.12.2.tar.gz package. Extract this file into a temp directory. Copy the file libusb-win32-device-bin-0.1.12.2\include\usb.h to your MinGW include directory. Copy the library libusb-win32-device-bin-0.1.12.2\lib\gcc\libusb.a to your MinGW library directory. Take note that different Linux distributions often have different MinGW installation directory. Some of them also put the library and include into a separate sys-root directory. When the libusb-win32 repository is more current than its release code, you could build that instead. These are the instruction from the libusb-win32 Makefile: # If you're cross-compiling and your mingw32 tools are called # i586-mingw32msvc-gcc and so on, then you can compile libusb-win32 # by running # make host_prefix=i586-mingw32msvc all libftdi ------- The author does not provide Windows binary. You can build it from a released source tarball or the git tree. If you are using the git tree, the following are the instructions from README.mingw. You will need to have the cmake utility installed. - Edit Toolchain-mingw32.cmake to point to the correct MinGW installation. - Create a build directory like "mkdir build-win32", e.g in ../libftdi/ - cd into that directory and run "cmake -DCMAKE_TOOLCHAIN_FILE=../Toolchain-mingw32.cmake .." - Copy src/ftdi.h to your MinGW include directory. - Copy build-win32/src/*.a to your MinGW lib directory. libftd2xx --------- The Cygwin/Win32 ZIP file contains a directory named ftd2xx.win32. After being extracted, the directory does not need further preparation. Instead, its path must be provided to the --with-ftd2xx-win32-zipdir configure option, as shown in the next section. OpenOCD ------- Now you can build OpenOCD under Linux using MinGW. You need to use --build and --host configure options. To use libftdi: ./configure --build=i686-pc-linux-gnu --host=i586-mingw32msvc \ --enable-ft2232_libftdi \ ... other options ... To use ftd2xx: ./configure --build=i686-pc-linux-gnu --host=i586-mingw32msvc \ --enable-ft2232_ftd2xx \ --with-ftd2xx-win32-zipdir=/path/to/libftd2xx-win32 \ ... other options ... If you are using the GIT repository, see the README file for additional instructions about configuring and building OpenOCD. openocd-0.7.0/common.mk0000644000175000001440000000046212134336410011702 00000000000000 # common flags used in openocd build AM_CPPFLAGS = -I$(top_srcdir)/src \ -I$(top_builddir)/src \ -I$(top_srcdir)/src/helper \ -DPKGDATADIR=\"$(pkgdatadir)\" \ -DPKGLIBDIR=\"$(pkglibdir)\" if INTERNAL_JIMTCL AM_CPPFLAGS += -I$(top_srcdir)/jimtcl \ -I$(top_builddir)/jimtcl endif openocd-0.7.0/NEWS0000644000175000001440000000234712137151330010563 00000000000000This file includes highlights of the changes made in the OpenOCD source archive release. See the repository history for details about what changed, including bugfixes and other issues not mentioned here. JTAG Layer: New TI ICDI adapter support. Support Latest OSBDM firmware. Improved MIPS EJTAG Support. Boundary Scan: Target Layer: New ARMv7R and Cortex-R4 support. Added ChibiOS/RT support. Flash Layer: New NXP LPC1850 support. New NXP LPC4300 support. New NXP SPIFI support. New Energy Micro EFM32 support. New ST STM32W support. New ST STM32f2 write protection and lock/unlock support. Ability to override STM32 flash bank size. Board, Target, and Interface Configuration Scripts: Support Freescale i.MX6 series targets. Documentation: New MIPS debugging info. Build and Release: For more details about what has changed since the last release, see the git repository history. With gitweb, you can browse that in various levels of detail. For older NEWS, see the NEWS files associated with each release (i.e. NEWS-). For more information about contributing test reports, bug fixes, or new features and device support, please read the new Developer Manual (or the BUGS and PATCHES.txt files in the source archive). openocd-0.7.0/install-sh0000755000175000001440000003325512141414275012077 00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2011-11-20.07; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # 'make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) dst_arg=$2 # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call 'install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for 'test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: openocd-0.7.0/aclocal.m40000644000175000001440000126100312141414272011723 00000000000000# generated automatically by aclocal 1.13.1 -*- Autoconf -*- # Copyright (C) 1996-2012 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, [m4_warning([this file was generated for autoconf 2.69. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) # libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. m4_define([_LT_COPYING], [dnl # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is part of GNU Libtool. # # GNU Libtool 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. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool 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 GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, or # obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ]) # serial 57 LT_INIT # LT_PREREQ(VERSION) # ------------------ # Complain and exit if this libtool version is less that VERSION. m4_defun([LT_PREREQ], [m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, [m4_default([$3], [m4_fatal([Libtool version $1 or higher is required], 63)])], [$2])]) # _LT_CHECK_BUILDDIR # ------------------ # Complain if the absolute build directory name contains unusual characters m4_defun([_LT_CHECK_BUILDDIR], [case `pwd` in *\ * | *\ *) AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; esac ]) # LT_INIT([OPTIONS]) # ------------------ AC_DEFUN([LT_INIT], [AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl AC_BEFORE([$0], [LT_LANG])dnl AC_BEFORE([$0], [LT_OUTPUT])dnl AC_BEFORE([$0], [LTDL_INIT])dnl m4_require([_LT_CHECK_BUILDDIR])dnl dnl Autoconf doesn't catch unexpanded LT_ macros by default: m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 dnl unless we require an AC_DEFUNed macro: AC_REQUIRE([LTOPTIONS_VERSION])dnl AC_REQUIRE([LTSUGAR_VERSION])dnl AC_REQUIRE([LTVERSION_VERSION])dnl AC_REQUIRE([LTOBSOLETE_VERSION])dnl m4_require([_LT_PROG_LTMAIN])dnl _LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) dnl Parse OPTIONS _LT_SET_OPTIONS([$0], [$1]) # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ltmain" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' AC_SUBST(LIBTOOL)dnl _LT_SETUP # Only expand once: m4_define([LT_INIT]) ])# LT_INIT # Old names: AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PROG_LIBTOOL], []) dnl AC_DEFUN([AM_PROG_LIBTOOL], []) # _LT_CC_BASENAME(CC) # ------------------- # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. m4_defun([_LT_CC_BASENAME], [for cc_temp in $1""; do case $cc_temp in compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` ]) # _LT_FILEUTILS_DEFAULTS # ---------------------- # It is okay to use these file commands and assume they have been set # sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'. m4_defun([_LT_FILEUTILS_DEFAULTS], [: ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} ])# _LT_FILEUTILS_DEFAULTS # _LT_SETUP # --------- m4_defun([_LT_SETUP], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl _LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl dnl _LT_DECL([], [host_alias], [0], [The host system])dnl _LT_DECL([], [host], [0])dnl _LT_DECL([], [host_os], [0])dnl dnl _LT_DECL([], [build_alias], [0], [The build system])dnl _LT_DECL([], [build], [0])dnl _LT_DECL([], [build_os], [0])dnl dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl dnl AC_REQUIRE([AC_PROG_LN_S])dnl test -z "$LN_S" && LN_S="ln -s" _LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl dnl AC_REQUIRE([LT_CMD_MAX_LEN])dnl _LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl _LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl m4_require([_LT_CMD_RELOAD])dnl m4_require([_LT_CHECK_MAGIC_METHOD])dnl m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl m4_require([_LT_CMD_OLD_ARCHIVE])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_WITH_SYSROOT])dnl _LT_CONFIG_LIBTOOL_INIT([ # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi ]) if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi _LT_CHECK_OBJDIR m4_require([_LT_TAG_COMPILER])dnl case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld="$lt_cv_prog_gnu_ld" old_CC="$CC" old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o _LT_CC_BASENAME([$compiler]) # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then _LT_PATH_MAGIC fi ;; esac # Use C for the default configuration in the libtool script LT_SUPPORTED_TAG([CC]) _LT_LANG_C_CONFIG _LT_LANG_DEFAULT_CONFIG _LT_CONFIG_COMMANDS ])# _LT_SETUP # _LT_PREPARE_SED_QUOTE_VARS # -------------------------- # Define a few sed substitution that help us do robust quoting. m4_defun([_LT_PREPARE_SED_QUOTE_VARS], [# Backslashify metacharacters that are still active within # double-quoted strings. sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\([["`\\]]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' ]) # _LT_PROG_LTMAIN # --------------- # Note that this code is called both from `configure', and `config.status' # now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, # `config.status' has no value for ac_aux_dir unless we are using Automake, # so we pass a copy along to make sure it has a sensible value anyway. m4_defun([_LT_PROG_LTMAIN], [m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl _LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) ltmain="$ac_aux_dir/ltmain.sh" ])# _LT_PROG_LTMAIN # So that we can recreate a full libtool script including additional # tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS # in macros and then make a single call at the end using the `libtool' # label. # _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) # ---------------------------------------- # Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL_INIT], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_INIT], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_INIT]) # _LT_CONFIG_LIBTOOL([COMMANDS]) # ------------------------------ # Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) # _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) # ----------------------------------------------------- m4_defun([_LT_CONFIG_SAVE_COMMANDS], [_LT_CONFIG_LIBTOOL([$1]) _LT_CONFIG_LIBTOOL_INIT([$2]) ]) # _LT_FORMAT_COMMENT([COMMENT]) # ----------------------------- # Add leading comment marks to the start of each line, and a trailing # full-stop to the whole comment if one is not present already. m4_define([_LT_FORMAT_COMMENT], [m4_ifval([$1], [ m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) )]) # _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) # ------------------------------------------------------------------- # CONFIGNAME is the name given to the value in the libtool script. # VARNAME is the (base) name used in the configure script. # VALUE may be 0, 1 or 2 for a computed quote escaped value based on # VARNAME. Any other value will be used directly. m4_define([_LT_DECL], [lt_if_append_uniq([lt_decl_varnames], [$2], [, ], [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], [m4_ifval([$1], [$1], [$2])]) lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) m4_ifval([$4], [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) lt_dict_add_subkey([lt_decl_dict], [$2], [tagged?], [m4_ifval([$5], [yes], [no])])]) ]) # _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) # -------------------------------------------------------- m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) # lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_tag_varnames], [_lt_decl_filter([tagged?], [yes], $@)]) # _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) # --------------------------------------------------------- m4_define([_lt_decl_filter], [m4_case([$#], [0], [m4_fatal([$0: too few arguments: $#])], [1], [m4_fatal([$0: too few arguments: $#: $1])], [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], [lt_dict_filter([lt_decl_dict], $@)])[]dnl ]) # lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) # -------------------------------------------------- m4_define([lt_decl_quote_varnames], [_lt_decl_filter([value], [1], $@)]) # lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_dquote_varnames], [_lt_decl_filter([value], [2], $@)]) # lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_varnames_tagged], [m4_assert([$# <= 2])dnl _$0(m4_quote(m4_default([$1], [[, ]])), m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) m4_define([_lt_decl_varnames_tagged], [m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) # lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_all_varnames], [_$0(m4_quote(m4_default([$1], [[, ]])), m4_if([$2], [], m4_quote(lt_decl_varnames), m4_quote(m4_shift($@))))[]dnl ]) m4_define([_lt_decl_all_varnames], [lt_join($@, lt_decl_varnames_tagged([$1], lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl ]) # _LT_CONFIG_STATUS_DECLARE([VARNAME]) # ------------------------------------ # Quote a variable value, and forward it to `config.status' so that its # declaration there will have the same value as in `configure'. VARNAME # must have a single quote delimited value for this to work. m4_define([_LT_CONFIG_STATUS_DECLARE], [$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`']) # _LT_CONFIG_STATUS_DECLARATIONS # ------------------------------ # We delimit libtool config variables with single quotes, so when # we write them to config.status, we have to be sure to quote all # embedded single quotes properly. In configure, this macro expands # each variable declared with _LT_DECL (and _LT_TAGDECL) into: # # ='`$ECHO "$" | $SED "$delay_single_quote_subst"`' m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], [m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAGS # ---------------- # Output comment and list of tags supported by the script m4_defun([_LT_LIBTOOL_TAGS], [_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl available_tags="_LT_TAGS"dnl ]) # _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) # ----------------------------------- # Extract the dictionary values for VARNAME (optionally with TAG) and # expand to a commented shell variable setting: # # # Some comment about what VAR is for. # visible_name=$lt_internal_name m4_define([_LT_LIBTOOL_DECLARE], [_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [description])))[]dnl m4_pushdef([_libtool_name], m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), [0], [_libtool_name=[$]$1], [1], [_libtool_name=$lt_[]$1], [2], [_libtool_name=$lt_[]$1], [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl ]) # _LT_LIBTOOL_CONFIG_VARS # ----------------------- # Produce commented declarations of non-tagged libtool config variables # suitable for insertion in the LIBTOOL CONFIG section of the `libtool' # script. Tagged libtool config variables (even for the LIBTOOL CONFIG # section) are produced by _LT_LIBTOOL_TAG_VARS. m4_defun([_LT_LIBTOOL_CONFIG_VARS], [m4_foreach([_lt_var], m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAG_VARS(TAG) # ------------------------- m4_define([_LT_LIBTOOL_TAG_VARS], [m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) # _LT_TAGVAR(VARNAME, [TAGNAME]) # ------------------------------ m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) # _LT_CONFIG_COMMANDS # ------------------- # Send accumulated output to $CONFIG_STATUS. Thanks to the lists of # variables for single and double quote escaping we saved from calls # to _LT_DECL, we can put quote escaped variables declarations # into `config.status', and then the shell code to quote escape them in # for loops in `config.status'. Finally, any additional code accumulated # from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. m4_defun([_LT_CONFIG_COMMANDS], [AC_PROVIDE_IFELSE([LT_OUTPUT], dnl If the libtool generation code has been placed in $CONFIG_LT, dnl instead of duplicating it all over again into config.status, dnl then we will have config.status run $CONFIG_LT later, so it dnl needs to know what name is stored there: [AC_CONFIG_COMMANDS([libtool], [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], dnl If the libtool generation code is destined for config.status, dnl expand the accumulated commands and init code now: [AC_CONFIG_COMMANDS([libtool], [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) ])#_LT_CONFIG_COMMANDS # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], [ # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' _LT_CONFIG_STATUS_DECLARATIONS LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$[]1 _LTECHO_EOF' } # Quote evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_quote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_dquote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done _LT_OUTPUT_LIBTOOL_INIT ]) # _LT_GENERATED_FILE_INIT(FILE, [COMMENT]) # ------------------------------------ # Generate a child script FILE with all initialization necessary to # reuse the environment learned by the parent script, and make the # file executable. If COMMENT is supplied, it is inserted after the # `#!' sequence but before initialization text begins. After this # macro, additional text can be appended to FILE to form the body of # the child script. The macro ends with non-zero status if the # file could not be fully written (such as if the disk is full). m4_ifdef([AS_INIT_GENERATED], [m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])], [m4_defun([_LT_GENERATED_FILE_INIT], [m4_require([AS_PREPARE])]dnl [m4_pushdef([AS_MESSAGE_LOG_FD])]dnl [lt_write_fail=0 cat >$1 <<_ASEOF || lt_write_fail=1 #! $SHELL # Generated by $as_me. $2 SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$1 <<\_ASEOF || lt_write_fail=1 AS_SHELL_SANITIZE _AS_PREPARE exec AS_MESSAGE_FD>&1 _ASEOF test $lt_write_fail = 0 && chmod +x $1[]dnl m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT # LT_OUTPUT # --------- # This macro allows early generation of the libtool script (before # AC_OUTPUT is called), incase it is used in configure for compilation # tests. AC_DEFUN([LT_OUTPUT], [: ${CONFIG_LT=./config.lt} AC_MSG_NOTICE([creating $CONFIG_LT]) _LT_GENERATED_FILE_INIT(["$CONFIG_LT"], [# Run this file to recreate a libtool stub with the current configuration.]) cat >>"$CONFIG_LT" <<\_LTEOF lt_cl_silent=false exec AS_MESSAGE_LOG_FD>>config.log { echo AS_BOX([Running $as_me.]) } >&AS_MESSAGE_LOG_FD lt_cl_help="\ \`$as_me' creates a local libtool stub from the current configuration, for use in further configure time tests before the real libtool is generated. Usage: $[0] [[OPTIONS]] -h, --help print this help, then exit -V, --version print version number, then exit -q, --quiet do not print progress messages -d, --debug don't remove temporary files Report bugs to ." lt_cl_version="\ m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) configured by $[0], generated by m4_PACKAGE_STRING. Copyright (C) 2011 Free Software Foundation, Inc. This config.lt script is free software; the Free Software Foundation gives unlimited permision to copy, distribute and modify it." while test $[#] != 0 do case $[1] in --version | --v* | -V ) echo "$lt_cl_version"; exit 0 ;; --help | --h* | -h ) echo "$lt_cl_help"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --quiet | --q* | --silent | --s* | -q ) lt_cl_silent=: ;; -*) AC_MSG_ERROR([unrecognized option: $[1] Try \`$[0] --help' for more information.]) ;; *) AC_MSG_ERROR([unrecognized argument: $[1] Try \`$[0] --help' for more information.]) ;; esac shift done if $lt_cl_silent; then exec AS_MESSAGE_FD>/dev/null fi _LTEOF cat >>"$CONFIG_LT" <<_LTEOF _LT_OUTPUT_LIBTOOL_COMMANDS_INIT _LTEOF cat >>"$CONFIG_LT" <<\_LTEOF AC_MSG_NOTICE([creating $ofile]) _LT_OUTPUT_LIBTOOL_COMMANDS AS_EXIT(0) _LTEOF chmod +x "$CONFIG_LT" # configure is writing to config.log, but config.lt does its own redirection, # appending to config.log, which fails on DOS, as config.log is still kept # open by configure. Here we exec the FD to /dev/null, effectively closing # config.log, so it can be properly (re)opened and appended to by config.lt. lt_cl_success=: test "$silent" = yes && lt_config_lt_args="$lt_config_lt_args --quiet" exec AS_MESSAGE_LOG_FD>/dev/null $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false exec AS_MESSAGE_LOG_FD>>config.log $lt_cl_success || AS_EXIT(1) ])# LT_OUTPUT # _LT_CONFIG(TAG) # --------------- # If TAG is the built-in tag, create an initial libtool script with a # default configuration from the untagged config vars. Otherwise add code # to config.status for appending the configuration named by TAG from the # matching tagged config vars. m4_defun([_LT_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_CONFIG_SAVE_COMMANDS([ m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl m4_if(_LT_TAG, [C], [ # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi cfgfile="${ofile}T" trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # _LT_COPYING _LT_LIBTOOL_TAGS # ### BEGIN LIBTOOL CONFIG _LT_LIBTOOL_CONFIG_VARS _LT_LIBTOOL_TAG_VARS # ### END LIBTOOL CONFIG _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac _LT_PROG_LTMAIN # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) _LT_PROG_REPLACE_SHELLFNS mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ], [cat <<_LT_EOF >> "$ofile" dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded dnl in a comment (ie after a #). # ### BEGIN LIBTOOL TAG CONFIG: $1 _LT_LIBTOOL_TAG_VARS(_LT_TAG) # ### END LIBTOOL TAG CONFIG: $1 _LT_EOF ])dnl /m4_if ], [m4_if([$1], [], [ PACKAGE='$PACKAGE' VERSION='$VERSION' TIMESTAMP='$TIMESTAMP' RM='$RM' ofile='$ofile'], []) ])dnl /_LT_CONFIG_SAVE_COMMANDS ])# _LT_CONFIG # LT_SUPPORTED_TAG(TAG) # --------------------- # Trace this macro to discover what tags are supported by the libtool # --tag option, using: # autoconf --trace 'LT_SUPPORTED_TAG:$1' AC_DEFUN([LT_SUPPORTED_TAG], []) # C support is built-in for now m4_define([_LT_LANG_C_enabled], []) m4_define([_LT_TAGS], []) # LT_LANG(LANG) # ------------- # Enable libtool support for the given language if not already enabled. AC_DEFUN([LT_LANG], [AC_BEFORE([$0], [LT_OUTPUT])dnl m4_case([$1], [C], [_LT_LANG(C)], [C++], [_LT_LANG(CXX)], [Go], [_LT_LANG(GO)], [Java], [_LT_LANG(GCJ)], [Fortran 77], [_LT_LANG(F77)], [Fortran], [_LT_LANG(FC)], [Windows Resource], [_LT_LANG(RC)], [m4_ifdef([_LT_LANG_]$1[_CONFIG], [_LT_LANG($1)], [m4_fatal([$0: unsupported language: "$1"])])])dnl ])# LT_LANG # _LT_LANG(LANGNAME) # ------------------ m4_defun([_LT_LANG], [m4_ifdef([_LT_LANG_]$1[_enabled], [], [LT_SUPPORTED_TAG([$1])dnl m4_append([_LT_TAGS], [$1 ])dnl m4_define([_LT_LANG_]$1[_enabled], [])dnl _LT_LANG_$1_CONFIG($1)])dnl ])# _LT_LANG m4_ifndef([AC_PROG_GO], [ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_GO. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # m4_defun([AC_PROG_GO], [AC_LANG_PUSH(Go)dnl AC_ARG_VAR([GOC], [Go compiler command])dnl AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl _AC_ARG_VAR_LDFLAGS()dnl AC_CHECK_TOOL(GOC, gccgo) if test -z "$GOC"; then if test -n "$ac_tool_prefix"; then AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo]) fi fi if test -z "$GOC"; then AC_CHECK_PROG(GOC, gccgo, gccgo, false) fi ])#m4_defun ])#m4_ifndef # _LT_LANG_DEFAULT_CONFIG # ----------------------- m4_defun([_LT_LANG_DEFAULT_CONFIG], [AC_PROVIDE_IFELSE([AC_PROG_CXX], [LT_LANG(CXX)], [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) AC_PROVIDE_IFELSE([AC_PROG_F77], [LT_LANG(F77)], [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) AC_PROVIDE_IFELSE([AC_PROG_FC], [LT_LANG(FC)], [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal dnl pulling things in needlessly. AC_PROVIDE_IFELSE([AC_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([LT_PROG_GCJ], [LT_LANG(GCJ)], [m4_ifdef([AC_PROG_GCJ], [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([A][M_PROG_GCJ], [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([LT_PROG_GCJ], [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) AC_PROVIDE_IFELSE([AC_PROG_GO], [LT_LANG(GO)], [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])]) AC_PROVIDE_IFELSE([LT_PROG_RC], [LT_LANG(RC)], [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) ])# _LT_LANG_DEFAULT_CONFIG # Obsolete macros: AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_CXX], []) dnl AC_DEFUN([AC_LIBTOOL_F77], []) dnl AC_DEFUN([AC_LIBTOOL_FC], []) dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) dnl AC_DEFUN([AC_LIBTOOL_RC], []) # _LT_TAG_COMPILER # ---------------- m4_defun([_LT_TAG_COMPILER], [AC_REQUIRE([AC_PROG_CC])dnl _LT_DECL([LTCC], [CC], [1], [A C compiler])dnl _LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl _LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl _LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC ])# _LT_TAG_COMPILER # _LT_COMPILER_BOILERPLATE # ------------------------ # Check for compiler boilerplate output or warnings with # the simple compiler test code. m4_defun([_LT_COMPILER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ])# _LT_COMPILER_BOILERPLATE # _LT_LINKER_BOILERPLATE # ---------------------- # Check for linker boilerplate output or warnings with # the simple link test code. m4_defun([_LT_LINKER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ])# _LT_LINKER_BOILERPLATE # _LT_REQUIRED_DARWIN_CHECKS # ------------------------- m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ case $host_os in rhapsody* | darwin*) AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) AC_CHECK_TOOL([LIPO], [lipo], [:]) AC_CHECK_TOOL([OTOOL], [otool], [:]) AC_CHECK_TOOL([OTOOL64], [otool64], [:]) _LT_DECL([], [DSYMUTIL], [1], [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) _LT_DECL([], [NMEDIT], [1], [Tool to change global to local symbols on Mac OS X]) _LT_DECL([], [LIPO], [1], [Tool to manipulate fat objects and archives on Mac OS X]) _LT_DECL([], [OTOOL], [1], [ldd/readelf like tool for Mach-O binaries on Mac OS X]) _LT_DECL([], [OTOOL64], [1], [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], [lt_cv_apple_cc_single_mod=no if test -z "${LT_MULTI_MODULE}"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? # If there is a non-empty error log, and "single_module" # appears in it, assume the flag caused a linker warning if test -s conftest.err && $GREP single_module conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD # Otherwise, if the output was created with a 0 exit code from # the compiler, it worked. elif test -f libconftest.dylib && test $_lt_result -eq 0; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -rf libconftest.dylib* rm -f conftest.* fi]) AC_CACHE_CHECK([for -exported_symbols_list linker flag], [lt_cv_ld_exported_symbols_list], [lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [lt_cv_ld_exported_symbols_list=yes], [lt_cv_ld_exported_symbols_list=no]) LDFLAGS="$save_LDFLAGS" ]) AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load], [lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD cat > conftest.c << _LT_EOF int main() { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err _lt_result=$? if test -s conftest.err && $GREP force_load conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then lt_cv_ld_force_load=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM ]) case $host_os in rhapsody* | darwin1.[[012]]) _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; 10.[[012]]*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test "$lt_cv_apple_cc_single_mod" = "yes"; then _lt_dar_single_mod='$single_module' fi if test "$lt_cv_ld_exported_symbols_list" = "yes"; then _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' fi if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac ]) # _LT_DARWIN_LINKER_FEATURES([TAG]) # --------------------------------- # Checks for linker and compiler features on darwin m4_defun([_LT_DARWIN_LINKER_FEATURES], [ m4_require([_LT_REQUIRED_DARWIN_CHECKS]) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported if test "$lt_cv_ld_force_load" = "yes"; then _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes], [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes]) else _LT_TAGVAR(whole_archive_flag_spec, $1)='' fi _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined" case $cc_basename in ifort*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then output_verbose_link_cmd=func_echo_all _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" m4_if([$1], [CXX], [ if test "$lt_cv_apple_cc_single_mod" != "yes"; then _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" fi ],[]) else _LT_TAGVAR(ld_shlibs, $1)=no fi ]) # _LT_SYS_MODULE_PATH_AIX([TAGNAME]) # ---------------------------------- # Links a minimal program and checks the executable # for the system default hardcoded library path. In most cases, # this is /usr/lib:/lib, but when the MPI compilers are used # the location of the communication and MPI libs are included too. # If we don't find anything, use the default library path according # to the aix ld manual. # Store the results from the different compilers for each TAGNAME. # Allow to override them for all tags through lt_cv_aix_libpath. m4_defun([_LT_SYS_MODULE_PATH_AIX], [m4_require([_LT_DECL_SED])dnl if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])], [AC_LINK_IFELSE([AC_LANG_PROGRAM],[ lt_aix_libpath_sed='[ /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }]' _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi],[]) if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib" fi ]) aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1]) fi ])# _LT_SYS_MODULE_PATH_AIX # _LT_SHELL_INIT(ARG) # ------------------- m4_define([_LT_SHELL_INIT], [m4_divert_text([M4SH-INIT], [$1 ])])# _LT_SHELL_INIT # _LT_PROG_ECHO_BACKSLASH # ----------------------- # Find how we can fake an echo command that does not interpret backslash. # In particular, with Autoconf 2.60 or later we add some code to the start # of the generated configure script which will find a shell with a builtin # printf (which we can use as an echo command). m4_defun([_LT_PROG_ECHO_BACKSLASH], [ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO AC_MSG_CHECKING([how to print strings]) # Test print first, because it will be a builtin if present. if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='print -r --' elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='printf %s\n' else # Use this function as a fallback that always works. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $[]1 _LTECHO_EOF' } ECHO='func_fallback_echo' fi # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } case "$ECHO" in printf*) AC_MSG_RESULT([printf]) ;; print*) AC_MSG_RESULT([print -r]) ;; *) AC_MSG_RESULT([cat]) ;; esac m4_ifdef([_AS_DETECT_SUGGESTED], [_AS_DETECT_SUGGESTED([ test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || ( ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO PATH=/empty FPATH=/empty; export PATH FPATH test "X`printf %s $ECHO`" = "X$ECHO" \ || test "X`print -r -- $ECHO`" = "X$ECHO" )])]) _LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) _LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) ])# _LT_PROG_ECHO_BACKSLASH # _LT_WITH_SYSROOT # ---------------- AC_DEFUN([_LT_WITH_SYSROOT], [AC_MSG_CHECKING([for sysroot]) AC_ARG_WITH([sysroot], [ --with-sysroot[=DIR] Search for dependent libraries within DIR (or the compiler's sysroot if not specified).], [], [with_sysroot=no]) dnl lt_sysroot will always be passed unquoted. We quote it here dnl in case the user passed a directory name. lt_sysroot= case ${with_sysroot} in #( yes) if test "$GCC" = yes; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) AC_MSG_RESULT([${with_sysroot}]) AC_MSG_ERROR([The sysroot must be an absolute path.]) ;; esac AC_MSG_RESULT([${lt_sysroot:-no}]) _LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl [dependent libraries, and in which our libraries should be installed.])]) # _LT_ENABLE_LOCK # --------------- m4_defun([_LT_ENABLE_LOCK], [AC_ARG_ENABLE([libtool-lock], [AS_HELP_STRING([--disable-libtool-lock], [avoid locking (might break parallel builds)])]) test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" ;; *ELF-64*) HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_i386" ;; ppc64-*linux*|powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; ppc*-*linux*|powerpc*-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, [AC_LANG_PUSH(C) AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) AC_LANG_POP]) if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; *-*solaris*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*) LD="${LD-ld} -m elf_x86_64" ;; sparc*-*-solaris*) LD="${LD-ld} -m elf64_sparc" ;; esac # GNU ld 2.21 introduced _sol2 emulations. Use them if available. if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then LD="${LD-ld}_sol2" fi ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks="$enable_libtool_lock" ])# _LT_ENABLE_LOCK # _LT_PROG_AR # ----------- m4_defun([_LT_PROG_AR], [AC_CHECK_TOOLS(AR, [ar], false) : ${AR=ar} : ${AR_FLAGS=cru} _LT_DECL([], [AR], [1], [The archiver]) _LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive]) AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], [lt_cv_ar_at_file=no AC_COMPILE_IFELSE([AC_LANG_PROGRAM], [echo conftest.$ac_objext > conftest.lst lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD' AC_TRY_EVAL([lt_ar_try]) if test "$ac_status" -eq 0; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a AC_TRY_EVAL([lt_ar_try]) if test "$ac_status" -ne 0; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a ]) ]) if test "x$lt_cv_ar_at_file" = xno; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file fi _LT_DECL([], [archiver_list_spec], [1], [How to feed a file listing to the archiver]) ])# _LT_PROG_AR # _LT_CMD_OLD_ARCHIVE # ------------------- m4_defun([_LT_CMD_OLD_ARCHIVE], [_LT_PROG_AR AC_CHECK_TOOL(STRIP, strip, :) test -z "$STRIP" && STRIP=: _LT_DECL([], [STRIP], [1], [A symbol stripping program]) AC_CHECK_TOOL(RANLIB, ranlib, :) test -z "$RANLIB" && RANLIB=: _LT_DECL([], [RANLIB], [1], [Commands used to install an old-style archive]) # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in darwin*) lock_old_archive_extraction=yes ;; *) lock_old_archive_extraction=no ;; esac _LT_DECL([], [old_postinstall_cmds], [2]) _LT_DECL([], [old_postuninstall_cmds], [2]) _LT_TAGDECL([], [old_archive_cmds], [2], [Commands used to build an old-style archive]) _LT_DECL([], [lock_old_archive_extraction], [0], [Whether to use a lock for old archive extraction]) ])# _LT_CMD_OLD_ARCHIVE # _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------------------- # Check whether the given compiler option works AC_DEFUN([_LT_COMPILER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$3" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi fi $RM conftest* ]) if test x"[$]$2" = xyes; then m4_if([$5], , :, [$5]) else m4_if([$6], , :, [$6]) fi ])# _LT_COMPILER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) # _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------- # Check whether the given linker option works AC_DEFUN([_LT_LINKER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $3" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&AS_MESSAGE_LOG_FD $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi else $2=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" ]) if test x"[$]$2" = xyes; then m4_if([$4], , :, [$4]) else m4_if([$5], , :, [$5]) fi ])# _LT_LINKER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) # LT_CMD_MAX_LEN #--------------- AC_DEFUN([LT_CMD_MAX_LEN], [AC_REQUIRE([AC_CANONICAL_HOST])dnl # find the maximum length of command line arguments AC_MSG_CHECKING([the maximum length of command line arguments]) AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl i=0 teststring="ABCD" case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; mint*) # On MiNT this can take a long time and run out of memory. lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; os2*) # The test takes a long time on OS/2. lt_cv_sys_max_cmd_len=8192 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8 ; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac ]) if test -n $lt_cv_sys_max_cmd_len ; then AC_MSG_RESULT($lt_cv_sys_max_cmd_len) else AC_MSG_RESULT(none) fi max_cmd_len=$lt_cv_sys_max_cmd_len _LT_DECL([], [max_cmd_len], [0], [What is the maximum length of a command?]) ])# LT_CMD_MAX_LEN # Old name: AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) # _LT_HEADER_DLFCN # ---------------- m4_defun([_LT_HEADER_DLFCN], [AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl ])# _LT_HEADER_DLFCN # _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, # ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) # ---------------------------------------------------------------- m4_defun([_LT_TRY_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test "$cross_compiling" = yes; then : [$4] else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF [#line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisbility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; }] _LT_EOF if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) $1 ;; x$lt_dlneed_uscore) $2 ;; x$lt_dlunknown|x*) $3 ;; esac else : # compilation failed $3 fi fi rm -fr conftest* ])# _LT_TRY_DLOPEN_SELF # LT_SYS_DLOPEN_SELF # ------------------ AC_DEFUN([LT_SYS_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ]) ;; *) AC_CHECK_FUNC([shl_load], [lt_cv_dlopen="shl_load"], [AC_CHECK_LIB([dld], [shl_load], [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"], [AC_CHECK_FUNC([dlopen], [lt_cv_dlopen="dlopen"], [AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], [AC_CHECK_LIB([svld], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], [AC_CHECK_LIB([dld], [dld_link], [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"]) ]) ]) ]) ]) ]) ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" AC_CACHE_CHECK([whether a program can dlopen itself], lt_cv_dlopen_self, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) ]) if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" AC_CACHE_CHECK([whether a statically linked program can dlopen itself], lt_cv_dlopen_self_static, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) ]) fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi _LT_DECL([dlopen_support], [enable_dlopen], [0], [Whether dlopen is supported]) _LT_DECL([dlopen_self], [enable_dlopen_self], [0], [Whether dlopen of programs is supported]) _LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], [Whether dlopen of statically linked programs is supported]) ])# LT_SYS_DLOPEN_SELF # Old name: AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) # _LT_COMPILER_C_O([TAGNAME]) # --------------------------- # Check to see if options -c and -o are simultaneously supported by compiler. # This macro does not hard code the compiler like AC_PROG_CC_C_O. m4_defun([_LT_COMPILER_C_O], [m4_require([_LT_DECL_SED])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes fi fi chmod u+w . 2>&AS_MESSAGE_LOG_FD $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* ]) _LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], [Does compiler simultaneously support -c and -o options?]) ])# _LT_COMPILER_C_O # _LT_COMPILER_FILE_LOCKS([TAGNAME]) # ---------------------------------- # Check to see if we can do hard links to lock some files if needed m4_defun([_LT_COMPILER_FILE_LOCKS], [m4_require([_LT_ENABLE_LOCK])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_COMPILER_C_O([$1]) hard_links="nottested" if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user AC_MSG_CHECKING([if we can lock with hard links]) hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no AC_MSG_RESULT([$hard_links]) if test "$hard_links" = no; then AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) need_locks=warn fi else need_locks=no fi _LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) ])# _LT_COMPILER_FILE_LOCKS # _LT_CHECK_OBJDIR # ---------------- m4_defun([_LT_CHECK_OBJDIR], [AC_CACHE_CHECK([for objdir], [lt_cv_objdir], [rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null]) objdir=$lt_cv_objdir _LT_DECL([], [objdir], [0], [The name of the directory that contains temporary libtool files])dnl m4_pattern_allow([LT_OBJDIR])dnl AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/", [Define to the sub-directory in which libtool stores uninstalled libraries.]) ])# _LT_CHECK_OBJDIR # _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) # -------------------------------------- # Check hardcoding attributes. m4_defun([_LT_LINKER_HARDCODE_LIBPATH], [AC_MSG_CHECKING([how to hardcode library paths into programs]) _LT_TAGVAR(hardcode_action, $1)= if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || test -n "$_LT_TAGVAR(runpath_var, $1)" || test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then # We can hardcode non-existent directories. if test "$_LT_TAGVAR(hardcode_direct, $1)" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no && test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then # Linking always hardcodes the temporary library directory. _LT_TAGVAR(hardcode_action, $1)=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. _LT_TAGVAR(hardcode_action, $1)=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. _LT_TAGVAR(hardcode_action, $1)=unsupported fi AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) if test "$_LT_TAGVAR(hardcode_action, $1)" = relink || test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi _LT_TAGDECL([], [hardcode_action], [0], [How to hardcode a shared library path into an executable]) ])# _LT_LINKER_HARDCODE_LIBPATH # _LT_CMD_STRIPLIB # ---------------- m4_defun([_LT_CMD_STRIPLIB], [m4_require([_LT_DECL_EGREP]) striplib= old_striplib= AC_MSG_CHECKING([whether stripping libraries is possible]) if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" AC_MSG_RESULT([yes]) else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" old_striplib="$STRIP -S" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ;; *) AC_MSG_RESULT([no]) ;; esac fi _LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) _LT_DECL([], [striplib], [1]) ])# _LT_CMD_STRIPLIB # _LT_SYS_DYNAMIC_LINKER([TAG]) # ----------------------------- # PORTME Fill in your ld.so characteristics m4_defun([_LT_SYS_DYNAMIC_LINKER], [AC_REQUIRE([AC_CANONICAL_HOST])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_OBJDUMP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl AC_MSG_CHECKING([dynamic linker characteristics]) m4_if([$1], [], [ if test "$GCC" = yes; then case $host_os in darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; *) lt_awk_arg="/^libraries:/" ;; esac case $host_os in mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;; *) lt_sed_strip_eq="s,=/,/,g" ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ;; *) lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ;; esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary. lt_tmp_lt_search_path_spec= lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path/$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" else test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS=" "; FS="/|\n";} { lt_foo=""; lt_count=0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo="/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[[lt_foo]]++; } if (lt_freq[[lt_foo]] == 1) { print lt_foo; } }'` # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's,/\([[A-Za-z]]:\),\1,g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi]) library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix[[4-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[[01]] | aix4.[[01]].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[[45]]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' library_names_spec='${libname}.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec="$LIB" if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[[23]].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[[01]]* | freebsdelf3.[[01]]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=yes sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[[3-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath], [lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], [lt_cv_shlibpath_overrides_runpath=yes])]) LDFLAGS=$save_LDFLAGS libdir=$save_libdir ]) shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[[89]] | openbsd2.[[89]].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac AC_MSG_RESULT([$dynamic_linker]) test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi _LT_DECL([], [variables_saved_for_relink], [1], [Variables whose values should be saved in libtool wrapper scripts and restored at link time]) _LT_DECL([], [need_lib_prefix], [0], [Do we need the "lib" prefix for modules?]) _LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) _LT_DECL([], [version_type], [0], [Library versioning type]) _LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) _LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) _LT_DECL([], [shlibpath_overrides_runpath], [0], [Is shlibpath searched before the hard-coded library search path?]) _LT_DECL([], [libname_spec], [1], [Format of library name prefix]) _LT_DECL([], [library_names_spec], [1], [[List of archive names. First name is the real one, the rest are links. The last name is the one that the linker finds with -lNAME]]) _LT_DECL([], [soname_spec], [1], [[The coded name of the library, if different from the real name]]) _LT_DECL([], [install_override_mode], [1], [Permission mode override for installation of shared libraries]) _LT_DECL([], [postinstall_cmds], [2], [Command to use after installation of a shared archive]) _LT_DECL([], [postuninstall_cmds], [2], [Command to use after uninstallation of a shared archive]) _LT_DECL([], [finish_cmds], [2], [Commands used to finish a libtool library installation in a directory]) _LT_DECL([], [finish_eval], [1], [[As "finish_cmds", except a single script fragment to be evaled but not shown]]) _LT_DECL([], [hardcode_into_libs], [0], [Whether we should hardcode library paths into libraries]) _LT_DECL([], [sys_lib_search_path_spec], [2], [Compile-time system search path for libraries]) _LT_DECL([], [sys_lib_dlsearch_path_spec], [2], [Run-time system search path for libraries]) ])# _LT_SYS_DYNAMIC_LINKER # _LT_PATH_TOOL_PREFIX(TOOL) # -------------------------- # find a file program which can recognize shared library AC_DEFUN([_LT_PATH_TOOL_PREFIX], [m4_require([_LT_DECL_EGREP])dnl AC_MSG_CHECKING([for $1]) AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, [case $MAGIC_CMD in [[\\/*] | ?:[\\/]*]) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR dnl $ac_dummy forces splitting on constant user-supplied paths. dnl POSIX.2 word splitting is done only on the output of word expansions, dnl not every word. This closes a longstanding sh security hole. ac_dummy="m4_if([$2], , $PATH, [$2])" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$1; then lt_cv_path_MAGIC_CMD="$ac_dir/$1" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac]) MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then AC_MSG_RESULT($MAGIC_CMD) else AC_MSG_RESULT(no) fi _LT_DECL([], [MAGIC_CMD], [0], [Used to examine libraries when file_magic_cmd begins with "file"])dnl ])# _LT_PATH_TOOL_PREFIX # Old name: AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) # _LT_PATH_MAGIC # -------------- # find a file program which can recognize a shared library m4_defun([_LT_PATH_MAGIC], [_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) else MAGIC_CMD=: fi fi ])# _LT_PATH_MAGIC # LT_PATH_LD # ---------- # find the pathname to the GNU or non-GNU linker AC_DEFUN([LT_PATH_LD], [AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PROG_ECHO_BACKSLASH])dnl AC_ARG_WITH([gnu-ld], [AS_HELP_STRING([--with-gnu-ld], [assume the C compiler uses GNU ld @<:@default=no@:>@])], [test "$withval" = no || with_gnu_ld=yes], [with_gnu_ld=no])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 $CC]) 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. [[\\/]]* | ?:[[\\/]]*) re_direlt='/[[^/]][[^/]]*/\.\./' # Canonicalize the pathname 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(lt_cv_path_LD, [if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; gnu*) lt_cv_deplibs_check_method=pass_all ;; haiku*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'] lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[[3-9]]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu) lt_cv_deplibs_check_method=pass_all ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; esac ]) file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in mingw* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"` fi ;; esac fi file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown _LT_DECL([], [deplibs_check_method], [1], [Method to check whether dependent libraries are shared objects]) _LT_DECL([], [file_magic_cmd], [1], [Command to use when deplibs_check_method = "file_magic"]) _LT_DECL([], [file_magic_glob], [1], [How to find potential files when deplibs_check_method = "file_magic"]) _LT_DECL([], [want_nocaseglob], [1], [Find potential files using nocaseglob when deplibs_check_method = "file_magic"]) ])# _LT_CHECK_MAGIC_METHOD # LT_PATH_NM # ---------- # find the pathname to a BSD- or MS-compatible name lister AC_DEFUN([LT_PATH_NM], [AC_REQUIRE([AC_PROG_CC])dnl AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, [if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM="$NM" else lt_nm_to_check="${ac_tool_prefix}nm" if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. tmp_nm="$ac_dir/$lt_tmp_nm" if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS="$lt_save_ifs" done : ${lt_cv_path_NM=no} fi]) if test "$lt_cv_path_NM" != "no"; then NM="$lt_cv_path_NM" else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : # Let the user override the test. else AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols" ;; *) DUMPBIN=: ;; esac fi AC_SUBST([DUMPBIN]) if test "$DUMPBIN" != ":"; then NM="$DUMPBIN" fi fi test -z "$NM" && NM=nm AC_SUBST([NM]) _LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], [lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD) cat conftest.out >&AS_MESSAGE_LOG_FD if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest*]) ])# LT_PATH_NM # Old names: AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_PROG_NM], []) dnl AC_DEFUN([AC_PROG_NM], []) # _LT_CHECK_SHAREDLIB_FROM_LINKLIB # -------------------------------- # how to determine the name of the shared library # associated with a specific link library. # -- PORTME fill in with the dynamic library characteristics m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB], [m4_require([_LT_DECL_EGREP]) m4_require([_LT_DECL_OBJDUMP]) m4_require([_LT_DECL_DLLTOOL]) AC_CACHE_CHECK([how to associate runtime and link libraries], lt_cv_sharedlib_from_linklib_cmd, [lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh # decide which to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib ;; *) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback ;; esac ;; *) # fallback: assume linklib IS sharedlib lt_cv_sharedlib_from_linklib_cmd="$ECHO" ;; esac ]) sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO _LT_DECL([], [sharedlib_from_linklib_cmd], [1], [Command to associate shared and link libraries]) ])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB # _LT_PATH_MANIFEST_TOOL # ---------------------- # locate the manifest tool m4_defun([_LT_PATH_MANIFEST_TOOL], [AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], [lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&AS_MESSAGE_LOG_FD if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi rm -f conftest*]) if test "x$lt_cv_path_mainfest_tool" != xyes; then MANIFEST_TOOL=: fi _LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl ])# _LT_PATH_MANIFEST_TOOL # LT_LIB_M # -------- # check for math library AC_DEFUN([LT_LIB_M], [AC_REQUIRE([AC_CANONICAL_HOST])dnl LIBM= case $host in *-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) # These system don't have libm, or don't need it ;; *-ncr-sysv4.3*) AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") ;; *) AC_CHECK_LIB(m, cos, LIBM="-lm") ;; esac AC_SUBST([LIBM]) ])# LT_LIB_M # Old name: AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_CHECK_LIBM], []) # _LT_COMPILER_NO_RTTI([TAGNAME]) # ------------------------------- m4_defun([_LT_COMPILER_NO_RTTI], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= if test "$GCC" = yes; then case $cc_basename in nvcc*) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;; *) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;; esac _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], lt_cv_prog_compiler_rtti_exceptions, [-fno-rtti -fno-exceptions], [], [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) fi _LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], [Compiler flag to turn off builtin functions]) ])# _LT_COMPILER_NO_RTTI # _LT_CMD_GLOBAL_SYMBOLS # ---------------------- m4_defun([_LT_CMD_GLOBAL_SYMBOLS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([LT_PATH_NM])dnl AC_REQUIRE([LT_PATH_LD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_TAG_COMPILER])dnl # Check for command to grab the raw symbol name followed by C symbol from nm. AC_MSG_CHECKING([command to parse $NM output from $compiler object]) AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], [ # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[[BCDEGRST]]' # Regexp to match symbols that can be accessed directly from C. sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[[BCDT]]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[[ABCDGISTW]]' ;; hpux*) if test "$host_cpu" = ia64; then symcode='[[ABCDEGRST]]' fi ;; irix* | nonstopux*) symcode='[[BCDEGRST]]' ;; osf*) symcode='[[BCDEGQRST]]' ;; solaris*) symcode='[[BDRT]]' ;; sco3.2v5*) symcode='[[DT]]' ;; sysv4.2uw2*) symcode='[[DT]]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[[ABDT]]' ;; sysv4) symcode='[[DFNSTU]]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[[ABCDGIRSTW]]' ;; esac # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function # and D for any global variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK ['"\ " {last_section=section; section=\$ 3};"\ " /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ " {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ " s[1]~/^[@?]/{print s[1], s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx]" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if AC_TRY_EVAL(ac_compile); then # Now try to grab the symbols. nlist=conftest.nm if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT@&t@_DLSYM_CONST #elif defined(__osf__) /* This system does not cope well with relocations in const data. */ # define LT@&t@_DLSYM_CONST #else # define LT@&t@_DLSYM_CONST const #endif #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ LT@&t@_DLSYM_CONST struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[[]] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD fi else echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= fi done ]) if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then AC_MSG_RESULT(failed) else AC_MSG_RESULT(ok) fi # Response file support. if test "$lt_cv_nm_interface" = "MS dumpbin"; then nm_file_list_spec='@' elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then nm_file_list_spec='@' fi _LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], [Take the output of nm and produce a listing of raw symbols and C names]) _LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], [Transform the output of nm in a proper C declaration]) _LT_DECL([global_symbol_to_c_name_address], [lt_cv_sys_global_symbol_to_c_name_address], [1], [Transform the output of nm in a C name address pair]) _LT_DECL([global_symbol_to_c_name_address_lib_prefix], [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], [Transform the output of nm in a C name address pair when lib prefix is needed]) _LT_DECL([], [nm_file_list_spec], [1], [Specify filename containing input files for $NM]) ]) # _LT_CMD_GLOBAL_SYMBOLS # _LT_COMPILER_PIC([TAGNAME]) # --------------------------- m4_defun([_LT_COMPILER_PIC], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_wl, $1)= _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)= m4_if([$1], [CXX], [ # C++ specific cases for pic, static, wl, etc. if test "$GXX" = yes; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else case $host_os in aix[[4-9]]*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68*) # Green Hills C++ Compiler # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; dgux*) case $cc_basename in ec++*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; ghcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; freebsd* | dragonfly*) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' if test "$host_cpu" != ia64; then _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' fi ;; aCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac ;; *) ;; esac ;; interix*) # This is c89, which is MS Visual C++ (no shared libs) # Anyone wants to do a port? ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in KCC*) # KAI C++ Compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; ecpc* ) # old Intel C++ for x86_64 which still supported -KPIC. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; icpc* ) # Intel C++, used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; pgCC* | pgcpp*) # Portland Group C++ compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; cxx*) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL 8.0, 9.0 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; esac ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' ;; *) ;; esac ;; netbsd*) ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' ;; RCC*) # Rational C++ 2.4.1 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; cxx*) # Digital/Compaq C++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; *) ;; esac ;; psos*) ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; lcc*) # Lucid _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; *) ;; esac ;; vxworks*) ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ], [ if test "$GCC" = yes; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac case $cc_basename in nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)" fi ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; hpux9* | hpux10* | hpux11*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC (with -KPIC) is the default. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in # old Intel for x86_64 which still supported -KPIC. ecc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # Lahey Fortran 8.1. lf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' ;; nagfor*) # NAG Fortran compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; ccc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All Alpha code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xl* | bgxl* | bgf* | mpixl*) # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*) # Sun Fortran 8.3 passes all unrecognized flags to the linker _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='' ;; *Sun\ F* | *Sun*Fortran*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' ;; *Intel*\ [[CF]]*Compiler*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; *Portland\ Group*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; esac ;; newsos6) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All OSF/1 code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; rdos*) _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; solaris*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; *) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; esac ;; sunos4*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; unicos*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; uts4*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ]) case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" ;; esac AC_CACHE_CHECK([for $compiler option to produce PIC], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) _LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1) # # Check to make sure the PIC flag actually works. # if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in "" | " "*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; esac], [_LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) fi _LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], [Additional compiler flags for building library objects]) _LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], [How to pass a linker flag through the compiler]) # # Check to make sure the static flag actually works. # wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" _LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), $lt_tmp_static_flag, [], [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) _LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], [Compiler flag to prevent dynamic linking]) ])# _LT_COMPILER_PIC # _LT_LINKER_SHLIBS([TAGNAME]) # ---------------------------- # See if the linker supports building shared libraries. m4_defun([_LT_LINKER_SHLIBS], [AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) m4_if([$1], [CXX], [ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] case $host_os in aix[[4-9]]*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global defined # symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi ;; pw32*) _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" ;; cygwin* | mingw* | cegcc*) case $cc_basename in cl*) _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] ;; esac ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac ], [ runpath_var= _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_cmds, $1)= _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(old_archive_from_new_cmds, $1)= _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= _LT_TAGVAR(thread_safe_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list _LT_TAGVAR(include_expsyms, $1)= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. dnl Note also adjust exclude_expsyms for C++ above. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; esac _LT_TAGVAR(ld_shlibs, $1)=yes # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no if test "$with_gnu_ld" = yes; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility # with the native linker. However, as the warning in the GNU ld # block says, versions before 2.19.5* couldn't really create working # shared libraries, regardless of the interface used. case `$LD -v 2>&1` in *\ \(GNU\ Binutils\)\ 2.19.5*) ;; *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;; *\ \(GNU\ Binutils\)\ [[3-9]]*) ;; *) lt_use_gnu_ld_interface=yes ;; esac ;; *) lt_use_gnu_ld_interface=yes ;; esac fi if test "$lt_use_gnu_ld_interface" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi supports_anon_versioning=no case `$LD -v 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[[3-9]]*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.19, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to install binutils *** 2.20 or above, or modify your PATH so that a non-GNU linker is found. *** You will then need to restart the configuration process. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test "$host_os" = linux-dietlibc; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test "$tmp_diet" = no then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 _LT_TAGVAR(whole_archive_flag_spec, $1)= tmp_sharedflag='--shared' ;; xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi case $cc_basename in xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; sunos4*) _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then runpath_var= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. _LT_TAGVAR(hardcode_minus_L, $1)=yes if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. _LT_TAGVAR(hardcode_direct, $1)=unsupported fi ;; aix[[4-9]]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global # defined symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' if test "$GCC" = yes; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi ;; esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. _LT_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; bsdi[[45]]*) _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl*) # Native MSVC _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # Assume MSVC wrapper _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' # FIXME: Should let the user specify the lib program. _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2.*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; hpux9*) if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; hpux10*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test "$with_gnu_ld" = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes fi ;; hpux11*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) m4_if($1, [], [ # Older versions of the 11.00 compiler do not understand -b yet # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) _LT_LINKER_OPTION([if $CC understands -b], _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b], [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])], [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags']) ;; esac fi if test "$with_gnu_ld" = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. # This should be the same for all languages, so no per-tag cache variable. AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol], [lt_cv_irix_exported_symbol], [save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" AC_LINK_IFELSE( [AC_LANG_SOURCE( [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], [C++], [[int foo (void) { return 0; }]], [Fortran 77], [[ subroutine foo end]], [Fortran], [[ subroutine foo end]])])], [lt_cv_irix_exported_symbol=yes], [lt_cv_irix_exported_symbol=no]) LDFLAGS="$save_LDFLAGS"]) if test "$lt_cv_irix_exported_symbol" = yes; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' fi else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes _LT_TAGVAR(link_all_deplibs, $1)=yes ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; newsos6) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *nto* | *qnx*) ;; openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' else case $host_os in openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' ;; esac fi else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; solaris*) _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' if test "$GCC" = yes; then wlarc='${wl}' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='${wl}' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. GCC discards it without `$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test "$GCC" = yes; then _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' else _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' fi ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4) case $host_vendor in sni) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' _LT_TAGVAR(hardcode_direct, $1)=no ;; motorola) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4.3*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes _LT_TAGVAR(ld_shlibs, $1)=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(ld_shlibs, $1)=no ;; esac if test x$host_vendor = xsni; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym' ;; esac fi fi ]) AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld _LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl _LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl _LT_DECL([], [extract_expsyms_cmds], [2], [The commands to extract the exported symbol list from a shared archive]) # # Do we need to explicitly link libc? # case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in x|xyes) # Assume -lc should be added _LT_TAGVAR(archive_cmds_need_lc, $1)=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $_LT_TAGVAR(archive_cmds, $1) in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. AC_CACHE_CHECK([whether -lc should be explicitly linked in], [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), [$RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if AC_TRY_EVAL(ac_compile) 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) _LT_TAGVAR(allow_undefined_flag, $1)= if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) then lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no else lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes fi _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* ]) _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1) ;; esac fi ;; esac _LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], [Whether or not to add -lc for building shared libraries]) _LT_TAGDECL([allow_libtool_libs_with_static_runtimes], [enable_shared_with_static_runtimes], [0], [Whether or not to disallow shared libs when runtime libs are static]) _LT_TAGDECL([], [export_dynamic_flag_spec], [1], [Compiler flag to allow reflexive dlopens]) _LT_TAGDECL([], [whole_archive_flag_spec], [1], [Compiler flag to generate shared objects directly from archives]) _LT_TAGDECL([], [compiler_needs_object], [1], [Whether the compiler copes with passing no objects directly]) _LT_TAGDECL([], [old_archive_from_new_cmds], [2], [Create an old-style archive from a shared archive]) _LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], [Create a temporary old-style archive to link instead of a shared archive]) _LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) _LT_TAGDECL([], [archive_expsym_cmds], [2]) _LT_TAGDECL([], [module_cmds], [2], [Commands used to build a loadable module if different from building a shared archive.]) _LT_TAGDECL([], [module_expsym_cmds], [2]) _LT_TAGDECL([], [with_gnu_ld], [1], [Whether we are building with GNU ld or not]) _LT_TAGDECL([], [allow_undefined_flag], [1], [Flag that allows shared libraries with undefined symbols to be built]) _LT_TAGDECL([], [no_undefined_flag], [1], [Flag that enforces no undefined symbols]) _LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], [Flag to hardcode $libdir into a binary during linking. This must work even if $libdir does not exist]) _LT_TAGDECL([], [hardcode_libdir_separator], [1], [Whether we need a single "-rpath" flag with a separated argument]) _LT_TAGDECL([], [hardcode_direct], [0], [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_direct_absolute], [0], [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the resulting binary and the resulting library dependency is "absolute", i.e impossible to change by setting ${shlibpath_var} if the library is relocated]) _LT_TAGDECL([], [hardcode_minus_L], [0], [Set to "yes" if using the -LDIR flag during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_shlibpath_var], [0], [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_automatic], [0], [Set to "yes" if building a shared library automatically hardcodes DIR into the library and all subsequent libraries and executables linked against it]) _LT_TAGDECL([], [inherit_rpath], [0], [Set to yes if linker adds runtime paths of dependent libraries to runtime path list]) _LT_TAGDECL([], [link_all_deplibs], [0], [Whether libtool must link a program against all its dependency libraries]) _LT_TAGDECL([], [always_export_symbols], [0], [Set to "yes" if exported symbols are required]) _LT_TAGDECL([], [export_symbols_cmds], [2], [The commands to list exported symbols]) _LT_TAGDECL([], [exclude_expsyms], [1], [Symbols that should not be listed in the preloaded symbols]) _LT_TAGDECL([], [include_expsyms], [1], [Symbols that must always be exported]) _LT_TAGDECL([], [prelink_cmds], [2], [Commands necessary for linking programs (against libraries) with templates]) _LT_TAGDECL([], [postlink_cmds], [2], [Commands necessary for finishing linking programs]) _LT_TAGDECL([], [file_list_spec], [1], [Specify filename containing input files]) dnl FIXME: Not yet implemented dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], dnl [Compiler flag to generate thread safe objects]) ])# _LT_LINKER_SHLIBS # _LT_LANG_C_CONFIG([TAG]) # ------------------------ # Ensure that the configuration variables for a C compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to `libtool'. m4_defun([_LT_LANG_C_CONFIG], [m4_require([_LT_DECL_EGREP])dnl lt_save_CC="$CC" AC_LANG_PUSH(C) # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' _LT_TAG_COMPILER # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) LT_SYS_DLOPEN_SELF _LT_CMD_STRIPLIB # Report which library types will actually be built AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_CONFIG($1) fi AC_LANG_POP CC="$lt_save_CC" ])# _LT_LANG_C_CONFIG # _LT_LANG_CXX_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a C++ compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to `libtool'. m4_defun([_LT_LANG_CXX_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl if test -n "$CXX" && ( test "X$CXX" != "Xno" && ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || (test "X$CXX" != "Xg++"))) ; then AC_PROG_CXXCPP else _lt_caught_CXX_error=yes fi AC_LANG_PUSH(C++) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for C++ test sources. ac_ext=cpp # Object file extension for compiled C++ test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the CXX compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_caught_CXX_error" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else $as_unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else $as_unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} CFLAGS=$CXXFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then # We don't want -fno-exception when compiling C++ code, so set the # no_builtin_flag separately if test "$GXX" = yes; then _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' else _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= fi if test "$GXX" = yes; then # Set up default GNU C++ configuration LT_PATH_LD # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test "$with_gnu_ld" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='${wl}' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) _LT_TAGVAR(ld_shlibs, $1)=yes case $host_os in aix3*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aix[[4-9]]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' if test "$GXX" = yes; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to # export. _LT_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an empty # executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared # libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; cygwin* | mingw* | pw32* | cegcc*) case $GXX,$cc_basename in ,cl* | no,cl*) # Native MSVC # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ func_to_tool_file "$lt_outputfile"~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # g++ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) case $cc_basename in ec++*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; ghcx*) # Green Hills C++ Compiler # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; freebsd2.*) # C++ shared libraries reported to be fairly broken before # switch to ELF _LT_TAGVAR(ld_shlibs, $1)=no ;; freebsd-elf*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; freebsd* | dragonfly*) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions _LT_TAGVAR(ld_shlibs, $1)=yes ;; gnu*) ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; hpux9*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; hpux10*|hpux11*) if test $with_gnu_ld = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) ;; *) _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; esac fi case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes; then if test $with_gnu_ld = no; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; irix5* | irix6*) case $cc_basename in CC*) # SGI C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test "$GXX" = yes; then if test "$with_gnu_ld" = no; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib' fi fi _LT_TAGVAR(link_all_deplibs, $1)=yes ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc* | ecpc* ) # Intel C++ with_gnu_ld=yes # version 8.0 and above of icpc choke on multiply defined symbols # if we add $predep_objects and $postdep_objects, however 7.1 and # earlier do not add the objects themselves. case `$CC -V 2>&1` in *"Version 7."*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 8.0 or newer tmp_idyn= case $host_cpu in ia64*) tmp_idyn=' -i_dynamic';; esac _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; esac _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' ;; pgCC* | pgcpp*) # Portland Group C++ compiler case `$CC -V` in *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*) _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ $RANLIB $oldlib' _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; *) # Version 6 and above use weak symbols _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' ;; cxx*) # Compaq C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' ;; xl* | mpixl* | bgxl*) # IBM XL 8.0 on PPC, with GNU ld _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes # Not sure whether something based on # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 # would be better. output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; esac ;; esac ;; lynxos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; m88k*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; mvs*) case $cc_basename in cxx*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; *nto* | *qnx*) _LT_TAGVAR(ld_shlibs, $1)=yes ;; openbsd2*) # C++ shared libraries are fairly broken _LT_TAGVAR(ld_shlibs, $1)=no ;; openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' fi output_verbose_link_cmd=func_echo_all else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Archives containing C++ object files must be created using # the KAI C++ compiler. case $host in osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; esac ;; RCC*) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; cxx*) case $host in osf3*) _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' ;; *) _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~ $RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' ;; esac _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' case $host in osf3*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; lcc*) # Lucid # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. # Supported since Solaris 2.6 (maybe 2.5.1?) _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' if $CC --version | $GREP -v '^2\.7' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # g++ 2.7 appears to require `-G' NOT `-shared' on this # platform. _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' ;; esac fi ;; esac ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~ '"$_LT_TAGVAR(old_archive_cmds, $1)" _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~ '"$_LT_TAGVAR(reload_cmds, $1)" ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_TAGVAR(GCC, $1)="$GXX" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld fi # test "$_lt_caught_CXX_error" != yes AC_LANG_POP ])# _LT_LANG_CXX_CONFIG # _LT_FUNC_STRIPNAME_CNF # ---------------------- # func_stripname_cnf prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # # This function is identical to the (non-XSI) version of func_stripname, # except this one can be used by m4 code that may be executed by configure, # rather than the libtool script. m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl AC_REQUIRE([_LT_DECL_SED]) AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH]) func_stripname_cnf () { case ${2} in .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; esac } # func_stripname_cnf ])# _LT_FUNC_STRIPNAME_CNF # _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) # --------------------------------- # Figure out "hidden" library dependencies from verbose # compiler output when linking a shared library. # Parse the compiler output and extract the necessary # objects, libraries and library flags. m4_defun([_LT_SYS_HIDDEN_LIBDEPS], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl # Dependencies to place before and after the object being linked: _LT_TAGVAR(predep_objects, $1)= _LT_TAGVAR(postdep_objects, $1)= _LT_TAGVAR(predeps, $1)= _LT_TAGVAR(postdeps, $1)= _LT_TAGVAR(compiler_lib_search_path, $1)= dnl we can't use the lt_simple_compile_test_code here, dnl because it contains code intended for an executable, dnl not a library. It's possible we should let each dnl tag define a new lt_????_link_test_code variable, dnl but it's only used here... m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF int a; void foo (void) { a = 0; } _LT_EOF ], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF class Foo { public: Foo (void) { a = 0; } private: int a; }; _LT_EOF ], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer*4 a a=0 return end _LT_EOF ], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer a a=0 return end _LT_EOF ], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF public class foo { private int a; public void bar (void) { a = 0; } }; _LT_EOF ], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF package foo func foo() { } _LT_EOF ]) _lt_libdeps_save_CFLAGS=$CFLAGS case "$CC $CFLAGS " in #( *\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; *\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; *\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; esac dnl Parse the compiler output and extract the necessary dnl objects, libraries and library flags. if AC_TRY_EVAL(ac_compile); then # Parse the compiler output and extract the necessary # objects, libraries and library flags. # Sentinel used to keep track of whether or not we are before # the conftest object file. pre_test_object_deps_done=no for p in `eval "$output_verbose_link_cmd"`; do case ${prev}${p} in -L* | -R* | -l*) # Some compilers place space between "-{L,R}" and the path. # Remove the space. if test $p = "-L" || test $p = "-R"; then prev=$p continue fi # Expand the sysroot to ease extracting the directories later. if test -z "$prev"; then case $p in -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; esac fi case $p in =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; esac if test "$pre_test_object_deps_done" = no; then case ${prev} in -L | -R) # Internal compiler library paths should come after those # provided the user. The postdeps already come after the # user supplied libs so there is no need to process them. if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}" else _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}" fi ;; # The "-l" case would never come before the object being # linked, so don't bother handling this case. esac else if test -z "$_LT_TAGVAR(postdeps, $1)"; then _LT_TAGVAR(postdeps, $1)="${prev}${p}" else _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}" fi fi prev= ;; *.lto.$objext) ;; # Ignore GCC LTO objects *.$objext) # This assumes that the test object file only shows up # once in the compiler output. if test "$p" = "conftest.$objext"; then pre_test_object_deps_done=yes continue fi if test "$pre_test_object_deps_done" = no; then if test -z "$_LT_TAGVAR(predep_objects, $1)"; then _LT_TAGVAR(predep_objects, $1)="$p" else _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" fi else if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then _LT_TAGVAR(postdep_objects, $1)="$p" else _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" fi fi ;; *) ;; # Ignore the rest. esac done # Clean up. rm -f a.out a.exe else echo "libtool.m4: error: problem compiling $1 test program" fi $RM -f confest.$objext CFLAGS=$_lt_libdeps_save_CFLAGS # PORTME: override above test on systems where it is broken m4_if([$1], [CXX], [case $host_os in interix[[3-9]]*) # Interix 3.5 installs completely hosed .la files for C++, so rather than # hack all around it, let's just trust "g++" to DTRT. _LT_TAGVAR(predep_objects,$1)= _LT_TAGVAR(postdep_objects,$1)= _LT_TAGVAR(postdeps,$1)= ;; linux*) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac # Adding this requires a known-good setup of shared libraries for # Sun compiler versions before 5.6, else PIC objects from an old # archive will be linked into the output, leading to subtle bugs. if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; esac ]) case " $_LT_TAGVAR(postdeps, $1) " in *" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; esac _LT_TAGVAR(compiler_lib_search_dirs, $1)= if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` fi _LT_TAGDECL([], [compiler_lib_search_dirs], [1], [The directories searched by this compiler when creating a shared library]) _LT_TAGDECL([], [predep_objects], [1], [Dependencies to place before and after the objects being linked to create a shared library]) _LT_TAGDECL([], [postdep_objects], [1]) _LT_TAGDECL([], [predeps], [1]) _LT_TAGDECL([], [postdeps], [1]) _LT_TAGDECL([], [compiler_lib_search_path], [1], [The library search path used internally by the compiler when linking a shared library]) ])# _LT_SYS_HIDDEN_LIBDEPS # _LT_LANG_F77_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a Fortran 77 compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_F77_CONFIG], [AC_LANG_PUSH(Fortran 77) if test -z "$F77" || test "X$F77" = "Xno"; then _lt_disable_F77=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for f77 test sources. ac_ext=f # Object file extension for compiled f77 test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the F77 compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_disable_F77" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${F77-"f77"} CFLAGS=$FFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) GCC=$G77 if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)="$G77" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC="$lt_save_CC" CFLAGS="$lt_save_CFLAGS" fi # test "$_lt_disable_F77" != yes AC_LANG_POP ])# _LT_LANG_F77_CONFIG # _LT_LANG_FC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for a Fortran compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_FC_CONFIG], [AC_LANG_PUSH(Fortran) if test -z "$FC" || test "X$FC" = "Xno"; then _lt_disable_FC=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for fc test sources. ac_ext=${ac_fc_srcext-f} # Object file extension for compiled fc test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the FC compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_disable_FC" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${FC-"f95"} CFLAGS=$FCFLAGS compiler=$CC GCC=$ac_cv_fc_compiler_gnu _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS fi # test "$_lt_disable_FC" != yes AC_LANG_POP ])# _LT_LANG_FC_CONFIG # _LT_LANG_GCJ_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Java Compiler compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_GCJ_CONFIG], [AC_REQUIRE([LT_PROG_GCJ])dnl AC_LANG_SAVE # Source file extension for Java test sources. ac_ext=java # Object file extension for compiled Java test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="class foo {}" # Code to be used in simple link tests lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GCJ-"gcj"} CFLAGS=$GCJFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)="$LD" _LT_CC_BASENAME([$compiler]) # GCJ did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GCJ_CONFIG # _LT_LANG_GO_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Go compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_GO_CONFIG], [AC_REQUIRE([LT_PROG_GO])dnl AC_LANG_SAVE # Source file extension for Go test sources. ac_ext=go # Object file extension for compiled Go test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="package main; func main() { }" # Code to be used in simple link tests lt_simple_link_test_code='package main; func main() { }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GOC-"gccgo"} CFLAGS=$GOFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)="$LD" _LT_CC_BASENAME([$compiler]) # Go did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GO_CONFIG # _LT_LANG_RC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for the Windows resource compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_RC_CONFIG], [AC_REQUIRE([LT_PROG_RC])dnl AC_LANG_SAVE # Source file extension for RC test sources. ac_ext=rc # Object file extension for compiled RC test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' # Code to be used in simple link tests lt_simple_link_test_code="$lt_simple_compile_test_code" # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC= CC=${RC-"windres"} CFLAGS= compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes if test -n "$compiler"; then : _LT_CONFIG($1) fi GCC=$lt_save_GCC AC_LANG_RESTORE CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_RC_CONFIG # LT_PROG_GCJ # ----------- AC_DEFUN([LT_PROG_GCJ], [m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], [AC_CHECK_TOOL(GCJ, gcj,) test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" AC_SUBST(GCJFLAGS)])])[]dnl ]) # Old name: AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_GCJ], []) # LT_PROG_GO # ---------- AC_DEFUN([LT_PROG_GO], [AC_CHECK_TOOL(GOC, gccgo,) ]) # LT_PROG_RC # ---------- AC_DEFUN([LT_PROG_RC], [AC_CHECK_TOOL(RC, windres,) ]) # Old name: AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_RC], []) # _LT_DECL_EGREP # -------------- # If we don't have a new enough Autoconf to choose the best grep # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_EGREP], [AC_REQUIRE([AC_PROG_EGREP])dnl AC_REQUIRE([AC_PROG_FGREP])dnl test -z "$GREP" && GREP=grep _LT_DECL([], [GREP], [1], [A grep program that handles long lines]) _LT_DECL([], [EGREP], [1], [An ERE matcher]) _LT_DECL([], [FGREP], [1], [A literal string matcher]) dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too AC_SUBST([GREP]) ]) # _LT_DECL_OBJDUMP # -------------- # If we don't have a new enough Autoconf to choose the best objdump # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_OBJDUMP], [AC_CHECK_TOOL(OBJDUMP, objdump, false) test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) AC_SUBST([OBJDUMP]) ]) # _LT_DECL_DLLTOOL # ---------------- # Ensure DLLTOOL variable is set. m4_defun([_LT_DECL_DLLTOOL], [AC_CHECK_TOOL(DLLTOOL, dlltool, false) test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program]) AC_SUBST([DLLTOOL]) ]) # _LT_DECL_SED # ------------ # Check for a fully-functional sed program, that truncates # as few characters as possible. Prefer GNU sed if found. m4_defun([_LT_DECL_SED], [AC_PROG_SED test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" _LT_DECL([], [SED], [1], [A sed program that does not truncate output]) _LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], [Sed that helps us avoid accidentally triggering echo(1) options like -n]) ])# _LT_DECL_SED m4_ifndef([AC_PROG_SED], [ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_SED. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # m4_defun([AC_PROG_SED], [AC_MSG_CHECKING([for a sed that does not truncate output]) AC_CACHE_VAL(lt_cv_path_SED, [# Loop through the user's path and test for sed and gsed. # Then use that list of sed's as ones to test for truncation. as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for lt_ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" fi done done done IFS=$as_save_IFS lt_ac_max=0 lt_ac_count=0 # Add /usr/xpg4/bin/sed as it is typically found on Solaris # along with /bin/sed that truncates output. for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do test ! -f $lt_ac_sed && continue cat /dev/null > conftest.in lt_ac_count=0 echo $ECHO_N "0123456789$ECHO_C" >conftest.in # Check for GNU sed and select it if it is found. if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then lt_cv_path_SED=$lt_ac_sed break fi while true; do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo >>conftest.nl $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break cmp -s conftest.out conftest.nl || break # 10000 chars as input seems more than enough test $lt_ac_count -gt 10 && break lt_ac_count=`expr $lt_ac_count + 1` if test $lt_ac_count -gt $lt_ac_max; then lt_ac_max=$lt_ac_count lt_cv_path_SED=$lt_ac_sed fi done done ]) SED=$lt_cv_path_SED AC_SUBST([SED]) AC_MSG_RESULT([$SED]) ])#AC_PROG_SED ])#m4_ifndef # Old name: AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_SED], []) # _LT_CHECK_SHELL_FEATURES # ------------------------ # Find out whether the shell is Bourne or XSI compatible, # or has some other useful features. m4_defun([_LT_CHECK_SHELL_FEATURES], [AC_MSG_CHECKING([whether the shell understands some XSI constructs]) # Try some XSI features xsi_shell=no ( _lt_dummy="a/b/c" test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ = c,a/b,b/c, \ && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes AC_MSG_RESULT([$xsi_shell]) _LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell']) AC_MSG_CHECKING([whether the shell understands "+="]) lt_shell_append=no ( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \ >/dev/null 2>&1 \ && lt_shell_append=yes AC_MSG_RESULT([$lt_shell_append]) _LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append']) if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi _LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac _LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl _LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl ])# _LT_CHECK_SHELL_FEATURES # _LT_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY) # ------------------------------------------------------ # In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and # '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY. m4_defun([_LT_PROG_FUNCTION_REPLACE], [dnl { sed -e '/^$1 ()$/,/^} # $1 /c\ $1 ()\ {\ m4_bpatsubsts([$2], [$], [\\], [^\([ ]\)], [\\\1]) } # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: ]) # _LT_PROG_REPLACE_SHELLFNS # ------------------------- # Replace existing portable implementations of several shell functions with # equivalent extended shell implementations where those features are available.. m4_defun([_LT_PROG_REPLACE_SHELLFNS], [if test x"$xsi_shell" = xyes; then _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac]) _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl func_basename_result="${1##*/}"]) _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac func_basename_result="${1##*/}"]) _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are # positional parameters, so assign one to ordinary parameter first. func_stripname_result=${3} func_stripname_result=${func_stripname_result#"${1}"} func_stripname_result=${func_stripname_result%"${2}"}]) _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl func_split_long_opt_name=${1%%=*} func_split_long_opt_arg=${1#*=}]) _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl func_split_short_opt_arg=${1#??} func_split_short_opt_name=${1%"$func_split_short_opt_arg"}]) _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl case ${1} in *.lo) func_lo2o_result=${1%.lo}.${objext} ;; *) func_lo2o_result=${1} ;; esac]) _LT_PROG_FUNCTION_REPLACE([func_xform], [ func_xform_result=${1%.*}.lo]) _LT_PROG_FUNCTION_REPLACE([func_arith], [ func_arith_result=$(( $[*] ))]) _LT_PROG_FUNCTION_REPLACE([func_len], [ func_len_result=${#1}]) fi if test x"$lt_shell_append" = xyes; then _LT_PROG_FUNCTION_REPLACE([func_append], [ eval "${1}+=\\${2}"]) _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl func_quote_for_eval "${2}" dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \ eval "${1}+=\\\\ \\$func_quote_for_eval_result"]) # Save a `func_append' function call where possible by direct use of '+=' sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: else # Save a `func_append' function call even when '+=' is not available sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$_lt_function_replace_fail" = x":"; then AC_MSG_WARN([Unable to substitute extended shell functions in $ofile]) fi ]) # _LT_PATH_CONVERSION_FUNCTIONS # ----------------------------- # Determine which file name conversion functions should be used by # func_to_host_file (and, implicitly, by func_to_host_path). These are needed # for certain cross-compile configurations and native mingw. m4_defun([_LT_PATH_CONVERSION_FUNCTIONS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_MSG_CHECKING([how to convert $build file names to $host format]) AC_CACHE_VAL(lt_cv_to_host_file_cmd, [case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 ;; esac ;; *-*-cygwin* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin ;; esac ;; * ) # unhandled hosts (and "normal" native builds) lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac ]) to_host_file_cmd=$lt_cv_to_host_file_cmd AC_MSG_RESULT([$lt_cv_to_host_file_cmd]) _LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd], [0], [convert $build file names to $host format])dnl AC_MSG_CHECKING([how to convert $build file names to toolchain format]) AC_CACHE_VAL(lt_cv_to_tool_file_cmd, [#assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac ;; esac ]) to_tool_file_cmd=$lt_cv_to_tool_file_cmd AC_MSG_RESULT([$lt_cv_to_tool_file_cmd]) _LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd], [0], [convert $build files to toolchain format])dnl ])# _LT_PATH_CONVERSION_FUNCTIONS # longlong.m4 serial 17 dnl Copyright (C) 1999-2007, 2009-2013 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Paul Eggert. # Define HAVE_LONG_LONG_INT if 'long long int' works. # This fixes a bug in Autoconf 2.61, and can be faster # than what's in Autoconf 2.62 through 2.68. # Note: If the type 'long long int' exists but is only 32 bits large # (as on some very old compilers), HAVE_LONG_LONG_INT will not be # defined. In this case you can treat 'long long int' like 'long int'. AC_DEFUN([AC_TYPE_LONG_LONG_INT], [ AC_REQUIRE([AC_TYPE_UNSIGNED_LONG_LONG_INT]) AC_CACHE_CHECK([for long long int], [ac_cv_type_long_long_int], [ac_cv_type_long_long_int=yes if test "x${ac_cv_prog_cc_c99-no}" = xno; then ac_cv_type_long_long_int=$ac_cv_type_unsigned_long_long_int if test $ac_cv_type_long_long_int = yes; then dnl Catch a bug in Tandem NonStop Kernel (OSS) cc -O circa 2004. dnl If cross compiling, assume the bug is not important, since dnl nobody cross compiles for this platform as far as we know. AC_RUN_IFELSE( [AC_LANG_PROGRAM( [[@%:@include @%:@ifndef LLONG_MAX @%:@ define HALF \ (1LL << (sizeof (long long int) * CHAR_BIT - 2)) @%:@ define LLONG_MAX (HALF - 1 + HALF) @%:@endif]], [[long long int n = 1; int i; for (i = 0; ; i++) { long long int m = n << i; if (m >> i != n) return 1; if (LLONG_MAX / 2 < m) break; } return 0;]])], [], [ac_cv_type_long_long_int=no], [:]) fi fi]) if test $ac_cv_type_long_long_int = yes; then AC_DEFINE([HAVE_LONG_LONG_INT], [1], [Define to 1 if the system has the type 'long long int'.]) fi ]) # Define HAVE_UNSIGNED_LONG_LONG_INT if 'unsigned long long int' works. # This fixes a bug in Autoconf 2.61, and can be faster # than what's in Autoconf 2.62 through 2.68. # Note: If the type 'unsigned long long int' exists but is only 32 bits # large (as on some very old compilers), AC_TYPE_UNSIGNED_LONG_LONG_INT # will not be defined. In this case you can treat 'unsigned long long int' # like 'unsigned long int'. AC_DEFUN([AC_TYPE_UNSIGNED_LONG_LONG_INT], [ AC_CACHE_CHECK([for unsigned long long int], [ac_cv_type_unsigned_long_long_int], [ac_cv_type_unsigned_long_long_int=yes if test "x${ac_cv_prog_cc_c99-no}" = xno; then AC_LINK_IFELSE( [_AC_TYPE_LONG_LONG_SNIPPET], [], [ac_cv_type_unsigned_long_long_int=no]) fi]) if test $ac_cv_type_unsigned_long_long_int = yes; then AC_DEFINE([HAVE_UNSIGNED_LONG_LONG_INT], [1], [Define to 1 if the system has the type 'unsigned long long int'.]) fi ]) # Expands to a C program that can be used to test for simultaneous support # of 'long long' and 'unsigned long long'. We don't want to say that # 'long long' is available if 'unsigned long long' is not, or vice versa, # because too many programs rely on the symmetry between signed and unsigned # integer types (excluding 'bool'). AC_DEFUN([_AC_TYPE_LONG_LONG_SNIPPET], [ AC_LANG_PROGRAM( [[/* For now, do not test the preprocessor; as of 2007 there are too many implementations with broken preprocessors. Perhaps this can be revisited in 2012. In the meantime, code should not expect #if to work with literals wider than 32 bits. */ /* Test literals. */ long long int ll = 9223372036854775807ll; long long int nll = -9223372036854775807LL; unsigned long long int ull = 18446744073709551615ULL; /* Test constant expressions. */ typedef int a[((-9223372036854775807LL < 0 && 0 < 9223372036854775807ll) ? 1 : -1)]; typedef int b[(18446744073709551615ULL <= (unsigned long long int) -1 ? 1 : -1)]; int i = 63;]], [[/* Test availability of runtime routines for shift and division. */ long long int llmax = 9223372036854775807ll; unsigned long long int ullmax = 18446744073709551615ull; return ((ll << 63) | (ll >> 63) | (ll < i) | (ll > i) | (llmax / ll) | (llmax % ll) | (ull << 63) | (ull >> 63) | (ull << i) | (ull >> i) | (ullmax / ull) | (ullmax % ull));]]) ]) # Helper functions for option handling. -*- Autoconf -*- # # Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation, # Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 7 ltoptions.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) # _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) # ------------------------------------------ m4_define([_LT_MANGLE_OPTION], [[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) # _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) # --------------------------------------- # Set option OPTION-NAME for macro MACRO-NAME, and if there is a # matching handler defined, dispatch to it. Other OPTION-NAMEs are # saved as a flag. m4_define([_LT_SET_OPTION], [m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), _LT_MANGLE_DEFUN([$1], [$2]), [m4_warning([Unknown $1 option `$2'])])[]dnl ]) # _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) # ------------------------------------------------------------ # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. m4_define([_LT_IF_OPTION], [m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) # _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) # ------------------------------------------------------- # Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME # are set. m4_define([_LT_UNLESS_OPTIONS], [m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), [m4_define([$0_found])])])[]dnl m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 ])[]dnl ]) # _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) # ---------------------------------------- # OPTION-LIST is a space-separated list of Libtool options associated # with MACRO-NAME. If any OPTION has a matching handler declared with # LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about # the unknown option and exit. m4_defun([_LT_SET_OPTIONS], [# Set options m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [_LT_SET_OPTION([$1], _LT_Option)]) m4_if([$1],[LT_INIT],[ dnl dnl Simply set some default values (i.e off) if boolean options were not dnl specified: _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no ]) _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no ]) dnl dnl If no reference was made to various pairs of opposing options, then dnl we run the default mode handler for the pair. For example, if neither dnl `shared' nor `disable-shared' was passed, we enable building of shared dnl archives by default: _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], [_LT_ENABLE_FAST_INSTALL]) ]) ])# _LT_SET_OPTIONS # _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) # ----------------------------------------- m4_define([_LT_MANGLE_DEFUN], [[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) # LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) # ----------------------------------------------- m4_define([LT_OPTION_DEFINE], [m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl ])# LT_OPTION_DEFINE # dlopen # ------ LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes ]) AU_DEFUN([AC_LIBTOOL_DLOPEN], [_LT_SET_OPTION([LT_INIT], [dlopen]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `dlopen' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) # win32-dll # --------- # Declare package support for building win32 dll's. LT_OPTION_DEFINE([LT_INIT], [win32-dll], [enable_win32_dll=yes case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) AC_CHECK_TOOL(AS, as, false) AC_CHECK_TOOL(DLLTOOL, dlltool, false) AC_CHECK_TOOL(OBJDUMP, objdump, false) ;; esac test -z "$AS" && AS=as _LT_DECL([], [AS], [1], [Assembler program])dnl test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl ])# win32-dll AU_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_REQUIRE([AC_CANONICAL_HOST])dnl _LT_SET_OPTION([LT_INIT], [win32-dll]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `win32-dll' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) # _LT_ENABLE_SHARED([DEFAULT]) # ---------------------------- # implement the --enable-shared flag, and supports the `shared' and # `disable-shared' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_SHARED], [m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([shared], [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) _LT_DECL([build_libtool_libs], [enable_shared], [0], [Whether or not to build shared libraries]) ])# _LT_ENABLE_SHARED LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) # Old names: AC_DEFUN([AC_ENABLE_SHARED], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) ]) AC_DEFUN([AC_DISABLE_SHARED], [_LT_SET_OPTION([LT_INIT], [disable-shared]) ]) AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_SHARED], []) dnl AC_DEFUN([AM_DISABLE_SHARED], []) # _LT_ENABLE_STATIC([DEFAULT]) # ---------------------------- # implement the --enable-static flag, and support the `static' and # `disable-static' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_STATIC], [m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([static], [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_static=]_LT_ENABLE_STATIC_DEFAULT) _LT_DECL([build_old_libs], [enable_static], [0], [Whether or not to build static libraries]) ])# _LT_ENABLE_STATIC LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) # Old names: AC_DEFUN([AC_ENABLE_STATIC], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) ]) AC_DEFUN([AC_DISABLE_STATIC], [_LT_SET_OPTION([LT_INIT], [disable-static]) ]) AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_STATIC], []) dnl AC_DEFUN([AM_DISABLE_STATIC], []) # _LT_ENABLE_FAST_INSTALL([DEFAULT]) # ---------------------------------- # implement the --enable-fast-install flag, and support the `fast-install' # and `disable-fast-install' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_FAST_INSTALL], [m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([fast-install], [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) _LT_DECL([fast_install], [enable_fast_install], [0], [Whether or not to optimize for fast installation])dnl ])# _LT_ENABLE_FAST_INSTALL LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) # Old names: AU_DEFUN([AC_ENABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `fast-install' option into LT_INIT's first parameter.]) ]) AU_DEFUN([AC_DISABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], [disable-fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `disable-fast-install' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) # _LT_WITH_PIC([MODE]) # -------------------- # implement the --with-pic flag, and support the `pic-only' and `no-pic' # LT_INIT options. # MODE is either `yes' or `no'. If omitted, it defaults to `both'. m4_define([_LT_WITH_PIC], [AC_ARG_WITH([pic], [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@], [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], [lt_p=${PACKAGE-default} case $withval in yes|no) pic_mode=$withval ;; *) pic_mode=default # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for lt_pkg in $withval; do IFS="$lt_save_ifs" if test "X$lt_pkg" = "X$lt_p"; then pic_mode=yes fi done IFS="$lt_save_ifs" ;; esac], [pic_mode=default]) test -z "$pic_mode" && pic_mode=m4_default([$1], [default]) _LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl ])# _LT_WITH_PIC LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) # Old name: AU_DEFUN([AC_LIBTOOL_PICMODE], [_LT_SET_OPTION([LT_INIT], [pic-only]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `pic-only' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) m4_define([_LTDL_MODE], []) LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], [m4_define([_LTDL_MODE], [nonrecursive])]) LT_OPTION_DEFINE([LTDL_INIT], [recursive], [m4_define([_LTDL_MODE], [recursive])]) LT_OPTION_DEFINE([LTDL_INIT], [subproject], [m4_define([_LTDL_MODE], [subproject])]) m4_define([_LTDL_TYPE], []) LT_OPTION_DEFINE([LTDL_INIT], [installable], [m4_define([_LTDL_TYPE], [installable])]) LT_OPTION_DEFINE([LTDL_INIT], [convenience], [m4_define([_LTDL_TYPE], [convenience])]) # ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 6 ltsugar.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) # lt_join(SEP, ARG1, [ARG2...]) # ----------------------------- # Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their # associated separator. # Needed until we can rely on m4_join from Autoconf 2.62, since all earlier # versions in m4sugar had bugs. m4_define([lt_join], [m4_if([$#], [1], [], [$#], [2], [[$2]], [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) m4_define([_lt_join], [m4_if([$#$2], [2], [], [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) # lt_car(LIST) # lt_cdr(LIST) # ------------ # Manipulate m4 lists. # These macros are necessary as long as will still need to support # Autoconf-2.59 which quotes differently. m4_define([lt_car], [[$1]]) m4_define([lt_cdr], [m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], [$#], 1, [], [m4_dquote(m4_shift($@))])]) m4_define([lt_unquote], $1) # lt_append(MACRO-NAME, STRING, [SEPARATOR]) # ------------------------------------------ # Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'. # Note that neither SEPARATOR nor STRING are expanded; they are appended # to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). # No SEPARATOR is output if MACRO-NAME was previously undefined (different # than defined and empty). # # This macro is needed until we can rely on Autoconf 2.62, since earlier # versions of m4sugar mistakenly expanded SEPARATOR but not STRING. m4_define([lt_append], [m4_define([$1], m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) # lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) # ---------------------------------------------------------- # Produce a SEP delimited list of all paired combinations of elements of # PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list # has the form PREFIXmINFIXSUFFIXn. # Needed until we can rely on m4_combine added in Autoconf 2.62. m4_define([lt_combine], [m4_if(m4_eval([$# > 3]), [1], [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl [[m4_foreach([_Lt_prefix], [$2], [m4_foreach([_Lt_suffix], ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) # lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) # ----------------------------------------------------------------------- # Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited # by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. m4_define([lt_if_append_uniq], [m4_ifdef([$1], [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], [lt_append([$1], [$2], [$3])$4], [$5])], [lt_append([$1], [$2], [$3])$4])]) # lt_dict_add(DICT, KEY, VALUE) # ----------------------------- m4_define([lt_dict_add], [m4_define([$1($2)], [$3])]) # lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) # -------------------------------------------- m4_define([lt_dict_add_subkey], [m4_define([$1($2:$3)], [$4])]) # lt_dict_fetch(DICT, KEY, [SUBKEY]) # ---------------------------------- m4_define([lt_dict_fetch], [m4_ifval([$3], m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) # lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) # ----------------------------------------------------------------- m4_define([lt_if_dict_fetch], [m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], [$5], [$6])]) # lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) # -------------------------------------------------------------- m4_define([lt_dict_filter], [m4_if([$5], [], [], [lt_join(m4_quote(m4_default([$4], [[, ]])), lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl ]) # ltversion.m4 -- version numbers -*- Autoconf -*- # # Copyright (C) 2004 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # @configure_input@ # serial 3337 ltversion.m4 # This file is part of GNU Libtool m4_define([LT_PACKAGE_VERSION], [2.4.2]) m4_define([LT_PACKAGE_REVISION], [1.3337]) AC_DEFUN([LTVERSION_VERSION], [macro_version='2.4.2' macro_revision='1.3337' _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) _LT_DECL(, macro_revision, 0) ]) # lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004. # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 5 lt~obsolete.m4 # These exist entirely to fool aclocal when bootstrapping libtool. # # In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN) # which have later been changed to m4_define as they aren't part of the # exported API, or moved to Autoconf or Automake where they belong. # # The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN # in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us # using a macro with the same name in our local m4/libtool.m4 it'll # pull the old libtool.m4 in (it doesn't see our shiny new m4_define # and doesn't know about Autoconf macros at all.) # # So we provide this file, which has a silly filename so it's always # included after everything else. This provides aclocal with the # AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything # because those macros already exist, or will be overwritten later. # We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. # # Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. # Yes, that means every name once taken will need to remain here until # we give up compatibility with versions before 1.7, at which point # we need to keep only those names which we still refer to. # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) # Copyright (C) 2002-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.13' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.13.1], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.13.1])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to # '$srcdir', '$srcdir/..', or '$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is '.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [dnl Rely on autoconf to set up CDPATH properly. AC_PREREQ([2.50])dnl # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ([2.52])dnl m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], [$1], [CXX], [depcc="$CXX" am_compiler_list=], [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], [$1], [UPC], [depcc="$UPC" am_compiler_list=], [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES. AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE([dependency-tracking], [dnl AS_HELP_STRING( [--enable-dependency-tracking], [do not reject slow dependency extractors]) AS_HELP_STRING( [--disable-dependency-tracking], [speeds up one-time build])]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl AC_SUBST([am__nodep])dnl _AM_SUBST_NOTMAKE([am__nodep])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named 'Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`AS_DIRNAME("$mf")` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running 'make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`AS_DIRNAME(["$file"])` AS_MKDIR_P([$dirpart/$fdir]) # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking # is enabled. FIXME. This creates each '.P' file that we will # need in order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) ]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.65])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [AC_DIAGNOSE([obsolete], [$0: two- and three-arguments forms are deprecated.]) m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if( m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), [ok:ok],, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) AM_MISSING_PROG([AUTOCONF], [autoconf]) AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) AM_MISSING_PROG([AUTOHEADER], [autoheader]) AM_MISSING_PROG([MAKEINFO], [makeinfo]) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # AC_SUBST([mkdir_p], ['$(MKDIR_P)']) # We need awk for the "check" target. The system "awk" is bad on # some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES([CC])], [m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES([CXX])], [m4_define([AC_PROG_CXX], m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES([OBJC])], [m4_define([AC_PROG_OBJC], m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], [_AM_DEPENDENCIES([OBJCXX])], [m4_define([AC_PROG_OBJCXX], m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl ]) AC_REQUIRE([AM_SILENT_RULES])dnl dnl The testsuite driver may need to know about EXEEXT, so add the dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl ]) dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST([install_sh])]) # Copyright (C) 2003-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Add --enable-maintainer-mode option to configure. -*- Autoconf -*- # From Jim Meyering # Copyright (C) 1996-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MAINTAINER_MODE([DEFAULT-MODE]) # ---------------------------------- # Control maintainer-specific portions of Makefiles. # Default is to disable them, unless 'enable' is passed literally. # For symmetry, 'disable' may be passed as well. Anyway, the user # can override the default with the --enable/--disable switch. AC_DEFUN([AM_MAINTAINER_MODE], [m4_case(m4_default([$1], [disable]), [enable], [m4_define([am_maintainer_other], [disable])], [disable], [m4_define([am_maintainer_other], [enable])], [m4_define([am_maintainer_other], [enable]) m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])]) AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) dnl maintainer-mode's default is 'disable' unless 'enable' is passed AC_ARG_ENABLE([maintainer-mode], [AS_HELP_STRING([--]am_maintainer_other[-maintainer-mode], am_maintainer_other[ make rules and dependencies not useful (and sometimes confusing) to the casual installer])], [USE_MAINTAINER_MODE=$enableval], [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes])) AC_MSG_RESULT([$USE_MAINTAINER_MODE]) AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes]) MAINT=$MAINTAINER_MODE_TRUE AC_SUBST([MAINT])dnl ] ) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MAKE_INCLUDE() # ----------------- # Check to see how make treats includes. AC_DEFUN([AM_MAKE_INCLUDE], [am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. AC_MSG_CHECKING([for style of include used by $am_make]) am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from 'make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi AC_SUBST([am__include]) AC_SUBST([am__quote]) AC_MSG_RESULT([$_am_result]) rm -f confinc confmf ]) # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_CC_C_O # -------------- # Like AC_PROG_CC_C_O, but changed for automake. AC_DEFUN([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC_C_O])dnl AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([compile])dnl # FIXME: we rely on the cache variable name because # there is no other way. set dummy $CC am_cc=`echo $[2] | sed ['s/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/']` eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o if test "$am_t" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi dnl Make sure AC_PROG_CC is never called again, or it will override our dnl setting of CC. m4_define([AC_PROG_CC], [m4_fatal([AC_PROG_CC cannot be called after AM_PROG_CC_C_O])]) ]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it is modern enough. # If it is, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= AC_MSG_WARN(['missing' script is too old or missing]) fi ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # -------------------- # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), [1])]) # _AM_SET_OPTIONS(OPTIONS) # ------------------------ # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi if test "$[2]" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT([yes]) # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi AC_CONFIG_COMMANDS_PRE( [AC_MSG_CHECKING([that generated files are newer than configure]) if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi AC_MSG_RESULT([done])]) rm -f conftest.file ]) # Copyright (C) 2009-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SILENT_RULES([DEFAULT]) # -------------------------- # Enable less verbose build rules; with the default set to DEFAULT # ("yes" being less verbose, "no" or empty being verbose). AC_DEFUN([AM_SILENT_RULES], [AC_ARG_ENABLE([silent-rules], [dnl AS_HELP_STRING( [--enable-silent-rules], [less verbose build output (undo: "make V=1")]) AS_HELP_STRING( [--disable-silent-rules], [verbose build output (undo: "make V=0")])dnl ]) case $enable_silent_rules in @%:@ ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; esac dnl dnl A few 'make' implementations (e.g., NonStop OS and NextStep) dnl do not support nested variable expansions. dnl See automake bug#9928 and bug#10237. am_make=${MAKE-make} AC_CACHE_CHECK([whether $am_make supports nested variables], [am_cv_make_support_nested_variables], [if AS_ECHO([['TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi]) if test $am_cv_make_support_nested_variables = yes; then dnl Using '$V' instead of '$(V)' breaks IRIX make. AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AC_SUBST([AM_V])dnl AM_SUBST_NOTMAKE([AM_V])dnl AC_SUBST([AM_DEFAULT_V])dnl AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl AC_SUBST([AM_DEFAULT_VERBOSITY])dnl AM_BACKSLASH='\' AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor 'install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in "make install-strip", and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # -------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of 'v7', 'ustar', or 'pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AC_SUBST([AMTAR], ['$${TAR-tar}']) m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar],, [pax],, [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' _am_tools=${am_cv_prog_tar_$1-$_am_tools} # Do not fold the above two line into one, because Tru64 sh and # Solaris sh will not grok spaces in the rhs of '-'. for _am_tool in $_am_tools do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR openocd-0.7.0/configure0000755000175000001440000177454312141414273012015 00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for openocd 0.7.0. # # Report bugs to >. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO PATH=/empty FPATH=/empty; export PATH FPATH test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org and OpenOCD Mailing $0: List about your $0: system, 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'" SHELL=${CONFIG_SHELL-/bin/sh} 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='openocd' PACKAGE_TARNAME='openocd' PACKAGE_VERSION='0.7.0' PACKAGE_STRING='openocd 0.7.0' PACKAGE_BUGREPORT='OpenOCD Mailing List ' PACKAGE_URL='' ac_unique_file="src/openocd.c" # 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" enable_option_checking=no ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LIBOBJS EXEEXT_FOR_BUILD CFLAGS_FOR_BUILD CC_FOR_BUILD INTERNAL_JIMTCL_FALSE INTERNAL_JIMTCL_TRUE MINIDRIVER_DUMMY_FALSE MINIDRIVER_DUMMY_TRUE MINIDRIVER_FALSE MINIDRIVER_TRUE BITQ_FALSE BITQ_TRUE IS_DARWIN_FALSE IS_DARWIN_TRUE IS_WIN32_FALSE IS_WIN32_TRUE IS_MINGW_FALSE IS_MINGW_TRUE IS_CYGWIN_FALSE IS_CYGWIN_TRUE USE_LIBUSB1_FALSE USE_LIBUSB1_TRUE USE_LIBUSB0_FALSE USE_LIBUSB0_TRUE USB_NG_FALSE USB_NG_TRUE USB_FALSE USB_TRUE SYSFSGPIO_FALSE SYSFSGPIO_TRUE OPENDOUS_FALSE OPENDOUS_TRUE OSBDM_FALSE OSBDM_TRUE HLADAPTER_FALSE HLADAPTER_TRUE BUSPIRATE_FALSE BUSPIRATE_TRUE REMOTE_BITBANG_FALSE REMOTE_BITBANG_TRUE ARMJTAGEW_FALSE ARMJTAGEW_TRUE ULINK_FALSE ULINK_TRUE RLINK_FALSE RLINK_TRUE VSLLINK_FALSE VSLLINK_TRUE JLINK_FALSE JLINK_TRUE OOCD_TRACE_FALSE OOCD_TRACE_TRUE USBPROG_FALSE USBPROG_TRUE PRESTO_DRIVER_FALSE PRESTO_DRIVER_TRUE PRESTO_LIBFTDI_FALSE PRESTO_LIBFTDI_TRUE GW16012_FALSE GW16012_TRUE AMTJTAGACCEL_FALSE AMTJTAGACCEL_TRUE USB_BLASTER_DRIVER_FALSE USB_BLASTER_DRIVER_TRUE USB_BLASTER_LIBFTDI_FALSE USB_BLASTER_LIBFTDI_TRUE FTDI_DRIVER_FALSE FTDI_DRIVER_TRUE FT2232_DRIVER_FALSE FT2232_DRIVER_TRUE FT2232_LIBFTDI_FALSE FT2232_LIBFTDI_TRUE BITBANG_FALSE BITBANG_TRUE AT91RM9200_FALSE AT91RM9200_TRUE IOUTIL_FALSE IOUTIL_TRUE ZY1000_MASTER_FALSE ZY1000_MASTER_TRUE ZY1000_FALSE ZY1000_TRUE EP93XX_FALSE EP93XX_TRUE GIVEIO_FALSE GIVEIO_TRUE DUMMY_FALSE DUMMY_TRUE PARPORT_FALSE PARPORT_TRUE RELEASE_FALSE RELEASE_TRUE subdirs doxygen_as_pdf doxygen_as_html LIBTOOL_DEPS CPP OTOOL64 OTOOL LIPO NMEDIT DSYMUTIL MANIFEST_TOOL ac_ct_AR AR DLLTOOL OBJDUMP LN_S NM ac_ct_DUMPBIN DUMPBIN LD FGREP EGREP GREP SED host_os host_vendor host_cpu host build_os build_vendor build_cpu build LIBTOOL RANLIB am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE am__nodep AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE am__quote am__include DEPDIR OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC MAINT MAINTAINER_MODE_FALSE MAINTAINER_MODE_TRUE AM_BACKSLASH AM_DEFAULT_VERBOSITY AM_DEFAULT_V AM_V am__untar am__tar AMTAR am__leading_dot SET_MAKE AWK mkdir_p MKDIR_P INSTALL_STRIP_PROGRAM STRIP install_sh MAKEINFO AUTOHEADER AUTOMAKE AUTOCONF ACLOCAL VERSION PACKAGE CYGPATH_W am__isrc INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM 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 enable_silent_rules enable_maintainer_mode enable_dependency_tracking enable_shared enable_static with_pic enable_fast_install with_gnu_ld with_sysroot enable_libtool_lock enable_assert with_ftd2xx with_ftd2xx_win32_zipdir with_ftd2xx_linux_tardir with_ftd2xx_lib enable_doxygen_html enable_doxygen_pdf enable_gccwarnings enable_wextra enable_werror enable_verbose enable_verbose_jtag_io enable_verbose_usb_io enable_verbose_usb_comms enable_malloc_logging enable_dummy enable_parport enable_parport_ppdev enable_parport_giveio enable_ft2232_libftdi enable_ft2232_ftd2xx enable_ftdi enable_usb_blaster_libftdi enable_usb_blaster_ftd2xx enable_amtjtagaccel enable_zy1000_master enable_zy1000 enable_ioutil enable_ep93xx enable_at91rm9200 enable_gw16012 enable_presto_libftdi enable_presto_ftd2xx enable_usbprog enable_oocd_trace enable_jlink enable_vsllink enable_rlink enable_ulink enable_arm_jtag_ew enable_buspirate enable_stlink enable_ti_icdi enable_osbdm enable_opendous enable_sysfsgpio enable_minidriver_dummy enable_internal_jimtcl enable_libusb0 enable_remote_bitbang ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP' ac_subdirs_all='jimtcl' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures openocd 0.7.0 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/openocd] --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 System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of openocd 0.7.0:";; esac 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-silent-rules less verbose build output (undo: "make V=1") --disable-silent-rules verbose build output (undo: "make V=0") --enable-maintainer-mode enable make rules and dependencies not useful (and sometimes confusing) to the casual installer --enable-dependency-tracking do not reject slow dependency extractors --disable-dependency-tracking speeds up one-time build --enable-shared[=PKGS] build shared libraries [default=no] --enable-static[=PKGS] build static libraries [default=yes] --enable-fast-install[=PKGS] optimize for fast installation [default=yes] --disable-libtool-lock avoid locking (might break parallel builds) --disable-assert turn off assertions --disable-doxygen-html Disable building Doxygen manual as HTML. --enable-doxygen-pdf Enable building Doxygen manual as PDF. --disable-gccwarnings Disable compiler warnings --disable-wextra Disable extra compiler warnings --disable-werror Do not treat warnings as errors --enable-verbose Enable verbose JTAG I/O messages (for debugging). --enable-verbose-jtag-io Enable verbose JTAG I/O messages (for debugging). --enable-verbose-usb-io Enable verbose USB I/O messages (for debugging) --enable-verbose-usb-comms Enable verbose USB communication messages (for debugging) --enable-malloc-logging Include free space in logging messages (requires malloc.h). --enable-dummy Enable building the dummy port driver --enable-parport Enable building the pc parallel port driver --disable-parport-ppdev Disable use of ppdev (/dev/parportN) for parport (for x86 only) --enable-parport-giveio Enable use of giveio for parport (for CygWin only) --enable-ft2232_libftdi Enable building support for FT2232 based devices using the libftdi driver, opensource alternate of FTD2XX --enable-ft2232_ftd2xx Enable building support for FT2232 based devices using the FTD2XX driver from ftdichip.com --enable-ftdi Enable building support for the MPSSE mode of FTDI based devices, using libusb-1.0 in asynchronous mode --enable-usb_blaster_libftdi Enable building support for the Altera USB-Blaster using the libftdi driver, opensource alternate of FTD2XX --enable-usb_blaster_ftd2xx Enable building support for the Altera USB-Blaster using the FTD2XX driver from ftdichip.com --enable-amtjtagaccel Enable building the Amontec JTAG-Accelerator driver --enable-zy1000-master Use ZY1000 JTAG master registers --enable-zy1000 Enable ZY1000 interface --enable-ioutil Enable ioutil functions - useful for standalone OpenOCD implementations --enable-ep93xx Enable building support for EP93xx based SBCs --enable-at91rm9200 Enable building support for AT91RM9200 based SBCs --enable-gw16012 Enable building support for the Gateworks GW16012 JTAG Programmer --enable-presto_libftdi Enable building support for ASIX Presto Programmer using the libftdi driver --enable-presto_ftd2xx Enable building support for ASIX Presto Programmer using the FTD2XX driver --enable-usbprog Enable building support for the usbprog JTAG Programmer --enable-oocd_trace Enable building support for some prototype OpenOCD+trace ETM capture hardware --enable-jlink Enable building support for the Segger J-Link JTAG Programmer --enable-vsllink Enable building support for the Versaloon-Link JTAG Programmer --enable-rlink Enable building support for the Raisonance RLink JTAG Programmer --enable-ulink Enable building support for the Keil ULINK JTAG Programmer --enable-arm-jtag-ew Enable building support for the Olimex ARM-JTAG-EW Programmer --enable-buspirate Enable building support for the Buspirate --enable-stlink Enable building support for the ST-Link JTAG Programmer --enable-ti-icdi Enable building support for the TI ICDI JTAG Programmer --enable-osbdm Enable building support for the OSBDM (JTAG only) Programmer --enable-opendous Enable building support for the estick/opendous JTAG Programmer --enable-sysfsgpio Enable building support for programming driven via sysfs gpios. --enable-minidriver-dummy Enable the dummy minidriver. --disable-internal-jimtcl Disable building internal jimtcl --enable-libusb0 Use libusb-0.1 library for USB JTAG devices --enable-remote-bitbang Enable building support for the Remote Bitbang jtag driver Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use both] --with-gnu-ld assume the C compiler uses GNU ld [default=no] --with-sysroot=DIR Search for dependent libraries within DIR (or the compiler's sysroot if not specified). --with-ftd2xx= This option has been removed. --with-ftd2xx-win32-zipdir Where (CYGWIN/MINGW) the zip file from ftdichip.com was unpacked (default=search) --with-ftd2xx-linux-tardir Where (Linux/Unix) the tar file from ftdichip.com was unpacked (default=search) --with-ftd2xx-lib Use static or shared ftd2xx libs (default=static) 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 Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to >. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF openocd configure 0.7.0 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_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_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 # 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_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;} ( $as_echo "## ------------------------------------------------------------------------- ## ## Report this to OpenOCD Mailing List ## ## ------------------------------------------------------------------------- ##" ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { 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 eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else eval "$3=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 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_type 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 openocd $as_me 0.7.0, 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 am__api_version='1.13' 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. # 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' { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 $as_echo_n "checking whether build environment is sane... " >&6; } # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[\\\"\#\$\&\'\`$am_lf]*) as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; esac case $srcdir in *[\\\"\#\$\&\'\`$am_lf\ \ ]*) as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$*" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$*" != "X $srcdir/configure conftest.file" \ && test "$*" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". as_fn_error $? "ls -t appears to fail. Make sure there is not a broken alias in your environment" "$LINENO" 5 fi if test "$2" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$2" = conftest.file ) then # Ok. : else as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi rm -f conftest.file 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"` # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 $as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;} fi if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. if test "$cross_compiling" != no; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $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 STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $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_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $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_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" 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 STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 $as_echo_n "checking for a thread-safe mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if ${ac_cv_path_mkdir+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir (GNU coreutils) '* | \ 'mkdir (coreutils) '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext break 3;; esac done done done IFS=$as_save_IFS fi test -d ./--version && rmdir ./--version if test "${ac_cv_path_mkdir+set}" = set; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a # value for MKDIR_P 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. MKDIR_P="$ac_install_sh -d" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 $as_echo "$MKDIR_P" >&6; } for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AWK+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$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 AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null # Check whether --enable-silent-rules was given. if test "${enable_silent_rules+set}" = set; then : enableval=$enable_silent_rules; fi case $enable_silent_rules in # ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=1;; esac am_make=${MAKE-make} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 $as_echo_n "checking whether $am_make supports nested variables... " >&6; } if ${am_cv_make_support_nested_variables+:} false; then : $as_echo_n "(cached) " >&6 else if $as_echo 'TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 $as_echo "$am_cv_make_support_nested_variables" >&6; } if test $am_cv_make_support_nested_variables = yes; then AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AM_BACKSLASH='\' if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." am__isrc=' -I$(srcdir)' # test to see if srcdir already configured if test -f $srcdir/config.status; then as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi # Define the identity of the package. PACKAGE='openocd' VERSION='0.7.0' cat >>confdefs.h <<_ACEOF #define PACKAGE "$PACKAGE" _ACEOF cat >>confdefs.h <<_ACEOF #define VERSION "$VERSION" _ACEOF # Some tools Automake needs. ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # mkdir_p='$(MKDIR_P)' # We need awk for the "check" target. The system "awk" is bad on # some platforms. # Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AMTAR='$${TAR-tar}' am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5 $as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } # Check whether --enable-maintainer-mode was given. if test "${enable_maintainer_mode+set}" = set; then : enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval else USE_MAINTAINER_MODE=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5 $as_echo "$USE_MAINTAINER_MODE" >&6; } if test $USE_MAINTAINER_MODE = yes; then MAINTAINER_MODE_TRUE= MAINTAINER_MODE_FALSE='#' else MAINTAINER_MODE_TRUE='#' MAINTAINER_MODE_FALSE= fi MAINT=$MAINTAINER_MODE_TRUE ac_config_headers="$ac_config_headers config.h" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $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 DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 $as_echo_n "checking for style of include used by $am_make... " >&6; } am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from 'make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 $as_echo "$_am_result" >&6; } rm -f confinc confmf # Check whether --enable-dependency-tracking was given. if test "${enable_dependency_tracking+set}" = set; then : enableval=$enable_dependency_tracking; fi if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi if test "x$enable_dependency_tracking" != xno; then AMDEP_TRUE= AMDEP_FALSE='#' else AMDEP_TRUE='#' AMDEP_FALSE= fi depcc="$CC" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CC_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 $as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C99" >&5 $as_echo_n "checking for $CC option to accept ISO C99... " >&6; } if ${ac_cv_prog_cc_c99+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include #include // Check varargs macros. These examples are taken from C99 6.10.3.5. #define debug(...) fprintf (stderr, __VA_ARGS__) #define showlist(...) puts (#__VA_ARGS__) #define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) static void test_varargs_macros (void) { int x = 1234; int y = 5678; debug ("Flag"); debug ("X = %d\n", x); showlist (The first, second, and third items.); report (x>y, "x is %d but y is %d", x, y); } // Check long long types. #define BIG64 18446744073709551615ull #define BIG32 4294967295ul #define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) #if !BIG_OK your preprocessor is broken; #endif #if BIG_OK #else your preprocessor is broken; #endif static long long int bignum = -9223372036854775807LL; static unsigned long long int ubignum = BIG64; struct incomplete_array { int datasize; double data[]; }; struct named_init { int number; const wchar_t *name; double average; }; typedef const char *ccp; static inline int test_restrict (ccp restrict text) { // See if C++-style comments work. // Iterate through items via the restricted pointer. // Also check for declarations in for loops. for (unsigned int i = 0; *(text+i) != '\0'; ++i) continue; return 0; } // Check varargs and va_copy. static void test_varargs (const char *format, ...) { va_list args; va_start (args, format); va_list args_copy; va_copy (args_copy, args); const char *str; int number; float fnumber; while (*format) { switch (*format++) { case 's': // string str = va_arg (args_copy, const char *); break; case 'd': // int number = va_arg (args_copy, int); break; case 'f': // float fnumber = va_arg (args_copy, double); break; default: break; } } va_end (args_copy); va_end (args); } int main () { // Check bool. _Bool success = false; // Check restrict. if (test_restrict ("String literal") == 0) success = true; char *restrict newvar = "Another string"; // Check varargs. test_varargs ("s, d' f .", "string", 65, 34.234); test_varargs_macros (); // Check flexible array members. struct incomplete_array *ia = malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); ia->datasize = 10; for (int i = 0; i < ia->datasize; ++i) ia->data[i] = i * 1.234; // Check named initializers. struct named_init ni = { .number = 34, .name = L"Test wide string", .average = 543.34343, }; ni.number = 58; int dynamic_array[ni.number]; dynamic_array[ni.number - 1] = 543; // work around unused variable warnings return (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x' || dynamic_array[ni.number - 1] != 543); ; return 0; } _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -D_STDC_C99= -qlanglvl=extc99 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c99" 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_c99" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 $as_echo "$ac_cv_prog_cc_c99" >&6; } ;; esac if test "x$ac_cv_prog_cc_c99" != xno; then : fi if test "x$CC" != xcc; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC and cc understand -c and -o together" >&5 $as_echo_n "checking whether $CC and cc understand -c and -o together... " >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether cc understands -c and -o together" >&5 $as_echo_n "checking whether cc understands -c and -o together... " >&6; } fi set dummy $CC; ac_cc=`$as_echo "$2" | sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'` if eval \${ac_cv_prog_cc_${ac_cc}_c_o+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF # Make sure it works both with $CC and with simple cc. # We do the test twice because some compilers refuse to overwrite an # existing .o file with -o, though they will create one. ac_try='$CC -c conftest.$ac_ext -o conftest2.$ac_objext >&5' rm -f conftest2.* if { { 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; } && test -f conftest2.$ac_objext && { { 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 eval ac_cv_prog_cc_${ac_cc}_c_o=yes if test "x$CC" != xcc; then # Test first that cc exists at all. if { ac_try='cc -c conftest.$ac_ext >&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_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then ac_try='cc -c conftest.$ac_ext -o conftest2.$ac_objext >&5' rm -f conftest2.* if { { 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; } && test -f conftest2.$ac_objext && { { 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 # cc works too. : else # cc exists but doesn't like -o. eval ac_cv_prog_cc_${ac_cc}_c_o=no fi fi fi else eval ac_cv_prog_cc_${ac_cc}_c_o=no fi rm -f core conftest* fi if eval test \$ac_cv_prog_cc_${ac_cc}_c_o = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "#define NO_MINUS_C_MINUS_O 1" >>confdefs.h fi # FIXME: we rely on the cache variable name because # there is no other way. set dummy $CC am_cc=`echo $2 | sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'` eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o if test "$am_t" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $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 # Check whether --enable-shared was given. if test "${enable_shared+set}" = set; then : enableval=$enable_shared; p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$lt_save_ifs" ;; esac else enable_shared=no fi case `pwd` in *\ * | *\ *) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 $as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; esac macro_version='2.4.2' macro_revision='1.3337' ltmain="$ac_aux_dir/ltmain.sh" # 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 # Backslashify metacharacters that are still active within # double-quoted strings. sed_quote_subst='s/\(["`$\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\(["`\\]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 $as_echo_n "checking how to print strings... " >&6; } # Test print first, because it will be a builtin if present. if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='print -r --' elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='printf %s\n' else # Use this function as a fallback that always works. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } ECHO='func_fallback_echo' fi # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "" } case "$ECHO" in printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5 $as_echo "printf" >&6; } ;; print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 $as_echo "print -r" >&6; } ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5 $as_echo "cat" >&6; } ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 $as_echo_n "checking for a sed that does not truncate output... " >&6; } if ${ac_cv_path_SED+:} false; then : $as_echo_n "(cached) " >&6 else ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ for ac_i in 1 2 3 4 5 6 7; do ac_script="$ac_script$as_nl$ac_script" done echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed { ac_script=; unset ac_script;} if test -z "$SED"; then ac_path_SED_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 do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_SED" || continue # Check for GNU ac_path_SED and select it if it is found. # Check for GNU $ac_path_SED case `"$ac_path_SED" --version 2>&1` in *GNU*) ac_cv_path_SED="$ac_path_SED" ac_path_SED_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 '' >> "conftest.nl" "$ac_path_SED" -f conftest.sed < "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_SED_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_SED="$ac_path_SED" ac_path_SED_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_SED_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_SED"; then as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 fi else ac_cv_path_SED=$SED fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 $as_echo "$ac_cv_path_SED" >&6; } SED="$ac_cv_path_SED" rm -f conftest.sed test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" { $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 fgrep" >&5 $as_echo_n "checking for fgrep... " >&6; } if ${ac_cv_path_FGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 then ac_cv_path_FGREP="$GREP -F" else if test -z "$FGREP"; then ac_path_FGREP_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 fgrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_FGREP" || continue # Check for GNU ac_path_FGREP and select it if it is found. # Check for GNU $ac_path_FGREP case `"$ac_path_FGREP" --version 2>&1` in *GNU*) ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_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 'FGREP' >> "conftest.nl" "$ac_path_FGREP" FGREP < "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_FGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_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_FGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_FGREP"; then as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_FGREP=$FGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 $as_echo "$ac_cv_path_FGREP" >&6; } FGREP="$ac_cv_path_FGREP" test -z "$GREP" && GREP=grep # 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 $CC" >&5 $as_echo_n "checking for ld used by $CC... " >&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. [\\/]* | ?:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the pathname 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 ${lt_cv_path_LD+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &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 ${lt_cv_prog_gnu_ld+:} false; then : $as_echo_n "(cached) " >&6 else # I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 &5 $as_echo "$lt_cv_prog_gnu_ld" >&6; } with_gnu_ld=$lt_cv_prog_gnu_ld { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 $as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } if ${lt_cv_path_NM+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM="$NM" else lt_nm_to_check="${ac_tool_prefix}nm" if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. tmp_nm="$ac_dir/$lt_tmp_nm" if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS="$lt_save_ifs" done : ${lt_cv_path_NM=no} fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 $as_echo "$lt_cv_path_NM" >&6; } if test "$lt_cv_path_NM" != "no"; then NM="$lt_cv_path_NM" else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : # Let the user override the test. else if test -n "$ac_tool_prefix"; then for ac_prog in dumpbin "link -dump" 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_DUMPBIN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DUMPBIN"; then ac_cv_prog_DUMPBIN="$DUMPBIN" # 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_DUMPBIN="$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 DUMPBIN=$ac_cv_prog_DUMPBIN if test -n "$DUMPBIN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 $as_echo "$DUMPBIN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$DUMPBIN" && break done fi if test -z "$DUMPBIN"; then ac_ct_DUMPBIN=$DUMPBIN for ac_prog in dumpbin "link -dump" 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_DUMPBIN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DUMPBIN"; then ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # 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_DUMPBIN="$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_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN if test -n "$ac_ct_DUMPBIN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 $as_echo "$ac_ct_DUMPBIN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_DUMPBIN" && break done if test "x$ac_ct_DUMPBIN" = x; then DUMPBIN=":" 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 DUMPBIN=$ac_ct_DUMPBIN fi fi case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols" ;; *) DUMPBIN=: ;; esac fi if test "$DUMPBIN" != ":"; then NM="$DUMPBIN" fi fi test -z "$NM" && NM=nm { $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 $as_echo_n "checking the name lister ($NM) interface... " >&6; } if ${lt_cv_nm_interface+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 (eval echo "\"\$as_me:$LINENO: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 $as_echo "$lt_cv_nm_interface" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 $as_echo_n "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 $as_echo "no, using $LN_S" >&6; } fi # find the maximum length of command line arguments { $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 $as_echo_n "checking the maximum length of command line arguments... " >&6; } if ${lt_cv_sys_max_cmd_len+:} false; then : $as_echo_n "(cached) " >&6 else i=0 teststring="ABCD" case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; mint*) # On MiNT this can take a long time and run out of memory. lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; os2*) # The test takes a long time on OS/2. lt_cv_sys_max_cmd_len=8192 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8 ; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac fi if test -n $lt_cv_sys_max_cmd_len ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 $as_echo "$lt_cv_sys_max_cmd_len" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 $as_echo "none" >&6; } fi max_cmd_len=$lt_cv_sys_max_cmd_len : ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5 $as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } # Try some XSI features xsi_shell=no ( _lt_dummy="a/b/c" test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ = c,a/b,b/c, \ && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5 $as_echo "$xsi_shell" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5 $as_echo_n "checking whether the shell understands \"+=\"... " >&6; } lt_shell_append=no ( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ >/dev/null 2>&1 \ && lt_shell_append=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5 $as_echo "$lt_shell_append" >&6; } if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 $as_echo_n "checking how to convert $build file names to $host format... " >&6; } if ${lt_cv_to_host_file_cmd+:} false; then : $as_echo_n "(cached) " >&6 else case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 ;; esac ;; *-*-cygwin* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin ;; esac ;; * ) # unhandled hosts (and "normal" native builds) lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac fi to_host_file_cmd=$lt_cv_to_host_file_cmd { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 $as_echo "$lt_cv_to_host_file_cmd" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 $as_echo_n "checking how to convert $build file names to toolchain format... " >&6; } if ${lt_cv_to_tool_file_cmd+:} false; then : $as_echo_n "(cached) " >&6 else #assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac ;; esac fi to_tool_file_cmd=$lt_cv_to_tool_file_cmd { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 $as_echo "$lt_cv_to_tool_file_cmd" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 $as_echo_n "checking for $LD option to reload object files... " >&6; } if ${lt_cv_ld_reload_flag+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_reload_flag='-r' fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 $as_echo "$lt_cv_ld_reload_flag" >&6; } reload_flag=$lt_cv_ld_reload_flag case $reload_flag in "" | " "*) ;; *) reload_flag=" $reload_flag" ;; esac reload_cmds='$LD$reload_flag -o $output$reload_objs' case $host_os in cygwin* | mingw* | pw32* | cegcc*) if test "$GCC" != yes; then reload_cmds=false fi ;; darwin*) if test "$GCC" = yes; then reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' else reload_cmds='$LD$reload_flag -o $output$reload_objs' fi ;; esac if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. set dummy ${ac_tool_prefix}objdump; 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_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OBJDUMP"; then ac_cv_prog_OBJDUMP="$OBJDUMP" # 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_OBJDUMP="${ac_tool_prefix}objdump" $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 OBJDUMP=$ac_cv_prog_OBJDUMP if test -n "$OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 $as_echo "$OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OBJDUMP"; then ac_ct_OBJDUMP=$OBJDUMP # Extract the first word of "objdump", so it can be a program name with args. set dummy objdump; 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_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OBJDUMP"; then ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # 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_OBJDUMP="objdump" $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_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP if test -n "$ac_ct_OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 $as_echo "$ac_ct_OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OBJDUMP" = x; then OBJDUMP="false" 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 OBJDUMP=$ac_ct_OBJDUMP fi else OBJDUMP="$ac_cv_prog_OBJDUMP" fi test -z "$OBJDUMP" && OBJDUMP=objdump { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 $as_echo_n "checking how to recognize dependent libraries... " >&6; } if ${lt_cv_deplibs_check_method+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_file_magic_cmd='$MAGIC_CMD' lt_cv_file_magic_test_file= lt_cv_deplibs_check_method='unknown' # Need to set the preceding variable on all platforms that support # interlibrary dependencies. # 'none' -- dependencies not supported. # `unknown' -- same as none, but documents that we really don't know. # 'pass_all' -- all dependencies passed with no checks. # 'test_compile' -- check by making test program. # 'file_magic [[regex]]' -- check by looking for files in library path # which responds to the $file_magic_cmd with a given extended regex. # If you have `file' or equivalent on your system and you're not sure # whether `pass_all' will *always* work, you probably want this one. case $host_os in aix[4-9]*) lt_cv_deplibs_check_method=pass_all ;; beos*) lt_cv_deplibs_check_method=pass_all ;; bsdi[45]*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' lt_cv_file_magic_cmd='/usr/bin/file -L' lt_cv_file_magic_test_file=/shlib/libc.so ;; cygwin*) # func_win32_libid is a shell function defined in ltmain.sh lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' ;; mingw* | pw32*) # Base MSYS/MinGW do not provide the 'file' command needed by # func_win32_libid shell function, so use a weaker test based on 'objdump', # unless we find 'file', for example because we are cross-compiling. # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin. if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; gnu*) lt_cv_deplibs_check_method=pass_all ;; haiku*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[3-9]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu) lt_cv_deplibs_check_method=pass_all ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 $as_echo "$lt_cv_deplibs_check_method" >&6; } file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in mingw* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` fi ;; esac fi file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. set dummy ${ac_tool_prefix}dlltool; 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_DLLTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DLLTOOL"; then ac_cv_prog_DLLTOOL="$DLLTOOL" # 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_DLLTOOL="${ac_tool_prefix}dlltool" $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 DLLTOOL=$ac_cv_prog_DLLTOOL if test -n "$DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 $as_echo "$DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DLLTOOL"; then ac_ct_DLLTOOL=$DLLTOOL # Extract the first word of "dlltool", so it can be a program name with args. set dummy dlltool; 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_DLLTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DLLTOOL"; then ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # 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_DLLTOOL="dlltool" $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_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL if test -n "$ac_ct_DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 $as_echo "$ac_ct_DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DLLTOOL" = x; then DLLTOOL="false" 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 DLLTOOL=$ac_ct_DLLTOOL fi else DLLTOOL="$ac_cv_prog_DLLTOOL" fi test -z "$DLLTOOL" && DLLTOOL=dlltool { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 $as_echo_n "checking how to associate runtime and link libraries... " >&6; } if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh # decide which to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib ;; *) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback ;; esac ;; *) # fallback: assume linklib IS sharedlib lt_cv_sharedlib_from_linklib_cmd="$ECHO" ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 $as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; } sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO if test -n "$ac_tool_prefix"; then for ac_prog in ar 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_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # 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_AR="$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 AR=$ac_cv_prog_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AR" && break done fi if test -z "$AR"; then ac_ct_AR=$AR for ac_prog in ar 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_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # 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_AR="$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_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 $as_echo "$ac_ct_AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_AR" && break done if test "x$ac_ct_AR" = x; then AR="false" 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 AR=$ac_ct_AR fi fi : ${AR=ar} : ${AR_FLAGS=cru} { $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 $as_echo_n "checking for archiver @FILE support... " >&6; } if ${lt_cv_ar_at_file+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ar_at_file=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : echo conftest.$ac_objext > conftest.lst lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 (eval $lt_ar_try) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -eq 0; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 (eval $lt_ar_try) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -ne 0; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 $as_echo "$lt_cv_ar_at_file" >&6; } if test "x$lt_cv_ar_at_file" = xno; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $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 STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $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_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $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_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" 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 STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi test -z "$STRIP" && STRIP=: 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 test -z "$RANLIB" && RANLIB=: # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in darwin*) lock_old_archive_extraction=yes ;; *) lock_old_archive_extraction=no ;; esac # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Check for command to grab the raw symbol name followed by C symbol from nm. { $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 $as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } if ${lt_cv_sys_global_symbol_pipe+:} false; then : $as_echo_n "(cached) " >&6 else # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[BCDEGRST]' # Regexp to match symbols that can be accessed directly from C. sympat='\([_A-Za-z][_A-Za-z0-9]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[BCDT]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[ABCDGISTW]' ;; hpux*) if test "$host_cpu" = ia64; then symcode='[ABCDEGRST]' fi ;; irix* | nonstopux*) symcode='[BCDEGRST]' ;; osf*) symcode='[BCDEGQRST]' ;; solaris*) symcode='[BDRT]' ;; sco3.2v5*) symcode='[DT]' ;; sysv4.2uw2*) symcode='[DT]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[ABDT]' ;; sysv4) symcode='[DFNSTU]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[ABCDGIRSTW]' ;; esac # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function # and D for any global variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK '"\ " {last_section=section; section=\$ 3};"\ " /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ " {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ " s[1]~/^[@?]/{print s[1], s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # Now try to grab the symbols. nlist=conftest.nm if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5 (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT_DLSYM_CONST #elif defined(__osf__) /* This system does not cope well with relocations in const data. */ # define LT_DLSYM_CONST #else # define LT_DLSYM_CONST const #endif #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ LT_DLSYM_CONST struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&5 fi else echo "cannot find nm_test_var in $nlist" >&5 fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 fi else echo "$progname: failed program was:" >&5 cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= fi done fi if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 $as_echo "failed" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } fi # Response file support. if test "$lt_cv_nm_interface" = "MS dumpbin"; then nm_file_list_spec='@' elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then nm_file_list_spec='@' fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 $as_echo_n "checking for sysroot... " >&6; } # Check whether --with-sysroot was given. if test "${with_sysroot+set}" = set; then : withval=$with_sysroot; else with_sysroot=no fi lt_sysroot= case ${with_sysroot} in #( yes) if test "$GCC" = yes; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_sysroot}" >&5 $as_echo "${with_sysroot}" >&6; } as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 $as_echo "${lt_sysroot:-no}" >&6; } # Check whether --enable-libtool-lock was given. if test "${enable_libtool_lock+set}" = set; then : enableval=$enable_libtool_lock; fi test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" ;; *ELF-64*) HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '#line '$LINENO' "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_i386" ;; ppc64-*linux*|powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; ppc*-*linux*|powerpc*-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 $as_echo_n "checking whether the C compiler needs -belf... " >&6; } if ${lt_cv_cc_needs_belf+:} false; then : $as_echo_n "(cached) " >&6 else 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 cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_cc_needs_belf=yes else lt_cv_cc_needs_belf=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 $as_echo "$lt_cv_cc_needs_belf" >&6; } if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; *-*solaris*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*) LD="${LD-ld} -m elf_x86_64" ;; sparc*-*-solaris*) LD="${LD-ld} -m elf64_sparc" ;; esac # GNU ld 2.21 introduced _sol2 emulations. Use them if available. if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then LD="${LD-ld}_sol2" fi ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks="$enable_libtool_lock" if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. set dummy ${ac_tool_prefix}mt; 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_MANIFEST_TOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$MANIFEST_TOOL"; then ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # 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_MANIFEST_TOOL="${ac_tool_prefix}mt" $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 MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL if test -n "$MANIFEST_TOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 $as_echo "$MANIFEST_TOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_MANIFEST_TOOL"; then ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL # Extract the first word of "mt", so it can be a program name with args. set dummy mt; 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_MANIFEST_TOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_MANIFEST_TOOL"; then ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # 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_MANIFEST_TOOL="mt" $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_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL if test -n "$ac_ct_MANIFEST_TOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 $as_echo "$ac_ct_MANIFEST_TOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_MANIFEST_TOOL" = x; then MANIFEST_TOOL=":" 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 MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL fi else MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" fi test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 $as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } if ${lt_cv_path_mainfest_tool+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&5 if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 $as_echo "$lt_cv_path_mainfest_tool" >&6; } if test "x$lt_cv_path_mainfest_tool" != xyes; then MANIFEST_TOOL=: fi case $host_os in rhapsody* | darwin*) if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. set dummy ${ac_tool_prefix}dsymutil; 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_DSYMUTIL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DSYMUTIL"; then ac_cv_prog_DSYMUTIL="$DSYMUTIL" # 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_DSYMUTIL="${ac_tool_prefix}dsymutil" $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 DSYMUTIL=$ac_cv_prog_DSYMUTIL if test -n "$DSYMUTIL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 $as_echo "$DSYMUTIL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DSYMUTIL"; then ac_ct_DSYMUTIL=$DSYMUTIL # Extract the first word of "dsymutil", so it can be a program name with args. set dummy dsymutil; 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_DSYMUTIL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DSYMUTIL"; then ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # 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_DSYMUTIL="dsymutil" $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_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL if test -n "$ac_ct_DSYMUTIL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 $as_echo "$ac_ct_DSYMUTIL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DSYMUTIL" = x; then DSYMUTIL=":" 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 DSYMUTIL=$ac_ct_DSYMUTIL fi else DSYMUTIL="$ac_cv_prog_DSYMUTIL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. set dummy ${ac_tool_prefix}nmedit; 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_NMEDIT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NMEDIT"; then ac_cv_prog_NMEDIT="$NMEDIT" # 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_NMEDIT="${ac_tool_prefix}nmedit" $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 NMEDIT=$ac_cv_prog_NMEDIT if test -n "$NMEDIT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 $as_echo "$NMEDIT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_NMEDIT"; then ac_ct_NMEDIT=$NMEDIT # Extract the first word of "nmedit", so it can be a program name with args. set dummy nmedit; 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_NMEDIT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_NMEDIT"; then ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # 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_NMEDIT="nmedit" $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_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT if test -n "$ac_ct_NMEDIT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 $as_echo "$ac_ct_NMEDIT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_NMEDIT" = x; then NMEDIT=":" 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 NMEDIT=$ac_ct_NMEDIT fi else NMEDIT="$ac_cv_prog_NMEDIT" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. set dummy ${ac_tool_prefix}lipo; 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_LIPO+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$LIPO"; then ac_cv_prog_LIPO="$LIPO" # 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_LIPO="${ac_tool_prefix}lipo" $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 LIPO=$ac_cv_prog_LIPO if test -n "$LIPO"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 $as_echo "$LIPO" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_LIPO"; then ac_ct_LIPO=$LIPO # Extract the first word of "lipo", so it can be a program name with args. set dummy lipo; 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_LIPO+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_LIPO"; then ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # 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_LIPO="lipo" $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_LIPO=$ac_cv_prog_ac_ct_LIPO if test -n "$ac_ct_LIPO"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 $as_echo "$ac_ct_LIPO" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_LIPO" = x; then LIPO=":" 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 LIPO=$ac_ct_LIPO fi else LIPO="$ac_cv_prog_LIPO" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. set dummy ${ac_tool_prefix}otool; 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_OTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL"; then ac_cv_prog_OTOOL="$OTOOL" # 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_OTOOL="${ac_tool_prefix}otool" $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 OTOOL=$ac_cv_prog_OTOOL if test -n "$OTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 $as_echo "$OTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OTOOL"; then ac_ct_OTOOL=$OTOOL # Extract the first word of "otool", so it can be a program name with args. set dummy otool; 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_OTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL"; then ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # 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_OTOOL="otool" $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_OTOOL=$ac_cv_prog_ac_ct_OTOOL if test -n "$ac_ct_OTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 $as_echo "$ac_ct_OTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OTOOL" = x; then OTOOL=":" 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 OTOOL=$ac_ct_OTOOL fi else OTOOL="$ac_cv_prog_OTOOL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. set dummy ${ac_tool_prefix}otool64; 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_OTOOL64+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL64"; then ac_cv_prog_OTOOL64="$OTOOL64" # 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_OTOOL64="${ac_tool_prefix}otool64" $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 OTOOL64=$ac_cv_prog_OTOOL64 if test -n "$OTOOL64"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 $as_echo "$OTOOL64" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OTOOL64"; then ac_ct_OTOOL64=$OTOOL64 # Extract the first word of "otool64", so it can be a program name with args. set dummy otool64; 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_OTOOL64+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL64"; then ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # 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_OTOOL64="otool64" $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_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 if test -n "$ac_ct_OTOOL64"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 $as_echo "$ac_ct_OTOOL64" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OTOOL64" = x; then OTOOL64=":" 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 OTOOL64=$ac_ct_OTOOL64 fi else OTOOL64="$ac_cv_prog_OTOOL64" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 $as_echo_n "checking for -single_module linker flag... " >&6; } if ${lt_cv_apple_cc_single_mod+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_apple_cc_single_mod=no if test -z "${LT_MULTI_MODULE}"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&5 $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? # If there is a non-empty error log, and "single_module" # appears in it, assume the flag caused a linker warning if test -s conftest.err && $GREP single_module conftest.err; then cat conftest.err >&5 # Otherwise, if the output was created with a 0 exit code from # the compiler, it worked. elif test -f libconftest.dylib && test $_lt_result -eq 0; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&5 fi rm -rf libconftest.dylib* rm -f conftest.* fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 $as_echo "$lt_cv_apple_cc_single_mod" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 $as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } if ${lt_cv_ld_exported_symbols_list+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_ld_exported_symbols_list=yes else lt_cv_ld_exported_symbols_list=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 $as_echo "$lt_cv_ld_exported_symbols_list" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 $as_echo_n "checking for -force_load linker flag... " >&6; } if ${lt_cv_ld_force_load+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 echo "$AR cru libconftest.a conftest.o" >&5 $AR cru libconftest.a conftest.o 2>&5 echo "$RANLIB libconftest.a" >&5 $RANLIB libconftest.a 2>&5 cat > conftest.c << _LT_EOF int main() { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err _lt_result=$? if test -s conftest.err && $GREP force_load conftest.err; then cat conftest.err >&5 elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then lt_cv_ld_force_load=yes else cat conftest.err >&5 fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 $as_echo "$lt_cv_ld_force_load" >&6; } case $host_os in rhapsody* | darwin1.[012]) _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[91]*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; 10.[012]*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test "$lt_cv_apple_cc_single_mod" = "yes"; then _lt_dar_single_mod='$single_module' fi if test "$lt_cv_ld_exported_symbols_list" = "yes"; then _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' fi if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac 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 ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in dlfcn.h do : ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default " if test "x$ac_cv_header_dlfcn_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_DLFCN_H 1 _ACEOF fi done # Set options enable_dlopen=no enable_win32_dll=no # Check whether --enable-static was given. if test "${enable_static+set}" = set; then : enableval=$enable_static; p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$lt_save_ifs" ;; esac else enable_static=yes fi # Check whether --with-pic was given. if test "${with_pic+set}" = set; then : withval=$with_pic; lt_p=${PACKAGE-default} case $withval in yes|no) pic_mode=$withval ;; *) pic_mode=default # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for lt_pkg in $withval; do IFS="$lt_save_ifs" if test "X$lt_pkg" = "X$lt_p"; then pic_mode=yes fi done IFS="$lt_save_ifs" ;; esac else pic_mode=default fi test -z "$pic_mode" && pic_mode=default # Check whether --enable-fast-install was given. if test "${enable_fast_install+set}" = set; then : enableval=$enable_fast_install; p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$lt_save_ifs" ;; esac else enable_fast_install=yes fi # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ltmain" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' test -z "$LN_S" && LN_S="ln -s" if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 $as_echo_n "checking for objdir... " >&6; } if ${lt_cv_objdir+:} false; then : $as_echo_n "(cached) " >&6 else rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 $as_echo "$lt_cv_objdir" >&6; } objdir=$lt_cv_objdir cat >>confdefs.h <<_ACEOF #define LT_OBJDIR "$lt_cv_objdir/" _ACEOF case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld="$lt_cv_prog_gnu_ld" old_CC="$CC" old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o for cc_temp in $compiler""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 $as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/${ac_tool_prefix}file; then lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac fi MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 $as_echo_n "checking for file... " >&6; } if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/file; then lt_cv_path_MAGIC_CMD="$ac_dir/file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac fi MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi else MAGIC_CMD=: fi fi fi ;; esac # Use C for the default configuration in the libtool script lt_save_CC="$CC" 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 # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o objext=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* if test -n "$compiler"; then lt_prog_compiler_no_builtin_flag= if test "$GCC" = yes; then case $cc_basename in nvcc*) lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; *) lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 $as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_rtti_exceptions=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-fno-rtti -fno-exceptions" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_rtti_exceptions=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 $as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" else : fi fi lt_prog_compiler_wl= lt_prog_compiler_pic= lt_prog_compiler_static= if test "$GCC" = yes; then lt_prog_compiler_wl='-Wl,' lt_prog_compiler_static='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support lt_prog_compiler_pic='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries lt_prog_compiler_pic='-DDLL_EXPORT' ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic='-fno-common' ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. lt_prog_compiler_static= ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) lt_prog_compiler_pic='-fPIC' ;; esac ;; interix[3-9]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. lt_prog_compiler_can_build_shared=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic=-Kconform_pic fi ;; *) lt_prog_compiler_pic='-fPIC' ;; esac case $cc_basename in nvcc*) # Cuda Compiler Driver 2.2 lt_prog_compiler_wl='-Xlinker ' if test -n "$lt_prog_compiler_pic"; then lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" fi ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) lt_prog_compiler_wl='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' else lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic='-DDLL_EXPORT' ;; hpux9* | hpux10* | hpux11*) lt_prog_compiler_wl='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? lt_prog_compiler_static='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) lt_prog_compiler_wl='-Wl,' # PIC (with -KPIC) is the default. lt_prog_compiler_static='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in # old Intel for x86_64 which still supported -KPIC. ecc*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; # Lahey Fortran 8.1. lf95*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='--shared' lt_prog_compiler_static='--static' ;; nagfor*) # NAG Fortran compiler lt_prog_compiler_wl='-Wl,-Wl,,' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fpic' lt_prog_compiler_static='-Bstatic' ;; ccc*) lt_prog_compiler_wl='-Wl,' # All Alpha code is PIC. lt_prog_compiler_static='-non_shared' ;; xl* | bgxl* | bgf* | mpixl*) # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-qpic' lt_prog_compiler_static='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) # Sun Fortran 8.3 passes all unrecognized flags to the linker lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='' ;; *Sun\ F* | *Sun*Fortran*) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='-Qoption ld ' ;; *Sun\ C*) # Sun C 5.9 lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='-Wl,' ;; *Intel*\ [CF]*Compiler*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; *Portland\ Group*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fpic' lt_prog_compiler_static='-Bstatic' ;; esac ;; esac ;; newsos6) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic='-fPIC -shared' ;; osf3* | osf4* | osf5*) lt_prog_compiler_wl='-Wl,' # All OSF/1 code is PIC. lt_prog_compiler_static='-non_shared' ;; rdos*) lt_prog_compiler_static='-non_shared' ;; solaris*) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) lt_prog_compiler_wl='-Qoption ld ';; *) lt_prog_compiler_wl='-Wl,';; esac ;; sunos4*) lt_prog_compiler_wl='-Qoption ld ' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then lt_prog_compiler_pic='-Kconform_pic' lt_prog_compiler_static='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; unicos*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_can_build_shared=no ;; uts4*) lt_prog_compiler_pic='-pic' lt_prog_compiler_static='-Bstatic' ;; *) lt_prog_compiler_can_build_shared=no ;; esac fi case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic= ;; *) lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 $as_echo_n "checking for $compiler option to produce PIC... " >&6; } if ${lt_cv_prog_compiler_pic+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic=$lt_prog_compiler_pic fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 $as_echo "$lt_cv_prog_compiler_pic" >&6; } lt_prog_compiler_pic=$lt_cv_prog_compiler_pic # # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 $as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } if ${lt_cv_prog_compiler_pic_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic_works=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic -DPIC" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_pic_works=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 $as_echo "$lt_cv_prog_compiler_pic_works" >&6; } if test x"$lt_cv_prog_compiler_pic_works" = xyes; then case $lt_prog_compiler_pic in "" | " "*) ;; *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; esac else lt_prog_compiler_pic= lt_prog_compiler_can_build_shared=no fi fi # # Check to make sure the static flag actually works. # wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 $as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } if ${lt_cv_prog_compiler_static_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_static_works=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $lt_tmp_static_flag" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_static_works=yes fi else lt_cv_prog_compiler_static_works=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 $as_echo "$lt_cv_prog_compiler_static_works" >&6; } if test x"$lt_cv_prog_compiler_static_works" = xyes; then : else lt_prog_compiler_static= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } hard_links="nottested" if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 $as_echo_n "checking if we can lock with hard links... " >&6; } hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 $as_echo "$hard_links" >&6; } if test "$hard_links" = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 $as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} need_locks=warn fi else need_locks=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } runpath_var= allow_undefined_flag= always_export_symbols=no archive_cmds= archive_expsym_cmds= compiler_needs_object=no enable_shared_with_static_runtimes=no export_dynamic_flag_spec= export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' hardcode_automatic=no hardcode_direct=no hardcode_direct_absolute=no hardcode_libdir_flag_spec= hardcode_libdir_separator= hardcode_minus_L=no hardcode_shlibpath_var=unsupported inherit_rpath=no link_all_deplibs=unknown module_cmds= module_expsym_cmds= old_archive_from_new_cmds= old_archive_from_expsyms_cmds= thread_safe_flag_spec= whole_archive_flag_spec= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list include_expsyms= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; esac ld_shlibs=yes # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no if test "$with_gnu_ld" = yes; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility # with the native linker. However, as the warning in the GNU ld # block says, versions before 2.19.5* couldn't really create working # shared libraries, regardless of the interface used. case `$LD -v 2>&1` in *\ \(GNU\ Binutils\)\ 2.19.5*) ;; *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; *\ \(GNU\ Binutils\)\ [3-9]*) ;; *) lt_use_gnu_ld_interface=yes ;; esac ;; *) lt_use_gnu_ld_interface=yes ;; esac fi if test "$lt_use_gnu_ld_interface" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' export_dynamic_flag_spec='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else whole_archive_flag_spec= fi supports_anon_versioning=no case `$LD -v 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[3-9]*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.19, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to install binutils *** 2.20 or above, or modify your PATH so that a non-GNU linker is found. *** You will then need to restart the configuration process. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then allow_undefined_flag=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else ld_shlibs=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' export_dynamic_flag_spec='${wl}--export-all-symbols' allow_undefined_flag=unsupported always_export_symbols=no enable_shared_with_static_runtimes=yes export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else ld_shlibs=no fi ;; haiku*) archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' link_all_deplibs=yes ;; interix[3-9]*) hardcode_direct=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='${wl}-rpath,$libdir' export_dynamic_flag_spec='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test "$host_os" = linux-dietlibc; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test "$tmp_diet" = no then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 whole_archive_flag_spec= tmp_sharedflag='--shared' ;; xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' compiler_needs_object=yes ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' compiler_needs_object=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi case $cc_basename in xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test "x$supports_anon_versioning" = xyes; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else ld_shlibs=no fi ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac ;; sunos4*) archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= hardcode_direct=yes hardcode_shlibpath_var=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac if test "$ld_shlibs" = no; then runpath_var= hardcode_libdir_flag_spec= export_dynamic_flag_spec= whole_archive_flag_spec= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) allow_undefined_flag=unsupported always_export_symbols=yes archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L=yes if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct=unsupported fi ;; aix[4-9]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global # defined symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. archive_cmds='' hardcode_direct=yes hardcode_direct_absolute=yes hardcode_libdir_separator=':' link_all_deplibs=yes file_list_spec='${wl}-f,' if test "$GCC" = yes; then case $host_os in aix4.[012]|aix4.[012].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 hardcode_direct=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking hardcode_minus_L=yes hardcode_libdir_flag_spec='-L$libdir' hardcode_libdir_separator= fi ;; esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi export_dynamic_flag_spec='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. always_export_symbols=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. allow_undefined_flag='-berok' # Determine the default libpath from the value encoded in an # empty executable. if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath_+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_="/usr/lib:/lib" fi fi aix_libpath=$lt_cv_aix_libpath_ fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' allow_undefined_flag="-z nodefs" archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath_+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_="/usr/lib:/lib" fi fi aix_libpath=$lt_cv_aix_libpath_ fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag=' ${wl}-bernotok' allow_undefined_flag=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec='$convenience' fi archive_cmds_need_lc=yes # This is similar to how AIX traditionally builds its shared libraries. archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; esac ;; bsdi[45]*) export_dynamic_flag_spec=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl*) # Native MSVC hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported always_export_symbols=yes file_list_spec='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, )='true' enable_shared_with_static_runtimes=yes exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' # Don't use ranlib old_postinstall_cmds='chmod 644 $oldlib' postlink_cmds='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # Assume MSVC wrapper hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. old_archive_from_new_cmds='true' # FIXME: Should let the user specify the lib program. old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' enable_shared_with_static_runtimes=yes ;; esac ;; darwin* | rhapsody*) archive_cmds_need_lc=no hardcode_direct=no hardcode_automatic=yes hardcode_shlibpath_var=unsupported if test "$lt_cv_ld_force_load" = "yes"; then whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' else whole_archive_flag_spec='' fi link_all_deplibs=yes allow_undefined_flag="$_lt_dar_allow_undefined" case $cc_basename in ifort*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then output_verbose_link_cmd=func_echo_all archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" else ld_shlibs=no fi ;; dgux*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2.*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; hpux9*) if test "$GCC" = yes; then archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes export_dynamic_flag_spec='${wl}-E' ;; hpux10*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes hardcode_direct_absolute=yes export_dynamic_flag_spec='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes fi ;; hpux11*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) # Older versions of the 11.00 compiler do not understand -b yet # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 $as_echo_n "checking if $CC understands -b... " >&6; } if ${lt_cv_prog_compiler__b+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler__b=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -b" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler__b=yes fi else lt_cv_prog_compiler__b=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 $as_echo "$lt_cv_prog_compiler__b" >&6; } if test x"$lt_cv_prog_compiler__b" = xyes; then archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi ;; esac fi if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: case $host_cpu in hppa*64*|ia64*) hardcode_direct=no hardcode_shlibpath_var=no ;; *) hardcode_direct=yes hardcode_direct_absolute=yes export_dynamic_flag_spec='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. # This should be the same for all languages, so no per-tag cache variable. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 $as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; } if ${lt_cv_irix_exported_symbol+:} false; then : $as_echo_n "(cached) " >&6 else save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int foo (void) { return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_irix_exported_symbol=yes else lt_cv_irix_exported_symbol=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 $as_echo "$lt_cv_irix_exported_symbol" >&6; } if test "$lt_cv_irix_exported_symbol" = yes; then archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' fi else archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: inherit_rpath=yes link_all_deplibs=yes ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; newsos6) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: hardcode_shlibpath_var=no ;; *nto* | *qnx*) ;; openbsd*) if test -f /usr/libexec/ld.so; then hardcode_direct=yes hardcode_shlibpath_var=no hardcode_direct_absolute=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' export_dynamic_flag_spec='${wl}-E' else case $host_os in openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-R$libdir' ;; *) archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ;; esac fi else ld_shlibs=no fi ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' archive_cmds='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly hardcode_libdir_flag_spec='-rpath $libdir' fi archive_cmds_need_lc='no' hardcode_libdir_separator=: ;; solaris*) no_undefined_flag=' -z defs' if test "$GCC" = yes; then wlarc='${wl}' archive_cmds='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='${wl}' archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi hardcode_libdir_flag_spec='-R$libdir' hardcode_shlibpath_var=no case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. GCC discards it without `$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test "$GCC" = yes; then whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' else whole_archive_flag_spec='-z allextract$convenience -z defaultextract' fi ;; esac link_all_deplibs=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi hardcode_libdir_flag_spec='-L$libdir' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; sysv4) case $host_vendor in sni) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' reload_cmds='$CC -r -o $output$reload_objs' hardcode_direct=no ;; motorola) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' hardcode_shlibpath_var=no ;; sysv4.3*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no export_dynamic_flag_spec='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes ld_shlibs=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) no_undefined_flag='${wl}-z,text' archive_cmds_need_lc=no hardcode_shlibpath_var=no runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. no_undefined_flag='${wl}-z,text' allow_undefined_flag='${wl}-z,nodefs' archive_cmds_need_lc=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='${wl}-R,$libdir' hardcode_libdir_separator=':' link_all_deplibs=yes export_dynamic_flag_spec='${wl}-Bexport' runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; *) ld_shlibs=no ;; esac if test x$host_vendor = xsni; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) export_dynamic_flag_spec='${wl}-Blargedynsym' ;; esac fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 $as_echo "$ld_shlibs" >&6; } test "$ld_shlibs" = no && can_build_shared=no with_gnu_ld=$with_gnu_ld # # Do we need to explicitly link libc? # case "x$archive_cmds_need_lc" in x|xyes) # Assume -lc should be added archive_cmds_need_lc=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $archive_cmds in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } if ${lt_cv_archive_cmds_need_lc+:} false; then : $as_echo_n "(cached) " >&6 else $RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$lt_prog_compiler_wl pic_flag=$lt_prog_compiler_pic compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag allow_undefined_flag= if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then lt_cv_archive_cmds_need_lc=no else lt_cv_archive_cmds_need_lc=yes fi allow_undefined_flag=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 $as_echo "$lt_cv_archive_cmds_need_lc" >&6; } archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc ;; esac fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 $as_echo_n "checking dynamic linker characteristics... " >&6; } if test "$GCC" = yes; then case $host_os in darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; *) lt_awk_arg="/^libraries:/" ;; esac case $host_os in mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;; *) lt_sed_strip_eq="s,=/,/,g" ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ;; *) lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ;; esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary. lt_tmp_lt_search_path_spec= lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path/$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" else test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS=" "; FS="/|\n";} { lt_foo=""; lt_count=0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo="/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[lt_foo]++; } if (lt_freq[lt_foo] == 1) { print lt_foo; } }'` # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's,/\([A-Za-z]:\),\1,g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix[4-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[45]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' library_names_spec='${libname}.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec="$LIB" if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[23].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[01]* | freebsdelf3.[01]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=yes sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[3-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH if ${lt_cv_shlibpath_overrides_runpath+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : lt_cv_shlibpath_overrides_runpath=yes fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS libdir=$save_libdir fi shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[89] | openbsd2.[89].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 $as_echo "$dynamic_linker" >&6; } test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 $as_echo_n "checking how to hardcode library paths into programs... " >&6; } hardcode_action= if test -n "$hardcode_libdir_flag_spec" || test -n "$runpath_var" || test "X$hardcode_automatic" = "Xyes" ; then # We can hardcode non-existent directories. if test "$hardcode_direct" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no && test "$hardcode_minus_L" != no; then # Linking always hardcodes the temporary library directory. hardcode_action=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action=unsupported fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 $as_echo "$hardcode_action" >&6; } if test "$hardcode_action" = relink || test "$inherit_rpath" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $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 dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=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_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes fi ;; *) ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" if test "x$ac_cv_func_shl_load" = xyes; then : lt_cv_dlopen="shl_load" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } if ${ac_cv_lib_dld_shl_load+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char shl_load (); int main () { return shl_load (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_shl_load=yes else ac_cv_lib_dld_shl_load=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 $as_echo "$ac_cv_lib_dld_shl_load" >&6; } if test "x$ac_cv_lib_dld_shl_load" = xyes; then : lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" else ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" if test "x$ac_cv_func_dlopen" = xyes; then : lt_cv_dlopen="dlopen" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $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 dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=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_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 $as_echo_n "checking for dlopen in -lsvld... " >&6; } if ${ac_cv_lib_svld_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsvld $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 dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_svld_dlopen=yes else ac_cv_lib_svld_dlopen=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_svld_dlopen" >&5 $as_echo "$ac_cv_lib_svld_dlopen" >&6; } if test "x$ac_cv_lib_svld_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 $as_echo_n "checking for dld_link in -ldld... " >&6; } if ${ac_cv_lib_dld_dld_link+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dld_link (); int main () { return dld_link (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_dld_link=yes else ac_cv_lib_dld_dld_link=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 $as_echo "$ac_cv_lib_dld_dld_link" >&6; } if test "x$ac_cv_lib_dld_dld_link" = xyes; then : lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" fi fi fi fi fi fi ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 $as_echo_n "checking whether a program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisbility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; esac else : # compilation failed lt_cv_dlopen_self=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 $as_echo "$lt_cv_dlopen_self" >&6; } if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 $as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self_static+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisbility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; esac else : # compilation failed lt_cv_dlopen_self_static=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 $as_echo "$lt_cv_dlopen_self_static" >&6; } fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi striplib= old_striplib= { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 $as_echo_n "checking whether stripping libraries is possible... " >&6; } if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" old_striplib="$STRIP -S" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ;; esac fi # Report which library types will actually be built { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 $as_echo_n "checking if libtool supports shared libraries... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 $as_echo "$can_build_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 $as_echo_n "checking whether to build shared libraries... " >&6; } test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[4-9]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 $as_echo "$enable_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 $as_echo_n "checking whether to build static libraries... " >&6; } # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 $as_echo "$enable_static" >&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 CC="$lt_save_CC" ac_config_commands="$ac_config_commands libtool" # Only expand once: { $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 $as_echo_n "checking for an ANSI C-conforming const... " >&6; } if ${ac_cv_c_const+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __cplusplus /* Ultrix mips cc rejects this sort of thing. */ typedef int charset[2]; const charset cs = { 0, 0 }; /* SunOS 4.1.1 cc rejects this. */ char const *const *pcpcc; char **ppc; /* NEC SVR4.0.2 mips cc rejects this. */ struct point {int x, y;}; static struct point const zero = {0,0}; /* AIX XL C 1.02.0.0 rejects this. It does not let you subtract one const X* pointer from another in an arm of an if-expression whose if-part is not a constant expression */ const char *g = "string"; pcpcc = &g + (g ? g-g : 0); /* HPUX 7.0 cc rejects these. */ ++pcpcc; ppc = (char**) pcpcc; pcpcc = (char const *const *) ppc; { /* SCO 3.2v4 cc rejects this sort of thing. */ char tx; char *t = &tx; char const *s = 0 ? (char *) 0 : (char const *) 0; *t++ = 0; if (s) return 0; } { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ int x[] = {25, 17}; const int *foo = &x[0]; ++foo; } { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ typedef const int *iptr; iptr p = 0; ++p; } { /* AIX XL C 1.02.0.0 rejects this sort of thing, saying "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ struct s { int j; const int *ap[3]; } bx; struct s *b = &bx; b->j = 5; } { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ const int foo = 10; if (!foo) return 0; } return !cs[0] && !zero.x; #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_const=yes else ac_cv_c_const=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 $as_echo "$ac_cv_c_const" >&6; } if test $ac_cv_c_const = no; then $as_echo "#define const /**/" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for unsigned long long int" >&5 $as_echo_n "checking for unsigned long long int... " >&6; } if ${ac_cv_type_unsigned_long_long_int+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_type_unsigned_long_long_int=yes if test "x${ac_cv_prog_cc_c99-no}" = xno; then cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* For now, do not test the preprocessor; as of 2007 there are too many implementations with broken preprocessors. Perhaps this can be revisited in 2012. In the meantime, code should not expect #if to work with literals wider than 32 bits. */ /* Test literals. */ long long int ll = 9223372036854775807ll; long long int nll = -9223372036854775807LL; unsigned long long int ull = 18446744073709551615ULL; /* Test constant expressions. */ typedef int a[((-9223372036854775807LL < 0 && 0 < 9223372036854775807ll) ? 1 : -1)]; typedef int b[(18446744073709551615ULL <= (unsigned long long int) -1 ? 1 : -1)]; int i = 63; int main () { /* Test availability of runtime routines for shift and division. */ long long int llmax = 9223372036854775807ll; unsigned long long int ullmax = 18446744073709551615ull; return ((ll << 63) | (ll >> 63) | (ll < i) | (ll > i) | (llmax / ll) | (llmax % ll) | (ull << 63) | (ull >> 63) | (ull << i) | (ull >> i) | (ullmax / ull) | (ullmax % ull)); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : else ac_cv_type_unsigned_long_long_int=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_unsigned_long_long_int" >&5 $as_echo "$ac_cv_type_unsigned_long_long_int" >&6; } if test $ac_cv_type_unsigned_long_long_int = yes; then $as_echo "#define HAVE_UNSIGNED_LONG_LONG_INT 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for long long int" >&5 $as_echo_n "checking for long long int... " >&6; } if ${ac_cv_type_long_long_int+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_type_long_long_int=yes if test "x${ac_cv_prog_cc_c99-no}" = xno; then ac_cv_type_long_long_int=$ac_cv_type_unsigned_long_long_int if test $ac_cv_type_long_long_int = yes; then if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #ifndef LLONG_MAX # define HALF \ (1LL << (sizeof (long long int) * CHAR_BIT - 2)) # define LLONG_MAX (HALF - 1 + HALF) #endif int main () { long long int n = 1; int i; for (i = 0; ; i++) { long long int m = n << i; if (m >> i != n) return 1; if (LLONG_MAX / 2 < m) break; } return 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_type_long_long_int=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 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_long_long_int" >&5 $as_echo "$ac_cv_type_long_long_int" >&6; } if test $ac_cv_type_long_long_int = yes; then $as_echo "#define HAVE_LONG_LONG_INT 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing ioperm" >&5 $as_echo_n "checking for library containing ioperm... " >&6; } if ${ac_cv_search_ioperm+:} 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 ioperm (); int main () { return ioperm (); ; return 0; } _ACEOF for ac_lib in '' ioperm; 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_ioperm=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_ioperm+:} false; then : break fi done if ${ac_cv_search_ioperm+:} false; then : else ac_cv_search_ioperm=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_ioperm" >&5 $as_echo "$ac_cv_search_ioperm" >&6; } ac_res=$ac_cv_search_ioperm if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing dlopen" >&5 $as_echo_n "checking for library containing dlopen... " >&6; } if ${ac_cv_search_dlopen+:} 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 dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF for ac_lib in '' dl; 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_dlopen=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_dlopen+:} false; then : break fi done if ${ac_cv_search_dlopen+:} false; then : else ac_cv_search_dlopen=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dlopen" >&5 $as_echo "$ac_cv_search_dlopen" >&6; } ac_res=$ac_cv_search_dlopen if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi for ac_header in sys/socket.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/socket.h" "ac_cv_header_sys_socket_h" "$ac_includes_default" if test "x$ac_cv_header_sys_socket_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_SOCKET_H 1 _ACEOF fi done for ac_header in arpa/inet.h do : ac_fn_c_check_header_compile "$LINENO" "arpa/inet.h" "ac_cv_header_arpa_inet_h" "#include #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_SYS_SOCKET_H # include #endif " if test "x$ac_cv_header_arpa_inet_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_ARPA_INET_H 1 _ACEOF fi done for ac_header in elf.h do : ac_fn_c_check_header_mongrel "$LINENO" "elf.h" "ac_cv_header_elf_h" "$ac_includes_default" if test "x$ac_cv_header_elf_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_ELF_H 1 _ACEOF fi done for ac_header in dirent.h do : ac_fn_c_check_header_mongrel "$LINENO" "dirent.h" "ac_cv_header_dirent_h" "$ac_includes_default" if test "x$ac_cv_header_dirent_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_DIRENT_H 1 _ACEOF fi done for ac_header in fcntl.h do : ac_fn_c_check_header_mongrel "$LINENO" "fcntl.h" "ac_cv_header_fcntl_h" "$ac_includes_default" if test "x$ac_cv_header_fcntl_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_FCNTL_H 1 _ACEOF fi done for ac_header in ifaddrs.h do : ac_fn_c_check_header_compile "$LINENO" "ifaddrs.h" "ac_cv_header_ifaddrs_h" "#include #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_SYS_SOCKET_H # include #endif " if test "x$ac_cv_header_ifaddrs_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_IFADDRS_H 1 _ACEOF fi done for ac_header in malloc.h do : ac_fn_c_check_header_mongrel "$LINENO" "malloc.h" "ac_cv_header_malloc_h" "$ac_includes_default" if test "x$ac_cv_header_malloc_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_MALLOC_H 1 _ACEOF fi done for ac_header in netdb.h do : ac_fn_c_check_header_mongrel "$LINENO" "netdb.h" "ac_cv_header_netdb_h" "$ac_includes_default" if test "x$ac_cv_header_netdb_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_NETDB_H 1 _ACEOF fi done for ac_header in netinet/in.h do : ac_fn_c_check_header_compile "$LINENO" "netinet/in.h" "ac_cv_header_netinet_in_h" "#include #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_SYS_SOCKET_H # include #endif " if test "x$ac_cv_header_netinet_in_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_NETINET_IN_H 1 _ACEOF fi done for ac_header in netinet/tcp.h do : ac_fn_c_check_header_compile "$LINENO" "netinet/tcp.h" "ac_cv_header_netinet_tcp_h" "#include #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_SYS_SOCKET_H # include #endif " if test "x$ac_cv_header_netinet_tcp_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_NETINET_TCP_H 1 _ACEOF fi done for ac_header in pthread.h do : ac_fn_c_check_header_mongrel "$LINENO" "pthread.h" "ac_cv_header_pthread_h" "$ac_includes_default" if test "x$ac_cv_header_pthread_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_PTHREAD_H 1 _ACEOF fi done for ac_header in strings.h do : ac_fn_c_check_header_mongrel "$LINENO" "strings.h" "ac_cv_header_strings_h" "$ac_includes_default" if test "x$ac_cv_header_strings_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRINGS_H 1 _ACEOF fi done for ac_header in sys/ioctl.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/ioctl.h" "ac_cv_header_sys_ioctl_h" "$ac_includes_default" if test "x$ac_cv_header_sys_ioctl_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_IOCTL_H 1 _ACEOF fi done for ac_header in sys/param.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/param.h" "ac_cv_header_sys_param_h" "$ac_includes_default" if test "x$ac_cv_header_sys_param_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_PARAM_H 1 _ACEOF fi done for ac_header in sys/poll.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/poll.h" "ac_cv_header_sys_poll_h" "$ac_includes_default" if test "x$ac_cv_header_sys_poll_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_POLL_H 1 _ACEOF fi done for ac_header in sys/select.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/select.h" "ac_cv_header_sys_select_h" "$ac_includes_default" if test "x$ac_cv_header_sys_select_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_SELECT_H 1 _ACEOF fi done for ac_header in sys/stat.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/stat.h" "ac_cv_header_sys_stat_h" "$ac_includes_default" if test "x$ac_cv_header_sys_stat_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_STAT_H 1 _ACEOF fi done for ac_header in sys/time.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/time.h" "ac_cv_header_sys_time_h" "$ac_includes_default" if test "x$ac_cv_header_sys_time_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_TIME_H 1 _ACEOF fi done for ac_header in sys/types.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$ac_includes_default" if test "x$ac_cv_header_sys_types_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_TYPES_H 1 _ACEOF fi done for ac_header in unistd.h do : ac_fn_c_check_header_mongrel "$LINENO" "unistd.h" "ac_cv_header_unistd_h" "$ac_includes_default" if test "x$ac_cv_header_unistd_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_UNISTD_H 1 _ACEOF fi done for ac_header in net/if.h do : ac_fn_c_check_header_compile "$LINENO" "net/if.h" "ac_cv_header_net_if_h" "#include #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_SYS_SOCKET_H # include #endif " if test "x$ac_cv_header_net_if_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_NET_IF_H 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable assertions" >&5 $as_echo_n "checking whether to enable assertions... " >&6; } # Check whether --enable-assert was given. if test "${enable_assert+set}" = set; then : enableval=$enable_assert; ac_enable_assert=$enableval if test "x$enableval" = xno; then : $as_echo "#define NDEBUG 1" >>confdefs.h elif test "x$enableval" != xyes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: invalid argument supplied to --enable-assert" >&5 $as_echo "$as_me: WARNING: invalid argument supplied to --enable-assert" >&2;} ac_enable_assert=yes fi else ac_enable_assert=yes fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_enable_assert" >&5 $as_echo "$ac_enable_assert" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdbool.h that conforms to C99" >&5 $as_echo_n "checking for stdbool.h that conforms to C99... " >&6; } if ${ac_cv_header_stdbool_h+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #ifndef bool "error: bool is not defined" #endif #ifndef false "error: false is not defined" #endif #if false "error: false is not 0" #endif #ifndef true "error: true is not defined" #endif #if true != 1 "error: true is not 1" #endif #ifndef __bool_true_false_are_defined "error: __bool_true_false_are_defined is not defined" #endif struct s { _Bool s: 1; _Bool t; } s; char a[true == 1 ? 1 : -1]; char b[false == 0 ? 1 : -1]; char c[__bool_true_false_are_defined == 1 ? 1 : -1]; char d[(bool) 0.5 == true ? 1 : -1]; /* See body of main program for 'e'. */ char f[(_Bool) 0.0 == false ? 1 : -1]; char g[true]; char h[sizeof (_Bool)]; char i[sizeof s.t]; enum { j = false, k = true, l = false * true, m = true * 256 }; /* The following fails for HP aC++/ANSI C B3910B A.05.55 [Dec 04 2003]. */ _Bool n[m]; char o[sizeof n == m * sizeof n[0] ? 1 : -1]; char p[-1 - (_Bool) 0 < 0 && -1 - (bool) 0 < 0 ? 1 : -1]; /* Catch a bug in an HP-UX C compiler. See http://gcc.gnu.org/ml/gcc-patches/2003-12/msg02303.html http://lists.gnu.org/archive/html/bug-coreutils/2005-11/msg00161.html */ _Bool q = true; _Bool *pq = &q; int main () { bool e = &s; *pq |= q; *pq |= ! q; /* Refer to every declared value, to avoid compiler optimizations. */ return (!a + !b + !c + !d + !e + !f + !g + !h + !i + !!j + !k + !!l + !m + !n + !o + !p + !q + !pq); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdbool_h=yes else ac_cv_header_stdbool_h=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdbool_h" >&5 $as_echo "$ac_cv_header_stdbool_h" >&6; } ac_fn_c_check_type "$LINENO" "_Bool" "ac_cv_type__Bool" "$ac_includes_default" if test "x$ac_cv_type__Bool" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE__BOOL 1 _ACEOF fi if test $ac_cv_header_stdbool_h = yes; then $as_echo "#define HAVE_STDBOOL_H 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time.h and sys/time.h may both be included" >&5 $as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; } if ${ac_cv_header_time+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include int main () { if ((struct tm *) 0) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_time=yes else ac_cv_header_time=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_time" >&5 $as_echo "$ac_cv_header_time" >&6; } if test $ac_cv_header_time = yes; then $as_echo "#define TIME_WITH_SYS_TIME 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 $as_echo_n "checking whether byte ordering is bigendian... " >&6; } if ${ac_cv_c_bigendian+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_c_bigendian=unknown # See if we're dealing with a universal compiler. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __APPLE_CC__ not a universal capable compiler #endif typedef int dummy; _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # Check for potential -arch flags. It is not universal unless # there are at least two -arch flags with different values. ac_arch= ac_prev= for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do if test -n "$ac_prev"; then case $ac_word in i?86 | x86_64 | ppc | ppc64) if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then ac_arch=$ac_word else ac_cv_c_bigendian=universal break fi ;; esac ac_prev= elif test "x$ac_word" = "x-arch"; then ac_prev=arch fi done fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_c_bigendian = unknown; then # See if sys/param.h defines the BYTE_ORDER macro. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { #if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ && LITTLE_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # It does; now see whether it defined to BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { #if BYTE_ORDER != BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_bigendian=yes else ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # See if defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { #if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # It does; now see whether it defined to _BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { #ifndef _BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_bigendian=yes else ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # Compile a test program. if test "$cross_compiling" = yes; then : # Try to guess by grepping values from an object file. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; int use_ascii (int i) { return ascii_mm[i] + ascii_ii[i]; } short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; int use_ebcdic (int i) { return ebcdic_mm[i] + ebcdic_ii[i]; } extern int foo; int main () { return use_ascii (foo) == use_ebcdic (foo); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then ac_cv_c_bigendian=yes fi if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then if test "$ac_cv_c_bigendian" = unknown; then ac_cv_c_bigendian=no else # finding both strings is unlikely to happen, but who knows? ac_cv_c_bigendian=unknown fi fi fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { /* Are we little or big endian? From Harbison&Steele. */ union { long int l; char c[sizeof (long int)]; } u; u.l = 1; return u.c[sizeof (long int) - 1] == 1; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_c_bigendian=no else ac_cv_c_bigendian=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 $as_echo "$ac_cv_c_bigendian" >&6; } case $ac_cv_c_bigendian in #( yes) $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h ;; #( no) ;; #( universal) $as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h ;; #( *) as_fn_error $? "unknown endianness presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; esac for ac_func in strndup do : ac_fn_c_check_func "$LINENO" "strndup" "ac_cv_func_strndup" if test "x$ac_cv_func_strndup" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRNDUP 1 _ACEOF fi done for ac_func in strnlen do : ac_fn_c_check_func "$LINENO" "strnlen" "ac_cv_func_strnlen" if test "x$ac_cv_func_strnlen" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STRNLEN 1 _ACEOF fi done for ac_func in gettimeofday do : ac_fn_c_check_func "$LINENO" "gettimeofday" "ac_cv_func_gettimeofday" if test "x$ac_cv_func_gettimeofday" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETTIMEOFDAY 1 _ACEOF fi done for ac_func in usleep do : ac_fn_c_check_func "$LINENO" "usleep" "ac_cv_func_usleep" if test "x$ac_cv_func_usleep" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_USLEEP 1 _ACEOF fi done for ac_func in vasprintf do : ac_fn_c_check_func "$LINENO" "vasprintf" "ac_cv_func_vasprintf" if test "x$ac_cv_func_vasprintf" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_VASPRINTF 1 _ACEOF fi done build_bitbang=no build_bitq=no is_cygwin=no is_mingw=no is_win32=no is_darwin=no # guess-rev.sh only exists in the repository, not in the released archives { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build a release" >&5 $as_echo_n "checking whether to build a release... " >&6; } if test -x $srcdir/guess-rev.sh ; then build_release=no else build_release=yes fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $build_release" >&5 $as_echo "$build_release" >&6; } # We are not *ALWAYS* being installed in the standard place. # We may be installed in a "tool-build" specific location. # Normally with other packages - as part of a tool distro. # Thus - we should search that 'libdir' also. # # And - if we are being installed there - the odds are # The libraries unique to what we are are there too. # # Expand nd deal with NONE - just like configure will do later OCDprefix=$prefix OCDxprefix=$exec_prefix test x"$OCDprefix" = xNONE && OCDprefix=$ac_default_prefix # Let make expand exec_prefix. test x"$OCDxprefix" = xNONE && OCDxprefix="$OCDprefix" # what matters is the "exec-prefix" if test "$OCDxprefix" != "$ac_default_prefix" then # We are installing in a non-standard place # Nonstandard --prefix and/or --exec-prefix # We have an override of some sort. # use build specific install library dir LDFLAGS="$LDFLAGS -L$OCDxprefix/lib" # RPATH becomes an issue on Linux only if test $host_os = linux-gnu || test $host_os = linux ; then LDFLAGS="$LDFLAGS -Wl,-rpath,$OCDxprefix/lib" fi # The "INCDIR" is also usable CFLAGS="$CFLAGS -I$includedir" fi # Check whether --with-ftd2xx was given. if test "${with_ftd2xx+set}" = set; then : withval=$with_ftd2xx; # Option Given. cat << __EOF__ The option: --with-ftd2xx= has been removed. On Linux, the new option is: --with-ftd2xx-linux-tardir=/path/to/files Where is the path the the directory where the "tar.gz" file from FTDICHIP.COM was unpacked, for example: --with-ftd2xx-linux-tardir=${HOME}/libftd2xx0.4.16 On Cygwin/MingW32, the new option is: --with-ftd2xx-win32-zipdir=/path/to/files Where is the path to the directory where the "zip" file from FTDICHIP.COM was unpacked, for example: --with-ftd2xx-win32-zipdir=${HOME}/ftd2xx.cdm.files __EOF__ as_fn_error $? "Sorry Cannot continue" "$LINENO" 5 else true fi #======================================== # FTD2XXX support comes in 4 forms. # (1) win32 - via a zip file # (2) linux - via a tar file # (3) linux/cygwin/mingw - via libftdi # (4) darwin - installed under /usr/local # # In case (1) and (2) we need to know where the package was unpacked. # Check whether --with-ftd2xx-win32-zipdir was given. if test "${with_ftd2xx_win32_zipdir+set}" = set; then : withval=$with_ftd2xx_win32_zipdir; # option present if test -d $with_ftd2xx_win32_zipdir then with_ftd2xx_win32_zipdir=`cd $with_ftd2xx_win32_zipdir && pwd` { $as_echo "$as_me:${as_lineno-$LINENO}: Using: ftdichip.com library: $with_ftd2xx_win32_zipdir" >&5 $as_echo "$as_me: Using: ftdichip.com library: $with_ftd2xx_win32_zipdir" >&6;} else as_fn_error $? "Parameter to --with-ftd2xx-win32-zipdir is not a dir: $with_ftd2xx_win32_zipdir" "$LINENO" 5 fi else true fi # Check whether --with-ftd2xx-linux-tardir was given. if test "${with_ftd2xx_linux_tardir+set}" = set; then : withval=$with_ftd2xx_linux_tardir; # Option present if test $is_win32 = yes ; then as_fn_error $? "The option: --with-ftd2xx-linux-tardir is only usable on linux" "$LINENO" 5 fi if test -d $with_ftd2xx_linux_tardir then with_ftd2xx_linux_tardir=`cd $with_ftd2xx_linux_tardir && pwd` { $as_echo "$as_me:${as_lineno-$LINENO}: Using: ftdichip.com library: $with_ftd2xx_linux_tardir" >&5 $as_echo "$as_me: Using: ftdichip.com library: $with_ftd2xx_linux_tardir" >&6;} else as_fn_error $? "Parameter to --with-ftd2xx-linux-tardir is not a dir: $with_ftd2xx_linux_tardir" "$LINENO" 5 fi else true fi # Check whether --with-ftd2xx-lib was given. if test "${with_ftd2xx_lib+set}" = set; then : withval=$with_ftd2xx_lib; case "$withval" in static) with_ftd2xx_lib=$withval ;; shared) with_ftd2xx_lib=$withval ;; *) as_fn_error $? "Option: --with-ftd2xx-lib=static or --with-ftd2xx-lib=shared not, $withval" "$LINENO" 5 ;; esac else # Default is static - it is simpler :-( with_ftd2xx_lib=static fi # Check whether --enable-doxygen-html was given. if test "${enable_doxygen_html+set}" = set; then : enableval=$enable_doxygen_html; doxygen_as_html=$enableval else doxygen_as_html=yes fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build Doxygen as HTML" >&5 $as_echo_n "checking whether to build Doxygen as HTML... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $doxygen_as_html" >&5 $as_echo "$doxygen_as_html" >&6; } # Check whether --enable-doxygen-pdf was given. if test "${enable_doxygen_pdf+set}" = set; then : enableval=$enable_doxygen_pdf; doxygen_as_pdf=$enableval else doxygen_as_pdf=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build Doxygen as PDF" >&5 $as_echo_n "checking whether to build Doxygen as PDF... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $doxygen_as_pdf" >&5 $as_echo "$doxygen_as_pdf" >&6; } # Check whether --enable-gccwarnings was given. if test "${enable_gccwarnings+set}" = set; then : enableval=$enable_gccwarnings; gcc_warnings=$enableval else gcc_warnings=yes fi # Check whether --enable-wextra was given. if test "${enable_wextra+set}" = set; then : enableval=$enable_wextra; gcc_wextra=$enableval else gcc_wextra=$gcc_warnings fi # Check whether --enable-werror was given. if test "${enable_werror+set}" = set; then : enableval=$enable_werror; gcc_werror=$enableval else gcc_werror=$gcc_warnings fi # set default verbose options, overridden by following options debug_jtag_io=no debug_usb_io=no debug_usb_comms=no # Check whether --enable-verbose was given. if test "${enable_verbose+set}" = set; then : enableval=$enable_verbose; debug_jtag_io=$enableval debug_usb_io=$enableval debug_usb_comms=$enableval fi # Check whether --enable-verbose_jtag_io was given. if test "${enable_verbose_jtag_io+set}" = set; then : enableval=$enable_verbose_jtag_io; debug_jtag_io=$enableval fi # Check whether --enable-verbose_usb_io was given. if test "${enable_verbose_usb_io+set}" = set; then : enableval=$enable_verbose_usb_io; debug_usb_io=$enableval fi # Check whether --enable-verbose_usb_comms was given. if test "${enable_verbose_usb_comms+set}" = set; then : enableval=$enable_verbose_usb_comms; debug_usb_comms=$enableval fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable verbose JTAG I/O messages" >&5 $as_echo_n "checking whether to enable verbose JTAG I/O messages... " >&6; }; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $debug_jtag_io" >&5 $as_echo "$debug_jtag_io" >&6; } if test $debug_jtag_io = yes; then $as_echo "#define _DEBUG_JTAG_IO_ 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable verbose USB I/O messages" >&5 $as_echo_n "checking whether to enable verbose USB I/O messages... " >&6; }; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $debug_usb_io" >&5 $as_echo "$debug_usb_io" >&6; } if test $debug_usb_io = yes; then $as_echo "#define _DEBUG_USB_IO_ 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable verbose USB communication messages" >&5 $as_echo_n "checking whether to enable verbose USB communication messages... " >&6; }; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $debug_usb_comms" >&5 $as_echo "$debug_usb_comms" >&6; } if test $debug_usb_comms = yes; then $as_echo "#define _DEBUG_USB_COMMS_ 1" >>confdefs.h fi debug_malloc=no # Check whether --enable-malloc_logging was given. if test "${enable_malloc_logging+set}" = set; then : enableval=$enable_malloc_logging; debug_malloc=$enableval fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable malloc free space logging" >&5 $as_echo_n "checking whether to enable malloc free space logging... " >&6; }; { $as_echo "$as_me:${as_lineno-$LINENO}: result: $debug_malloc" >&5 $as_echo "$debug_malloc" >&6; } if test $debug_malloc = yes; then $as_echo "#define _DEBUG_FREE_SPACE_ 1" >>confdefs.h fi # Check whether --enable-dummy was given. if test "${enable_dummy+set}" = set; then : enableval=$enable_dummy; build_dummy=$enableval else build_dummy=no fi # Check whether --enable-parport was given. if test "${enable_parport+set}" = set; then : enableval=$enable_parport; build_parport=$enableval else build_parport=no fi # Check whether --enable-parport_ppdev was given. if test "${enable_parport_ppdev+set}" = set; then : enableval=$enable_parport_ppdev; parport_use_ppdev=$enableval else parport_use_ppdev=yes fi # Check whether --enable-parport_giveio was given. if test "${enable_parport_giveio+set}" = set; then : enableval=$enable_parport_giveio; parport_use_giveio=$enableval else parport_use_giveio= fi # Check whether --enable-ft2232_libftdi was given. if test "${enable_ft2232_libftdi+set}" = set; then : enableval=$enable_ft2232_libftdi; build_ft2232_libftdi=$enableval else build_ft2232_libftdi=no fi # Check whether --enable-ft2232_ftd2xx was given. if test "${enable_ft2232_ftd2xx+set}" = set; then : enableval=$enable_ft2232_ftd2xx; build_ft2232_ftd2xx=$enableval else build_ft2232_ftd2xx=no fi # Check whether --enable-ftdi was given. if test "${enable_ftdi+set}" = set; then : enableval=$enable_ftdi; build_ftdi=$enableval else build_ftdi=no fi # Check whether --enable-usb_blaster_libftdi was given. if test "${enable_usb_blaster_libftdi+set}" = set; then : enableval=$enable_usb_blaster_libftdi; build_usb_blaster_libftdi=$enableval else build_usb_blaster_libftdi=no fi # Check whether --enable-usb_blaster_ftd2xx was given. if test "${enable_usb_blaster_ftd2xx+set}" = set; then : enableval=$enable_usb_blaster_ftd2xx; build_usb_blaster_ftd2xx=$enableval else build_usb_blaster_ftd2xx=no fi # Check whether --enable-amtjtagaccel was given. if test "${enable_amtjtagaccel+set}" = set; then : enableval=$enable_amtjtagaccel; build_amtjtagaccel=$enableval else build_amtjtagaccel=no fi # Check whether --enable-zy1000_master was given. if test "${enable_zy1000_master+set}" = set; then : enableval=$enable_zy1000_master; build_zy1000_master=$enableval else build_zy1000_master=no fi # Check whether --enable-zy1000 was given. if test "${enable_zy1000+set}" = set; then : enableval=$enable_zy1000; build_zy1000=$enableval else build_zy1000=no fi # Check whether --enable-ioutil was given. if test "${enable_ioutil+set}" = set; then : enableval=$enable_ioutil; build_ioutil=$enableval else build_ioutil=no fi case "${host_cpu}" in arm*) # Check whether --enable-ep93xx was given. if test "${enable_ep93xx+set}" = set; then : enableval=$enable_ep93xx; build_ep93xx=$enableval else build_ep93xx=no fi # Check whether --enable-at91rm9200 was given. if test "${enable_at91rm9200+set}" = set; then : enableval=$enable_at91rm9200; build_at91rm9200=$enableval else build_at91rm9200=no fi ;; *) build_ep93xx=no build_at91rm9200=no ;; esac # Check whether --enable-gw16012 was given. if test "${enable_gw16012+set}" = set; then : enableval=$enable_gw16012; build_gw16012=$enableval else build_gw16012=no fi # Check whether --enable-presto_libftdi was given. if test "${enable_presto_libftdi+set}" = set; then : enableval=$enable_presto_libftdi; build_presto_libftdi=$enableval else build_presto_libftdi=no fi # Check whether --enable-presto_ftd2xx was given. if test "${enable_presto_ftd2xx+set}" = set; then : enableval=$enable_presto_ftd2xx; build_presto_ftd2xx=$enableval else build_presto_ftd2xx=no fi # Check whether --enable-usbprog was given. if test "${enable_usbprog+set}" = set; then : enableval=$enable_usbprog; build_usbprog=$enableval else build_usbprog=no fi # Check whether --enable-oocd_trace was given. if test "${enable_oocd_trace+set}" = set; then : enableval=$enable_oocd_trace; build_oocd_trace=$enableval else build_oocd_trace=no fi # Check whether --enable-jlink was given. if test "${enable_jlink+set}" = set; then : enableval=$enable_jlink; build_jlink=$enableval else build_jlink=no fi # Check whether --enable-vsllink was given. if test "${enable_vsllink+set}" = set; then : enableval=$enable_vsllink; build_vsllink=$enableval else build_vsllink=no fi # Check whether --enable-rlink was given. if test "${enable_rlink+set}" = set; then : enableval=$enable_rlink; build_rlink=$enableval else build_rlink=no fi # Check whether --enable-ulink was given. if test "${enable_ulink+set}" = set; then : enableval=$enable_ulink; build_ulink=$enableval else build_ulink=no fi # Check whether --enable-arm-jtag-ew was given. if test "${enable_arm_jtag_ew+set}" = set; then : enableval=$enable_arm_jtag_ew; build_armjtagew=$enableval else build_armjtagew=no fi # Check whether --enable-buspirate was given. if test "${enable_buspirate+set}" = set; then : enableval=$enable_buspirate; build_buspirate=$enableval else build_buspirate=no fi # Check whether --enable-stlink was given. if test "${enable_stlink+set}" = set; then : enableval=$enable_stlink; build_hladapter_stlink=$enableval else build_hladapter_stlink=no fi # Check whether --enable-ti-icdi was given. if test "${enable_ti_icdi+set}" = set; then : enableval=$enable_ti_icdi; build_hladapter_icdi=$enableval else build_hladapter_icdi=no fi # Check whether --enable-osbdm was given. if test "${enable_osbdm+set}" = set; then : enableval=$enable_osbdm; build_osbdm=$enableval else build_osbdm=no fi # Check whether --enable-opendous was given. if test "${enable_opendous+set}" = set; then : enableval=$enable_opendous; build_opendous=$enableval else build_opendous=no fi # Check whether --enable-sysfsgpio was given. if test "${enable_sysfsgpio+set}" = set; then : enableval=$enable_sysfsgpio; build_sysfsgpio=$enableval else build_sysfsgpio=no fi # Check whether --enable-minidriver_dummy was given. if test "${enable_minidriver_dummy+set}" = set; then : enableval=$enable_minidriver_dummy; build_minidriver_dummy=$enableval else build_minidriver_dummy=no fi # Check whether --enable-internal-jimtcl was given. if test "${enable_internal_jimtcl+set}" = set; then : enableval=$enable_internal_jimtcl; use_internal_jimtcl=$enableval else use_internal_jimtcl=yes fi # Check whether --enable-libusb0 was given. if test "${enable_libusb0+set}" = set; then : enableval=$enable_libusb0; check_libusb0=$enableval else check_libusb0=no fi build_minidriver=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable ZY1000 minidriver" >&5 $as_echo_n "checking whether to enable ZY1000 minidriver... " >&6; } if test $build_zy1000 = yes; then if test $build_minidriver = yes; then as_fn_error $? "Multiple minidriver options have been enabled." "$LINENO" 5 fi $as_echo "#define HAVE_JTAG_MINIDRIVER_H 1" >>confdefs.h build_minidriver=yes fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $build_zy1000" >&5 $as_echo "$build_zy1000" >&6; } # Check whether --enable-remote-bitbang was given. if test "${enable_remote_bitbang+set}" = set; then : enableval=$enable_remote_bitbang; build_remote_bitbang=$enableval else build_remote_bitbang=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable dummy minidriver" >&5 $as_echo_n "checking whether to enable dummy minidriver... " >&6; } if test $build_minidriver_dummy = yes; then if test $build_minidriver = yes; then as_fn_error $? "Multiple minidriver options have been enabled." "$LINENO" 5 fi build_minidriver=yes $as_echo "#define BUILD_MINIDRIVER_DUMMY 1" >>confdefs.h $as_echo "#define HAVE_JTAG_MINIDRIVER_H 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $build_minidriver_dummy" >&5 $as_echo "$build_minidriver_dummy" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether standard drivers can be built" >&5 $as_echo_n "checking whether standard drivers can be built... " >&6; } if test "$build_minidriver" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Using the minidriver disables all other drivers." >&5 $as_echo "$as_me: WARNING: Using the minidriver disables all other drivers." >&2;} sleep 2 else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi case "${host_cpu}" in i?86|x86*) ;; *) if test x$parport_use_ppdev = xno; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --disable-parport-ppdev is not supported by the host CPU" >&5 $as_echo "$as_me: WARNING: --disable-parport-ppdev is not supported by the host CPU" >&2;} fi parport_use_ppdev=yes ;; esac case $host in *-cygwin*) is_win32=yes parport_use_ppdev=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return __MINGW32__; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : is_mingw=yes else is_mingw=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $is_mingw = yes; then $as_echo "#define IS_MINGW 1" >>confdefs.h if test x$parport_use_giveio = xno; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --disable-parport-giveio is not supported by MinGW32 hosts" >&5 $as_echo "$as_me: WARNING: --disable-parport-giveio is not supported by MinGW32 hosts" >&2;} fi parport_use_giveio=yes is_cygwin=no else is_cygwin=yes $as_echo "#define IS_CYGWIN 1" >>confdefs.h # sys/io.h needed under cygwin for parport access if test $build_parport = yes; then for ac_header in sys/io.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/io.h" "ac_cv_header_sys_io_h" "$ac_includes_default" if test "x$ac_cv_header_sys_io_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_IO_H 1 _ACEOF else as_fn_error $? "Please install the cygwin ioperm package" "$LINENO" 5 fi done fi fi $as_echo "#define IS_WIN32 1" >>confdefs.h $as_echo "#define IS_DARWIN 0" >>confdefs.h ;; *-mingw*) is_mingw=yes is_win32=yes parport_use_ppdev=no if test x$parport_use_giveio = xno; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --disable-parport-giveio is not supported by MinGW32 hosts" >&5 $as_echo "$as_me: WARNING: --disable-parport-giveio is not supported by MinGW32 hosts" >&2;} fi parport_use_giveio=yes if test x$build_buspirate = xyes; then as_fn_error $? "buspirate currently not supported by MinGW32 hosts" "$LINENO" 5 fi CFLAGS="$CFLAGS -D__USE_MINGW_ANSI_STDIO" $as_echo "#define IS_MINGW 1" >>confdefs.h $as_echo "#define IS_WIN32 1" >>confdefs.h $as_echo "#define IS_DARWIN 0" >>confdefs.h ;; *darwin*) is_darwin=yes if test x$parport_use_giveio = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --enable-parport-giveio cannot be used by Darwin hosts" >&5 $as_echo "$as_me: WARNING: --enable-parport-giveio cannot be used by Darwin hosts" >&2;} fi parport_use_giveio=no $as_echo "#define IS_CYGWIN 0" >>confdefs.h $as_echo "#define IS_WIN32 0" >>confdefs.h $as_echo "#define IS_DARWIN 1" >>confdefs.h ;; *) if test x$parport_use_giveio = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --enable-parport-giveio cannot be used by $host hosts" >&5 $as_echo "$as_me: WARNING: --enable-parport-giveio cannot be used by $host hosts" >&2;} fi parport_use_giveio=no $as_echo "#define IS_CYGWIN 0" >>confdefs.h $as_echo "#define IS_WIN32 0" >>confdefs.h $as_echo "#define IS_DARWIN 0" >>confdefs.h ;; esac if test $build_parport = yes; then build_bitbang=yes $as_echo "#define BUILD_PARPORT 1" >>confdefs.h else $as_echo "#define BUILD_PARPORT 0" >>confdefs.h fi if test $build_dummy = yes; then build_bitbang=yes $as_echo "#define BUILD_DUMMY 1" >>confdefs.h else $as_echo "#define BUILD_DUMMY 0" >>confdefs.h fi if test $build_ep93xx = yes; then build_bitbang=yes $as_echo "#define BUILD_EP93XX 1" >>confdefs.h else $as_echo "#define BUILD_EP93XX 0" >>confdefs.h fi if test $build_zy1000 = yes; then $as_echo "#define BUILD_ZY1000 1" >>confdefs.h else $as_echo "#define BUILD_ZY1000 0" >>confdefs.h fi if test $build_zy1000_master = yes; then $as_echo "#define BUILD_ZY1000_MASTER 1" >>confdefs.h else $as_echo "#define BUILD_ZY1000_MASTER 0" >>confdefs.h fi if test $build_at91rm9200 = yes; then build_bitbang=yes $as_echo "#define BUILD_AT91RM9200 1" >>confdefs.h else $as_echo "#define BUILD_AT91RM9200 0" >>confdefs.h fi if test x$parport_use_ppdev = xyes; then $as_echo "#define PARPORT_USE_PPDEV 1" >>confdefs.h else $as_echo "#define PARPORT_USE_PPDEV 0" >>confdefs.h fi if test x$parport_use_giveio = xyes; then $as_echo "#define PARPORT_USE_GIVEIO 1" >>confdefs.h else $as_echo "#define PARPORT_USE_GIVEIO 0" >>confdefs.h fi if test $build_bitbang = yes; then $as_echo "#define BUILD_BITBANG 1" >>confdefs.h else $as_echo "#define BUILD_BITBANG 0" >>confdefs.h fi if test $build_ft2232_libftdi = yes; then $as_echo "#define BUILD_FT2232_LIBFTDI 1" >>confdefs.h else $as_echo "#define BUILD_FT2232_LIBFTDI 0" >>confdefs.h fi if test $build_ft2232_ftd2xx = yes; then $as_echo "#define BUILD_FT2232_FTD2XX 1" >>confdefs.h else $as_echo "#define BUILD_FT2232_FTD2XX 0" >>confdefs.h fi if test $build_ftdi = yes; then $as_echo "#define BUILD_FTDI 1" >>confdefs.h else $as_echo "#define BUILD_FTDI 0" >>confdefs.h fi if test $build_usb_blaster_libftdi = yes; then build_bitbang=yes $as_echo "#define BUILD_USB_BLASTER_LIBFTDI 1" >>confdefs.h else $as_echo "#define BUILD_USB_BLASTER_LIBFTDI 0" >>confdefs.h fi if test $build_usb_blaster_ftd2xx = yes; then build_bitbang=yes $as_echo "#define BUILD_USB_BLASTER_FTD2XX 1" >>confdefs.h else $as_echo "#define BUILD_USB_BLASTER_FTD2XX 0" >>confdefs.h fi if test $build_amtjtagaccel = yes; then $as_echo "#define BUILD_AMTJTAGACCEL 1" >>confdefs.h else $as_echo "#define BUILD_AMTJTAGACCEL 0" >>confdefs.h fi if test $build_gw16012 = yes; then $as_echo "#define BUILD_GW16012 1" >>confdefs.h else $as_echo "#define BUILD_GW16012 0" >>confdefs.h fi if test $build_presto_libftdi = yes; then build_bitq=yes $as_echo "#define BUILD_PRESTO_LIBFTDI 1" >>confdefs.h else $as_echo "#define BUILD_PRESTO_LIBFTDI 0" >>confdefs.h fi if test $build_presto_ftd2xx = yes; then build_bitq=yes $as_echo "#define BUILD_PRESTO_FTD2XX 1" >>confdefs.h else $as_echo "#define BUILD_PRESTO_FTD2XX 0" >>confdefs.h fi if test $build_bitq = yes; then $as_echo "#define BUILD_BITQ 1" >>confdefs.h else $as_echo "#define BUILD_BITQ 0" >>confdefs.h fi if test $build_usbprog = yes; then $as_echo "#define BUILD_USBPROG 1" >>confdefs.h else $as_echo "#define BUILD_USBPROG 0" >>confdefs.h fi if test $build_oocd_trace = yes; then $as_echo "#define BUILD_OOCD_TRACE 1" >>confdefs.h else $as_echo "#define BUILD_OOCD_TRACE 0" >>confdefs.h fi if test $build_jlink = yes; then $as_echo "#define BUILD_JLINK 1" >>confdefs.h else $as_echo "#define BUILD_JLINK 0" >>confdefs.h fi if test $build_vsllink = yes; then $as_echo "#define BUILD_VSLLINK 1" >>confdefs.h else $as_echo "#define BUILD_VSLLINK 0" >>confdefs.h fi if test $build_rlink = yes; then $as_echo "#define BUILD_RLINK 1" >>confdefs.h else $as_echo "#define BUILD_RLINK 0" >>confdefs.h fi if test $build_ulink = yes; then $as_echo "#define BUILD_ULINK 1" >>confdefs.h else $as_echo "#define BUILD_ULINK 0" >>confdefs.h fi if test $build_armjtagew = yes; then $as_echo "#define BUILD_ARMJTAGEW 1" >>confdefs.h else $as_echo "#define BUILD_ARMJTAGEW 0" >>confdefs.h fi if test $build_buspirate = yes; then $as_echo "#define BUILD_BUSPIRATE 1" >>confdefs.h else $as_echo "#define BUILD_BUSPIRATE 0" >>confdefs.h fi if test $build_hladapter_stlink = yes -o $build_hladapter_icdi = yes; then $as_echo "#define BUILD_HLADAPTER 1" >>confdefs.h else $as_echo "#define BUILD_HLADAPTER 0" >>confdefs.h fi if test $build_osbdm = yes; then $as_echo "#define BUILD_OSBDM 1" >>confdefs.h else $as_echo "#define BUILD_OSBDM 0" >>confdefs.h fi if test $build_opendous = yes; then $as_echo "#define BUILD_OPENDOUS 1" >>confdefs.h else $as_echo "#define BUILD_OPENDOUS 0" >>confdefs.h fi if test "$use_internal_jimtcl" = yes; then if test -f "$srcdir/jimtcl/configure.ac"; then subdirs="$subdirs jimtcl" printf "#!/bin/sh "\$"SHELL "../$srcdir/jimtcl/configure" --disable-install-jim \""\$"@"\" > "$srcdir/jimtcl/configure.gnu" else as_fn_error $? "jimtcl not found, run git submodule init and git submodule update." "$LINENO" 5 fi fi if test $build_remote_bitbang = yes; then build_bitbang=yes $as_echo "#define BUILD_REMOTE_BITBANG 1" >>confdefs.h else $as_echo "#define BUILD_REMOTE_BITBANG 0" >>confdefs.h fi if test $build_sysfsgpio = yes; then build_bitbang=yes $as_echo "#define BUILD_SYSFSGPIO 1" >>confdefs.h else $as_echo "#define BUILD_SYSFSGPIO 0" >>confdefs.h fi #-- Deal with MingW/Cygwin FTD2XX issues if test $is_win32 = yes; then if test "${with_ftd2xx_linux_tardir+set}" = set then as_fn_error $? "The option: with_ftd2xx_linux_tardir is for LINUX only." "$LINENO" 5 fi if test $build_ft2232_ftd2xx = yes -o $build_presto_ftd2xx = yes -o $build_usb_blaster_ftd2xx = yes ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ftd2xx.lib exists (win32)" >&5 $as_echo_n "checking for ftd2xx.lib exists (win32)... " >&6; } # if we are given a zipdir... if test "${with_ftd2xx_win32_zipdir+set}" = set then # Set the CFLAGS for "ftd2xx.h" f=$with_ftd2xx_win32_zipdir/ftd2xx.h if test ! -f $f ; then as_fn_error $? "File: $f cannot be found" "$LINENO" 5 fi CFLAGS="$CFLAGS -I$with_ftd2xx_win32_zipdir" # And calculate the LDFLAGS for the machine case "$host_cpu" in i?86|x86_32) LDFLAGS="$LDFLAGS -L$with_ftd2xx_win32_zipdir/i386" LIBS="$LIBS -lftd2xx" f=$with_ftd2xx_win32_zipdir/i386/ftd2xx.lib ;; amd64|x86_64) LDFLAGS="$LDFLAGS -L$with_ftd2xx_win32_zipdir/amd64" LIBS="$LIBS -lftd2xx" f=$with_ftd2xx_win32_zipdir/amd64/ftd2xx.lib ;; *) as_fn_error $? "Unknown Win32 host cpu: $host_cpu" "$LINENO" 5 ;; esac if test ! -f $f ; then as_fn_error $? "Library: $f not found" "$LINENO" 5 fi else LIBS="$LIBS -lftd2xx" { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: ASSUMPTION: The (win32) FTDICHIP.COM files: ftd2xx.h and ftd2xx.lib are in a proper place" >&5 $as_echo "$as_me: WARNING: ASSUMPTION: The (win32) FTDICHIP.COM files: ftd2xx.h and ftd2xx.lib are in a proper place" >&2;} fi fi fi # win32 if test $is_darwin = yes ; then if test "${with_ftd2xx_win32_zipdir+set}" = set then as_fn_error $? "The option: --with-ftd2xx-win32-zipdir is for win32 only" "$LINENO" 5 fi if test "${with_ftd2xx_linux_tardir+set}" = set then as_fn_error $? "The option: with_ftd2xx_linux_tardir is for LINUX only." "$LINENO" 5 fi if test $build_ft2232_ftd2xx = yes -o $build_presto_ftd2xx = yes -o $build_usb_blaster_ftd2xx = yes ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libftd2xx.a (darwin)" >&5 $as_echo_n "checking for libftd2xx.a (darwin)... " >&6; } if test ! -f /usr/local/include/ftd2xx.h ; then as_fn_error $? "ftd2xx library from FTDICHIP.com seems to be missing, cannot find: /usr/local/include/ftd2xx.h" "$LINENO" 5 fi CFLAGS="$CFLAGS -I/usr/local/include" LDFLAGS="$LDFLAGS -L/usr/local/lib" LIBS="$LIBS -lftd2xx" { $as_echo "$as_me:${as_lineno-$LINENO}: result: -L/usr/local/lib -lftd2xx" >&5 $as_echo "-L/usr/local/lib -lftd2xx" >&6; } fi fi # darwin if test $is_win32 = no && test $is_darwin = no ; then if test "${with_ftd2xx_win32_zipdir+set}" = set then as_fn_error $? "The option: --with-ftd2xx-win32-zipdir is for win32 only" "$LINENO" 5 fi if test $build_ft2232_ftd2xx = yes -o $build_presto_ftd2xx = yes -o $build_usb_blaster_ftd2xx = yes ; then # Must be linux if test $host_os != linux-gnu && test $host_os != linux ; then as_fn_error $? "The (linux) ftd2xx library from FTDICHIP.com is linux only. Try --enable-ft2232-libftdi instead" "$LINENO" 5 fi # Are we given a TAR directory? if test "${with_ftd2xx_linux_tardir+set}" = set then { $as_echo "$as_me:${as_lineno-$LINENO}: checking uninstalled ftd2xx distribution" >&5 $as_echo_n "checking uninstalled ftd2xx distribution... " >&6; } # The .H file is simple.. FTD2XX_H=$with_ftd2xx_linux_tardir/ftd2xx.h if test ! -f "${FTD2XX_H}"; then as_fn_error $? "Option: --with-ftd2xx-linux-tardir appears wrong, cannot find: ${FTD2XX_H}" "$LINENO" 5 fi CFLAGS="$CFLAGS -I$with_ftd2xx_linux_tardir" if test $with_ftd2xx_lib = shared; then FTD2XX_LDFLAGS="-L$with_ftd2xx_linux_tardir" FTD2XX_LIB="-lftd2xx" else # Test #1 - v1.0.x case "$host_cpu" in i?86|x86_32) dir=build/i386;; amd64|x86_64) dir=build/x86_64;; *) dir=none;; esac if test -f "$with_ftd2xx_linux_tardir/$dir/libftd2xx.a"; then FTD2XX_LDFLAGS="-L$with_ftd2xx_linux_tardir/$dir" # Also needs -lrt FTD2XX_LIB="-lftd2xx -lrt" else # Test Number2. # Grr.. perhaps it exists as a version number? FTD2XX_LIB="$with_ftd2xx_linux_tardir/static_lib/libftd2xx.a.*.*.*" count=`ls ${FTD2XX_LIB} | wc -l` if test $count -gt 1 ; then as_fn_error $? "Multiple libftd2xx.a files found in: $with_ftd2xx_linux_tardir/static_lib sorry cannot handle this yet" "$LINENO" 5 fi if test $count -ne 1 ; then as_fn_error $? "Not found: $f, option: --with-ftd2xx-linux-tardir appears to be wrong" "$LINENO" 5 fi # Because the "-l" rules do not understand version numbers... # we will just stuff the absolute path onto the LIBS variable FTD2XX_LIB="`ls ${FTD2XX_LIB}` -lpthread" FTD2XX_LDFLAGS="" fi fi LDFLAGS="${LDFLAGS} ${FTD2XX_LDFLAGS}" LIBS="${FTD2XX_LIB} ${LIBS}" { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${FTD2XX_LDFLAGS} ${FTD2XX_LIB}" >&5 $as_echo "${FTD2XX_LDFLAGS} ${FTD2XX_LIB}" >&6; } else ac_fn_c_check_header_mongrel "$LINENO" "ftd2xx.h" "ac_cv_header_ftd2xx_h" "$ac_includes_default" if test "x$ac_cv_header_ftd2xx_h" = xyes; then : else as_fn_error $? "You seem to be missing the FTD2xx driver header file." "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing FT_GetLibraryVersion" >&5 $as_echo_n "checking for library containing FT_GetLibraryVersion... " >&6; } if ${ac_cv_search_FT_GetLibraryVersion+:} 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 FT_GetLibraryVersion (); int main () { return FT_GetLibraryVersion (); ; return 0; } _ACEOF for ac_lib in '' ftd2xx; 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_FT_GetLibraryVersion=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_FT_GetLibraryVersion+:} false; then : break fi done if ${ac_cv_search_FT_GetLibraryVersion+:} false; then : else ac_cv_search_FT_GetLibraryVersion=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_FT_GetLibraryVersion" >&5 $as_echo "$ac_cv_search_FT_GetLibraryVersion" >&6; } ac_res=$ac_cv_search_FT_GetLibraryVersion if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" else as_fn_error $? "You appear to be missing the FTD2xx driver library." "$LINENO" 5 fi fi fi fi # linux if test $build_ft2232_ftd2xx = yes -o $build_presto_ftd2xx = yes -o $build_usb_blaster_ftd2xx = yes ; then # Before we go any further - make sure we can *BUILD* and *RUN* # a simple app with the "ftd2xx.lib" file - in what ever form we where given # We should be able to compile, link and run this test program now { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ftd2xx library works" >&5 $as_echo_n "checking whether ftd2xx library works... " >&6; } # # Save the LDFLAGS for later.. LDFLAGS_SAVE=$LDFLAGS CFLAGS_SAVE=$CFLAGS _LDFLAGS=`eval echo $LDFLAGS` _CFLAGS=`eval echo $CFLAGS` LDFLAGS=$_LDFLAGS CFLAGS=$_CFLAGS if test "$cross_compiling" = yes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: Skipping as we are cross-compiling" >&5 $as_echo "Skipping as we are cross-compiling" >&6; } else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include "confdefs.h" #if IS_WIN32 #include "windows.h" #endif #include #include int main () { DWORD x; FT_GetLibraryVersion( &x ); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: Success!" >&5 $as_echo "Success!" >&6; } else as_fn_error $? "Cannot build & run test program using ftd2xx.lib" "$LINENO" 5 fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ftd2xx highspeed device support" >&5 $as_echo_n "checking for ftd2xx highspeed device support... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include "confdefs.h" #if IS_WIN32 #include "windows.h" #endif #include #include DWORD x = FT_DEVICE_4232H; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : $as_echo "#define BUILD_FT2232_HIGHSPEED 1" >>confdefs.h build_ft2232_highspeed=yes else build_ft2232_highspeed=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $build_ft2232_highspeed" >&5 $as_echo "$build_ft2232_highspeed" >&6; } if test $build_ft2232_highspeed = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You need a newer FTD2XX driver (version 2.04.16 or later)." >&5 $as_echo "$as_me: WARNING: You need a newer FTD2XX driver (version 2.04.16 or later)." >&2;} fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ftd2xx FT232H device support" >&5 $as_echo_n "checking for ftd2xx FT232H device support... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include "confdefs.h" #if IS_WIN32 #include "windows.h" #endif #include #include DWORD x = FT_DEVICE_232H; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : $as_echo "#define HAS_ENUM_FT232H 1" >>confdefs.h has_enum_ft232h=yes else has_enum_ft232h=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $has_enum_ft232h" >&5 $as_echo "$has_enum_ft232h" >&6; } if test $has_enum_ft232h = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You need a newer FTD2XX driver (version 2.08.12 or later)." >&5 $as_echo "$as_me: WARNING: You need a newer FTD2XX driver (version 2.08.12 or later)." >&2;} fi LDFLAGS=$LDFLAGS_SAVE CFLAGS=$CFLAGS_SAVE fi if test $build_ft2232_libftdi = yes ; then # We assume: the package is preinstalled in the proper place # these present as 2 libraries.. LIBS="$LIBS -lftdi -lusb" # # Try to build a small program. { $as_echo "$as_me:${as_lineno-$LINENO}: checking Build & Link with libftdi..." >&5 $as_echo_n "checking Build & Link with libftdi...... " >&6; } LDFLAGS_SAVE=$LDFLAGS CFLAGS_SAVE=$CFLAGS _LDFLAGS=`eval echo $LDFLAGS` _CFLAGS=`eval echo $CFLAGS` LDFLAGS=$_LDFLAGS CFLAGS=$_CFLAGS if test "$cross_compiling" = yes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: Skipping as we are cross-compiling" >&5 $as_echo "Skipping as we are cross-compiling" >&6; } else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { struct ftdi_context *p; p = ftdi_new(); if( p != NULL ){ return 0; } else { fprintf( stderr, "calling ftdi_new() failed\n"); return 1; } ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: Success" >&5 $as_echo "Success" >&6; } else as_fn_error $? "Cannot build & run test program using libftdi" "$LINENO" 5 fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libftdi highspeed device support" >&5 $as_echo_n "checking for libftdi highspeed device support... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { enum ftdi_chip_type x = TYPE_2232H; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : $as_echo "#define BUILD_FT2232_HIGHSPEED 1" >>confdefs.h build_ft2232_highspeed=yes else build_ft2232_highspeed=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $build_ft2232_highspeed" >&5 $as_echo "$build_ft2232_highspeed" >&6; } if test $build_ft2232_highspeed = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You need a newer libftdi version (0.16 or later)." >&5 $as_echo "$as_me: WARNING: You need a newer libftdi version (0.16 or later)." >&2;} fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libftdi FT232H device support" >&5 $as_echo_n "checking for libftdi FT232H device support... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { enum ftdi_chip_type x = TYPE_232H; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : $as_echo "#define HAS_ENUM_FT232H 1" >>confdefs.h has_enum_ft232h=yes else has_enum_ft232h=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $has_enum_ft232h" >&5 $as_echo "$has_enum_ft232h" >&6; } if test $has_enum_ft232h = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You need a newer libftdi version (0.20 or later)." >&5 $as_echo "$as_me: WARNING: You need a newer libftdi version (0.20 or later)." >&2;} fi # Restore the 'unexpanded ldflags' LDFLAGS=$LDFLAGS_SAVE CFLAGS=$CFLAGS_SAVE fi # check for usb.h when a driver will require it build_usb=no if test $build_vsllink = yes -o $build_usbprog = yes -o \ $build_rlink = yes -o $build_ulink = yes -o $build_armjtagew = yes then build_usb=yes fi # Check for libusb1 ported drivers. build_usb_ng=no if test $build_jlink = yes -o $build_hladapter_stlink = yes -o $build_osbdm = yes -o \ $build_opendous = yes -o $build_ftdi = yes -o $build_hladapter_icdi = yes then build_usb_ng=yes fi # check for libusb library if necessary use_libusb0=no use_libusb1=no if test $build_usb = yes -o $build_usb_ng = yes; then if test $check_libusb0 = no -a $build_usb_ng = yes; then ac_fn_c_check_header_mongrel "$LINENO" "libusb-1.0/libusb.h" "ac_cv_header_libusb_1_0_libusb_h" "$ac_includes_default" if test "x$ac_cv_header_libusb_1_0_libusb_h" = xyes; then : $as_echo "#define HAVE_LIBUSB1 1" >>confdefs.h check_libusb0=no use_libusb1=yes else check_libusb0=yes use_libusb1=no fi fi if test $check_libusb0 = yes -o $build_usb = yes; then for ac_header in usb.h do : ac_fn_c_check_header_mongrel "$LINENO" "usb.h" "ac_cv_header_usb_h" "$ac_includes_default" if test "x$ac_cv_header_usb_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_USB_H 1 _ACEOF use_libusb0=yes else as_fn_error $? "libusb or libusb-1.0 are required to build some OpenOCD driver(s)" "$LINENO" 5 fi done fi fi if test $build_release = yes; then RELEASE_TRUE= RELEASE_FALSE='#' else RELEASE_TRUE='#' RELEASE_FALSE= fi if test $build_parport = yes; then PARPORT_TRUE= PARPORT_FALSE='#' else PARPORT_TRUE='#' PARPORT_FALSE= fi if test $build_dummy = yes; then DUMMY_TRUE= DUMMY_FALSE='#' else DUMMY_TRUE='#' DUMMY_FALSE= fi if test x$parport_use_giveio = xyes; then GIVEIO_TRUE= GIVEIO_FALSE='#' else GIVEIO_TRUE='#' GIVEIO_FALSE= fi if test $build_ep93xx = yes; then EP93XX_TRUE= EP93XX_FALSE='#' else EP93XX_TRUE='#' EP93XX_FALSE= fi if test $build_zy1000 = yes; then ZY1000_TRUE= ZY1000_FALSE='#' else ZY1000_TRUE='#' ZY1000_FALSE= fi if test $build_zy1000_master = yes; then ZY1000_MASTER_TRUE= ZY1000_MASTER_FALSE='#' else ZY1000_MASTER_TRUE='#' ZY1000_MASTER_FALSE= fi if test $build_ioutil = yes; then IOUTIL_TRUE= IOUTIL_FALSE='#' else IOUTIL_TRUE='#' IOUTIL_FALSE= fi if test $build_at91rm9200 = yes; then AT91RM9200_TRUE= AT91RM9200_FALSE='#' else AT91RM9200_TRUE='#' AT91RM9200_FALSE= fi if test $build_bitbang = yes; then BITBANG_TRUE= BITBANG_FALSE='#' else BITBANG_TRUE='#' BITBANG_FALSE= fi if test $build_ft2232_libftdi = yes; then FT2232_LIBFTDI_TRUE= FT2232_LIBFTDI_FALSE='#' else FT2232_LIBFTDI_TRUE='#' FT2232_LIBFTDI_FALSE= fi if test $build_ft2232_ftd2xx = yes -o $build_ft2232_libftdi = yes; then FT2232_DRIVER_TRUE= FT2232_DRIVER_FALSE='#' else FT2232_DRIVER_TRUE='#' FT2232_DRIVER_FALSE= fi if test $build_ftdi = yes; then FTDI_DRIVER_TRUE= FTDI_DRIVER_FALSE='#' else FTDI_DRIVER_TRUE='#' FTDI_DRIVER_FALSE= fi if test $build_usb_blaster_libftdi = yes; then USB_BLASTER_LIBFTDI_TRUE= USB_BLASTER_LIBFTDI_FALSE='#' else USB_BLASTER_LIBFTDI_TRUE='#' USB_BLASTER_LIBFTDI_FALSE= fi if test $build_usb_blaster_ftd2xx = yes -o $build_usb_blaster_libftdi = yes; then USB_BLASTER_DRIVER_TRUE= USB_BLASTER_DRIVER_FALSE='#' else USB_BLASTER_DRIVER_TRUE='#' USB_BLASTER_DRIVER_FALSE= fi if test $build_amtjtagaccel = yes; then AMTJTAGACCEL_TRUE= AMTJTAGACCEL_FALSE='#' else AMTJTAGACCEL_TRUE='#' AMTJTAGACCEL_FALSE= fi if test $build_gw16012 = yes; then GW16012_TRUE= GW16012_FALSE='#' else GW16012_TRUE='#' GW16012_FALSE= fi if test $build_presto_libftdi = yes; then PRESTO_LIBFTDI_TRUE= PRESTO_LIBFTDI_FALSE='#' else PRESTO_LIBFTDI_TRUE='#' PRESTO_LIBFTDI_FALSE= fi if test $build_presto_ftd2xx = yes -o $build_presto_libftdi = yes; then PRESTO_DRIVER_TRUE= PRESTO_DRIVER_FALSE='#' else PRESTO_DRIVER_TRUE='#' PRESTO_DRIVER_FALSE= fi if test $build_usbprog = yes; then USBPROG_TRUE= USBPROG_FALSE='#' else USBPROG_TRUE='#' USBPROG_FALSE= fi if test $build_oocd_trace = yes; then OOCD_TRACE_TRUE= OOCD_TRACE_FALSE='#' else OOCD_TRACE_TRUE='#' OOCD_TRACE_FALSE= fi if test $build_jlink = yes; then JLINK_TRUE= JLINK_FALSE='#' else JLINK_TRUE='#' JLINK_FALSE= fi if test $build_vsllink = yes; then VSLLINK_TRUE= VSLLINK_FALSE='#' else VSLLINK_TRUE='#' VSLLINK_FALSE= fi if test $build_rlink = yes; then RLINK_TRUE= RLINK_FALSE='#' else RLINK_TRUE='#' RLINK_FALSE= fi if test $build_ulink = yes; then ULINK_TRUE= ULINK_FALSE='#' else ULINK_TRUE='#' ULINK_FALSE= fi if test $build_armjtagew = yes; then ARMJTAGEW_TRUE= ARMJTAGEW_FALSE='#' else ARMJTAGEW_TRUE='#' ARMJTAGEW_FALSE= fi if test $build_remote_bitbang = yes; then REMOTE_BITBANG_TRUE= REMOTE_BITBANG_FALSE='#' else REMOTE_BITBANG_TRUE='#' REMOTE_BITBANG_FALSE= fi if test $build_buspirate = yes; then BUSPIRATE_TRUE= BUSPIRATE_FALSE='#' else BUSPIRATE_TRUE='#' BUSPIRATE_FALSE= fi if test $build_hladapter_stlink = yes -o $build_hladapter_icdi = yes; then HLADAPTER_TRUE= HLADAPTER_FALSE='#' else HLADAPTER_TRUE='#' HLADAPTER_FALSE= fi if test $build_osbdm = yes; then OSBDM_TRUE= OSBDM_FALSE='#' else OSBDM_TRUE='#' OSBDM_FALSE= fi if test $build_opendous = yes; then OPENDOUS_TRUE= OPENDOUS_FALSE='#' else OPENDOUS_TRUE='#' OPENDOUS_FALSE= fi if test $build_sysfsgpio = yes; then SYSFSGPIO_TRUE= SYSFSGPIO_FALSE='#' else SYSFSGPIO_TRUE='#' SYSFSGPIO_FALSE= fi if test $build_usb = yes; then USB_TRUE= USB_FALSE='#' else USB_TRUE='#' USB_FALSE= fi if test $build_usb_ng = yes; then USB_NG_TRUE= USB_NG_FALSE='#' else USB_NG_TRUE='#' USB_NG_FALSE= fi if test $use_libusb0 = yes; then USE_LIBUSB0_TRUE= USE_LIBUSB0_FALSE='#' else USE_LIBUSB0_TRUE='#' USE_LIBUSB0_FALSE= fi if test $use_libusb1 = yes; then USE_LIBUSB1_TRUE= USE_LIBUSB1_FALSE='#' else USE_LIBUSB1_TRUE='#' USE_LIBUSB1_FALSE= fi if test $is_cygwin = yes; then IS_CYGWIN_TRUE= IS_CYGWIN_FALSE='#' else IS_CYGWIN_TRUE='#' IS_CYGWIN_FALSE= fi if test $is_mingw = yes; then IS_MINGW_TRUE= IS_MINGW_FALSE='#' else IS_MINGW_TRUE='#' IS_MINGW_FALSE= fi if test $is_win32 = yes; then IS_WIN32_TRUE= IS_WIN32_FALSE='#' else IS_WIN32_TRUE='#' IS_WIN32_FALSE= fi if test $is_darwin = yes; then IS_DARWIN_TRUE= IS_DARWIN_FALSE='#' else IS_DARWIN_TRUE='#' IS_DARWIN_FALSE= fi if test $build_bitq = yes; then BITQ_TRUE= BITQ_FALSE='#' else BITQ_TRUE='#' BITQ_FALSE= fi if test $build_minidriver = yes; then MINIDRIVER_TRUE= MINIDRIVER_FALSE='#' else MINIDRIVER_TRUE='#' MINIDRIVER_FALSE= fi if test $build_minidriver_dummy = yes; then MINIDRIVER_DUMMY_TRUE= MINIDRIVER_DUMMY_FALSE='#' else MINIDRIVER_DUMMY_TRUE='#' MINIDRIVER_DUMMY_FALSE= fi if test $use_internal_jimtcl = yes; then INTERNAL_JIMTCL_TRUE= INTERNAL_JIMTCL_FALSE='#' else INTERNAL_JIMTCL_TRUE='#' INTERNAL_JIMTCL_FALSE= fi # Look for environ alternatives. Possibility #1: is environ in unistd.h or stdlib.h? { $as_echo "$as_me:${as_lineno-$LINENO}: checking for environ in unistd.h and stdlib.h" >&5 $as_echo_n "checking for environ in unistd.h and stdlib.h... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _GNU_SOURCE #include #include int main () { char **ep = environ; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } has_environ=yes else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } # Possibility #2: can environ be found in an available library? { $as_echo "$as_me:${as_lineno-$LINENO}: checking for extern environ" >&5 $as_echo_n "checking for extern environ... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ extern char **environ; int main () { char **ep = environ; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : $as_echo "#define NEED_ENVIRON_EXTERN 1" >>confdefs.h has_environ=yes else has_environ=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${has_environ}" >&5 $as_echo "${has_environ}" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test "${has_environ}" != "yes" ; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "Could not find 'environ' in unistd.h or available libraries. See \`config.log' for more details" "$LINENO" 5; } fi $as_echo "#define _GNU_SOURCE 1" >>confdefs.h # set default gcc warnings GCC_WARNINGS="-Wall -Wstrict-prototypes -Wformat-security -Wshadow" if test "${gcc_wextra}" = yes; then GCC_WARNINGS="${GCC_WARNINGS} -Wextra -Wno-unused-parameter" GCC_WARNINGS="${GCC_WARNINGS} -Wbad-function-cast" GCC_WARNINGS="${GCC_WARNINGS} -Wcast-align" GCC_WARNINGS="${GCC_WARNINGS} -Wredundant-decls" fi if test "${gcc_werror}" = yes; then GCC_WARNINGS="${GCC_WARNINGS} -Werror" fi # overide default gcc cflags if test $gcc_warnings = yes; then CFLAGS="$CFLAGS $GCC_WARNINGS" fi # Setup for compiling build tools { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a C compiler for build tools" >&5 $as_echo_n "checking for a C compiler for build tools... " >&6; } if test $cross_compiling = yes; then for ac_prog in gcc cc 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_CC_FOR_BUILD+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC_FOR_BUILD"; then ac_cv_prog_CC_FOR_BUILD="$CC_FOR_BUILD" # 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_FOR_BUILD="$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_FOR_BUILD=$ac_cv_prog_CC_FOR_BUILD if test -n "$CC_FOR_BUILD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC_FOR_BUILD" >&5 $as_echo "$CC_FOR_BUILD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC_FOR_BUILD" && break done CFLAGS_FOR_BUILD="-g -O2 $GCC_WARNINGS" else CC_FOR_BUILD=$CC CFLAGS_FOR_BUILD=$CFLAGS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC_FOR_BUILD" >&5 $as_echo "$CC_FOR_BUILD" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executable build tools" >&5 $as_echo_n "checking for suffix of executable build tools... " >&6; } if test $cross_compiling = yes; then cat >conftest.c <<\_______EOF int main () { exit (0); } _______EOF for i in .exe ""; do compile="$CC_FOR_BUILD conftest.c -o conftest$i" if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$compile\""; } >&5 (eval $compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then if (./conftest) 2>&5; then EXEEXT_FOR_BUILD=$i break fi fi done rm -f conftest* if test "${EXEEXT_FOR_BUILD+set}" != set; then as_fn_error $? "Cannot determine suffix of executable build tools" "$LINENO" 5 fi else EXEEXT_FOR_BUILD=$EXEEXT fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $EXEEXT_FOR_BUILD" >&5 $as_echo "$EXEEXT_FOR_BUILD" >&6; } ac_config_files="$ac_config_files Makefile src/Makefile src/helper/Makefile src/jtag/Makefile src/jtag/drivers/Makefile src/jtag/hla/Makefile src/transport/Makefile src/xsvf/Makefile src/svf/Makefile src/target/Makefile src/rtos/Makefile src/server/Makefile src/flash/Makefile src/flash/nor/Makefile src/flash/nand/Makefile src/pld/Makefile doc/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}' DEFS=-DHAVE_CONFIG_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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 $as_echo_n "checking that generated files are newer than configure... " >&6; } if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 $as_echo "done" >&6; } if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' else am__EXEEXT_TRUE='#' am__EXEEXT_FALSE= fi if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then as_fn_error $? "conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${RELEASE_TRUE}" && test -z "${RELEASE_FALSE}"; then as_fn_error $? "conditional \"RELEASE\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${PARPORT_TRUE}" && test -z "${PARPORT_FALSE}"; then as_fn_error $? "conditional \"PARPORT\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${DUMMY_TRUE}" && test -z "${DUMMY_FALSE}"; then as_fn_error $? "conditional \"DUMMY\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${GIVEIO_TRUE}" && test -z "${GIVEIO_FALSE}"; then as_fn_error $? "conditional \"GIVEIO\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${EP93XX_TRUE}" && test -z "${EP93XX_FALSE}"; then as_fn_error $? "conditional \"EP93XX\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ZY1000_TRUE}" && test -z "${ZY1000_FALSE}"; then as_fn_error $? "conditional \"ZY1000\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ZY1000_MASTER_TRUE}" && test -z "${ZY1000_MASTER_FALSE}"; then as_fn_error $? "conditional \"ZY1000_MASTER\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${IOUTIL_TRUE}" && test -z "${IOUTIL_FALSE}"; then as_fn_error $? "conditional \"IOUTIL\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${AT91RM9200_TRUE}" && test -z "${AT91RM9200_FALSE}"; then as_fn_error $? "conditional \"AT91RM9200\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${BITBANG_TRUE}" && test -z "${BITBANG_FALSE}"; then as_fn_error $? "conditional \"BITBANG\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${FT2232_LIBFTDI_TRUE}" && test -z "${FT2232_LIBFTDI_FALSE}"; then as_fn_error $? "conditional \"FT2232_LIBFTDI\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${FT2232_DRIVER_TRUE}" && test -z "${FT2232_DRIVER_FALSE}"; then as_fn_error $? "conditional \"FT2232_DRIVER\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${FTDI_DRIVER_TRUE}" && test -z "${FTDI_DRIVER_FALSE}"; then as_fn_error $? "conditional \"FTDI_DRIVER\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${USB_BLASTER_LIBFTDI_TRUE}" && test -z "${USB_BLASTER_LIBFTDI_FALSE}"; then as_fn_error $? "conditional \"USB_BLASTER_LIBFTDI\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${USB_BLASTER_DRIVER_TRUE}" && test -z "${USB_BLASTER_DRIVER_FALSE}"; then as_fn_error $? "conditional \"USB_BLASTER_DRIVER\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${AMTJTAGACCEL_TRUE}" && test -z "${AMTJTAGACCEL_FALSE}"; then as_fn_error $? "conditional \"AMTJTAGACCEL\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${GW16012_TRUE}" && test -z "${GW16012_FALSE}"; then as_fn_error $? "conditional \"GW16012\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${PRESTO_LIBFTDI_TRUE}" && test -z "${PRESTO_LIBFTDI_FALSE}"; then as_fn_error $? "conditional \"PRESTO_LIBFTDI\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${PRESTO_DRIVER_TRUE}" && test -z "${PRESTO_DRIVER_FALSE}"; then as_fn_error $? "conditional \"PRESTO_DRIVER\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${USBPROG_TRUE}" && test -z "${USBPROG_FALSE}"; then as_fn_error $? "conditional \"USBPROG\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${OOCD_TRACE_TRUE}" && test -z "${OOCD_TRACE_FALSE}"; then as_fn_error $? "conditional \"OOCD_TRACE\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${JLINK_TRUE}" && test -z "${JLINK_FALSE}"; then as_fn_error $? "conditional \"JLINK\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${VSLLINK_TRUE}" && test -z "${VSLLINK_FALSE}"; then as_fn_error $? "conditional \"VSLLINK\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${RLINK_TRUE}" && test -z "${RLINK_FALSE}"; then as_fn_error $? "conditional \"RLINK\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ULINK_TRUE}" && test -z "${ULINK_FALSE}"; then as_fn_error $? "conditional \"ULINK\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ARMJTAGEW_TRUE}" && test -z "${ARMJTAGEW_FALSE}"; then as_fn_error $? "conditional \"ARMJTAGEW\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${REMOTE_BITBANG_TRUE}" && test -z "${REMOTE_BITBANG_FALSE}"; then as_fn_error $? "conditional \"REMOTE_BITBANG\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${BUSPIRATE_TRUE}" && test -z "${BUSPIRATE_FALSE}"; then as_fn_error $? "conditional \"BUSPIRATE\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HLADAPTER_TRUE}" && test -z "${HLADAPTER_FALSE}"; then as_fn_error $? "conditional \"HLADAPTER\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${OSBDM_TRUE}" && test -z "${OSBDM_FALSE}"; then as_fn_error $? "conditional \"OSBDM\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${OPENDOUS_TRUE}" && test -z "${OPENDOUS_FALSE}"; then as_fn_error $? "conditional \"OPENDOUS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${SYSFSGPIO_TRUE}" && test -z "${SYSFSGPIO_FALSE}"; then as_fn_error $? "conditional \"SYSFSGPIO\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${USB_TRUE}" && test -z "${USB_FALSE}"; then as_fn_error $? "conditional \"USB\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${USB_NG_TRUE}" && test -z "${USB_NG_FALSE}"; then as_fn_error $? "conditional \"USB_NG\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${USE_LIBUSB0_TRUE}" && test -z "${USE_LIBUSB0_FALSE}"; then as_fn_error $? "conditional \"USE_LIBUSB0\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${USE_LIBUSB1_TRUE}" && test -z "${USE_LIBUSB1_FALSE}"; then as_fn_error $? "conditional \"USE_LIBUSB1\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${IS_CYGWIN_TRUE}" && test -z "${IS_CYGWIN_FALSE}"; then as_fn_error $? "conditional \"IS_CYGWIN\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${IS_MINGW_TRUE}" && test -z "${IS_MINGW_FALSE}"; then as_fn_error $? "conditional \"IS_MINGW\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${IS_WIN32_TRUE}" && test -z "${IS_WIN32_FALSE}"; then as_fn_error $? "conditional \"IS_WIN32\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${IS_DARWIN_TRUE}" && test -z "${IS_DARWIN_FALSE}"; then as_fn_error $? "conditional \"IS_DARWIN\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${BITQ_TRUE}" && test -z "${BITQ_FALSE}"; then as_fn_error $? "conditional \"BITQ\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${MINIDRIVER_TRUE}" && test -z "${MINIDRIVER_FALSE}"; then as_fn_error $? "conditional \"MINIDRIVER\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${MINIDRIVER_DUMMY_TRUE}" && test -z "${MINIDRIVER_DUMMY_FALSE}"; then as_fn_error $? "conditional \"MINIDRIVER_DUMMY\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${INTERNAL_JIMTCL_TRUE}" && test -z "${INTERNAL_JIMTCL_FALSE}"; then as_fn_error $? "conditional \"INTERNAL_JIMTCL\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi : "${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 openocd $as_me 0.7.0, 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 case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" config_commands="$ac_config_commands" _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 --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Configuration commands: $config_commands Report bugs to >." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ openocd config.status 0.7.0 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' MKDIR_P='$MKDIR_P' AWK='$AWK' 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;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --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 # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`' hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$1 _LTECHO_EOF' } # Quote evaled strings. for var in SHELL \ ECHO \ PATH_SEPARATOR \ SED \ GREP \ EGREP \ FGREP \ LD \ NM \ LN_S \ lt_SP2NL \ lt_NL2SP \ reload_flag \ OBJDUMP \ deplibs_check_method \ file_magic_cmd \ file_magic_glob \ want_nocaseglob \ DLLTOOL \ sharedlib_from_linklib_cmd \ AR \ AR_FLAGS \ archiver_list_spec \ STRIP \ RANLIB \ CC \ CFLAGS \ compiler \ lt_cv_sys_global_symbol_pipe \ lt_cv_sys_global_symbol_to_cdecl \ lt_cv_sys_global_symbol_to_c_name_address \ lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ nm_file_list_spec \ lt_prog_compiler_no_builtin_flag \ lt_prog_compiler_pic \ lt_prog_compiler_wl \ lt_prog_compiler_static \ lt_cv_prog_compiler_c_o \ need_locks \ MANIFEST_TOOL \ DSYMUTIL \ NMEDIT \ LIPO \ OTOOL \ OTOOL64 \ shrext_cmds \ export_dynamic_flag_spec \ whole_archive_flag_spec \ compiler_needs_object \ with_gnu_ld \ allow_undefined_flag \ no_undefined_flag \ hardcode_libdir_flag_spec \ hardcode_libdir_separator \ exclude_expsyms \ include_expsyms \ file_list_spec \ variables_saved_for_relink \ libname_spec \ library_names_spec \ soname_spec \ install_override_mode \ finish_eval \ old_striplib \ striplib; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in reload_cmds \ old_postinstall_cmds \ old_postuninstall_cmds \ old_archive_cmds \ extract_expsyms_cmds \ old_archive_from_new_cmds \ old_archive_from_expsyms_cmds \ archive_cmds \ archive_expsym_cmds \ module_cmds \ module_expsym_cmds \ export_symbols_cmds \ prelink_cmds \ postlink_cmds \ postinstall_cmds \ postuninstall_cmds \ finish_cmds \ sys_lib_search_path_spec \ sys_lib_dlsearch_path_spec; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done ac_aux_dir='$ac_aux_dir' xsi_shell='$xsi_shell' lt_shell_append='$lt_shell_append' # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi PACKAGE='$PACKAGE' VERSION='$VERSION' TIMESTAMP='$TIMESTAMP' RM='$RM' ofile='$ofile' _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 "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; "src/helper/Makefile") CONFIG_FILES="$CONFIG_FILES src/helper/Makefile" ;; "src/jtag/Makefile") CONFIG_FILES="$CONFIG_FILES src/jtag/Makefile" ;; "src/jtag/drivers/Makefile") CONFIG_FILES="$CONFIG_FILES src/jtag/drivers/Makefile" ;; "src/jtag/hla/Makefile") CONFIG_FILES="$CONFIG_FILES src/jtag/hla/Makefile" ;; "src/transport/Makefile") CONFIG_FILES="$CONFIG_FILES src/transport/Makefile" ;; "src/xsvf/Makefile") CONFIG_FILES="$CONFIG_FILES src/xsvf/Makefile" ;; "src/svf/Makefile") CONFIG_FILES="$CONFIG_FILES src/svf/Makefile" ;; "src/target/Makefile") CONFIG_FILES="$CONFIG_FILES src/target/Makefile" ;; "src/rtos/Makefile") CONFIG_FILES="$CONFIG_FILES src/rtos/Makefile" ;; "src/server/Makefile") CONFIG_FILES="$CONFIG_FILES src/server/Makefile" ;; "src/flash/Makefile") CONFIG_FILES="$CONFIG_FILES src/flash/Makefile" ;; "src/flash/nor/Makefile") CONFIG_FILES="$CONFIG_FILES src/flash/nor/Makefile" ;; "src/flash/nand/Makefile") CONFIG_FILES="$CONFIG_FILES src/flash/nand/Makefile" ;; "src/pld/Makefile") CONFIG_FILES="$CONFIG_FILES src/pld/Makefile" ;; "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/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 test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands 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" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" 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 ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; 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 s&@MKDIR_P@&$ac_MKDIR_P&;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 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi # Compute "$ac_file"'s index in $config_headers. _am_arg="$ac_file" _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || $as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$_am_arg" : 'X\(//\)[^/]' \| \ X"$_am_arg" : 'X\(//\)$' \| \ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$_am_arg" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'`/stamp-h$_am_stamp_count ;; :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 $as_echo "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "depfiles":C) test x"$AMDEP_TRUE" != x"" || { # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named 'Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`$as_dirname -- "$mf" || $as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$mf" : 'X\(//\)[^/]' \| \ X"$mf" : 'X\(//\)$' \| \ X"$mf" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running 'make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`$as_dirname -- "$file" || $as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$file" : 'X\(//\)[^/]' \| \ X"$file" : 'X\(//\)$' \| \ X"$file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir=$dirpart/$fdir; as_fn_mkdir_p # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ;; "libtool":C) # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi cfgfile="${ofile}T" trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is part of GNU Libtool. # # GNU Libtool 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. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool 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 GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, or # obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # The names of the tagged configurations supported by this script. available_tags="" # ### BEGIN LIBTOOL CONFIG # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # Which release of libtool.m4 was used? macro_version=$macro_version macro_revision=$macro_revision # Whether or not to build static libraries. build_old_libs=$enable_static # What type of objects to build. pic_mode=$pic_mode # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # An echo program that protects backslashes. ECHO=$lt_ECHO # The PATH separator for the build system. PATH_SEPARATOR=$lt_PATH_SEPARATOR # The host system. host_alias=$host_alias host=$host host_os=$host_os # The build system. build_alias=$build_alias build=$build build_os=$build_os # A sed program that does not truncate output. SED=$lt_SED # Sed that helps us avoid accidentally triggering echo(1) options like -n. Xsed="\$SED -e 1s/^X//" # A grep program that handles long lines. GREP=$lt_GREP # An ERE matcher. EGREP=$lt_EGREP # A literal string matcher. FGREP=$lt_FGREP # A BSD- or MS-compatible name lister. NM=$lt_NM # Whether we need soft or hard links. LN_S=$lt_LN_S # What is the maximum length of a command? max_cmd_len=$max_cmd_len # Object file suffix (normally "o"). objext=$ac_objext # Executable file suffix (normally ""). exeext=$exeext # whether the shell understands "unset". lt_unset=$lt_unset # turn spaces into newlines. SP2NL=$lt_lt_SP2NL # turn newlines into spaces. NL2SP=$lt_lt_NL2SP # convert \$build file names to \$host format. to_host_file_cmd=$lt_cv_to_host_file_cmd # convert \$build files to toolchain format. to_tool_file_cmd=$lt_cv_to_tool_file_cmd # An object symbol dumper. OBJDUMP=$lt_OBJDUMP # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method # Command to use when deplibs_check_method = "file_magic". file_magic_cmd=$lt_file_magic_cmd # How to find potential files when deplibs_check_method = "file_magic". file_magic_glob=$lt_file_magic_glob # Find potential files using nocaseglob when deplibs_check_method = "file_magic". want_nocaseglob=$lt_want_nocaseglob # DLL creation program. DLLTOOL=$lt_DLLTOOL # Command to associate shared and link libraries. sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd # The archiver. AR=$lt_AR # Flags to create an archive. AR_FLAGS=$lt_AR_FLAGS # How to feed a file listing to the archiver. archiver_list_spec=$lt_archiver_list_spec # A symbol stripping program. STRIP=$lt_STRIP # Commands used to install an old-style archive. RANLIB=$lt_RANLIB old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # Whether to use a lock for old archive extraction. lock_old_archive_extraction=$lock_old_archive_extraction # A C compiler. LTCC=$lt_CC # LTCC compiler flags. LTCFLAGS=$lt_CFLAGS # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration. global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm in a C name address pair. global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # Transform the output of nm in a C name address pair when lib prefix is needed. global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix # Specify filename containing input files for \$NM. nm_file_list_spec=$lt_nm_file_list_spec # The root where to search for dependent libraries,and in which our libraries should be installed. lt_sysroot=$lt_sysroot # The name of the directory that contains temporary libtool files. objdir=$objdir # Used to examine libraries when file_magic_cmd begins with "file". MAGIC_CMD=$MAGIC_CMD # Must we lock files when doing compilation? need_locks=$lt_need_locks # Manifest tool. MANIFEST_TOOL=$lt_MANIFEST_TOOL # Tool to manipulate archived DWARF debug symbol files on Mac OS X. DSYMUTIL=$lt_DSYMUTIL # Tool to change global to local symbols on Mac OS X. NMEDIT=$lt_NMEDIT # Tool to manipulate fat objects and archives on Mac OS X. LIPO=$lt_LIPO # ldd/readelf like tool for Mach-O binaries on Mac OS X. OTOOL=$lt_OTOOL # ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. OTOOL64=$lt_OTOOL64 # Old archive suffix (normally "a"). libext=$libext # Shared library suffix (normally ".so"). shrext_cmds=$lt_shrext_cmds # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Variables whose values should be saved in libtool wrapper scripts and # restored at link time. variables_saved_for_relink=$lt_variables_saved_for_relink # Do we need the "lib" prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Library versioning type. version_type=$version_type # Shared library runtime path variable. runpath_var=$runpath_var # Shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # Format of library name prefix. libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec # Permission mode override for installation of shared libraries. install_override_mode=$lt_install_override_mode # Command to use after installation of a shared archive. postinstall_cmds=$lt_postinstall_cmds # Command to use after uninstallation of a shared archive. postuninstall_cmds=$lt_postuninstall_cmds # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # As "finish_cmds", except a single script fragment to be evaled but # not shown. finish_eval=$lt_finish_eval # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Compile-time system search path for libraries. sys_lib_search_path_spec=$lt_sys_lib_search_path_spec # Run-time system search path for libraries. sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec # Whether dlopen is supported. dlopen_support=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # The linker used to build libraries. LD=$lt_LD # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # Commands used to build an old-style archive. old_archive_cmds=$lt_old_archive_cmds # A language specific compiler. CC=$lt_compiler # Is the compiler the GNU compiler? with_gcc=$GCC # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc # Whether or not to disallow shared libs when runtime libs are static. allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec # Whether the compiler copes with passing no objects directly. compiler_needs_object=$lt_compiler_needs_object # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds # Commands used to build a shared archive. archive_cmds=$lt_archive_cmds archive_expsym_cmds=$lt_archive_expsym_cmds # Commands used to build a loadable module if different from building # a shared archive. module_cmds=$lt_module_cmds module_expsym_cmds=$lt_module_expsym_cmds # Whether we are building with GNU ld or not. with_gnu_ld=$lt_with_gnu_ld # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag # Flag that enforces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec # Whether we need a single "-rpath" flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator # Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary. hardcode_direct=$hardcode_direct # Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary and the resulting library dependency is # "absolute",i.e impossible to change by setting \${shlibpath_var} if the # library is relocated. hardcode_direct_absolute=$hardcode_direct_absolute # Set to "yes" if using the -LDIR flag during linking hardcodes DIR # into the resulting binary. hardcode_minus_L=$hardcode_minus_L # Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR # into the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var # Set to "yes" if building a shared library automatically hardcodes DIR # into the library and all subsequent libraries and executables linked # against it. hardcode_automatic=$hardcode_automatic # Set to yes if linker adds runtime paths of dependent libraries # to runtime path list. inherit_rpath=$inherit_rpath # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs # Set to "yes" if exported symbols are required. always_export_symbols=$always_export_symbols # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms # Symbols that must always be exported. include_expsyms=$lt_include_expsyms # Commands necessary for linking programs (against libraries) with templates. prelink_cmds=$lt_prelink_cmds # Commands necessary for finishing linking programs. postlink_cmds=$lt_postlink_cmds # Specify filename containing input files. file_list_spec=$lt_file_list_spec # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action # ### END LIBTOOL CONFIG _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac ltmain="$ac_aux_dir/ltmain.sh" # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) if test x"$xsi_shell" = xyes; then sed -e '/^func_dirname ()$/,/^} # func_dirname /c\ func_dirname ()\ {\ \ case ${1} in\ \ */*) func_dirname_result="${1%/*}${2}" ;;\ \ * ) func_dirname_result="${3}" ;;\ \ esac\ } # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_basename ()$/,/^} # func_basename /c\ func_basename ()\ {\ \ func_basename_result="${1##*/}"\ } # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\ func_dirname_and_basename ()\ {\ \ case ${1} in\ \ */*) func_dirname_result="${1%/*}${2}" ;;\ \ * ) func_dirname_result="${3}" ;;\ \ esac\ \ func_basename_result="${1##*/}"\ } # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_stripname ()$/,/^} # func_stripname /c\ func_stripname ()\ {\ \ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are\ \ # positional parameters, so assign one to ordinary parameter first.\ \ func_stripname_result=${3}\ \ func_stripname_result=${func_stripname_result#"${1}"}\ \ func_stripname_result=${func_stripname_result%"${2}"}\ } # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\ func_split_long_opt ()\ {\ \ func_split_long_opt_name=${1%%=*}\ \ func_split_long_opt_arg=${1#*=}\ } # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\ func_split_short_opt ()\ {\ \ func_split_short_opt_arg=${1#??}\ \ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\ } # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\ func_lo2o ()\ {\ \ case ${1} in\ \ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\ \ *) func_lo2o_result=${1} ;;\ \ esac\ } # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_xform ()$/,/^} # func_xform /c\ func_xform ()\ {\ func_xform_result=${1%.*}.lo\ } # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_arith ()$/,/^} # func_arith /c\ func_arith ()\ {\ func_arith_result=$(( $* ))\ } # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_len ()$/,/^} # func_len /c\ func_len ()\ {\ func_len_result=${#1}\ } # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$lt_shell_append" = xyes; then sed -e '/^func_append ()$/,/^} # func_append /c\ func_append ()\ {\ eval "${1}+=\\${2}"\ } # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\ func_append_quoted ()\ {\ \ func_quote_for_eval "${2}"\ \ eval "${1}+=\\\\ \\$func_quote_for_eval_result"\ } # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: # Save a `func_append' function call where possible by direct use of '+=' sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: else # Save a `func_append' function call even when '+=' is not available sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$_lt_function_replace_fail" = x":"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5 $as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;} fi mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ;; 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 # # CONFIG_SUBDIRS section. # if test "$no_recursion" != yes; then # Remove --cache-file, --srcdir, and --disable-option-checking arguments # so they do not pile up. ac_sub_configure_args= ac_prev= eval "set x $ac_configure_args" shift for ac_arg do if test -n "$ac_prev"; then ac_prev= continue fi case $ac_arg in -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=*) ;; --config-cache | -C) ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) ;; --disable-option-checking) ;; *) case $ac_arg in *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append ac_sub_configure_args " '$ac_arg'" ;; esac done # Always prepend --prefix to ensure using the same prefix # in subdir configurations. ac_arg="--prefix=$prefix" case $ac_arg in *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac ac_sub_configure_args="'$ac_arg' $ac_sub_configure_args" # Pass --silent if test "$silent" = yes; then ac_sub_configure_args="--silent $ac_sub_configure_args" fi # Always prepend --disable-option-checking to silence warnings, since # different subdirs can have different --enable and --with options. ac_sub_configure_args="--disable-option-checking $ac_sub_configure_args" ac_popdir=`pwd` for ac_dir in : $subdirs; do test "x$ac_dir" = x: && continue # Do not complain, so a configure script can configure whichever # parts of a large source tree are present. test -d "$srcdir/$ac_dir" || continue ac_msg="=== configuring in $ac_dir (`pwd`/$ac_dir)" $as_echo "$as_me:${as_lineno-$LINENO}: $ac_msg" >&5 $as_echo "$ac_msg" >&6 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 cd "$ac_dir" # Check for guested configure; otherwise get Cygnus style configure. if test -f "$ac_srcdir/configure.gnu"; then ac_sub_configure=$ac_srcdir/configure.gnu elif test -f "$ac_srcdir/configure"; then ac_sub_configure=$ac_srcdir/configure elif test -f "$ac_srcdir/configure.in"; then # This should be Cygnus configure. ac_sub_configure=$ac_aux_dir/configure else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: no configuration information is in $ac_dir" >&5 $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2;} ac_sub_configure= fi # The recursion is here. if test -n "$ac_sub_configure"; then # Make the cache file name correct relative to the subdirectory. case $cache_file in [\\/]* | ?:[\\/]* ) ac_sub_cache_file=$cache_file ;; *) # Relative name. ac_sub_cache_file=$ac_top_build_prefix$cache_file ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&5 $as_echo "$as_me: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&6;} # The eval makes quoting arguments work. eval "\$SHELL \"\$ac_sub_configure\" $ac_sub_configure_args \ --cache-file=\"\$ac_sub_cache_file\" --srcdir=\"\$ac_srcdir\"" || as_fn_error $? "$ac_sub_configure failed for $ac_dir" "$LINENO" 5 fi cd "$ac_popdir" done 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 openocd-0.7.0/BUGS0000644000175000001440000000475412134336410010554 00000000000000// This file is part of the Doxygen Developer Manual /** @page bugs Bug Reporting Please report bugs by subscribing to the OpenOCD mailing list and posting a message with your report: openocd-devel@lists.sourceforge.net Also, please check the Trac bug database to see if a ticket for the bug has already been opened. You might be asked to open such a ticket, or to update an existing ticket with more data. https://sourceforge.net/apps/trac/openocd/ To minimize work for OpenOCD developers, you should try to include all of the information listed below. If you feel that some of the items below are unnecessary for a clear bug report, you may leave them out; likewise, feel free to include additional information that may be important. - Target PCB/board description - Configuration scripts - OpenOCD command line - List of commands issued or GDB operations performed - Expected result - Actual result - Logs using debug_level 3 (or with '-d 3' on the command line) - If the report is for a regression: - Include logs for both working and broken versions. - Find the precise version that caused the regression by binary search. You can use "git bisect" to expedite this binary search: http://www.kernel.org/pub/software/scm/git/docs/git-bisect.html If possible, please develop and attach a patch that helps to expose or solve the reported problem. See the HACKING file for information about that process. Attach all files directly to your posting. The mailing list knows to transform attachments to links, but attachments must be less than 300KB in total. @section bugscrashdump Obtaining Crash Backtraces If OpenOCD is crashing, there are two very effective things you can do to improve your chances of getting help on the development mailing list. Try to reproduce the problem using the dummy JTAG interface to allow other developers to replicate your problem robustly and use GDB to get a trace:@par @code % OPENOCDSRC/configure --enable-dummy ... % openocd -f interface/dummy.cfg -f target/xxx.cfg => SEGFAULT % gdb --args openocd .... (gdb) run (gdb) bt => here a stack trace is dumped. @endcode @section bugsintreedebug Running and Debugging In-Tree To run or debug the in-tree executable (not recommended), you must use libtool to set up the correct shared library paths: @code libtool gdb --args openocd .... @endcode or the more pedantic (and forward-compatible): @code libtool --mode=execute gdb --args openocd .... @endcode */ /** @file This file contains the @ref bugs page. */ openocd-0.7.0/config.sub0000755000175000001440000010546712141414275012063 00000000000000#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, # 2011, 2012, 2013 Free Software Foundation, Inc. timestamp='2012-12-29' # 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 3 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, see . # # 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. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches with a ChangeLog entry to config-patches@gnu.org. # # 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. # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD # 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, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 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" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) 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* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; android-linux) os=-linux-android basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown ;; *) 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 | -knuth | -cray | -microblaze*) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -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 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -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/'` ;; -sco5v6*) # 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*178) os=-lynxos178 ;; -lynx*5) os=-lynxos5 ;; -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 \ | aarch64 | aarch64_be \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc \ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ | avr | avr32 \ | be32 | be64 \ | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | epiphany \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ | nios | nios2 \ | ns16k | ns32k \ | open8 \ | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ | rl78 | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu \ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; c54x) basic_machine=tic54x-unknown ;; c55x) basic_machine=tic55x-unknown ;; c6x) basic_machine=tic6x-unknown ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; strongarm | thumb | xscale) basic_machine=arm-unknown ;; xgate) basic_machine=$basic_machine-unknown os=-none ;; xscaleeb) basic_machine=armeb-unknown ;; xscaleel) basic_machine=armel-unknown ;; # 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-* \ | aarch64-* | aarch64_be-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hexagon-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | le32-* | le64-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ | microblaze-* | microblazeel-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ | nios-* | nios2-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # 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 ;; abacus) basic_machine=abacus-unknown ;; 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 ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; 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 ;; aros) basic_machine=i386-pc os=-aros ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c54x-*) basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c55x-*) basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c6x-*) basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; 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 | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16 | cr16-*) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; 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*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 ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze*) basic_machine=microblaze-xilinx ;; mingw64) basic_machine=x86_64-pc os=-mingw64 ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; msys) basic_machine=i386-pc os=-msys ;; mvs) basic_machine=i370-ibm os=-mvs ;; nacl) basic_machine=le32-unknown os=-nacl ;; 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 ;; neo-tandem) basic_machine=neo-tandem ;; nse-tandem) basic_machine=nse-tandem ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; 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 ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc | ppcbe) basic_machine=powerpc-unknown ;; ppc-* | ppcbe-*) 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 ;; rdos | rdos64) basic_machine=x86_64-pc os=-rdos ;; rdos32) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-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 ;; strongarm-* | thumb-*) basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` ;; 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=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tile*) basic_machine=$basic_machine-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; 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 ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; xscale-* | xscalee[bl]-*) basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-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 ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; 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 ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) 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 ;; *-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. -auroraux) os=-auroraux ;; -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* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -bitrig* | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-musl* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -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 ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -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 ;; -aros*) os=-aros ;; -kaos*) os=-kaos ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -nacl*) ;; -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 score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; hexagon-*) os=-elf ;; tic54x-*) os=-coff ;; tic55x-*) os=-coff ;; tic6x-*) os=-coff ;; # This must come before the *-dec entry. 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 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-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 ;; -cnk*|-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 ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) 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 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: openocd-0.7.0/doc/0000755000175000001440000000000012141414413010702 500000000000000openocd-0.7.0/doc/openocd.info0000644000175000001440000000652112141414411013130 00000000000000This is openocd.info, produced by makeinfo version 5.1 from openocd.texi. This User's Guide documents release 0.7.0, dated 4 May 2013, of the Open On-Chip Debugger (OpenOCD). * Copyright (C) 2008 The OpenOCD Project * Copyright (C) 2007-2008 Spencer Oliver * Copyright (C) 2008-2010 Oyvind Harboe * Copyright (C) 2008 Duane Ellis * Copyright (C) 2009-2010 David Brownell Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, with no Front-Cover Texts, and with no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License". INFO-DIR-SECTION Development START-INFO-DIR-ENTRY * OpenOCD: (openocd). OpenOCD User's Guide END-INFO-DIR-ENTRY  Indirect: openocd.info-1: 990 openocd.info-2: 301821  Tag Table: (Indirect) Node: Top990 Node: About3496 Node: Developers7842 Node: Debug Adapter Hardware10510 Node: About Jim-Tcl21044 Node: Running23186 Node: OpenOCD Project Setup28081 Ref: OpenOCD Project Setup-Footnote-147973 Ref: OpenOCD Project Setup-Footnote-248313 Ref: OpenOCD Project Setup-Footnote-348581 Node: Config File Guidelines48909 Ref: theinitboardprocedure72069 Ref: definecputargetsworkinginsmp78860 Ref: theinittargetsprocedure83294 Ref: translatingconfigurationfiles86553 Ref: Config File Guidelines-Footnote-187780 Node: Daemon Configuration87855 Ref: configurationstage88177 Ref: enteringtherunstage89029 Ref: tcpipports91478 Ref: gdbconfiguration93724 Ref: gdbbreakpointoverride94039 Ref: gdbflashprogram94414 Ref: eventpolling95289 Node: Debug Adapter Configuration97725 Ref: jtagspeed125585 Node: Reset Configuration128543 Ref: srstandtrstissues131471 Node: TAP Declaration143516 Ref: enablinganddisablingtaps155076 Ref: autoprobing157723 Ref: TAP Declaration-Footnote-1160414 Node: CPU Configuration160614 Ref: targettypes164761 Ref: targetconfiguration166765 Ref: targetcurstate175679 Ref: targetevents176920 Node: Flash Commands181766 Ref: norconfiguration183298 Ref: flashprogrammingcommands185957 Ref: flashprotect191530 Ref: program191888 Ref: flashdriverlist192139 Ref: at91sam3196024 Ref: Flash Commands-Footnote-1221282 Ref: Flash Commands-Footnote-2221448 Node: Flash Programming221613 Node: NAND Flash Commands223061 Ref: nandconfiguration226029 Ref: nanddriverlist236404 Node: PLD/FPGA Commands241099 Node: General Commands243162 Ref: debuglevel245109 Ref: targetstatehandling246035 Ref: resetcommand249687 Ref: memoryaccess251957 Ref: imageaccess253584 Node: Architecture and Core Commands257966 Ref: armhardwaretracing258436 Ref: traceportdrivers266354 Ref: arm9vectorcatch274250 Ref: xscalevectorcatch282653 Ref: softwaredebugmessagesandtracing288914 Node: JTAG Commands292381 Node: Boundary Scan Commands301821 Node: TFTP304271 Node: GDB and OpenOCD305145 Ref: programmingusinggdb310040 Ref: usingopenocdsmpwithgdb311483 Node: Tcl Scripting API312914 Node: FAQ315554 Ref: faqrtck315664 Ref: faqtaporder328202 Node: Tcl Crash Course329965 Node: License341963 Node: OpenOCD Concept Index364373 Node: Command and Driver Index382304  End Tag Table openocd-0.7.0/doc/version.texi0000644000175000001440000000013212141414310013172 00000000000000@set UPDATED 4 May 2013 @set UPDATED-MONTH May 2013 @set EDITION 0.7.0 @set VERSION 0.7.0 openocd-0.7.0/doc/openocd.info-10000644000175000001440000111343712141414411013274 00000000000000This is openocd.info, produced by makeinfo version 5.1 from openocd.texi. This User's Guide documents release 0.7.0, dated 4 May 2013, of the Open On-Chip Debugger (OpenOCD). * Copyright (C) 2008 The OpenOCD Project * Copyright (C) 2007-2008 Spencer Oliver * Copyright (C) 2008-2010 Oyvind Harboe * Copyright (C) 2008 Duane Ellis * Copyright (C) 2009-2010 David Brownell Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, with no Front-Cover Texts, and with no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License". INFO-DIR-SECTION Development START-INFO-DIR-ENTRY * OpenOCD: (openocd). OpenOCD User's Guide END-INFO-DIR-ENTRY  File: openocd.info, Node: Top, Next: About, Up: (dir) OpenOCD User's Guide ******************** This User's Guide documents release 0.7.0, dated 4 May 2013, of the Open On-Chip Debugger (OpenOCD). * Copyright (C) 2008 The OpenOCD Project * Copyright (C) 2007-2008 Spencer Oliver * Copyright (C) 2008-2010 Oyvind Harboe * Copyright (C) 2008 Duane Ellis * Copyright (C) 2009-2010 David Brownell Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, with no Front-Cover Texts, and with no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License". * Menu: * About:: About OpenOCD * Developers:: OpenOCD Developer Resources * Debug Adapter Hardware:: Debug Adapter Hardware * About Jim-Tcl:: About Jim-Tcl * Running:: Running OpenOCD * OpenOCD Project Setup:: OpenOCD Project Setup * Config File Guidelines:: Config File Guidelines * Daemon Configuration:: Daemon Configuration * Debug Adapter Configuration:: Debug Adapter Configuration * Reset Configuration:: Reset Configuration * TAP Declaration:: TAP Declaration * CPU Configuration:: CPU Configuration * Flash Commands:: Flash Commands * Flash Programming:: Flash Programming * NAND Flash Commands:: NAND Flash Commands * PLD/FPGA Commands:: PLD/FPGA Commands * General Commands:: General Commands * Architecture and Core Commands:: Architecture and Core Commands * JTAG Commands:: JTAG Commands * Boundary Scan Commands:: Boundary Scan Commands * TFTP:: TFTP * GDB and OpenOCD:: Using GDB and OpenOCD * Tcl Scripting API:: Tcl Scripting API * FAQ:: Frequently Asked Questions * Tcl Crash Course:: Tcl Crash Course * License:: GNU Free Documentation License * OpenOCD Concept Index:: Concept Index * Command and Driver Index:: Command and Driver Index  File: openocd.info, Node: About, Next: Developers, Prev: Top, Up: Top About ***** OpenOCD was created by Dominic Rath as part of a diploma thesis written at the University of Applied Sciences Augsburg (). Since that time, the project has grown into an active open-source project, supported by a diverse community of software and hardware developers from around the world. What is OpenOCD? ================ The Open On-Chip Debugger (OpenOCD) aims to provide debugging, in-system programming and boundary-scan testing for embedded target devices. It does so with the assistance of a "debug adapter", which is a small hardware module which helps provide the right kind of electrical signaling to the target being debugged. These are required since the debug host (on which OpenOCD runs) won't usually have native support for such signaling, or the connector needed to hook up to the target. Such debug adapters support one or more "transport" protocols, each of which involves different electrical signaling (and uses different messaging protocols on top of that signaling). There are many types of debug adapter, and little uniformity in what they are called. (There are also product naming differences.) These adapters are sometimes packaged as discrete dongles, which may generically be called "hardware interface dongles". Some development boards also integrate them directly, which may let the development board can be directly connected to the debug host over USB (and sometimes also to power it over USB). For example, a "JTAG Adapter" supports JTAG signaling, and is used to communicate with JTAG (IEEE 1149.1) compliant TAPs on your target board. A "TAP" is a "Test Access Port", a module which processes special instructions and data. TAPs are daisy-chained within and between chips and boards. JTAG supports debugging and boundary scan operations. There are also "SWD Adapters" that support Serial Wire Debug (SWD) signaling to communicate with some newer ARM cores, as well as debug adapters which support both JTAG and SWD transports. SWD only supports debugging, whereas JTAG also supports boundary scan operations. For some chips, there are also "Programming Adapters" supporting special transports used only to write code to flash memory, without support for on-chip debugging or boundary scan. (At this writing, OpenOCD does not support such non-debug adapters.) Dongles: OpenOCD currently supports many types of hardware dongles: USB based, parallel port based, and other standalone boxes that run OpenOCD internally. *Note Debug Adapter Hardware::. GDB Debug: It allows ARM7 (ARM7TDMI and ARM720t), ARM9 (ARM920T, ARM922T, ARM926EJ-S, ARM966E-S), XScale (PXA25x, IXP42x) and Cortex-M3 (Stellaris LM3, ST STM32 and Energy Micro EFM32) based cores to be debugged via the GDB protocol. Flash Programing: Flash writing is supported for external CFI compatible NOR flashes (Intel and AMD/Spansion command set) and several internal flashes (LPC1700, LPC1800, LPC2000, LPC4300, AT91SAM7, AT91SAM3U, STR7x, STR9x, LM3, STM32x and EFM32). Preliminary support for various NAND flash controllers (LPC3180, Orion, S3C24xx, more) controller is included. OpenOCD Web Site ================ The OpenOCD web site provides the latest public news from the community: Latest User's Guide: ==================== The user's guide you are now reading may not be the latest one available. A version for more recent code may be available. Its HTML form is published regularly at: PDF form is likewise published at: OpenOCD User's Forum ==================== There is an OpenOCD forum (phpBB) hosted by SparkFun, which might be helpful to you. Note that if you want anything to come to the attention of developers, you should post it to the OpenOCD Developer Mailing List instead of this forum. OpenOCD User's Mailing List =========================== The OpenOCD User Mailing List provides the primary means of communication between users: OpenOCD IRC =========== Support can also be found on irc:  File: openocd.info, Node: Developers, Next: Debug Adapter Hardware, Prev: About, Up: Top 1 OpenOCD Developer Resources ***************************** If you are interested in improving the state of OpenOCD's debugging and testing support, new contributions will be welcome. Motivated developers can produce new target, flash or interface drivers, improve the documentation, as well as more conventional bug fixes and enhancements. The resources in this chapter are available for developers wishing to explore or expand the OpenOCD source code. 1.1 OpenOCD GIT Repository ========================== During the 0.3.x release cycle, OpenOCD switched from Subversion to a GIT repository hosted at SourceForge. The repository URL is: or via http You may prefer to use a mirror and the HTTP protocol: With standard GIT tools, use 'git clone' to initialize a local repository, and 'git pull' to update it. There are also gitweb pages letting you browse the repository with a web browser, or download arbitrary snapshots without needing a GIT client: The 'README' file contains the instructions for building the project from the repository or a snapshot. Developers that want to contribute patches to the OpenOCD system are strongly encouraged to work against mainline. Patches created against older versions may require additional work from their submitter in order to be updated for newer releases. 1.2 Doxygen Developer Manual ============================ During the 0.2.x release cycle, the OpenOCD project began providing a Doxygen reference manual. This document contains more technical information about the software internals, development processes, and similar documentation: This document is a work-in-progress, but contributions would be welcome to fill in the gaps. All of the source files are provided in-tree, listed in the Doxyfile configuration in the top of the source tree. 1.3 OpenOCD Developer Mailing List ================================== The OpenOCD Developer Mailing List provides the primary means of communication between developers: Discuss and submit patches to this list. The 'HACKING' file contains basic information about how to prepare patches. 1.4 OpenOCD Bug Database ======================== During the 0.4.x release cycle the OpenOCD project team began using Trac for its bug database:  File: openocd.info, Node: Debug Adapter Hardware, Next: About Jim-Tcl, Prev: Developers, Up: Top 2 Debug Adapter Hardware ************************ Defined: dongle: A small device that plugins into a computer and serves as an adapter .... [snip] In the OpenOCD case, this generally refers to a small adapter that attaches to your computer via USB or the Parallel Printer Port. One exception is the Zylin ZY1000, packaged as a small box you attach via an ethernet cable. The Zylin ZY1000 has the advantage that it does not require any drivers to be installed on the developer PC. It also has a built in web interface. It supports RTCK/RCLK or adaptive clocking and has a built in relay to power cycle targets remotely. 2.1 Choosing a Dongle ===================== There are several things you should keep in mind when choosing a dongle. 1. Transport Does it support the kind of communication that you need? OpenOCD focusses mostly on JTAG. Your version may also support other ways to communicate with target devices. 2. Voltage What voltage is your target - 1.8, 2.8, 3.3, or 5V? Does your dongle support it? You might need a level converter. 3. Pinout What pinout does your target board use? Does your dongle support it? You may be able to use jumper wires, or an "octopus" connector, to convert pinouts. 4. Connection Does your computer have the USB, printer, or Ethernet port needed? 5. RTCK Do you expect to use it with ARM chips and boards with RTCK support? Also known as "adaptive clocking" 2.2 Stand alone Systems ======================= ZY1000 See: Technically, not a dongle, but a standalone box. The ZY1000 has the advantage that it does not require any drivers installed on the developer PC. It also has a built in web interface. It supports RTCK/RCLK or adaptive clocking and has a built in relay to power cycle targets remotely. 2.3 USB FT2232 Based ==================== There are many USB JTAG dongles on the market, many of them are based on a chip from "Future Technology Devices International" (FTDI) known as the FTDI FT2232; this is a USB full speed (12 Mbps) chip. See: for more information. In summer 2009, USB high speed (480 Mbps) versions of these FTDI chips are starting to become available in JTAG adapters. Around 2012 a new variant appeared - FT232H - this is a single-channel version of FT2232H. (Adapters using those high speed FT2232H or FT232H chips may support adaptive clocking.) The FT2232 chips are flexible enough to support some other transport options, such as SWD or the SPI variants used to program some chips. They have two communications channels, and one can be used for a UART adapter at the same time the other one is used to provide a debug adapter. Also, some development boards integrate an FT2232 chip to serve as a built-in low cost debug adapter and usb-to-serial solution. * usbjtag Link * jtagkey See: * jtagkey2 See: * oocdlink See: By Joern Kaipf * signalyzer See: * Stellaris Eval Boards See: - The Stellaris eval boards bundle FT2232-based JTAG and SWD support, which can be used to debug the Stellaris chips. Using separate JTAG adapters is optional. These boards can also be used in a "pass through" mode as JTAG adapters to other target boards, disabling the Stellaris chip. * TI/Luminary ICDI See: - TI/Luminary In-Circuit Debug Interface (ICDI) Boards are included in Stellaris LM3S9B9x Evaluation Kits. Like the non-detachable FT2232 support on the other Stellaris eval boards, they can be used to debug other target boards. * olimex-jtag See: * Flyswatter/Flyswatter2 See: * turtelizer2 See: Turtelizer 2 (http://www.ethernut.de/en/hardware/turtelizer/index.html), or * comstick Link: * stm32stick Link * axm0432_jtag Axiom AXM-0432 Link - NOTE: This JTAG does not appear to be available anymore as of April 2012. * cortino Link * dlp-usb1232h Link * digilent-hs1 Link * opendous Link FT2232H-based (OpenHardware). * JTAG-lock-pick Tiny 2 Link FT232H-based 2.4 USB-JTAG / Altera USB-Blaster compatibles ============================================= These devices also show up as FTDI devices, but are not protocol-compatible with the FT2232 devices. They are, however, protocol-compatible among themselves. USB-JTAG devices typically consist of a FT245 followed by a CPLD that understands a particular protocol, or emulate this protocol using some other hardware. They may appear under different USB VID/PID depending on the particular product. The driver can be configured to search for any VID/PID pair (see the section on driver commands). * USB-JTAG Kolja Waschk's USB Blaster-compatible adapter Link: * Altera USB-Blaster Link: 2.5 USB JLINK based =================== There are several OEM versions of the Segger JLINK adapter. It is an example of a micro controller based JTAG adapter, it uses an AT91SAM764 internally. * ATMEL SAMICE Only works with ATMEL chips! Link: * SEGGER JLINK Link: * IAR J-Link Link: 2.6 USB RLINK based =================== Raisonance has an adapter called RLink. It exists in a stripped-down form on the STM32 Primer, permanently attached to the JTAG lines. It also exists on the STM32 Primer2, but that is wired for SWD and not JTAG, thus not supported. * Raisonance RLink Link: * STM32 Primer Link: * STM32 Primer2 Link: 2.7 USB ST-LINK based ===================== ST Micro has an adapter called ST-LINK. They only work with ST Micro chips, notably STM32 and STM8. * ST-LINK This is available standalone and as part of some kits, eg. STM32VLDISCOVERY. Link: * ST-LINK/V2 This is available standalone and as part of some kits, eg. STM32F4DISCOVERY. Link: For info the original ST-LINK enumerates using the mass storage usb class, however it's implementation is completely broken. The result is this causes issues under linux. The simplest solution is to get linux to ignore the ST-LINK using one of the following methods: * modprobe -r usb-storage && modprobe usb-storage quirks=483:3744:i * add "options usb-storage quirks=483:3744:i" to /etc/modprobe.conf 2.8 USB TI/Stellaris ICDI based =============================== Texas Instruments has an adapter called ICDI. It is not to be confused with the FTDI based adapters that were originally fitted to their evaluation boards. This is the adapter fitted to the Stellaris LaunchPad. 2.9 USB Other ============= * USBprog Link: - which uses an Atmel MEGA32 and a UBN9604 * USB - Presto Link: * Versaloon-Link Link: * ARM-JTAG-EW Link: * Buspirate Link: * opendous Link: - which uses an AT90USB162 * estick Link: * Keil ULINK v1 Link: 2.10 IBM PC Parallel Printer Port Based ======================================= The two well known "JTAG Parallel Ports" cables are the Xilnx DLC5 and the Macraigor Wiggler. There are many clones and variations of these on the market. Note that parallel ports are becoming much less common, so if you have the choice you should probably avoid these adapters in favor of USB-based ones. * Wiggler - There are many clones of this. Link: * DLC5 - From XILINX - There are many clones of this Link: Search the web for: "XILINX DLC5" - it is no longer produced, PDF schematics are easily found and it is easy to make. * Amontec - JTAG Accelerator Link: * GW16402 Link: * Wiggler2 Link: * Wiggler_ntrst_inverted Yet another variation - See the source code, src/jtag/parport.c * old_amt_wiggler Unknown - probably not on the market today * arm-jtag Link: Most likely [another wiggler clone] * chameleon Link: * Triton Unknown. * Lattice ispDownload from Lattice Semiconductor * flashlink From ST Microsystems; Link: 2.11 Other... ============= * ep93xx An EP93xx based Linux machine using the GPIO pins directly. * at91rm9200 Like the EP93xx - but an ATMEL AT91RM9200 based solution using the GPIO pins on the chip.  File: openocd.info, Node: About Jim-Tcl, Next: Running, Prev: Debug Adapter Hardware, Up: Top 3 About Jim-Tcl *************** OpenOCD uses a small "Tcl Interpreter" known as Jim-Tcl. This programming language provides a simple and extensible command interpreter. All commands presented in this Guide are extensions to Jim-Tcl. You can use them as simple commands, without needing to learn much of anything about Tcl. Alternatively, can write Tcl programs with them. You can learn more about Jim at its website, . There is an active and responsive community, get on the mailing list if you have any questions. Jim-Tcl maintainers also lurk on the OpenOCD mailing list. * Jim vs. Tcl Jim-Tcl is a stripped down version of the well known Tcl language, which can be found here: . Jim-Tcl has far fewer features. Jim-Tcl is several dozens of .C files and .H files and implements the basic Tcl command set. In contrast: Tcl 8.6 is a 4.2 MB .zip file containing 1540 files. * Missing Features Our practice has been: Add/clone the real Tcl feature if/when needed. We welcome Jim-Tcl improvements, not bloat. Also there are a large number of optional Jim-Tcl features that are not enabled in OpenOCD. * Scripts OpenOCD configuration scripts are Jim-Tcl Scripts. OpenOCD's command interpreter today is a mixture of (newer) Jim-Tcl commands, and (older) the orginal command interpreter. * Commands At the OpenOCD telnet command line (or via the GDB monitor command) one can type a Tcl for() loop, set variables, etc. Some of the commands documented in this guide are implemented as Tcl scripts, from a 'startup.tcl' file internal to the server. * Historical Note Jim-Tcl was introduced to OpenOCD in spring 2008. Fall 2010, before OpenOCD 0.5 release OpenOCD switched to using Jim Tcl as a git submodule, which greatly simplified upgrading Jim Tcl to benefit from new features and bugfixes in Jim Tcl. * Need a crash course in Tcl? *Note Tcl Crash Course::.  File: openocd.info, Node: Running, Next: OpenOCD Project Setup, Prev: About Jim-Tcl, Up: Top 4 Running ********* Properly installing OpenOCD sets up your operating system to grant it access to the debug adapters. On Linux, this usually involves installing a file in '/etc/udev/rules.d,' so OpenOCD has permissions. MS-Windows needs complex and confusing driver configuration for every peripheral. Such issues are unique to each operating system, and are not detailed in this User's Guide. Then later you will invoke the OpenOCD server, with various options to tell it how each debug session should work. The '--help' option shows: bash$ openocd --help --help | -h display this help --version | -v display OpenOCD version --file | -f use configuration file --search | -s dir to search for config files and scripts --debug | -d set debug level <0-3> --log_output | -l redirect log output to file --command | -c run If you don't give any '-f' or '-c' options, OpenOCD tries to read the configuration file 'openocd.cfg'. To specify one or more different configuration files, use '-f' options. For example: openocd -f config1.cfg -f config2.cfg -f config3.cfg Configuration files and scripts are searched for in 1. the current directory, 2. any search dir specified on the command line using the '-s' option, 3. any search dir specified using the 'add_script_search_dir' command, 4. '$HOME/.openocd' (not on Windows), 5. the site wide script library '$pkgdatadir/site' and 6. the OpenOCD-supplied script library '$pkgdatadir/scripts'. The first found file with a matching file name will be used. Note: Don't try to use configuration script names or paths which include the "#" character. That character begins Tcl comments. 4.1 Simple setup, no customization ================================== In the best case, you can use two scripts from one of the script libraries, hook up your JTAG adapter, and start the server ... and your JTAG setup will just work "out of the box". Always try to start by reusing those scripts, but assume you'll need more customization even if this works. *Note OpenOCD Project Setup::. If you find a script for your JTAG adapter, and for your board or target, you may be able to hook up your JTAG adapter then start the server like: openocd -f interface/ADAPTER.cfg -f board/MYBOARD.cfg You might also need to configure which reset signals are present, using '-c 'reset_config trst_and_srst'' or something similar. If all goes well you'll see output something like Open On-Chip Debugger 0.4.0 (2010-01-14-15:06) For bug reports, read http://openocd.sourceforge.net/doc/doxygen/bugs.html Info : JTAG tap: lm3s.cpu tap/device found: 0x3ba00477 (mfg: 0x23b, part: 0xba00, ver: 0x3) Seeing that "tap/device found" message, and no warnings, means the JTAG communication is working. That's a key milestone, but you'll probably need more project-specific setup. 4.2 What OpenOCD does as it starts ================================== OpenOCD starts by processing the configuration commands provided on the command line or, if there were no '-c command' or '-f file.cfg' options given, in 'openocd.cfg'. *Note Configuration Stage: configurationstage. At the end of the configuration stage it verifies the JTAG scan chain defined using those commands; your configuration should ensure that this always succeeds. Normally, OpenOCD then starts running as a daemon. Alternatively, commands may be used to terminate the configuration stage early, perform work (such as updating some flash memory), and then shut down without acting as a daemon. Once OpenOCD starts running as a daemon, it waits for connections from clients (Telnet, GDB, Other) and processes the commands issued through those channels. If you are having problems, you can enable internal debug messages via the '-d' option. Also it is possible to interleave Jim-Tcl commands w/config scripts using the '-c' command line switch. To enable debug output (when reporting problems or working on OpenOCD itself), use the '-d' command line switch. This sets the 'debug_level' to "3", outputting the most information, including debug messages. The default setting is "2", outputting only informational messages, warnings and errors. You can also change this setting from within a telnet or gdb session using 'debug_level' (*note debug_level: debuglevel.). You can redirect all output from the daemon to a file using the '-l ' switch. Note! OpenOCD will launch the GDB & telnet server even if it can not establish a connection with the target. In general, it is possible for the JTAG controller to be unresponsive until the target is set up correctly via e.g. GDB monitor commands in a GDB init script.  File: openocd.info, Node: OpenOCD Project Setup, Next: Config File Guidelines, Prev: Running, Up: Top 5 OpenOCD Project Setup *********************** To use OpenOCD with your development projects, you need to do more than just connecting the JTAG adapter hardware (dongle) to your development board and then starting the OpenOCD server. You also need to configure that server so that it knows about that adapter and board, and helps your work. You may also want to connect OpenOCD to GDB, possibly using Eclipse or some other GUI. 5.1 Hooking up the JTAG Adapter =============================== Today's most common case is a dongle with a JTAG cable on one side (such as a ribbon cable with a 10-pin or 20-pin IDC connector) and a USB cable on the other. Instead of USB, some cables use Ethernet; older ones may use a PC parallel port, or even a serial port. 1. _Start with power to your target board turned off_, and nothing connected to your JTAG adapter. If you're particularly paranoid, unplug power to the board. It's important to have the ground signal properly set up, unless you are using a JTAG adapter which provides galvanic isolation between the target board and the debugging host. 2. _Be sure it's the right kind of JTAG connector._ If your dongle has a 20-pin ARM connector, you need some kind of adapter (or octopus, see below) to hook it up to boards using 14-pin or 10-pin connectors ... or to 20-pin connectors which don't use ARM's pinout. In the same vein, make sure the voltage levels are compatible. Not all JTAG adapters have the level shifters needed to work with 1.2 Volt boards. 3. _Be certain the cable is properly oriented_ or you might damage your board. In most cases there are only two possible ways to connect the cable. Connect the JTAG cable from your adapter to the board. Be sure it's firmly connected. In the best case, the connector is keyed to physically prevent you from inserting it wrong. This is most often done using a slot on the board's male connector housing, which must match a key on the JTAG cable's female connector. If there's no housing, then you must look carefully and make sure pin 1 on the cable hooks up to pin 1 on the board. Ribbon cables are frequently all grey except for a wire on one edge, which is red. The red wire is pin 1. Sometimes dongles provide cables where one end is an "octopus" of color coded single-wire connectors, instead of a connector block. These are great when converting from one JTAG pinout to another, but are tedious to set up. Use these with connector pinout diagrams to help you match up the adapter signals to the right board pins. 4. _Connect the adapter's other end_ once the JTAG cable is connected. A USB, parallel, or serial port connector will go to the host which you are using to run OpenOCD. For Ethernet, consult the documentation and your network administrator. For USB based JTAG adapters you have an easy sanity check at this point: does the host operating system see the JTAG adapter? If that host is an MS-Windows host, you'll need to install a driver before OpenOCD works. 5. _Connect the adapter's power supply, if needed._ This step is primarily for non-USB adapters, but sometimes USB adapters need extra power. 6. _Power up the target board._ Unless you just let the magic smoke escape, you're now ready to set up the OpenOCD server so you can use JTAG to work with that board. Talk with the OpenOCD server using telnet ('telnet localhost 4444' on many systems) or GDB. *Note GDB and OpenOCD::. 5.2 Project Directory ===================== There are many ways you can configure OpenOCD and start it up. A simple way to organize them all involves keeping a single directory for your work with a given board. When you start OpenOCD from that directory, it searches there first for configuration files, scripts, files accessed through semihosting, and for code you upload to the target board. It is also the natural place to write files, such as log files and data you download from the board. 5.3 Configuration Basics ======================== There are two basic ways of configuring OpenOCD, and a variety of ways you can mix them. Think of the difference as just being how you start the server: * Many '-f file' or '-c command' options on the command line * No options, but a "user config file" in the current directory named 'openocd.cfg' Here is an example 'openocd.cfg' file for a setup using a Signalyzer FT2232-based JTAG adapter to talk to a board with an Atmel AT91SAM7X256 microcontroller: source [find interface/signalyzer.cfg] # GDB can also flash my flash! gdb_memory_map enable gdb_flash_program enable source [find target/sam7x256.cfg] Here is the command line equivalent of that configuration: openocd -f interface/signalyzer.cfg \ -c "gdb_memory_map enable" \ -c "gdb_flash_program enable" \ -f target/sam7x256.cfg You could wrap such long command lines in shell scripts, each supporting a different development task. One might re-flash the board with a specific firmware version. Another might set up a particular debugging or run-time environment. Important: At this writing (October 2009) the command line method has problems with how it treats variables. For example, after '-c "set VAR value"', or doing the same in a script, the variable VAR will have no value that can be tested in a later script. Here we will focus on the simpler solution: one user config file, including basic configuration plus any TCL procedures to simplify your work. 5.4 User Config Files ===================== A user configuration file ties together all the parts of a project in one place. One of the following will match your situation best: * Ideally almost everything comes from configuration files provided by someone else. For example, OpenOCD distributes a 'scripts' directory (probably in '/usr/share/openocd/scripts' on Linux). Board and tool vendors can provide these too, as can individual user sites; the '-s' command line option lets you say where to find these files. (*Note Running::.) The AT91SAM7X256 example above works this way. Three main types of non-user configuration file each have their own subdirectory in the 'scripts' directory: 1. interface - one for each different debug adapter; 2. board - one for each different board 3. target - the chips which integrate CPUs and other JTAG TAPs Best case: include just two files, and they handle everything else. The first is an interface config file. The second is board-specific, and it sets up the JTAG TAPs and their GDB targets (by deferring to some 'target.cfg' file), declares all flash memory, and leaves you nothing to do except meet your deadline: source [find interface/olimex-jtag-tiny.cfg] source [find board/csb337.cfg] Boards with a single microcontroller often won't need more than the target config file, as in the AT91SAM7X256 example. That's because there is no external memory (flash, DDR RAM), and the board differences are encapsulated by application code. * Maybe you don't know yet what your board looks like to JTAG. Once you know the 'interface.cfg' file to use, you may need help from OpenOCD to discover what's on the board. Once you find the JTAG TAPs, you can just search for appropriate target and board configuration files ... or write your own, from the bottom up. *Note Autoprobing: autoprobing. * You can often reuse some standard config files but need to write a few new ones, probably a 'board.cfg' file. You will be using commands described later in this User's Guide, and working with the guidelines in the next chapter. For example, there may be configuration files for your JTAG adapter and target chip, but you need a new board-specific config file giving access to your particular flash chips. Or you might need to write another target chip configuration file for a new chip built around the Cortex M3 core. Note: When you write new configuration files, please submit them for inclusion in the next OpenOCD release. For example, a 'board/newboard.cfg' file will help the next users of that board, and a 'target/newcpu.cfg' will help support users of any board using that chip. * You may may need to write some C code. It may be as simple as a supporting a new ft2232 or parport based adapter; a bit more involved, like a NAND or NOR flash controller driver; or a big piece of work like supporting a new chip architecture. Reuse the existing config files when you can. Look first in the 'scripts/boards' area, then 'scripts/targets'. You may find a board configuration that's a good example to follow. When you write config files, separate the reusable parts (things every user of that interface, chip, or board needs) from ones specific to your environment and debugging approach. * For example, a 'gdb-attach' event handler that invokes the 'reset init' command will interfere with debugging early boot code, which performs some of the same actions that the 'reset-init' event handler does. * Likewise, the 'arm9 vector_catch' command (or its siblings 'xscale vector_catch' and 'cortex_m vector_catch') can be a timesaver during some debug sessions, but don't make everyone use that either. Keep those kinds of debugging aids in your user config file, along with messaging and tracing setup. (*Note Software Debug Messages and Tracing: softwaredebugmessagesandtracing.) * You might need to override some defaults. For example, you might need to move, shrink, or back up the target's work area if your application needs much SRAM. * TCP/IP port configuration is another example of something which is environment-specific, and should only appear in a user config file. *Note TCP/IP Ports: tcpipports. 5.5 Project-Specific Utilities ============================== A few project-specific utility routines may well speed up your work. Write them, and keep them in your project's user config file. For example, if you are making a boot loader work on a board, it's nice to be able to debug the "after it's loaded to RAM" parts separately from the finicky early code which sets up the DDR RAM controller and clocks. A script like this one, or a more GDB-aware sibling, may help: proc ramboot { } { # Reset, running the target's "reset-init" scripts # to initialize clocks and the DDR RAM controller. # Leave the CPU halted. reset init # Load CONFIG_SKIP_LOWLEVEL_INIT version into DDR RAM. load_image u-boot.bin 0x20000000 # Start running. resume 0x20000000 } Then once that code is working you will need to make it boot from NOR flash; a different utility would help. Alternatively, some developers write to flash using GDB. (You might use a similar script if you're working with a flash based microcontroller application instead of a boot loader.) proc newboot { } { # Reset, leaving the CPU halted. The "reset-init" event # proc gives faster access to the CPU and to NOR flash; # "reset halt" would be slower. reset init # Write standard version of U-Boot into the first two # sectors of NOR flash ... the standard version should # do the same lowlevel init as "reset-init". flash protect 0 0 1 off flash erase_sector 0 0 1 flash write_bank 0 u-boot.bin 0x0 flash protect 0 0 1 on # Reboot from scratch using that new boot loader. reset run } You may need more complicated utility procedures when booting from NAND. That often involves an extra bootloader stage, running from on-chip SRAM to perform DDR RAM setup so it can load the main bootloader code (which won't fit into that SRAM). Other helper scripts might be used to write production system images, involving considerably more than just a three stage bootloader. 5.6 Target Software Changes =========================== Sometimes you may want to make some small changes to the software you're developing, to help make JTAG debugging work better. For example, in C or assembly language code you might use '#ifdef JTAG_DEBUG' (or its converse) around code handling issues like: * Watchdog Timers... Watchog timers are typically used to automatically reset systems if some application task doesn't periodically reset the timer. (The assumption is that the system has locked up if the task can't run.) When a JTAG debugger halts the system, that task won't be able to run and reset the timer ... potentially causing resets in the middle of your debug sessions. It's rarely a good idea to disable such watchdogs, since their usage needs to be debugged just like all other parts of your firmware. That might however be your only option. Look instead for chip-specific ways to stop the watchdog from counting while the system is in a debug halt state. It may be simplest to set that non-counting mode in your debugger startup scripts. You may however need a different approach when, for example, a motor could be physically damaged by firmware remaining inactive in a debug halt state. That might involve a type of firmware mode where that "non-counting" mode is disabled at the beginning then re-enabled at the end; a watchdog reset might fire and complicate the debug session, but hardware (or people) would be protected.(1) * ARM Semihosting... When linked with a special runtime library provided with many toolchains(2), your target code can use I/O facilities on the debug host. That library provides a small set of system calls which are handled by OpenOCD. It can let the debugger provide your system console and a file system, helping with early debugging or providing a more capable environment for sometimes-complex tasks like installing system firmware onto NAND or SPI flash. * ARM Wait-For-Interrupt... Many ARM chips synchronize the JTAG clock using the core clock. Low power states which stop that core clock thus prevent JTAG access. Idle loops in tasking environments often enter those low power states via the 'WFI' instruction (or its coprocessor equivalent, before ARMv7). You may want to _disable that instruction_ in source code, or otherwise prevent using that state, to ensure you can get JTAG access at any time.(3) For example, the OpenOCD 'halt' command may not work for an idle processor otherwise. * Delay after reset... Not all chips have good support for debugger access right after reset; many LPC2xxx chips have issues here. Similarly, applications that reconfigure pins used for JTAG access as they start will also block debugger access. To work with boards like this, _enable a short delay loop_ the first thing after reset, before "real" startup activities. For example, one second's delay is usually more than enough time for a JTAG debugger to attach, so that early code execution can be debugged or firmware can be replaced. * Debug Communications Channel (DCC)... Some processors include mechanisms to send messages over JTAG. Many ARM cores support these, as do some cores from other vendors. (OpenOCD may be able to use this DCC internally, speeding up some operations like writing to memory.) Your application may want to deliver various debugging messages over JTAG, by _linking with a small library of code_ provided with OpenOCD and using the utilities there to send various kinds of message. *Note Software Debug Messages and Tracing: softwaredebugmessagesandtracing. 5.7 Target Hardware Setup ========================= Chip vendors often provide software development boards which are highly configurable, so that they can support all options that product boards may require. _Make sure that any jumpers or switches match the system configuration you are working with._ Common issues include: * JTAG setup ... Boards may support more than one JTAG configuration. Examples include jumpers controlling pullups versus pulldowns on the nTRST and/or nSRST signals, and choice of connectors (e.g. which of two headers on the base board, or one from a daughtercard). For some Texas Instruments boards, you may need to jumper the EMU0 and EMU1 signals (which OpenOCD won't currently control). * Boot Modes ... Complex chips often support multiple boot modes, controlled by external jumpers. Make sure this is set up correctly. For example many i.MX boards from NXP need to be jumpered to "ATX mode" to start booting using the on-chip ROM, when using second stage bootloader code stored in a NAND flash chip. Such explicit configuration is common, and not limited to booting from NAND. You might also need to set jumpers to start booting using code loaded from an MMC/SD card; external SPI flash; Ethernet, UART, or USB links; NOR flash; OneNAND flash; some external host; or various other sources. * Memory Addressing ... Boards which support multiple boot modes may also have jumpers to configure memory addressing. One board, for example, jumpers external chipselect 0 (used for booting) to address either a large SRAM (which must be pre-loaded via JTAG), NOR flash, or NAND flash. When it's jumpered to address NAND flash, that board must also be told to start booting from on-chip ROM. Your 'board.cfg' file may also need to be told this jumper configuration, so that it can know whether to declare NOR flash using 'flash bank' or instead declare NAND flash with 'nand device'; and likewise which probe to perform in its 'reset-init' handler. A closely related issue is bus width. Jumpers might need to distinguish between 8 bit or 16 bit bus access for the flash used to start booting. * Peripheral Access ... Development boards generally provide access to every peripheral on the chip, sometimes in multiple modes (such as by providing multiple audio codec chips). This interacts with software configuration of pin multiplexing, where for example a given pin may be routed either to the MMC/SD controller or the GPIO controller. It also often interacts with configuration jumpers. One jumper may be used to route signals to an MMC/SD card slot or an expansion bus (which might in turn affect booting); others might control which audio or video codecs are used. Plus you should of course have 'reset-init' event handlers which set up the hardware to match that jumper configuration. That includes in particular any oscillator or PLL used to clock the CPU, and any memory controllers needed to access external memory and peripherals. Without such handlers, you won't be able to access those resources without working target firmware which can do that setup ... this can be awkward when you're trying to debug that target firmware. Even if there's a ROM bootloader which handles a few issues, it rarely provides full access to all board-specific capabilities. ---------- Footnotes ---------- (1) Note that many systems support a "monitor mode" debug that is a somewhat cleaner way to address such issues. You can think of it as only halting part of the system, maybe just one task, instead of the whole thing. At this writing, January 2010, OpenOCD based debugging does not support monitor mode debug, only "halt mode" debug. (2) See chapter 8 "Semihosting" in ARM DUI 0203I (http://infocenter.arm.com/help/topic/com.arm.doc.dui0203i/DUI0203I_rvct_developer_guide.pdf), the "RealView Compilation Tools Developer Guide". The CodeSourcery EABI toolchain also includes a semihosting library. (3) As a more polite alternative, some processors have special debug-oriented registers which can be used to change various features including how the low power states are clocked while debugging. The STM32 DBGMCU_CR register is an example; at the cost of extra power consumption, JTAG can be used during low power states.  File: openocd.info, Node: Config File Guidelines, Next: Daemon Configuration, Prev: OpenOCD Project Setup, Up: Top 6 Config File Guidelines ************************ This chapter is aimed at any user who needs to write a config file, including developers and integrators of OpenOCD and any user who needs to get a new board working smoothly. It provides guidelines for creating those files. You should find the following directories under $(INSTALLDIR)/scripts, with files including the ones listed here. Use them as-is where you can; or as models for new files. * 'interface' ... These are for debug adapters. Files that configure JTAG adapters go here. $ ls interface -R interface/: altera-usb-blaster.cfg hilscher_nxhx50_re.cfg openocd-usb-hs.cfg arm-jtag-ew.cfg hitex_str9-comstick.cfg openrd.cfg at91rm9200.cfg icebear.cfg osbdm.cfg axm0432.cfg jlink.cfg parport.cfg busblaster.cfg jtagkey2.cfg parport_dlc5.cfg buspirate.cfg jtagkey2p.cfg redbee-econotag.cfg calao-usb-a9260-c01.cfg jtagkey.cfg redbee-usb.cfg calao-usb-a9260-c02.cfg jtagkey-tiny.cfg rlink.cfg calao-usb-a9260.cfg jtag-lock-pick_tiny_2.cfg sheevaplug.cfg chameleon.cfg kt-link.cfg signalyzer.cfg cortino.cfg lisa-l.cfg signalyzer-h2.cfg digilent-hs1.cfg luminary.cfg signalyzer-h4.cfg dlp-usb1232h.cfg luminary-icdi.cfg signalyzer-lite.cfg dummy.cfg luminary-lm3s811.cfg stlink-v1.cfg estick.cfg minimodule.cfg stlink-v2.cfg flashlink.cfg neodb.cfg stm32-stick.cfg flossjtag.cfg ngxtech.cfg sysfsgpio-raspberrypi.cfg flossjtag-noeeprom.cfg olimex-arm-usb-ocd.cfg ti-icdi.cfg flyswatter2.cfg olimex-arm-usb-ocd-h.cfg turtelizer2.cfg flyswatter.cfg olimex-arm-usb-tiny-h.cfg ulink.cfg ftdi olimex-jtag-tiny.cfg usb-jtag.cfg hilscher_nxhx10_etm.cfg oocdlink.cfg usbprog.cfg hilscher_nxhx500_etm.cfg opendous.cfg vpaclink.cfg hilscher_nxhx500_re.cfg opendous_ftdi.cfg vsllink.cfg hilscher_nxhx50_etm.cfg openocd-usb.cfg xds100v2.cfg interface/ftdi: axm0432.cfg icebear.cfg oocdlink.cfg calao-usb-a9260-c01.cfg jtagkey2.cfg opendous_ftdi.cfg calao-usb-a9260-c02.cfg jtagkey2p.cfg openocd-usb.cfg cortino.cfg jtagkey.cfg openocd-usb-hs.cfg dlp-usb1232h.cfg jtag-lock-pick_tiny_2.cfg openrd.cfg dp_busblaster.cfg kt-link.cfg redbee-econotag.cfg flossjtag.cfg lisa-l.cfg redbee-usb.cfg flossjtag-noeeprom.cfg luminary.cfg sheevaplug.cfg flyswatter2.cfg luminary-icdi.cfg signalyzer.cfg flyswatter.cfg luminary-lm3s811.cfg signalyzer-lite.cfg hilscher_nxhx10_etm.cfg minimodule.cfg stm32-stick.cfg hilscher_nxhx500_etm.cfg neodb.cfg turtelizer2-revB.cfg hilscher_nxhx500_re.cfg ngxtech.cfg turtelizer2-revC.cfg hilscher_nxhx50_etm.cfg olimex-arm-usb-ocd.cfg vpaclink.cfg hilscher_nxhx50_re.cfg olimex-arm-usb-ocd-h.cfg xds100v2.cfg hitex_lpc1768stick.cfg olimex-arm-usb-tiny-h.cfg hitex_str9-comstick.cfg olimex-jtag-tiny.cfg $ * 'board' ... think Circuit Board, PWA, PCB, they go by many names. Board files contain initialization items that are specific to a board. They reuse target configuration files, since the same microprocessor chips are used on many boards, but support for external parts varies widely. For example, the SDRAM initialization sequence for the board, or the type of external flash and what address it uses. Any initialization sequence to enable that external flash or SDRAM should be found in the board file. Boards may also contain multiple targets: two CPUs; or a CPU and an FPGA. $ ls board actux3.cfg lpc1850_spifi_generic.cfg am3517evm.cfg lpc4350_spifi_generic.cfg arm_evaluator7t.cfg lubbock.cfg at91cap7a-stk-sdram.cfg mcb1700.cfg at91eb40a.cfg microchip_explorer16.cfg at91rm9200-dk.cfg mini2440.cfg at91rm9200-ek.cfg mini6410.cfg at91sam9261-ek.cfg netgear-dg834v3.cfg at91sam9263-ek.cfg olimex_LPC2378STK.cfg at91sam9g20-ek.cfg olimex_lpc_h2148.cfg atmel_at91sam7s-ek.cfg olimex_sam7_ex256.cfg atmel_at91sam9260-ek.cfg olimex_sam9_l9260.cfg atmel_at91sam9rl-ek.cfg olimex_stm32_h103.cfg atmel_sam3n_ek.cfg olimex_stm32_h107.cfg atmel_sam3s_ek.cfg olimex_stm32_p107.cfg atmel_sam3u_ek.cfg omap2420_h4.cfg atmel_sam3x_ek.cfg open-bldc.cfg atmel_sam4s_ek.cfg openrd.cfg balloon3-cpu.cfg osk5912.cfg colibri.cfg phone_se_j100i.cfg crossbow_tech_imote2.cfg phytec_lpc3250.cfg csb337.cfg pic-p32mx.cfg csb732.cfg propox_mmnet1001.cfg da850evm.cfg pxa255_sst.cfg digi_connectcore_wi-9c.cfg redbee.cfg diolan_lpc4350-db1.cfg rsc-w910.cfg dm355evm.cfg sheevaplug.cfg dm365evm.cfg smdk6410.cfg dm6446evm.cfg spear300evb.cfg efikamx.cfg spear300evb_mod.cfg eir.cfg spear310evb20.cfg ek-lm3s1968.cfg spear310evb20_mod.cfg ek-lm3s3748.cfg spear320cpu.cfg ek-lm3s6965.cfg spear320cpu_mod.cfg ek-lm3s811.cfg steval_pcc010.cfg ek-lm3s811-revb.cfg stm320518_eval_stlink.cfg ek-lm3s8962.cfg stm32100b_eval.cfg ek-lm3s9b9x.cfg stm3210b_eval.cfg ek-lm3s9d92.cfg stm3210c_eval.cfg ek-lm4f120xl.cfg stm3210e_eval.cfg ek-lm4f232.cfg stm3220g_eval.cfg embedded-artists_lpc2478-32.cfg stm3220g_eval_stlink.cfg ethernut3.cfg stm3241g_eval.cfg glyn_tonga2.cfg stm3241g_eval_stlink.cfg hammer.cfg stm32f0discovery.cfg hilscher_nxdb500sys.cfg stm32f3discovery.cfg hilscher_nxeb500hmi.cfg stm32f4discovery.cfg hilscher_nxhx10.cfg stm32ldiscovery.cfg hilscher_nxhx500.cfg stm32vldiscovery.cfg hilscher_nxhx50.cfg str910-eval.cfg hilscher_nxsb100.cfg telo.cfg hitex_lpc1768stick.cfg ti_am335xevm.cfg hitex_lpc2929.cfg ti_beagleboard.cfg hitex_stm32-performancestick.cfg ti_beagleboard_xm.cfg hitex_str9-comstick.cfg ti_beaglebone.cfg iar_lpc1768.cfg ti_blaze.cfg iar_str912_sk.cfg ti_pandaboard.cfg icnova_imx53_sodimm.cfg ti_pandaboard_es.cfg icnova_sam9g45_sodimm.cfg topas910.cfg imx27ads.cfg topasa900.cfg imx27lnst.cfg twr-k60f120m.cfg imx28evk.cfg twr-k60n512.cfg imx31pdk.cfg tx25_stk5.cfg imx35pdk.cfg tx27_stk5.cfg imx53loco.cfg unknown_at91sam9260.cfg keil_mcb1700.cfg uptech_2410.cfg keil_mcb2140.cfg verdex.cfg kwikstik.cfg voipac.cfg linksys_nslu2.cfg voltcraft_dso-3062c.cfg lisa-l.cfg x300t.cfg logicpd_imx27.cfg zy1000.cfg $ * 'target' ... think chip. The "target" directory represents the JTAG TAPs on a chip which OpenOCD should control, not a board. Two common types of targets are ARM chips and FPGA or CPLD chips. When a chip has multiple TAPs (maybe it has both ARM and DSP cores), the target config file defines all of them. $ ls target aduc702x.cfg lpc1763.cfg am335x.cfg lpc1764.cfg amdm37x.cfg lpc1765.cfg ar71xx.cfg lpc1766.cfg at32ap7000.cfg lpc1767.cfg at91r40008.cfg lpc1768.cfg at91rm9200.cfg lpc1769.cfg at91sam3ax_4x.cfg lpc1788.cfg at91sam3ax_8x.cfg lpc17xx.cfg at91sam3ax_xx.cfg lpc1850.cfg at91sam3nXX.cfg lpc2103.cfg at91sam3sXX.cfg lpc2124.cfg at91sam3u1c.cfg lpc2129.cfg at91sam3u1e.cfg lpc2148.cfg at91sam3u2c.cfg lpc2294.cfg at91sam3u2e.cfg lpc2378.cfg at91sam3u4c.cfg lpc2460.cfg at91sam3u4e.cfg lpc2478.cfg at91sam3uxx.cfg lpc2900.cfg at91sam3XXX.cfg lpc2xxx.cfg at91sam4sd32x.cfg lpc3131.cfg at91sam4sXX.cfg lpc3250.cfg at91sam4XXX.cfg lpc4350.cfg at91sam7se512.cfg lpc4350.cfg.orig at91sam7sx.cfg mc13224v.cfg at91sam7x256.cfg nuc910.cfg at91sam7x512.cfg omap2420.cfg at91sam9260.cfg omap3530.cfg at91sam9260_ext_RAM_ext_flash.cfg omap4430.cfg at91sam9261.cfg omap4460.cfg at91sam9263.cfg omap5912.cfg at91sam9.cfg omapl138.cfg at91sam9g10.cfg pic32mx.cfg at91sam9g20.cfg pxa255.cfg at91sam9g45.cfg pxa270.cfg at91sam9rl.cfg pxa3xx.cfg atmega128.cfg readme.txt avr32.cfg samsung_s3c2410.cfg c100.cfg samsung_s3c2440.cfg c100config.tcl samsung_s3c2450.cfg c100helper.tcl samsung_s3c4510.cfg c100regs.tcl samsung_s3c6410.cfg cs351x.cfg sharp_lh79532.cfg davinci.cfg smp8634.cfg dragonite.cfg spear3xx.cfg dsp56321.cfg stellaris.cfg dsp568013.cfg stellaris_icdi.cfg dsp568037.cfg stm32f0x_stlink.cfg efm32_stlink.cfg stm32f1x.cfg epc9301.cfg stm32f1x_stlink.cfg faux.cfg stm32f2x.cfg feroceon.cfg stm32f2x_stlink.cfg fm3.cfg stm32f3x.cfg hilscher_netx10.cfg stm32f3x_stlink.cfg hilscher_netx500.cfg stm32f4x.cfg hilscher_netx50.cfg stm32f4x_stlink.cfg icepick.cfg stm32l.cfg imx21.cfg stm32lx_dual_bank.cfg imx25.cfg stm32lx_stlink.cfg imx27.cfg stm32_stlink.cfg imx28.cfg stm32w108_stlink.cfg imx31.cfg stm32xl.cfg imx35.cfg str710.cfg imx51.cfg str730.cfg imx53.cfg str750.cfg imx6.cfg str912.cfg imx.cfg swj-dp.tcl is5114.cfg test_reset_syntax_error.cfg ixp42x.cfg test_syntax_error.cfg k40.cfg ti-ar7.cfg k60.cfg ti_calypso.cfg lpc1751.cfg ti_dm355.cfg lpc1752.cfg ti_dm365.cfg lpc1754.cfg ti_dm6446.cfg lpc1756.cfg tmpa900.cfg lpc1758.cfg tmpa910.cfg lpc1759.cfg u8500.cfg * _more_ ... browse for other library files which may be useful. For example, there are various generic and CPU-specific utilities. The 'openocd.cfg' user config file may override features in any of the above files by setting variables before sourcing the target file, or by adding commands specific to their situation. 6.1 Interface Config Files ========================== The user config file should be able to source one of these files with a command like this: source [find interface/FOOBAR.cfg] A preconfigured interface file should exist for every debug adapter in use today with OpenOCD. That said, perhaps some of these config files have only been used by the developer who created it. A separate chapter gives information about how to set these up. *Note Debug Adapter Configuration::. Read the OpenOCD source code (and Developer's Guide) if you have a new kind of hardware interface and need to provide a driver for it. 6.2 Board Config Files ====================== The user config file should be able to source one of these files with a command like this: source [find board/FOOBAR.cfg] The point of a board config file is to package everything about a given board that user config files need to know. In summary the board files should contain (if present) 1. One or more 'source [target/...cfg]' statements 2. NOR flash configuration (*note NOR Configuration: norconfiguration.) 3. NAND flash configuration (*note NAND Configuration: nandconfiguration.) 4. Target 'reset' handlers for SDRAM and I/O configuration 5. JTAG adapter reset configuration (*note Reset Configuration::) 6. All things that are not "inside a chip" Generic things inside target chips belong in target config files, not board config files. So for example a 'reset-init' event handler should know board-specific oscillator and PLL parameters, which it passes to target-specific utility code. The most complex task of a board config file is creating such a 'reset-init' event handler. Define those handlers last, after you verify the rest of the board configuration works. 6.2.1 Communication Between Config files ---------------------------------------- In addition to target-specific utility code, another way that board and target config files communicate is by following a convention on how to use certain variables. The full Tcl/Tk language supports "namespaces", but Jim-Tcl does not. Thus the rule we follow in OpenOCD is this: Variables that begin with a leading underscore are temporary in nature, and can be modified and used at will within a target configuration file. Complex board config files can do the things like this, for a board with three chips: # Chip #1: PXA270 for network side, big endian set CHIPNAME network set ENDIAN big source [find target/pxa270.cfg] # on return: _TARGETNAME = network.cpu # other commands can refer to the "network.cpu" target. $_TARGETNAME configure .... events for this CPU.. # Chip #2: PXA270 for video side, little endian set CHIPNAME video set ENDIAN little source [find target/pxa270.cfg] # on return: _TARGETNAME = video.cpu # other commands can refer to the "video.cpu" target. $_TARGETNAME configure .... events for this CPU.. # Chip #3: Xilinx FPGA for glue logic set CHIPNAME xilinx unset ENDIAN source [find target/spartan3.cfg] That example is oversimplified because it doesn't show any flash memory, or the 'reset-init' event handlers to initialize external DRAM or (assuming it needs it) load a configuration into the FPGA. Such features are usually needed for low-level work with many boards, where "low level" implies that the board initialization software may not be working. (That's a common reason to need JTAG tools. Another is to enable working with microcontroller-based systems, which often have no debugging support except a JTAG connector.) Target config files may also export utility functions to board and user config files. Such functions should use name prefixes, to help avoid naming collisions. Board files could also accept input variables from user config files. For example, there might be a 'J4_JUMPER' setting used to identify what kind of flash memory a development board is using, or how to set up other clocks and peripherals. 6.2.2 Variable Naming Convention -------------------------------- Most boards have only one instance of a chip. However, it should be easy to create a board with more than one such chip (as shown above). Accordingly, we encourage these conventions for naming variables associated with different 'target.cfg' files, to promote consistency and so that board files can override target defaults. Inputs to target config files include: * 'CHIPNAME' ... This gives a name to the overall chip, and is used as part of tap identifier dotted names. While the default is normally provided by the chip manufacturer, board files may need to distinguish between instances of a chip. * 'ENDIAN' ... By default 'little' - although chips may hard-wire 'big'. Chips that can't change endianness don't need to use this variable. * 'CPUTAPID' ... When OpenOCD examines the JTAG chain, it can be told verify the chips against the JTAG IDCODE register. The target file will hold one or more defaults, but sometimes the chip in a board will use a different ID (perhaps a newer revision). Outputs from target config files include: * '_TARGETNAME' ... By convention, this variable is created by the target configuration script. The board configuration file may make use of this variable to configure things like a "reset init" script, or other things specific to that board and that target. If the chip has 2 targets, the names are '_TARGETNAME0', '_TARGETNAME1', ... etc. 6.2.3 The reset-init Event Handler ---------------------------------- Board config files run in the OpenOCD configuration stage; they can't use TAPs or targets, since they haven't been fully set up yet. This means you can't write memory or access chip registers; you can't even verify that a flash chip is present. That's done later in event handlers, of which the target 'reset-init' handler is one of the most important. Except on microcontrollers, the basic job of 'reset-init' event handlers is setting up flash and DRAM, as normally handled by boot loaders. Microcontrollers rarely use boot loaders; they run right out of their on-chip flash and SRAM memory. But they may want to use one of these handlers too, if just for developer convenience. Note: Because this is so very board-specific, and chip-specific, no examples are included here. Instead, look at the board config files distributed with OpenOCD. If you have a boot loader, its source code will help; so will configuration files for other JTAG tools (*note Translating Configuration Files: translatingconfigurationfiles.). Some of this code could probably be shared between different boards. For example, setting up a DRAM controller often doesn't differ by much except the bus width (16 bits or 32?) and memory timings, so a reusable TCL procedure loaded by the 'target.cfg' file might take those as parameters. Similarly with oscillator, PLL, and clock setup; and disabling the watchdog. Structure the code cleanly, and provide comments to help the next developer doing such work. (_You might be that next person_ trying to reuse init code!) The last thing normally done in a 'reset-init' handler is probing whatever flash memory was configured. For most chips that needs to be done while the associated target is halted, either because JTAG memory access uses the CPU or to prevent conflicting CPU access. 6.2.4 JTAG Clock Rate --------------------- Before your 'reset-init' handler has set up the PLLs and clocking, you may need to run with a low JTAG clock rate. *Note JTAG Speed: jtagspeed. Then you'd increase that rate after your handler has made it possible to use the faster JTAG clock. When the initial low speed is board-specific, for example because it depends on a board-specific oscillator speed, then you should probably set it up in the board config file; if it's target-specific, it belongs in the target config file. For most ARM-based processors the fastest JTAG clock(1) is one sixth of the CPU clock; or one eighth for ARM11 cores. Consult chip documentation to determine the peak JTAG clock rate, which might be less than that. Warning: On most ARMs, JTAG clock detection is coupled to the core clock, so software using a 'wait for interrupt' operation blocks JTAG access. Adaptive clocking provides a partial workaround, but a more complete solution just avoids using that instruction with JTAG debuggers. If both the chip and the board support adaptive clocking, use the 'jtag_rclk' command, in case your board is used with JTAG adapter which also supports it. Otherwise use 'adapter_khz'. Set the slow rate at the beginning of the reset sequence, and the faster rate as soon as the clocks are at full speed. 6.2.5 The init_board procedure ------------------------------ The concept of 'init_board' procedure is very similar to 'init_targets' (*Note The init_targets procedure: theinittargetsprocedure.) - it's a replacement of "linear" configuration scripts. This procedure is meant to be executed when OpenOCD enters run stage (*Note Entering the Run Stage: enteringtherunstage,) after 'init_targets'. The idea to have spearate 'init_targets' and 'init_board' procedures is to allow the first one to configure everything target specific (internal flash, internal RAM, etc.) and the second one to configure everything board specific (reset signals, chip frequency, reset-init event handler, external memory, etc.). Additionally "linear" board config file will most likely fail when target config file uses 'init_targets' scheme ("linear" script is executed before 'init' and 'init_targets' - after), so separating these two configuration stages is very convenient, as the easiest way to overcome this problem is to convert board config file to use 'init_board' procedure. Board config scripts don't need to override 'init_targets' defined in target config files when they only need to to add some specifics. Just as 'init_targets', the 'init_board' procedure can be overriden by "next level" script (which sources the original), allowing greater code reuse. ### board_file.cfg ### # source target file that does most of the config in init_targets source [find target/target.cfg] proc enable_fast_clock {} { # enables fast on-board clock source # configures the chip to use it } # initialize only board specifics - reset, clock, adapter frequency proc init_board {} { reset_config trst_and_srst trst_pulls_srst $_TARGETNAME configure -event reset-init { adapter_khz 1 enable_fast_clock adapter_khz 10000 } } 6.3 Target Config Files ======================= Board config files communicate with target config files using naming conventions as described above, and may source one or more target config files like this: source [find target/FOOBAR.cfg] The point of a target config file is to package everything about a given chip that board config files need to know. In summary the target files should contain 1. Set defaults 2. Add TAPs to the scan chain 3. Add CPU targets (includes GDB support) 4. CPU/Chip/CPU-Core specific features 5. On-Chip flash As a rule of thumb, a target file sets up only one chip. For a microcontroller, that will often include a single TAP, which is a CPU needing a GDB target, and its on-chip flash. More complex chips may include multiple TAPs, and the target config file may need to define them all before OpenOCD can talk to the chip. For example, some phone chips have JTAG scan chains that include an ARM core for operating system use, a DSP, another ARM core embedded in an image processing engine, and other processing engines. 6.3.1 Default Value Boiler Plate Code ------------------------------------- All target configuration files should start with code like this, letting board config files express environment-specific differences in how things should be set up. # Boards may override chip names, perhaps based on role, # but the default should match what the vendor uses if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME sam7x256 } # ONLY use ENDIAN with targets that can change it. if { [info exists ENDIAN] } { set _ENDIAN $ENDIAN } else { set _ENDIAN little } # TAP identifiers may change as chips mature, for example with # new revision fields (the "3" here). Pick a good default; you # can pass several such identifiers to the "jtag newtap" command. if { [info exists CPUTAPID ] } { set _CPUTAPID $CPUTAPID } else { set _CPUTAPID 0x3f0f0f0f } _Remember:_ Board config files may include multiple target config files, or the same target file multiple times (changing at least 'CHIPNAME'). Likewise, the target configuration file should define '_TARGETNAME' (or '_TARGETNAME0' etc) and use it later on when defining debug targets: set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -chain-position $_TARGETNAME 6.3.2 Adding TAPs to the Scan Chain ----------------------------------- After the "defaults" are set up, add the TAPs on each chip to the JTAG scan chain. *Note TAP Declaration::, and the naming convention for taps. In the simplest case the chip has only one TAP, probably for a CPU or FPGA. The config file for the Atmel AT91SAM7X256 looks (in part) like this: jtag newtap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID A board with two such at91sam7 chips would be able to source such a config file twice, with different values for 'CHIPNAME', so it adds a different TAP each time. If there are nonzero '-expected-id' values, OpenOCD attempts to verify the actual tap id against those values. It will issue error messages if there is mismatch, which can help to pinpoint problems in OpenOCD configurations. JTAG tap: sam7x256.cpu tap/device found: 0x3f0f0f0f (Manufacturer: 0x787, Part: 0xf0f0, Version: 0x3) ERROR: Tap: sam7x256.cpu - Expected id: 0x12345678, Got: 0x3f0f0f0f ERROR: expected: mfg: 0x33c, part: 0x2345, ver: 0x1 ERROR: got: mfg: 0x787, part: 0xf0f0, ver: 0x3 There are more complex examples too, with chips that have multiple TAPs. Ones worth looking at include: * 'target/omap3530.cfg' - with disabled ARM and DSP, plus a JRC to enable them * 'target/str912.cfg' - with flash, CPU, and boundary scan * 'target/ti_dm355.cfg' - with ETM, ARM, and JRC (this JRC is not currently used) 6.3.3 Add CPU targets --------------------- After adding a TAP for a CPU, you should set it up so that GDB and other commands can use it. *Note CPU Configuration::. For the at91sam7 example above, the command can look like this; note that '$_ENDIAN' is not needed, since OpenOCD defaults to little endian, and this chip doesn't support changing that. set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -chain-position $_TARGETNAME Work areas are small RAM areas associated with CPU targets. They are used by OpenOCD to speed up downloads, and to download small snippets of code to program flash chips. If the chip includes a form of "on-chip-ram" - and many do - define a work area if you can. Again using the at91sam7 as an example, this can look like: $_TARGETNAME configure -work-area-phys 0x00200000 \ -work-area-size 0x4000 -work-area-backup 0 6.3.4 Define CPU targets working in SMP --------------------------------------- After setting targets, you can define a list of targets working in SMP. set _TARGETNAME_1 $_CHIPNAME.cpu1 set _TARGETNAME_2 $_CHIPNAME.cpu2 target create $_TARGETNAME_1 cortex_a -chain-position $_CHIPNAME.dap \ -coreid 0 -dbgbase $_DAP_DBG1 target create $_TARGETNAME_2 cortex_a -chain-position $_CHIPNAME.dap \ -coreid 1 -dbgbase $_DAP_DBG2 #define 2 targets working in smp. target smp $_CHIPNAME.cpu2 $_CHIPNAME.cpu1 In the above example on cortex_a, 2 cpus are working in SMP. In SMP only one GDB instance is created and : * a set of hardware breakpoint sets the same breakpoint on all targets in the list. * halt command triggers the halt of all targets in the list. * resume command triggers the write context and the restart of all targets in the list. * following a breakpoint: the target stopped by the breakpoint is displayed to the GDB session. * dedicated GDB serial protocol packets are implemented for switching/retrieving the target displayed by the GDB session *note Using OpenOCD SMP with GDB: usingopenocdsmpwithgdb. The SMP behaviour can be disabled/enabled dynamically. On cortex_a following command have been implemented. * cortex_a smp_on : enable SMP mode, behaviour is as described above. * cortex_a smp_off : disable SMP mode, the current target is the one displayed in the GDB session, only this target is now controlled by GDB session. This behaviour is useful during system boot up. * cortex_a smp_gdb : display/fix the core id displayed in GDB session see following example. >cortex_a smp_gdb gdb coreid 0 -> -1 #0 : coreid 0 is displayed to GDB , #-> -1 : next resume triggers a real resume > cortex_a smp_gdb 1 gdb coreid 0 -> 1 #0 :coreid 0 is displayed to GDB , #->1 : next resume displays coreid 1 to GDB > resume > cortex_a smp_gdb gdb coreid 1 -> 1 #1 :coreid 1 is displayed to GDB , #->1 : next resume displays coreid 1 to GDB > cortex_a smp_gdb -1 gdb coreid 1 -> -1 #1 :coreid 1 is displayed to GDB, #->-1 : next resume triggers a real resume 6.3.5 Chip Reset Setup ---------------------- As a rule, you should put the 'reset_config' command into the board file. Most things you think you know about a chip can be tweaked by the board. Some chips have specific ways the TRST and SRST signals are managed. In the unusual case that these are _chip specific_ and can never be changed by board wiring, they could go here. For example, some chips can't support JTAG debugging without both signals. Provide a 'reset-assert' event handler if you can. Such a handler uses JTAG operations to reset the target, letting this target config be used in systems which don't provide the optional SRST signal, or on systems where you don't want to reset all targets at once. Such a handler might write to chip registers to force a reset, use a JRC to do that (preferable - the target may be wedged!), or force a watchdog timer to trigger. (For Cortex-M targets, this is not necessary. The target driver knows how to use trigger an NVIC reset when SRST is not available.) Some chips need special attention during reset handling if they're going to be used with JTAG. An example might be needing to send some commands right after the target's TAP has been reset, providing a 'reset-deassert-post' event handler that writes a chip register to report that JTAG debugging is being done. Another would be reconfiguring the watchdog so that it stops counting while the core is halted in the debugger. JTAG clocking constraints often change during reset, and in some cases target config files (rather than board config files) are the right places to handle some of those issues. For example, immediately after reset most chips run using a slower clock than they will use later. That means that after reset (and potentially, as OpenOCD first starts up) they must use a slower JTAG clock rate than they will use later. *Note JTAG Speed: jtagspeed. Important: When you are debugging code that runs right after chip reset, getting these issues right is critical. In particular, if you see intermittent failures when OpenOCD verifies the scan chain after reset, look at how you are setting up JTAG clocking. 6.3.6 The init_targets procedure -------------------------------- Target config files can either be "linear" (script executed line-by-line when parsed in configuration stage, *Note Configuration Stage: configurationstage,) or they can contain a special procedure called 'init_targets', which will be executed when entering run stage (after parsing all config files or after 'init' command, *Note Entering the Run Stage: enteringtherunstage.) Such procedure can be overriden by "next level" script (which sources the original). This concept faciliates code reuse when basic target config files provide generic configuration procedures and 'init_targets' procedure, which can then be sourced and enchanced or changed in a "more specific" target config file. This is not possible with "linear" config scripts, because sourcing them executes every initialization commands they provide. ### generic_file.cfg ### proc setup_my_chip {chip_name flash_size ram_size} { # basic initialization procedure ... } proc init_targets {} { # initializes generic chip with 4kB of flash and 1kB of RAM setup_my_chip MY_GENERIC_CHIP 4096 1024 } ### specific_file.cfg ### source [find target/generic_file.cfg] proc init_targets {} { # initializes specific chip with 128kB of flash and 64kB of RAM setup_my_chip MY_CHIP_WITH_128K_FLASH_64KB_RAM 131072 65536 } The easiest way to convert "linear" config files to 'init_targets' version is to enclose every line of "code" (i.e. not 'source' commands, procedures, etc.) in this procedure. For an example of this scheme see LPC2000 target config files. The 'init_boards' procedure is a similar concept concerning board config files (*Note The init_board procedure: theinitboardprocedure.) 6.3.7 ARM Core Specific Hacks ----------------------------- If the chip has a DCC, enable it. If the chip is an ARM9 with some special high speed download features - enable it. If present, the MMU, the MPU and the CACHE should be disabled. Some ARM cores are equipped with trace support, which permits examination of the instruction and data bus activity. Trace activity is controlled through an "Embedded Trace Module" (ETM) on one of the core's scan chains. The ETM emits voluminous data through a "trace port". (*Note ARM Hardware Tracing: armhardwaretracing.) If you are using an external trace port, configure it in your board config file. If you are using an on-chip "Embedded Trace Buffer" (ETB), configure it in your target config file. etm config $_TARGETNAME 16 normal full etb etb config $_TARGETNAME $_CHIPNAME.etb 6.3.8 Internal Flash Configuration ---------------------------------- This applies ONLY TO MICROCONTROLLERS that have flash built in. Never ever in the "target configuration file" define any type of flash that is external to the chip. (For example a BOOT flash on Chip Select 0.) Such flash information goes in a board file - not the TARGET (chip) file. Examples: * at91sam7x256 - has 256K flash YES enable it. * str912 - has flash internal YES enable it. * imx27 - uses boot flash on CS0 - it goes in the board file. * pxa270 - again - CS0 flash - it goes in the board file. 6.4 Translating Configuration Files =================================== If you have a configuration file for another hardware debugger or toolset (Abatron, BDI2000, BDI3000, CCS, Lauterbach, Segger, Macraigor, etc.), translating it into OpenOCD syntax is often quite straightforward. The most tricky part of creating a configuration script is oftentimes the reset init sequence where e.g. PLLs, DRAM and the like is set up. One trick that you can use when translating is to write small Tcl procedures to translate the syntax into OpenOCD syntax. This can avoid manual translation errors and make it easier to convert other scripts later on. Example of transforming quirky arguments to a simple search and replace job: # Lauterbach syntax(?) # # Data.Set c15:0x042f %long 0x40000015 # # OpenOCD syntax when using procedure below. # # setc15 0x01 0x00050078 proc setc15 {regs value} { global TARGETNAME echo [format "set p15 0x%04x, 0x%08x" $regs $value] arm mcr 15 [expr ($regs>>12)&0x7] \ [expr ($regs>>0)&0xf] [expr ($regs>>4)&0xf] \ [expr ($regs>>8)&0x7] $value } ---------- Footnotes ---------- (1) A FAQ gives details.  File: openocd.info, Node: Daemon Configuration, Next: Debug Adapter Configuration, Prev: Config File Guidelines, Up: Top 7 Daemon Configuration ********************** The commands here are commonly found in the openocd.cfg file and are used to specify what TCP/IP ports are used, and how GDB should be supported. 7.1 Configuration Stage ======================= When the OpenOCD server process starts up, it enters a _configuration stage_ which is the only time that certain commands, _configuration commands_, may be issued. Normally, configuration commands are only available inside startup scripts. In this manual, the definition of a configuration command is presented as a _Config Command_, not as a _Command_ which may be issued interactively. The runtime 'help' command also highlights configuration commands, and those which may be issued at any time. Those configuration commands include declaration of TAPs, flash banks, the interface used for JTAG communication, and other basic setup. The server must leave the configuration stage before it may access or activate TAPs. After it leaves this stage, configuration commands may no longer be issued. 7.2 Entering the Run Stage ========================== The first thing OpenOCD does after leaving the configuration stage is to verify that it can talk to the scan chain (list of TAPs) which has been configured. It will warn if it doesn't find TAPs it expects to find, or finds TAPs that aren't supposed to be there. You should see no errors at this point. If you see errors, resolve them by correcting the commands you used to configure the server. Common errors include using an initial JTAG speed that's too fast, and not providing the right IDCODE values for the TAPs on the scan chain. Once OpenOCD has entered the run stage, a number of commands become available. A number of these relate to the debug targets you may have declared. For example, the 'mww' command will not be available until a target has been successfuly instantiated. If you want to use those commands, you may need to force entry to the run stage. -- Config Command: init This command terminates the configuration stage and enters the run stage. This helps when you need to have the startup scripts manage tasks such as resetting the target, programming flash, etc. To reset the CPU upon startup, add "init" and "reset" at the end of the config script or at the end of the OpenOCD command line using the '-c' command line switch. If this command does not appear in any startup/configuration file OpenOCD executes the command for you after processing all configuration files and/or command line options. NOTE: This command normally occurs at or near the end of your openocd.cfg file to force OpenOCD to "initialize" and make the targets ready. For example: If your openocd.cfg file needs to read/write memory on your target, 'init' must occur before the memory read/write commands. This includes 'nand probe'. -- Overridable Procedure: jtag_init This is invoked at server startup to verify that it can talk to the scan chain (list of TAPs) which has been configured. The default implementation first tries 'jtag arp_init', which uses only a lightweight JTAG reset before examining the scan chain. If that fails, it tries again, using a harder reset from the overridable procedure 'init_reset'. Implementations must have verified the JTAG scan chain before they return. This is done by calling 'jtag arp_init' (or 'jtag arp_init-reset'). 7.3 TCP/IP Ports ================ The OpenOCD server accepts remote commands in several syntaxes. Each syntax uses a different TCP/IP port, which you may specify only during configuration (before those ports are opened). For reasons including security, you may wish to prevent remote access using one or more of these ports. In such cases, just specify the relevant port number as zero. If you disable all access through TCP/IP, you will need to use the command line '-pipe' option. -- Command: gdb_port [number] Normally gdb listens to a TCP/IP port, but GDB can also communicate via pipes(stdin/out or named pipes). The name "gdb_port" stuck because it covers probably more than 90% of the normal use cases. No arguments reports GDB port. "pipe" means listen to stdin output to stdout, an integer is base port number, "disable" disables the gdb server. When using "pipe", also use log_output to redirect the log output to a file so as not to flood the stdin/out pipes. The -p/-pipe option is deprecated and a warning is printed as it is equivalent to passing in -c "gdb_port pipe; log_output openocd.log". Any other string is interpreted as named pipe to listen to. Output pipe is the same name as input pipe, but with 'o' appended, e.g. /var/gdb, /var/gdbo. The GDB port for the first target will be the base port, the second target will listen on gdb_port + 1, and so on. When not specified during the configuration stage, the port NUMBER defaults to 3333. -- Command: tcl_port [number] Specify or query the port used for a simplified RPC connection that can be used by clients to issue TCL commands and get the output from the Tcl engine. Intended as a machine interface. When not specified during the configuration stage, the port NUMBER defaults to 6666. -- Command: telnet_port [number] Specify or query the port on which to listen for incoming telnet connections. This port is intended for interaction with one human through TCL commands. When not specified during the configuration stage, the port NUMBER defaults to 4444. When specified as zero, this port is not activated. 7.4 GDB Configuration ===================== You can reconfigure some GDB behaviors if needed. The ones listed here are static and global. *Note Target Configuration: targetconfiguration, about configuring individual targets. *Note Target Events: targetevents, about configuring target-specific event handling. -- Command: gdb_breakpoint_override ['hard'|'soft'|'disable'] Force breakpoint type for gdb 'break' commands. This option supports GDB GUIs which don't distinguish hard versus soft breakpoints, if the default OpenOCD and GDB behaviour is not sufficient. GDB normally uses hardware breakpoints if the memory map has been set up for flash regions. -- Config Command: gdb_flash_program ('enable'|'disable') Set to 'enable' to cause OpenOCD to program the flash memory when a vFlash packet is received. The default behaviour is 'enable'. -- Config Command: gdb_memory_map ('enable'|'disable') Set to 'enable' to cause OpenOCD to send the memory configuration to GDB when requested. GDB will then know when to set hardware breakpoints, and program flash using the GDB load command. 'gdb_flash_program enable' must also be enabled for flash programming to work. Default behaviour is 'enable'. *Note gdb_flash_program: gdbflashprogram. -- Config Command: gdb_report_data_abort ('enable'|'disable') Specifies whether data aborts cause an error to be reported by GDB memory read packets. The default behaviour is 'disable'; use 'enable' see these errors reported. 7.5 Event Polling ================= Hardware debuggers are parts of asynchronous systems, where significant events can happen at any time. The OpenOCD server needs to detect some of these events, so it can report them to through TCL command line or to GDB. Examples of such events include: * One of the targets can stop running ... maybe it triggers a code breakpoint or data watchpoint, or halts itself. * Messages may be sent over "debug message" channels ... many targets support such messages sent over JTAG, for receipt by the person debugging or tools. * Loss of power ... some adapters can detect these events. * Resets not issued through JTAG ... such reset sources can include button presses or other system hardware, sometimes including the target itself (perhaps through a watchdog). * Debug instrumentation sometimes supports event triggering such as "trace buffer full" (so it can quickly be emptied) or other signals (to correlate with code behavior). None of those events are signaled through standard JTAG signals. However, most conventions for JTAG connectors include voltage level and system reset (SRST) signal detection. Some connectors also include instrumentation signals, which can imply events when those signals are inputs. In general, OpenOCD needs to periodically check for those events, either by looking at the status of signals on the JTAG connector or by sending synchronous "tell me your status" JTAG requests to the various active targets. There is a command to manage and monitor that polling, which is normally done in the background. -- Command: poll ['on'|'off'] Poll the current target for its current state. (Also, *note target curstate: targetcurstate.) If that target is in debug mode, architecture specific information about the current state is printed. An optional parameter allows background polling to be enabled and disabled. You could use this from the TCL command shell, or from GDB using 'monitor poll' command. Leave background polling enabled while you're using GDB. > poll background polling: on target state: halted target halted in ARM state due to debug-request, \ current mode: Supervisor cpsr: 0x800000d3 pc: 0x11081bfc MMU: disabled, D-Cache: disabled, I-Cache: enabled >  File: openocd.info, Node: Debug Adapter Configuration, Next: Reset Configuration, Prev: Daemon Configuration, Up: Top 8 Debug Adapter Configuration ***************************** Correctly installing OpenOCD includes making your operating system give OpenOCD access to debug adapters. Once that has been done, Tcl commands are used to select which one is used, and to configure how it is used. Note: Because OpenOCD started out with a focus purely on JTAG, you may find places where it wrongly presumes JTAG is the only transport protocol in use. Be aware that recent versions of OpenOCD are removing that limitation. JTAG remains more functional than most other transports. Other transports do not support boundary scan operations, or may be specific to a given chip vendor. Some might be usable only for programming flash memory, instead of also for debugging. Debug Adapters/Interfaces/Dongles are normally configured through commands in an interface configuration file which is sourced by your 'openocd.cfg' file, or through a command line '-f interface/....cfg' option. source [find interface/olimex-jtag-tiny.cfg] These commands tell OpenOCD what type of JTAG adapter you have, and how to talk to it. A few cases are so simple that you only need to say what driver to use: # jlink interface interface jlink Most adapters need a bit more configuration than that. 8.1 Interface Configuration =========================== The interface command tells OpenOCD what type of debug adapter you are using. Depending on the type of adapter, you may need to use one or more additional commands to further identify or configure the adapter. -- Config Command: interface name Use the interface driver NAME to connect to the target. -- Command: interface_list List the debug adapter drivers that have been built into the running copy of OpenOCD. -- Command: interface transports transport_name+ Specifies the transports supported by this debug adapter. The adapter driver builds-in similar knowledge; use this only when external configuration (such as jumpering) changes what the hardware can support. -- Command: adapter_name Returns the name of the debug adapter driver being used. 8.2 Interface Drivers ===================== Each of the interface drivers listed here must be explicitly enabled when OpenOCD is configured, in order to be made available at run time. -- Interface Driver: amt_jtagaccel Amontec Chameleon in its JTAG Accelerator configuration, connected to a PC's EPP mode parallel port. This defines some driver-specific commands: -- Config Command: parport_port number Specifies either the address of the I/O port (default: 0x378 for LPT1) or the number of the '/dev/parport' device. -- Config Command: rtck ['enable'|'disable'] Displays status of RTCK option. Optionally sets that option first. -- Interface Driver: arm-jtag-ew Olimex ARM-JTAG-EW USB adapter This has one driver-specific command: -- Command: armjtagew_info Logs some status -- Interface Driver: at91rm9200 Supports bitbanged JTAG from the local system, presuming that system is an Atmel AT91rm9200 and a specific set of GPIOs is used. -- Interface Driver: dummy A dummy software-only driver for debugging. -- Interface Driver: ep93xx Cirrus Logic EP93xx based single-board computer bit-banging (in development) -- Interface Driver: ft2232 FTDI FT2232 (USB) based devices over one of the userspace libraries. Note that this driver has several flaws and the 'ftdi' driver is recommended as its replacement. These interfaces have several commands, used to configure the driver before initializing the JTAG scan chain: -- Config Command: ft2232_device_desc description Provides the USB device description (the _iProduct string_) of the FTDI FT2232 device. If not specified, the FTDI default value is used. This setting is only valid if compiled with FTD2XX support. -- Config Command: ft2232_serial serial-number Specifies the SERIAL-NUMBER of the FTDI FT2232 device to use, in case the vendor provides unique IDs and more than one FT2232 device is connected to the host. If not specified, serial numbers are not considered. (Note that USB serial numbers can be arbitrary Unicode strings, and are not restricted to containing only decimal digits.) -- Config Command: ft2232_layout name Each vendor's FT2232 device can use different GPIO signals to control output-enables, reset signals, and LEDs. Currently valid layout NAME values include: - axm0432_jtag Axiom AXM-0432 - comstick Hitex STR9 comstick - cortino Hitex Cortino JTAG interface - evb_lm3s811 TI/Luminary Micro EVB_LM3S811 as a JTAG interface, either for the local Cortex-M3 (SRST only) or in a passthrough mode (neither SRST nor TRST) This layout can not support the SWO trace mechanism, and should be used only for older boards (before rev C). - luminary_icdi This layout should be used with most TI/Luminary eval boards, including Rev C LM3S811 eval boards and the eponymous ICDI boards, to debug either the local Cortex-M3 or in passthrough mode to debug some other target. It can support the SWO trace mechanism. - flyswatter Tin Can Tools Flyswatter - icebear ICEbear JTAG adapter from Section 5 - jtagkey Amontec JTAGkey and JTAGkey-Tiny (and compatibles) - jtagkey2 Amontec JTAGkey2 (and compatibles) - m5960 American Microsystems M5960 - olimex-jtag Olimex ARM-USB-OCD and ARM-USB-Tiny - oocdlink OOCDLink - redbee-econotag Integrated with a Redbee development board. - redbee-usb Integrated with a Redbee USB-stick development board. - sheevaplug Marvell Sheevaplug development kit - signalyzer Xverve Signalyzer - stm32stick Hitex STM32 Performance Stick - turtelizer2 egnite Software turtelizer2 - usbjtag "USBJTAG-1" layout described in the OpenOCD diploma thesis -- Config Command: ft2232_vid_pid [vid pid]+ The vendor ID and product ID of the FTDI FT2232 device. If not specified, the FTDI default values are used. Currently, up to eight [VID, PID] pairs may be given, e.g. ft2232_vid_pid 0x0403 0xcff8 0x15ba 0x0003 -- Config Command: ft2232_latency ms On some systems using FT2232 based JTAG interfaces the FT_Read function call in ft2232_read() fails to return the expected number of bytes. This can be caused by USB communication delays and has proved hard to reproduce and debug. Setting the FT2232 latency timer to a larger value increases delays for short USB packets but it also reduces the risk of timeouts before receiving the expected number of bytes. The OpenOCD default value is 2 and for some systems a value of 10 has proved useful. -- Config Command: ft2232_channel channel Used to select the channel of the ft2232 chip to use (between 1 and 4). The default value is 1. For example, the interface config file for a Turtelizer JTAG Adapter looks something like this: interface ft2232 ft2232_device_desc "Turtelizer JTAG/RS232 Adapter" ft2232_layout turtelizer2 ft2232_vid_pid 0x0403 0xbdc8 -- Interface Driver: ftdi This driver is for adapters using the MPSSE (Multi-Protocol Synchronous Serial Engine) mode built into many FTDI chips, such as the FT2232, FT4232 and FT232H. It is a complete rewrite to address a large number of problems with the ft2232 interface driver. The driver is using libusb-1.0 in asynchronous mode to talk to the FTDI device, bypassing intermediate libraries like libftdi of D2XX. Performance-wise it is consistently faster than the ft2232 driver, sometimes several times faster. A major improvement of this driver is that support for new FTDI based adapters can be added competely through configuration files, without the need to patch and rebuild OpenOCD. The driver uses a signal abstraction to enable Tcl configuration files to define outputs for one or several FTDI GPIO. These outputs can then be controlled using the 'ftdi_set_signal' command. Special signal names are reserved for nTRST, nSRST and LED (for blink) so that they, if defined, will be used for their customary purpose. Depending on the type of buffer attached to the FTDI GPIO, the outputs have to be controlled differently. In order to support tristateable signals such as nSRST, both a data GPIO and an output-enable GPIO can be specified for each signal. The following output buffer configurations are supported: - Push-pull with one FTDI output as (non-)inverted data line - Open drain with one FTDI output as (non-)inverted output-enable - Tristate with one FTDI output as (non-)inverted data line and another FTDI output as (non-)inverted output-enable - Unbuffered, using the FTDI GPIO as a tristate output directly by switching data and direction as necessary These interfaces have several commands, used to configure the driver before initializing the JTAG scan chain: -- Config Command: ftdi_vid_pid [vid pid]+ The vendor ID and product ID of the adapter. If not specified, the FTDI default values are used. Currently, up to eight [VID, PID] pairs may be given, e.g. ftdi_vid_pid 0x0403 0xcff8 0x15ba 0x0003 -- Config Command: ftdi_device_desc description Provides the USB device description (the _iProduct string_) of the adapter. If not specified, the device description is ignored during device selection. -- Config Command: ftdi_serial serial-number Specifies the SERIAL-NUMBER of the adapter to use, in case the vendor provides unique IDs and more than one adapter is connected to the host. If not specified, serial numbers are not considered. (Note that USB serial numbers can be arbitrary Unicode strings, and are not restricted to containing only decimal digits.) -- Config Command: ftdi_channel channel Selects the channel of the FTDI device to use for MPSSE operations. Most adapters use the default, channel 0, but there are exceptions. -- Config Command: ftdi_layout_init data direction Specifies the initial values of the FTDI GPIO data and direction registers. Each value is a 16-bit number corresponding to the concatenation of the high and low FTDI GPIO registers. The values should be selected based on the schematics of the adapter, such that all signals are set to safe levels with minimal impact on the target system. Avoid floating inputs, conflicting outputs and initially asserted reset signals. -- Config Command: ftdi_layout_signal name ['-data'|'-ndata' data_mask] ['-oe'|'-noe' oe_mask] Creates a signal with the specified NAME, controlled by one or more FTDI GPIO pins via a range of possible buffer connections. The masks are FTDI GPIO register bitmasks to tell the driver the connection and type of the output buffer driving the respective signal. DATA_MASK is the bitmask for the pin(s) connected to the data input of the output buffer. '-ndata' is used with inverting data inputs and '-data' with non-inverting inputs. The '-oe' (or '-noe') option tells where the output-enable (or not-output-enable) input to the output buffer is connected. Both DATA_MASK and OE_MASK need not be specified. For example, a simple open-collector transistor driver would be specified with '-oe' only. In that case the signal can only be set to drive low or to Hi-Z and the driver will complain if the signal is set to drive high. Which means that if it's a reset signal, 'reset_config' must be specified as 'srst_open_drain', not 'srst_push_pull'. A special case is provided when '-data' and '-oe' is set to the same bitmask. Then the FTDI pin is considered being connected straight to the target without any buffer. The FTDI pin is then switched between output and input as necessary to provide the full set of low, high and Hi-Z characteristics. In all other cases, the pins specified in a signal definition are always driven by the FTDI. -- Command: ftdi_set_signal name '0'|'1'|'z' Set a previously defined signal to the specified level. - '0', drive low - '1', drive high - 'z', set to high-impedance For example adapter definitions, see the configuration files shipped in the 'interface/ftdi' directory. -- Interface Driver: remote_bitbang Drive JTAG from a remote process. This sets up a UNIX or TCP socket connection with a remote process and sends ASCII encoded bitbang requests to that process instead of directly driving JTAG. The remote_bitbang driver is useful for debugging software running on processors which are being simulated. -- Config Command: remote_bitbang_port number Specifies the TCP port of the remote process to connect to or 0 to use UNIX sockets instead of TCP. -- Config Command: remote_bitbang_host hostname Specifies the hostname of the remote process to connect to using TCP, or the name of the UNIX socket to use if remote_bitbang_port is 0. For example, to connect remotely via TCP to the host foobar you might have something like: interface remote_bitbang remote_bitbang_port 3335 remote_bitbang_host foobar To connect to another process running locally via UNIX sockets with socket named mysocket: interface remote_bitbang remote_bitbang_port 0 remote_bitbang_host mysocket -- Interface Driver: usb_blaster USB JTAG/USB-Blaster compatibles over one of the userspace libraries for FTDI chips. These interfaces have several commands, used to configure the driver before initializing the JTAG scan chain: -- Config Command: usb_blaster_device_desc description Provides the USB device description (the _iProduct string_) of the FTDI FT245 device. If not specified, the FTDI default value is used. This setting is only valid if compiled with FTD2XX support. -- Config Command: usb_blaster_vid_pid vid pid The vendor ID and product ID of the FTDI FT245 device. If not specified, default values are used. Currently, only one VID, PID pair may be given, e.g. for Altera USB-Blaster (default): usb_blaster_vid_pid 0x09FB 0x6001 The following VID/PID is for Kolja Waschk's USB JTAG: usb_blaster_vid_pid 0x16C0 0x06AD -- Command: usb_blaster ('pin6'|'pin8') ('0'|'1') Sets the state of the unused GPIO pins on USB-Blasters (pins 6 and 8 on the female JTAG header). These pins can be used as SRST and/or TRST provided the appropriate connections are made on the target board. For example, to use pin 6 as SRST (as with an AVR board): $_TARGETNAME configure -event reset-assert \ "usb_blaster pin6 1; wait 1; usb_blaster pin6 0" -- Interface Driver: gw16012 Gateworks GW16012 JTAG programmer. This has one driver-specific command: -- Config Command: parport_port [port_number] Display either the address of the I/O port (default: 0x378 for LPT1) or the number of the '/dev/parport' device. If a parameter is provided, first switch to use that port. This is a write-once setting. -- Interface Driver: jlink Segger J-Link family of USB adapters. It currently supports only the JTAG transport. Compatibility Note: Segger released many firmware versions for the many harware versions they produced. OpenOCD was extensively tested and intended to run on all of them, but some combinations were reported as incompatible. As a general recommendation, it is advisable to use the latest firmware version available for each hardware version. However the current V8 is a moving target, and Segger firmware versions released after the OpenOCD was released may not be compatible. In such cases it is recommended to revert to the last known functional version. For 0.5.0, this is from "Feb 8 2012 14:30:39", packed with 4.42c. For 0.6.0, the last known version is from "May 3 2012 18:36:22", packed with 4.46f. -- Command: jlink caps Display the device firmware capabilities. -- Command: jlink info Display various device information, like hardware version, firmware version, current bus status. -- Command: jlink hw_jtag ['2'|'3'] Set the JTAG protocol version to be used. Without argument, show the actual JTAG protocol version. -- Command: jlink config Display the J-Link configuration. -- Command: jlink config kickstart [val] Set the Kickstart power on JTAG-pin 19. Without argument, show the Kickstart configuration. -- Command: jlink config mac_address ['ff:ff:ff:ff:ff:ff'] Set the MAC address of the J-Link Pro. Without argument, show the MAC address. -- Command: jlink config ip ['A.B.C.D'('/E'|'F.G.H.I')] Set the IP configuration of the J-Link Pro, where A.B.C.D is the IP address, E the bit of the subnet mask and F.G.H.I the subnet mask. Without arguments, show the IP configuration. -- Command: jlink config usb_address ['0x00' to '0x03' or '0xff'] Set the USB address; this will also change the product id. Without argument, show the USB address. -- Command: jlink config reset Reset the current configuration. -- Command: jlink config save Save the current configuration to the internal persistent storage. -- Config: jlink pid val Set the USB PID of the interface. As a configuration command, it can be used only before 'init'. -- Interface Driver: parport Supports PC parallel port bit-banging cables: Wigglers, PLD download cable, and more. These interfaces have several commands, used to configure the driver before initializing the JTAG scan chain: -- Config Command: parport_cable name Set the layout of the parallel port cable used to connect to the target. This is a write-once setting. Currently valid cable NAME values include: - altium Altium Universal JTAG cable. - arm-jtag Same as original wiggler except SRST and TRST connections reversed and TRST is also inverted. - chameleon The Amontec Chameleon's CPLD when operated in configuration mode. This is only used to program the Chameleon itself, not a connected target. - dlc5 The Xilinx Parallel cable III. - flashlink The ST Parallel cable. - lattice Lattice ispDOWNLOAD Cable - old_amt_wiggler The Wiggler configuration that comes with some versions of Amontec's Chameleon Programmer. The new version available from the website uses the original Wiggler layout ('WIGGLER') - triton The parallel port adapter found on the "Karo Triton 1 Development Board". This is also the layout used by the HollyGates design (see ). - wiggler The original Wiggler layout, also supported by several clones, such as the Olimex ARM-JTAG - wiggler2 Same as original wiggler except an led is fitted on D5. - wiggler_ntrst_inverted Same as original wiggler except TRST is inverted. -- Config Command: parport_port [port_number] Display either the address of the I/O port (default: 0x378 for LPT1) or the number of the '/dev/parport' device. If a parameter is provided, first switch to use that port. This is a write-once setting. When using PPDEV to access the parallel port, use the number of the parallel port: 'parport_port 0' (the default). If 'parport_port 0x378' is specified you may encounter a problem. -- Command: parport_toggling_time [nanoseconds] Displays how many nanoseconds the hardware needs to toggle TCK; the parport driver uses this value to obey the 'adapter_khz' configuration. When the optional NANOSECONDS parameter is given, that setting is changed before displaying the current value. The default setting should work reasonably well on commodity PC hardware. However, you may want to calibrate for your specific hardware. Tip: To measure the toggling time with a logic analyzer or a digital storage oscilloscope, follow the procedure below: > parport_toggling_time 1000 > adapter_khz 500 This sets the maximum JTAG clock speed of the hardware, but the actual speed probably deviates from the requested 500 kHz. Now, measure the time between the two closest spaced TCK transitions. You can use 'runtest 1000' or something similar to generate a large set of samples. Update the setting to match your measurement: > parport_toggling_time Now the clock speed will be a better match for 'adapter_khz rate' commands given in OpenOCD scripts and event handlers. You can do something similar with many digital multimeters, but note that you'll probably need to run the clock continuously for several seconds before it decides what clock rate to show. Adjust the toggling time up or down until the measured clock rate is a good match for the adapter_khz rate you specified; be conservative. -- Config Command: parport_write_on_exit ('on'|'off') This will configure the parallel driver to write a known cable-specific value to the parallel interface on exiting OpenOCD. For example, the interface configuration file for a classic "Wiggler" cable on LPT2 might look something like this: interface parport parport_port 0x278 parport_cable wiggler -- Interface Driver: presto ASIX PRESTO USB JTAG programmer. -- Config Command: presto_serial serial_string Configures the USB serial number of the Presto device to use. -- Interface Driver: rlink Raisonance RLink USB adapter -- Interface Driver: usbprog usbprog is a freely programmable USB adapter. -- Interface Driver: vsllink vsllink is part of Versaloon which is a versatile USB programmer. Note: This defines quite a few driver-specific commands, which are not currently documented here. -- Interface Driver: hla This is a driver that supports multiple High Level Adapters. This type of adapter does not expose some of the lower level api's that OpenOCD would normally use to access the target. Currently supported adapters include the ST STLINK and TI ICDI. -- Config Command: hla_device_desc description Currently Not Supported. -- Config Command: hla_serial serial Currently Not Supported. -- Config Command: hla_layout ('stlink'|'icdi') Specifies the adapter layout to use. -- Config Command: hla_vid_pid vid pid The vendor ID and product ID of the device. -- Config Command: stlink_api api_level Manually sets the stlink api used, valid options are 1 or 2. (STLINK Only). -- Interface Driver: opendous opendous-jtag is a freely programmable USB adapter. -- Interface Driver: ulink This is the Keil ULINK v1 JTAG debugger. -- Interface Driver: ZY1000 This is the Zylin ZY1000 JTAG debugger. Note: This defines some driver-specific commands, which are not currently documented here. -- Command: power ['on'|'off'] Turn power switch to target on/off. No arguments: print status. 8.3 Transport Configuration =========================== As noted earlier, depending on the version of OpenOCD you use, and the debug adapter you are using, several transports may be available to communicate with debug targets (or perhaps to program flash memory). -- Command: transport list displays the names of the transports supported by this version of OpenOCD. -- Command: transport select transport_name Select which of the supported transports to use in this OpenOCD session. The transport must be supported by the debug adapter hardware and by the version of OPenOCD you are using (including the adapter's driver). No arguments: returns name of session's selected transport. 8.3.1 JTAG Transport -------------------- JTAG is the original transport supported by OpenOCD, and most of the OpenOCD commands support it. JTAG transports expose a chain of one or more Test Access Points (TAPs), each of which must be explicitly declared. JTAG supports both debugging and boundary scan testing. Flash programming support is built on top of debug support. 8.3.2 SWD Transport ------------------- SWD (Serial Wire Debug) is an ARM-specific transport which exposes one Debug Access Point (DAP, which must be explicitly declared. (SWD uses fewer signal wires than JTAG.) SWD is debug-oriented, and does not support boundary scan testing. Flash programming support is built on top of debug support. (Some processors support both JTAG and SWD.) -- Command: swd newdap ... Declares a single DAP which uses SWD transport. Parameters are currently the same as "jtag newtap" but this is expected to change. -- Command: swd wcr trn prescale Updates TRN (turnaraound delay) and prescaling.fields of the Wire Control Register (WCR). No parameters: displays current settings. 8.3.3 SPI Transport ------------------- The Serial Peripheral Interface (SPI) is a general purpose transport which uses four wire signaling. Some processors use it as part of a solution for flash programming. 8.4 JTAG Speed ============== JTAG clock setup is part of system setup. It _does not belong with interface setup_ since any interface only knows a few of the constraints for the JTAG clock speed. Sometimes the JTAG speed is changed during the target initialization process: (1) slow at reset, (2) program the CPU clocks, (3) run fast. Both the "slow" and "fast" clock rates are functions of the oscillators used, the chip, the board design, and sometimes power management software that may be active. The speed used during reset, and the scan chain verification which follows reset, can be adjusted using a 'reset-start' target event handler. It can then be reconfigured to a faster speed by a 'reset-init' target event handler after it reprograms those CPU clocks, or manually (if something else, such as a boot loader, sets up those clocks). *Note Target Events: targetevents. When the initial low JTAG speed is a chip characteristic, perhaps because of a required oscillator speed, provide such a handler in the target config file. When that speed is a function of a board-specific characteristic such as which speed oscillator is used, it belongs in the board config file instead. In both cases it's safest to also set the initial JTAG clock rate to that same slow speed, so that OpenOCD never starts up using a clock speed that's faster than the scan chain can support. jtag_rclk 3000 $_TARGET.cpu configure -event reset-start { jtag_rclk 3000 } If your system supports adaptive clocking (RTCK), configuring JTAG to use that is probably the most robust approach. However, it introduces delays to synchronize clocks; so it may not be the fastest solution. NOTE: Script writers should consider using 'jtag_rclk' instead of 'adapter_khz', but only for (ARM) cores and boards which support adaptive clocking. -- Command: adapter_khz max_speed_kHz A non-zero speed is in KHZ. Hence: 3000 is 3mhz. JTAG interfaces usually support a limited number of speeds. The speed actually used won't be faster than the speed specified. Chip data sheets generally include a top JTAG clock rate. The actual rate is often a function of a CPU core clock, and is normally less than that peak rate. For example, most ARM cores accept at most one sixth of the CPU clock. Speed 0 (khz) selects RTCK method. *Note FAQ RTCK: faqrtck. If your system uses RTCK, you won't need to change the JTAG clocking after setup. Not all interfaces, boards, or targets support "rtck". If the interface device can not support it, an error is returned when you try to use RTCK. -- Function: jtag_rclk fallback_speed_kHz This Tcl proc (defined in 'startup.tcl') attempts to enable RTCK/RCLK. If that fails (maybe the interface, board, or target doesn't support it), falls back to the specified frequency. # Fall back to 3mhz if RTCK is not supported jtag_rclk 3000  File: openocd.info, Node: Reset Configuration, Next: TAP Declaration, Prev: Debug Adapter Configuration, Up: Top 9 Reset Configuration ********************* Every system configuration may require a different reset configuration. This can also be quite confusing. Resets also interact with RESET-INIT event handlers, which do things like setting up clocks and DRAM, and JTAG clock rates. (*Note JTAG Speed: jtagspeed.) They can also interact with JTAG routers. Please see the various board files for examples. Note: To maintainers and integrators: Reset configuration touches several things at once. Normally the board configuration file should define it and assume that the JTAG adapter supports everything that's wired up to the board's JTAG connector. However, the target configuration file could also make note of something the silicon vendor has done inside the chip, which will be true for most (or all) boards using that chip. And when the JTAG adapter doesn't support everything, the user configuration file will need to override parts of the reset configuration provided by other files. 9.1 Types of Reset ================== There are many kinds of reset possible through JTAG, but they may not all work with a given board and adapter. That's part of why reset configuration can be error prone. * _System Reset_ ... the _SRST_ hardware signal resets all chips connected to the JTAG adapter, such as processors, power management chips, and I/O controllers. Normally resets triggered with this signal behave exactly like pressing a RESET button. * _JTAG TAP Reset_ ... the _TRST_ hardware signal resets just the TAP controllers connected to the JTAG adapter. Such resets should not be visible to the rest of the system; resetting a device's TAP controller just puts that controller into a known state. * _Emulation Reset_ ... many devices can be reset through JTAG commands. These resets are often distinguishable from system resets, either explicitly (a "reset reason" register says so) or implicitly (not all parts of the chip get reset). * _Other Resets_ ... system-on-chip devices often support several other types of reset. You may need to arrange that a watchdog timer stops while debugging, preventing a watchdog reset. There may be individual module resets. In the best case, OpenOCD can hold SRST, then reset the TAPs via TRST and send commands through JTAG to halt the CPU at the reset vector before the 1st instruction is executed. Then when it finally releases the SRST signal, the system is halted under debugger control before any code has executed. This is the behavior required to support the 'reset halt' and 'reset init' commands; after 'reset init' a board-specific script might do things like setting up DRAM. (*Note Reset Command: resetcommand.) 9.2 SRST and TRST Issues ======================== Because SRST and TRST are hardware signals, they can have a variety of system-specific constraints. Some of the most common issues are: * _Signal not available_ ... Some boards don't wire SRST or TRST to the JTAG connector. Some JTAG adapters don't support such signals even if they are wired up. Use the 'reset_config' SIGNALS options to say when either of those signals is not connected. When SRST is not available, your code might not be able to rely on controllers having been fully reset during code startup. Missing TRST is not a problem, since JTAG-level resets can be triggered using with TMS signaling. * _Signals shorted_ ... Sometimes a chip, board, or adapter will connect SRST to TRST, instead of keeping them separate. Use the 'reset_config' COMBINATION options to say when those signals aren't properly independent. * _Timing_ ... Reset circuitry like a resistor/capacitor delay circuit, reset supervisor, or on-chip features can extend the effect of a JTAG adapter's reset for some time after the adapter stops issuing the reset. For example, there may be chip or board requirements that all reset pulses last for at least a certain amount of time; and reset buttons commonly have hardware debouncing. Use the 'adapter_nsrst_delay' and 'jtag_ntrst_delay' commands to say when extra delays are needed. * _Drive type_ ... Reset lines often have a pullup resistor, letting the JTAG interface treat them as open-drain signals. But that's not a requirement, so the adapter may need to use push/pull output drivers. Also, with weak pullups it may be advisable to drive signals to both levels (push/pull) to minimize rise times. Use the 'reset_config' TRST_TYPE and SRST_TYPE parameters to say how to drive reset signals. * _Special initialization_ ... Targets sometimes need special JTAG initialization sequences to handle chip-specific issues (not limited to errata). For example, certain JTAG commands might need to be issued while the system as a whole is in a reset state (SRST active) but the JTAG scan chain is usable (TRST inactive). Many systems treat combined assertion of SRST and TRST as a trigger for a harder reset than SRST alone. Such custom reset handling is discussed later in this chapter. There can also be other issues. Some devices don't fully conform to the JTAG specifications. Trivial system-specific differences are common, such as SRST and TRST using slightly different names. There are also vendors who distribute key JTAG documentation for their chips only to developers who have signed a Non-Disclosure Agreement (NDA). Sometimes there are chip-specific extensions like a requirement to use the normally-optional TRST signal (precluding use of JTAG adapters which don't pass TRST through), or needing extra steps to complete a TAP reset. In short, SRST and especially TRST handling may be very finicky, needing to cope with both architecture and board specific constraints. 9.3 Commands for Handling Resets ================================ -- Command: adapter_nsrst_assert_width milliseconds Minimum amount of time (in milliseconds) OpenOCD should wait after asserting nSRST (active-low system reset) before allowing it to be deasserted. -- Command: adapter_nsrst_delay milliseconds How long (in milliseconds) OpenOCD should wait after deasserting nSRST (active-low system reset) before starting new JTAG operations. When a board has a reset button connected to SRST line it will probably have hardware debouncing, implying you should use this. -- Command: jtag_ntrst_assert_width milliseconds Minimum amount of time (in milliseconds) OpenOCD should wait after asserting nTRST (active-low JTAG TAP reset) before allowing it to be deasserted. -- Command: jtag_ntrst_delay milliseconds How long (in milliseconds) OpenOCD should wait after deasserting nTRST (active-low JTAG TAP reset) before starting new JTAG operations. -- Command: reset_config mode_flag ... This command displays or modifies the reset configuration of your combination of JTAG board and target in target configuration scripts. Information earlier in this section describes the kind of problems the command is intended to address (*note SRST and TRST Issues: srstandtrstissues.). As a rule this command belongs only in board config files, describing issues like _board doesn't connect TRST_; or in user config files, addressing limitations derived from a particular combination of interface and board. (An unlikely example would be using a TRST-only adapter with a board that only wires up SRST.) The MODE_FLAG options can be specified in any order, but only one of each type - SIGNALS, COMBINATION, GATES, TRST_TYPE, SRST_TYPE and CONNECT_TYPE - may be specified at a time. If you don't provide a new value for a given type, its previous value (perhaps the default) is unchanged. For example, this means that you don't need to say anything at all about TRST just to declare that if the JTAG adapter should want to drive SRST, it must explicitly be driven high ('srst_push_pull'). * SIGNALS can specify which of the reset signals are connected. For example, If the JTAG interface provides SRST, but the board doesn't connect that signal properly, then OpenOCD can't use it. Possible values are 'none' (the default), 'trst_only', 'srst_only' and 'trst_and_srst'. Tip: If your board provides SRST and/or TRST through the JTAG connector, you must declare that so those signals can be used. * The COMBINATION is an optional value specifying broken reset signal implementations. The default behaviour if no option given is 'separate', indicating everything behaves normally. 'srst_pulls_trst' states that the test logic is reset together with the reset of the system (e.g. NXP LPC2000, "broken" board layout), 'trst_pulls_srst' says that the system is reset together with the test logic (only hypothetical, I haven't seen hardware with such a bug, and can be worked around). 'combined' implies both 'srst_pulls_trst' and 'trst_pulls_srst'. * The GATES tokens control flags that describe some cases where JTAG may be unvailable during reset. 'srst_gates_jtag' (default) indicates that asserting SRST gates the JTAG clock. This means that no communication can happen on JTAG while SRST is asserted. Its converse is 'srst_nogate', indicating that JTAG commands can safely be issued while SRST is active. * The CONNECT_TYPE tokens control flags that describe some cases where SRST is asserted while connecting to the target. 'srst_nogate' is required to use this option. 'connect_deassert_srst' (default) indicates that SRST will not be asserted while connecting to the target. Its converse is 'connect_assert_srst', indicating that SRST will be asserted before any target connection. Only some targets support this feature, STM32 and STR9 are examples. This feature is useful if you are unable to connect to your target due to incorrect options byte config or illegal program execution. The optional TRST_TYPE and SRST_TYPE parameters allow the driver mode of each reset line to be specified. These values only affect JTAG interfaces with support for different driver modes, like the Amontec JTAGkey and JTAG Accelerator. Also, they are necessarily ignored if the relevant signal (TRST or SRST) is not connected. * Possible TRST_TYPE driver modes for the test reset signal (TRST) are the default 'trst_push_pull', and 'trst_open_drain'. Most boards connect this signal to a pulldown, so the JTAG TAPs never leave reset unless they are hooked up to a JTAG adapter. * Possible SRST_TYPE driver modes for the system reset signal (SRST) are the default 'srst_open_drain', and 'srst_push_pull'. Most boards connect this signal to a pullup, and allow the signal to be pulled low by various events including system powerup and pressing a reset button. 9.4 Custom Reset Handling ========================= OpenOCD has several ways to help support the various reset mechanisms provided by chip and board vendors. The commands shown in the previous section give standard parameters. There are also _event handlers_ associated with TAPs or Targets. Those handlers are Tcl procedures you can provide, which are invoked at particular points in the reset sequence. _When SRST is not an option_ you must set up a 'reset-assert' event handler for your target. For example, some JTAG adapters don't include the SRST signal; and some boards have multiple targets, and you won't always want to reset everything at once. After configuring those mechanisms, you might still find your board doesn't start up or reset correctly. For example, maybe it needs a slightly different sequence of SRST and/or TRST manipulations, because of quirks that the 'reset_config' mechanism doesn't address; or asserting both might trigger a stronger reset, which needs special attention. Experiment with lower level operations, such as 'jtag_reset' and the 'jtag arp_*' operations shown here, to find a sequence of operations that works. *Note JTAG Commands::. When you find a working sequence, it can be used to override 'jtag_init', which fires during OpenOCD startup (*note Configuration Stage: configurationstage.); or 'init_reset', which fires during reset processing. You might also want to provide some project-specific reset schemes. For example, on a multi-target board the standard 'reset' command would reset all targets, but you may need the ability to reset only one target at time and thus want to avoid using the board-wide SRST signal. -- Overridable Procedure: init_reset mode This is invoked near the beginning of the 'reset' command, usually to provide as much of a cold (power-up) reset as practical. By default it is also invoked from 'jtag_init' if the scan chain does not respond to pure JTAG operations. The MODE parameter is the parameter given to the low level reset command ('halt', 'init', or 'run'), 'setup', or potentially some other value. The default implementation just invokes 'jtag arp_init-reset'. Replacements will normally build on low level JTAG operations such as 'jtag_reset'. Operations here must not address individual TAPs (or their associated targets) until the JTAG scan chain has first been verified to work. Implementations must have verified the JTAG scan chain before they return. This is done by calling 'jtag arp_init' (or 'jtag arp_init-reset'). -- Command: jtag arp_init This validates the scan chain using just the four standard JTAG signals (TMS, TCK, TDI, TDO). It starts by issuing a JTAG-only reset. Then it performs checks to verify that the scan chain configuration matches the TAPs it can observe. Those checks include checking IDCODE values for each active TAP, and verifying the length of their instruction registers using TAP '-ircapture' and '-irmask' values. If these tests all pass, TAP 'setup' events are issued to all TAPs with handlers for that event. -- Command: jtag arp_init-reset This uses TRST and SRST to try resetting everything on the JTAG scan chain (and anything else connected to SRST). It then invokes the logic of 'jtag arp_init'.  File: openocd.info, Node: TAP Declaration, Next: CPU Configuration, Prev: Reset Configuration, Up: Top 10 TAP Declaration ****************** _Test Access Ports_ (TAPs) are the core of JTAG. TAPs serve many roles, including: * Debug Target A CPU TAP can be used as a GDB debug target * Flash Programing Some chips program the flash directly via JTAG. Others do it indirectly, making a CPU do it. * Program Download Using the same CPU support GDB uses, you can initialize a DRAM controller, download code to DRAM, and then start running that code. * Boundary Scan Most chips support boundary scan, which helps test for board assembly problems like solder bridges and missing connections OpenOCD must know about the active TAPs on your board(s). Setting up the TAPs is the core task of your configuration files. Once those TAPs are set up, you can pass their names to code which sets up CPUs and exports them as GDB targets, probes flash memory, performs low-level JTAG operations, and more. 10.1 Scan Chains ================ TAPs are part of a hardware "scan chain", which is daisy chain of TAPs. They also need to be added to OpenOCD's software mirror of that hardware list, giving each member a name and associating other data with it. Simple scan chains, with a single TAP, are common in systems with a single microcontroller or microprocessor. More complex chips may have several TAPs internally. Very complex scan chains might have a dozen or more TAPs: several in one chip, more in the next, and connecting to other boards with their own chips and TAPs. You can display the list with the 'scan_chain' command. (Don't confuse this with the list displayed by the 'targets' command, presented in the next chapter. That only displays TAPs for CPUs which are configured as debugging targets.) Here's what the scan chain might look like for a chip more than one TAP: TapName Enabled IdCode Expected IrLen IrCap IrMask -- ------------------ ------- ---------- ---------- ----- ----- ------ 0 omap5912.dsp Y 0x03df1d81 0x03df1d81 38 0x01 0x03 1 omap5912.arm Y 0x0692602f 0x0692602f 4 0x01 0x0f 2 omap5912.unknown Y 0x00000000 0x00000000 8 0x01 0x03 OpenOCD can detect some of that information, but not all of it. *Note Autoprobing: autoprobing. Unfortunately those TAPs can't always be autoconfigured, because not all devices provide good support for that. JTAG doesn't require supporting IDCODE instructions, and chips with JTAG routers may not link TAPs into the chain until they are told to do so. The configuration mechanism currently supported by OpenOCD requires explicit configuration of all TAP devices using 'jtag newtap' commands, as detailed later in this chapter. A command like this would declare one tap and name it 'chip1.cpu': jtag newtap chip1 cpu -irlen 4 -expected-id 0x3ba00477 Each target configuration file lists the TAPs provided by a given chip. Board configuration files combine all the targets on a board, and so forth. Note that _the order in which TAPs are declared is very important._ It must match the order in the JTAG scan chain, both inside a single chip and between them. *Note FAQ TAP Order: faqtaporder. For example, the ST Microsystems STR912 chip has three separate TAPs(1). To configure those taps, 'target/str912.cfg' includes commands something like this: jtag newtap str912 flash ... params ... jtag newtap str912 cpu ... params ... jtag newtap str912 bs ... params ... Actual config files use a variable instead of literals like 'str912', to support more than one chip of each type. *Note Config File Guidelines::. -- Command: jtag names Returns the names of all current TAPs in the scan chain. Use 'jtag cget' or 'jtag tapisenabled' to examine attributes and state of each TAP. foreach t [jtag names] { puts [format "TAP: %s\n" $t] } -- Command: scan_chain Displays the TAPs in the scan chain configuration, and their status. The set of TAPs listed by this command is fixed by exiting the OpenOCD configuration stage, but systems with a JTAG router can enable or disable TAPs dynamically. 10.2 TAP Names ============== When TAP objects are declared with 'jtag newtap', a "dotted.name" is created for the TAP, combining the name of a module (usually a chip) and a label for the TAP. For example: 'xilinx.tap', 'str912.flash', 'omap3530.jrc', 'dm6446.dsp', or 'stm32.cpu'. Many other commands use that dotted.name to manipulate or refer to the TAP. For example, CPU configuration uses the name, as does declaration of NAND or NOR flash banks. The components of a dotted name should follow "C" symbol name rules: start with an alphabetic character, then numbers and underscores are OK; while others (including dots!) are not. Tip: In older code, JTAG TAPs were numbered from 0..N. This feature is still present. However its use is highly discouraged, and should not be relied on; it will be removed by mid-2010. Update all of your scripts to use TAP names rather than numbers, by paying attention to the runtime warnings they trigger. Using TAP numbers in target configuration scripts prevents reusing those scripts on boards with multiple targets. 10.3 TAP Declaration Commands ============================= -- Command: jtag newtap chipname tapname configparams... Declares a new TAP with the dotted name CHIPNAME.TAPNAME, and configured according to the various CONFIGPARAMS. The CHIPNAME is a symbolic name for the chip. Conventionally target config files use '$_CHIPNAME', defaulting to the model name given by the chip vendor but overridable. The TAPNAME reflects the role of that TAP, and should follow this convention: * 'bs' - For boundary scan if this is a seperate TAP; * 'cpu' - The main CPU of the chip, alternatively 'arm' and 'dsp' on chips with both ARM and DSP CPUs, 'arm1' and 'arm2' on chips two ARMs, and so forth; * 'etb' - For an embedded trace buffer (example: an ARM ETB11); * 'flash' - If the chip has a flash TAP, like the str912; * 'jrc' - For JTAG route controller (example: the ICEpick modules on many Texas Instruments chips, like the OMAP3530 on Beagleboards); * 'tap' - Should be used only FPGA or CPLD like devices with a single TAP; * 'unknownN' - If you have no idea what the TAP is for (N is a number); * _when in doubt_ - Use the chip maker's name in their data sheet. For example, the Freescale IMX31 has a SDMA (Smart DMA) with a JTAG TAP; that TAP should be named 'sdma'. Every TAP requires at least the following CONFIGPARAMS: * '-irlen' NUMBER The length in bits of the instruction register, such as 4 or 5 bits. A TAP may also provide optional CONFIGPARAMS: * '-disable' (or '-enable') Use the '-disable' parameter to flag a TAP which is not linked in to the scan chain after a reset using either TRST or the JTAG state machine's RESET state. You may use '-enable' to highlight the default state (the TAP is linked in). *Note Enabling and Disabling TAPs: enablinganddisablingtaps. * '-expected-id' NUMBER A non-zero NUMBER represents a 32-bit IDCODE which you expect to find when the scan chain is examined. These codes are not required by all JTAG devices. _Repeat the option_ as many times as required if more than one ID code could appear (for example, multiple versions). Specify NUMBER as zero to suppress warnings about IDCODE values that were found but not included in the list. Provide this value if at all possible, since it lets OpenOCD tell when the scan chain it sees isn't right. These values are provided in vendors' chip documentation, usually a technical reference manual. Sometimes you may need to probe the JTAG hardware to find these values. *Note Autoprobing: autoprobing. * '-ignore-version' Specify this to ignore the JTAG version field in the '-expected-id' option. When vendors put out multiple versions of a chip, or use the same JTAG-level ID for several largely-compatible chips, it may be more practical to ignore the version field than to update config files to handle all of the various chip IDs. The version field is defined as bit 28-31 of the IDCODE. * '-ircapture' NUMBER The bit pattern loaded by the TAP into the JTAG shift register on entry to the IRCAPTURE state, such as 0x01. JTAG requires the two LSBs of this value to be 01. By default, '-ircapture' and '-irmask' are set up to verify that two-bit value. You may provide additional bits, if you know them, or indicate that a TAP doesn't conform to the JTAG specification. * '-irmask' NUMBER A mask used with '-ircapture' to verify that instruction scans work correctly. Such scans are not used by OpenOCD except to verify that there seems to be no problems with JTAG scan chain operations. 10.4 Other TAP commands ======================= -- Command: jtag cget dotted.name '-event' name -- Command: jtag configure dotted.name '-event' name string At this writing this TAP attribute mechanism is used only for event handling. (It is not a direct analogue of the 'cget'/'configure' mechanism for debugger targets.) See the next section for information about the available events. The 'configure' subcommand assigns an event handler, a TCL string which is evaluated when the event is triggered. The 'cget' subcommand returns that handler. 10.5 TAP Events =============== OpenOCD includes two event mechanisms. The one presented here applies to all JTAG TAPs. The other applies to debugger targets, which are associated with certain TAPs. The TAP events currently defined are: * post-reset The TAP has just completed a JTAG reset. The tap may still be in the JTAG RESET state. Handlers for these events might perform initialization sequences such as issuing TCK cycles, TMS sequences to ensure exit from the ARM SWD mode, and more. Because the scan chain has not yet been verified, handlers for these events _should not issue commands which scan the JTAG IR or DR registers_ of any particular target. NOTE: As this is written (September 2009), nothing prevents such access. * setup The scan chain has been reset and verified. This handler may enable TAPs as needed. * tap-disable The TAP needs to be disabled. This handler should implement 'jtag tapdisable' by issuing the relevant JTAG commands. * tap-enable The TAP needs to be enabled. This handler should implement 'jtag tapenable' by issuing the relevant JTAG commands. If you need some action after each JTAG reset, which isn't actually specific to any TAP (since you can't yet trust the scan chain's contents to be accurate), you might: jtag configure CHIP.jrc -event post-reset { echo "JTAG Reset done" ... non-scan jtag operations to be done after reset } 10.6 Enabling and Disabling TAPs ================================ In some systems, a "JTAG Route Controller" (JRC) is used to enable and/or disable specific JTAG TAPs. Many ARM based chips from Texas Instruments include an "ICEpick" module, which is a JRC. Such chips include DaVinci and OMAP3 processors. A given TAP may not be visible until the JRC has been told to link it into the scan chain; and if the JRC has been told to unlink that TAP, it will no longer be visible. Such routers address problems that JTAG "bypass mode" ignores, such as: * The scan chain can only go as fast as its slowest TAP. * Having many TAPs slows instruction scans, since all TAPs receive new instructions. * TAPs in the scan chain must be powered up, which wastes power and prevents debugging some power management mechanisms. The IEEE 1149.1 JTAG standard has no concept of a "disabled" tap, as implied by the existence of JTAG routers. However, the upcoming IEEE 1149.7 framework (layered on top of JTAG) does include a kind of JTAG router functionality. In OpenOCD, tap enabling/disabling is invoked by the Tcl commands shown below, and is implemented using TAP event handlers. So for example, when defining a TAP for a CPU connected to a JTAG router, your 'target.cfg' file should define TAP event handlers using code that looks something like this: jtag configure CHIP.cpu -event tap-enable { ... jtag operations using CHIP.jrc } jtag configure CHIP.cpu -event tap-disable { ... jtag operations using CHIP.jrc } Then you might want that CPU's TAP enabled almost all the time: jtag configure $CHIP.jrc -event setup "jtag tapenable $CHIP.cpu" Note how that particular setup event handler declaration uses quotes to evaluate '$CHIP' when the event is configured. Using brackets { } would cause it to be evaluated later, at runtime, when it might have a different value. -- Command: jtag tapdisable dotted.name If necessary, disables the tap by sending it a 'tap-disable' event. Returns the string "1" if the tap specified by DOTTED.NAME is enabled, and "0" if it is disabled. -- Command: jtag tapenable dotted.name If necessary, enables the tap by sending it a 'tap-enable' event. Returns the string "1" if the tap specified by DOTTED.NAME is enabled, and "0" if it is disabled. -- Command: jtag tapisenabled dotted.name Returns the string "1" if the tap specified by DOTTED.NAME is enabled, and "0" if it is disabled. Note: Humans will find the 'scan_chain' command more helpful for querying the state of the JTAG taps. 10.7 Autoprobing ================ TAP configuration is the first thing that needs to be done after interface and reset configuration. Sometimes it's hard finding out what TAPs exist, or how they are identified. Vendor documentation is not always easy to find and use. To help you get past such problems, OpenOCD has a limited _autoprobing_ ability to look at the scan chain, doing a "blind interrogation" and then reporting the TAPs it finds. To use this mechanism, start the OpenOCD server with only data that configures your JTAG interface, and arranges to come up with a slow clock (many devices don't support fast JTAG clocks right when they come out of reset). For example, your 'openocd.cfg' file might have: source [find interface/olimex-arm-usb-tiny-h.cfg] reset_config trst_and_srst jtag_rclk 8 When you start the server without any TAPs configured, it will attempt to autoconfigure the TAPs. There are two parts to this: 1. _TAP discovery_ ... After a JTAG reset (sometimes a system reset may be needed too), each TAP's data registers will hold the contents of either the IDCODE or BYPASS register. If JTAG communication is working, OpenOCD will see each TAP, and report what '-expected-id' to use with it. 2. _IR Length discovery_ ... Unfortunately JTAG does not provide a reliable way to find out the value of the '-irlen' parameter to use with a TAP that is discovered. If OpenOCD can discover the length of a TAP's instruction register, it will report it. Otherwise you may need to consult vendor documentation, such as chip data sheets or BSDL files. In many cases your board will have a simple scan chain with just a single device. Here's what OpenOCD reported with one board that's a bit more complex: clock speed 8 kHz There are no enabled taps. AUTO PROBING MIGHT NOT WORK!! AUTO auto0.tap - use "jtag newtap auto0 tap -expected-id 0x2b900f0f ..." AUTO auto1.tap - use "jtag newtap auto1 tap -expected-id 0x07926001 ..." AUTO auto2.tap - use "jtag newtap auto2 tap -expected-id 0x0b73b02f ..." AUTO auto0.tap - use "... -irlen 4" AUTO auto1.tap - use "... -irlen 4" AUTO auto2.tap - use "... -irlen 6" no gdb ports allocated as no target has been specified Given that information, you should be able to either find some existing config files to use, or create your own. If you create your own, you would configure from the bottom up: first a 'target.cfg' file with these TAPs, any targets associated with them, and any on-chip resources; then a 'board.cfg' with off-chip resources, clocking, and so forth. ---------- Footnotes ---------- (1) See the ST document titled: _STR91xFAxxx, Section 3.15 Jtag Interface, Page: 28/102, Figure 3: JTAG chaining inside the STR91xFA_.  File: openocd.info, Node: CPU Configuration, Next: Flash Commands, Prev: TAP Declaration, Up: Top 11 CPU Configuration ******************** This chapter discusses how to set up GDB debug targets for CPUs. You can also access these targets without GDB (*note Architecture and Core Commands::, and *note Target State handling: targetstatehandling.) and through various kinds of NAND and NOR flash commands. If you have multiple CPUs you can have multiple such targets. We'll start by looking at how to examine the targets you have, then look at how to add one more target and how to configure it. 11.1 Target List ================ All targets that have been set up are part of a list, where each member has a name. That name should normally be the same as the TAP name. You can display the list with the 'targets' (plural!) command. This display often has only one CPU; here's what it might look like with more than one: TargetName Type Endian TapName State -- ------------------ ---------- ------ ------------------ ------------ 0* at91rm9200.cpu arm920t little at91rm9200.cpu running 1 MyTarget cortex_m little mychip.foo tap-disabled One member of that list is the "current target", which is implicitly referenced by many commands. It's the one marked with a '*' near the target name. In particular, memory addresses often refer to the address space seen by that current target. Commands like 'mdw' (memory display words) and 'flash erase_address' (erase NOR flash blocks) are examples; and there are many more. Several commands let you examine the list of targets: -- Command: target count _Note: target numbers are deprecated; don't use them. They will be removed shortly after August 2010, including this command. Iterate target using 'target names', not by counting._ Returns the number of targets, N. The highest numbered target is N - 1. set c [target count] for { set x 0 } { $x < $c } { incr x } { # Assuming you have created this function print_target_details $x } -- Command: target current Returns the name of the current target. -- Command: target names Lists the names of all current targets in the list. foreach t [target names] { puts [format "Target: %s\n" $t] } -- Command: target number number _Note: target numbers are deprecated; don't use them. They will be removed shortly after August 2010, including this command._ The list of targets is numbered starting at zero. This command returns the name of the target at index NUMBER. set thename [target number $x] puts [format "Target %d is: %s\n" $x $thename] -- Command: targets [name] _Note: the name of this command is plural. Other target command names are singular._ With no parameter, this command displays a table of all known targets in a user friendly form. With a parameter, this command sets the current target to the given target with the given NAME; this is only relevant on boards which have more than one target. 11.2 Target CPU Types and Variants ================================== Each target has a "CPU type", as shown in the output of the 'targets' command. You need to specify that type when calling 'target create'. The CPU type indicates more than just the instruction set. It also indicates how that instruction set is implemented, what kind of debug support it integrates, whether it has an MMU (and if so, what kind), what core-specific commands may be available (*note Architecture and Core Commands::), and more. For some CPU types, OpenOCD also defines "variants" which indicate differences that affect their handling. For example, a particular implementation bug might need to be worked around in some chip versions. It's easy to see what target types are supported, since there's a command to list them. However, there is currently no way to list what target variants are supported (other than by reading the OpenOCD source code). -- Command: target types Lists all supported target types. At this writing, the supported CPU types and variants are: * 'arm11' - this is a generation of ARMv6 cores * 'arm720t' - this is an ARMv4 core with an MMU * 'arm7tdmi' - this is an ARMv4 core * 'arm920t' - this is an ARMv4 core with an MMU * 'arm926ejs' - this is an ARMv5 core with an MMU * 'arm966e' - this is an ARMv5 core * 'arm9tdmi' - this is an ARMv4 core * 'avr' - implements Atmel's 8-bit AVR instruction set. (Support for this is preliminary and incomplete.) * 'cortex_a' - this is an ARMv7 core with an MMU * 'cortex_m' - this is an ARMv7 core, supporting only the compact Thumb2 instruction set. * 'dragonite' - resembles arm966e * 'dsp563xx' - implements Freescale's 24-bit DSP. (Support for this is still incomplete.) * 'fa526' - resembles arm920 (w/o Thumb) * 'feroceon' - resembles arm926 * 'mips_m4k' - a MIPS core. This supports one variant: * 'xscale' - this is actually an architecture, not a CPU type. It is based on the ARMv5 architecture. There are several variants defined: - 'ixp42x', 'ixp45x', 'ixp46x', 'pxa27x' ... instruction register length is 7 bits - 'pxa250', 'pxa255', 'pxa26x' ... instruction register length is 5 bits - 'pxa3xx' ... instruction register length is 11 bits To avoid being confused by the variety of ARM based cores, remember this key point: _ARM is a technology licencing company_. (See: .) The CPU name used by OpenOCD will reflect the CPU design that was licenced, not a vendor brand which incorporates that design. Name prefixes like arm7, arm9, arm11, and cortex reflect design generations; while names like ARMv4, ARMv5, ARMv6, and ARMv7 reflect an architecture version implemented by a CPU design. 11.3 Target Configuration ========================= Before creating a "target", you must have added its TAP to the scan chain. When you've added that TAP, you will have a 'dotted.name' which is used to set up the CPU support. The chip-specific configuration file will normally configure its CPU(s) right after it adds all of the chip's TAPs to the scan chain. Although you can set up a target in one step, it's often clearer if you use shorter commands and do it in two steps: create it, then configure optional parts. All operations on the target after it's created will use a new command, created as part of target creation. The two main things to configure after target creation are a work area, which usually has target-specific defaults even if the board setup code overrides them later; and event handlers (*note Target Events: targetevents.), which tend to be much more board-specific. The key steps you use might look something like this target create MyTarget cortex_m -chain-position mychip.cpu $MyTarget configure -work-area-phys 0x08000 -work-area-size 8096 $MyTarget configure -event reset-deassert-pre { jtag_rclk 5 } $MyTarget configure -event reset-init { myboard_reinit } You should specify a working area if you can; typically it uses some on-chip SRAM. Such a working area can speed up many things, including bulk writes to target memory; flash operations like checking to see if memory needs to be erased; GDB memory checksumming; and more. Warning: On more complex chips, the work area can become inaccessible when application code (such as an operating system) enables or disables the MMU. For example, the particular MMU context used to acess the virtual address will probably matter ... and that context might not have easy access to other addresses needed. At this writing, OpenOCD doesn't have much MMU intelligence. It's often very useful to define a 'reset-init' event handler. For systems that are normally used with a boot loader, common tasks include updating clocks and initializing memory controllers. That may be needed to let you write the boot loader into flash, in order to "de-brick" your board; or to load programs into external DDR memory without having run the boot loader. -- Command: target create target_name type configparams... This command creates a GDB debug target that refers to a specific JTAG tap. It enters that target into a list, and creates a new command ('TARGET_NAME') which is used for various purposes including additional configuration. * TARGET_NAME ... is the name of the debug target. By convention this should be the same as the _dotted.name_ of the TAP associated with this target, which must be specified here using the '-chain-position DOTTED.NAME' configparam. This name is also used to create the target object command, referred to here as '$target_name', and in other places the target needs to be identified. * TYPE ... specifies the target type. *Note target types: targettypes. * CONFIGPARAMS ... all parameters accepted by '$target_name configure' are permitted. If the target is big-endian, set it here with '-endian big'. If the variant matters, set it here with '-variant'. You _must_ set the '-chain-position DOTTED.NAME' here. -- Command: $target_name configure configparams... The options accepted by this command may also be specified as parameters to 'target create'. Their values can later be queried one at a time by using the '$target_name cget' command. _Warning:_ changing some of these after setup is dangerous. For example, moving a target from one TAP to another; and changing its endianness or variant. * '-chain-position' DOTTED.NAME - names the TAP used to access this target. * '-endian' ('big'|'little') - specifies whether the CPU uses big or little endian conventions * '-event' EVENT_NAME EVENT_BODY - *Note Target Events: targetevents. Note that this updates a list of named event handlers. Calling this twice with two different event names assigns two different handlers, but calling it twice with the same event name assigns only one handler. * '-variant' NAME - specifies a variant of the target, which OpenOCD needs to know about. * '-work-area-backup' ('0'|'1') - says whether the work area gets backed up; by default, _it is not backed up._ When possible, use a working_area that doesn't need to be backed up, since performing a backup slows down operations. For example, the beginning of an SRAM block is likely to be used by most build systems, but the end is often unused. * '-work-area-size' SIZE - specify work are size, in bytes. The same size applies regardless of whether its physical or virtual address is being used. * '-work-area-phys' ADDRESS - set the work area base ADDRESS to be used when no MMU is active. * '-work-area-virt' ADDRESS - set the work area base ADDRESS to be used when an MMU is active. _Do not specify a value for this except on targets with an MMU._ The value should normally correspond to a static mapping for the '-work-area-phys' address, set up by the current operating system. * '-rtos' RTOS_TYPE - enable rtos support for target, RTOS_TYPE can be one of 'auto'|'eCos'|'ThreadX'| 'FreeRTOS'|'linux'|'ChibiOS'. 11.4 Other $target_name Commands ================================ The Tcl/Tk language has the concept of object commands, and OpenOCD adopts that same model for targets. A good Tk example is a on screen button. Once a button is created a button has a name (a path in Tk terms) and that name is useable as a first class command. For example in Tk, one can create a button and later configure it like this: # Create button .foobar -background red -command { foo } # Modify .foobar configure -foreground blue # Query set x [.foobar cget -background] # Report puts [format "The button is %s" $x] In OpenOCD's terms, the "target" is an object just like a Tcl/Tk button, and its object commands are invoked the same way. str912.cpu mww 0x1234 0x42 omap3530.cpu mww 0x5555 123 The commands supported by OpenOCD target objects are: -- Command: $target_name arp_examine -- Command: $target_name arp_halt -- Command: $target_name arp_poll -- Command: $target_name arp_reset -- Command: $target_name arp_waitstate Internal OpenOCD scripts (most notably 'startup.tcl') use these to deal with specific reset cases. They are not otherwise documented here. -- Command: $target_name array2mem arrayname width address count -- Command: $target_name mem2array arrayname width address count These provide an efficient script-oriented interface to memory. The 'array2mem' primitive writes bytes, halfwords, or words; while 'mem2array' reads them. In both cases, the TCL side uses an array, and the target side uses raw memory. The efficiency comes from enabling the use of bulk JTAG data transfer operations. The script orientation comes from working with data values that are packaged for use by TCL scripts; 'mdw' type primitives only print data they retrieve, and neither store nor return those values. * ARRAYNAME ... is the name of an array variable * WIDTH ... is 8/16/32 - indicating the memory access size * ADDRESS ... is the target memory address * COUNT ... is the number of elements to process -- Command: $target_name cget queryparm Each configuration parameter accepted by '$target_name configure' can be individually queried, to return its current value. The QUERYPARM is a parameter name accepted by that command, such as '-work-area-phys'. There are a few special cases: * '-event' EVENT_NAME - returns the handler for the event named EVENT_NAME. This is a special case because setting a handler requires two parameters. * '-type' - returns the target type. This is a special case because this is set using 'target create' and can't be changed using '$target_name configure'. For example, if you wanted to summarize information about all the targets you might use something like this: foreach name [target names] { set y [$name cget -endian] set z [$name cget -type] puts [format "Chip %d is %s, Endian: %s, type: %s" \ $x $name $y $z] } -- Command: $target_name curstate Displays the current target state: 'debug-running', 'halted', 'reset', 'running', or 'unknown'. (Also, *note Event Polling: eventpolling.) -- Command: $target_name eventlist Displays a table listing all event handlers currently associated with this target. *Note Target Events: targetevents. -- Command: $target_name invoke-event event_name Invokes the handler for the event named EVENT_NAME. (This is primarily intended for use by OpenOCD framework code, for example by the reset code in 'startup.tcl'.) -- Command: $target_name mdw addr [count] -- Command: $target_name mdh addr [count] -- Command: $target_name mdb addr [count] Display contents of address ADDR, as 32-bit words ('mdw'), 16-bit halfwords ('mdh'), or 8-bit bytes ('mdb'). If COUNT is specified, displays that many units. (If you want to manipulate the data instead of displaying it, see the 'mem2array' primitives.) -- Command: $target_name mww addr word -- Command: $target_name mwh addr halfword -- Command: $target_name mwb addr byte Writes the specified WORD (32 bits), HALFWORD (16 bits), or BYTE (8-bit) pattern, at the specified address ADDR. 11.5 Target Events ================== At various times, certain things can happen, or you want them to happen. For example: * What should happen when GDB connects? Should your target reset? * When GDB tries to flash the target, do you need to enable the flash via a special command? * Is using SRST appropriate (and possible) on your system? Or instead of that, do you need to issue JTAG commands to trigger reset? SRST usually resets everything on the scan chain, which can be inappropriate. * During reset, do you need to write to certain memory locations to set up system clocks or to reconfigure the SDRAM? How about configuring the watchdog timer, or other peripherals, to stop running while you hold the core stopped for debugging? All of the above items can be addressed by target event handlers. These are set up by '$target_name configure -event' or 'target create ... -event'. The programmer's model matches the '-command' option used in Tcl/Tk buttons and events. The two examples below act the same, but one creates and invokes a small procedure while the other inlines it. proc my_attach_proc { } { echo "Reset..." reset halt } mychip.cpu configure -event gdb-attach my_attach_proc mychip.cpu configure -event gdb-attach { echo "Reset..." # To make flash probe and gdb load to flash work we need a reset init. reset init } The following target events are defined: * debug-halted The target has halted for debug reasons (i.e.: breakpoint) * debug-resumed The target has resumed (i.e.: gdb said run) * early-halted Occurs early in the halt process * examine-start Before target examine is called. * examine-end After target examine is called with no errors. * gdb-attach When GDB connects. This is before any communication with the target, so this can be used to set up the target so it is possible to probe flash. Probing flash is necessary during gdb connect if gdb load is to write the image to flash. Another use of the flash memory map is for GDB to automatically hardware/software breakpoints depending on whether the breakpoint is in RAM or read only memory. * gdb-detach When GDB disconnects * gdb-end When the target has halted and GDB is not doing anything (see early halt) * gdb-flash-erase-start Before the GDB flash process tries to erase the flash * gdb-flash-erase-end After the GDB flash process has finished erasing the flash * gdb-flash-write-start Before GDB writes to the flash * gdb-flash-write-end After GDB writes to the flash * gdb-start Before the target steps, gdb is trying to start/resume the target * halted The target has halted * reset-assert-pre Issued as part of 'reset' processing after 'reset_init' was triggered but before either SRST alone is re-asserted on the scan chain, or 'reset-assert' is triggered. * reset-assert Issued as part of 'reset' processing after 'reset-assert-pre' was triggered. When such a handler is present, cores which support this event will use it instead of asserting SRST. This support is essential for debugging with JTAG interfaces which don't include an SRST line (JTAG doesn't require SRST), and for selective reset on scan chains that have multiple targets. * reset-assert-post Issued as part of 'reset' processing after 'reset-assert' has been triggered. or the target asserted SRST on the entire scan chain. * reset-deassert-pre Issued as part of 'reset' processing after 'reset-assert-post' has been triggered. * reset-deassert-post Issued as part of 'reset' processing after 'reset-deassert-pre' has been triggered and (if the target is using it) after SRST has been released on the scan chain. * reset-end Issued as the final step in 'reset' processing. * reset-init Used by reset init command for board-specific initialization. This event fires after _reset-deassert-post_. This is where you would configure PLLs and clocking, set up DRAM so you can download programs that don't fit in on-chip SRAM, set up pin multiplexing, and so on. (You may be able to switch to a fast JTAG clock rate here, after the target clocks are fully set up.) * reset-start Issued as part of 'reset' processing before 'reset_init' is called. This is the most robust place to use 'jtag_rclk' or 'adapter_khz' to switch to a low JTAG clock rate, when reset disables PLLs needed to use a fast clock. * resume-start Before any target is resumed * resume-end After all targets have resumed * resumed Target has resumed  File: openocd.info, Node: Flash Commands, Next: Flash Programming, Prev: CPU Configuration, Up: Top 12 Flash Commands ***************** OpenOCD has different commands for NOR and NAND flash; the "flash" command works with NOR flash, while the "nand" command works with NAND flash. This partially reflects different hardware technologies: NOR flash usually supports direct CPU instruction and data bus access, while data from a NAND flash must be copied to memory before it can be used. (SPI flash must also be copied to memory before use.) However, the documentation also uses "flash" as a generic term; for example, "Put flash configuration in board-specific files". Flash Steps: 1. Configure via the command 'flash bank' Do this in a board-specific configuration file, passing parameters as needed by the driver. 2. Operate on the flash via 'flash subcommand' Often commands to manipulate the flash are typed by a human, or run via a script in some automated way. Common tasks include writing a boot loader, operating system, or other data. 3. GDB Flashing Flashing via GDB requires the flash be configured via "flash bank", and the GDB flash features be enabled. *Note GDB Configuration: gdbconfiguration. Many CPUs have the ablity to "boot" from the first flash bank. This means that misprogramming that bank can "brick" a system, so that it can't boot. JTAG tools, like OpenOCD, are often then used to "de-brick" the board by (re)installing working boot firmware. 12.1 Flash Configuration Commands ================================= -- Config Command: flash bank name driver base size chip_width bus_width target [driver_options] Configures a flash bank which provides persistent storage for addresses from base to base + size - 1. These banks will often be visible to GDB through the target's memory map. In some cases, configuring a flash bank will activate extra commands; see the driver-specific documentation. * NAME ... may be used to reference the flash bank in other flash commands. A number is also available. * DRIVER ... identifies the controller driver associated with the flash bank being declared. This is usually 'cfi' for external flash, or else the name of a microcontroller with embedded flash memory. *Note Flash Driver List: flashdriverlist. * BASE ... Base address of the flash chip. * SIZE ... Size of the chip, in bytes. For some drivers, this value is detected from the hardware. * CHIP_WIDTH ... Width of the flash chip, in bytes; ignored for most microcontroller drivers. * BUS_WIDTH ... Width of the data bus used to access the chip, in bytes; ignored for most microcontroller drivers. * TARGET ... Names the target used to issue commands to the flash controller. * DRIVER_OPTIONS ... drivers may support, or require, additional parameters. See the driver-specific documentation for more information. Note: This command is not available after OpenOCD initialization has completed. Use it in board specific configuration files, not interactively. -- Command: flash banks Prints a one-line summary of each device that was declared using 'flash bank', numbered from zero. Note that this is the _plural_ form; the _singular_ form is a very different command. -- Command: flash list Retrieves a list of associative arrays for each device that was declared using 'flash bank', numbered from zero. This returned list can be manipulated easily from within scripts. -- Command: flash probe num Identify the flash, or validate the parameters of the configured flash. Operation depends on the flash type. The NUM parameter is a value shown by 'flash banks'. Most flash commands will implicitly _autoprobe_ the bank; flash drivers can distinguish between probing and autoprobing, but most don't bother. 12.2 Erasing, Reading, Writing to Flash ======================================= One feature distinguishing NOR flash from NAND or serial flash technologies is that for read access, it acts exactly like any other addressible memory. This means you can use normal memory read commands like 'mdw' or 'dump_image' with it, with no special 'flash' subcommands. *Note Memory access: memoryaccess, and *note Image access: imageaccess. Write access works differently. Flash memory normally needs to be erased before it's written. Erasing a sector turns all of its bits to ones, and writing can turn ones into zeroes. This is why there are special commands for interactive erasing and writing, and why GDB needs to know which parts of the address space hold NOR flash memory. Note: Most of these erase and write commands leverage the fact that NOR flash chips consume target address space. They implicitly refer to the current JTAG target, and map from an address in that target's address space back to a flash bank. A few commands use abstract addressing based on bank and sector numbers, and don't depend on searching the current target and its address space. Avoid confusing the two command models. Some flash chips implement software protection against accidental writes, since such buggy writes could in some cases "brick" a system. For such systems, erasing and writing may require sector protection to be disabled first. Examples include CFI flash such as "Intel Advanced Bootblock flash", and AT91SAM7 on-chip flash. *Note flash protect: flashprotect. -- Command: flash erase_sector num first last Erase sectors in bank NUM, starting at sector FIRST up to and including LAST. Sector numbering starts at 0. Providing a LAST sector of 'last' specifies "to the end of the flash bank". The NUM parameter is a value shown by 'flash banks'. -- Command: flash erase_address ['pad'] ['unlock'] address length Erase sectors starting at ADDRESS for LENGTH bytes. Unless 'pad' is specified, address must begin a flash sector, and address + length - 1 must end a sector. Specifying 'pad' erases extra data at the beginning and/or end of the specified region, as needed to erase only full sectors. The flash bank to use is inferred from the ADDRESS, and the specified length must stay within that bank. As a special case, when LENGTH is zero and ADDRESS is the start of the bank, the whole flash is erased. If 'unlock' is specified, then the flash is unprotected before erase starts. -- Command: flash fillw address word length -- Command: flash fillh address halfword length -- Command: flash fillb address byte length Fills flash memory with the specified WORD (32 bits), HALFWORD (16 bits), or BYTE (8-bit) pattern, starting at ADDRESS and continuing for LENGTH units (word/halfword/byte). No erasure is done before writing; when needed, that must be done before issuing this command. Writes are done in blocks of up to 1024 bytes, and each write is verified by reading back the data and comparing it to what was written. The flash bank to use is inferred from the ADDRESS of each block, and the specified length must stay within that bank. -- Command: flash write_bank num filename offset Write the binary 'filename' to flash bank NUM, starting at OFFSET bytes from the beginning of the bank. The NUM parameter is a value shown by 'flash banks'. -- Command: flash write_image [erase] [unlock] filename [offset] [type] Write the image 'filename' to the current target's flash bank(s). A relocation OFFSET may be specified, in which case it is added to the base address for each section in the image. The file [TYPE] can be specified explicitly as 'bin' (binary), 'ihex' (Intel hex), 'elf' (ELF file), 's19' (Motorola s19). 'mem', or 'builder'. The relevant flash sectors will be erased prior to programming if the 'erase' parameter is given. If 'unlock' is provided, then the flash banks are unlocked before erase and program. The flash bank to use is inferred from the address of each image section. Warning: Be careful using the 'erase' flag when the flash is holding data you want to preserve. Portions of the flash outside those described in the image's sections might be erased with no notice. * When a section of the image being written does not fill out all the sectors it uses, the unwritten parts of those sectors are necessarily also erased, because sectors can't be partially erased. * Data stored in sector "holes" between image sections are also affected. For example, "'flash write_image erase ...'" of an image with one byte at the beginning of a flash bank and one byte at the end erases the entire bank - not just the two sectors being written. Also, when flash protection is important, you must re-apply it after it has been removed by the 'unlock' flag. 12.3 Other Flash commands ========================= -- Command: flash erase_check num Check erase state of sectors in flash bank NUM, and display that status. The NUM parameter is a value shown by 'flash banks'. -- Command: flash info num Print info about flash bank NUM The NUM parameter is a value shown by 'flash banks'. This command will first query the hardware, it does not print cached and possibly stale information. -- Command: flash protect num first last ('on'|'off') Enable ('on') or disable ('off') protection of flash sectors in flash bank NUM, starting at sector FIRST and continuing up to and including LAST. Providing a LAST sector of 'last' specifies "to the end of the flash bank". The NUM parameter is a value shown by 'flash banks'. -- Command: program filename [verify] [reset] [offset] This is a helper script that simplifies using OpenOCD as a standalone programmer. The only required parameter is 'filename', the others are optional. *Note Flash Programming::. 12.4 Flash Driver List ====================== As noted above, the 'flash bank' command requires a driver name, and allows driver-specific options and behaviors. Some drivers also activate driver-specific commands. 12.4.1 External Flash --------------------- -- Flash Driver: cfi The "Common Flash Interface" (CFI) is the main standard for external NOR flash chips, each of which connects to a specific external chip select on the CPU. Frequently the first such chip is used to boot the system. Your board's 'reset-init' handler might need to configure additional chip selects using other commands (like: 'mww' to configure a bus and its timings), or perhaps configure a GPIO pin that controls the "write protect" pin on the flash chip. The CFI driver can use a target-specific working area to significantly speed up operation. The CFI driver can accept the following optional parameters, in any order: * JEDEC_PROBE ... is used to detect certain non-CFI flash ROMs, like AM29LV010 and similar types. * X16_AS_X8 ... when a 16-bit flash is hooked up to an 8-bit bus. To configure two adjacent banks of 16 MBytes each, both sixteen bits (two bytes) wide on a sixteen bit bus: flash bank $_FLASHNAME cfi 0x00000000 0x01000000 2 2 $_TARGETNAME flash bank $_FLASHNAME cfi 0x01000000 0x01000000 2 2 $_TARGETNAME To configure one bank of 32 MBytes built from two sixteen bit (two byte) wide parts wired in parallel to create a thirty-two bit (four byte) bus with doubled throughput: flash bank $_FLASHNAME cfi 0x00000000 0x02000000 2 4 $_TARGETNAME -- Flash Driver: lpcspifi NXP's LPC43xx and LPC18xx families include a proprietary SPI Flash Interface (SPIFI) peripheral that can drive and provide memory mapped access to external SPI flash devices. The lpcspifi driver initializes this interface and provides program and erase functionality for these serial flash devices. Use of this driver requires a working area of at least 1kB to be configured on the target device; more than this will significantly reduce flash programming times. The setup command only requires the BASE parameter. All other parameters are ignored, and the flash size and layout are configured by the driver. flash bank $_FLASHNAME lpcspifi 0x14000000 0 0 0 $_TARGETNAME -- Flash Driver: stmsmi Some devices form STMicroelectronics (e.g. STR75x MCU family, SPEAr MPU family) include a proprietary "Serial Memory Interface" (SMI) controller able to drive external SPI flash devices. Depending on specific device and board configuration, up to 4 external flash devices can be connected. SMI makes the flash content directly accessible in the CPU address space; each external device is mapped in a memory bank. CPU can directly read data, execute code and boot from SMI banks. Normal OpenOCD commands like 'mdw' can be used to display the flash content. The setup command only requires the BASE parameter in order to identify the memory bank. All other parameters are ignored. Additional information, like flash size, are detected automatically. flash bank $_FLASHNAME stmsmi 0xf8000000 0 0 0 $_TARGETNAME 12.4.2 Internal Flash (Microcontrollers) ---------------------------------------- -- Flash Driver: aduc702x The ADUC702x analog microcontrollers from Analog Devices include internal flash and use ARM7TDMI cores. The aduc702x flash driver works with models ADUC7019 through ADUC7028. The setup command only requires the TARGET argument since all devices in this family have the same memory layout. flash bank $_FLASHNAME aduc702x 0 0 0 0 $_TARGETNAME -- Flash Driver: at91sam3 All members of the AT91SAM3 microcontroller family from Atmel include internal flash and use ARM's Cortex-M3 core. The driver currently (6/22/09) recognizes the AT91SAM3U[1/2/4][C/E] chips. Note that the driver was orginaly developed and tested using the AT91SAM3U4E, using a SAM3U-EK eval board. Support for other chips in the family was cribbed from the data sheet. _Note to future readers/updaters: Please remove this worrysome comment after other chips are confirmed._ The AT91SAM3U4[E/C] (256K) chips have two flash banks; most other chips have one flash bank. In all cases the flash banks are at the following fixed locations: # Flash bank 0 - all chips flash bank $_FLASHNAME at91sam3 0x00080000 0 1 1 $_TARGETNAME # Flash bank 1 - only 256K chips flash bank $_FLASHNAME at91sam3 0x00100000 0 1 1 $_TARGETNAME Internally, the AT91SAM3 flash memory is organized as follows. Unlike the AT91SAM7 chips, these are not used as parameters to the 'flash bank' command: * _N-Banks:_ 256K chips have 2 banks, others have 1 bank. * _Bank Size:_ 128K/64K Per flash bank * _Sectors:_ 16 or 8 per bank * _SectorSize:_ 8K Per Sector * _PageSize:_ 256 bytes per page. Note that OpenOCD operates on 'sector' sizes, not page sizes. The AT91SAM3 driver adds some additional commands: -- Command: at91sam3 gpnvm -- Command: at91sam3 gpnvm clear number -- Command: at91sam3 gpnvm set number -- Command: at91sam3 gpnvm show ['all'|number] With no parameters, 'show' or 'show all', shows the status of all GPNVM bits. With 'show' NUMBER, displays that bit. With 'set' NUMBER or 'clear' NUMBER, modifies that GPNVM bit. -- Command: at91sam3 info This command attempts to display information about the AT91SAM3 chip. _First_ it read the 'CHIPID_CIDR' [address 0x400e0740, see Section 28.2.1, page 505 of the AT91SAM3U 29/may/2009 datasheet, document id: doc6430A] and decodes the values. _Second_ it reads the various clock configuration registers and attempts to display how it believes the chip is configured. By default, the SLOWCLK is assumed to be 32768 Hz, see the command 'at91sam3 slowclk'. -- Command: at91sam3 slowclk [value] This command shows/sets the slow clock frequency used in the 'at91sam3 info' command calculations above. -- Flash Driver: at91sam4 All members of the AT91SAM4 microcontroller family from Atmel include internal flash and use ARM's Cortex-M4 core. This driver uses the same cmd names/syntax as *Note at91sam3::. -- Flash Driver: at91sam7 All members of the AT91SAM7 microcontroller family from Atmel include internal flash and use ARM7TDMI cores. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. flash bank $_FLASHNAME at91sam7 0 0 0 0 $_TARGETNAME For chips which are not recognized by the controller driver, you must provide additional parameters in the following order: * CHIP_MODEL ... label used with 'flash info' * BANKS * SECTORS_PER_BANK * PAGES_PER_SECTOR * PAGES_SIZE * NUM_NVM_BITS * FREQ_KHZ ... required if an external clock is provided, optional (but recommended) when the oscillator frequency is known It is recommended that you provide zeroes for all of those values except the clock frequency, so that everything except that frequency will be autoconfigured. Knowing the frequency helps ensure correct timings for flash access. The flash controller handles erases automatically on a page (128/256 byte) basis, so explicit erase commands are not necessary for flash programming. However, there is an "EraseAll" command that can erase an entire flash plane (of up to 256KB), and it will be used automatically when you issue 'flash erase_sector' or 'flash erase_address' commands. -- Command: at91sam7 gpnvm bitnum ('set'|'clear') Set or clear a "General Purpose Non-Volatile Memory" (GPNVM) bit for the processor. Each processor has a number of such bits, used for controlling features such as brownout detection (so they are not truly general purpose). Note: This assumes that the first flash bank (number 0) is associated with the appropriate at91sam7 target. -- Flash Driver: avr The AVR 8-bit microcontrollers from Atmel integrate flash memory. _The current implementation is incomplete._ -- Flash Driver: efm32 All members of the EFM32 microcontroller family from Energy Micro include internal flash and use ARM Cortex M3 cores. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. flash bank $_FLASHNAME efm32 0 0 0 0 $_TARGETNAME _The current implementation is incomplete. Unprotecting flash pages is not supported._ -- Flash Driver: lpc2000 Most members of the LPC1700, LPC1800, LPC2000 and LPC4300 microcontroller families from NXP include internal flash and use Cortex-M3 (LPC1700, LPC1800), Cortex-M4 (LPC4300) or ARM7TDMI (LPC2000) cores. Note: There are LPC2000 devices which are not supported by the LPC2000 driver: The LPC2888 is supported by the LPC288X driver. The LPC29xx family is supported by the LPC2900 driver. The LPC2000 driver defines two mandatory and one optional parameters, which must appear in the following order: * VARIANT ... required, may be 'lpc2000_v1' (older LPC21xx and LPC22xx) 'lpc2000_v2' (LPC213x, LPC214x, LPC210[123], LPC23xx and LPC24xx) 'lpc1700' (LPC175x and LPC176x) or 'lpc4300' - available also as 'lpc1800' alias (LPC18x[2357] and LPC43x[2357]) * CLOCK_KHZ ... the frequency, in kiloHertz, at which the core is running * 'calc_checksum' ... optional (but you probably want to provide this!), telling the driver to calculate a valid checksum for the exception vector table. Note: If you don't provide 'calc_checksum' when you're writing the vector table, the boot ROM will almost certainly ignore your flash image. However, if you do provide it, with most tool chains 'verify_image' will fail. LPC flashes don't require the chip and bus width to be specified. flash bank $_FLASHNAME lpc2000 0x0 0x7d000 0 0 $_TARGETNAME \ lpc2000_v2 14765 calc_checksum -- Command: lpc2000 part_id bank Displays the four byte part identifier associated with the specified flash BANK. -- Flash Driver: lpc288x The LPC2888 microcontroller from NXP needs slightly different flash support from its lpc2000 siblings. The LPC288X driver defines one mandatory parameter, the programming clock rate in Hz. LPC flashes don't require the chip and bus width to be specified. flash bank $_FLASHNAME lpc288x 0 0 0 0 $_TARGETNAME 12000000 -- Flash Driver: lpc2900 This driver supports the LPC29xx ARM968E based microcontroller family from NXP. The predefined parameters BASE, SIZE, CHIP_WIDTH and BUS_WIDTH of the 'flash bank' command are ignored. Flash size and sector layout are auto-configured by the driver. The driver has one additional mandatory parameter: The CPU clock rate (in kHz) at the time the flash operations will take place. Most of the time this will not be the crystal frequency, but a higher PLL frequency. The 'reset-init' event handler in the board script is usually the place where you start the PLL. The driver rejects flashless devices (currently the LPC2930). The EEPROM in LPC2900 devices is not mapped directly into the address space. It must be handled much more like NAND flash memory, and will therefore be handled by a separate 'lpc2900_eeprom' driver (not yet available). Sector protection in terms of the LPC2900 is handled transparently. Every time a sector needs to be erased or programmed, it is automatically unprotected. What is shown as protection status in the 'flash info' command, is actually the LPC2900 _sector security_. This is a mechanism to prevent a sector from ever being erased or programmed again. As this is an irreversible mechanism, it is handled by a special command ('lpc2900 secure_sector'), and not by the standard 'flash protect' command. Example for a 125 MHz clock frequency: flash bank $_FLASHNAME lpc2900 0 0 0 0 $_TARGETNAME 125000 Some 'lpc2900'-specific commands are defined. In the following command list, the BANK parameter is the bank number as obtained by the 'flash banks' command. -- Command: lpc2900 signature bank Calculates a 128-bit hash value, the _signature_, from the whole flash content. This is a hardware feature of the flash block, hence the calculation is very fast. You may use this to verify the content of a programmed device against a known signature. Example: lpc2900 signature 0 signature: 0x5f40cdc8:0xc64e592e:0x10490f89:0x32a0f317 -- Command: lpc2900 read_custom bank filename Reads the 912 bytes of customer information from the flash index sector, and saves it to a file in binary format. Example: lpc2900 read_custom 0 /path_to/customer_info.bin The index sector of the flash is a _write-only_ sector. It cannot be erased! In order to guard against unintentional write access, all following commands need to be preceeded by a successful call to the 'password' command: -- Command: lpc2900 password bank password You need to use this command right before each of the following commands: 'lpc2900 write_custom', 'lpc2900 secure_sector', 'lpc2900 secure_jtag'. The password string is fixed to "I_know_what_I_am_doing". Example: lpc2900 password 0 I_know_what_I_am_doing Potentially dangerous operation allowed in next command! -- Command: lpc2900 write_custom bank filename type Writes the content of the file into the customer info space of the flash index sector. The filetype can be specified with the TYPE field. Possible values for TYPE are: BIN (binary), IHEX (Intel hex format), ELF (ELF binary) or S19 (Motorola S-records). The file must contain a single section, and the contained data length must be exactly 912 bytes. Attention: This cannot be reverted! Be careful! Example: lpc2900 write_custom 0 /path_to/customer_info.bin bin -- Command: lpc2900 secure_sector bank first last Secures the sector range from FIRST to LAST (including) against further program and erase operations. The sector security will be effective after the next power cycle. Attention: This cannot be reverted! Be careful! Secured sectors appear as _protected_ in the 'flash info' command. Example: lpc2900 secure_sector 0 1 1 flash info 0 #0 : lpc2900 at 0x20000000, size 0x000c0000, (...) # 0: 0x00000000 (0x2000 8kB) not protected # 1: 0x00002000 (0x2000 8kB) protected # 2: 0x00004000 (0x2000 8kB) not protected -- Command: lpc2900 secure_jtag bank Irreversibly disable the JTAG port. The new JTAG security setting will be effective after the next power cycle. Attention: This cannot be reverted! Be careful! Examples: lpc2900 secure_jtag 0 -- Flash Driver: ocl _No idea what this is, other than using some arm7/arm9 core._ flash bank $_FLASHNAME ocl 0 0 0 0 $_TARGETNAME -- Flash Driver: pic32mx The PIC32MX microcontrollers are based on the MIPS 4K cores, and integrate flash memory. flash bank $_FLASHNAME pix32mx 0x1fc00000 0 0 0 $_TARGETNAME flash bank $_FLASHNAME pix32mx 0x1d000000 0 0 0 $_TARGETNAME Some pic32mx-specific commands are defined: -- Command: pic32mx pgm_word address value bank Programs the specified 32-bit VALUE at the given ADDRESS in the specified chip BANK. -- Command: pic32mx unlock bank Unlock and erase specified chip BANK. This will remove any Code Protection. -- Flash Driver: stellaris All members of the Stellaris LM3Sxxx microcontroller family from Texas Instruments include internal flash and use ARM Cortex M3 cores. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. (1) flash bank $_FLASHNAME stellaris 0 0 0 0 $_TARGETNAME -- Command: stellaris recover bank_id Performs the _Recovering a "Locked" Device_ procedure to restore the flash specified by BANK_ID and its associated nonvolatile registers to their factory default values (erased). This is the only way to remove flash protection or re-enable debugging if that capability has been disabled. Note that the final "power cycle the chip" step in this procedure must be performed by hand, since OpenOCD can't do it. Warning: if more than one Stellaris chip is connected, the procedure is applied to all of them. -- Flash Driver: stm32f1x All members of the STM32F0, STM32F1 and STM32F3 microcontroller families from ST Microelectronics include internal flash and use ARM Cortex-M0/M3/M4 cores. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. flash bank $_FLASHNAME stm32f1x 0 0 0 0 $_TARGETNAME Note that some devices have been found that have a flash size register that contains an invalid value, to workaround this issue you can override the probed value used by the flash driver. flash bank $_FLASHNAME stm32f1x 0 0x20000 0 0 $_TARGETNAME If you have a target with dual flash banks then define the second bank as per the following example. flash bank $_FLASHNAME stm32f1x 0x08080000 0 0 0 $_TARGETNAME Some stm32f1x-specific commands (2) are defined: -- Command: stm32f1x lock num Locks the entire stm32 device. The NUM parameter is a value shown by 'flash banks'. -- Command: stm32f1x unlock num Unlocks the entire stm32 device. The NUM parameter is a value shown by 'flash banks'. -- Command: stm32f1x options_read num Read and display the stm32 option bytes written by the 'stm32f1x options_write' command. The NUM parameter is a value shown by 'flash banks'. -- Command: stm32f1x options_write num ('SWWDG'|'HWWDG') ('RSTSTNDBY'|'NORSTSTNDBY') ('RSTSTOP'|'NORSTSTOP') Writes the stm32 option byte with the specified values. The NUM parameter is a value shown by 'flash banks'. -- Flash Driver: stm32f2x All members of the STM32F2 and STM32F4 microcontroller families from ST Microelectronics include internal flash and use ARM Cortex-M3/M4 cores. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. Note that some devices have been found that have a flash size register that contains an invalid value, to workaround this issue you can override the probed value used by the flash driver. flash bank $_FLASHNAME stm32f2x 0 0x20000 0 0 $_TARGETNAME Some stm32f2x-specific commands are defined: -- Command: stm32f2x lock num Locks the entire stm32 device. The NUM parameter is a value shown by 'flash banks'. -- Command: stm32f2x unlock num Unlocks the entire stm32 device. The NUM parameter is a value shown by 'flash banks'. -- Flash Driver: stm32lx All members of the STM32L microcontroller families from ST Microelectronics include internal flash and use ARM Cortex-M3 cores. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. Note that some devices have been found that have a flash size register that contains an invalid value, to workaround this issue you can override the probed value used by the flash driver. flash bank $_FLASHNAME stm32lx 0 0x20000 0 0 $_TARGETNAME -- Flash Driver: str7x All members of the STR7 microcontroller family from ST Microelectronics include internal flash and use ARM7TDMI cores. The STR7X driver defines one mandatory parameter, VARIANT, which is either 'STR71x', 'STR73x' or 'STR75x'. flash bank $_FLASHNAME str7x 0x40000000 0x00040000 0 0 $_TARGETNAME STR71x -- Command: str7x disable_jtag bank Activate the Debug/Readout protection mechanism for the specified flash bank. -- Flash Driver: str9x Most members of the STR9 microcontroller family from ST Microelectronics include internal flash and use ARM966E cores. The str9 needs the flash controller to be configured using the 'str9x flash_config' command prior to Flash programming. flash bank $_FLASHNAME str9x 0x40000000 0x00040000 0 0 $_TARGETNAME str9x flash_config 0 4 2 0 0x80000 -- Command: str9x flash_config num bbsr nbbsr bbadr nbbadr Configures the str9 flash controller. The NUM parameter is a value shown by 'flash banks'. * BBSR - Boot Bank Size register * NBBSR - Non Boot Bank Size register * BBADR - Boot Bank Start Address register * NBBADR - Boot Bank Start Address register -- Flash Driver: tms470 Most members of the TMS470 microcontroller family from Texas Instruments include internal flash and use ARM7TDMI cores. This driver doesn't require the chip and bus width to be specified. Some tms470-specific commands are defined: -- Command: tms470 flash_keyset key0 key1 key2 key3 Saves programming keys in a register, to enable flash erase and write commands. -- Command: tms470 osc_mhz clock_mhz Reports the clock speed, which is used to calculate timings. -- Command: tms470 plldis (0|1) Disables (1) or enables (0) use of the PLL to speed up the flash clock. -- Flash Driver: virtual This is a special driver that maps a previously defined bank to another address. All bank settings will be copied from the master physical bank. The VIRTUAL driver defines one mandatory parameters, * MASTER_BANK The bank that this virtual address refers to. So in the following example addresses 0xbfc00000 and 0x9fc00000 refer to the flash bank defined at address 0x1fc00000. Any cmds executed on the virtual banks are actually performed on the physical banks. flash bank $_FLASHNAME pic32mx 0x1fc00000 0 0 0 $_TARGETNAME flash bank vbank0 virtual 0xbfc00000 0 0 0 $_TARGETNAME $_FLASHNAME flash bank vbank1 virtual 0x9fc00000 0 0 0 $_TARGETNAME $_FLASHNAME -- Flash Driver: fm3 All members of the FM3 microcontroller family from Fujitsu include internal flash and use ARM Cortex M3 cores. The FM3 driver uses the TARGET parameter to select the correct bank config, it can currently be one of the following: 'mb9bfxx1.cpu', 'mb9bfxx2.cpu', 'mb9bfxx3.cpu', 'mb9bfxx4.cpu', 'mb9bfxx5.cpu' or 'mb9bfxx6.cpu'. flash bank $_FLASHNAME fm3 0 0 0 0 $_TARGETNAME 12.4.3 str9xpec driver ---------------------- Here is some background info to help you better understand how this driver works. OpenOCD has two flash drivers for the str9: 1. Standard driver 'str9x' programmed via the str9 core. Normally used for flash programming as it is faster than the 'str9xpec' driver. 2. Direct programming 'str9xpec' using the flash controller. This is an ISC compilant (IEEE 1532) tap connected in series with the str9 core. The str9 core does not need to be running to program using this flash driver. Typical use for this driver is locking/unlocking the target and programming the option bytes. Before we run any commands using the 'str9xpec' driver we must first disable the str9 core. This example assumes the 'str9xpec' driver has been configured for flash bank 0. # assert srst, we do not want core running # while accessing str9xpec flash driver jtag_reset 0 1 # turn off target polling poll off # disable str9 core str9xpec enable_turbo 0 # read option bytes str9xpec options_read 0 # re-enable str9 core str9xpec disable_turbo 0 poll on reset halt The above example will read the str9 option bytes. When performing a unlock remember that you will not be able to halt the str9 - it has been locked. Halting the core is not required for the 'str9xpec' driver as mentioned above, just issue the commands above manually or from a telnet prompt. -- Flash Driver: str9xpec Only use this driver for locking/unlocking the device or configuring the option bytes. Use the standard str9 driver for programming. Before using the flash commands the turbo mode must be enabled using the 'str9xpec enable_turbo' command. Several str9xpec-specific commands are defined: -- Command: str9xpec disable_turbo num Restore the str9 into JTAG chain. -- Command: str9xpec enable_turbo num Enable turbo mode, will simply remove the str9 from the chain and talk directly to the embedded flash controller. -- Command: str9xpec lock num Lock str9 device. The str9 will only respond to an unlock command that will erase the device. -- Command: str9xpec part_id num Prints the part identifier for bank NUM. -- Command: str9xpec options_cmap num ('bank0'|'bank1') Configure str9 boot bank. -- Command: str9xpec options_lvdsel num ('vdd'|'vdd_vddq') Configure str9 lvd source. -- Command: str9xpec options_lvdthd num ('2.4v'|'2.7v') Configure str9 lvd threshold. -- Command: str9xpec options_lvdwarn bank ('vdd'|'vdd_vddq') Configure str9 lvd reset warning source. -- Command: str9xpec options_read num Read str9 option bytes. -- Command: str9xpec options_write num Write str9 option bytes. -- Command: str9xpec unlock num unlock str9 device. 12.5 mFlash =========== 12.5.1 mFlash Configuration --------------------------- -- Config Command: mflash bank soc base RST_pin target Configures a mflash for SOC host bank at address BASE. The pin number format depends on the host GPIO naming convention. Currently, the mflash driver supports s3c2440 and pxa270. Example for s3c2440 mflash where RST PIN is GPIO B1: mflash bank $_FLASHNAME s3c2440 0x10000000 1b 0 Example for pxa270 mflash where RST PIN is GPIO 43: mflash bank $_FLASHNAME pxa270 0x08000000 43 0 12.5.2 mFlash commands ---------------------- -- Command: mflash config pll frequency Configure mflash PLL. The FREQUENCY is the mflash input frequency, in Hz. Issuing this command will erase mflash's whole internal nand and write new pll. After this command, mflash needs power-on-reset for normal operation. If pll was newly configured, storage and boot(optional) info also need to be update. -- Command: mflash config boot Configure bootable option. If bootable option is set, mflash offer the first 8 sectors (4kB) for boot. -- Command: mflash config storage Configure storage information. For the normal storage operation, this information must be written. -- Command: mflash dump num filename offset size Dump SIZE bytes, starting at OFFSET bytes from the beginning of the bank NUM, to the file named FILENAME. -- Command: mflash probe Probe mflash. -- Command: mflash write num filename offset Write the binary file FILENAME to mflash bank NUM, starting at OFFSET bytes from the beginning of the bank. ---------- Footnotes ---------- (1) Currently there is a 'stellaris mass_erase' command. That seems pointless since the same effect can be had using the standard 'flash erase_address' command. (2) Currently there is a 'stm32f1x mass_erase' command. That seems pointless since the same effect can be had using the standard 'flash erase_address' command.  File: openocd.info, Node: Flash Programming, Next: NAND Flash Commands, Prev: Flash Commands, Up: Top 13 Flash Programming ******************** OpenOCD implements numerous ways to program the target flash, whether internal or external. Programming can be acheived by either using GDB *note Programming using GDB: programmingusinggdb, or using the cmds given in *note Flash Programming Commands: flashprogrammingcommands. To simplify using the flash cmds directly a jimtcl script is available that handles the programming and verify stage. OpenOCD will program/verify/reset the target and shutdown. The script is executed as follows and by default the following actions will be peformed. 1. 'init' is executed. 2. 'reset init' is called to reset and halt the target, any 'reset init' scripts are executed. 3. 'flash write_image' is called to erase and write any flash using the filename given. 4. 'verify_image' is called if 'verify' parameter is given. 5. 'reset run' is called if 'reset' parameter is given. 6. OpenOCD is shutdown. An example of usage is given below. *Note program::. # program and verify using elf/hex/s19. verify and reset # are optional parameters openocd -f board/stm32f3discovery.cfg \ -c "program filename.elf verify reset" # binary files need the flash address passing openocd -f board/stm32f3discovery.cfg \ -c "program filename.bin 0x08000000"  File: openocd.info, Node: NAND Flash Commands, Next: PLD/FPGA Commands, Prev: Flash Programming, Up: Top 14 NAND Flash Commands ********************** Compared to NOR or SPI flash, NAND devices are inexpensive and high density. Today's NAND chips, and multi-chip modules, commonly hold multiple GigaBytes of data. NAND chips consist of a number of "erase blocks" of a given size (such as 128 KBytes), each of which is divided into a number of pages (of perhaps 512 or 2048 bytes each). Each page of a NAND flash has an "out of band" (OOB) area to hold Error Correcting Code (ECC) and other metadata, usually 16 bytes of OOB for every 512 bytes of page data. One key characteristic of NAND flash is that its error rate is higher than that of NOR flash. In normal operation, that ECC is used to correct and detect errors. However, NAND blocks can also wear out and become unusable; those blocks are then marked "bad". NAND chips are even shipped from the manufacturer with a few bad blocks. The highest density chips use a technology (MLC) that wears out more quickly, so ECC support is increasingly important as a way to detect blocks that have begun to fail, and help to preserve data integrity with techniques such as wear leveling. Software is used to manage the ECC. Some controllers don't support ECC directly; in those cases, software ECC is used. Other controllers speed up the ECC calculations with hardware. Single-bit error correction hardware is routine. Controllers geared for newer MLC chips may correct 4 or more errors for every 512 bytes of data. You will need to make sure that any data you write using OpenOCD includes the apppropriate kind of ECC. For example, that may mean passing the 'oob_softecc' flag when writing NAND data, or ensuring that the correct hardware ECC mode is used. The basic steps for using NAND devices include: 1. Declare via the command 'nand device' Do this in a board-specific configuration file, passing parameters as needed by the controller. 2. Configure each device using 'nand probe'. Do this only after the associated target is set up, such as in its reset-init script or in procures defined to access that device. 3. Operate on the flash via 'nand subcommand' Often commands to manipulate the flash are typed by a human, or run via a script in some automated way. Common task include writing a boot loader, operating system, or other data needed to initialize or de-brick a board. NOTE: At the time this text was written, the largest NAND flash fully supported by OpenOCD is 2 GiBytes (16 GiBits). This is because the variables used to hold offsets and lengths are only 32 bits wide. (Larger chips may work in some cases, unless an offset or length is larger than 0xffffffff, the largest 32-bit unsigned integer.) Some larger devices will work, since they are actually multi-chip modules with two smaller chips and individual chipselect lines. 14.1 NAND Configuration Commands ================================ NAND chips must be declared in configuration scripts, plus some additional configuration that's done after OpenOCD has initialized. -- Config Command: nand device name driver target [configparams...] Declares a NAND device, which can be read and written to after it has been configured through 'nand probe'. In OpenOCD, devices are single chips; this is unlike some operating systems, which may manage multiple chips as if they were a single (larger) device. In some cases, configuring a device will activate extra commands; see the controller-specific documentation. NOTE: This command is not available after OpenOCD initialization has completed. Use it in board specific configuration files, not interactively. * NAME ... may be used to reference the NAND bank in most other NAND commands. A number is also available. * DRIVER ... identifies the NAND controller driver associated with the NAND device being declared. *Note NAND Driver List: nanddriverlist. * TARGET ... names the target used when issuing commands to the NAND controller. * CONFIGPARAMS ... controllers may support, or require, additional parameters. See the controller-specific documentation for more information. -- Command: nand list Prints a summary of each device declared using 'nand device', numbered from zero. Note that un-probed devices show no details. > nand list #0: NAND 1GiB 3,3V 8-bit (Micron) pagesize: 2048, buswidth: 8, blocksize: 131072, blocks: 8192 #1: NAND 1GiB 3,3V 8-bit (Micron) pagesize: 2048, buswidth: 8, blocksize: 131072, blocks: 8192 > -- Command: nand probe num Probes the specified device to determine key characteristics like its page and block sizes, and how many blocks it has. The NUM parameter is the value shown by 'nand list'. You must (successfully) probe a device before you can use it with most other NAND commands. 14.2 Erasing, Reading, Writing to NAND Flash ============================================ -- Command: nand dump num filename offset length [oob_option] Reads binary data from the NAND device and writes it to the file, starting at the specified offset. The NUM parameter is the value shown by 'nand list'. Use a complete path name for FILENAME, so you don't depend on the directory used to start the OpenOCD server. The OFFSET and LENGTH must be exact multiples of the device's page size. They describe a data region; the OOB data associated with each such page may also be accessed. NOTE: At the time this text was written, no error correction was done on the data that's read, unless raw access was disabled and the underlying NAND controller driver had a 'read_page' method which handled that error correction. By default, only page data is saved to the specified file. Use an OOB_OPTION parameter to save OOB data: * no oob_* parameter Output file holds only page data; OOB is discarded. * 'oob_raw' Output file interleaves page data and OOB data; the file will be longer than "length" by the size of the spare areas associated with each data page. Note that this kind of "raw" access is different from what's implied by 'nand raw_access', which just controls whether a hardware-aware access method is used. * 'oob_only' Output file has only raw OOB data, and will be smaller than "length" since it will contain only the spare areas associated with each data page. -- Command: nand erase num [offset length] Erases blocks on the specified NAND device, starting at the specified OFFSET and continuing for LENGTH bytes. Both of those values must be exact multiples of the device's block size, and the region they specify must fit entirely in the chip. If those parameters are not specified, the whole NAND chip will be erased. The NUM parameter is the value shown by 'nand list'. NOTE: This command will try to erase bad blocks, when told to do so, which will probably invalidate the manufacturer's bad block marker. For the remainder of the current server session, 'nand info' will still report that the block "is" bad. -- Command: nand write num filename offset [option...] Writes binary data from the file into the specified NAND device, starting at the specified offset. Those pages should already have been erased; you can't change zero bits to one bits. The NUM parameter is the value shown by 'nand list'. Use a complete path name for FILENAME, so you don't depend on the directory used to start the OpenOCD server. The OFFSET must be an exact multiple of the device's page size. All data in the file will be written, assuming it doesn't run past the end of the device. Only full pages are written, and any extra space in the last page will be filled with 0xff bytes. (That includes OOB data, if that's being written.) NOTE: At the time this text was written, bad blocks are ignored. That is, this routine will not skip bad blocks, but will instead try to write them. This can cause problems. Provide at most one OPTION parameter. With some NAND drivers, the meanings of these parameters may change if 'nand raw_access' was used to disable hardware ECC. * no oob_* parameter File has only page data, which is written. If raw acccess is in use, the OOB area will not be written. Otherwise, if the underlying NAND controller driver has a 'write_page' routine, that routine may write the OOB with hardware-computed ECC data. * 'oob_only' File has only raw OOB data, which is written to the OOB area. Each page's data area stays untouched. This can be a dangerous option, since it can invalidate the ECC data. You may need to force raw access to use this mode. * 'oob_raw' File interleaves data and OOB data, both of which are written If raw access is enabled, the data is written first, then the un-altered OOB. Otherwise, if the underlying NAND controller driver has a 'write_page' routine, that routine may modify the OOB before it's written, to include hardware-computed ECC data. * 'oob_softecc' File has only page data, which is written. The OOB area is filled with 0xff, except for a standard 1-bit software ECC code stored in conventional locations. You might need to force raw access to use this mode, to prevent the underlying driver from applying hardware ECC. * 'oob_softecc_kw' File has only page data, which is written. The OOB area is filled with 0xff, except for a 4-bit software ECC specific to the boot ROM in Marvell Kirkwood SoCs. You might need to force raw access to use this mode, to prevent the underlying driver from applying hardware ECC. -- Command: nand verify num filename offset [option...] Verify the binary data in the file has been programmed to the specified NAND device, starting at the specified offset. The NUM parameter is the value shown by 'nand list'. Use a complete path name for FILENAME, so you don't depend on the directory used to start the OpenOCD server. The OFFSET must be an exact multiple of the device's page size. All data in the file will be read and compared to the contents of the flash, assuming it doesn't run past the end of the device. As with 'nand write', only full pages are verified, so any extra space in the last page will be filled with 0xff bytes. The same OPTIONS accepted by 'nand write', and the file will be processed similarly to produce the buffers that can be compared against the contents produced from 'nand dump'. NOTE: This will not work when the underlying NAND controller driver's 'write_page' routine must update the OOB with a hardward-computed ECC before the data is written. This limitation may be removed in a future release. 14.3 Other NAND commands ======================== -- Command: nand check_bad_blocks num [offset length] Checks for manufacturer bad block markers on the specified NAND device. If no parameters are provided, checks the whole device; otherwise, starts at the specified OFFSET and continues for LENGTH bytes. Both of those values must be exact multiples of the device's block size, and the region they specify must fit entirely in the chip. The NUM parameter is the value shown by 'nand list'. NOTE: Before using this command you should force raw access with 'nand raw_access enable' to ensure that the underlying driver will not try to apply hardware ECC. -- Command: nand info num The NUM parameter is the value shown by 'nand list'. This prints the one-line summary from "nand list", plus for devices which have been probed this also prints any known status for each block. -- Command: nand raw_access num ('enable'|'disable') Sets or clears an flag affecting how page I/O is done. The NUM parameter is the value shown by 'nand list'. This flag is cleared (disabled) by default, but changing that value won't affect all NAND devices. The key factor is whether the underlying driver provides 'read_page' or 'write_page' methods. If it doesn't provide those methods, the setting of this flag is irrelevant; all access is effectively "raw". When those methods exist, they are normally used when reading data ('nand dump' or reading bad block markers) or writing it ('nand write'). However, enabling raw access (setting the flag) prevents use of those methods, bypassing hardware ECC logic. This can be a dangerous option, since writing blocks with the wrong ECC data can cause them to be marked as bad. 14.4 NAND Driver List ===================== As noted above, the 'nand device' command allows driver-specific options and behaviors. Some controllers also activate controller-specific commands. -- NAND Driver: at91sam9 This driver handles the NAND controllers found on AT91SAM9 family chips from Atmel. It takes two extra parameters: address of the NAND chip; address of the ECC controller. nand device $NANDFLASH at91sam9 $CHIPNAME 0x40000000 0xfffffe800 AT91SAM9 chips support single-bit ECC hardware. The 'write_page' and 'read_page' methods are used to utilize the ECC hardware unless they are disabled by using the 'nand raw_access' command. There are four additional commands that are needed to fully configure the AT91SAM9 NAND controller. Two are optional; most boards use the same wiring for ALE/CLE: -- Command: at91sam9 cle num addr_line Configure the address line used for latching commands. The NUM parameter is the value shown by 'nand list'. -- Command: at91sam9 ale num addr_line Configure the address line used for latching addresses. The NUM parameter is the value shown by 'nand list'. For the next two commands, it is assumed that the pins have already been properly configured for input or output. -- Command: at91sam9 rdy_busy num pio_base_addr pin Configure the RDY/nBUSY input from the NAND device. The NUM parameter is the value shown by 'nand list'. PIO_BASE_ADDR is the base address of the PIO controller and PIN is the pin number. -- Command: at91sam9 ce num pio_base_addr pin Configure the chip enable input to the NAND device. The NUM parameter is the value shown by 'nand list'. PIO_BASE_ADDR is the base address of the PIO controller and PIN is the pin number. -- NAND Driver: davinci This driver handles the NAND controllers found on DaVinci family chips from Texas Instruments. It takes three extra parameters: address of the NAND chip; hardware ECC mode to use ('hwecc1', 'hwecc4', 'hwecc4_infix'); address of the AEMIF controller on this processor. nand device davinci dm355.arm 0x02000000 hwecc4 0x01e10000 All DaVinci processors support the single-bit ECC hardware, and newer ones also support the four-bit ECC hardware. The 'write_page' and 'read_page' methods are used to implement those ECC modes, unless they are disabled using the 'nand raw_access' command. -- NAND Driver: lpc3180 These controllers require an extra 'nand device' parameter: the clock rate used by the controller. -- Command: lpc3180 select num [mlc|slc] Configures use of the MLC or SLC controller mode. MLC implies use of hardware ECC. The NUM parameter is the value shown by 'nand list'. At this writing, this driver includes 'write_page' and 'read_page' methods. Using 'nand raw_access' to disable those methods will prevent use of hardware ECC in the MLC controller mode, but won't change SLC behavior. -- NAND Driver: mx3 This driver handles the NAND controller in i.MX31. The mxc driver should work for this chip aswell. -- NAND Driver: mxc This driver handles the NAND controller found in Freescale i.MX chips. It has support for v1 (i.MX27 and i.MX31) and v2 (i.MX35). The driver takes 3 extra arguments, chip ('mx27', 'mx31', 'mx35'), ecc ('noecc', 'hwecc') and optionally if bad block information should be swapped between main area and spare area ('biswap'), defaults to off. nand device mx35.nand mxc imx35.cpu mx35 hwecc biswap -- Command: mxc biswap bank_num [enable|disable] Turns on/off bad block information swaping from main area, without parameter query status. -- NAND Driver: orion These controllers require an extra 'nand device' parameter: the address of the controller. nand device orion 0xd8000000 These controllers don't define any specialized commands. At this writing, their drivers don't include 'write_page' or 'read_page' methods, so 'nand raw_access' won't change any behavior. -- NAND Driver: s3c2410 -- NAND Driver: s3c2412 -- NAND Driver: s3c2440 -- NAND Driver: s3c2443 -- NAND Driver: s3c6400 These S3C family controllers don't have any special 'nand device' options, and don't define any specialized commands. At this writing, their drivers don't include 'write_page' or 'read_page' methods, so 'nand raw_access' won't change any behavior.  File: openocd.info, Node: PLD/FPGA Commands, Next: General Commands, Prev: NAND Flash Commands, Up: Top 15 PLD/FPGA Commands ******************** Programmable Logic Devices (PLDs) and the more flexible Field Programmable Gate Arrays (FPGAs) are both types of programmable hardware. OpenOCD can support programming them. Although PLDs are generally restrictive (cells are less functional, and there are no special purpose cells for memory or computational tasks), they share the same OpenOCD infrastructure. Accordingly, both are called PLDs here. 15.1 PLD/FPGA Configuration and Commands ======================================== As it does for JTAG TAPs, debug targets, and flash chips (both NOR and NAND), OpenOCD maintains a list of PLDs available for use in various commands. Also, each such PLD requires a driver. They are referenced by the number shown by the 'pld devices' command, and new PLDs are defined by 'pld device driver_name'. -- Config Command: pld device driver_name tap_name [driver_options] Defines a new PLD device, supported by driver DRIVER_NAME, using the TAP named TAP_NAME. The driver may make use of any DRIVER_OPTIONS to configure its behavior. -- Command: pld devices Lists the PLDs and their numbers. -- Command: pld load num filename Loads the file 'filename' into the PLD identified by NUM. The file format must be inferred by the driver. 15.2 PLD/FPGA Drivers, Options, and Commands ============================================ Drivers may support PLD-specific options to the 'pld device' definition command, and may also define commands usable only with that particular type of PLD. -- FPGA Driver: virtex2 Virtex-II is a family of FPGAs sold by Xilinx. It supports the IEEE 1532 standard for In-System Configuration (ISC). No driver-specific PLD definition options are used, and one driver-specific command is defined. -- Command: virtex2 read_stat num Reads and displays the Virtex-II status register (STAT) for FPGA NUM.  File: openocd.info, Node: General Commands, Next: Architecture and Core Commands, Prev: PLD/FPGA Commands, Up: Top 16 General Commands ******************* The commands documented in this chapter here are common commands that you, as a human, may want to type and see the output of. Configuration type commands are documented elsewhere. Intent: * Source Of Commands OpenOCD commands can occur in a configuration script (discussed elsewhere) or typed manually by a human or supplied programatically, or via one of several TCP/IP Ports. * From the human A human should interact with the telnet interface (default port: 4444) or via GDB (default port 3333). To issue commands from within a GDB session, use the 'monitor' command, e.g. use 'monitor poll' to issue the 'poll' command. All output is relayed through the GDB session. * Machine Interface The Tcl interface's intent is to be a machine interface. The default Tcl port is 5555. 16.1 Daemon Commands ==================== -- Command: exit Exits the current telnet session. -- Command: help [string] With no parameters, prints help text for all commands. Otherwise, prints each helptext containing STRING. Not every command provides helptext. Configuration commands, and commands valid at any time, are explicitly noted in parenthesis. In most cases, no such restriction is listed; this indicates commands which are only available after the configuration stage has completed. -- Command: sleep msec ['busy'] Wait for at least MSEC milliseconds before resuming. If 'busy' is passed, busy-wait instead of sleeping. (This option is strongly discouraged.) Useful in connection with script files ('script' command and 'target_name' configuration). -- Command: shutdown Close the OpenOCD daemon, disconnecting all clients (GDB, telnet, other). -- Command: debug_level [n] Display debug level. If N (from 0..3) is provided, then set it to that level. This affects the kind of messages sent to the server log. Level 0 is error messages only; level 1 adds warnings; level 2 adds informational messages; and level 3 adds debugging messages. The default is level 2, but that can be overridden on the command line along with the location of that log file (which is normally the server's standard output). *Note Running::. -- Command: echo [-n] message Logs a message at "user" priority. Output MESSAGE to stdout. Option "-n" suppresses trailing newline. echo "Downloading kernel -- please wait" -- Command: log_output [filename] Redirect logging to FILENAME; the initial log output channel is stderr. -- Command: add_script_search_dir [directory] Add DIRECTORY to the file/script search path. 16.2 Target State handling ========================== In this section "target" refers to a CPU configured as shown earlier (*note CPU Configuration::). These commands, like many, implicitly refer to a current target which is used to perform the various operations. The current target may be changed by using 'targets' command with the name of the target which should become current. -- Command: reg [(number|name) [value]] Access a single register by NUMBER or by its NAME. The target must generally be halted before access to CPU core registers is allowed. Depending on the hardware, some other registers may be accessible while the target is running. _With no arguments_: list all available registers for the current target, showing number, name, size, value, and cache status. For valid entries, a value is shown; valid entries which are also dirty (and will be written back later) are flagged as such. _With number/name_: display that register's value. _With both number/name and value_: set register's value. Writes may be held in a writeback cache internal to OpenOCD, so that setting the value marks the register as dirty instead of immediately flushing that value. Resuming CPU execution (including by single stepping) or otherwise activating the relevant module will flush such values. Cores may have surprisingly many registers in their Debug and trace infrastructure: > reg ===== ARM registers (0) r0 (/32): 0x0000D3C2 (dirty) (1) r1 (/32): 0xFD61F31C (2) r2 (/32) ... (164) ETM_contextid_comparator_mask (/32) > -- Command: halt [ms] -- Command: wait_halt [ms] The 'halt' command first sends a halt request to the target, which 'wait_halt' doesn't. Otherwise these behave the same: wait up to MS milliseconds, or 5 seconds if there is no parameter, for the target to halt (and enter debug mode). Using 0 as the MS parameter prevents OpenOCD from waiting. Warning: On ARM cores, software using the _wait for interrupt_ operation often blocks the JTAG access needed by a 'halt' command. This is because that operation also puts the core into a low power mode by gating the core clock; but the core clock is needed to detect JTAG clock transitions. One partial workaround uses adaptive clocking: when the core is interrupted the operation completes, then JTAG clocks are accepted at least until the interrupt handler completes. However, this workaround is often unusable since the processor, board, and JTAG adapter must all support adaptive JTAG clocking. Also, it can't work until an interrupt is issued. A more complete workaround is to not use that operation while you work with a JTAG debugger. Tasking environments generaly have idle loops where the body is the _wait for interrupt_ operation. (On older cores, it is a coprocessor action; newer cores have a 'wfi' instruction.) Such loops can just remove that operation, at the cost of higher power consumption (because the CPU is needlessly clocked). -- Command: resume [address] Resume the target at its current code position, or the optional ADDRESS if it is provided. OpenOCD will wait 5 seconds for the target to resume. -- Command: step [address] Single-step the target at its current code position, or the optional ADDRESS if it is provided. -- Command: reset -- Command: reset run -- Command: reset halt -- Command: reset init Perform as hard a reset as possible, using SRST if possible. _All defined targets will be reset, and target events will fire during the reset sequence._ The optional parameter specifies what should happen after the reset. If there is no parameter, a 'reset run' is executed. The other options will not work on all systems. *Note Reset Configuration::. - run Let the target run - halt Immediately halt the target - init Immediately halt the target, and execute the reset-init script -- Command: soft_reset_halt Requesting target halt and executing a soft reset. This is often used when a target cannot be reset and halted. The target, after reset is released begins to execute code. OpenOCD attempts to stop the CPU and then sets the program counter back to the reset vector. Unfortunately the code that was executed may have left the hardware in an unknown state. 16.3 I/O Utilities ================== These commands are available when OpenOCD is built with '--enable-ioutil'. They are mainly useful on embedded targets, notably the ZY1000. Hosts with operating systems have complementary tools. _Note:_ there are several more such commands. -- Command: append_file filename [string]* Appends the STRING parameters to the text file 'filename'. Each string except the last one is followed by one space. The last string is followed by a newline. -- Command: cat filename Reads and displays the text file 'filename'. -- Command: cp src_filename dest_filename Copies contents from the file 'src_filename' into 'dest_filename'. -- Command: ip _No description provided._ -- Command: ls _No description provided._ -- Command: mac _No description provided._ -- Command: meminfo Display available RAM memory on OpenOCD host. Used in OpenOCD regression testing scripts. -- Command: peek _No description provided._ -- Command: poke _No description provided._ -- Command: rm filename Unlinks the file 'filename'. -- Command: trunc filename Removes all data in the file 'filename'. 16.4 Memory access commands =========================== These commands allow accesses of a specific size to the memory system. Often these are used to configure the current target in some special way. For example - one may need to write certain values to the SDRAM controller to enable SDRAM. 1. Use the 'targets' (plural) command to change the current target. 2. In system level scripts these commands are deprecated. Please use their TARGET object siblings to avoid making assumptions about what TAP is the current target, or about MMU configuration. -- Command: mdw [phys] addr [count] -- Command: mdh [phys] addr [count] -- Command: mdb [phys] addr [count] Display contents of address ADDR, as 32-bit words ('mdw'), 16-bit halfwords ('mdh'), or 8-bit bytes ('mdb'). When the current target has an MMU which is present and active, ADDR is interpreted as a virtual address. Otherwise, or if the optional PHYS flag is specified, ADDR is interpreted as a physical address. If COUNT is specified, displays that many units. (If you want to manipulate the data instead of displaying it, see the 'mem2array' primitives.) -- Command: mww [phys] addr word -- Command: mwh [phys] addr halfword -- Command: mwb [phys] addr byte Writes the specified WORD (32 bits), HALFWORD (16 bits), or BYTE (8-bit) value, at the specified address ADDR. When the current target has an MMU which is present and active, ADDR is interpreted as a virtual address. Otherwise, or if the optional PHYS flag is specified, ADDR is interpreted as a physical address. 16.5 Image loading commands =========================== -- Command: dump_image filename address size Dump SIZE bytes of target memory starting at ADDRESS to the binary file named FILENAME. -- Command: fast_load Loads an image stored in memory by 'fast_load_image' to the current target. Must be preceeded by fast_load_image. -- Command: fast_load_image filename address ['bin'|'ihex'|'elf'|'s19'] Normally you should be using 'load_image' or GDB load. However, for testing purposes or when I/O overhead is significant(OpenOCD running on an embedded host), storing the image in memory and uploading the image to the target can be a way to upload e.g. multiple debug sessions when the binary does not change. Arguments are the same as 'load_image', but the image is stored in OpenOCD host memory, i.e. does not affect target. This approach is also useful when profiling target programming performance as I/O and target programming can easily be profiled separately. -- Command: load_image filename address [['bin'|'ihex'|'elf'|'s19'] 'min_addr' 'max_length'] Load image from file FILENAME to target memory offset by ADDRESS from its load address. The file format may optionally be specified ('bin', 'ihex', 'elf', or 's19'). In addition the following arguments may be specifed: MIN_ADDR - ignore data below MIN_ADDR (this is w.r.t. to the target's load address + ADDRESS) MAX_LENGTH - maximum number of bytes to load. proc load_image_bin {fname foffset address length } { # Load data from fname filename at foffset offset to # target at address. Load at most length bytes. load_image $fname [expr $address - $foffset] bin $address $length } -- Command: test_image filename [address ['bin'|'ihex'|'elf']] Displays image section sizes and addresses as if FILENAME were loaded into target memory starting at ADDRESS (defaults to zero). The file format may optionally be specified ('bin', 'ihex', or 'elf') -- Command: verify_image filename address ['bin'|'ihex'|'elf'] Verify FILENAME against target memory starting at ADDRESS. The file format may optionally be specified ('bin', 'ihex', or 'elf') This will first attempt a comparison using a CRC checksum, if this fails it will try a binary compare. 16.6 Breakpoint and Watchpoint commands ======================================= CPUs often make debug modules accessible through JTAG, with hardware support for a handful of code breakpoints and data watchpoints. In addition, CPUs almost always support software breakpoints. -- Command: bp [address len ['hw']] With no parameters, lists all active breakpoints. Else sets a breakpoint on code execution starting at ADDRESS for LENGTH bytes. This is a software breakpoint, unless 'hw' is specified in which case it will be a hardware breakpoint. (*Note arm9 vector_catch: arm9vectorcatch, or *note xscale vector_catch: xscalevectorcatch, for similar mechanisms that do not consume hardware breakpoints.) -- Command: rbp address Remove the breakpoint at ADDRESS. -- Command: rwp address Remove data watchpoint on ADDRESS -- Command: wp [address len [('r'|'w'|'a') [value [mask]]]] With no parameters, lists all active watchpoints. Else sets a data watchpoint on data from ADDRESS for LENGTH bytes. The watch point is an "access" watchpoint unless the 'r' or 'w' parameter is provided, defining it as respectively a read or write watchpoint. If a VALUE is provided, that value is used when determining if the watchpoint should trigger. The value may be first be masked using MASK to mark "don't care" fields. 16.7 Misc Commands ================== -- Command: profile seconds filename Profiling samples the CPU's program counter as quickly as possible, which is useful for non-intrusive stochastic profiling. Saves up to 10000 sampines in 'filename' using "gmon.out" format. -- Command: version Displays a string identifying the version of this OpenOCD server. -- Command: virt2phys virtual_address Requests the current target to map the specified VIRTUAL_ADDRESS to its corresponding physical address, and displays the result.  File: openocd.info, Node: Architecture and Core Commands, Next: JTAG Commands, Prev: General Commands, Up: Top 17 Architecture and Core Commands ********************************* Most CPUs have specialized JTAG operations to support debugging. OpenOCD packages most such operations in its standard command framework. Some of those operations don't fit well in that framework, so they are exposed here as architecture or implementation (core) specific commands. 17.1 ARM Hardware Tracing ========================= CPUs based on ARM cores may include standard tracing interfaces, based on an "Embedded Trace Module" (ETM) which sends voluminous address and data bus trace records to a "Trace Port". * Development-oriented boards will sometimes provide a high speed trace connector for collecting that data, when the particular CPU supports such an interface. (The standard connector is a 38-pin Mictor, with both JTAG and trace port support.) Those trace connectors are supported by higher end JTAG adapters and some logic analyzer modules; frequently those modules can buffer several megabytes of trace data. Configuring an ETM coupled to such an external trace port belongs in the board-specific configuration file. * If the CPU doesn't provide an external interface, it probably has an "Embedded Trace Buffer" (ETB) on the chip, which is a dedicated SRAM. 4KBytes is one common ETB size. Configuring an ETM coupled only to an ETB belongs in the CPU-specific (target) configuration file, since it works the same on all boards. ETM support in OpenOCD doesn't seem to be widely used yet. Issues: ETM support may be buggy, and at least some 'etm config' parameters should be detected by asking the ETM for them. ETM trigger events could also implement a kind of complex hardware breakpoint, much more powerful than the simple watchpoint hardware exported by EmbeddedICE modules. _Such breakpoints can be triggered even when using the dummy trace port driver_. It seems like a GDB hookup should be possible, as well as tracing only during specific states (perhaps _handling IRQ 23_ or _calls foo()_). There should be GUI tools to manipulate saved trace data and help analyse it in conjunction with the source code. It's unclear how much of a common interface is shared with the current XScale trace support, or should be shared with eventual Nexus-style trace module support. At this writing (November 2009) only ARM7, ARM9, and ARM11 support for ETM modules is available. The code should be able to work with some newer cores; but not all of them support this original style of JTAG access. 17.1.1 ETM Configuration ------------------------ ETM setup is coupled with the trace port driver configuration. -- Config Command: etm config target width mode clocking driver Declares the ETM associated with TARGET, and associates it with a given trace port DRIVER. *Note Trace Port Drivers: traceportdrivers. Several of the parameters must reflect the trace port capabilities, which are a function of silicon capabilties (exposed later using 'etm info') and of what hardware is connected to that port (such as an external pod, or ETB). The WIDTH must be either 4, 8, or 16, except with ETMv3.0 and newer modules which may also support 1, 2, 24, 32, 48, and 64 bit widths. (With those versions, 'etm info' also shows whether the selected port width and mode are supported.) The MODE must be 'normal', 'multiplexed', or 'demultiplexed'. The CLOCKING must be 'half' or 'full'. Warning: With ETMv3.0 and newer, the bits set with the MODE and CLOCKING parameters both control the mode. This modified mode does not map to the values supported by previous ETM modules, so this syntax is subject to change. Note: You can see the ETM registers using the 'reg' command. Not all possible registers are present in every ETM. Most of the registers are write-only, and are used to configure what CPU activities are traced. -- Command: etm info Displays information about the current target's ETM. This includes resource counts from the 'ETM_CONFIG' register, as well as silicon capabilities (except on rather old modules). from the 'ETM_SYS_CONFIG' register. -- Command: etm status Displays status of the current target's ETM and trace port driver: is the ETM idle, or is it collecting data? Did trace data overflow? Was it triggered? -- Command: etm tracemode [type context_id_bits cycle_accurate branch_output] Displays what data that ETM will collect. If arguments are provided, first configures that data. When the configuration changes, tracing is stopped and any buffered trace data is invalidated. * TYPE ... describing how data accesses are traced, when they pass any ViewData filtering that that was set up. The value is one of 'none' (save nothing), 'data' (save data), 'address' (save addresses), 'all' (save data and addresses) * CONTEXT_ID_BITS ... 0, 8, 16, or 32 * CYCLE_ACCURATE ... 'enable' or 'disable' cycle-accurate instruction tracing. Before ETMv3, enabling this causes much extra data to be recorded. * BRANCH_OUTPUT ... 'enable' or 'disable'. Disable this unless you need to try reconstructing the instruction trace stream without an image of the code. -- Command: etm trigger_debug ('enable'|'disable') Displays whether ETM triggering debug entry (like a breakpoint) is enabled or disabled, after optionally modifying that configuration. The default behaviour is 'disable'. Any change takes effect after the next 'etm start'. By using script commands to configure ETM registers, you can make the processor enter debug state automatically when certain conditions, more complex than supported by the breakpoint hardware, happen. 17.1.2 ETM Trace Operation -------------------------- After setting up the ETM, you can use it to collect data. That data can be exported to files for later analysis. It can also be parsed with OpenOCD, for basic sanity checking. To configure what is being traced, you will need to write various trace registers using 'reg ETM_*' commands. For the definitions of these registers, read ARM publication _IHI 0014, "Embedded Trace Macrocell, Architecture Specification"_. Be aware that most of the relevant registers are write-only, and that ETM resources are limited. There are only a handful of address comparators, data comparators, counters, and so on. Examples of scenarios you might arrange to trace include: * Code flow within a function, _excluding_ subroutines it calls. Use address range comparators to enable tracing for instruction access within that function's body. * Code flow within a function, _including_ subroutines it calls. Use the sequencer and address comparators to activate tracing on an "entered function" state, then deactivate it by exiting that state when the function's exit code is invoked. * Code flow starting at the fifth invocation of a function, combining one of the above models with a counter. * CPU data accesses to the registers for a particular device, using address range comparators and the ViewData logic. * Such data accesses only during IRQ handling, combining the above model with sequencer triggers which on entry and exit to the IRQ handler. * _... more_ At this writing, September 2009, there are no Tcl utility procedures to help set up any common tracing scenarios. -- Command: etm analyze Reads trace data into memory, if it wasn't already present. Decodes and prints the data that was collected. -- Command: etm dump filename Stores the captured trace data in 'filename'. -- Command: etm image filename [base_address] [type] Opens an image file. -- Command: etm load filename Loads captured trace data from 'filename'. -- Command: etm start Starts trace data collection. -- Command: etm stop Stops trace data collection. 17.1.3 Trace Port Drivers ------------------------- To use an ETM trace port it must be associated with a driver. -- Trace Port Driver: dummy Use the 'dummy' driver if you are configuring an ETM that's not connected to anything (on-chip ETB or off-chip trace connector). _This driver lets OpenOCD talk to the ETM, but it does not expose any trace data collection._ -- Config Command: etm_dummy config target Associates the ETM for TARGET with a dummy driver. -- Trace Port Driver: etb Use the 'etb' driver if you are configuring an ETM to use on-chip ETB memory. -- Config Command: etb config target etb_tap Associates the ETM for TARGET with the ETB at ETB_TAP. You can see the ETB registers using the 'reg' command. -- Command: etb trigger_percent [percent] This displays, or optionally changes, ETB behavior after the ETM's configured _trigger_ event fires. It controls how much more trace data is saved after the (single) trace trigger becomes active. * The default corresponds to _trace around_ usage, recording 50 percent data before the event and the rest afterwards. * The minimum value of PERCENT is 2 percent, recording almost exclusively data before the trigger. Such extreme _trace before_ usage can help figure out what caused that event to happen. * The maximum value of PERCENT is 100 percent, recording data almost exclusively after the event. This extreme _trace after_ usage might help sort out how the event caused trouble. -- Trace Port Driver: oocd_trace This driver isn't available unless OpenOCD was explicitly configured with the '--enable-oocd_trace' option. You probably don't want to configure it unless you've built the appropriate prototype hardware; it's _proof-of-concept_ software. Use the 'oocd_trace' driver if you are configuring an ETM that's connected to an off-chip trace connector. -- Config Command: oocd_trace config target tty Associates the ETM for TARGET with a trace driver which collects data through the serial port TTY. -- Command: oocd_trace resync Re-synchronizes with the capture clock. -- Command: oocd_trace status Reports whether the capture clock is locked or not. 17.2 Generic ARM ================ These commands should be available on all ARM processors. They are available in addition to other core-specific commands that may be available. -- Command: arm core_state ['arm'|'thumb'] Displays the core_state, optionally changing it to process either 'arm' or 'thumb' instructions. The target may later be resumed in the currently set core_state. (Processors may also support the Jazelle state, but that is not currently supported in OpenOCD.) -- Command: arm disassemble address [count ['thumb']] Disassembles COUNT instructions starting at ADDRESS. If COUNT is not specified, a single instruction is disassembled. If 'thumb' is specified, or the low bit of the address is set, Thumb2 (mixed 16/32-bit) instructions are used; else ARM (32-bit) instructions are used. (Processors may also support the Jazelle state, but those instructions are not currently understood by OpenOCD.) Note that all Thumb instructions are Thumb2 instructions, so older processors (without Thumb2 support) will still see correct disassembly of Thumb code. Also, ThumbEE opcodes are the same as Thumb2, with a handful of exceptions. ThumbEE disassembly currently has no explicit support. -- Command: arm mcr pX op1 CRn CRm op2 value Write VALUE to a coprocessor PX register passing parameters CRN, CRM, opcodes OPC1 and OPC2, and using the MCR instruction. (Parameter sequence matches the ARM instruction, but omits an ARM register.) -- Command: arm mrc pX coproc op1 CRn CRm op2 Read a coprocessor PX register passing parameters CRN, CRM, opcodes OPC1 and OPC2, and the MRC instruction. Returns the result so it can be manipulated by Jim scripts. (Parameter sequence matches the ARM instruction, but omits an ARM register.) -- Command: arm reg Display a table of all banked core registers, fetching the current value from every core mode if necessary. -- Command: arm semihosting ['enable'|'disable'] Display status of semihosting, after optionally changing that status. Semihosting allows for code executing on an ARM target to use the I/O facilities on the host computer i.e. the system where OpenOCD is running. The target application must be linked against a library implementing the ARM semihosting convention that forwards operation requests by using a special SVC instruction that is trapped at the Supervisor Call vector by OpenOCD. 17.3 ARMv4 and ARMv5 Architecture ================================= The ARMv4 and ARMv5 architectures are widely used in embedded systems, and introduced core parts of the instruction set in use today. That includes the Thumb instruction set, introduced in the ARMv4T variant. 17.3.1 ARM7 and ARM9 specific commands -------------------------------------- These commands are specific to ARM7 and ARM9 cores, like ARM7TDMI, ARM720T, ARM9TDMI, ARM920T or ARM926EJ-S. They are available in addition to the ARM commands, and any other core-specific commands that may be available. -- Command: arm7_9 dbgrq ['enable'|'disable'] Displays the value of the flag controlling use of the the EmbeddedIce DBGRQ signal to force entry into debug mode, instead of breakpoints. If a boolean parameter is provided, first assigns that flag. This should be safe for all but ARM7TDMI-S cores (like NXP LPC). This feature is enabled by default on most ARM9 cores, including ARM9TDMI, ARM920T, and ARM926EJ-S. -- Command: arm7_9 dcc_downloads ['enable'|'disable'] Displays the value of the flag controlling use of the debug communications channel (DCC) to write larger (>128 byte) amounts of memory. If a boolean parameter is provided, first assigns that flag. DCC downloads offer a huge speed increase, but might be unsafe, especially with targets running at very low speeds. This command was introduced with OpenOCD rev. 60, and requires a few bytes of working area. -- Command: arm7_9 fast_memory_access ['enable'|'disable'] Displays the value of the flag controlling use of memory writes and reads that don't check completion of the operation. If a boolean parameter is provided, first assigns that flag. This provides a huge speed increase, especially with USB JTAG cables (FT2232), but might be unsafe if used with targets running at very low speeds, like the 32kHz startup clock of an AT91RM9200. 17.3.2 ARM720T specific commands -------------------------------- These commands are available to ARM720T based CPUs, which are implementations of the ARMv4T architecture based on the ARM7TDMI-S integer core. They are available in addition to the ARM and ARM7/ARM9 commands. -- Command: arm720t cp15 opcode [value] _DEPRECATED - avoid using this. Use the 'arm mrc' or 'arm mcr' commands instead._ Display cp15 register returned by the ARM instruction OPCODE; else if a VALUE is provided, that value is written to that register. The OPCODE should be the value of either an MRC or MCR instruction. 17.3.3 ARM9 specific commands ----------------------------- ARM9-family cores are built around ARM9TDMI or ARM9E (including ARM9EJS) integer processors. Such cores include the ARM920T, ARM926EJ-S, and ARM966. -- Command: arm9 vector_catch ['all'|'none'|list] Vector Catch hardware provides a sort of dedicated breakpoint for hardware events such as reset, interrupt, and abort. You can use this to conserve normal breakpoint resources, so long as you're not concerned with code that branches directly to those hardware vectors. This always finishes by listing the current configuration. If parameters are provided, it first reconfigures the vector catch hardware to intercept 'all' of the hardware vectors, 'none' of them, or a list with one or more of the following: 'reset' 'undef' 'swi' 'pabt' 'dabt' 'irq' 'fiq'. 17.3.4 ARM920T specific commands -------------------------------- These commands are available to ARM920T based CPUs, which are implementations of the ARMv4T architecture built using the ARM9TDMI integer core. They are available in addition to the ARM, ARM7/ARM9, and ARM9 commands. -- Command: arm920t cache_info Print information about the caches found. This allows to see whether your target is an ARM920T (2x16kByte cache) or ARM922T (2x8kByte cache). -- Command: arm920t cp15 regnum [value] Display cp15 register REGNUM; else if a VALUE is provided, that value is written to that register. This uses "physical access" and the register number is as shown in bits 38..33 of table 9-9 in the ARM920T TRM. (Not all registers can be written.) -- Command: arm920t cp15i opcode [value [address]] _DEPRECATED - avoid using this. Use the 'arm mrc' or 'arm mcr' commands instead._ Interpreted access using ARM instruction OPCODE, which should be the value of either an MRC or MCR instruction (as shown tables 9-11, 9-12, and 9-13 in the ARM920T TRM). If no VALUE is provided, the result is displayed. Else if that value is written using the specified ADDRESS, or using zero if no other address is provided. -- Command: arm920t read_cache filename Dump the content of ICache and DCache to a file named 'filename'. -- Command: arm920t read_mmu filename Dump the content of the ITLB and DTLB to a file named 'filename'. 17.3.5 ARM926ej-s specific commands ----------------------------------- These commands are available to ARM926ej-s based CPUs, which are implementations of the ARMv5TEJ architecture based on the ARM9EJ-S integer core. They are available in addition to the ARM, ARM7/ARM9, and ARM9 commands. The Feroceon cores also support these commands, although they are not built from ARM926ej-s designs. -- Command: arm926ejs cache_info Print information about the caches found. 17.3.6 ARM966E specific commands -------------------------------- These commands are available to ARM966 based CPUs, which are implementations of the ARMv5TE architecture. They are available in addition to the ARM, ARM7/ARM9, and ARM9 commands. -- Command: arm966e cp15 regnum [value] Display cp15 register REGNUM; else if a VALUE is provided, that value is written to that register. The six bit REGNUM values are bits 37..32 from table 7-2 of the ARM966E-S TRM. There is no current control over bits 31..30 from that table, as required for BIST support. 17.3.7 XScale specific commands ------------------------------- Some notes about the debug implementation on the XScale CPUs: The XScale CPU provides a special debug-only mini-instruction cache (mini-IC) in which exception vectors and target-resident debug handler code are placed by OpenOCD. In order to get access to the CPU, OpenOCD must point vector 0 (the reset vector) to the entry of the debug handler. However, this means that the complete first cacheline in the mini-IC is marked valid, which makes the CPU fetch all exception handlers from the mini-IC, ignoring the code in RAM. To address this situation, OpenOCD provides the 'xscale vector_table' command, which allows the user to explicity write individual entries to either the high or low vector table stored in the mini-IC. It is recommended to place a pc-relative indirect branch in the vector table, and put the branch destination somewhere in memory. Doing so makes sure the code in the vector table stays constant regardless of code layout in memory: _vectors: ldr pc,[pc,#0x100-8] ldr pc,[pc,#0x100-8] ldr pc,[pc,#0x100-8] ldr pc,[pc,#0x100-8] ldr pc,[pc,#0x100-8] ldr pc,[pc,#0x100-8] ldr pc,[pc,#0x100-8] ldr pc,[pc,#0x100-8] .org 0x100 .long real_reset_vector .long real_ui_handler .long real_swi_handler .long real_pf_abort .long real_data_abort .long 0 /* unused */ .long real_irq_handler .long real_fiq_handler Alternatively, you may choose to keep some or all of the mini-IC vector table entries synced with those written to memory by your system software. The mini-IC can not be modified while the processor is executing, but for each vector table entry not previously defined using the 'xscale vector_table' command, OpenOCD will copy the value from memory to the mini-IC every time execution resumes from a halt. This is done for both high and low vector tables (although the table not in use may not be mapped to valid memory, and in this case that copy operation will silently fail). This means that you will need to briefly halt execution at some strategic point during system start-up; e.g., after the software has initialized the vector table, but before exceptions are enabled. A breakpoint can be used to accomplish this once the appropriate location in the start-up code has been identified. A watchpoint over the vector table region is helpful in finding the location if you're not sure. Note that the same situation exists any time the vector table is modified by the system software. The debug handler must be placed somewhere in the address space using the 'xscale debug_handler' command. The allowed locations for the debug handler are either (0x800 - 0x1fef800) or (0xfe000800 - 0xfffff800). The default value is 0xfe000800. XScale has resources to support two hardware breakpoints and two watchpoints. However, the following restrictions on watchpoint functionality apply: (1) the value and mask arguments to the 'wp' command are not supported, (2) the watchpoint length must be a power of two and not less than four, and can not be greater than the watchpoint address, and (3) a watchpoint with a length greater than four consumes all the watchpoint hardware resources. This means that at any one time, you can have enabled either two watchpoints with a length of four, or one watchpoint with a length greater than four. These commands are available to XScale based CPUs, which are implementations of the ARMv5TE architecture. -- Command: xscale analyze_trace Displays the contents of the trace buffer. -- Command: xscale cache_clean_address address Changes the address used when cleaning the data cache. -- Command: xscale cache_info Displays information about the CPU caches. -- Command: xscale cp15 regnum [value] Display cp15 register REGNUM; else if a VALUE is provided, that value is written to that register. -- Command: xscale debug_handler target address Changes the address used for the specified target's debug handler. -- Command: xscale dcache ['enable'|'disable'] Enables or disable the CPU's data cache. -- Command: xscale dump_trace filename Dumps the raw contents of the trace buffer to 'filename'. -- Command: xscale icache ['enable'|'disable'] Enables or disable the CPU's instruction cache. -- Command: xscale mmu ['enable'|'disable'] Enables or disable the CPU's memory management unit. -- Command: xscale trace_buffer ['enable'|'disable' ['fill' [n] | 'wrap']] Displays the trace buffer status, after optionally enabling or disabling the trace buffer and modifying how it is emptied. -- Command: xscale trace_image filename [offset [type]] Opens a trace image from 'filename', optionally rebasing its segment addresses by OFFSET. The image TYPE may be one of 'bin' (binary), 'ihex' (Intel hex), 'elf' (ELF file), 's19' (Motorola s19), 'mem', or 'builder'. -- Command: xscale vector_catch [mask] Display a bitmask showing the hardware vectors to catch. If the optional parameter is provided, first set the bitmask to that value. The mask bits correspond with bit 16..23 in the DCSR: 0x01 Trap Reset 0x02 Trap Undefined Instructions 0x04 Trap Software Interrupt 0x08 Trap Prefetch Abort 0x10 Trap Data Abort 0x20 reserved 0x40 Trap IRQ 0x80 Trap FIQ -- Command: xscale vector_table [('low'|'high') index value] Set an entry in the mini-IC vector table. There are two tables: one for low vectors (at 0x00000000), and one for high vectors (0xFFFF0000), each holding the 8 exception vectors. INDEX can be 1-7, because vector 0 points to the debug handler entry and can not be overwritten. VALUE holds the 32-bit opcode that is placed in the mini-IC. Without arguments, the current settings are displayed. 17.4 ARMv6 Architecture ======================= 17.4.1 ARM11 specific commands ------------------------------ -- Command: arm11 memwrite burst ['enable'|'disable'] Displays the value of the memwrite burst-enable flag, which is enabled by default. If a boolean parameter is provided, first assigns that flag. Burst writes are only used for memory writes larger than 1 word. They improve performance by assuming that the CPU has read each data word over JTAG and completed its write before the next word arrives, instead of polling for a status flag to verify that completion. This is usually safe, because JTAG runs much slower than the CPU. -- Command: arm11 memwrite error_fatal ['enable'|'disable'] Displays the value of the memwrite error_fatal flag, which is enabled by default. If a boolean parameter is provided, first assigns that flag. When set, certain memory write errors cause earlier transfer termination. -- Command: arm11 step_irq_enable ['enable'|'disable'] Displays the value of the flag controlling whether IRQs are enabled during single stepping; they are disabled by default. If a boolean parameter is provided, first assigns that. -- Command: arm11 vcr [value] Displays the value of the _Vector Catch Register (VCR)_, coprocessor 14 register 7. If VALUE is defined, first assigns that. Vector Catch hardware provides dedicated breakpoints for certain hardware events. The specific bit values are core-specific (as in fact is using coprocessor 14 register 7 itself) but all current ARM11 cores _except the ARM1176_ use the same six bits. 17.5 ARMv7 Architecture ======================= 17.5.1 ARMv7 Debug Access Port (DAP) specific commands ------------------------------------------------------ These commands are specific to ARM architecture v7 Debug Access Port (DAP), included on Cortex-M and Cortex-A systems. They are available in addition to other core-specific commands that may be available. -- Command: dap apid [num] Displays ID register from AP NUM, defaulting to the currently selected AP. -- Command: dap apsel [num] Select AP NUM, defaulting to 0. -- Command: dap baseaddr [num] Displays debug base address from MEM-AP NUM, defaulting to the currently selected AP. -- Command: dap info [num] Displays the ROM table for MEM-AP NUM, defaulting to the currently selected AP. -- Command: dap memaccess [value] Displays the number of extra tck cycles in the JTAG idle to use for MEM-AP memory bus access [0-255], giving additional time to respond to reads. If VALUE is defined, first assigns that. -- Command: dap apcsw [0 / 1] fix CSW_SPROT from register AP_REG_CSW on selected dap. Defaulting to 0. 17.5.2 Cortex-M specific commands --------------------------------- -- Command: cortex_m maskisr ('auto'|'on'|'off') Control masking (disabling) interrupts during target step/resume. The 'auto' option handles interrupts during stepping a way they get served but don't disturb the program flow. The step command first allows pending interrupt handlers to execute, then disables interrupts and steps over the next instruction where the core was halted. After the step interrupts are enabled again. If the interrupt handlers don't complete within 500ms, the step command leaves with the core running. Note that a free breakpoint is required for the 'auto' option. If no breakpoint is available at the time of the step, then the step is taken with interrupts enabled, i.e. the same way the 'off' option does. Default is 'auto'. -- Command: cortex_m vector_catch ['all'|'none'|list] Vector Catch hardware provides dedicated breakpoints for certain hardware events. Parameters request interception of 'all' of these hardware event vectors, 'none' of them, or one or more of the following: 'hard_err' for a HardFault exception; 'mm_err' for a MemManage exception; 'bus_err' for a BusFault exception; 'irq_err', 'state_err', 'chk_err', or 'nocp_err' for various UsageFault exceptions; or 'reset'. If NVIC setup code does not enable them, MemManage, BusFault, and UsageFault exceptions are mapped to HardFault. UsageFault checks for divide-by-zero and unaligned access must also be explicitly enabled. This finishes by listing the current vector catch configuration. -- Command: cortex_m reset_config ('srst'|'sysresetreq'|'vectreset') Control reset handling. The default 'srst' is to use srst if fitted, otherwise fallback to 'vectreset'. - 'srst' use hardware srst if fitted otherwise fallback to 'vectreset'. - 'sysresetreq' use NVIC SYSRESETREQ to reset system. - 'vectreset' use NVIC VECTRESET to reset system. Using 'vectreset' is a safe option for all current Cortex-M cores. This however has the disadvantage of only resetting the core, all peripherals are uneffected. A solution would be to use a 'reset-init' event handler to manually reset the peripherals. *Note Target Events: targetevents. 17.6 Software Debug Messages and Tracing ======================================== OpenOCD can process certain requests from target software, when the target uses appropriate libraries. The most powerful mechanism is semihosting, but there is also a lighter weight mechanism using only the DCC channel. Currently 'target_request debugmsgs' is supported only for 'arm7_9' and 'cortex_m' cores. These messages are received as part of target polling, so you need to have 'poll on' active to receive them. They are intrusive in that they will affect program execution times. If that is a problem, *note ARM Hardware Tracing: armhardwaretracing. See 'libdcc' in the contrib dir for more details. In addition to sending strings, characters, and arrays of various size integers from the target, 'libdcc' also exports a software trace point mechanism. The target being debugged may issue trace messages which include a 24-bit "trace point" number. Trace point support includes two distinct mechanisms, each supported by a command: * _History_ ... A circular buffer of trace points can be set up, and then displayed at any time. This tracks where code has been, which can be invaluable in finding out how some fault was triggered. The buffer may overflow, since it collects records continuously. It may be useful to use some of the 24 bits to represent a particular event, and other bits to hold data. * _Counting_ ... An array of counters can be set up, and then displayed at any time. This can help establish code coverage and identify hot spots. The array of counters is directly indexed by the trace point number, so trace points with higher numbers are not counted. Linux-ARM kernels have a "Kernel low-level debugging via EmbeddedICE DCC channel" option (CONFIG_DEBUG_ICEDCC, depends on CONFIG_DEBUG_LL) which uses this mechanism to deliver messages before a serial console can be activated. This is not the same format used by 'libdcc'. Other software, such as the U-Boot boot loader, sometimes does the same thing. -- Command: target_request debugmsgs ['enable'|'disable'|'charmsg'] Displays current handling of target DCC message requests. These messages may be sent to the debugger while the target is running. The optional 'enable' and 'charmsg' parameters both enable the messages, while 'disable' disables them. With 'charmsg' the DCC words each contain one character, as used by Linux with CONFIG_DEBUG_ICEDCC; otherwise the libdcc format is used. -- Command: trace history ['clear'|count] With no parameter, displays all the trace points that have triggered in the order they triggered. With the parameter 'clear', erases all current trace history records. With a COUNT parameter, allocates space for that many history records. -- Command: trace point ['clear'|identifier] With no parameter, displays all trace point identifiers and how many times they have been triggered. With the parameter 'clear', erases all current trace point counters. With a numeric IDENTIFIER parameter, creates a new a trace point counter and associates it with that identifier. _Important:_ The identifier and the trace point number are not related except by this command. These trace point numbers always start at zero (from server startup, or after 'trace point clear') and count up from there.  File: openocd.info, Node: JTAG Commands, Next: Boundary Scan Commands, Prev: Architecture and Core Commands, Up: Top 18 JTAG Commands **************** Most general purpose JTAG commands have been presented earlier. (*Note JTAG Speed: jtagspeed, *note Reset Configuration::, and *note TAP Declaration::.) Lower level JTAG commands, as presented here, may be needed to work with targets which require special attention during operations such as reset or initialization. To use these commands you will need to understand some of the basics of JTAG, including: * A JTAG scan chain consists of a sequence of individual TAP devices such as a CPUs. * Control operations involve moving each TAP through the same standard state machine (in parallel) using their shared TMS and clock signals. * Data transfer involves shifting data through the chain of instruction or data registers of each TAP, writing new register values while the reading previous ones. * Data register sizes are a function of the instruction active in a given TAP, while instruction register sizes are fixed for each TAP. All TAPs support a BYPASS instruction with a single bit data register. * The way OpenOCD differentiates between TAP devices is by shifting different instructions into (and out of) their instruction registers. 18.1 Low Level JTAG Commands ============================ These commands are used by developers who need to access JTAG instruction or data registers, possibly controlling the order of TAP state transitions. If you're not debugging OpenOCD internals, or bringing up a new JTAG adapter or a new type of TAP device (like a CPU or JTAG router), you probably won't need to use these commands. In a debug session that doesn't use JTAG for its transport protocol, these commands are not available. -- Command: drscan tap [numbits value]+ ['-endstate' tap_state] Loads the data register of TAP with a series of bit fields that specify the entire register. Each field is NUMBITS bits long with a numeric VALUE (hexadecimal encouraged). The return value holds the original value of each of those fields. For example, a 38 bit number might be specified as one field of 32 bits then one of 6 bits. _For portability, never pass fields which are more than 32 bits long. Many OpenOCD implementations do not support 64-bit (or larger) integer values._ All TAPs other than TAP must be in BYPASS mode. The single bit in their data registers does not matter. When TAP_STATE is specified, the JTAG state machine is left in that state. For example DRPAUSE might be specified, so that more instructions can be issued before re-entering the RUN/IDLE state. If the end state is not specified, the RUN/IDLE state is entered. Warning: OpenOCD does not record information about data register lengths, so _it is important that you get the bit field lengths right_. Remember that different JTAG instructions refer to different data registers, which may have different lengths. Moreover, those lengths may not be fixed; the SCAN_N instruction can change the length of the register accessed by the INTEST instruction (by connecting a different scan chain). -- Command: flush_count Returns the number of times the JTAG queue has been flushed. This may be used for performance tuning. For example, flushing a queue over USB involves a minimum latency, often several milliseconds, which does not change with the amount of data which is written. You may be able to identify performance problems by finding tasks which waste bandwidth by flushing small transfers too often, instead of batching them into larger operations. -- Command: irscan [tap instruction]+ ['-endstate' tap_state] For each TAP listed, loads the instruction register with its associated numeric INSTRUCTION. (The number of bits in that instruction may be displayed using the 'scan_chain' command.) For other TAPs, a BYPASS instruction is loaded. When TAP_STATE is specified, the JTAG state machine is left in that state. For example IRPAUSE might be specified, so the data register can be loaded before re-entering the RUN/IDLE state. If the end state is not specified, the RUN/IDLE state is entered. Note: OpenOCD currently supports only a single field for instruction register values, unlike data register values. For TAPs where the instruction register length is more than 32 bits, portable scripts currently must issue only BYPASS instructions. -- Command: jtag_reset trst srst Set values of reset signals. The TRST and SRST parameter values may be '0', indicating that reset is inactive (pulled or driven high), or '1', indicating it is active (pulled or driven low). The 'reset_config' command should already have been used to configure how the board and JTAG adapter treat these two signals, and to say if either signal is even present. *Note Reset Configuration::. Note that TRST is specially handled. It actually signifies JTAG's RESET state. So if the board doesn't support the optional TRST signal, or it doesn't support it along with the specified SRST value, JTAG reset is triggered with TMS and TCK signals instead of the TRST signal. And no matter how that JTAG reset is triggered, once the scan chain enters RESET with TRST inactive, TAP 'post-reset' events are delivered to all TAPs with handlers for that event. -- Command: pathmove start_state [next_state ...] Start by moving to START_STATE, which must be one of the _stable_ states. Unless it is the only state given, this will often be the current state, so that no TCK transitions are needed. Then, in a series of single state transitions (conforming to the JTAG state machine) shift to each NEXT_STATE in sequence, one per TCK cycle. The final state must also be stable. -- Command: runtest NUM_CYCLES Move to the RUN/IDLE state, and execute at least NUM_CYCLES of the JTAG clock (TCK). Instructions often need some time to execute before they take effect. -- Command: verify_ircapture ('enable'|'disable') Verify values captured during IRCAPTURE and returned during IR scans. Default is enabled, but this can be overridden by 'verify_jtag'. This flag is ignored when validating JTAG chain configuration. -- Command: verify_jtag ('enable'|'disable') Enables verification of DR and IR scans, to help detect programming errors. For IR scans, 'verify_ircapture' must also be enabled. Default is enabled. 18.2 TAP state names ==================== The TAP_STATE names used by OpenOCD in the 'drscan', 'irscan', and 'pathmove' commands are the same as those used in SVF boundary scan documents, except that SVF uses IDLE instead of RUN/IDLE. * RESET ... _stable_ (with TMS high); acts as if TRST were pulsed * RUN/IDLE ... _stable_; don't assume this always means IDLE * DRSELECT * DRCAPTURE * DRSHIFT ... _stable_; TDI/TDO shifting through the data register * DREXIT1 * DRPAUSE ... _stable_; data register ready for update or more shifting * DREXIT2 * DRUPDATE * IRSELECT * IRCAPTURE * IRSHIFT ... _stable_; TDI/TDO shifting through the instruction register * IREXIT1 * IRPAUSE ... _stable_; instruction register ready for update or more shifting * IREXIT2 * IRUPDATE Note that only six of those states are fully "stable" in the face of TMS fixed (low except for RESET) and a free-running JTAG clock. For all the others, the next TCK transition changes to a new state. * From DRSHIFT and IRSHIFT, clock transitions will produce side effects by changing register contents. The values to be latched in upcoming DRUPDATE or IRUPDATE states may not be as expected. * RUN/IDLE, DRPAUSE, and IRPAUSE are reasonable choices after 'drscan' or 'irscan' commands, since they are free of JTAG side effects. * RUN/IDLE may have side effects that appear at non-JTAG levels, such as advancing the ARM9E-S instruction pipeline. Consult the documentation for the TAP(s) you are working with. openocd-0.7.0/doc/manual/0000755000175000001440000000000012141414413012157 500000000000000openocd-0.7.0/doc/manual/main.txt0000644000175000001440000000716212137151330013573 00000000000000/** @mainpage OpenOCD Developer's Guide Welcome to the OpenOCD Developer's Guide -- the developer's resource for learning about the internal architecture of the OpenOCD project. @par In addition, this document contains the tactical and strategic plans and processes that have been developed by and for the OpenOCD community. Developers that want to contribute to OpenOCD should read the following sections before starting work: - The List of @subpage thelist enumerates opportunities for improving or extending the OpenOCD platform. If your ideas are on The List, you might check the mailing list archives to find the status of your feature (or bug). - The @subpage styleguide provides rules that developers should follow when writing new code for OpenOCD. - The @subpage patchguide provides policies that developers should follow when submitting patches to the project. - The @subpage bugs page contains the content of the BUGS file, which provides instructions for submitting bug reports to the maintainers. - The @subpage releases page describes the project's release process. @ref primer provide introductory materials for new developers on various specific topics. Finally, the @ref oocd pages explain how the code has been organized into layers of APIs, providing an overview of how they fit together. These pages attempt to give developers a high-level perspective of the various code modules provided by OpenOCD. */ /** @page primer OpenOCD Technical Primers This pages lists Technical Primers available for OpenOCD Developers. They seek to provide information to pull novices up the learning curves associated with the fundamental technologies used by OpenOCD. - @subpage primerdocs - @subpage primerautotools - @subpage primertcl - @subpage primerjtag The above documents should bridge any "ancillary" gaps in contributor knowledge, without having to learn the complete languages or technology. They should provide enough information for experienced developers to learn how to make "correct" changes when creating patches. Beyond the fundamentals, the following primers provide introductory tutorials for OpenOCD's sub-systems. These complement the @ref oocd pages that provide more high-level perspective on related topics. - @subpage primercommand In all cases, these Primers should use idiomatic conventions that the community has agreed are the "right way of doing things". In this respect, these documents typically assume some familiarity with the information contained in one or more @ref styleguide, or they will directly refer to specific style guides as supplemental reading. Contributions or suggestions for new Technical Primers are welcome. */ /** @page oocd OpenOCD Architecture The OpenOCD library consists of several APIs that build together to provide the support functionality. The following list shows how these modules are stacked in the current implementation (from bottom to top): - @subpage helperdocs - @ref helperporting - @ref helperjim - @ref helpercommand - @ref helperlogging - @subpage jtagdocs - @ref jtagcore - @ref jtagtcl - @ref jtagcmd - @ref jtagiface - @ref jtagdriver - @subpage targetdocs - @ref targetarm - @ref targetnotarm - @ref targetmips - @ref targetregister - @ref targetimage - @ref targettrace - @subpage flashdocs - @ref flashcfi - @ref flashnand - @ref flashtarget - @subpage serverdocs - @ref servergdb - @ref servertelnet - @ref serverhttp - @subpage appdocs Obviously, there are some nuances to the stack that are not shown by this linear list of layers. The List of @ref thelist enumerates opportunities for improving or extending the OpenOCD platform. */ openocd-0.7.0/doc/manual/jtag.txt0000644000175000001440000000366312134336410013577 00000000000000/** @page jtagdocs JTAG APIs For new developers unfamiliar with the technology, @ref primerjtag provides a brief introduction to the IEEE JTAG interface. The OpenOCD JTAG library API covers several functional areas. The jtag @b core communicates through the @b minidriver API with either its full @a driver implementation (src/jtag/jtag_driver.c) or a @a minidriver . Internally, the @b command API is used by the JTAG driver for managing asynchronous transactions. - @subpage jtagcore - @b public API routines - declared in @c src/jtag/jtag.h - used by other modules - @subpage jtagtcl - @b private TCL handling routines - defined in @c src/jtag/tcl.c - registers and handles Jim commands that configure and use the JTAG core - @subpage jtagcmd - @b private command queue API - declared in @c src/jtag/commands.h - provides routines used internally by the full JTAG drivers. - @subpage jtagiface - @b private interface driver API - declared in @c src/jtag/interface.h - used by the core, minidrivers, and the full interface device drivers. - allows implementing new interface device drivers. - includes the Cable/TAP API (commands starting with @c tap_) - @subpage jtagdriver - @b private minidriver API - declared in @c src/jtag/minidriver.h - used @a only by the core and minidriver implementations: - @c jtag_driver.c (in-tree OpenOCD drivers) - @c zy1000/build/include/jtag_minidriver.h (ZY1000 minidriver) - future implementations (on other embedded hosts) - interface device drivers do @b not need this API. */ /** @page jtagcore JTAG Core API This section needs to be expanded. */ /** @page jtagtcl JTAG TCL API This section needs to be expanded. */ /** @page jtagcmd JTAG Command API This section needs to be expanded. */ /** @page jtagiface JTAG Interface API This section needs to be expanded. */ /** @page jtagdriver JTAG Minidriver API This section needs to be expanded. */ openocd-0.7.0/doc/manual/helper.txt0000644000175000001440000001205612134336410014125 00000000000000/** @page helperdocs OpenOCD Helper APIs OpenOCD uses several low-level APIs as the foundation for high-level APIs: - @subpage helperporting - @subpage helperjim - @subpage helpercommand - @subpage helperlogging - @subpage helperbuffers This section needs to be expanded. */ /** @page helperporting OpenOCD Types/Portability APIs This section needs to be expanded to describe OpenOCD's type and portability API. */ /** @page helperjim OpenOCD Jim API The Jim API provides access to a small-footprint TCL implementation. Visit http://jim.berlios.de/ for more information on Jim. This section needs to be expanded to describe OpenOCD's Jim API. */ /** @page helpercommand OpenOCD Command API OpenOCD's command API allows modules to register callbacks that are then available to the scripting services. It provides the mechanism for these commands to be dispatched to the modlue using a standard interfaces. It provides macros for defining functions that use and extend this interface. @section helpercmdhandler Command Handlers Command handlers are functions with a particular signature, which can be extended by modules for passing additional parameters to helpers or another layer of handlers. @subsection helpercmdhandlerdef Defining and Calling Command Handlers These functions should be defined using the @c COMMAND_HANDLER macro. These methods must be defined as static, as their principle entry point should be the run_command dispatch mechanism. Command helper functions that require access to the full set of parameters should be defined using the @c COMMAND_HELPER. These must be declared static by you, as sometimes you might want to share a helper among several files (e.g. @c s3c24xx_nand.h). Both types of routines must be called using the @c CALL_COMMAND_HANDLER macro. Calls using this macro to normal handlers require the name of the command handler (which can a name or function pointer). Calls to helpers and derived handlers must pass those extra parameters specified by their definitions; however, lexical capture is used for the core parameters. This dirty trick is being used as a stop-gap measure while the API is migrated to one that passes a pointer to a structure containing the same ingredients. At that point, this macro will be removed and callers will be able to use direct invocations. Thus, the following macros can be used to define and call command handlers or helpers: - @c COMMAND_HANDLER - declare or define a command handler. - @c COMMAND_HELPER - declare or define a derived command handler or helper. - @c CALL_COMMAND_COMMAND - call a command handler/helper. @subsection helpercmdhandlermacros Command Handler Macros In addition, the following macros may be used in the context of command handlers and helpers: - @c CMD_CTX - the current @c command_context - @c CMD_NAME - invoked command name - @c CMD_ARGC - the number of command arguments - @c CMD_ARGV - array of command argument strings @section helpercmdregister Command Registration In order to use a command handler, it must be registered with the command subsystem. All commands are registered with command_registration structures, specifying the name of the command, its handler, its allowed mode(s) of execution, and strings that provide usage and help text. A single handler may be registered using multiple names, but any name may have only one handler associated with it. The @c register_commands() and @c register_commands() functions provide registration, while the @c unregister_command() and @c unregister_all_commands() functions will remove existing commands. These may be called at any time, allowing the command set to change in response to system actions. @subsection helpercmdjim Jim Command Registration The command_registration structure provides support for registering native Jim command handlers (@c jim_handler) too. For these handlers, the module can provide help and usage support; however, this mechanism allows Jim handlers to be called as sub-commands of other commands. These commands may be registered with a private data value (@c jim_handler_data) that will be available when called, as with low-level Jim command registration. A command may have a normal @c handler or a @c jim_handler, but not both. @subsection helpercmdregisterchains Command Chaining When using register_commands(), the array of commands may reference other arrays. When the @c chain field is filled in a command_registration record, the commands on in the chained list will added in one of two places. If the record defines a new command, then the chained commands are added under it; otherwise, the commands are added in the same context as the other commands in the array. @section helpercmdprimer Command Development Primer This @ref primercommand provides details about the @c hello module, showing how the pieces desrcribed on this page fit together. */ /** @page helperlogging OpenOCD Logging API This section needs to be expanded to describe OpenOCD's Logging API. */ /** @page helperbuffers OpenOCD Byte Buffer API This section needs to be expanded to describe OpenOCD's Byte Buffer API. */ openocd-0.7.0/doc/manual/release.txt0000644000175000001440000005301212141300571014260 00000000000000/** @page releases Release Processes This page provides an introduction to the OpenOCD Release Processes: - @ref releasewhy - Explain the motivations for producing releases on a regular basis. - @ref releasewho - Describes the responsibilities and authority required to produce official OpenOCD releases. - @ref releasewhen - Provides guidelines for scheduling activities for each release cycle. - @ref releasehow - Outlines all of the steps for the processes used to produce and release the package source archives. - @ref releasescriptcmds - Introduces the automated @c release.sh script. @section releasewhy Why Produce Releases? The OpenOCD maintainers produce releases periodically for many reasons. This section provides the key reasons for making releases on a regular basis and why a set of release processes should be used to produce them. At any time, source archives can be produced by running make dist in the OpenOCD project tree. With the 0.2.0 release, this command will package the tree into several popular archive formats: openocd-\.{tar.gz,tar.bz2,zip}. If produced properly, these files are suitable for release to the public. When properly versioned and released for users, these archives present several important advantages compared to using the source repository (including snapshots downloaded from that repository using gitweb): -# They allow others to package and distribute the code using consistent version labels. Users won't normally need to care whose package they use, just the version of OpenOCD. -# They contain a working configure script and makefiles, which were produced as part of creating the archive. -# Because they have been formally released by the project, users don't need to try a random work-in-process revision. Releasing involves spending some time specifically on quality improvments, including bugfixing source code and documentation. -# They provide developers with the flexibility needed to address larger issues, which sometimes involves temporary breakage. Hopefully, this shows several good reasons to produce regular releases, but the release processes were developed with some additional design goals in mind. Specifically, the releases processes should have the following properties: -# Produce successive sets of archives cleanly and consistently. -# Implementable as a script that automates the critical steps. -# Prevent human operators from producing broken packages, when possible. -# Allow scheduling and automation of building and publishing milestones. The current release processes are documented in the following sections. They attempt to meet these design goals, but improvements may still need to be made. @subsection version_labels Version Labels Users can display the OpenOCD version string in at least two ways. The command line openocd -v invocation displays it; as does the Tcl version command. Labels for released versions look like 0.3.0, or 0.3.0-rc1 for a preliminary release. Non-released (developer) versions look like 0.3.0-dev, or 0.3.0-rc1-dev. In all cases, additional tags may be appended to those base release version labels. The tools/release/version.sh script is used to manipulate version IDs found in the source tree. @subsubsection releaseversions Release Versions and Tags The OpenOCD version string is composed of three numeric components separated by two decimal points: @c x.y.z, where @c x is the @a major version number, @c y is the @a minor number, and @c z is the @a micro. For any bug-fix release, the micro version number will be non-zero (z > 0). For a minor release, the micro version number will be zero (z = 0). For a major releases, the minor version will @a also be zero (y = 0, z = 0). After these required numeric components, release version strings may contain tags such as as -rc1 or -rc2. These 'rc' tags indicate "release candidate" versions of the package. Like major/minor/micro numbers, these are updated as part of the release process. The release process includes version number manipulations to the tree being released, ensuring that all numbers are incremented (or rolled over) at the right time and in the proper locations of the repository. One of those manipulations creates a repository tag matching that release's version label. @subsubsection releaseversionsdist Packager Versions Distributors of patched versions of OpenOCD are encouraged to extend the version string with a unique version tag when producing external releases, as this helps to identify your particular distribution series. Knowing that a release has such patches can be essential to tracking down and fixing bugs. Packager version tags should always be suffixes to the version code from the OpenOCD project, signifying modifications to the original code base. Each packager release should have a unique version. For example, the following command will add a 'foo' tag to the configure.ac script of a local copy of the source tree, giving a version label like 0.3.0-foo: @code tools/release/version.sh tag add foo @endcode This command will modify the configure.ac script in your working copy only. After running the @c bootstrap sequence, the tree can be patched and used to produce your own derived versions. You might check that change into a private branch of your git tree, along with the other patches you are providing. You can also "bump" those tags (so "foo1" becomes "foo2" etc) each time a derived package is released, incrementing the tag's version to facilitate tracking the changes you have distributed. @code tools/release/version.sh bump tag foo @endcode Of course, any patches in your branches must be provided to your customers, and be in conformance with the GPL. In most cases you should also work to merge your improvements to the mainline tree. @subsubsection version_tags Development Versions and Tags Everything except formal releases should have the tag -dev in their version number. This helps developers identify reports created from non-release versions, and it can be detected and manipulated by the release script. Specifically, this tag will be removed and re-added during the release process; it should never be manipulated by developers in submitted patches. Versions built from developer trees may have additional tags. Trees built from git snapshots have snapshot tags. When built from a "live" git tree, tags specify specific git revisions: 0.3.0-rc1-dev-00015-gf37c9b8-dirty indicates a development tree based on git revison f37c9b8 (a truncated version of a SHA1 hash) with some non-git patches applied (the dirty tag). This information can be useful when tracking down bugs. (Note that at this writing, the tags do not directly correspond to git describe output. The hash ID can be used with git show, but the relevant repository tag isn't 0.3.0-rc1-dev; this might change in the future.) @section releasewho Release Manager OpenOCD archive releases will be produced by an individual filling the role of Release Manager, hereafter abbreviated as RM. This individual determines the schedule and executes the release processes for the community. @subsection releasewhohow RM Authority Each release requires one individual to fulfill the RM role; however, graceful transitions of this authority may take place at any time. The current RM may transfer their authority to another contributor in a post to the OpenOCD development mailing list. Such delegation of authority must be approved by the individual that will receive it and the community of maintainers. Initial arrangements with the new RM should be made off-list, as not every contributor wants these responsibilities. @subsection releasewhowhat RM Responsibilities In addition to the actual process of producing the releases, the RM is responsible for keeping the community informed of all progress through the release cycle(s) being managed. The RM is responsible for managing the changes to the package version, though the release tools should manage the tasks of adding or removing any required development branch tags and incrementing the version. These responsibilities matter most towards the end of the release cycle, when the RM creates the first RC and all contributors enter a quality-improvement mode. The RM works with other contributors to make sure everyone knows what kinds of fixes should merge, the status of major issues, and the release timetable. In particular, the RM has the final decision on whether a given bug should block the release. @section releasewhen Release Schedule The OpenOCD release process must be carried out on a periodic basis, so the project can realize the benefits presented in answer to the question, @ref releasewhy. Starting with the 0.2.0 release, the OpenOCD project expects to produce new releases every few months. Bug fix releases could be provided more frequently. These release schedule goals may be adjusted in the future, after the project maintainers and distributors receive feedback and experience. More importantly, the statements made in this section do not create an obligation by any member of the OpenOCD community to produce new releases on regular schedule, now or in the future. @subsection releasewhenexample Sample Schedule The RM must pro-actively communicate with the community from the beginning of the development cycle through the delivery of the new release. This section presents guidelines for scheduling key points where the community must be informed of changing conditions. If Tn is the time of release n, then the following schedule might describe some key T0-to-T1 release cycle milestones. - T0 ... End of T0 release cycle. T1 cycle starts, with merge window opening. Developers begin to merge queued work. - ... several weeks of merge window ... - RC1 ... Close mainline to new work. Produce RC1 release, begin testing phase; developers are in "bugfix mode", all other work is queued; send out planned endgame schedule. - RC2 ... Produce RC2 and send schedule update to mailing list, listing priorities for remaining fixes - ... more RC milestones, until ready ... - T1: End of T1 release cycle. T2 cycle starts, with merge window opening. Developers begin to merge queued work. Note that until it happens, any date for T1 is just a goal. Critical bugs prevent releases from happening. We are just beginning to use this window-plus-RCs process, so the lengths of the merge windows versus the RC phase is subject to change. Most projects have RC phases of a month or more. Some additional supplemental communication will be desirable. The above list omits the step-by-step instructions to daily release management. Individuals performing release management need to have the ability to interact proactively with the community as a whole, anticipating when such interaction will be required and giving ample notification. The next section explains why the OpenOCD project allows significant flexibility in the part of the development that precedes the release process. @subsection releasewhenflex Schedule Flexibility The Release Manager should attempt to follow the guidelines in this document, but the process of scheduling each release milestone should be community driven at the start. Features that don't complete before the merge window closes can be held (perhaps in some branch) until the next merge window opens, rather than delaying the release cycle. The Release Manager cannot schedule the work that will be done on the project, when it will be submitted, reviewed, and deemed suitable to be committed. That is, the RM cannot act as a priest in a cathedral; OpenOCD uses the bazaar development model. The release schedule must adapt continuously in response to changes in the rate of work. Fewer releases may be required if developers contribute less patches, and more releases may be desirable if the project continues to grow and experience high rates of community contribution. During each cycle, the RM should be tracking the situation and gathering feedback from the community. @section releasehow Release Process: Step-by-Step The release process is not final; it may need more iterations to work out bugs. While there are release scripts, key steps require community support; the Release Manager isn't the only participant. The following steps should be followed to produce each release: -# Produce final patches using a local clone of mainline. Nobody except the RM should be committing anything. Everyone with commit privileges needs to know and agree to this in advance! Even the RM only commits a handful of updates as part of the release process itself ... to files which are part of the version identification scheme or release process; and to create the version tag; and then to open the merge window for the next release cycle. -# Finalize @c the NEWS file to describe the changes in the release - This file is used to automatically post "blurbs" about the project. - This material should have been produced during the development cycle, by adding items for each @c NEWS-worthy contribution, when committed during the merge window. (One part of closing the merge window, by opening the RC phase of the release, is the commitment to hold all further such contributions until the next merge window opens.) - The RM should make sure nothing important was omitted, as part of the RC1 cycle. From then on, no more updates to NEWS content should be needed (except to seed the process for the next release, or maybe if a significant and longstanding bug is fixed late in the RC phase). -# Bump library version if our API changed (not yet required) -# Update and commit the final package version in @c configure.ac: (The tools/release/version.sh script might help ensure the versions are named properly.): -# Remove @c -dev tag. -# Update any @c -rc tag: - If producing the final release from an -rc series, remove it - If producing the first RC in a series, add rc1 - If producing the next RC in a series, bump the rc number -# Commit that version change, with a good descriptive comment. -# Create a git tag for the final commit, with a tag name matching the version string in configure.ac (including -rcN where relevant): @verbatim PACKAGE_VERSION="x.y.z" PACKAGE_TAG="v${PACKAGE_VERSION}" git tag -m "The openocd-${PACKAGE_VERSION} release." "${PACKAGE_TAG}" @endverbatim -# Do not push those changes to mainline yet; only builds using the source archives you will be creating should ever be labeled as official releases (with no "-dev" suffix). Since mainline is a development tree, these will be pushed later, as part of opening the merge window for the next release cycle (restoring the "-dev" suffix for that next release.) Those version and tag updates are the last ones to be included in the release being made. -# Produce the release files, using the local clone of the source tree which holds the release's tag and updated version in @c configure.ac ... this is used only to produce the release, and all files should already be properly checked out. -# Run tools/release.sh package to produce the source archives. This automatically bootstraps and configures the process. -# Run tools/release.sh stage to create an @c archives directory with the release data, including MD5 and SHA1 checksum files. -# Sanity check at least one of those archives, by extracting and configuring its contents, using them to build a copy of OpenOCD, and verifying that the result prints the correct release version in its startup banner. (For example, "configure --enable-ft2232_libftdi --enable-parport" then "make" and run "src/openocd -v" as a sanity check.) -# Run make docs to create the documentation which will be published. -# Upload packages and post announcements of their availability: -# Release packages into files section of project sites: - SF.net: -# Under "Project Admin", use the "File Manager" -# Create a new folder under "openocd" named "${PACKAGE_VERSION}" -# Upload the @c NEWS file and mark it as the release notes. -# Upload the three source archive files, using the Web interface, into that folder. Verify the upload worked OK by checking the MD5 and SHA1 checksums computed by SourceForge against the versions created as part of staging the release. -# Also upload doc/openocd.pdf (the User's Guide) so the version matching each release will be easily available. -# Select each file in the release, and use the property panel to set its type and select the right release notes. - .tar.bz2: Linux, Mac - .tar.gz: BSD, Solaris, Others - .zip: Windows - For openocd.pdf just associate it with the right release notes. -# Create an SF.net project news update. -# Depending on how paranoid you're feeling today, verify the images by downloading them from the websites and making sure there are no differences between the downloaded copies and your originals. -# Publish User's and Developer's Guides to the project web sites: -# Use SCP to update the SF.net web site with PDF and HTML for the User's Guide, and HTML for the developer's guide ... you can instantiate a shell.sourceforge.net instance and set up symlinks from your home directory, to simplify this process. -# Post announcement e-mail to the openocd-development list. -# optionally: -# Post an update on the OpenOCD blog. -# Announce updates on freshmeat.net and other trackers. -# Submit updates to news feeds (e.g. Digg, Reddit, etc.). -# Resume normal development on mainline, by opening the merge window for the next major or minor release cycle. (You might want to do this before all the release bits are fully published.) - Update the version label in the @c configure.ac file: - Restore @c -dev version tag. - For a new minor release cycle, increment the release's minor number - For a new major release cycle, increment the release's major number and zero its minor number - Archive @c NEWS file as "doc/news/NEWS-${PACKAGE_VERSION}". - Create a new @c NEWS file for the next release - Commit those changes. - Push all the updates to mainline. - Last updates for the release, including the release tag (you will need to "git push --tags"). - Updates opening the merge window - At this point, it's OK for commiters to start pushing changes which have been held off until the next release. (Any bugfixes to this release will be against a bug-fix release branch starting from the commit you tagged as this release, not mainline.) - Announce to the openocd-development list. Ideally, you will also be able to say who is managing the next release cycle. To start a bug-fix release branch: -# Create a new branch, starting from a major or minor release tag -# Restore @c -dev version tag. -# Bump micro version number in configure.ac -# Backport bugfix patches from mainline into that branch. (Always be sure mainline has the fix first, so it's hard to just lose a bugfix.) -# Commit and push those patches. -# When desired, release as above ... except note that the next release of a bugfix branch is never a new major or minor release @subsection releasescriptcmds Release Script Commands The @c release.sh script automates some of the steps involved in making releases, simplifying the Release Manager's work. The release script can be used for two tasks: - Creating releases and starting a new release cycle: @code git checkout master tools/release.sh --type=minor --final --start-rc release @endcode - Creating a development branch from a tagged release: @code git checkout 'v0.2.0' tools/release.sh --type=micro branch @endcode Both of these variations make automatic commits and tags in your repository, so you should be sure to run it on a cloned copy before proceding with a live release. @subsection releasescriptopts Release Script Options The @c release.sh script recognizes some command-line options that affect its behavior: - The @c --start-rc indicates that the new development release cycle should start with @c -rc0. Without this, the @c -rc tag will be omitted, leading to non-monotonic versioning of the in-tree version numbers. - The @c --final indicates that the release should drop the @c -rc tag, to going from @c x.y.z-rcN-dev to x.y.z. @subsection releasescriptenv Release Script Environment The @c release.sh script recognizes some environment variables which affect its behavior: - @c CONFIG_OPTS : Passed as options to the configure script. - @c MAKE_OPTS : Passed as options to the 'make' processes. @section releasetutorial Release Tutorials This section should contain a brief tutorial for using the Release Script to perform release tasks, but the new script needs to be used for 0.3.0. @section releasetodo Release Script Shortcomings Improved automated packaging and distribution of OpenOCD requires more patching of the configure script. The final release script should be able to manage most steps of the processes. The steps requiring user input could be guided by an "assistant" that walks the Release Manager through the process from beginning to end, performing basic sanity checks on their various inputs (e.g. the @c NEWS blurb). */ /** @file This file contains the @ref releases page. */ openocd-0.7.0/doc/manual/target/0000755000175000001440000000000012141414413013445 500000000000000openocd-0.7.0/doc/manual/target/notarm.txt0000644000175000001440000000355312134336410015436 00000000000000/** @page targetnotarm OpenOCD Non-ARM Targets This page describes outstanding issues w.r.t. non-ARM targets. @section targetnotarmflash Flash drivers The flash drivers contain ARM32 code that is used to execute code on the target. This needs to be handled in some CPU independent manner. The ocl and ecos flash drivers compile the flash driver code to run on the target on the developer machine. The ocl and ecos flash drivers should be unified and instructions should be written on how to compile the target flash drivers. Perhaps using automake? eCos has CFI driver that could probably be compiled for all targets. The trick is to figure out a way to make the compiled flash drivers work on all target memory maps + sort out all the little details @section targetnotarm32v64 32 vs. 64 bit Currently OpenOCD only supports 32 bit targets. Adding 64 bit support would be nice but there hasn't been any call for it in the openocd development mailing list @section targetnotarmsupport Target Support target.h is relatively CPU agnostic and the intention is to move in the direction of less instruction set specific. Non-CPU targets are also supported, but there isn't a lot of activity on it in the mailing list currently. An example is FPGA programming support via JTAG, but also flash chips can be programmed directly using JTAG. @section targetnotarmphy non-JTAG physical layer JTAG is not the only physical protocol used to talk to CPUs. OpenOCD does not today have targets that use non-JTAG. The actual physical layer is a relatively modest part of the total OpenOCD system. @section targetnotarmppc PowerPC there exists open source implementations of powerpc target manipulation, but there hasn't been a lot of activity in the mailing list. @section targetnotarmmips MIPS Currently OpenOCD has a MIPS target defined. This is the first non-ARM example of a CPU target */ openocd-0.7.0/doc/manual/target/mips.txt0000644000175000001440000006304312137151330015105 00000000000000/** @page targetmips OpenOCD MIPS Targets @section ejatgmem EJTAG Memory Addresses An optional uncached and unmapped debug segment dseg (EJTAG area) appears in the address range 0xFFFF FFFF FF20 0000 to 0xFFFF FFFF FF3F FFFF. The dseg segment thereby appears in the kseg part of the compatibility segment, and access to kseg is possible with the dseg segment. The dseg segment is subdivided into dmseg (EJTAG memory) segment and the drseg (EJTAG registers) segment. The dmseg segment is used when the probe services the memory segment. The drseg segment is used when the memory-mapped debug registers are accessed. Table 5-2 shows the subdivision and attributes for the segments. dseg is divided in : - dmseg (0xFFFF FFFF FF20 0000 to 0xFFFF FFFF FF2F FFFF) - drseg (0xFFFF FFFF FF30 0000 to 0xFFFF FFFF FF3F FFFF) Because the dseg segment is serviced exclusively by the EJTAG features, there are no physical address per se. Instead the lower 21 bits of the virtual address select the appropriate reference in either EJTAG memory or registers. References are not mapped through the TLB, nor do the accesses appear on the external system memory interface. Both of this memory segments are Uncached. On debug exception (break) CPU jumps to the beginning of dmseg. This some kind of memory shared between CPU and EJTAG dongle. There CPU stops (correct terminology is : stalls, because it stops it's pipeline), and is waiting for some action of dongle. If the dongle gives it instruction, CPU executes it, augments it's PC to 0xFFFF FFFF FF20 0001 - but it again points to dmseg area, so it stops waiting for next instruction. This will all become clear later, after reading following prerequisite chapters. @section impflags Important flags @subsection pnnw PNnW Indicates read or write of a pending processor access: - 0 : Read processor access, for a fetch/load access - 1 : Write processor access, for a store access This value is defined only when a processor access is pending. Processor will do the action for us : it can for example read internal state (register values), and send us back the information via EJTAG memory (dmseg), or it can take some data from dmseg and write it into the registers or RAM. Every time when it sees address (i.e. when this address is the part of the opcode it is executing, wether it is instruction or data fetch) that falls into dmseg, processor stalls. That acutally meand that CPU stops it's pipeline and it is waitning for dongle to take some action. CPU is now either waiting for dongle to take some data from dmseg (if we requested for CPU do give us internal state, for example), or it will wait for some data from dongle (if it needs following instruction because it did previous, or if the operand address of the currently executed opcode falls somewhere (anywhere) in dmseg (0xff..ff20000 - 0xff..ff2fffff)). Bit PNnW describes character of CPU access to EJTAG memory (the memry where dongle puts/takes data) - CPU can either READ for it (PNnW == 0) or WRITE to it (PNnW == 1). By reading PNnW bit OpenOCD will know if it has to send (PNnW == 0) or to take (PNnW == 1) data (from dmseg, via dongle). @subsection pracc PrAcc Indicates a pending processor access and controls finishing of a pending processor access. When read: - 0 : No pending processor access - 1 : Pending processor access A write of 0 finishes a processor access if pending; otherwise operation of the processor is UNDEFINED if the bit is written to 0 when no processor access is pending. A write of 1 is ignored. A successful FASTDATA access will clear this bit. As noted above, on any access to dmseg, processor will stall. It waits for dongle to do some action - either to take or put some data. OpenOCD can figure out which action has to be taken by reading PrAcc bit. Once action from dongle has been done, i.e. after the data is taken/put, OpenOCD can signal to CPU to proceed with executing the instruction. This can be the next instruction (if previous was finished before pending), or the same instruction - if for example CPU was waiting on dongle to give it an operand, because it saw in the instruction opcode that operand address is somewhere in dmseg. That prowoked the CPU to stall (it tried operand fetch to dmseg and stopped), and PNnW bit is 0 (CPU does read from dmseg), and PrAcc is 1 (CPU is pending on dmseg access). @subsection spracc SPrAcc Shifting in a zero value requests completion of the Fastdata access. The PrAcc bit in the EJTAG Control register is overwritten with zero when the access succeeds. (The access succeeds if PrAcc is one and the operation address is in the legal dmseg segment Fastdata area.) When successful, a one is shifted out. Shifting out a zero indicates a Fastdata access failure. Shifting in a one does not complete the Fastdata access and the PrAcc bit is unchanged. Shifting out a one indicates that the access would have been successful if allowed to complete and a zero indicates the access would not have successfully completed. @section fdreg Fastdata Register (TAP Instruction FASTDATA) The width of the Fastdata register is 1 bit. During a Fastdata access, the Fastdata register is written and read, i.e., a bit is shifted in and a bit is shifted out. Also during a Fastdata access, the Fastdata register value shifted in specifies whether the Fastdata access should be completed or not. The value shifted out is a flag that indicates whether the Fastdata access was successful or not (if completion was requested). @section ejtagacc EJTAG Access Implementation OpenOCD reads/writes data to JTAG via mips_m4k_read_memory() and mips_m4k_write_memory() functions defined in src/target/mips_m4k.c. Internally, these functions call mips32_pracc_read_mem() and mips32_pracc_write_mem() defined in src/target/mips32_pracc.c Let's take for example function mips32_pracc_read_mem32() which describes CPU reads (fetches) from dmseg (EJTAG memory) : @code static const uint32_t code[] = { /* start: */ MIPS32_MTC0(15,31,0), /* move $15 to COP0 DeSave */ MIPS32_LUI(15,UPPER16(MIPS32_PRACC_STACK)), /* $15 = MIPS32_PRACC_STACK */ MIPS32_ORI(15,15,LOWER16(MIPS32_PRACC_STACK)), MIPS32_SW(8,0,15), /* sw $8,($15) */ MIPS32_SW(9,0,15), /* sw $9,($15) */ MIPS32_SW(10,0,15), /* sw $10,($15) */ MIPS32_SW(11,0,15), /* sw $11,($15) */ MIPS32_LUI(8,UPPER16(MIPS32_PRACC_PARAM_IN)), /* $8 = MIPS32_PRACC_PARAM_IN */ MIPS32_ORI(8,8,LOWER16(MIPS32_PRACC_PARAM_IN)), MIPS32_LW(9,0,8), /* $9 = mem[$8]; read addr */ MIPS32_LW(10,4,8), /* $10 = mem[$8 + 4]; read count */ MIPS32_LUI(11,UPPER16(MIPS32_PRACC_PARAM_OUT)), /* $11 = MIPS32_PRACC_PARAM_OUT */ MIPS32_ORI(11,11,LOWER16(MIPS32_PRACC_PARAM_OUT)), /* loop: */ MIPS32_BEQ(0,10,8), /* beq 0, $10, end */ MIPS32_NOP, MIPS32_LW(8,0,9), /* lw $8,0($9), Load $8 with the word @mem[$9] */ MIPS32_SW(8,0,11), /* sw $8,0($11) */ MIPS32_ADDI(10,10,NEG16(1)), /* $10-- */ MIPS32_ADDI(9,9,4), /* $1 += 4 */ MIPS32_ADDI(11,11,4), /* $11 += 4 */ MIPS32_B(NEG16(8)), /* b loop */ MIPS32_NOP, /* end: */ MIPS32_LW(11,0,15), /* lw $11,($15) */ MIPS32_LW(10,0,15), /* lw $10,($15) */ MIPS32_LW(9,0,15), /* lw $9,($15) */ MIPS32_LW(8,0,15), /* lw $8,($15) */ MIPS32_B(NEG16(27)), /* b start */ MIPS32_MFC0(15,31,0), /* move COP0 DeSave to $15 */ }; @endcode We have to pass this code to CPU via dongle via dmseg. After debug exception CPU will find itself stalling at the begining of the dmseg. It waits for the first instruction from dongle. This is MIPS32_MTC0(15,31,0), so CPU saves C0 and continues to addr 0xFF20 0001, which falls also to dmseg, so it stalls. Dongle proceeds giving to CPU one by one instruction in this manner. However, things are not so simple. If you take a look at the program, you will see that some instructions take operands. If it has to take operand from the address in dmseg, CPU will stall witing for the dongle to do the action of passing the operand and signal this by putting PrAcc to 0. If this operand is somewhere in RAM, CPU will not stall (it stalls only on dmseg), but it will just take it and proceed to nex instruction. But since PC for next instruction points to dmseg, it will stall, so that dongle can pass next instruction. Some instuctions are jumps (if these are jumps in dmseg addr, CPU will jump and then stall. If this is jump to some address in RAM, CPU will jump and just proceed - will not stall on addresses in RAM). To have information about CPU is currently (does it stalls wanting on operand or it jumped somewhere waiting for next instruction), OpenOCD has to call TAP ADDRESS instruction, which will ask CPU to give us his address within EJTAG memory : @code address = data = 0; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); mips_ejtag_drscan_32(ejtag_info, &address); @endcode And then, upon the results, we can conclude where it is in our code so far, so we can give it what it wants next : @code if ((address >= MIPS32_PRACC_PARAM_IN) && (address <= MIPS32_PRACC_PARAM_IN + ctx->num_iparam * 4)) { offset = (address - MIPS32_PRACC_PARAM_IN) / 4; data = ctx->local_iparam[offset]; } else if ((address >= MIPS32_PRACC_PARAM_OUT) && (address <= MIPS32_PRACC_PARAM_OUT + ctx->num_oparam * 4)) { offset = (address - MIPS32_PRACC_PARAM_OUT) / 4; data = ctx->local_oparam[offset]; } else if ((address >= MIPS32_PRACC_TEXT) && (address <= MIPS32_PRACC_TEXT + ctx->code_len * 4)) { offset = (address - MIPS32_PRACC_TEXT) / 4; data = ctx->code[offset]; } else if (address == MIPS32_PRACC_STACK) { /* save to our debug stack */ data = ctx->stack[--ctx->stack_offset]; } else { /* TODO: send JMP 0xFF200000 instruction. Hopefully processor jump back to start of debug vector */ data = 0; LOG_ERROR("Error reading unexpected address 0x%8.8" PRIx32 "", address); return ERROR_JTAG_DEVICE_ERROR; } @endcode i.e. if CPU is stalling on addresses in dmseg that are reserved for input parameters, we can conclude that it actually tried to take (read) parametar from there, and saw that address of param falls in dmseg, so it stopped. Obviously, now dongle have to give to it operand. Similarly, mips32_pracc_exec_write() describes CPU writes into EJTAG memory (dmseg). Obvioulsy, code is RO, and CPU can change only parameters : @code mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_DATA); mips_ejtag_drscan_32(ctx->ejtag_info, &data); /* Clear access pending bit */ ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC; mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_CONTROL); mips_ejtag_drscan_32(ctx->ejtag_info, &ejtag_ctrl); //jtag_add_clocks(5); jtag_execute_queue(); if ((address >= MIPS32_PRACC_PARAM_IN) && (address <= MIPS32_PRACC_PARAM_IN + ctx->num_iparam * 4)) { offset = (address - MIPS32_PRACC_PARAM_IN) / 4; ctx->local_iparam[offset] = data; } else if ((address >= MIPS32_PRACC_PARAM_OUT) && (address <= MIPS32_PRACC_PARAM_OUT + ctx->num_oparam * 4)) { offset = (address - MIPS32_PRACC_PARAM_OUT) / 4; ctx->local_oparam[offset] = data; } else if (address == MIPS32_PRACC_STACK) { /* save data onto our stack */ ctx->stack[ctx->stack_offset++] = data; } else { LOG_ERROR("Error writing unexpected address 0x%8.8" PRIx32 "", address); return ERROR_JTAG_DEVICE_ERROR; } @endcode CPU loops here : @code while (1) { if ((retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl)) != ERROR_OK) return retval; address = data = 0; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); mips_ejtag_drscan_32(ejtag_info, &address); /* Check for read or write */ if (ejtag_ctrl & EJTAG_CTRL_PRNW) { if ((retval = mips32_pracc_exec_write(&ctx, address)) != ERROR_OK) return retval; } else { /* Check to see if its reading at the debug vector. The first pass through * the module is always read at the vector, so the first one we allow. When * the second read from the vector occurs we are done and just exit. */ if ((address == MIPS32_PRACC_TEXT) && (pass++)) { break; } if ((retval = mips32_pracc_exec_read(&ctx, address)) != ERROR_OK) return retval; } if (cycle == 0) break; } @endcode and using presented R (mips32_pracc_exec_read()) and W (mips32_pracc_exec_write()) functions it reads in the code (RO) and reads and writes operands (RW). @section fdimpl OpenOCD FASTDATA Implementation OpenOCD FASTDATA write function, mips32_pracc_fastdata_xfer() is called from bulk_write_memory callback, which writes a count items of 4 bytes to the memory of a target at the an address given. Because it operates only on whole words, this should be faster than target_write_memory(). In order to implement FASTDATA write, mips32_pracc_fastdata_xfer() uses the following handler : @code uint32_t handler_code[] = { /* caution when editing, table is modified below */ /* r15 points to the start of this code */ MIPS32_SW(8,MIPS32_FASTDATA_HANDLER_SIZE - 4,15), MIPS32_SW(9,MIPS32_FASTDATA_HANDLER_SIZE - 8,15), MIPS32_SW(10,MIPS32_FASTDATA_HANDLER_SIZE - 12,15), MIPS32_SW(11,MIPS32_FASTDATA_HANDLER_SIZE - 16,15), /* start of fastdata area in t0 */ MIPS32_LUI(8,UPPER16(MIPS32_PRACC_FASTDATA_AREA)), MIPS32_ORI(8,8,LOWER16(MIPS32_PRACC_FASTDATA_AREA)), MIPS32_LW(9,0,8), /* start addr in t1 */ MIPS32_LW(10,0,8), /* end addr to t2 */ /* loop: */ /* 8 */ MIPS32_LW(11,0,0), /* lw t3,[t8 | r9] */ /* 9 */ MIPS32_SW(11,0,0), /* sw t3,[r9 | r8] */ MIPS32_BNE(10,9,NEG16(3)), /* bne $t2,t1,loop */ MIPS32_ADDI(9,9,4), /* addi t1,t1,4 */ MIPS32_LW(8,MIPS32_FASTDATA_HANDLER_SIZE - 4,15), MIPS32_LW(9,MIPS32_FASTDATA_HANDLER_SIZE - 8,15), MIPS32_LW(10,MIPS32_FASTDATA_HANDLER_SIZE - 12,15), MIPS32_LW(11,MIPS32_FASTDATA_HANDLER_SIZE - 16,15), MIPS32_LUI(15,UPPER16(MIPS32_PRACC_TEXT)), MIPS32_ORI(15,15,LOWER16(MIPS32_PRACC_TEXT)), MIPS32_JR(15), /* jr start */ MIPS32_MFC0(15,31,0), /* move COP0 DeSave to $15 */ }; @endcode In the begining and the end of the handler we have fuction prologue (save the regs that will be clobbered) and epilogue (restore regs), and in the very end, after all the xfer have been done, we do jump to the MIPS32_PRACC_TEXT address, i.e. Debug Exception Vector location. We will use this fact (that we came back to MIPS32_PRACC_TEXT) to verify later if all the handler is executed (because when in RAM, processor do not stall - it executes all instructions untill one of them do not demand access to dmseg (if one of it's opernads is there)). This handler is put into the RAM and executed from there, and not instruction by instruction, like in previous simple write (mips_m4k_write_memory()) and read (mips_m4k_read_memory()) functions. N.B. When it is executing this code in RAM, CPU will not stall on instructions, but execute all until it comes to the : @code MIPS32_LW(9,0,8) /* start addr in t1 */ @endcode and there it will stall - because it will see that one of the operands have to be fetched from dmseg (EJTAG memory, in this case FASTDATA memory segment). This handler is loaded in the RAM, ath the reserved location "work_area". This work_area is configured in OpenOCD configuration script and should be selected in that way that it is not clobbered (overwritten) by data we want to write-in using FASTDATA. What is executed instruction by instruction which is passed by dongle (via EJATG memory) is small jump code, which jumps at the handler in RAM. CPU stalls on dmseg when receiving these jmp_code instructions, but once it jumps in RAM, CPU do not stall anymore and executes bunch of handler instructions. Untill it comes to the first instruction which has an operand in FASTDATA area. There it stalls and waits on action from probe. It happens actually when CPU comes to this loop : @code MIPS32_LW(9,0,8), /* start addr in t1 */ MIPS32_LW(10,0,8), /* end addr to t2 */ /* loop: */ /* 8 */ MIPS32_LW(11,0,0), /* lw t3,[t8 | r9] */ /* 9 */ MIPS32_SW(11,0,0), /* sw t3,[r9 | r8] */ MIPS32_BNE(10,9,NEG16(3)), /* bne $t2,t1,loop */ @endcode and then it stalls because operand in r8 points to FASTDATA area. OpenOCD first verifies that CPU came to this place by : @code /* next fetch to dmseg should be in FASTDATA_AREA, check */ address = 0; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); mips_ejtag_drscan_32(ejtag_info, &address); if (address != MIPS32_PRACC_FASTDATA_AREA) return ERROR_FAIL; @endcode and then passes to CPU start and end address of the loop region for handler in RAM. In the loop in handler, CPU sees that it has to take and operand from FSTDATA area (to write it to the dst in RAM after), and so it stalls, putting PrAcc to "1". OpenOCD fills the data via this loop : @code for (i = 0; i < count; i++) { /* Send the data out using fastdata (clears the access pending bit) */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_FASTDATA); if ((retval = mips_ejtag_fastdata_scan(ejtag_info, write_t, buf++)) != ERROR_OK) return retval; } @endcode Each time when OpenOCD fills data to CPU (via dongle, via dmseg), CPU takes it and proceeds in executing the endler. However, since handler is in a assembly loop, CPU comes to next instruction which also fetches data from FASTDATA area. So it stalls. Then OpenOCD fills the data again, from it's (OpenOCD's) loop. And this game continues untill all the data has been filled. After the last data has beend given to CPU it sees that it reached the end address, so it proceeds with next instruction. However, rhis instruction do not point into dmseg, so CPU executes bunch of handler instructions (all prologue) and in the end jumps to MIPS32_PRACC_TEXT address. On it's side, OpenOCD checks in CPU has jumped back to MIPS32_PRACC_TEXT, which is the confirmation that it correclty executed all the rest of the handler in RAM, and that is not stuck somewhere in the RAM, or stalling on some acces in dmseg - that would be an error : @code address = 0; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); mips_ejtag_drscan_32(ejtag_info, &address); if (address != MIPS32_PRACC_TEXT) LOG_ERROR("mini program did not return to start"); @endcode @section fdejtagspec EJTAG spec on FASTDATA access The width of the Fastdata register is 1 bit. During a Fastdata access, the Fastdata register is written and read, i.e., a bit is shifted in and a bit is shifted out. During a Fastdata access, the Fastdata register value shifted in specifies whether the Fastdata access should be completed or not. The value shifted out is a flag that indicates whether the Fastdata access was successful or not (if completion was requested). The FASTDATA access is used for efficient block transfers between dmseg (on the probe) and target memory (on the processor). An "upload" is defined as a sequence of processor loads from target memory and stores to dmseg. A "download" is a sequence of processor loads from dmseg and stores to target memory. The "Fastdata area" specifies the legal range of dmseg addresses (0xFF20.0000 - 0xFF20.000F) that can be used for uploads and downloads. The Data + Fastdata registers (selected with the FASTDATA instruction) allow efficient completion of pending Fastdata area accesses. During Fastdata uploads and downloads, the processor will stall on accesses to the Fastdata area. The PrAcc (processor access pending bit) will be 1 indicating the probe is required to complete the access. Both upload and download accesses are attempted by shifting in a zero SPrAcc value (to request access completion) and shifting out SPrAcc to see if the attempt will be successful (i.e., there was an access pending and a legal Fastdata area address was used). Downloads will also shift in the data to be used to satisfy the load from dmseg’s Fastdata area, while uploads will shift out the data being stored to dmseg’s Fastdata area. As noted above, two conditions must be true for the Fastdata access to succeed. These are: - PrAcc must be 1, i.e., there must be a pending processor access. - The Fastdata operation must use a valid Fastdata area address in dmseg (0xFF20.0000 to 0xFF20.000F). Basically, because FASTDATA area in dmseg is 16 bytes, we transfer (0xFF20.0000 - 0xFF20.000F) FASTDATA scan TAP instruction selects the Data and the Fastdata registers at once. They come in order : TDI -> | Data register| -> | Fastdata register | -> TDO FASTDATA register is 1-bit width register. It takes in SPrAcc bit which should be shifted first, followed by 32 bit of data. Scan width of FASTDTA is 33 bits in total : 33 bits are shifted in and 33 bits are shifted out. First bit that is shifted out is SPrAcc that comes out of Fastdata register and should give us status on FATSDATA write we want to do. @section fdcheck OpenOCD misses FASTDATA check Download flow (probe -> target block transfer) : 1) Probe transfer target execution to a loop in target memory doing a fixed number of "loads" to fastdata area of dmseg (and stores to the target download destination.) 2) Probe loops attempting to satisfy the loads "expected" from the target. On FASTDATA access "successful" move on to next "load". On FASTDATA access "failure" repeat until "successful" or timeout. (A "failure" is an attempt to satisfy an access when none are pending.) Note: A failure may have a recoverable (and even expected) cause like slow target execution of the load loop. Other failures may be due to unexpected more troublesome causes like an exception while in debug mode or a target hang on a bad target memory access. Shifted out SPrAcc bit inform us that there was CPU access pendingand that it can be complete. Basically, we should do following procedure : - Download (dongle -> CPU) : You shift "download" DATA and FASTDATA[SPrAcc] = 0 (33 bit scan) into the target. If the value of FASTDATA[SPrAcc] shifted out is "1" then an access was pending when you started the scan and it is now complete. If SPrAcc is 0 then no access was pending to the fastdata area. (Repeat attempt to complete the access you expect for this data word. Timeout if you think the access is "long overdue" as something unexpected has happened.) - Upload (CPU -> dongle) : You shift "dummy" DATA and FASTDATA[SPrAcc] = 0 (33 bit scan) into the target. If the value of FASTDATA[SPrAcc] shifted out is "1" then an access was pending when you started the scan and it is now complete. The "upload" is the DATA shifted out of the target. If SPrAcc is 0 then no access was pending to the fastdata area. (Repeat attempt to complete the access you expect for this data word. Timeout if you think the access is "long overdue" as something unexpected has happened.) Basically, if checking first (before scan) if CPU is pending on FASTDATA access (PrAcc is "1"), like this @code wait(ready); do_scan(); @endcode which is inefficient, we should do it like this : @code BEGIN : do_scan(); if (!was_ready) goto BEGIN; @endcode by checking SPrAcc that we shifted out. If some FASTDATA write fails, OpenOCD will continue with it's loop (on the host side), but CPU will rest pending (on the target side) waiting for correct FASTDATA write. Since OpenOCD goes ahead, it will eventually finish it's loop, and proceede to check if CPU took all the data. But since CPU did not took all the data, it is still turns in handler's loop in RAM, stalling on Fastdata area so this check : @code address = 0; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); retval = mips_ejtag_drscan_32(ejtag_info, &address); if (retval != ERROR_OK) return retval; if (address != MIPS32_PRACC_TEXT) LOG_ERROR("mini program did not return to start"); @endcode fails, and that gives us enough information of the failure. In this case, we can lower the JTAG frquency and try again, bacuse most probable reason of this failure is that we tried FASTDATA upload before CPU arrived to rise PrAcc (i.e. before it was pending on access). However, the reasons for failure might be numerous : reset, exceptions which can occur in debug mode, bus hangs, etc. If lowering the JTAG freq does not work either, we can fall back to more robust solution with patch posted below. To summarize, FASTDATA communication goes as following : -# CPU jumps to Debug Exception Vector Location 0xFF200200 in dmseg and it stalls, pending and waiting for EJTAG to give it first debug instruction and signall it by putting PrAcc to "0" -# When PrAcc goes to "0" CPU execute one opcode sent by EJTAG via DATA reg. Then it pends on next access, waiting for PrAcc to be put to "0" again -# Following this game, OpenOCD first loads handler code in RAM, and then sends the jmp_code - instruction by instruction via DATA reg, which redirects CPU to handler previously set up in RAM -# Once in RAM CPU does not pend on any instruction, but it executes all handler instructions untill first "fetch" to Fastdata area - then it stops and pends. -# So - when it comes to any instruction (opcode) in this handler in RAM which reads (or writes) to Fastdata area (0xF..F20.0000 to 0xF..F20.000F), CPU stops (i.e. stalls access). I.e. it stops on this lw opcode and waits to FASTDATA TAP command from the probe. -# CPU continues only if OpenOCD shifted in SPrAcc "0" (and if the PrAcc was "1"). It shifts-out "1" to tell us that it was OK (processor was stalled, so it can complete the access), and that it continued execution of the handler in RAM. -# If PrAcc was not "1" CPU will not continue (go to next instruction), but will shift-out "0" and keep stalling on the same instruction of my handler in RAM. -# When Fastdata loop is finished, CPU executes all following hadler instructions in RAM (prologue). -# In the end of my handler in RAM, I jumps back to begining of Debug Exception Vector Location 0xFF200200 in dmseg. -# When it jumps back to 0xFF200200 in dmseg processor stops and pends, waiting for OpenOCD to send it instruction via DATA reg and signal it by putting PrAcc to "0". */ openocd-0.7.0/doc/manual/flash.txt0000644000175000001440000000142112134336410013735 00000000000000/** @page flashdocs OpenOCD Flash APIs OpenOCD provides its Flash APIs for developers to support different types of flash devices, some of which are built-in to target devices while others may be connected via standard memory interface (e.g. CFI, FMI, etc.). The Flash module provides the following APIs: - @subpage flashcfi - @subpage flashnand - @subpage flashtarget This section needs to be expanded. */ /** @page flashcfi OpenOCD CFI Flash API This section needs to be expanded to describe OpenOCD's CFI Flash API. */ /** @page flashnand OpenOCD NAND Flash API This section needs to be expanded to describe OpenOCD's NAND Flash API. */ /** @page flashtarget OpenOCD Target Flash API This section needs to be expanded to describe OpenOCD's Target Flash API. */ openocd-0.7.0/doc/manual/style.txt0000644000175000001440000004105412134336410014006 00000000000000/** @page styleguide Style Guides The goals for each of these guides are: - to produce correct code that appears clean, consistent, and readable, - to allow developers to create patches that conform to a standard, and - to eliminate these issues as points of future contention. Some of these rules may be ignored in the spirit of these stated goals; however, such exceptions should be fairly rare. The following style guides describe a formatting, naming, and other conventions that should be followed when writing or changing the OpenOCD code: - @subpage styletcl - @subpage stylec - @subpage styleperl - @subpage styleautotools In addition, the following style guides provide information for providing documentation, either as part of the C code or stand-alone. - @subpage styledoxygen - @subpage styletexinfo - @subpage stylelatex Feedback would be welcome to improve the OpenOCD guidelines. */ /** @page styletcl TCL Style Guide OpenOCD needs to expand its Jim/TCL Style Guide. Many of the guidelines listed on the @ref stylec page should apply to OpenOCD's Jim/TCL code as well. */ /** @page stylec C Style Guide This page contains guidelines for writing new C source code for the OpenOCD project. @section styleformat Formatting Guide - remove any trailing white space at the end of lines. - use TAB characters for indentation; do NOT use spaces. - displayed TAB width is 4 characters. - use Unix line endings ('\\n'); do NOT use DOS endings ('\\r\\n') - limit adjacent empty lines to at most two (2). - remove any trailing empty lines at the end of source files - do not "comment out" code from the tree; instead, one should either: -# remove it entirely (git can retrieve the old version), or -# use an @c \#if/\#endif block. Finally, try to avoid lines of code that are longer than than 72-80 columns: - long lines frequently indicate other style problems: - insufficient use of static functions, macros, or temporary variables - poor flow-control structure; "inverted" logical tests - a few lines may be wider than this limit (typically format strings), but: - all C compilers will concatenate series of string constants. - all long string constants should be split across multiple lines. @section stylenames Naming Rules - most identifiers must use lower-case letters (and digits) only. - macros must use upper-case letters (and digits) only. - OpenOCD identifiers should NEVER use @c MixedCaps. - @c typedef names must end with the '_t' suffix. - This should be reserved for types that should be passed by value. - Do @b not mix the typedef keyword with @c struct. - use underline characters between consecutive words in identifiers (e.g. @c more_than_one_word). @section stylec99 C99 Rules - inline functions - @c // comments -- in new code, prefer these for single-line comments - trailing comma allowed in enum declarations - designated initializers ( .field = value ) - variables declarations should occur at the point of first use - new block scopes for selection and iteration statements - use malloc() to create dynamic arrays. Do @b not use @c alloca or variable length arrays on the stack. non-MMU hosts(uClinux) and pthreads require modest and predictable stack usage. @section styletypes Type Guidelines - use native types (@c int or @c unsigned) if the type is not important - if size matters, use the types from \ or \: - @c int8_t, @c int16_t, @c int32_t, or @c int64_t: signed types of specified size - @c uint8_t, @c uint16_t, @c uint32_t, or @c uint64_t: unsigned types of specified size - do @b NOT redefine @c uN types from "types.h" @section stylefunc Functions - static inline functions should be prefered over macros: @code /** do NOT define macro-like functions like this... */ #define CUBE(x) ((x) * (x) * (x)) /** instead, define the same expression using a C99 inline function */ static inline int cube(int x) { return x * x * x; } @endcode - Functions should be declared static unless required by other modules - define static functions before first usage to avoid forward declarations. - Functions should have no space between its name and its parameter list: @code int f(int x1, int x2) { ... int y = f(x1, x2 - x1); ... } @endcode - Separate assignment and logical test statements. In other words, you should write statements like the following: @code // separate statements should be preferred result = foo(); if (ERROR_OK != result) ... @endcode More directly, do @b not combine these kinds of statements: @code // Combined statements should be avoided if (ERROR_OK != (result = foo())) return result; @endcode */ /** @page styledoxygen Doxygen Style Guide The following sections provide guidelines for OpenOCD developers who wish to write Doxygen comments in the code or this manual. For an introduction to Doxygen documentation, see the @ref primerdoxygen. @section styledoxyblocks Doxygen Block Selection Several different types of Doxygen comments can be used; often, one style will be the most appropriate for a specific context. The following guidelines provide developers with heuristics for selecting an appropriate form and writing consistent documentation comments. -# use @c /// to for one-line documentation of instances. -# for documentation requiring multiple lines, use a "block" style: @verbatim /** * @brief First sentence is short description. Remaining text becomes * the full description block, where "empty" lines start new paragraphs. * * One can make text appear in @a italics, @b bold, @c monospace, or * in blocks such as the one in which this example appears in the Style * Guide. See the Doxygen Manual for the full list of commands. * * @param foo For a function, describe the parameters (e.g. @a foo). * @returns The value(s) returned, or possible error conditions. */ @endverbatim -# The block should start on the line following the opening @c /**. -# The end of the block, \f$*/\f$, should also be on its own line. -# Every line in the block should have a @c '*' in-line with its start: - A leading space is required to align the @c '*' with the @c /** line. - A single "empty" line should separate the function documentation from the block of parameter and return value descriptions. - Except to separate paragraphs of documentation, other extra "empty" lines should be removed from the block. -# Only single spaces should be used; do @b not add mid-line indentation. -# If the total line length will be less than 72-80 columns, then - The @c /**< form can be used on the same line. - This style should be used sparingly; the best use is for fields: @code int field; /**< field description */ @endcode @section styledoxyall Doxygen Style Guide The following guidelines apply to all Doxygen comment blocks: -# Use the @c '\@cmd' form for all doxygen commands (do @b not use @c '\\cmd'). -# Use symbol names such that Doxygen automatically creates links: -# @c function_name() can be used to reference functions (e.g. flash_set_dirty()). -# @c struct_name::member_name should be used to reference structure fields in the documentation (e.g. @c flash_driver::name). -# URLS get converted to markup automatically, without any extra effort. -# new pages can be linked into the heirarchy by using the @c \@subpage command somewhere the page(s) under which they should be linked: -# use @c \@ref in other contexts to create links to pages and sections. -# Use good Doxygen mark-up: -# '\@a' (italics) should be used to reference parameters (e.g. foo). -# '\@b' (bold) should be used to emphasizing single words. -# '\@c' (monospace) should be used with file names and code symbols, so they appear visually distinct from surrounding text. -# To mark-up multiple words, the HTML alternatives must be used. -# Two spaces should be used when nesting lists; do @b not use '\\t' in lists. -# Code examples provided in documentation must conform to the Style Guide. @section styledoxytext Doxygen Text Inputs In addition to the guidelines in the preceding sections, the following additional style guidelines should be considered when writing documentation as part of standalone text files: -# Text files must contain Doxygen at least one comment block: -# Documentation should begin in the first column (except for nested lists). -# Do NOT use the @c '*' convention that must be used in the source code. -# Each file should contain at least one @c \@page block. -# Each new page should be listed as a \@subpage in the \@page block of the page that should serve as its parent. -# Large pages should be structure in parts using meaningful \@section and \@subsection commands. -# Include a @c \@file block at the end of each Doxygen @c .txt file to document its contents: - Doxygen creates such pages for files automatically, but no content will appear on them for those that only contain manual pages. - The \@file block should provide useful meta-documentation to assist techincal writers; typically, a list of the pages that it contains. - For example, the @ref styleguide exists in @c doc/manual/style.txt, which contains a reference back to itself. -# The \@file and \@page commands should begin on the same line as the start of the Doxygen comment: @verbatim /** @page pagename Page Title Documentation for the page. */ /** @file This file contains the @ref pagename page. */ @endverbatim For an example, the Doxygen source for this Style Guide can be found in @c doc/manual/style.txt, alongside other parts of The Manual. */ /** @page styletexinfo Texinfo Style Guide The User's Guide is there to provide two basic kinds of information. It is a guide for how and why to use each feature or mechanism of OpenOCD. It is also the reference manual for all commands and options involved in using them, including interface, flash, target, and other drivers. At this time, it is the only user-targetted documentation; everything else is addressing OpenOCD developers. There are two key audiences for the User's Guide, both developer based. The primary audience is developers using OpenOCD as a tool in their work, or who may be starting to use it that way. A secondary audience includes developers who are supporting those users by packaging or customizing it for their hardware, installing it as part of some software distribution, or by evolving OpenOCD itself. There is some crossover between those audiences. We encourage contributions from users as the fundamental way to evolve and improve OpenOCD. In particular, creating a board or target specific configuration file is something that many users will end up doing at some point, and we like to see such files become part of the mainline release. General documentation rules to remember include: - Be concise and clear. It's work to remove those extra words and sentences, but such "noise" doesn't help readers. - Make it easy to skim and browse. "Tell what you're going to say, then say it". Help readers decide whether to dig in now, or leave it for later. - Make sure the chapters flow well. Presentations should not jump around, and should move easily from overview down to details. - Avoid using the passive voice. - Address the reader to clarify roles ("your config file", "the board you are debugging", etc.); "the user" (etc) is artificial. - Use good English grammar and spelling. Remember also that English will not be the first language for many readers. Avoid complex or idiomatic usage that could create needless barriers. - Use examples to highlight fundamental ideas and common idioms. - Don't overuse list constructs. This is not a slide presentation; prefer paragraphs. When presenting features and mechanisms of OpenOCD: - Explain key concepts before presenting commands using them. - Tie examples to common developer tasks. - When giving instructions, you can \@enumerate each step both to clearly delineate the steps, and to highlight that this is not explanatory text. - When you provide "how to use it" advice or tutorials, keep it in separate sections from the reference material. - Good indexing is something of a black art. Use \@cindex for important concepts, but don't overuse it. In particular, rely on the \@deffn indexing, and use \@cindex primarily with significant blocks of text such as \@subsection. The \@dfn of a key term may merit indexing. - Use \@xref (and \@anchor) with care. Hardcopy versions, from the PDF, must make sense without clickable links (which don't work all that well with Texinfo in any case). If you find you're using many links, read that as a symptom that the presentation may be disjointed and confusing. - Avoid font tricks like \@b, but use \@option, \@file, \@dfn, \@emph and related mechanisms where appropriate. For technical reference material: - It's OK to start sections with explanations and end them with detailed lists of the relevant commands. - Use the \@deffn style declarations to define all commands and drivers. These will automatically appear in the relevant index, and those declarations help promote consistent presentation and style. - It's a "Command" if it can be used interactively. - Else it's a "Config Command" if it must be used before the configuration stage completes. - For a "Driver", list its name. - Use EBNF style regular expressions to define parameters: brackets around zero-or-one choices, parentheses around exactly-one choices. - Use \@option, \@file, \@var and other mechanisms where appropriate. - Say what output it displays, and what value it returns to callers. - Explain clearly what the command does. Sometimes you will find that it can't be explained clearly. That usually means the command is poorly designed; replace it with something better, if you can. - Be complete: document all commands, except as part of a strategy to phase something in or out. - Be correct: review the documentation against the code, and vice versa. - Alphabetize the \@defn declarations for all commands in each section. - Keep the per-command documentation focussed on exactly what that command does, not motivation, advice, suggestions, or big examples. When commands deserve such expanded text, it belongs elsewhere. Solutions might be using a \@section explaining a cluster of related commands, or acting as a mini-tutorial. - Details for any given driver should be grouped together. The User's Guide is the first place most users will start reading, after they begin using OpenOCD. Make that investment of their time be as productive as possible. Needing to look at OpenOCD source code, to figure out how to use it is a bad sign, though it's OK to need to look at the User's guide to figure out what a config script is doing. */ /** @page stylelatex LaTeX Style Guide This page needs to provide style guidelines for using LaTeX, the typesetting language used by The References for OpenOCD Hardware. Likewise, the @ref primerlatex for using this guide needs to be completed. */ /** @page styleperl Perl Style Guide This page provides some style guidelines for using Perl, a scripting language used by several small tools in the tree: -# Ensure all Perl scripts use the proper suffix (@c .pl for scripts, and @c .pm for modules) -# Pass files as script parameters or piped as input: - Do NOT code paths to files in the tree, as this breaks out-of-tree builds. - If you must, then you must also use an automake rule to create the script. -# use @c '#!/usr/bin/perl' as the first line of Perl scripts. -# always use strict and use warnings -# invoke scripts indirectly in Makefiles or other scripts: @code perl script.pl @endcode Maintainers must also be sure to follow additional guidelines: -# Ensure that Perl scripts are committed as executables: Use "chmod +x script.pl" @a before using "git add script.pl" */ /** @page styleautotools Autotools Style Guide This page contains style guidelines for the OpenOCD autotools scripts. The following guidelines apply to the @c configure.ac file: - Better guidelines need to be developed, but until then... - Use good judgement. The following guidelines apply to @c Makefile.am files: -# When assigning variables with long lists of items: -# Separate the values on each line to make the files "patch friendly": @code VAR = \ value1 \ value2 \ ... value9 \ value10 @endcode */ /** @file This file contains the @ref styleguide pages. The @ref styleguide pages include the following Style Guides for their respective code and documentation languages: - @ref styletcl - @ref stylec - @ref styledoxygen - @ref styletexinfo - @ref stylelatex - @ref styleperl - @ref styleautotools */ openocd-0.7.0/doc/manual/scripting.txt0000644000175000001440000000604212134336410014646 00000000000000/** @page scripting Scripting Overview @section scriptingisnt What scripting will not do The scripting support is intended for developers of OpenOCD. It is not the intention that normal OpenOCD users will use tcl scripting extensively, write lots of clever scripts, or contribute back to OpenOCD. Target scripts can contain new procedures that end users may tinker to their needs without really understanding tcl. Since end users are not expected to mess with the scripting language, the choice of language is not terribly important to those same end users. Jim Tcl was chosen as it was easy to integrate, works great in an embedded environment and Øyvind Harboe had experience with it. @section scriptinguses Uses of scripting Default implementation of procedures in tcl/procedures.tcl. - Polymorphic commands for target scripts. - there will be added some commands in Tcl that the target scripts can replace. - produce \ \. Default implementation is to ignore serial number and write a raw binary file to beginning of first flash. Target script can dictate file format and structure of serialnumber. Tcl allows an argument to consist of e.g. a list so the structure of the serial number is not limited to a single string. - reset handling. Precise control of how srst, trst & tms is handled. - replace some parts of the current command line handler. This is only to simplify the implementation of OpenOCD and will have no externally visible consequences. Tcl has an advantage in that it's syntax is backwards compatible with the current OpenOCD syntax. - external scripting. Low level tcl functions will be defined that return machine readable output. These low level tcl functions constitute the tcl api. flash_banks is such a low level tcl proc. "flash banks" is an example of a command that has human readable output. The human readable output is expected to change inbetween versions of OpenOCD. The output from flash_banks may not be in the preferred form for the client. The client then has two choices a) parse the output from flash_banks or b) write a small piece of tcl to output the flash_banks output to a more suitable form. The latter may be simpler. @section scriptingexternal External scripting The embedded Jim Tcl interpreter in OpenOCD is very limited compared to any full scale PC hosted scripting language. The goal is to keep the internal Jim Tcl interpreter as small as possible and allow any advanced scripting, especially scripting that interacts with the host, run on the host and talk to OpenOCD via the TCP/IP scripting connection. Another problem with Jim Tcl is that there is no debugger for it. With a bit of trickery it should be possible to run Jim Tcl scripts under a Tcl interpreter on a PC. The advantage would be that the Jim Tcl scripts could be debugged using a standard PC Tcl debugger. The rough idea is to write an unknown proc that sends unknown commands to OpenOCD. Basically a PC version of startup.tcl. Patches most gratefully accepted! :-) */ openocd-0.7.0/doc/manual/primer/0000755000175000001440000000000012141414413013455 500000000000000openocd-0.7.0/doc/manual/primer/jtag.txt0000644000175000001440000001521412134336410015070 00000000000000/** @page primerjtag OpenOCD JTAG Primer JTAG is unnecessarily confusing, because JTAG is often confused with boundary scan, which is just one of its possible functions. JTAG is simply a communication interface designed to allow communication to functions contained on devices, for the designed purposes of initialisation, programming, testing, debugging, and anything else you want to use it for (as a chip designer). Think of JTAG as I2C for testing. It doesn't define what it can do, just a logical interface that allows a uniform channel for communication. See @par http://en.wikipedia.org/wiki/Joint_Test_Action_Group and @par http://www.inaccessnetworks.com/projects/ianjtag/jtag-intro/jtag-state-machine-large.png The first page (among other things) shows a logical representation describing how multiple devices are wired up using JTAG. JTAG does not specify, data rates or interface levels (3.3V/1.8V, etc) each device can support different data rates/interface logic levels. How to wire them in a compatible way is an exercise for an engineer. Basically TMS controls which shift register is placed on the device, between TDI and TDO. The second diagram shows the state transitions on TMS which will select different shift registers. The first thing you need to do is reset the state machine, because when you connect to a chip you do not know what state the controller is in,you need to clock TMS as 1, at least 5 times. This will put you into "Test Logic Reset" State. Knowing this, you can, once reset, then track what each transition on TMS will do, and hence know what state the JTAG state machine is in. There are 2 "types" of shift registers. The Instruction shift register and the data shift register. The sizes of these are undefined, and can change from chip to chip. The Instruction register is used to select which Data register/data register function is used, and the data register is used to read data from that function or write data to it. Each of the states control what happens to either the data register or instruction register. For example, one of the data registers will be known as "bypass" this is (usually) a single bit which has no function and is used to bypass the chip. Assume we have 3 identical chips, wired up like the picture(wikipedia) and each has a 3 bits instruction register, and there are 2 known instructions (110 = bypass, 010 = "some other function") if we want to use "some other function", on the second chip in the line, and not change the other chips we would do the following transitions. From Test Logic Reset, TMS goes: 0 1 1 0 0 which puts every chip in the chain into the "Shift IR state" Then (while holding TMS as 0) TDI goes: 0 1 1 0 1 0 0 1 1 which puts the following values in the instruction shift register for each chip [110] [010] [110] The order is reversed, because we shift out the least significant bit first. Then we transition TMS: 1 1 1 0 0 which puts us in the "Shift DR state". Now when we clock data onto TDI (again while holding TMS to 0) , the data shifts through the data registers, and because of the instruction registers we selected ("some other function" has 8 bits in its data register), our total data register in the chain looks like this: 0 00000000 0 The first and last bit are in the "bypassed" chips, so values read from them are irrelevant and data written to them is ignored. But we need to write bits for those registers, because they are in the chain. If we wanted to write 0xF5 to the data register we would clock out of TDI (holding TMS to 0): 0 1 0 1 0 1 1 1 1 0 Again, we are clocking the least-significant bit first. Then we would clock TMS: 1 1 0 which updates the selected data register with the value 0xF5 and returns us to run test idle. If we needed to read the data register before over-writing it with F5, no sweat, that's already done, because the TDI/TDO are set up as a circular shift register, so if you write enough bits to fill the shift register, you will receive the "captured" contents of the data registers simultaneously on TDO. That's JTAG in a nutshell. On top of this, you need to get specs for target chips and work out what the various instruction registers/data registers do, so you can actually do something useful. That's where it gets interesting. But in and of itself, JTAG is actually very simple. @section primerjtag More Reading A separate primer contains information about @subpage primerjtagbs for developers that want to extend OpenOCD for such purposes. */ /** @page primerjtagbs JTAG Boundary Scan Primer The following page provides an introduction on JTAG that focuses on its boundary scan capabilities: @par http://www.engr.udayton.edu/faculty/jloomis/ece446/notes/jtag/jtag1.html OpenOCD does not presently have clear means of using JTAG for boundary scan testing purposes; however, some developers have explored the possibilities. The page contains information that may be useful to those wishing to implement boundary scan capabilities in OpenOCD. @section primerbsdl The BSDL Language For more information on the Boundary Scan Description Language (BSDL), the following page provides a good introduction: @par http://www.radio-electronics.com/info/t_and_m/boundaryscan/bsdl.php @section primerbsdlvendors Vendor BSDL Files NXP LPC: @par http://www.standardics.nxp.com/support/models/lpc2000/ Freescale PowerPC: @par http://www.freescale.com/webapp/sps/site/overview.jsp?code=DRPPCBSDLFLS Freescale i.MX1 (too old): @par http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=i.MX1&nodeId=0162468rH311432973ZrDR&fpsp=1&tab=Design_Tools_Tab Renesas R32C/117: @par http://sg.renesas.com/fmwk.jsp?cnt=r32c116_7_8_root.jsp&fp=/products/mpumcu/m16c_family/r32c100_series/r32c116_7_8_group/ - The device page does not come with BSDL file; you have to register to download them. @par http://www.corelis.com/support/BSDL.htm TI links theirs right off the generic page for each chip; this may be the case for other vendors as well. For example: - DaVinci DM355 -- http://www.ti.com/litv/zip/sprm262b - DaVinci DM6446 - 2.1 silicon -- http://www.ti.com/litv/zip/sprm325a - older silicon -- http://www.ti.com/litv/zip/sprm203 - OMAP 3530 - CBB package -- http://www.ti.com/litv/zip/sprm315b - 515 ball s-PGBA, POP, 0.4mm pitch - CUS package -- http://www.ti.com/litv/zip/sprm314a - 515 ball s-PGBA, POP, 0.5mm pitch - CBC package -- http://www.ti.com/litv/zip/sprm346 - 423 ball s-PGBA, 0.65mm pitch Many other files are available in the "Semiconductor Manufacturer's BSDL files" section of the following site: @par http://www.freelabs.com/~whitis/electronics/jtag/ */ /** @file This file contains the @ref primerjtag and @ref primerjtagbs page. */ openocd-0.7.0/doc/manual/primer/docs.txt0000644000175000001440000001220612134336410015071 00000000000000/** @page primerdocs OpenOCD Documentation Primers This page provides an introduction to OpenOCD's documentation processes. OpenOCD presently produces several kinds of documentation: - The User's Guide: - Focuses on using the OpenOCD software. - Details the installation, usage, and customization. - Provides descriptions of public Jim/TCL script commands. - Written using GNU texinfo. - Created with 'make pdf' or 'make html'. - See @subpage primertexinfo and @ref styletexinfo. - The References: (as proposed) - Focuses on using specific hardware with OpenOCD. - Details the supported interfaces, chips, boards, and targets. - Provides overview, usage, reference, and FAQ for each device. - Written using LaTeX language with custom macros. - Created with 'make references'. - See @subpage primerlatex and @ref stylelatex. - The Manual: - Focuses on developing the OpenOCD software. - Details the architecutre, driver interfaces, and processes. - Provides "full" coverage of C source code (work-in-progress). - Written using Doxygen C language conventions (i.e. in comments). - Created with 'make doxygen'. - See @subpage primerdoxygen and @ref styledoxygen. The following sections provide more information for anyone that wants to contribute new or updated documentation to the OpenOCD project. */ /** @page primertexinfo Texinfo Primer The OpenOCD User's Guide presently exists entirely within the doc/openocd.texi document. That file contains documentation with mark-up suitable for being parsed by the GNU Texinfo utilities (http://www.gnu.org/software/texinfo/). When you add a new command, driver, or driver option, it needs to be documented in the User's Guide. Use the existing documentation for models, but feel free to make better use of Texinfo mechanisms. See the Texinfo web site for the Texinfo manual and more information. OpenOCD style guidelines for Texinfo documentation can be found on the @ref styletexinfo page. */ /** @page primerlatex LaTeX Primer The OpenOCD project provides a number of reference guides using the LaTeX typesetting language. - OpenOCD Quick Reference Sheets - OpenOCD Hardware Reference Guides These documents have not yet been produced, so this Primer serves as a placeholder to describe how they are created and can be extended. The same holds true for the @ref stylelatex page. */ /** @page primerdoxygen Doxygen Primer Doxygen-style comments are used to provide documentation in-line with the OpenOCD source code. These comments are used to document functions, variables, structs, enums, fields, and everything else that might need to be documented for developers. Additional files containing comments that supplement the code comments in order to provide complete developer documentation. Even if you already know Doxygen, please read this Primer to learn how OpenOCD developers already use Doxygen features in the project tree. For more information about OpenOCD's required style for using Doxygen, see the @ref styledoxygen page and look at existing documentation in the @c doc/manual tree. @section primerdoxytext Doxygen Input Files Doxygen has been configured parse all of the C source code files (*.c and *.h) in @c src/ in order to produce a complete reference of all OpenOCD project symbols. In addition to the source code files, other files will also be scanned for comment blocks; some are referenced explicitly by the @c INPUT variable in the Doxygen configuration file. By default, the Doxygen configuration enables a "full" set of features, including generation of dependency graphs (using the GraphViz package). These features may be disabled by editing the @c Doxyfile.in file at the top of the project tree; the configuration file includes comments that provide detailed documentation for each option. To support out-of-tree building of the documentation, the @c Doxyfile.in @c INPUT values will have all instances of the string @c "@srcdir@" replaced with the current value of the make variable $(srcdir). The Makefile uses a rule to convert @c Doxyfile.in into the @c Doxyfile used by make doxygen. @section primerdoxyoocd OpenOCD Input Files OpenOCD uses the @c INPUT mechanism to include additional documentation to provide The Manual for OpenOCD Developers. These extra files contain high-level information intended to supplement the relatively low-level documentation that gets extracted from the source code comments. OpenOCD's Doxygen configuration file will search for all @c .txt files that can be found under the @c doc/manual directory in the project tree. New files containing valid Doxygen markup that are placed in or under that directory will be detected and included in The Manual automatically. @section primerdoxyman Doxygen Reference Manual The full documentation for Doxygen can be referenced on-line at the project home page: http://www.doxygen.org/index.html. In HTML versions of this document, an image with a link to this site appears in the page footer. */ /** @file This file contains the Doxygen source code for the @ref primerdocs. The @ref primerdocs page also contains the following sections: - @ref primertexinfo - @ref primerlatex - @ref primerdoxygen */ openocd-0.7.0/doc/manual/primer/tcl.txt0000644000175000001440000002770412134336410014734 00000000000000/** @page primertcl OpenOCD TCL Primer The @subpage scripting page provides additional TCL Primer material. @verbatim **************************************** **************************************** This is a short introduction to 'un-scare' you about the language known as TCL. It is structured as a guided tour through the files written by me [Duane Ellis] - in early July 2008 for OpenOCD. Which uses the "JIM" embedded Tcl clone-ish language. Thing described here are *totally* TCL generic... not Jim specific. The goal of this document is to encourage you to add your own set of chips to the TCL package - and most importantly you should know where you should put them - so they end up in an organized way. --Duane Ellis. duane@duaneellis.com **************************************** **************************************** Adding "chip" support - Duane Ellis July 5 - 2008. The concept is this: In your "openocd.cfg" file add something like this: source [find tcl/chip/VENDOR/FAMILY/NAME.tcl] For example... source [find tcl/chip/atmel/at91/at91sam7x256.tcl] You'll notice that it makes use of: tcl/cpu/arm/.tcl. Yes, that is where you should put "core" specific things. Be careful and learn the difference: THE "CORE" - is not the entire chip! Definition: That "file" listed above is called a "CHIP FILE". It may be standalone, or may need to "source" other "helper" files. The reference [7/5/2008] is the at91sam7x256.tcl file. **************************************** **************************************** === TCL TOUR === Open: at91sam7x256.tcl === TCL TOUR === A walk through --- For those who are new to TCL. Examine the file: at91sam7x256.tcl It starts with: source [find path/filename.tcl] In TCL - this is very important. Rule #1 Everything is a string. Rule #2 If you think other wise See #1. Reminds you of: Rule #1: The wife is correct. Rule #2: If you think otherwise, See #1 Any text contained inside of [square-brackets] is just like `back-ticks` in BASH. Hence, the [find FILENAME] executes the command find with a single parameter the filename. ======================================== Next you see a series of: set NAME VALUE It is mostly "obvious" what is going on. Exception: The arrays. You would *THINK* Tcl supports arrays. In fact, multi-dim arrays. That is false. For the index for"FLASH(0,CHIPSELECT)" is actually the string "0,CHIPSELECT". This is problematic. In the normal world, you think of array indexes as integers. For example these are different: set foo(0x0c) 123 set foo(12) 444 Why? Because 0x0c {lowercase} is a string. Don't forget UPPER CASE. You must be careful - always... always... use simple decimal numbers. When in doubt use 'expr' the evaluator. These are all the same. set x 0x0c set foo([expr $x]) "twelve" set x 12 set foo([expr $x]) "twelve" set x "2 * 6" set foo([expr $x]) "twelve" ************************************************** *************************************************** === TCL TOUR === Open the file: "bitsbytes.tcl" There is some tricky things going on. =============== First, there is a "for" loop - at level 0 {level 0 means: out side of a proc/function} This means it is evaluated when the file is parsed. == SIDEBAR: About The FOR command == In TCL, "FOR" is a funny thing, it is not what you think it is. Syntactically - FOR is a just a command, it is not language construct like for(;;) in C... The "for" command takes 4 parameters. (1) The "initial command" to execute. (2) the test "expression" (3) the "next command" (4) the "body command" of the FOR loop. Notice I used the words "command" and "expression" above. The FOR command: 1) executes the "initial command" 2) evaluates the expression if 0 it stops. 3) executes the "body command" 4) executes the "next command" 5) Goto Step 2. As show, each of these items are in {curly-braces}. This means they are passed as they are - KEY-POINT: un evaluated to the FOR command. Think of it like escaping the backticks in Bash so that the "under-lying" command can evaluate the contents. In this case, the FOR COMMAND. == END: SIDEBAR: About The FOR command == You'll see two lines: LINE1: set vn [format "BIT%d" $x] Format is like "sprintf". Because of the [brackets], it becomes what you think. But here's how: First - the line is parsed - for {braces}. In this case, there are none. The, the parser looks for [brackets] and finds them. The, parser then evaluates the contents of the [brackets], and replaces them. It is alot this bash statement. EXPORT vn=`date` LINE 2 & 3 set $vn [expr (1024 * $x)] global $vn In line 1, we dynamically created a variable name. Here, we are assigning it a value. Lastly Line 3 we force the variable to be global, not "local" the the "for command body" =============== The PROCS proc create_mask { MSB LSB } { ... body .... } Like "for" - PROC is really just a command that takes 3 parameters. The (1) NAME of the function, a (2) LIST of parameters, and a (3) BODY Again, this is at "level 0" so it is a global function. (Yes, TCL supports local functions, you put them inside of a function} You'll see in some cases, I nest [brackets] alot and in others I'm lazy or wanted it to be more clear... it is a matter of choice. =============== ************************************************** *************************************************** === TCL TOUR === Open the file: "memory.tcl" =============== Here is where I setup some 'memory definitions' that various targets can use. For example - there is an "unknown" memory region. All memory regions must have 2 things: (1) N_ (2) NAME( array ) And the array must have some specific names: ( , THING ) Where: THING is one of: CHIPSELECT BASE LEN HUMAN TYPE RWX - the access ability. WIDTH - the accessible width. ie: Some regions of memory are not 'word' accessible. The function "address_info" - given an address should tell you about the address. [as of this writing: 7/5/2008 I have done only a little bit with this -Duane] === MAJOR FUNCTION: == proc memread32 { ADDR } proc memread16 { ADDR } proc memread8 { ADDR } All read memory - and return the contents. [ FIXME: 7/5/2008 - I need to create "memwrite" functions] ************************************************** *************************************************** === TCL TOUR === Open the file: "mmr_helpers.tcl" =============== This file is used to display and work with "memory mapped registers" For example - 'show_mmr32_reg' is given the NAME of the register to display. The assumption is - the NAME is a global variable holding the address of that MMR. The code does some tricks. The [set [set NAME]] is the TCL way of doing double variable interpolation - like makefiles... In a makefile or shell script you may have seen this: FOO_linux = "Penguins rule" FOO_winXP = "Broken Glass" FOO_mac = "I like cat names" # Pick one BUILD = linux #BUILD = winXP #BUILD = mac FOO = ${FOO_${BUILD}} The "double [set] square bracket" thing is the TCL way, nothing more. ---- The IF statement - and "CATCH" . Notice this IF COMMAND - (not statement) is like this: [7/5/2008 it is this way] if ![catch { command } msg ] { ...something... } else { error [format string...] } The "IF" command expects either 2 params, or 4 params. === Sidebar: About "commands" === Take a look at the internals of "jim.c" Look for the function: Jim_IfCoreCommand() And all those other "CoreCommands" You'll notice - they all have "argc" and "argv" Yea, the entire thing is done that way. IF is a command. SO is "FOR" and "WHILE" and "DO" and the others. That is why I keep using the phase it is a "command" === END: Sidebar: About "commands" === Parameter 1 to the IF command is expected to be an expression. As such, I do not need to wrap it in {braces}. In this case, the "expression" is the result of the "CATCH" command. CATCH - is an error catcher. You give CATCH 1 or 2 parameters. The first 1st parameter is the "code to execute" The 2nd (optional) is where to put the error message. CATCH returns 0 on success, 1 for failure. The "![catch command]" is self explaintory. The 3rd parameter to IF must be exactly "else" or "elseif" [I lied above, the IF command can take many parameters they just have to be joined by exactly the words "else" or "elseif". The 4th parameter contains: "error [format STRING....]" This lets me modify the previous lower level error by tacking more text onto the end of it. In this case, i want to add the MMR register name to make my error message look better. --------- Back to something inside show_mmr32_reg{}. You'll see something 'set fn show_${NAME}_helper' Here I am constructing a 'function name' Then - I look it up to see if it exists. {the function: "proc_exists" does this} And - if it does - I call the function. In "C" it is alot like using: 'sprintf()' to construct a function name string, then using "dlopen()" and "dlsym()" to look it up - and get a function pointer - and calling the function pointer. In this case - I execute a dynamic command. You can do some cool tricks with interpretors. ---------- Function: show_mmr32_bits() In this case, we use the special TCL command "upvar" which tcl's way of passing things by reference. In this case, we want to reach up into the callers lexical scope and find the array named "NAMES" The rest of the function is pretty straight forward. First - we figure out the longest name. Then print 4 rows of 8bits - with names. ************************************************** *************************************************** === TCL TOUR === Open the file: "chips/atmel/at91/usarts.tcl" =============== First - about the AT91SAM series - all of the usarts are basically identical... Second - there can be many of them. In this case - I do some more TCL tricks to dynamically create functions out of thin air. Some assumptions: The "CHIP" file has defined some variables in a proper form. ie: AT91C_BASE_US0 - for usart0, AT91C_BASE_US1 - for usart1 ... And so on ... Near the end of the file - look for a large "foreach" loop that looks like this: foreach WHO { US0 US1 US2 US3 US4 .... } { } In this case, I'm trying to figure out what USARTs exist. Step 1 - is to determine if the NAME has been defined. ie: Does AT91C_BASE_USx - where X is some number exist? The "info exists VARNAME" tells you if the variable exists. Then - inside the IF statement... There is another loop. This loop is the name of various "sub-registers" within the USART. Some more trick are played with the [set VAR] backtick evaluation stuff. And we create two variables We calculate and create the global variable name for every subregister in the USART. And - declare that variable as GLOBAL so the world can find it. Then - we dynamically create a function - based on the register name. Look carefully at how that is done. You'll notice the FUNCTION BODY is a string - not something in {braces}. Why? This is because we need TCL to evaluate the contents of that string "*NOW*" - when $vn exists not later, when the function "show_FOO" is invoked. Lastly - we build a "str" of commands - and create a single function - with the generated list of commands for the entire USART. With that little bit of code - I now have a bunch of functions like: show_US0, show_US1, show_US2, .... etc ... And show_US0_MR, show_US0_IMR ... etc... And - I have this for every USART... without having to create tons of boiler plate yucky code. **************************************** **************************************** END of the Tcl Intro and Walk Through **************************************** **************************************** FUTURE PLANS Some "GPIO" functions... @endverbatim */ openocd-0.7.0/doc/manual/primer/commands.txt0000644000175000001440000001042112134336410015737 00000000000000/** @page primercommand Command Development Primer This page provides a primer for writing commands by introducing @c hello module. The full source code used in this example can be found in hello.c, and the @ref primercmdcode section shows how to use it. A summary of this information can be found in @ref helpercommand . @section primercmdhandler Command Handlers Defining new commands and their helpers is easy. The following code defines a simple command handler that delegates its argument parsing: @code COMMAND_HANDLER(handle_hello_command) { const char *sep, *name; int retval = CALL_COMMAND_HANDLER(handle_hello_args); if (ERROR_OK == retval) command_print(CMD_CTX, "Greetings%s%s!", sep, name); return retval; } @endcode Here, the @c COMMAND_HANDLER macro establishes the function signature, see in command.h by the @c __COMMAND_HANDLER macro. The COMMAND_HELPER macro function allows defining functions with an extended version of the base signature. These helper functions can be called (with the appropriate parameters), the @c CALL_COMMAND_HANDLER macro to pass any e as parameters to the following helper function: The subsequent blocks of code are a normal C function that can do anything, so only complex commands deserve should use comamnd helper functions. In this respect, this example uses one to demonstrate how -- not when -- they should be used. @code static COMMAND_HELPER(handle_hello_args, const char **sep, const char **name) { if (argc > 1) { LOG_ERROR("%s: too many arguments", CMD_NAME); return ERROR_COMMAND_SYNTAX_ERROR; } if (1 == CMD_ARGC) { *sep = ", "; *name = CMD_ARGV[0]; } else *sep = *name = ""; return ERROR_OK; } @endcode Of course, you may also call other macros or functions, but that extends beyond the scope of this tutorial on writing commands. @section primercmdreg Command Registration Before this new function can be used, it must be registered somehow. For a new module, registering should be done in a new function for the purpose, which must be called from @c openocd.c: @code static const struct command_registration hello_command_handlers[] = { { .name = "hello", .mode = COMMAND_ANY, .handler = handle_hello_command, .help = "print a warm greeting", .usage = "[name]", }, { .chain = foo_command_handlers, } COMMAND_REGISTRATION_DONE }; int hello_register_commands(struct command_context_s *cmd_ctx) { return register_commands(cmd_ctx, NULL, handle_command_handlers); } @endcode Note that the "usage" text should use the same EBNF that's found in the User's Guide: literals in 'single quotes', sequences of optional parameters in [square brackets], and alternatives in (parentheses|with|vertical bars), and so forth. No angle brackets. That's it! The command should now be registered and available to scripts. @section primercmdchain Command Chaining This example also shows how to chain command handler registration, so your modules can "inherit" commands provided by other (sub)modules. Here, the hello module includes the foo commands in the same context that the 'hello' command will be registered. If the @c chain field had been put in the 'hello' command, then the @c foo module commands would be registered under it. Indeed, that technique is used to define the 'foo bar' and 'foo baz' commands, as well as for the example drivers that use these modules. The code for the 'foo' command handlers can be found in @c hello.c. @section primercmdcode Trying These Example Commands These commands have been inherited by the dummy interface, faux flash, and testee target drivers. The easiest way to test these is by using the dummy interface. Once OpenOCD has been built with this example code, the following command demonstrates the abilities that the @c hello module provides: @code openocd -c 'interface dummy' \ -c 'dummy hello' \ -c 'dummy hello World' \ -c 'dummy hello {John Doe}' \ -c 'dummy hello John Doe' # error: too many arguments @endcode If saved in @c hello.cfg, then running openocd -f hello.cfg should produce the following output before displaying the help text and exiting: @code Greetings! Greetings, World! Greetings, John Doe! Error: hello: too many arguments Runtime error, file "openocd.cfg", line 14: hello: too many arguments dummy hello [] prints a warm welcome @endcode */ openocd-0.7.0/doc/manual/primer/autotools.txt0000644000175000001440000001537412134336410016203 00000000000000/** @page primerautotools OpenOCD Autotools Primer This page provides an overview to OpenOCD's use of the GNU autotool suite: - @ref primerautoconf - @ref primerautomake - @ref primerlibtool Most developers do not need to concern themselves with these tools, as the @ref primerbootstrap script runs these tools in the required sequence. @section primerbootstrap Autotools Bootstrap The @c bootstrap script should be used by developers to run the autotools in the correct sequence. When run after a fresh checkout, this script generates the build files required to compile the project, producing the project configure script. After running @c configure, the @ref primermaintainermode settings will handle most situations that require running these tools again. In some cases, a fresh bootstrap may be still required. @subsection primerbootstrapcures Problems Solved By Bootstrap For example, the build system can fail in unexpected ways after running git pull. Here, the make maintainer-clean should be used to remove all of the files generated by the @c bootstrap script and subsequent build processes. In this particular case, one may also need to remove stray files by hand after running this command to ensure everything is rebuilt properly. This step should be necessary only if the @c maintainer-clean was run @b after altering the build system files with git. If it is run @b before any updates, the build system should never leave artifacts in the tree. Without such precautions, changes can be introduced that leave the tree timestamps in an inconsistent state, producing strange compile errors that are resolve after such diligence. @subsection primermaintainerclean Autotools Cleaning Normally, all files generated by the bootstrap script, configure process, and build system should be removed after running make maintainer-clean. Automatically generated files that remain after this should be listed in @c MAINTAINERCLEANFILES, @c DISTCLEANFILES, or @c CLEANFILES, depending on which stage of the build process they are produced. @section primerautoconf Autoconf Configuration Script The @c autoconf program generates the @c configure script from @c configure.in, using serious Perl voodoo. The resulting script is included in the project distribution packages and run by users to configure the build process for their system. @subsection primermaintainermode Maintainer Mode After a fresh checkout, @c bootstrap, and a simple @c configure, you may experience errors when running @c make that some files cannot be found (e.g. @c version.texi), and a second @c make will "mysteriously" solve the problems. The isssue is well-known and expected, if unfortunate. The OpenOCD project requires that all developers building from the git repository use the @c --enable-maintainer-mode option when running the @c configure script. This option ensures that certain files are created during the build process that would normally be packaged in the distribution tarball. The @c bootstrap script will remind you of this requirement when it runs. In addition to solving these problems, this option enables Makefile rules (provided by automake) that allow the normal @c make process to rebuild the autotools outputs, included the automake-generated Makefiles themselves. This avoids the heavy-handed approach of running the @c bootstrap script after changing one of these files. @section primerautomake Automake Makefiles The @c automake program generates @c Makefile.in files (from @c Makefile.am files). These files are later processed by the configure script produced by @c autoconf. @subsection primerautomakenewfiles Creating Makefile.am Files This section shows how to add a @c Makefile.am in a new directory (or one that lacks one). -# The new directory must be listed in the @c SUBDIRS variable in the parent directory's Makefile.am: @code $ echo 'SUBDIRS += directory' >>../Makefile.am @endcode -# Create an bare-bones Makefile.am file in directory that needs it: @code $ echo "MAINTAINERCLEANFILES = Makefile.in" >Makefile.am @endcode -# The @c configure.in script must be updated, so it generates the required Makefile when the @a configure script is run by the user: @verbatim AC_OUTPUT([ ... path/to/new/Makefile ]) @endverbatim Note: these instructions are @b not meant to be used literally, rather they are shown for demonstration purposes. The default MAINTAINERCLEANFILES rule ensures that the automake-generated @c Makefile.in file will be removed when developers run make maintainer-clean. Additional rules may be added after this; however, the project should bootstrap and tear down cleanly after taking these minimal steps, with the new directory being visited during the @c make sequence. @subsection primerautomaketweaks Updating Makefile.am Files Adding, removing, and renaming files from the project tree usually requires updating the autotools inputs. This section will help describe how to do this as questions arise. @section primerlibtool Libtool and Libraries The @c libtool program provides the means of generating libraries in a portable and painless manner (relatively speaking). This section will contain an answer to "what does libtool give OpenOCD?" and "what do developers need to consider in new code?" @section primerautotoolsmation Autotools Automation This section outlines three ways the autotools provides automation to assist with testing and distribution: - @ref primerautocheck -- automatic unit and smoke tests - @ref primerautodistcheck -- automatic distribution and packaging tests @subsection primerautocheck make check The make check command will run the OpenOCD test suite, once it has been integrated as such. This section will contain information about how to extend the testing build system components to implement new checks. @subsection primerautodistcheck make distcheck The make distcheck command produces an archive of the project deliverables (using make dist) and verifies its integrity for distribution by attemptng to use the package in the same manner as a user. These checks includes the following steps: -# Unpack the project archive into its expected directory. -# Configure and build the project in a temporary out-of-tree directory. -# Run make check to ensure the distributed code passes all tests. -# Run make install into a temporary installation directory. -# Check that make uninstall removes all files that were installed. -# Check that make distclean removes all files created during all other steps (except the first). If all of these steps complete successfully, the @c make process will output a friendly message indicating the archive is ready to be distributed. */ /** @file This file contains the @ref primerautotools page. */ openocd-0.7.0/doc/manual/jtag/0000755000175000001440000000000012141414413013104 500000000000000openocd-0.7.0/doc/manual/server.txt0000644000175000001440000003107712134336410014160 00000000000000/** @page serverdocs OpenOCD Server APIs OpenOCD provides support for implementing different types of servers. Presently, the following servers have APIs that can be used. - @subpage servergdb - @subpage servertelnet - @subpage serverhttp @section serverdocsoverview Overview What follows is a development history, and describes some of the intent of why certain features exist within OpenOCD along with the reasoning behind them. This roadmap section was written May 2009 - about 9 to 12 months after some of this work had started, it attempts to document some of the reasons why certain features exist within OpenOCD at that time. @section serverdocsbg Background In early 2008, Oyvind Harboe and Duane Ellis had talked about how to create a reasonable GUI for OpenOCD - something that is non-invasive, simple to use and maintain, and does not tie OpenOCD to many other packages. It would be wrong to "spider web" requirements into other external external packages. That makes it difficult for developers to write new code and creates a support nightmare. In many ways, people had talked about the need for some type of high-level interface to OpenOCD, because they only had two choices: - the ability to script: via an external program the actions of OpenOCD. - the ablity to write a complex internal commands: native 'commands' inside of OpenOCD was complicated. Fundamentally, the basic problem with both of those would be solved with a script language: -# Internal: simple, small, and self-contained. -# Cross Language: script friendly front-end -# Cross Host: GUI Host interface -# Cross Debugger: GUI-like interface What follows hopefully shows how the plans to solve these problems materialized and help to explain the grand roadmap plan. @subsection serverdocsjim Why JimTCL? The Internal Script Language At the time, the existing "command context schema" was proving itself insufficient. However, the problem was also considered from another direction: should OpenOCD be first class and the script second class? Which one rules? In the end, OpenOCD won, the conclusion was that simpler will be better. Let the script language be "good enough"; it would not need numerous features. Imagine debugging an embedded Perl module while debugging OpenOCD. Yuck. OpenOCD already has a complex enough build system, why make it worse? The goal was to add a simple language that would be moderately easy to work with and be self-contained. JimTCL is a single C and single H file, allowing OpenOCD to avoid the spider web of dependent packages. @section serverdocstcl TCL Server Port The TCL Server port was added in mid-2008. With embedded TCL, we can write scripts internally to help things, or we can write "C" code that interfaces well with TCL. From there, the developers wanted to create an external front-end that would be @a very usable and that that @a any language could utilize, allowing simple front-ends to be (a) cross-platform (b) languag agnostic, and (c) easy to develop and use. Simple ASCII protocols are easy. For example, HTTP, FTP (control), and SMTP are all text-based. All of these examples are widely and well-known, and they do not require high-speed or high-volume. They also support a high degree of interoperability with multiple systems. They are not human-centric protocols; more correctly, they are rigid, terse, simple ASCII protocols that are emensely parsable by a script. Thus, the TCL server -- a 'machine' type socket interface -- was added with the hope was it would output simple "name-value" pair type data. At the time, simple name/value pairs seemed reasonably easier to do at the time, though Maybe it should output JSON; See here: http://www.mail-archive.com/openocd-development%40lists.berlios.de/msg00248.html The hope was that one could write a script in what ever language you want and do things with it! @section serverdocsgui GUI Like Interfaces A lot has been said about various "widigit-foo-gui-library is so wonderful". Please refer back to the domino and spider web problem of dependencies. Sure, you may well know the WhatEver-GUI library, but most others will not (including the next contributer to OpenOCD). How do we solve that problem? For example, Cygwin can be painful, Cygwin GUI packages want X11 to be present, crossing the barrier between MinGW and Cygwin is painful, let alone getting the GUI front end to work on MacOS, and Linux, yuck yuck yuck. Painful. very very painful. What works easier and is less work is what is already present in every platform? The answer: A web browser. In other words, OpenOCD could serve out embedded web pages via "localhost" to your browser. Long before OpenOCD had a TCL command line, Zylin AS built their ZY1000 devince with a built-in HTTP server. Later, they were willing to both contribute and integrate most of that work into the main tree. @subsection serverdocsother Other Options Considered What if a web browser is not acceptable ie: You want to write your own front gadget in Eclipse, or KDevelop, or PerlTK, Ruby, or what ever the latest and greatest Script De Jour is. - Option 1: Can we transport this extra data through the GDB server protocol? In other words, can we extend the GDB server protocol? No, Eclipse wants to talk to GDB directly and control the GDB port. - Option 2: SWIG front end (libopenocd): Would that work? That's painful - unless you design your api to be very simplistic - every language has it's own set of wack-ness, parameter marshaling is painful. What about "callbacks" and structures, and other mess. Imagine debugging that system. When JimTCL was introduced Spencer Oliver had quite a few well-put concerns (Summer 2008) about the idea of "TCL" taking over OpenOCD. His concern is and was: how do you debug something written in 2 different languages? A "SWIG" front-end is unlikely to help that situation. @subsection serverdoccombined Combined: Socket & WebServer Benifits Seriously think about this question: What script language (or compiled language) today cannot talk directly to a socket? Every thing in the OpenOCD world can work a socket interface. Any host side tool can talk to Localhost or remote host, however one might want to make it work. A socket interface is very simple. One could write a Java application and serve it out via the embedded web server, could it - or something like it talk to the built in TCL server? Yes, absolutely! We are on to something here. @subsection serverdocplatforms Platform Permuntations Look at some permutations where OpenOCD can run; these "just work" if the Socket Approach is used. - Linux/Cygwin/MinGw/MacOSx/FreeBSD development Host Locally - OpenOCD with some dongle on that host - Linux/Cygwin/MingW/MacOS/FreeBSD development host - DONGLE: tcpip based ARM-Linux perhaps at91rm9200 or ep93xx.c, running openocd. - Windows cygwin/X desktop environment. - Linux development host (via remote X11) - Dongle: "eb93xx.c" based linux board @subsection serverdocfuture Development Scale Out During 2008, Duane Ellis created some TCL scripts to display peripheral register contents. For example, look at the sam7 TCL scripts, and the stm32 TCL scripts. The hope was others would create more. A good example of this is display/view the peripheral registers on your embedded target. Lots of commercial embedded debug tools have this, some can show the TIMER registers, the interrupt controller. What if the chip companies behind STM32, or PIC32, AT91SAM chips - wanted to write something that makes working with their chip better, easier, faster, etc. @a Question: How can we (the OpenOCD group) make that really fancy stuff across multiple different host platforms? Remember: OpenOCD runs on: -# Linux via USB, -# ARM Linux - bit-banging GPIO pins -# MacOSX -# FreeBSD -# Cygwin -# MinGW32 -# Ecos How can we get that to work? @subsection serverdocdebug What about Debugger Plugins? Really GDB is nice, it works, but it is not a good embedded debug tool. OpenOCD cannot work in a GUI when one cannot get to its command line. Some GDB front-end developers have pedantic designs that refuse any and all access to the GDB command line (e.g. http://www.kdbg.org/todo.php). The TELNET interface to OpenOCD works, but the intent of that interface is human interaction. It must remain available, developers depend upon it, sometimes that is the only scheme available. As a small group of developers, supporting all the platforms and targets in the debugger will be difficult, as there are enough problem with the plethora of Adapters, Chips, and different target boards. Yes, the TCL interface might be suitable, but it has not received much love or attention. Perhaps it will after you read and understand this. One reason might be, this adds one more host side requirement to make use of the feature. In other words, one could write a Python/TK front-end, but it is only useable if you have Python/TK installed. Maybe this can be done via Ecllipse, but not all developers use Ecplise. Many devlopers use Emacs (possibly with GUD mode) or vim and will not accept such an interface. The next developer reading this might be using Insight (GDB-TK) - and somebody else - DDD.. There is no common host-side GDB front-end method. @section serverdocschallenge Front-End Scaling Maybe we are wrong - ie: OpenOCD + some TK tool Remember: OpenOCD is often (maybe 99.9%) of the time used with GDB-REMOTE. There is always some front-end package - be it command-line GDB under DDD, Eclipse, KDevelop, Emacs, or some other package (e.g. IAR tools can talk to GDB servers). How can the OpenOCD developers make that fancy target display GUI visible under 5 to 10 different host-side GDB.. Sure - a man on a mission can make that work. The GUI might be libopenocd + Perl/TK, or maybe an Eclipse Plug-in. That is a development support nightmare for reasons described above. We have enough support problems as it is with targets, adapters, etc. @section serverdocshttpbg HTTP Server Background OpenOCD includes an HTTP server because most development environments are likely contain a web browser. The web browser can talk to OpenOCD's HTTP server and provide a high-level interfaces to the program. Altogether, it provides a universally accessible GUI for OpenOCD. @section serverdocshtml Simple HTML Pages There is (or could be) a simple "Jim TCL" function to read a memory location. If that can be tied into a TCL script that can modify the HTTP text, then we have a simple script-based web server with a JTAG engine under the hood. Imagine a web page - served from a small board with two buttons: "LED_ON" and "LED_OFF", each click - turns the LED on or OFF, a very simplistic idea. Little boards with web servers are great examples of this: Ethernut is a good example and Contiki (not a board, an embedded OS) is another example. One could create a simple: Click here to display memory or maybe click here to display the UART REGISTER BLOCK; click again and see each register explained in exquisit detail. For an STM32, one could create a simple HTML page, with simple substitution text that the simple web server use to substitute the HTML text JIMTCL_PEEK32( 0x12345678 ) with the value read from memory. We end up with an HTML page that could list the contents of every peripheral register on the target platform. That also is transportable, regardless of the OpenOCD host platform: Linux/X86, Linux/ARM, FreeBSD, Cygwin, MingW, or MacOSX. You could even port OpenOCD to an Android system and use it as a bit-banging JTAG Adapter serving web pages. @subsection serverdocshtmladv Advanced HTML Pages Java or JavaScript could be used to talk back to the TCL port. One could write a Java, AJAX, FLASH, or some other developer friendly toolbox and get a real cross-platform GUI interface. Sure, the interface is not native - but it is 100% cross-platform! OpenOCD current uses simple HTML pages; others might be an Adobe FLASH expert, or a Java Expert. These possibilities could allow the pages remain cross-platform but still provide a rich user-interface experience. Don't forget it can also be very simple, exactly what one developer can contribute, a set of very simple web pages. @subsection serverdocshtmlstatus HTTP/HTML Status As of May 2009, much of the HTML pages were contributed by Zylin AS, hence they continue to retain some resemblance to the ZY1000 interface. Patches would be welcome to move these parts of the system forward. */ /** @page servergdb OpenOCD GDB Server API This section needs to be expanded. */ /** @page servertelnet OpenOCD Telnet Server API This section needs to be expanded. */ /** @page serverhttp OpenOCD http Server API This section needs to be expanded. */ openocd-0.7.0/doc/manual/app.txt0000644000175000001440000000047312134336410013426 00000000000000/** @page appdocs OpenOCD Application APIs The top-level APIs in the OpenOCD library allow applications to integrate all of the low-level functionality using a set of simple function calls. These function calls do not exist in a re-usable form, but contributions to create and document them will be welcome. */ openocd-0.7.0/doc/manual/target.txt0000644000175000001440000000217212137151330014131 00000000000000/** @page targetdocs OpenOCD Target APIs OpenOCD provides its Target APIs to allow developers to provide trace and debugging support for specific device targets. These primarily consist of ARM cores, but other types have been supported. New targets should be developed by following or using these APIs. The Target Support module contains APIs that cover several functional areas: - @subpage targetarm - @subpage targetnotarm - @subpage targetmips - @subpage targetregister - @subpage targetimage - @subpage targettrace This section needs to be expanded. */ /** @page targetarm OpenOCD ARM Targets This section needs to describe OpenOCD's ARM target support. */ /** @page targetregister OpenOCD Target Register API This section needs to describe OpenOCD's Target Register API, as provided by 'src/target/register.h'. */ /** @page targetimage OpenOCD Target Image API This section needs to describe OpenOCD's Target Image API, as provided by 'src/target/image.h'. */ /** @page targettrace OpenOCD Target Trace API This section needs to describe OpenOCD's Target Trace API, as provided by 'src/target/trace.h'. */ openocd-0.7.0/doc/Makefile.in0000644000175000001440000006305312141414275012704 00000000000000# Makefile.in generated by automake 1.13.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = doc DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(openocd_TEXINFOS) mdate-sh $(srcdir)/version.texi \ $(srcdir)/stamp-vti texinfo.tex ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/config_subdir.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = AM_V_DVIPS = $(am__v_DVIPS_@AM_V@) am__v_DVIPS_ = $(am__v_DVIPS_@AM_DEFAULT_V@) am__v_DVIPS_0 = @echo " DVIPS " $@; am__v_DVIPS_1 = AM_V_MAKEINFO = $(am__v_MAKEINFO_@AM_V@) am__v_MAKEINFO_ = $(am__v_MAKEINFO_@AM_DEFAULT_V@) am__v_MAKEINFO_0 = @echo " MAKEINFO" $@; am__v_MAKEINFO_1 = AM_V_INFOHTML = $(am__v_INFOHTML_@AM_V@) am__v_INFOHTML_ = $(am__v_INFOHTML_@AM_DEFAULT_V@) am__v_INFOHTML_0 = @echo " INFOHTML" $@; am__v_INFOHTML_1 = AM_V_TEXI2DVI = $(am__v_TEXI2DVI_@AM_V@) am__v_TEXI2DVI_ = $(am__v_TEXI2DVI_@AM_DEFAULT_V@) am__v_TEXI2DVI_0 = @echo " TEXI2DVI" $@; am__v_TEXI2DVI_1 = AM_V_TEXI2PDF = $(am__v_TEXI2PDF_@AM_V@) am__v_TEXI2PDF_ = $(am__v_TEXI2PDF_@AM_DEFAULT_V@) am__v_TEXI2PDF_0 = @echo " TEXI2PDF" $@; am__v_TEXI2PDF_1 = AM_V_texinfo = $(am__v_texinfo_@AM_V@) am__v_texinfo_ = $(am__v_texinfo_@AM_DEFAULT_V@) am__v_texinfo_0 = -q am__v_texinfo_1 = AM_V_texidevnull = $(am__v_texidevnull_@AM_V@) am__v_texidevnull_ = $(am__v_texidevnull_@AM_DEFAULT_V@) am__v_texidevnull_0 = > /dev/null am__v_texidevnull_1 = INFO_DEPS = $(srcdir)/openocd.info am__TEXINFO_TEX_DIR = $(srcdir) DVIS = openocd.dvi PDFS = openocd.pdf PSS = openocd.ps HTMLS = openocd.html TEXINFOS = openocd.texi TEXI2DVI = texi2dvi TEXI2PDF = $(TEXI2DVI) --pdf --batch MAKEINFOHTML = $(MAKEINFO) --html AM_MAKEINFOHTMLFLAGS = $(AM_MAKEINFOFLAGS) DVIPS = dvips am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__installdirs = "$(DESTDIR)$(infodir)" "$(DESTDIR)$(man1dir)" am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } man1dir = $(mandir)/man1 NROFF = nroff MANS = $(man_MANS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CC_FOR_BUILD = @CC_FOR_BUILD@ CFLAGS = @CFLAGS@ CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@ FGREP = @FGREP@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ doxygen_as_html = @doxygen_as_html@ doxygen_as_pdf = @doxygen_as_pdf@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ info_TEXINFOS = openocd.texi openocd_TEXINFOS = fdl.texi man_MANS = openocd.1 EXTRA_DIST = openocd.1 \ INSTALL.txt MAINTAINERCLEANFILES = \ $(srcdir)/Makefile.in \ $(srcdir)/mdate-sh \ $(srcdir)/stamp-vti \ $(srcdir)/version.texi \ $(srcdir)/texinfo.tex all: all-am .SUFFIXES: .SUFFIXES: .dvi .html .info .pdf .ps .texi $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu doc/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs .texi.info: $(AM_V_MAKEINFO)restore=: && backupdir="$(am__leading_dot)am$$$$" && \ am__cwd=`pwd` && $(am__cd) $(srcdir) && \ rm -rf $$backupdir && mkdir $$backupdir && \ if ($(MAKEINFO) --version) >/dev/null 2>&1; then \ for f in $@ $@-[0-9] $@-[0-9][0-9] $(@:.info=).i[0-9] $(@:.info=).i[0-9][0-9]; do \ if test -f $$f; then mv $$f $$backupdir; restore=mv; else :; fi; \ done; \ else :; fi && \ cd "$$am__cwd"; \ if $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \ -o $@ $<; \ then \ rc=0; \ $(am__cd) $(srcdir); \ else \ rc=$$?; \ $(am__cd) $(srcdir) && \ $$restore $$backupdir/* `echo "./$@" | sed 's|[^/]*$$||'`; \ fi; \ rm -rf $$backupdir; exit $$rc .texi.dvi: $(AM_V_TEXI2DVI)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \ $(TEXI2DVI) $(AM_V_texinfo) --build-dir=$(@:.dvi=.t2d) -o $@ $(AM_V_texidevnull) \ $< .texi.pdf: $(AM_V_TEXI2PDF)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \ $(TEXI2PDF) $(AM_V_texinfo) --build-dir=$(@:.pdf=.t2p) -o $@ $(AM_V_texidevnull) \ $< .texi.html: $(AM_V_MAKEINFO)rm -rf $(@:.html=.htp) $(AM_V_at)if $(MAKEINFOHTML) $(AM_MAKEINFOHTMLFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \ -o $(@:.html=.htp) $<; \ then \ rm -rf $@; \ if test ! -d $(@:.html=.htp) && test -d $(@:.html=); then \ mv $(@:.html=) $@; else mv $(@:.html=.htp) $@; fi; \ else \ if test ! -d $(@:.html=.htp) && test -d $(@:.html=); then \ rm -rf $(@:.html=); else rm -Rf $(@:.html=.htp) $@; fi; \ exit 1; \ fi $(srcdir)/openocd.info: openocd.texi $(srcdir)/version.texi $(openocd_TEXINFOS) openocd.dvi: openocd.texi $(srcdir)/version.texi $(openocd_TEXINFOS) openocd.pdf: openocd.texi $(srcdir)/version.texi $(openocd_TEXINFOS) openocd.html: openocd.texi $(srcdir)/version.texi $(openocd_TEXINFOS) $(srcdir)/version.texi: @MAINTAINER_MODE_TRUE@ $(srcdir)/stamp-vti $(srcdir)/stamp-vti: openocd.texi $(top_srcdir)/configure @(dir=.; test -f ./openocd.texi || dir=$(srcdir); \ set `$(SHELL) $(srcdir)/mdate-sh $$dir/openocd.texi`; \ echo "@set UPDATED $$1 $$2 $$3"; \ echo "@set UPDATED-MONTH $$2 $$3"; \ echo "@set EDITION $(VERSION)"; \ echo "@set VERSION $(VERSION)") > vti.tmp @cmp -s vti.tmp $(srcdir)/version.texi \ || (echo "Updating $(srcdir)/version.texi"; \ cp vti.tmp $(srcdir)/version.texi) -@rm -f vti.tmp @cp $(srcdir)/version.texi $@ mostlyclean-vti: -rm -f vti.tmp maintainer-clean-vti: @MAINTAINER_MODE_TRUE@ -rm -f $(srcdir)/stamp-vti $(srcdir)/version.texi .dvi.ps: $(AM_V_DVIPS)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ $(DVIPS) $(AM_V_texinfo) -o $@ $< uninstall-dvi-am: @$(NORMAL_UNINSTALL) @list='$(DVIS)'; test -n "$(dvidir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(dvidir)/$$f'"; \ rm -f "$(DESTDIR)$(dvidir)/$$f"; \ done uninstall-html-am: @$(NORMAL_UNINSTALL) @list='$(HTMLS)'; test -n "$(htmldir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " rm -rf '$(DESTDIR)$(htmldir)/$$f'"; \ rm -rf "$(DESTDIR)$(htmldir)/$$f"; \ done uninstall-info-am: @$(PRE_UNINSTALL) @if test -d '$(DESTDIR)$(infodir)' && $(am__can_run_installinfo); then \ list='$(INFO_DEPS)'; \ for file in $$list; do \ relfile=`echo "$$file" | sed 's|^.*/||'`; \ echo " install-info --info-dir='$(DESTDIR)$(infodir)' --remove '$(DESTDIR)$(infodir)/$$relfile'"; \ if install-info --info-dir="$(DESTDIR)$(infodir)" --remove "$(DESTDIR)$(infodir)/$$relfile"; \ then :; else test ! -f "$(DESTDIR)$(infodir)/$$relfile" || exit 1; fi; \ done; \ else :; fi @$(NORMAL_UNINSTALL) @list='$(INFO_DEPS)'; \ for file in $$list; do \ relfile=`echo "$$file" | sed 's|^.*/||'`; \ relfile_i=`echo "$$relfile" | sed 's|\.info$$||;s|$$|.i|'`; \ (if test -d "$(DESTDIR)$(infodir)" && cd "$(DESTDIR)$(infodir)"; then \ echo " cd '$(DESTDIR)$(infodir)' && rm -f $$relfile $$relfile-[0-9] $$relfile-[0-9][0-9] $$relfile_i[0-9] $$relfile_i[0-9][0-9]"; \ rm -f $$relfile $$relfile-[0-9] $$relfile-[0-9][0-9] $$relfile_i[0-9] $$relfile_i[0-9][0-9]; \ else :; fi); \ done uninstall-pdf-am: @$(NORMAL_UNINSTALL) @list='$(PDFS)'; test -n "$(pdfdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(pdfdir)/$$f'"; \ rm -f "$(DESTDIR)$(pdfdir)/$$f"; \ done uninstall-ps-am: @$(NORMAL_UNINSTALL) @list='$(PSS)'; test -n "$(psdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(psdir)/$$f'"; \ rm -f "$(DESTDIR)$(psdir)/$$f"; \ done dist-info: $(INFO_DEPS) @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ list='$(INFO_DEPS)'; \ for base in $$list; do \ case $$base in \ $(srcdir)/*) base=`echo "$$base" | sed "s|^$$srcdirstrip/||"`;; \ esac; \ if test -f $$base; then d=.; else d=$(srcdir); fi; \ base_i=`echo "$$base" | sed 's|\.info$$||;s|$$|.i|'`; \ for file in $$d/$$base $$d/$$base-[0-9] $$d/$$base-[0-9][0-9] $$d/$$base_i[0-9] $$d/$$base_i[0-9][0-9]; do \ if test -f $$file; then \ relfile=`expr "$$file" : "$$d/\(.*\)"`; \ test -f "$(distdir)/$$relfile" || \ cp -p $$file "$(distdir)/$$relfile"; \ else :; fi; \ done; \ done mostlyclean-aminfo: -rm -rf openocd.t2d openocd.t2p clean-aminfo: -test -z "openocd.dvi openocd.pdf openocd.ps openocd.html" \ || rm -rf openocd.dvi openocd.pdf openocd.ps openocd.html maintainer-clean-aminfo: @list='$(INFO_DEPS)'; for i in $$list; do \ i_i=`echo "$$i" | sed 's|\.info$$||;s|$$|.i|'`; \ echo " rm -f $$i $$i-[0-9] $$i-[0-9][0-9] $$i_i[0-9] $$i_i[0-9][0-9]"; \ rm -f $$i $$i-[0-9] $$i-[0-9][0-9] $$i_i[0-9] $$i_i[0-9][0-9]; \ done install-man1: $(man_MANS) @$(NORMAL_INSTALL) @list1=''; \ list2='$(man_MANS)'; \ test -n "$(man1dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.1[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ done; } uninstall-man1: @$(NORMAL_UNINSTALL) @list=''; test -n "$(man1dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ sed -n '/\.1[a-z]*$$/p'; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$(top_distdir)" distdir="$(distdir)" \ dist-info dist-hook check-am: all-am check: check-am all-am: Makefile $(INFO_DEPS) $(MANS) installdirs: for dir in "$(DESTDIR)$(infodir)" "$(DESTDIR)$(man1dir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-aminfo clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: $(DVIS) html: html-am html-am: $(HTMLS) info: info-am info-am: $(INFO_DEPS) install-data-am: install-info-am install-man install-dvi: install-dvi-am install-dvi-am: $(DVIS) @$(NORMAL_INSTALL) @list='$(DVIS)'; test -n "$(dvidir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(dvidir)'"; \ $(MKDIR_P) "$(DESTDIR)$(dvidir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(dvidir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(dvidir)" || exit $$?; \ done install-exec-am: install-html: install-html-am install-html-am: $(HTMLS) @$(NORMAL_INSTALL) @list='$(HTMLS)'; list2=; test -n "$(htmldir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)'"; \ $(MKDIR_P) "$(DESTDIR)$(htmldir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p" || test -d "$$p"; then d=; else d="$(srcdir)/"; fi; \ $(am__strip_dir) \ d2=$$d$$p; \ if test -d "$$d2"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)/$$f'"; \ $(MKDIR_P) "$(DESTDIR)$(htmldir)/$$f" || exit 1; \ echo " $(INSTALL_DATA) '$$d2'/* '$(DESTDIR)$(htmldir)/$$f'"; \ $(INSTALL_DATA) "$$d2"/* "$(DESTDIR)$(htmldir)/$$f" || exit $$?; \ else \ list2="$$list2 $$d2"; \ fi; \ done; \ test -z "$$list2" || { echo "$$list2" | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(htmldir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(htmldir)" || exit $$?; \ done; } install-info: install-info-am install-info-am: $(INFO_DEPS) @$(NORMAL_INSTALL) @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ list='$(INFO_DEPS)'; test -n "$(infodir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(infodir)'"; \ $(MKDIR_P) "$(DESTDIR)$(infodir)" || exit 1; \ fi; \ for file in $$list; do \ case $$file in \ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ esac; \ if test -f $$file; then d=.; else d=$(srcdir); fi; \ file_i=`echo "$$file" | sed 's|\.info$$||;s|$$|.i|'`; \ for ifile in $$d/$$file $$d/$$file-[0-9] $$d/$$file-[0-9][0-9] \ $$d/$$file_i[0-9] $$d/$$file_i[0-9][0-9] ; do \ if test -f $$ifile; then \ echo "$$ifile"; \ else : ; fi; \ done; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(infodir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(infodir)" || exit $$?; done @$(POST_INSTALL) @if $(am__can_run_installinfo); then \ list='$(INFO_DEPS)'; test -n "$(infodir)" || list=; \ for file in $$list; do \ relfile=`echo "$$file" | sed 's|^.*/||'`; \ echo " install-info --info-dir='$(DESTDIR)$(infodir)' '$(DESTDIR)$(infodir)/$$relfile'";\ install-info --info-dir="$(DESTDIR)$(infodir)" "$(DESTDIR)$(infodir)/$$relfile" || :;\ done; \ else : ; fi install-man: install-man1 install-pdf: install-pdf-am install-pdf-am: $(PDFS) @$(NORMAL_INSTALL) @list='$(PDFS)'; test -n "$(pdfdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pdfdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pdfdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pdfdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pdfdir)" || exit $$?; done install-ps: install-ps-am install-ps-am: $(PSS) @$(NORMAL_INSTALL) @list='$(PSS)'; test -n "$(psdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(psdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(psdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(psdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(psdir)" || exit $$?; done installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-aminfo \ maintainer-clean-generic maintainer-clean-vti mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-aminfo mostlyclean-generic \ mostlyclean-libtool mostlyclean-vti pdf: pdf-am pdf-am: $(PDFS) ps: ps-am ps-am: $(PSS) uninstall-am: uninstall-dvi-am uninstall-html-am uninstall-info-am \ uninstall-man uninstall-pdf-am uninstall-ps-am uninstall-man: uninstall-man1 .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-aminfo clean-generic \ clean-libtool cscopelist-am ctags-am dist-hook dist-info \ distclean distclean-generic distclean-libtool distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-man1 \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-aminfo \ maintainer-clean-generic maintainer-clean-vti mostlyclean \ mostlyclean-aminfo mostlyclean-generic mostlyclean-libtool \ mostlyclean-vti pdf pdf-am ps ps-am tags-am uninstall \ uninstall-am uninstall-dvi-am uninstall-html-am \ uninstall-info-am uninstall-man uninstall-man1 \ uninstall-pdf-am uninstall-ps-am dist-hook: mkdir $(distdir)/manual cp -p $(srcdir)/manual/*.txt $(distdir)/manual for i in $$(cd $(srcdir)/manual/ && ls -d */); do \ mkdir $(distdir)/manual/$$i; \ cp -p $(srcdir)/manual/$$i/* $(distdir)/manual/$$i/; \ done # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: openocd-0.7.0/doc/mdate-sh0000755000175000001440000001363712141414275012272 00000000000000#!/bin/sh # Get modification time of a file or directory and pretty-print it. scriptversion=2010-08-21.06; # UTC # Copyright (C) 1995-2013 Free Software Foundation, Inc. # written by Ulrich Drepper , June 1995 # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # 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. # This file is maintained in Automake, please report # bugs to or send patches to # . 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 fi case $1 in '') echo "$0: No file. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: mdate-sh [--help] [--version] FILE Pretty-print the modification day of FILE, in the format: 1 January 1970 Report bugs to . EOF exit $? ;; -v | --v*) echo "mdate-sh $scriptversion" exit $? ;; esac error () { echo "$0: $1" >&2 exit 1 } # Prevent date giving response in another language. LANG=C export LANG LC_ALL=C export LC_ALL LC_TIME=C export LC_TIME # GNU ls changes its time format in response to the TIME_STYLE # variable. Since we cannot assume 'unset' works, revert this # variable to its documented default. if test "${TIME_STYLE+set}" = set; then TIME_STYLE=posix-long-iso export TIME_STYLE fi save_arg1=$1 # Find out how to get the extended ls output of a file or directory. if ls -L /dev/null 1>/dev/null 2>&1; then ls_command='ls -L -l -d' else ls_command='ls -l -d' fi # Avoid user/group names that might have spaces, when possible. if ls -n /dev/null 1>/dev/null 2>&1; then ls_command="$ls_command -n" fi # A 'ls -l' line looks as follows on OS/2. # drwxrwx--- 0 Aug 11 2001 foo # This differs from Unix, which adds ownership information. # drwxrwx--- 2 root root 4096 Aug 11 2001 foo # # To find the date, we split the line on spaces and iterate on words # until we find a month. This cannot work with files whose owner is a # user named "Jan", or "Feb", etc. However, it's unlikely that '/' # will be owned by a user whose name is a month. So we first look at # the extended ls output of the root directory to decide how many # words should be skipped to get the date. # On HPUX /bin/sh, "set" interprets "-rw-r--r--" as options, so the "x" below. set x`$ls_command /` # Find which argument is the month. month= command= until test $month do test $# -gt 0 || error "failed parsing '$ls_command /' output" shift # Add another shift to the command. command="$command shift;" case $1 in Jan) month=January; nummonth=1;; Feb) month=February; nummonth=2;; Mar) month=March; nummonth=3;; Apr) month=April; nummonth=4;; May) month=May; nummonth=5;; Jun) month=June; nummonth=6;; Jul) month=July; nummonth=7;; Aug) month=August; nummonth=8;; Sep) month=September; nummonth=9;; Oct) month=October; nummonth=10;; Nov) month=November; nummonth=11;; Dec) month=December; nummonth=12;; esac done test -n "$month" || error "failed parsing '$ls_command /' output" # Get the extended ls output of the file or directory. set dummy x`eval "$ls_command \"\\\$save_arg1\""` # Remove all preceding arguments eval $command # Because of the dummy argument above, month is in $2. # # On a POSIX system, we should have # # $# = 5 # $1 = file size # $2 = month # $3 = day # $4 = year or time # $5 = filename # # On Darwin 7.7.0 and 7.6.0, we have # # $# = 4 # $1 = day # $2 = month # $3 = year or time # $4 = filename # Get the month. case $2 in Jan) month=January; nummonth=1;; Feb) month=February; nummonth=2;; Mar) month=March; nummonth=3;; Apr) month=April; nummonth=4;; May) month=May; nummonth=5;; Jun) month=June; nummonth=6;; Jul) month=July; nummonth=7;; Aug) month=August; nummonth=8;; Sep) month=September; nummonth=9;; Oct) month=October; nummonth=10;; Nov) month=November; nummonth=11;; Dec) month=December; nummonth=12;; esac case $3 in ???*) day=$1;; *) day=$3; shift;; esac # Here we have to deal with the problem that the ls output gives either # the time of day or the year. case $3 in *:*) set `date`; eval year=\$$# case $2 in Jan) nummonthtod=1;; Feb) nummonthtod=2;; Mar) nummonthtod=3;; Apr) nummonthtod=4;; May) nummonthtod=5;; Jun) nummonthtod=6;; Jul) nummonthtod=7;; Aug) nummonthtod=8;; Sep) nummonthtod=9;; Oct) nummonthtod=10;; Nov) nummonthtod=11;; Dec) nummonthtod=12;; esac # For the first six month of the year the time notation can also # be used for files modified in the last year. if (expr $nummonth \> $nummonthtod) > /dev/null; then year=`expr $year - 1` fi;; *) year=$3;; esac # The result. echo $day $month $year # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: openocd-0.7.0/doc/texinfo.tex0000644000175000001440000116655512141414275013051 00000000000000% texinfo.tex -- TeX macros to handle Texinfo files. % % Load plain if necessary, i.e., if running under initex. \expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi % \def\texinfoversion{2012-11-08.11} % % Copyright 1985, 1986, 1988, 1990, 1991, 1992, 1993, 1994, 1995, % 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, % 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. % % This texinfo.tex 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 3 of the % License, or (at your option) any later version. % % This texinfo.tex file 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, see . % % As a special exception, when this file is read by TeX when processing % a Texinfo source document, you may use the result without % restriction. (This has been our intent since Texinfo was invented.) % % Please try the latest version of texinfo.tex before submitting bug % reports; you can get the latest version from: % http://ftp.gnu.org/gnu/texinfo/ (the Texinfo release area), or % http://ftpmirror.gnu.org/texinfo/ (same, via a mirror), or % http://www.gnu.org/software/texinfo/ (the Texinfo home page) % The texinfo.tex in any given distribution could well be out % of date, so if that's what you're using, please check. % % Send bug reports to bug-texinfo@gnu.org. Please include including a % complete document in each bug report with which we can reproduce the % problem. Patches are, of course, greatly appreciated. % % To process a Texinfo manual with TeX, it's most reliable to use the % texi2dvi shell script that comes with the distribution. For a simple % manual foo.texi, however, you can get away with this: % tex foo.texi % texindex foo.?? % tex foo.texi % tex foo.texi % dvips foo.dvi -o # or whatever; this makes foo.ps. % The extra TeX runs get the cross-reference information correct. % Sometimes one run after texindex suffices, and sometimes you need more % than two; texi2dvi does it as many times as necessary. % % It is possible to adapt texinfo.tex for other languages, to some % extent. You can get the existing language-specific files from the % full Texinfo distribution. % % The GNU Texinfo home page is http://www.gnu.org/software/texinfo. \message{Loading texinfo [version \texinfoversion]:} % If in a .fmt file, print the version number % and turn on active characters that we couldn't do earlier because % they might have appeared in the input file name. \everyjob{\message{[Texinfo version \texinfoversion]}% \catcode`+=\active \catcode`\_=\active} \chardef\other=12 % We never want plain's \outer definition of \+ in Texinfo. % For @tex, we can use \tabalign. \let\+ = \relax % Save some plain tex macros whose names we will redefine. \let\ptexb=\b \let\ptexbullet=\bullet \let\ptexc=\c \let\ptexcomma=\, \let\ptexdot=\. \let\ptexdots=\dots \let\ptexend=\end \let\ptexequiv=\equiv \let\ptexexclam=\! \let\ptexfootnote=\footnote \let\ptexgtr=> \let\ptexhat=^ \let\ptexi=\i \let\ptexindent=\indent \let\ptexinsert=\insert \let\ptexlbrace=\{ \let\ptexless=< \let\ptexnewwrite\newwrite \let\ptexnoindent=\noindent \let\ptexplus=+ \let\ptexraggedright=\raggedright \let\ptexrbrace=\} \let\ptexslash=\/ \let\ptexstar=\* \let\ptext=\t \let\ptextop=\top {\catcode`\'=\active \global\let\ptexquoteright'}% active in plain's math mode % If this character appears in an error message or help string, it % starts a new line in the output. \newlinechar = `^^J % Use TeX 3.0's \inputlineno to get the line number, for better error % messages, but if we're using an old version of TeX, don't do anything. % \ifx\inputlineno\thisisundefined \let\linenumber = \empty % Pre-3.0. \else \def\linenumber{l.\the\inputlineno:\space} \fi % Set up fixed words for English if not already set. \ifx\putwordAppendix\undefined \gdef\putwordAppendix{Appendix}\fi \ifx\putwordChapter\undefined \gdef\putwordChapter{Chapter}\fi \ifx\putworderror\undefined \gdef\putworderror{error}\fi \ifx\putwordfile\undefined \gdef\putwordfile{file}\fi \ifx\putwordin\undefined \gdef\putwordin{in}\fi \ifx\putwordIndexIsEmpty\undefined \gdef\putwordIndexIsEmpty{(Index is empty)}\fi \ifx\putwordIndexNonexistent\undefined \gdef\putwordIndexNonexistent{(Index is nonexistent)}\fi \ifx\putwordInfo\undefined \gdef\putwordInfo{Info}\fi \ifx\putwordInstanceVariableof\undefined \gdef\putwordInstanceVariableof{Instance Variable of}\fi \ifx\putwordMethodon\undefined \gdef\putwordMethodon{Method on}\fi \ifx\putwordNoTitle\undefined \gdef\putwordNoTitle{No Title}\fi \ifx\putwordof\undefined \gdef\putwordof{of}\fi \ifx\putwordon\undefined \gdef\putwordon{on}\fi \ifx\putwordpage\undefined \gdef\putwordpage{page}\fi \ifx\putwordsection\undefined \gdef\putwordsection{section}\fi \ifx\putwordSection\undefined \gdef\putwordSection{Section}\fi \ifx\putwordsee\undefined \gdef\putwordsee{see}\fi \ifx\putwordSee\undefined \gdef\putwordSee{See}\fi \ifx\putwordShortTOC\undefined \gdef\putwordShortTOC{Short Contents}\fi \ifx\putwordTOC\undefined \gdef\putwordTOC{Table of Contents}\fi % \ifx\putwordMJan\undefined \gdef\putwordMJan{January}\fi \ifx\putwordMFeb\undefined \gdef\putwordMFeb{February}\fi \ifx\putwordMMar\undefined \gdef\putwordMMar{March}\fi \ifx\putwordMApr\undefined \gdef\putwordMApr{April}\fi \ifx\putwordMMay\undefined \gdef\putwordMMay{May}\fi \ifx\putwordMJun\undefined \gdef\putwordMJun{June}\fi \ifx\putwordMJul\undefined \gdef\putwordMJul{July}\fi \ifx\putwordMAug\undefined \gdef\putwordMAug{August}\fi \ifx\putwordMSep\undefined \gdef\putwordMSep{September}\fi \ifx\putwordMOct\undefined \gdef\putwordMOct{October}\fi \ifx\putwordMNov\undefined \gdef\putwordMNov{November}\fi \ifx\putwordMDec\undefined \gdef\putwordMDec{December}\fi % \ifx\putwordDefmac\undefined \gdef\putwordDefmac{Macro}\fi \ifx\putwordDefspec\undefined \gdef\putwordDefspec{Special Form}\fi \ifx\putwordDefvar\undefined \gdef\putwordDefvar{Variable}\fi \ifx\putwordDefopt\undefined \gdef\putwordDefopt{User Option}\fi \ifx\putwordDeffunc\undefined \gdef\putwordDeffunc{Function}\fi % Since the category of space is not known, we have to be careful. \chardef\spacecat = 10 \def\spaceisspace{\catcode`\ =\spacecat} % sometimes characters are active, so we need control sequences. \chardef\ampChar = `\& \chardef\colonChar = `\: \chardef\commaChar = `\, \chardef\dashChar = `\- \chardef\dotChar = `\. \chardef\exclamChar= `\! \chardef\hashChar = `\# \chardef\lquoteChar= `\` \chardef\questChar = `\? \chardef\rquoteChar= `\' \chardef\semiChar = `\; \chardef\slashChar = `\/ \chardef\underChar = `\_ % Ignore a token. % \def\gobble#1{} % The following is used inside several \edef's. \def\makecsname#1{\expandafter\noexpand\csname#1\endcsname} % Hyphenation fixes. \hyphenation{ Flor-i-da Ghost-script Ghost-view Mac-OS Post-Script ap-pen-dix bit-map bit-maps data-base data-bases eshell fall-ing half-way long-est man-u-script man-u-scripts mini-buf-fer mini-buf-fers over-view par-a-digm par-a-digms rath-er rec-tan-gu-lar ro-bot-ics se-vere-ly set-up spa-ces spell-ing spell-ings stand-alone strong-est time-stamp time-stamps which-ever white-space wide-spread wrap-around } % Margin to add to right of even pages, to left of odd pages. \newdimen\bindingoffset \newdimen\normaloffset \newdimen\pagewidth \newdimen\pageheight % For a final copy, take out the rectangles % that mark overfull boxes (in case you have decided % that the text looks ok even though it passes the margin). % \def\finalout{\overfullrule=0pt } % Sometimes it is convenient to have everything in the transcript file % and nothing on the terminal. We don't just call \tracingall here, % since that produces some useless output on the terminal. We also make % some effort to order the tracing commands to reduce output in the log % file; cf. trace.sty in LaTeX. % \def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}% \def\loggingall{% \tracingstats2 \tracingpages1 \tracinglostchars2 % 2 gives us more in etex \tracingparagraphs1 \tracingoutput1 \tracingmacros2 \tracingrestores1 \showboxbreadth\maxdimen \showboxdepth\maxdimen \ifx\eTeXversion\thisisundefined\else % etex gives us more logging \tracingscantokens1 \tracingifs1 \tracinggroups1 \tracingnesting2 \tracingassigns1 \fi \tracingcommands3 % 3 gives us more in etex \errorcontextlines16 }% % @errormsg{MSG}. Do the index-like expansions on MSG, but if things % aren't perfect, it's not the end of the world, being an error message, % after all. % \def\errormsg{\begingroup \indexnofonts \doerrormsg} \def\doerrormsg#1{\errmessage{#1}} % add check for \lastpenalty to plain's definitions. If the last thing % we did was a \nobreak, we don't want to insert more space. % \def\smallbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\smallskipamount \removelastskip\penalty-50\smallskip\fi\fi} \def\medbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\medskipamount \removelastskip\penalty-100\medskip\fi\fi} \def\bigbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\bigskipamount \removelastskip\penalty-200\bigskip\fi\fi} % Do @cropmarks to get crop marks. % \newif\ifcropmarks \let\cropmarks = \cropmarkstrue % % Dimensions to add cropmarks at corners. % Added by P. A. MacKay, 12 Nov. 1986 % \newdimen\outerhsize \newdimen\outervsize % set by the paper size routines \newdimen\cornerlong \cornerlong=1pc \newdimen\cornerthick \cornerthick=.3pt \newdimen\topandbottommargin \topandbottommargin=.75in % Output a mark which sets \thischapter, \thissection and \thiscolor. % We dump everything together because we only have one kind of mark. % This works because we only use \botmark / \topmark, not \firstmark. % % A mark contains a subexpression of the \ifcase ... \fi construct. % \get*marks macros below extract the needed part using \ifcase. % % Another complication is to let the user choose whether \thischapter % (\thissection) refers to the chapter (section) in effect at the top % of a page, or that at the bottom of a page. The solution is % described on page 260 of The TeXbook. It involves outputting two % marks for the sectioning macros, one before the section break, and % one after. I won't pretend I can describe this better than DEK... \def\domark{% \toks0=\expandafter{\lastchapterdefs}% \toks2=\expandafter{\lastsectiondefs}% \toks4=\expandafter{\prevchapterdefs}% \toks6=\expandafter{\prevsectiondefs}% \toks8=\expandafter{\lastcolordefs}% \mark{% \the\toks0 \the\toks2 \noexpand\or \the\toks4 \the\toks6 \noexpand\else \the\toks8 }% } % \topmark doesn't work for the very first chapter (after the title % page or the contents), so we use \firstmark there -- this gets us % the mark with the chapter defs, unless the user sneaks in, e.g., % @setcolor (or @url, or @link, etc.) between @contents and the very % first @chapter. \def\gettopheadingmarks{% \ifcase0\topmark\fi \ifx\thischapter\empty \ifcase0\firstmark\fi \fi } \def\getbottomheadingmarks{\ifcase1\botmark\fi} \def\getcolormarks{\ifcase2\topmark\fi} % Avoid "undefined control sequence" errors. \def\lastchapterdefs{} \def\lastsectiondefs{} \def\prevchapterdefs{} \def\prevsectiondefs{} \def\lastcolordefs{} % Main output routine. \chardef\PAGE = 255 \output = {\onepageout{\pagecontents\PAGE}} \newbox\headlinebox \newbox\footlinebox % \onepageout takes a vbox as an argument. Note that \pagecontents % does insertions, but you have to call it yourself. \def\onepageout#1{% \ifcropmarks \hoffset=0pt \else \hoffset=\normaloffset \fi % \ifodd\pageno \advance\hoffset by \bindingoffset \else \advance\hoffset by -\bindingoffset\fi % % Do this outside of the \shipout so @code etc. will be expanded in % the headline as they should be, not taken literally (outputting ''code). \ifodd\pageno \getoddheadingmarks \else \getevenheadingmarks \fi \setbox\headlinebox = \vbox{\let\hsize=\pagewidth \makeheadline}% \ifodd\pageno \getoddfootingmarks \else \getevenfootingmarks \fi \setbox\footlinebox = \vbox{\let\hsize=\pagewidth \makefootline}% % {% % Have to do this stuff outside the \shipout because we want it to % take effect in \write's, yet the group defined by the \vbox ends % before the \shipout runs. % \indexdummies % don't expand commands in the output. \normalturnoffactive % \ in index entries must not stay \, e.g., if % the page break happens to be in the middle of an example. % We don't want .vr (or whatever) entries like this: % \entry{{\tt \indexbackslash }acronym}{32}{\code {\acronym}} % "\acronym" won't work when it's read back in; % it needs to be % {\code {{\tt \backslashcurfont }acronym} \shipout\vbox{% % Do this early so pdf references go to the beginning of the page. \ifpdfmakepagedest \pdfdest name{\the\pageno} xyz\fi % \ifcropmarks \vbox to \outervsize\bgroup \hsize = \outerhsize \vskip-\topandbottommargin \vtop to0pt{% \line{\ewtop\hfil\ewtop}% \nointerlineskip \line{% \vbox{\moveleft\cornerthick\nstop}% \hfill \vbox{\moveright\cornerthick\nstop}% }% \vss}% \vskip\topandbottommargin \line\bgroup \hfil % center the page within the outer (page) hsize. \ifodd\pageno\hskip\bindingoffset\fi \vbox\bgroup \fi % \unvbox\headlinebox \pagebody{#1}% \ifdim\ht\footlinebox > 0pt % Only leave this space if the footline is nonempty. % (We lessened \vsize for it in \oddfootingyyy.) % The \baselineskip=24pt in plain's \makefootline has no effect. \vskip 24pt \unvbox\footlinebox \fi % \ifcropmarks \egroup % end of \vbox\bgroup \hfil\egroup % end of (centering) \line\bgroup \vskip\topandbottommargin plus1fill minus1fill \boxmaxdepth = \cornerthick \vbox to0pt{\vss \line{% \vbox{\moveleft\cornerthick\nsbot}% \hfill \vbox{\moveright\cornerthick\nsbot}% }% \nointerlineskip \line{\ewbot\hfil\ewbot}% }% \egroup % \vbox from first cropmarks clause \fi }% end of \shipout\vbox }% end of group with \indexdummies \advancepageno \ifnum\outputpenalty>-20000 \else\dosupereject\fi } \newinsert\margin \dimen\margin=\maxdimen \def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}} {\catcode`\@ =11 \gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi % marginal hacks, juha@viisa.uucp (Juha Takala) \ifvoid\margin\else % marginal info is present \rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\fi \dimen@=\dp#1\relax \unvbox#1\relax \ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi \ifr@ggedbottom \kern-\dimen@ \vfil \fi} } % Here are the rules for the cropmarks. Note that they are % offset so that the space between them is truly \outerhsize or \outervsize % (P. A. MacKay, 12 November, 1986) % \def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong} \def\nstop{\vbox {\hrule height\cornerthick depth\cornerlong width\cornerthick}} \def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong} \def\nsbot{\vbox {\hrule height\cornerlong depth\cornerthick width\cornerthick}} % Parse an argument, then pass it to #1. The argument is the rest of % the input line (except we remove a trailing comment). #1 should be a % macro which expects an ordinary undelimited TeX argument. % \def\parsearg{\parseargusing{}} \def\parseargusing#1#2{% \def\argtorun{#2}% \begingroup \obeylines \spaceisspace #1% \parseargline\empty% Insert the \empty token, see \finishparsearg below. } {\obeylines % \gdef\parseargline#1^^M{% \endgroup % End of the group started in \parsearg. \argremovecomment #1\comment\ArgTerm% }% } % First remove any @comment, then any @c comment. \def\argremovecomment#1\comment#2\ArgTerm{\argremovec #1\c\ArgTerm} \def\argremovec#1\c#2\ArgTerm{\argcheckspaces#1\^^M\ArgTerm} % Each occurrence of `\^^M' or `\^^M' is replaced by a single space. % % \argremovec might leave us with trailing space, e.g., % @end itemize @c foo % This space token undergoes the same procedure and is eventually removed % by \finishparsearg. % \def\argcheckspaces#1\^^M{\argcheckspacesX#1\^^M \^^M} \def\argcheckspacesX#1 \^^M{\argcheckspacesY#1\^^M} \def\argcheckspacesY#1\^^M#2\^^M#3\ArgTerm{% \def\temp{#3}% \ifx\temp\empty % Do not use \next, perhaps the caller of \parsearg uses it; reuse \temp: \let\temp\finishparsearg \else \let\temp\argcheckspaces \fi % Put the space token in: \temp#1 #3\ArgTerm } % If a _delimited_ argument is enclosed in braces, they get stripped; so % to get _exactly_ the rest of the line, we had to prevent such situation. % We prepended an \empty token at the very beginning and we expand it now, % just before passing the control to \argtorun. % (Similarly, we have to think about #3 of \argcheckspacesY above: it is % either the null string, or it ends with \^^M---thus there is no danger % that a pair of braces would be stripped. % % But first, we have to remove the trailing space token. % \def\finishparsearg#1 \ArgTerm{\expandafter\argtorun\expandafter{#1}} % \parseargdef\foo{...} % is roughly equivalent to % \def\foo{\parsearg\Xfoo} % \def\Xfoo#1{...} % % Actually, I use \csname\string\foo\endcsname, ie. \\foo, as it is my % favourite TeX trick. --kasal, 16nov03 \def\parseargdef#1{% \expandafter \doparseargdef \csname\string#1\endcsname #1% } \def\doparseargdef#1#2{% \def#2{\parsearg#1}% \def#1##1% } % Several utility definitions with active space: { \obeyspaces \gdef\obeyedspace{ } % Make each space character in the input produce a normal interword % space in the output. Don't allow a line break at this space, as this % is used only in environments like @example, where each line of input % should produce a line of output anyway. % \gdef\sepspaces{\obeyspaces\let =\tie} % If an index command is used in an @example environment, any spaces % therein should become regular spaces in the raw index file, not the % expansion of \tie (\leavevmode \penalty \@M \ ). \gdef\unsepspaces{\let =\space} } \def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next} % Define the framework for environments in texinfo.tex. It's used like this: % % \envdef\foo{...} % \def\Efoo{...} % % It's the responsibility of \envdef to insert \begingroup before the % actual body; @end closes the group after calling \Efoo. \envdef also % defines \thisenv, so the current environment is known; @end checks % whether the environment name matches. The \checkenv macro can also be % used to check whether the current environment is the one expected. % % Non-false conditionals (@iftex, @ifset) don't fit into this, so they % are not treated as environments; they don't open a group. (The % implementation of @end takes care not to call \endgroup in this % special case.) % At run-time, environments start with this: \def\startenvironment#1{\begingroup\def\thisenv{#1}} % initialize \let\thisenv\empty % ... but they get defined via ``\envdef\foo{...}'': \long\def\envdef#1#2{\def#1{\startenvironment#1#2}} \def\envparseargdef#1#2{\parseargdef#1{\startenvironment#1#2}} % Check whether we're in the right environment: \def\checkenv#1{% \def\temp{#1}% \ifx\thisenv\temp \else \badenverr \fi } % Environment mismatch, #1 expected: \def\badenverr{% \errhelp = \EMsimple \errmessage{This command can appear only \inenvironment\temp, not \inenvironment\thisenv}% } \def\inenvironment#1{% \ifx#1\empty outside of any environment% \else in environment \expandafter\string#1% \fi } % @end foo executes the definition of \Efoo. % But first, it executes a specialized version of \checkenv % \parseargdef\end{% \if 1\csname iscond.#1\endcsname \else % The general wording of \badenverr may not be ideal. \expandafter\checkenv\csname#1\endcsname \csname E#1\endcsname \endgroup \fi } \newhelp\EMsimple{Press RETURN to continue.} % Be sure we're in horizontal mode when doing a tie, since we make space % equivalent to this in @example-like environments. Otherwise, a space % at the beginning of a line will start with \penalty -- and % since \penalty is valid in vertical mode, we'd end up putting the % penalty on the vertical list instead of in the new paragraph. {\catcode`@ = 11 % Avoid using \@M directly, because that causes trouble % if the definition is written into an index file. \global\let\tiepenalty = \@M \gdef\tie{\leavevmode\penalty\tiepenalty\ } } % @: forces normal size whitespace following. \def\:{\spacefactor=1000 } % @* forces a line break. \def\*{\unskip\hfil\break\hbox{}\ignorespaces} % @/ allows a line break. \let\/=\allowbreak % @. is an end-of-sentence period. \def\.{.\spacefactor=\endofsentencespacefactor\space} % @! is an end-of-sentence bang. \def\!{!\spacefactor=\endofsentencespacefactor\space} % @? is an end-of-sentence query. \def\?{?\spacefactor=\endofsentencespacefactor\space} % @frenchspacing on|off says whether to put extra space after punctuation. % \def\onword{on} \def\offword{off} % \parseargdef\frenchspacing{% \def\temp{#1}% \ifx\temp\onword \plainfrenchspacing \else\ifx\temp\offword \plainnonfrenchspacing \else \errhelp = \EMsimple \errmessage{Unknown @frenchspacing option `\temp', must be on|off}% \fi\fi } % @w prevents a word break. Without the \leavevmode, @w at the % beginning of a paragraph, when TeX is still in vertical mode, would % produce a whole line of output instead of starting the paragraph. \def\w#1{\leavevmode\hbox{#1}} % @group ... @end group forces ... to be all on one page, by enclosing % it in a TeX vbox. We use \vtop instead of \vbox to construct the box % to keep its height that of a normal line. According to the rules for % \topskip (p.114 of the TeXbook), the glue inserted is % max (\topskip - \ht (first item), 0). If that height is large, % therefore, no glue is inserted, and the space between the headline and % the text is small, which looks bad. % % Another complication is that the group might be very large. This can % cause the glue on the previous page to be unduly stretched, because it % does not have much material. In this case, it's better to add an % explicit \vfill so that the extra space is at the bottom. The % threshold for doing this is if the group is more than \vfilllimit % percent of a page (\vfilllimit can be changed inside of @tex). % \newbox\groupbox \def\vfilllimit{0.7} % \envdef\group{% \ifnum\catcode`\^^M=\active \else \errhelp = \groupinvalidhelp \errmessage{@group invalid in context where filling is enabled}% \fi \startsavinginserts % \setbox\groupbox = \vtop\bgroup % Do @comment since we are called inside an environment such as % @example, where each end-of-line in the input causes an % end-of-line in the output. We don't want the end-of-line after % the `@group' to put extra space in the output. Since @group % should appear on a line by itself (according to the Texinfo % manual), we don't worry about eating any user text. \comment } % % The \vtop produces a box with normal height and large depth; thus, TeX puts % \baselineskip glue before it, and (when the next line of text is done) % \lineskip glue after it. Thus, space below is not quite equal to space % above. But it's pretty close. \def\Egroup{% % To get correct interline space between the last line of the group % and the first line afterwards, we have to propagate \prevdepth. \endgraf % Not \par, as it may have been set to \lisppar. \global\dimen1 = \prevdepth \egroup % End the \vtop. % \dimen0 is the vertical size of the group's box. \dimen0 = \ht\groupbox \advance\dimen0 by \dp\groupbox % \dimen2 is how much space is left on the page (more or less). \dimen2 = \pageheight \advance\dimen2 by -\pagetotal % if the group doesn't fit on the current page, and it's a big big % group, force a page break. \ifdim \dimen0 > \dimen2 \ifdim \pagetotal < \vfilllimit\pageheight \page \fi \fi \box\groupbox \prevdepth = \dimen1 \checkinserts } % % TeX puts in an \escapechar (i.e., `@') at the beginning of the help % message, so this ends up printing `@group can only ...'. % \newhelp\groupinvalidhelp{% group can only be used in environments such as @example,^^J% where each line of input produces a line of output.} % @need space-in-mils % forces a page break if there is not space-in-mils remaining. \newdimen\mil \mil=0.001in \parseargdef\need{% % Ensure vertical mode, so we don't make a big box in the middle of a % paragraph. \par % % If the @need value is less than one line space, it's useless. \dimen0 = #1\mil \dimen2 = \ht\strutbox \advance\dimen2 by \dp\strutbox \ifdim\dimen0 > \dimen2 % % Do a \strut just to make the height of this box be normal, so the % normal leading is inserted relative to the preceding line. % And a page break here is fine. \vtop to #1\mil{\strut\vfil}% % % TeX does not even consider page breaks if a penalty added to the % main vertical list is 10000 or more. But in order to see if the % empty box we just added fits on the page, we must make it consider % page breaks. On the other hand, we don't want to actually break the % page after the empty box. So we use a penalty of 9999. % % There is an extremely small chance that TeX will actually break the % page at this \penalty, if there are no other feasible breakpoints in % sight. (If the user is using lots of big @group commands, which % almost-but-not-quite fill up a page, TeX will have a hard time doing % good page breaking, for example.) However, I could not construct an % example where a page broke at this \penalty; if it happens in a real % document, then we can reconsider our strategy. \penalty9999 % % Back up by the size of the box, whether we did a page break or not. \kern -#1\mil % % Do not allow a page break right after this kern. \nobreak \fi } % @br forces paragraph break (and is undocumented). \let\br = \par % @page forces the start of a new page. % \def\page{\par\vfill\supereject} % @exdent text.... % outputs text on separate line in roman font, starting at standard page margin % This records the amount of indent in the innermost environment. % That's how much \exdent should take out. \newskip\exdentamount % This defn is used inside fill environments such as @defun. \parseargdef\exdent{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break} % This defn is used inside nofill environments such as @example. \parseargdef\nofillexdent{{\advance \leftskip by -\exdentamount \leftline{\hskip\leftskip{\rm#1}}}} % @inmargin{WHICH}{TEXT} puts TEXT in the WHICH margin next to the current % paragraph. For more general purposes, use the \margin insertion % class. WHICH is `l' or `r'. Not documented, written for gawk manual. % \newskip\inmarginspacing \inmarginspacing=1cm \def\strutdepth{\dp\strutbox} % \def\doinmargin#1#2{\strut\vadjust{% \nobreak \kern-\strutdepth \vtop to \strutdepth{% \baselineskip=\strutdepth \vss % if you have multiple lines of stuff to put here, you'll need to % make the vbox yourself of the appropriate size. \ifx#1l% \llap{\ignorespaces #2\hskip\inmarginspacing}% \else \rlap{\hskip\hsize \hskip\inmarginspacing \ignorespaces #2}% \fi \null }% }} \def\inleftmargin{\doinmargin l} \def\inrightmargin{\doinmargin r} % % @inmargin{TEXT [, RIGHT-TEXT]} % (if RIGHT-TEXT is given, use TEXT for left page, RIGHT-TEXT for right; % else use TEXT for both). % \def\inmargin#1{\parseinmargin #1,,\finish} \def\parseinmargin#1,#2,#3\finish{% not perfect, but better than nothing. \setbox0 = \hbox{\ignorespaces #2}% \ifdim\wd0 > 0pt \def\lefttext{#1}% have both texts \def\righttext{#2}% \else \def\lefttext{#1}% have only one text \def\righttext{#1}% \fi % \ifodd\pageno \def\temp{\inrightmargin\righttext}% odd page -> outside is right margin \else \def\temp{\inleftmargin\lefttext}% \fi \temp } % @| inserts a changebar to the left of the current line. It should % surround any changed text. This approach does *not* work if the % change spans more than two lines of output. To handle that, we would % have adopt a much more difficult approach (putting marks into the main % vertical list for the beginning and end of each change). This command % is not documented, not supported, and doesn't work. % \def\|{% % \vadjust can only be used in horizontal mode. \leavevmode % % Append this vertical mode material after the current line in the output. \vadjust{% % We want to insert a rule with the height and depth of the current % leading; that is exactly what \strutbox is supposed to record. \vskip-\baselineskip % % \vadjust-items are inserted at the left edge of the type. So % the \llap here moves out into the left-hand margin. \llap{% % % For a thicker or thinner bar, change the `1pt'. \vrule height\baselineskip width1pt % % This is the space between the bar and the text. \hskip 12pt }% }% } % @include FILE -- \input text of FILE. % \def\include{\parseargusing\filenamecatcodes\includezzz} \def\includezzz#1{% \pushthisfilestack \def\thisfile{#1}% {% \makevalueexpandable % we want to expand any @value in FILE. \turnoffactive % and allow special characters in the expansion \indexnofonts % Allow `@@' and other weird things in file names. \wlog{texinfo.tex: doing @include of #1^^J}% \edef\temp{\noexpand\input #1 }% % % This trickery is to read FILE outside of a group, in case it makes % definitions, etc. \expandafter }\temp \popthisfilestack } \def\filenamecatcodes{% \catcode`\\=\other \catcode`~=\other \catcode`^=\other \catcode`_=\other \catcode`|=\other \catcode`<=\other \catcode`>=\other \catcode`+=\other \catcode`-=\other \catcode`\`=\other \catcode`\'=\other } \def\pushthisfilestack{% \expandafter\pushthisfilestackX\popthisfilestack\StackTerm } \def\pushthisfilestackX{% \expandafter\pushthisfilestackY\thisfile\StackTerm } \def\pushthisfilestackY #1\StackTerm #2\StackTerm {% \gdef\popthisfilestack{\gdef\thisfile{#1}\gdef\popthisfilestack{#2}}% } \def\popthisfilestack{\errthisfilestackempty} \def\errthisfilestackempty{\errmessage{Internal error: the stack of filenames is empty.}} % \def\thisfile{} % @center line % outputs that line, centered. % \parseargdef\center{% \ifhmode \let\centersub\centerH \else \let\centersub\centerV \fi \centersub{\hfil \ignorespaces#1\unskip \hfil}% \let\centersub\relax % don't let the definition persist, just in case } \def\centerH#1{{% \hfil\break \advance\hsize by -\leftskip \advance\hsize by -\rightskip \line{#1}% \break }} % \newcount\centerpenalty \def\centerV#1{% % The idea here is the same as in \startdefun, \cartouche, etc.: if % @center is the first thing after a section heading, we need to wipe % out the negative parskip inserted by \sectionheading, but still % prevent a page break here. \centerpenalty = \lastpenalty \ifnum\centerpenalty>10000 \vskip\parskip \fi \ifnum\centerpenalty>9999 \penalty\centerpenalty \fi \line{\kern\leftskip #1\kern\rightskip}% } % @sp n outputs n lines of vertical space % \parseargdef\sp{\vskip #1\baselineskip} % @comment ...line which is ignored... % @c is the same as @comment % @ignore ... @end ignore is another way to write a comment % \def\comment{\begingroup \catcode`\^^M=\other% \catcode`\@=\other \catcode`\{=\other \catcode`\}=\other% \commentxxx} {\catcode`\^^M=\other \gdef\commentxxx#1^^M{\endgroup}} % \let\c=\comment % @paragraphindent NCHARS % We'll use ems for NCHARS, close enough. % NCHARS can also be the word `asis' or `none'. % We cannot feasibly implement @paragraphindent asis, though. % \def\asisword{asis} % no translation, these are keywords \def\noneword{none} % \parseargdef\paragraphindent{% \def\temp{#1}% \ifx\temp\asisword \else \ifx\temp\noneword \defaultparindent = 0pt \else \defaultparindent = #1em \fi \fi \parindent = \defaultparindent } % @exampleindent NCHARS % We'll use ems for NCHARS like @paragraphindent. % It seems @exampleindent asis isn't necessary, but % I preserve it to make it similar to @paragraphindent. \parseargdef\exampleindent{% \def\temp{#1}% \ifx\temp\asisword \else \ifx\temp\noneword \lispnarrowing = 0pt \else \lispnarrowing = #1em \fi \fi } % @firstparagraphindent WORD % If WORD is `none', then suppress indentation of the first paragraph % after a section heading. If WORD is `insert', then do indent at such % paragraphs. % % The paragraph indentation is suppressed or not by calling % \suppressfirstparagraphindent, which the sectioning commands do. % We switch the definition of this back and forth according to WORD. % By default, we suppress indentation. % \def\suppressfirstparagraphindent{\dosuppressfirstparagraphindent} \def\insertword{insert} % \parseargdef\firstparagraphindent{% \def\temp{#1}% \ifx\temp\noneword \let\suppressfirstparagraphindent = \dosuppressfirstparagraphindent \else\ifx\temp\insertword \let\suppressfirstparagraphindent = \relax \else \errhelp = \EMsimple \errmessage{Unknown @firstparagraphindent option `\temp'}% \fi\fi } % Here is how we actually suppress indentation. Redefine \everypar to % \kern backwards by \parindent, and then reset itself to empty. % % We also make \indent itself not actually do anything until the next % paragraph. % \gdef\dosuppressfirstparagraphindent{% \gdef\indent{% \restorefirstparagraphindent \indent }% \gdef\noindent{% \restorefirstparagraphindent \noindent }% \global\everypar = {% \kern -\parindent \restorefirstparagraphindent }% } \gdef\restorefirstparagraphindent{% \global \let \indent = \ptexindent \global \let \noindent = \ptexnoindent \global \everypar = {}% } % @refill is a no-op. \let\refill=\relax % If working on a large document in chapters, it is convenient to % be able to disable indexing, cross-referencing, and contents, for test runs. % This is done with @novalidate (before @setfilename). % \newif\iflinks \linkstrue % by default we want the aux files. \let\novalidate = \linksfalse % @setfilename is done at the beginning of every texinfo file. % So open here the files we need to have open while reading the input. % This makes it possible to make a .fmt file for texinfo. \def\setfilename{% \fixbackslash % Turn off hack to swallow `\input texinfo'. \iflinks \tryauxfile % Open the new aux file. TeX will close it automatically at exit. \immediate\openout\auxfile=\jobname.aux \fi % \openindices needs to do some work in any case. \openindices \let\setfilename=\comment % Ignore extra @setfilename cmds. % % If texinfo.cnf is present on the system, read it. % Useful for site-wide @afourpaper, etc. \openin 1 texinfo.cnf \ifeof 1 \else \input texinfo.cnf \fi \closein 1 % \comment % Ignore the actual filename. } % Called from \setfilename. % \def\openindices{% \newindex{cp}% \newcodeindex{fn}% \newcodeindex{vr}% \newcodeindex{tp}% \newcodeindex{ky}% \newcodeindex{pg}% } % @bye. \outer\def\bye{\pagealignmacro\tracingstats=1\ptexend} \message{pdf,} % adobe `portable' document format \newcount\tempnum \newcount\lnkcount \newtoks\filename \newcount\filenamelength \newcount\pgn \newtoks\toksA \newtoks\toksB \newtoks\toksC \newtoks\toksD \newbox\boxA \newcount\countA \newif\ifpdf \newif\ifpdfmakepagedest % when pdftex is run in dvi mode, \pdfoutput is defined (so \pdfoutput=1 % can be set). So we test for \relax and 0 as well as being undefined. \ifx\pdfoutput\thisisundefined \else \ifx\pdfoutput\relax \else \ifcase\pdfoutput \else \pdftrue \fi \fi \fi % PDF uses PostScript string constants for the names of xref targets, % for display in the outlines, and in other places. Thus, we have to % double any backslashes. Otherwise, a name like "\node" will be % interpreted as a newline (\n), followed by o, d, e. Not good. % % See http://www.ntg.nl/pipermail/ntg-pdftex/2004-July/000654.html and % related messages. The final outcome is that it is up to the TeX user % to double the backslashes and otherwise make the string valid, so % that's what we do. pdftex 1.30.0 (ca.2005) introduced a primitive to % do this reliably, so we use it. % #1 is a control sequence in which to do the replacements, % which we \xdef. \def\txiescapepdf#1{% \ifx\pdfescapestring\thisisundefined % No primitive available; should we give a warning or log? % Many times it won't matter. \else % The expandable \pdfescapestring primitive escapes parentheses, % backslashes, and other special chars. \xdef#1{\pdfescapestring{#1}}% \fi } \newhelp\nopdfimagehelp{Texinfo supports .png, .jpg, .jpeg, and .pdf images with PDF output, and none of those formats could be found. (.eps cannot be supported due to the design of the PDF format; use regular TeX (DVI output) for that.)} \ifpdf % % Color manipulation macros based on pdfcolor.tex, % except using rgb instead of cmyk; the latter is said to render as a % very dark gray on-screen and a very dark halftone in print, instead % of actual black. \def\rgbDarkRed{0.50 0.09 0.12} \def\rgbBlack{0 0 0} % % k sets the color for filling (usual text, etc.); % K sets the color for stroking (thin rules, e.g., normal _'s). \def\pdfsetcolor#1{\pdfliteral{#1 rg #1 RG}} % % Set color, and create a mark which defines \thiscolor accordingly, % so that \makeheadline knows which color to restore. \def\setcolor#1{% \xdef\lastcolordefs{\gdef\noexpand\thiscolor{#1}}% \domark \pdfsetcolor{#1}% } % \def\maincolor{\rgbBlack} \pdfsetcolor{\maincolor} \edef\thiscolor{\maincolor} \def\lastcolordefs{} % \def\makefootline{% \baselineskip24pt \line{\pdfsetcolor{\maincolor}\the\footline}% } % \def\makeheadline{% \vbox to 0pt{% \vskip-22.5pt \line{% \vbox to8.5pt{}% % Extract \thiscolor definition from the marks. \getcolormarks % Typeset the headline with \maincolor, then restore the color. \pdfsetcolor{\maincolor}\the\headline\pdfsetcolor{\thiscolor}% }% \vss }% \nointerlineskip } % % \pdfcatalog{/PageMode /UseOutlines} % % #1 is image name, #2 width (might be empty/whitespace), #3 height (ditto). \def\dopdfimage#1#2#3{% \def\pdfimagewidth{#2}\setbox0 = \hbox{\ignorespaces #2}% \def\pdfimageheight{#3}\setbox2 = \hbox{\ignorespaces #3}% % % pdftex (and the PDF format) support .pdf, .png, .jpg (among % others). Let's try in that order, PDF first since if % someone has a scalable image, presumably better to use that than a % bitmap. \let\pdfimgext=\empty \begingroup \openin 1 #1.pdf \ifeof 1 \openin 1 #1.PDF \ifeof 1 \openin 1 #1.png \ifeof 1 \openin 1 #1.jpg \ifeof 1 \openin 1 #1.jpeg \ifeof 1 \openin 1 #1.JPG \ifeof 1 \errhelp = \nopdfimagehelp \errmessage{Could not find image file #1 for pdf}% \else \gdef\pdfimgext{JPG}% \fi \else \gdef\pdfimgext{jpeg}% \fi \else \gdef\pdfimgext{jpg}% \fi \else \gdef\pdfimgext{png}% \fi \else \gdef\pdfimgext{PDF}% \fi \else \gdef\pdfimgext{pdf}% \fi \closein 1 \endgroup % % without \immediate, ancient pdftex seg faults when the same image is % included twice. (Version 3.14159-pre-1.0-unofficial-20010704.) \ifnum\pdftexversion < 14 \immediate\pdfimage \else \immediate\pdfximage \fi \ifdim \wd0 >0pt width \pdfimagewidth \fi \ifdim \wd2 >0pt height \pdfimageheight \fi \ifnum\pdftexversion<13 #1.\pdfimgext \else {#1.\pdfimgext}% \fi \ifnum\pdftexversion < 14 \else \pdfrefximage \pdflastximage \fi} % \def\pdfmkdest#1{{% % We have to set dummies so commands such as @code, and characters % such as \, aren't expanded when present in a section title. \indexnofonts \turnoffactive \makevalueexpandable \def\pdfdestname{#1}% \txiescapepdf\pdfdestname \safewhatsit{\pdfdest name{\pdfdestname} xyz}% }} % % used to mark target names; must be expandable. \def\pdfmkpgn#1{#1} % % by default, use a color that is dark enough to print on paper as % nearly black, but still distinguishable for online viewing. \def\urlcolor{\rgbDarkRed} \def\linkcolor{\rgbDarkRed} \def\endlink{\setcolor{\maincolor}\pdfendlink} % % Adding outlines to PDF; macros for calculating structure of outlines % come from Petr Olsak \def\expnumber#1{\expandafter\ifx\csname#1\endcsname\relax 0% \else \csname#1\endcsname \fi} \def\advancenumber#1{\tempnum=\expnumber{#1}\relax \advance\tempnum by 1 \expandafter\xdef\csname#1\endcsname{\the\tempnum}} % % #1 is the section text, which is what will be displayed in the % outline by the pdf viewer. #2 is the pdf expression for the number % of subentries (or empty, for subsubsections). #3 is the node text, % which might be empty if this toc entry had no corresponding node. % #4 is the page number % \def\dopdfoutline#1#2#3#4{% % Generate a link to the node text if that exists; else, use the % page number. We could generate a destination for the section % text in the case where a section has no node, but it doesn't % seem worth the trouble, since most documents are normally structured. \edef\pdfoutlinedest{#3}% \ifx\pdfoutlinedest\empty \def\pdfoutlinedest{#4}% \else \txiescapepdf\pdfoutlinedest \fi % % Also escape PDF chars in the display string. \edef\pdfoutlinetext{#1}% \txiescapepdf\pdfoutlinetext % \pdfoutline goto name{\pdfmkpgn{\pdfoutlinedest}}#2{\pdfoutlinetext}% } % \def\pdfmakeoutlines{% \begingroup % Read toc silently, to get counts of subentries for \pdfoutline. \def\partentry##1##2##3##4{}% ignore parts in the outlines \def\numchapentry##1##2##3##4{% \def\thischapnum{##2}% \def\thissecnum{0}% \def\thissubsecnum{0}% }% \def\numsecentry##1##2##3##4{% \advancenumber{chap\thischapnum}% \def\thissecnum{##2}% \def\thissubsecnum{0}% }% \def\numsubsecentry##1##2##3##4{% \advancenumber{sec\thissecnum}% \def\thissubsecnum{##2}% }% \def\numsubsubsecentry##1##2##3##4{% \advancenumber{subsec\thissubsecnum}% }% \def\thischapnum{0}% \def\thissecnum{0}% \def\thissubsecnum{0}% % % use \def rather than \let here because we redefine \chapentry et % al. a second time, below. \def\appentry{\numchapentry}% \def\appsecentry{\numsecentry}% \def\appsubsecentry{\numsubsecentry}% \def\appsubsubsecentry{\numsubsubsecentry}% \def\unnchapentry{\numchapentry}% \def\unnsecentry{\numsecentry}% \def\unnsubsecentry{\numsubsecentry}% \def\unnsubsubsecentry{\numsubsubsecentry}% \readdatafile{toc}% % % Read toc second time, this time actually producing the outlines. % The `-' means take the \expnumber as the absolute number of % subentries, which we calculated on our first read of the .toc above. % % We use the node names as the destinations. \def\numchapentry##1##2##3##4{% \dopdfoutline{##1}{count-\expnumber{chap##2}}{##3}{##4}}% \def\numsecentry##1##2##3##4{% \dopdfoutline{##1}{count-\expnumber{sec##2}}{##3}{##4}}% \def\numsubsecentry##1##2##3##4{% \dopdfoutline{##1}{count-\expnumber{subsec##2}}{##3}{##4}}% \def\numsubsubsecentry##1##2##3##4{% count is always zero \dopdfoutline{##1}{}{##3}{##4}}% % % PDF outlines are displayed using system fonts, instead of % document fonts. Therefore we cannot use special characters, % since the encoding is unknown. For example, the eogonek from % Latin 2 (0xea) gets translated to a | character. Info from % Staszek Wawrykiewicz, 19 Jan 2004 04:09:24 +0100. % % TODO this right, we have to translate 8-bit characters to % their "best" equivalent, based on the @documentencoding. Too % much work for too little return. Just use the ASCII equivalents % we use for the index sort strings. % \indexnofonts \setupdatafile % We can have normal brace characters in the PDF outlines, unlike % Texinfo index files. So set that up. \def\{{\lbracecharliteral}% \def\}{\rbracecharliteral}% \catcode`\\=\active \otherbackslash \input \tocreadfilename \endgroup } {\catcode`[=1 \catcode`]=2 \catcode`{=\other \catcode`}=\other \gdef\lbracecharliteral[{]% \gdef\rbracecharliteral[}]% ] % \def\skipspaces#1{\def\PP{#1}\def\D{|}% \ifx\PP\D\let\nextsp\relax \else\let\nextsp\skipspaces \addtokens{\filename}{\PP}% \advance\filenamelength by 1 \fi \nextsp} \def\getfilename#1{% \filenamelength=0 % If we don't expand the argument now, \skipspaces will get % snagged on things like "@value{foo}". \edef\temp{#1}% \expandafter\skipspaces\temp|\relax } \ifnum\pdftexversion < 14 \let \startlink \pdfannotlink \else \let \startlink \pdfstartlink \fi % make a live url in pdf output. \def\pdfurl#1{% \begingroup % it seems we really need yet another set of dummies; have not % tried to figure out what each command should do in the context % of @url. for now, just make @/ a no-op, that's the only one % people have actually reported a problem with. % \normalturnoffactive \def\@{@}% \let\/=\empty \makevalueexpandable % do we want to go so far as to use \indexnofonts instead of just % special-casing \var here? \def\var##1{##1}% % \leavevmode\setcolor{\urlcolor}% \startlink attr{/Border [0 0 0]}% user{/Subtype /Link /A << /S /URI /URI (#1) >>}% \endgroup} \def\pdfgettoks#1.{\setbox\boxA=\hbox{\toksA={#1.}\toksB={}\maketoks}} \def\addtokens#1#2{\edef\addtoks{\noexpand#1={\the#1#2}}\addtoks} \def\adn#1{\addtokens{\toksC}{#1}\global\countA=1\let\next=\maketoks} \def\poptoks#1#2|ENDTOKS|{\let\first=#1\toksD={#1}\toksA={#2}} \def\maketoks{% \expandafter\poptoks\the\toksA|ENDTOKS|\relax \ifx\first0\adn0 \else\ifx\first1\adn1 \else\ifx\first2\adn2 \else\ifx\first3\adn3 \else\ifx\first4\adn4 \else\ifx\first5\adn5 \else\ifx\first6\adn6 \else\ifx\first7\adn7 \else\ifx\first8\adn8 \else\ifx\first9\adn9 \else \ifnum0=\countA\else\makelink\fi \ifx\first.\let\next=\done\else \let\next=\maketoks \addtokens{\toksB}{\the\toksD} \ifx\first,\addtokens{\toksB}{\space}\fi \fi \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi \next} \def\makelink{\addtokens{\toksB}% {\noexpand\pdflink{\the\toksC}}\toksC={}\global\countA=0} \def\pdflink#1{% \startlink attr{/Border [0 0 0]} goto name{\pdfmkpgn{#1}} \setcolor{\linkcolor}#1\endlink} \def\done{\edef\st{\global\noexpand\toksA={\the\toksB}}\st} \else % non-pdf mode \let\pdfmkdest = \gobble \let\pdfurl = \gobble \let\endlink = \relax \let\setcolor = \gobble \let\pdfsetcolor = \gobble \let\pdfmakeoutlines = \relax \fi % \ifx\pdfoutput \message{fonts,} % Change the current font style to #1, remembering it in \curfontstyle. % For now, we do not accumulate font styles: @b{@i{foo}} prints foo in % italics, not bold italics. % \def\setfontstyle#1{% \def\curfontstyle{#1}% not as a control sequence, because we are \edef'd. \csname ten#1\endcsname % change the current font } % Select #1 fonts with the current style. % \def\selectfonts#1{\csname #1fonts\endcsname \csname\curfontstyle\endcsname} \def\rm{\fam=0 \setfontstyle{rm}} \def\it{\fam=\itfam \setfontstyle{it}} \def\sl{\fam=\slfam \setfontstyle{sl}} \def\bf{\fam=\bffam \setfontstyle{bf}}\def\bfstylename{bf} \def\tt{\fam=\ttfam \setfontstyle{tt}} % Unfortunately, we have to override this for titles and the like, since % in those cases "rm" is bold. Sigh. \def\rmisbold{\rm\def\curfontstyle{bf}} % Texinfo sort of supports the sans serif font style, which plain TeX does not. % So we set up a \sf. \newfam\sffam \def\sf{\fam=\sffam \setfontstyle{sf}} \let\li = \sf % Sometimes we call it \li, not \sf. % We don't need math for this font style. \def\ttsl{\setfontstyle{ttsl}} % Set the baselineskip to #1, and the lineskip and strut size % correspondingly. There is no deep meaning behind these magic numbers % used as factors; they just match (closely enough) what Knuth defined. % \def\lineskipfactor{.08333} \def\strutheightpercent{.70833} \def\strutdepthpercent {.29167} % % can get a sort of poor man's double spacing by redefining this. \def\baselinefactor{1} % \newdimen\textleading \def\setleading#1{% \dimen0 = #1\relax \normalbaselineskip = \baselinefactor\dimen0 \normallineskip = \lineskipfactor\normalbaselineskip \normalbaselines \setbox\strutbox =\hbox{% \vrule width0pt height\strutheightpercent\baselineskip depth \strutdepthpercent \baselineskip }% } % PDF CMaps. See also LaTeX's t1.cmap. % % do nothing with this by default. \expandafter\let\csname cmapOT1\endcsname\gobble \expandafter\let\csname cmapOT1IT\endcsname\gobble \expandafter\let\csname cmapOT1TT\endcsname\gobble % if we are producing pdf, and we have \pdffontattr, then define cmaps. % (\pdffontattr was introduced many years ago, but people still run % older pdftex's; it's easy to conditionalize, so we do.) \ifpdf \ifx\pdffontattr\thisisundefined \else \begingroup \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char. \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap %%DocumentNeededResources: ProcSet (CIDInit) %%IncludeResource: ProcSet (CIDInit) %%BeginResource: CMap (TeX-OT1-0) %%Title: (TeX-OT1-0 TeX OT1 0) %%Version: 1.000 %%EndComments /CIDInit /ProcSet findresource begin 12 dict begin begincmap /CIDSystemInfo << /Registry (TeX) /Ordering (OT1) /Supplement 0 >> def /CMapName /TeX-OT1-0 def /CMapType 2 def 1 begincodespacerange <00> <7F> endcodespacerange 8 beginbfrange <00> <01> <0393> <09> <0A> <03A8> <23> <26> <0023> <28> <3B> <0028> <3F> <5B> <003F> <5D> <5E> <005D> <61> <7A> <0061> <7B> <7C> <2013> endbfrange 40 beginbfchar <02> <0398> <03> <039B> <04> <039E> <05> <03A0> <06> <03A3> <07> <03D2> <08> <03A6> <0B> <00660066> <0C> <00660069> <0D> <0066006C> <0E> <006600660069> <0F> <00660066006C> <10> <0131> <11> <0237> <12> <0060> <13> <00B4> <14> <02C7> <15> <02D8> <16> <00AF> <17> <02DA> <18> <00B8> <19> <00DF> <1A> <00E6> <1B> <0153> <1C> <00F8> <1D> <00C6> <1E> <0152> <1F> <00D8> <21> <0021> <22> <201D> <27> <2019> <3C> <00A1> <3D> <003D> <3E> <00BF> <5C> <201C> <5F> <02D9> <60> <2018> <7D> <02DD> <7E> <007E> <7F> <00A8> endbfchar endcmap CMapName currentdict /CMap defineresource pop end end %%EndResource %%EOF }\endgroup \expandafter\edef\csname cmapOT1\endcsname#1{% \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}% }% % % \cmapOT1IT \begingroup \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char. \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap %%DocumentNeededResources: ProcSet (CIDInit) %%IncludeResource: ProcSet (CIDInit) %%BeginResource: CMap (TeX-OT1IT-0) %%Title: (TeX-OT1IT-0 TeX OT1IT 0) %%Version: 1.000 %%EndComments /CIDInit /ProcSet findresource begin 12 dict begin begincmap /CIDSystemInfo << /Registry (TeX) /Ordering (OT1IT) /Supplement 0 >> def /CMapName /TeX-OT1IT-0 def /CMapType 2 def 1 begincodespacerange <00> <7F> endcodespacerange 8 beginbfrange <00> <01> <0393> <09> <0A> <03A8> <25> <26> <0025> <28> <3B> <0028> <3F> <5B> <003F> <5D> <5E> <005D> <61> <7A> <0061> <7B> <7C> <2013> endbfrange 42 beginbfchar <02> <0398> <03> <039B> <04> <039E> <05> <03A0> <06> <03A3> <07> <03D2> <08> <03A6> <0B> <00660066> <0C> <00660069> <0D> <0066006C> <0E> <006600660069> <0F> <00660066006C> <10> <0131> <11> <0237> <12> <0060> <13> <00B4> <14> <02C7> <15> <02D8> <16> <00AF> <17> <02DA> <18> <00B8> <19> <00DF> <1A> <00E6> <1B> <0153> <1C> <00F8> <1D> <00C6> <1E> <0152> <1F> <00D8> <21> <0021> <22> <201D> <23> <0023> <24> <00A3> <27> <2019> <3C> <00A1> <3D> <003D> <3E> <00BF> <5C> <201C> <5F> <02D9> <60> <2018> <7D> <02DD> <7E> <007E> <7F> <00A8> endbfchar endcmap CMapName currentdict /CMap defineresource pop end end %%EndResource %%EOF }\endgroup \expandafter\edef\csname cmapOT1IT\endcsname#1{% \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}% }% % % \cmapOT1TT \begingroup \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char. \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap %%DocumentNeededResources: ProcSet (CIDInit) %%IncludeResource: ProcSet (CIDInit) %%BeginResource: CMap (TeX-OT1TT-0) %%Title: (TeX-OT1TT-0 TeX OT1TT 0) %%Version: 1.000 %%EndComments /CIDInit /ProcSet findresource begin 12 dict begin begincmap /CIDSystemInfo << /Registry (TeX) /Ordering (OT1TT) /Supplement 0 >> def /CMapName /TeX-OT1TT-0 def /CMapType 2 def 1 begincodespacerange <00> <7F> endcodespacerange 5 beginbfrange <00> <01> <0393> <09> <0A> <03A8> <21> <26> <0021> <28> <5F> <0028> <61> <7E> <0061> endbfrange 32 beginbfchar <02> <0398> <03> <039B> <04> <039E> <05> <03A0> <06> <03A3> <07> <03D2> <08> <03A6> <0B> <2191> <0C> <2193> <0D> <0027> <0E> <00A1> <0F> <00BF> <10> <0131> <11> <0237> <12> <0060> <13> <00B4> <14> <02C7> <15> <02D8> <16> <00AF> <17> <02DA> <18> <00B8> <19> <00DF> <1A> <00E6> <1B> <0153> <1C> <00F8> <1D> <00C6> <1E> <0152> <1F> <00D8> <20> <2423> <27> <2019> <60> <2018> <7F> <00A8> endbfchar endcmap CMapName currentdict /CMap defineresource pop end end %%EndResource %%EOF }\endgroup \expandafter\edef\csname cmapOT1TT\endcsname#1{% \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}% }% \fi\fi % Set the font macro #1 to the font named \fontprefix#2. % #3 is the font's design size, #4 is a scale factor, #5 is the CMap % encoding (only OT1, OT1IT and OT1TT are allowed, or empty to omit). % Example: % #1 = \textrm % #2 = \rmshape % #3 = 10 % #4 = \mainmagstep % #5 = OT1 % \def\setfont#1#2#3#4#5{% \font#1=\fontprefix#2#3 scaled #4 \csname cmap#5\endcsname#1% } % This is what gets called when #5 of \setfont is empty. \let\cmap\gobble % % (end of cmaps) % Use cm as the default font prefix. % To specify the font prefix, you must define \fontprefix % before you read in texinfo.tex. \ifx\fontprefix\thisisundefined \def\fontprefix{cm} \fi % Support font families that don't use the same naming scheme as CM. \def\rmshape{r} \def\rmbshape{bx} % where the normal face is bold \def\bfshape{b} \def\bxshape{bx} \def\ttshape{tt} \def\ttbshape{tt} \def\ttslshape{sltt} \def\itshape{ti} \def\itbshape{bxti} \def\slshape{sl} \def\slbshape{bxsl} \def\sfshape{ss} \def\sfbshape{ss} \def\scshape{csc} \def\scbshape{csc} % Definitions for a main text size of 11pt. (The default in Texinfo.) % \def\definetextfontsizexi{% % Text fonts (11.2pt, magstep1). \def\textnominalsize{11pt} \edef\mainmagstep{\magstephalf} \setfont\textrm\rmshape{10}{\mainmagstep}{OT1} \setfont\texttt\ttshape{10}{\mainmagstep}{OT1TT} \setfont\textbf\bfshape{10}{\mainmagstep}{OT1} \setfont\textit\itshape{10}{\mainmagstep}{OT1IT} \setfont\textsl\slshape{10}{\mainmagstep}{OT1} \setfont\textsf\sfshape{10}{\mainmagstep}{OT1} \setfont\textsc\scshape{10}{\mainmagstep}{OT1} \setfont\textttsl\ttslshape{10}{\mainmagstep}{OT1TT} \font\texti=cmmi10 scaled \mainmagstep \font\textsy=cmsy10 scaled \mainmagstep \def\textecsize{1095} % A few fonts for @defun names and args. \setfont\defbf\bfshape{10}{\magstep1}{OT1} \setfont\deftt\ttshape{10}{\magstep1}{OT1TT} \setfont\defttsl\ttslshape{10}{\magstep1}{OT1TT} \def\df{\let\tentt=\deftt \let\tenbf = \defbf \let\tenttsl=\defttsl \bf} % Fonts for indices, footnotes, small examples (9pt). \def\smallnominalsize{9pt} \setfont\smallrm\rmshape{9}{1000}{OT1} \setfont\smalltt\ttshape{9}{1000}{OT1TT} \setfont\smallbf\bfshape{10}{900}{OT1} \setfont\smallit\itshape{9}{1000}{OT1IT} \setfont\smallsl\slshape{9}{1000}{OT1} \setfont\smallsf\sfshape{9}{1000}{OT1} \setfont\smallsc\scshape{10}{900}{OT1} \setfont\smallttsl\ttslshape{10}{900}{OT1TT} \font\smalli=cmmi9 \font\smallsy=cmsy9 \def\smallecsize{0900} % Fonts for small examples (8pt). \def\smallernominalsize{8pt} \setfont\smallerrm\rmshape{8}{1000}{OT1} \setfont\smallertt\ttshape{8}{1000}{OT1TT} \setfont\smallerbf\bfshape{10}{800}{OT1} \setfont\smallerit\itshape{8}{1000}{OT1IT} \setfont\smallersl\slshape{8}{1000}{OT1} \setfont\smallersf\sfshape{8}{1000}{OT1} \setfont\smallersc\scshape{10}{800}{OT1} \setfont\smallerttsl\ttslshape{10}{800}{OT1TT} \font\smalleri=cmmi8 \font\smallersy=cmsy8 \def\smallerecsize{0800} % Fonts for title page (20.4pt): \def\titlenominalsize{20pt} \setfont\titlerm\rmbshape{12}{\magstep3}{OT1} \setfont\titleit\itbshape{10}{\magstep4}{OT1IT} \setfont\titlesl\slbshape{10}{\magstep4}{OT1} \setfont\titlett\ttbshape{12}{\magstep3}{OT1TT} \setfont\titlettsl\ttslshape{10}{\magstep4}{OT1TT} \setfont\titlesf\sfbshape{17}{\magstep1}{OT1} \let\titlebf=\titlerm \setfont\titlesc\scbshape{10}{\magstep4}{OT1} \font\titlei=cmmi12 scaled \magstep3 \font\titlesy=cmsy10 scaled \magstep4 \def\titleecsize{2074} % Chapter (and unnumbered) fonts (17.28pt). \def\chapnominalsize{17pt} \setfont\chaprm\rmbshape{12}{\magstep2}{OT1} \setfont\chapit\itbshape{10}{\magstep3}{OT1IT} \setfont\chapsl\slbshape{10}{\magstep3}{OT1} \setfont\chaptt\ttbshape{12}{\magstep2}{OT1TT} \setfont\chapttsl\ttslshape{10}{\magstep3}{OT1TT} \setfont\chapsf\sfbshape{17}{1000}{OT1} \let\chapbf=\chaprm \setfont\chapsc\scbshape{10}{\magstep3}{OT1} \font\chapi=cmmi12 scaled \magstep2 \font\chapsy=cmsy10 scaled \magstep3 \def\chapecsize{1728} % Section fonts (14.4pt). \def\secnominalsize{14pt} \setfont\secrm\rmbshape{12}{\magstep1}{OT1} \setfont\secit\itbshape{10}{\magstep2}{OT1IT} \setfont\secsl\slbshape{10}{\magstep2}{OT1} \setfont\sectt\ttbshape{12}{\magstep1}{OT1TT} \setfont\secttsl\ttslshape{10}{\magstep2}{OT1TT} \setfont\secsf\sfbshape{12}{\magstep1}{OT1} \let\secbf\secrm \setfont\secsc\scbshape{10}{\magstep2}{OT1} \font\seci=cmmi12 scaled \magstep1 \font\secsy=cmsy10 scaled \magstep2 \def\sececsize{1440} % Subsection fonts (13.15pt). \def\ssecnominalsize{13pt} \setfont\ssecrm\rmbshape{12}{\magstephalf}{OT1} \setfont\ssecit\itbshape{10}{1315}{OT1IT} \setfont\ssecsl\slbshape{10}{1315}{OT1} \setfont\ssectt\ttbshape{12}{\magstephalf}{OT1TT} \setfont\ssecttsl\ttslshape{10}{1315}{OT1TT} \setfont\ssecsf\sfbshape{12}{\magstephalf}{OT1} \let\ssecbf\ssecrm \setfont\ssecsc\scbshape{10}{1315}{OT1} \font\sseci=cmmi12 scaled \magstephalf \font\ssecsy=cmsy10 scaled 1315 \def\ssececsize{1200} % Reduced fonts for @acro in text (10pt). \def\reducednominalsize{10pt} \setfont\reducedrm\rmshape{10}{1000}{OT1} \setfont\reducedtt\ttshape{10}{1000}{OT1TT} \setfont\reducedbf\bfshape{10}{1000}{OT1} \setfont\reducedit\itshape{10}{1000}{OT1IT} \setfont\reducedsl\slshape{10}{1000}{OT1} \setfont\reducedsf\sfshape{10}{1000}{OT1} \setfont\reducedsc\scshape{10}{1000}{OT1} \setfont\reducedttsl\ttslshape{10}{1000}{OT1TT} \font\reducedi=cmmi10 \font\reducedsy=cmsy10 \def\reducedecsize{1000} \textleading = 13.2pt % line spacing for 11pt CM \textfonts % reset the current fonts \rm } % end of 11pt text font size definitions, \definetextfontsizexi % Definitions to make the main text be 10pt Computer Modern, with % section, chapter, etc., sizes following suit. This is for the GNU % Press printing of the Emacs 22 manual. Maybe other manuals in the % future. Used with @smallbook, which sets the leading to 12pt. % \def\definetextfontsizex{% % Text fonts (10pt). \def\textnominalsize{10pt} \edef\mainmagstep{1000} \setfont\textrm\rmshape{10}{\mainmagstep}{OT1} \setfont\texttt\ttshape{10}{\mainmagstep}{OT1TT} \setfont\textbf\bfshape{10}{\mainmagstep}{OT1} \setfont\textit\itshape{10}{\mainmagstep}{OT1IT} \setfont\textsl\slshape{10}{\mainmagstep}{OT1} \setfont\textsf\sfshape{10}{\mainmagstep}{OT1} \setfont\textsc\scshape{10}{\mainmagstep}{OT1} \setfont\textttsl\ttslshape{10}{\mainmagstep}{OT1TT} \font\texti=cmmi10 scaled \mainmagstep \font\textsy=cmsy10 scaled \mainmagstep \def\textecsize{1000} % A few fonts for @defun names and args. \setfont\defbf\bfshape{10}{\magstephalf}{OT1} \setfont\deftt\ttshape{10}{\magstephalf}{OT1TT} \setfont\defttsl\ttslshape{10}{\magstephalf}{OT1TT} \def\df{\let\tentt=\deftt \let\tenbf = \defbf \let\tenttsl=\defttsl \bf} % Fonts for indices, footnotes, small examples (9pt). \def\smallnominalsize{9pt} \setfont\smallrm\rmshape{9}{1000}{OT1} \setfont\smalltt\ttshape{9}{1000}{OT1TT} \setfont\smallbf\bfshape{10}{900}{OT1} \setfont\smallit\itshape{9}{1000}{OT1IT} \setfont\smallsl\slshape{9}{1000}{OT1} \setfont\smallsf\sfshape{9}{1000}{OT1} \setfont\smallsc\scshape{10}{900}{OT1} \setfont\smallttsl\ttslshape{10}{900}{OT1TT} \font\smalli=cmmi9 \font\smallsy=cmsy9 \def\smallecsize{0900} % Fonts for small examples (8pt). \def\smallernominalsize{8pt} \setfont\smallerrm\rmshape{8}{1000}{OT1} \setfont\smallertt\ttshape{8}{1000}{OT1TT} \setfont\smallerbf\bfshape{10}{800}{OT1} \setfont\smallerit\itshape{8}{1000}{OT1IT} \setfont\smallersl\slshape{8}{1000}{OT1} \setfont\smallersf\sfshape{8}{1000}{OT1} \setfont\smallersc\scshape{10}{800}{OT1} \setfont\smallerttsl\ttslshape{10}{800}{OT1TT} \font\smalleri=cmmi8 \font\smallersy=cmsy8 \def\smallerecsize{0800} % Fonts for title page (20.4pt): \def\titlenominalsize{20pt} \setfont\titlerm\rmbshape{12}{\magstep3}{OT1} \setfont\titleit\itbshape{10}{\magstep4}{OT1IT} \setfont\titlesl\slbshape{10}{\magstep4}{OT1} \setfont\titlett\ttbshape{12}{\magstep3}{OT1TT} \setfont\titlettsl\ttslshape{10}{\magstep4}{OT1TT} \setfont\titlesf\sfbshape{17}{\magstep1}{OT1} \let\titlebf=\titlerm \setfont\titlesc\scbshape{10}{\magstep4}{OT1} \font\titlei=cmmi12 scaled \magstep3 \font\titlesy=cmsy10 scaled \magstep4 \def\titleecsize{2074} % Chapter fonts (14.4pt). \def\chapnominalsize{14pt} \setfont\chaprm\rmbshape{12}{\magstep1}{OT1} \setfont\chapit\itbshape{10}{\magstep2}{OT1IT} \setfont\chapsl\slbshape{10}{\magstep2}{OT1} \setfont\chaptt\ttbshape{12}{\magstep1}{OT1TT} \setfont\chapttsl\ttslshape{10}{\magstep2}{OT1TT} \setfont\chapsf\sfbshape{12}{\magstep1}{OT1} \let\chapbf\chaprm \setfont\chapsc\scbshape{10}{\magstep2}{OT1} \font\chapi=cmmi12 scaled \magstep1 \font\chapsy=cmsy10 scaled \magstep2 \def\chapecsize{1440} % Section fonts (12pt). \def\secnominalsize{12pt} \setfont\secrm\rmbshape{12}{1000}{OT1} \setfont\secit\itbshape{10}{\magstep1}{OT1IT} \setfont\secsl\slbshape{10}{\magstep1}{OT1} \setfont\sectt\ttbshape{12}{1000}{OT1TT} \setfont\secttsl\ttslshape{10}{\magstep1}{OT1TT} \setfont\secsf\sfbshape{12}{1000}{OT1} \let\secbf\secrm \setfont\secsc\scbshape{10}{\magstep1}{OT1} \font\seci=cmmi12 \font\secsy=cmsy10 scaled \magstep1 \def\sececsize{1200} % Subsection fonts (10pt). \def\ssecnominalsize{10pt} \setfont\ssecrm\rmbshape{10}{1000}{OT1} \setfont\ssecit\itbshape{10}{1000}{OT1IT} \setfont\ssecsl\slbshape{10}{1000}{OT1} \setfont\ssectt\ttbshape{10}{1000}{OT1TT} \setfont\ssecttsl\ttslshape{10}{1000}{OT1TT} \setfont\ssecsf\sfbshape{10}{1000}{OT1} \let\ssecbf\ssecrm \setfont\ssecsc\scbshape{10}{1000}{OT1} \font\sseci=cmmi10 \font\ssecsy=cmsy10 \def\ssececsize{1000} % Reduced fonts for @acro in text (9pt). \def\reducednominalsize{9pt} \setfont\reducedrm\rmshape{9}{1000}{OT1} \setfont\reducedtt\ttshape{9}{1000}{OT1TT} \setfont\reducedbf\bfshape{10}{900}{OT1} \setfont\reducedit\itshape{9}{1000}{OT1IT} \setfont\reducedsl\slshape{9}{1000}{OT1} \setfont\reducedsf\sfshape{9}{1000}{OT1} \setfont\reducedsc\scshape{10}{900}{OT1} \setfont\reducedttsl\ttslshape{10}{900}{OT1TT} \font\reducedi=cmmi9 \font\reducedsy=cmsy9 \def\reducedecsize{0900} \divide\parskip by 2 % reduce space between paragraphs \textleading = 12pt % line spacing for 10pt CM \textfonts % reset the current fonts \rm } % end of 10pt text font size definitions, \definetextfontsizex % We provide the user-level command % @fonttextsize 10 % (or 11) to redefine the text font size. pt is assumed. % \def\xiword{11} \def\xword{10} \def\xwordpt{10pt} % \parseargdef\fonttextsize{% \def\textsizearg{#1}% %\wlog{doing @fonttextsize \textsizearg}% % % Set \globaldefs so that documents can use this inside @tex, since % makeinfo 4.8 does not support it, but we need it nonetheless. % \begingroup \globaldefs=1 \ifx\textsizearg\xword \definetextfontsizex \else \ifx\textsizearg\xiword \definetextfontsizexi \else \errhelp=\EMsimple \errmessage{@fonttextsize only supports `10' or `11', not `\textsizearg'} \fi\fi \endgroup } % In order for the font changes to affect most math symbols and letters, % we have to define the \textfont of the standard families. Since % texinfo doesn't allow for producing subscripts and superscripts except % in the main text, we don't bother to reset \scriptfont and % \scriptscriptfont (which would also require loading a lot more fonts). % \def\resetmathfonts{% \textfont0=\tenrm \textfont1=\teni \textfont2=\tensy \textfont\itfam=\tenit \textfont\slfam=\tensl \textfont\bffam=\tenbf \textfont\ttfam=\tentt \textfont\sffam=\tensf } % The font-changing commands redefine the meanings of \tenSTYLE, instead % of just \STYLE. We do this because \STYLE needs to also set the % current \fam for math mode. Our \STYLE (e.g., \rm) commands hardwire % \tenSTYLE to set the current font. % % Each font-changing command also sets the names \lsize (one size lower) % and \lllsize (three sizes lower). These relative commands are used in % the LaTeX logo and acronyms. % % This all needs generalizing, badly. % \def\textfonts{% \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy \let\tenttsl=\textttsl \def\curfontsize{text}% \def\lsize{reduced}\def\lllsize{smaller}% \resetmathfonts \setleading{\textleading}} \def\titlefonts{% \let\tenrm=\titlerm \let\tenit=\titleit \let\tensl=\titlesl \let\tenbf=\titlebf \let\tentt=\titlett \let\smallcaps=\titlesc \let\tensf=\titlesf \let\teni=\titlei \let\tensy=\titlesy \let\tenttsl=\titlettsl \def\curfontsize{title}% \def\lsize{chap}\def\lllsize{subsec}% \resetmathfonts \setleading{27pt}} \def\titlefont#1{{\titlefonts\rmisbold #1}} \def\chapfonts{% \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy \let\tenttsl=\chapttsl \def\curfontsize{chap}% \def\lsize{sec}\def\lllsize{text}% \resetmathfonts \setleading{19pt}} \def\secfonts{% \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy \let\tenttsl=\secttsl \def\curfontsize{sec}% \def\lsize{subsec}\def\lllsize{reduced}% \resetmathfonts \setleading{16pt}} \def\subsecfonts{% \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy \let\tenttsl=\ssecttsl \def\curfontsize{ssec}% \def\lsize{text}\def\lllsize{small}% \resetmathfonts \setleading{15pt}} \let\subsubsecfonts = \subsecfonts \def\reducedfonts{% \let\tenrm=\reducedrm \let\tenit=\reducedit \let\tensl=\reducedsl \let\tenbf=\reducedbf \let\tentt=\reducedtt \let\reducedcaps=\reducedsc \let\tensf=\reducedsf \let\teni=\reducedi \let\tensy=\reducedsy \let\tenttsl=\reducedttsl \def\curfontsize{reduced}% \def\lsize{small}\def\lllsize{smaller}% \resetmathfonts \setleading{10.5pt}} \def\smallfonts{% \let\tenrm=\smallrm \let\tenit=\smallit \let\tensl=\smallsl \let\tenbf=\smallbf \let\tentt=\smalltt \let\smallcaps=\smallsc \let\tensf=\smallsf \let\teni=\smalli \let\tensy=\smallsy \let\tenttsl=\smallttsl \def\curfontsize{small}% \def\lsize{smaller}\def\lllsize{smaller}% \resetmathfonts \setleading{10.5pt}} \def\smallerfonts{% \let\tenrm=\smallerrm \let\tenit=\smallerit \let\tensl=\smallersl \let\tenbf=\smallerbf \let\tentt=\smallertt \let\smallcaps=\smallersc \let\tensf=\smallersf \let\teni=\smalleri \let\tensy=\smallersy \let\tenttsl=\smallerttsl \def\curfontsize{smaller}% \def\lsize{smaller}\def\lllsize{smaller}% \resetmathfonts \setleading{9.5pt}} % Fonts for short table of contents. \setfont\shortcontrm\rmshape{12}{1000}{OT1} \setfont\shortcontbf\bfshape{10}{\magstep1}{OT1} % no cmb12 \setfont\shortcontsl\slshape{12}{1000}{OT1} \setfont\shortconttt\ttshape{12}{1000}{OT1TT} % Define these just so they can be easily changed for other fonts. \def\angleleft{$\langle$} \def\angleright{$\rangle$} % Set the fonts to use with the @small... environments. \let\smallexamplefonts = \smallfonts % About \smallexamplefonts. If we use \smallfonts (9pt), @smallexample % can fit this many characters: % 8.5x11=86 smallbook=72 a4=90 a5=69 % If we use \scriptfonts (8pt), then we can fit this many characters: % 8.5x11=90+ smallbook=80 a4=90+ a5=77 % For me, subjectively, the few extra characters that fit aren't worth % the additional smallness of 8pt. So I'm making the default 9pt. % % By the way, for comparison, here's what fits with @example (10pt): % 8.5x11=71 smallbook=60 a4=75 a5=58 % --karl, 24jan03. % Set up the default fonts, so we can use them for creating boxes. % \definetextfontsizexi \message{markup,} % Check if we are currently using a typewriter font. Since all the % Computer Modern typewriter fonts have zero interword stretch (and % shrink), and it is reasonable to expect all typewriter fonts to have % this property, we can check that font parameter. % \def\ifmonospace{\ifdim\fontdimen3\font=0pt } % Markup style infrastructure. \defmarkupstylesetup\INITMACRO will % define and register \INITMACRO to be called on markup style changes. % \INITMACRO can check \currentmarkupstyle for the innermost % style and the set of \ifmarkupSTYLE switches for all styles % currently in effect. \newif\ifmarkupvar \newif\ifmarkupsamp \newif\ifmarkupkey %\newif\ifmarkupfile % @file == @samp. %\newif\ifmarkupoption % @option == @samp. \newif\ifmarkupcode \newif\ifmarkupkbd %\newif\ifmarkupenv % @env == @code. %\newif\ifmarkupcommand % @command == @code. \newif\ifmarkuptex % @tex (and part of @math, for now). \newif\ifmarkupexample \newif\ifmarkupverb \newif\ifmarkupverbatim \let\currentmarkupstyle\empty \def\setupmarkupstyle#1{% \csname markup#1true\endcsname \def\currentmarkupstyle{#1}% \markupstylesetup } \let\markupstylesetup\empty \def\defmarkupstylesetup#1{% \expandafter\def\expandafter\markupstylesetup \expandafter{\markupstylesetup #1}% \def#1% } % Markup style setup for left and right quotes. \defmarkupstylesetup\markupsetuplq{% \expandafter\let\expandafter \temp \csname markupsetuplq\currentmarkupstyle\endcsname \ifx\temp\relax \markupsetuplqdefault \else \temp \fi } \defmarkupstylesetup\markupsetuprq{% \expandafter\let\expandafter \temp \csname markupsetuprq\currentmarkupstyle\endcsname \ifx\temp\relax \markupsetuprqdefault \else \temp \fi } { \catcode`\'=\active \catcode`\`=\active \gdef\markupsetuplqdefault{\let`\lq} \gdef\markupsetuprqdefault{\let'\rq} \gdef\markupsetcodequoteleft{\let`\codequoteleft} \gdef\markupsetcodequoteright{\let'\codequoteright} } \let\markupsetuplqcode \markupsetcodequoteleft \let\markupsetuprqcode \markupsetcodequoteright % \let\markupsetuplqexample \markupsetcodequoteleft \let\markupsetuprqexample \markupsetcodequoteright % \let\markupsetuplqkbd \markupsetcodequoteleft \let\markupsetuprqkbd \markupsetcodequoteright % \let\markupsetuplqsamp \markupsetcodequoteleft \let\markupsetuprqsamp \markupsetcodequoteright % \let\markupsetuplqverb \markupsetcodequoteleft \let\markupsetuprqverb \markupsetcodequoteright % \let\markupsetuplqverbatim \markupsetcodequoteleft \let\markupsetuprqverbatim \markupsetcodequoteright % Allow an option to not use regular directed right quote/apostrophe % (char 0x27), but instead the undirected quote from cmtt (char 0x0d). % The undirected quote is ugly, so don't make it the default, but it % works for pasting with more pdf viewers (at least evince), the % lilypond developers report. xpdf does work with the regular 0x27. % \def\codequoteright{% \expandafter\ifx\csname SETtxicodequoteundirected\endcsname\relax \expandafter\ifx\csname SETcodequoteundirected\endcsname\relax '% \else \char'15 \fi \else \char'15 \fi } % % and a similar option for the left quote char vs. a grave accent. % Modern fonts display ASCII 0x60 as a grave accent, so some people like % the code environments to do likewise. % \def\codequoteleft{% \expandafter\ifx\csname SETtxicodequotebacktick\endcsname\relax \expandafter\ifx\csname SETcodequotebacktick\endcsname\relax % [Knuth] pp. 380,381,391 % \relax disables Spanish ligatures ?` and !` of \tt font. \relax`% \else \char'22 \fi \else \char'22 \fi } % Commands to set the quote options. % \parseargdef\codequoteundirected{% \def\temp{#1}% \ifx\temp\onword \expandafter\let\csname SETtxicodequoteundirected\endcsname = t% \else\ifx\temp\offword \expandafter\let\csname SETtxicodequoteundirected\endcsname = \relax \else \errhelp = \EMsimple \errmessage{Unknown @codequoteundirected value `\temp', must be on|off}% \fi\fi } % \parseargdef\codequotebacktick{% \def\temp{#1}% \ifx\temp\onword \expandafter\let\csname SETtxicodequotebacktick\endcsname = t% \else\ifx\temp\offword \expandafter\let\csname SETtxicodequotebacktick\endcsname = \relax \else \errhelp = \EMsimple \errmessage{Unknown @codequotebacktick value `\temp', must be on|off}% \fi\fi } % [Knuth] pp. 380,381,391, disable Spanish ligatures ?` and !` of \tt font. \def\noligaturesquoteleft{\relax\lq} % Count depth in font-changes, for error checks \newcount\fontdepth \fontdepth=0 % Font commands. % #1 is the font command (\sl or \it), #2 is the text to slant. % If we are in a monospaced environment, however, 1) always use \ttsl, % and 2) do not add an italic correction. \def\dosmartslant#1#2{% \ifusingtt {{\ttsl #2}\let\next=\relax}% {\def\next{{#1#2}\futurelet\next\smartitaliccorrection}}% \next } \def\smartslanted{\dosmartslant\sl} \def\smartitalic{\dosmartslant\it} % Output an italic correction unless \next (presumed to be the following % character) is such as not to need one. \def\smartitaliccorrection{% \ifx\next,% \else\ifx\next-% \else\ifx\next.% \else\ptexslash \fi\fi\fi \aftersmartic } % Unconditional use \ttsl, and no ic. @var is set to this for defuns. \def\ttslanted#1{{\ttsl #1}} % @cite is like \smartslanted except unconditionally use \sl. We never want % ttsl for book titles, do we? \def\cite#1{{\sl #1}\futurelet\next\smartitaliccorrection} \def\aftersmartic{} \def\var#1{% \let\saveaftersmartic = \aftersmartic \def\aftersmartic{\null\let\aftersmartic=\saveaftersmartic}% \smartslanted{#1}% } \let\i=\smartitalic \let\slanted=\smartslanted \let\dfn=\smartslanted \let\emph=\smartitalic % Explicit font changes: @r, @sc, undocumented @ii. \def\r#1{{\rm #1}} % roman font \def\sc#1{{\smallcaps#1}} % smallcaps font \def\ii#1{{\it #1}} % italic font % @b, explicit bold. Also @strong. \def\b#1{{\bf #1}} \let\strong=\b % @sansserif, explicit sans. \def\sansserif#1{{\sf #1}} % We can't just use \exhyphenpenalty, because that only has effect at % the end of a paragraph. Restore normal hyphenation at the end of the % group within which \nohyphenation is presumably called. % \def\nohyphenation{\hyphenchar\font = -1 \aftergroup\restorehyphenation} \def\restorehyphenation{\hyphenchar\font = `- } % Set sfcode to normal for the chars that usually have another value. % Can't use plain's \frenchspacing because it uses the `\x notation, and % sometimes \x has an active definition that messes things up. % \catcode`@=11 \def\plainfrenchspacing{% \sfcode\dotChar =\@m \sfcode\questChar=\@m \sfcode\exclamChar=\@m \sfcode\colonChar=\@m \sfcode\semiChar =\@m \sfcode\commaChar =\@m \def\endofsentencespacefactor{1000}% for @. and friends } \def\plainnonfrenchspacing{% \sfcode`\.3000\sfcode`\?3000\sfcode`\!3000 \sfcode`\:2000\sfcode`\;1500\sfcode`\,1250 \def\endofsentencespacefactor{3000}% for @. and friends } \catcode`@=\other \def\endofsentencespacefactor{3000}% default % @t, explicit typewriter. \def\t#1{% {\tt \rawbackslash \plainfrenchspacing #1}% \null } % @samp. \def\samp#1{{\setupmarkupstyle{samp}\lq\tclose{#1}\rq\null}} % @indicateurl is \samp, that is, with quotes. \let\indicateurl=\samp % @code (and similar) prints in typewriter, but with spaces the same % size as normal in the surrounding text, without hyphenation, etc. % This is a subroutine for that. \def\tclose#1{% {% % Change normal interword space to be same as for the current font. \spaceskip = \fontdimen2\font % % Switch to typewriter. \tt % % But `\ ' produces the large typewriter interword space. \def\ {{\spaceskip = 0pt{} }}% % % Turn off hyphenation. \nohyphenation % \rawbackslash \plainfrenchspacing #1% }% \null % reset spacefactor to 1000 } % We *must* turn on hyphenation at `-' and `_' in @code. % Otherwise, it is too hard to avoid overfull hboxes % in the Emacs manual, the Library manual, etc. % % Unfortunately, TeX uses one parameter (\hyphenchar) to control % both hyphenation at - and hyphenation within words. % We must therefore turn them both off (\tclose does that) % and arrange explicitly to hyphenate at a dash. % -- rms. { \catcode`\-=\active \catcode`\_=\active \catcode`\'=\active \catcode`\`=\active \global\let'=\rq \global\let`=\lq % default definitions % \global\def\code{\begingroup \setupmarkupstyle{code}% % The following should really be moved into \setupmarkupstyle handlers. \catcode\dashChar=\active \catcode\underChar=\active \ifallowcodebreaks \let-\codedash \let_\codeunder \else \let-\realdash \let_\realunder \fi \codex } } \def\codex #1{\tclose{#1}\endgroup} \def\realdash{-} \def\codedash{-\discretionary{}{}{}} \def\codeunder{% % this is all so @math{@code{var_name}+1} can work. In math mode, _ % is "active" (mathcode"8000) and \normalunderscore (or \char95, etc.) % will therefore expand the active definition of _, which is us % (inside @code that is), therefore an endless loop. \ifusingtt{\ifmmode \mathchar"075F % class 0=ordinary, family 7=ttfam, pos 0x5F=_. \else\normalunderscore \fi \discretionary{}{}{}}% {\_}% } % An additional complication: the above will allow breaks after, e.g., % each of the four underscores in __typeof__. This is undesirable in % some manuals, especially if they don't have long identifiers in % general. @allowcodebreaks provides a way to control this. % \newif\ifallowcodebreaks \allowcodebreakstrue \def\keywordtrue{true} \def\keywordfalse{false} \parseargdef\allowcodebreaks{% \def\txiarg{#1}% \ifx\txiarg\keywordtrue \allowcodebreakstrue \else\ifx\txiarg\keywordfalse \allowcodebreaksfalse \else \errhelp = \EMsimple \errmessage{Unknown @allowcodebreaks option `\txiarg', must be true|false}% \fi\fi } % For @command, @env, @file, @option quotes seem unnecessary, % so use \code rather than \samp. \let\command=\code \let\env=\code \let\file=\code \let\option=\code % @uref (abbreviation for `urlref') takes an optional (comma-separated) % second argument specifying the text to display and an optional third % arg as text to display instead of (rather than in addition to) the url % itself. First (mandatory) arg is the url. % (This \urefnobreak definition isn't used now, leaving it for a while % for comparison.) \def\urefnobreak#1{\dourefnobreak #1,,,\finish} \def\dourefnobreak#1,#2,#3,#4\finish{\begingroup \unsepspaces \pdfurl{#1}% \setbox0 = \hbox{\ignorespaces #3}% \ifdim\wd0 > 0pt \unhbox0 % third arg given, show only that \else \setbox0 = \hbox{\ignorespaces #2}% \ifdim\wd0 > 0pt \ifpdf \unhbox0 % PDF: 2nd arg given, show only it \else \unhbox0\ (\code{#1})% DVI: 2nd arg given, show both it and url \fi \else \code{#1}% only url given, so show it \fi \fi \endlink \endgroup} % This \urefbreak definition is the active one. \def\urefbreak{\begingroup \urefcatcodes \dourefbreak} \let\uref=\urefbreak \def\dourefbreak#1{\urefbreakfinish #1,,,\finish} \def\urefbreakfinish#1,#2,#3,#4\finish{% doesn't work in @example \unsepspaces \pdfurl{#1}% \setbox0 = \hbox{\ignorespaces #3}% \ifdim\wd0 > 0pt \unhbox0 % third arg given, show only that \else \setbox0 = \hbox{\ignorespaces #2}% \ifdim\wd0 > 0pt \ifpdf \unhbox0 % PDF: 2nd arg given, show only it \else \unhbox0\ (\urefcode{#1})% DVI: 2nd arg given, show both it and url \fi \else \urefcode{#1}% only url given, so show it \fi \fi \endlink \endgroup} % Allow line breaks around only a few characters (only). \def\urefcatcodes{% \catcode\ampChar=\active \catcode\dotChar=\active \catcode\hashChar=\active \catcode\questChar=\active \catcode\slashChar=\active } { \urefcatcodes % \global\def\urefcode{\begingroup \setupmarkupstyle{code}% \urefcatcodes \let&\urefcodeamp \let.\urefcodedot \let#\urefcodehash \let?\urefcodequest \let/\urefcodeslash \codex } % % By default, they are just regular characters. \global\def&{\normalamp} \global\def.{\normaldot} \global\def#{\normalhash} \global\def?{\normalquest} \global\def/{\normalslash} } % we put a little stretch before and after the breakable chars, to help % line breaking of long url's. The unequal skips make look better in % cmtt at least, especially for dots. \def\urefprestretch{\urefprebreak \hskip0pt plus.13em } \def\urefpoststretch{\urefpostbreak \hskip0pt plus.1em } % \def\urefcodeamp{\urefprestretch \&\urefpoststretch} \def\urefcodedot{\urefprestretch .\urefpoststretch} \def\urefcodehash{\urefprestretch \#\urefpoststretch} \def\urefcodequest{\urefprestretch ?\urefpoststretch} \def\urefcodeslash{\futurelet\next\urefcodeslashfinish} { \catcode`\/=\active \global\def\urefcodeslashfinish{% \urefprestretch \slashChar % Allow line break only after the final / in a sequence of % slashes, to avoid line break between the slashes in http://. \ifx\next/\else \urefpoststretch \fi } } % One more complication: by default we'll break after the special % characters, but some people like to break before the special chars, so % allow that. Also allow no breaking at all, for manual control. % \parseargdef\urefbreakstyle{% \def\txiarg{#1}% \ifx\txiarg\wordnone \def\urefprebreak{\nobreak}\def\urefpostbreak{\nobreak} \else\ifx\txiarg\wordbefore \def\urefprebreak{\allowbreak}\def\urefpostbreak{\nobreak} \else\ifx\txiarg\wordafter \def\urefprebreak{\nobreak}\def\urefpostbreak{\allowbreak} \else \errhelp = \EMsimple \errmessage{Unknown @urefbreakstyle setting `\txiarg'}% \fi\fi\fi } \def\wordafter{after} \def\wordbefore{before} \def\wordnone{none} \urefbreakstyle after % @url synonym for @uref, since that's how everyone uses it. % \let\url=\uref % rms does not like angle brackets --karl, 17may97. % So now @email is just like @uref, unless we are pdf. % %\def\email#1{\angleleft{\tt #1}\angleright} \ifpdf \def\email#1{\doemail#1,,\finish} \def\doemail#1,#2,#3\finish{\begingroup \unsepspaces \pdfurl{mailto:#1}% \setbox0 = \hbox{\ignorespaces #2}% \ifdim\wd0>0pt\unhbox0\else\code{#1}\fi \endlink \endgroup} \else \let\email=\uref \fi % @kbdinputstyle -- arg is `distinct' (@kbd uses slanted tty font always), % `example' (@kbd uses ttsl only inside of @example and friends), % or `code' (@kbd uses normal tty font always). \parseargdef\kbdinputstyle{% \def\txiarg{#1}% \ifx\txiarg\worddistinct \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl}% \else\ifx\txiarg\wordexample \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\tt}% \else\ifx\txiarg\wordcode \gdef\kbdexamplefont{\tt}\gdef\kbdfont{\tt}% \else \errhelp = \EMsimple \errmessage{Unknown @kbdinputstyle setting `\txiarg'}% \fi\fi\fi } \def\worddistinct{distinct} \def\wordexample{example} \def\wordcode{code} % Default is `distinct'. \kbdinputstyle distinct % @kbd is like @code, except that if the argument is just one @key command, % then @kbd has no effect. \def\kbd#1{{\def\look{#1}\expandafter\kbdsub\look??\par}} \def\xkey{\key} \def\kbdsub#1#2#3\par{% \def\one{#1}\def\three{#3}\def\threex{??}% \ifx\one\xkey\ifx\threex\three \key{#2}% \else{\tclose{\kbdfont\setupmarkupstyle{kbd}\look}}\fi \else{\tclose{\kbdfont\setupmarkupstyle{kbd}\look}}\fi } % definition of @key that produces a lozenge. Doesn't adjust to text size. %\setfont\keyrm\rmshape{8}{1000}{OT1} %\font\keysy=cmsy9 %\def\key#1{{\keyrm\textfont2=\keysy \leavevmode\hbox{% % \raise0.4pt\hbox{\angleleft}\kern-.08em\vtop{% % \vbox{\hrule\kern-0.4pt % \hbox{\raise0.4pt\hbox{\vphantom{\angleleft}}#1}}% % \kern-0.4pt\hrule}% % \kern-.06em\raise0.4pt\hbox{\angleright}}}} % definition of @key with no lozenge. If the current font is already % monospace, don't change it; that way, we respect @kbdinputstyle. But % if it isn't monospace, then use \tt. % \def\key#1{{\setupmarkupstyle{key}% \nohyphenation \ifmonospace\else\tt\fi #1}\null} % @clicksequence{File @click{} Open ...} \def\clicksequence#1{\begingroup #1\endgroup} % @clickstyle @arrow (by default) \parseargdef\clickstyle{\def\click{#1}} \def\click{\arrow} % Typeset a dimension, e.g., `in' or `pt'. The only reason for the % argument is to make the input look right: @dmn{pt} instead of @dmn{}pt. % \def\dmn#1{\thinspace #1} % @l was never documented to mean ``switch to the Lisp font'', % and it is not used as such in any manual I can find. We need it for % Polish suppressed-l. --karl, 22sep96. %\def\l#1{{\li #1}\null} % @acronym for "FBI", "NATO", and the like. % We print this one point size smaller, since it's intended for % all-uppercase. % \def\acronym#1{\doacronym #1,,\finish} \def\doacronym#1,#2,#3\finish{% {\selectfonts\lsize #1}% \def\temp{#2}% \ifx\temp\empty \else \space ({\unsepspaces \ignorespaces \temp \unskip})% \fi \null % reset \spacefactor=1000 } % @abbr for "Comput. J." and the like. % No font change, but don't do end-of-sentence spacing. % \def\abbr#1{\doabbr #1,,\finish} \def\doabbr#1,#2,#3\finish{% {\plainfrenchspacing #1}% \def\temp{#2}% \ifx\temp\empty \else \space ({\unsepspaces \ignorespaces \temp \unskip})% \fi \null % reset \spacefactor=1000 } % @asis just yields its argument. Used with @table, for example. % \def\asis#1{#1} % @math outputs its argument in math mode. % % One complication: _ usually means subscripts, but it could also mean % an actual _ character, as in @math{@var{some_variable} + 1}. So make % _ active, and distinguish by seeing if the current family is \slfam, % which is what @var uses. { \catcode`\_ = \active \gdef\mathunderscore{% \catcode`\_=\active \def_{\ifnum\fam=\slfam \_\else\sb\fi}% } } % Another complication: we want \\ (and @\) to output a math (or tt) \. % FYI, plain.tex uses \\ as a temporary control sequence (for no % particular reason), but this is not advertised and we don't care. % % The \mathchar is class=0=ordinary, family=7=ttfam, position=5C=\. \def\mathbackslash{\ifnum\fam=\ttfam \mathchar"075C \else\backslash \fi} % \def\math{% \tex \mathunderscore \let\\ = \mathbackslash \mathactive % make the texinfo accent commands work in math mode \let\"=\ddot \let\'=\acute \let\==\bar \let\^=\hat \let\`=\grave \let\u=\breve \let\v=\check \let\~=\tilde \let\dotaccent=\dot $\finishmath } \def\finishmath#1{#1$\endgroup} % Close the group opened by \tex. % Some active characters (such as <) are spaced differently in math. % We have to reset their definitions in case the @math was an argument % to a command which sets the catcodes (such as @item or @section). % { \catcode`^ = \active \catcode`< = \active \catcode`> = \active \catcode`+ = \active \catcode`' = \active \gdef\mathactive{% \let^ = \ptexhat \let< = \ptexless \let> = \ptexgtr \let+ = \ptexplus \let' = \ptexquoteright } } % ctrl is no longer a Texinfo command, but leave this definition for fun. \def\ctrl #1{{\tt \rawbackslash \hat}#1} % @inlinefmt{FMTNAME,PROCESSED-TEXT} and @inlineraw{FMTNAME,RAW-TEXT}. % Ignore unless FMTNAME == tex; then it is like @iftex and @tex, % except specified as a normal braced arg, so no newlines to worry about. % \def\outfmtnametex{tex} % \long\def\inlinefmt#1{\doinlinefmt #1,\finish} \long\def\doinlinefmt#1,#2,\finish{% \def\inlinefmtname{#1}% \ifx\inlinefmtname\outfmtnametex \ignorespaces #2\fi } % For raw, must switch into @tex before parsing the argument, to avoid % setting catcodes prematurely. Doing it this way means that, for % example, @inlineraw{html, foo{bar} gets a parse error instead of being % ignored. But this isn't important because if people want a literal % *right* brace they would have to use a command anyway, so they may as % well use a command to get a left brace too. We could re-use the % delimiter character idea from \verb, but it seems like overkill. % \long\def\inlineraw{\tex \doinlineraw} \long\def\doinlineraw#1{\doinlinerawtwo #1,\finish} \def\doinlinerawtwo#1,#2,\finish{% \def\inlinerawname{#1}% \ifx\inlinerawname\outfmtnametex \ignorespaces #2\fi \endgroup % close group opened by \tex. } \message{glyphs,} % and logos. % @@ prints an @, as does @atchar{}. \def\@{\char64 } \let\atchar=\@ % @{ @} @lbracechar{} @rbracechar{} all generate brace characters. % Unless we're in typewriter, use \ecfont because the CM text fonts do % not have braces, and we don't want to switch into math. \def\mylbrace{{\ifmonospace\else\ecfont\fi \char123}} \def\myrbrace{{\ifmonospace\else\ecfont\fi \char125}} \let\{=\mylbrace \let\lbracechar=\{ \let\}=\myrbrace \let\rbracechar=\} \begingroup % Definitions to produce \{ and \} commands for indices, % and @{ and @} for the aux/toc files. \catcode`\{ = \other \catcode`\} = \other \catcode`\[ = 1 \catcode`\] = 2 \catcode`\! = 0 \catcode`\\ = \other !gdef!lbracecmd[\{]% !gdef!rbracecmd[\}]% !gdef!lbraceatcmd[@{]% !gdef!rbraceatcmd[@}]% !endgroup % @comma{} to avoid , parsing problems. \let\comma = , % Accents: @, @dotaccent @ringaccent @ubaraccent @udotaccent % Others are defined by plain TeX: @` @' @" @^ @~ @= @u @v @H. \let\, = \ptexc \let\dotaccent = \ptexdot \def\ringaccent#1{{\accent23 #1}} \let\tieaccent = \ptext \let\ubaraccent = \ptexb \let\udotaccent = \d % Other special characters: @questiondown @exclamdown @ordf @ordm % Plain TeX defines: @AA @AE @O @OE @L (plus lowercase versions) @ss. \def\questiondown{?`} \def\exclamdown{!`} \def\ordf{\leavevmode\raise1ex\hbox{\selectfonts\lllsize \underbar{a}}} \def\ordm{\leavevmode\raise1ex\hbox{\selectfonts\lllsize \underbar{o}}} % Dotless i and dotless j, used for accents. \def\imacro{i} \def\jmacro{j} \def\dotless#1{% \def\temp{#1}% \ifx\temp\imacro \ifmmode\imath \else\ptexi \fi \else\ifx\temp\jmacro \ifmmode\jmath \else\j \fi \else \errmessage{@dotless can be used only with i or j}% \fi\fi } % The \TeX{} logo, as in plain, but resetting the spacing so that a % period following counts as ending a sentence. (Idea found in latex.) % \edef\TeX{\TeX \spacefactor=1000 } % @LaTeX{} logo. Not quite the same results as the definition in % latex.ltx, since we use a different font for the raised A; it's most % convenient for us to use an explicitly smaller font, rather than using % the \scriptstyle font (since we don't reset \scriptstyle and % \scriptscriptstyle). % \def\LaTeX{% L\kern-.36em {\setbox0=\hbox{T}% \vbox to \ht0{\hbox{% \ifx\textnominalsize\xwordpt % for 10pt running text, \lllsize (8pt) is too small for the A in LaTeX. % Revert to plain's \scriptsize, which is 7pt. \count255=\the\fam $\fam\count255 \scriptstyle A$% \else % For 11pt, we can use our lllsize. \selectfonts\lllsize A% \fi }% \vss }}% \kern-.15em \TeX } % Some math mode symbols. \def\bullet{$\ptexbullet$} \def\geq{\ifmmode \ge\else $\ge$\fi} \def\leq{\ifmmode \le\else $\le$\fi} \def\minus{\ifmmode -\else $-$\fi} % @dots{} outputs an ellipsis using the current font. % We do .5em per period so that it has the same spacing in the cm % typewriter fonts as three actual period characters; on the other hand, % in other typewriter fonts three periods are wider than 1.5em. So do % whichever is larger. % \def\dots{% \leavevmode \setbox0=\hbox{...}% get width of three periods \ifdim\wd0 > 1.5em \dimen0 = \wd0 \else \dimen0 = 1.5em \fi \hbox to \dimen0{% \hskip 0pt plus.25fil .\hskip 0pt plus1fil .\hskip 0pt plus1fil .\hskip 0pt plus.5fil }% } % @enddots{} is an end-of-sentence ellipsis. % \def\enddots{% \dots \spacefactor=\endofsentencespacefactor } % @point{}, @result{}, @expansion{}, @print{}, @equiv{}. % % Since these characters are used in examples, they should be an even number of % \tt widths. Each \tt character is 1en, so two makes it 1em. % \def\point{$\star$} \def\arrow{\leavevmode\raise.05ex\hbox to 1em{\hfil$\rightarrow$\hfil}} \def\result{\leavevmode\raise.05ex\hbox to 1em{\hfil$\Rightarrow$\hfil}} \def\expansion{\leavevmode\hbox to 1em{\hfil$\mapsto$\hfil}} \def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}} \def\equiv{\leavevmode\hbox to 1em{\hfil$\ptexequiv$\hfil}} % The @error{} command. % Adapted from the TeXbook's \boxit. % \newbox\errorbox % {\tentt \global\dimen0 = 3em}% Width of the box. \dimen2 = .55pt % Thickness of rules % The text. (`r' is open on the right, `e' somewhat less so on the left.) \setbox0 = \hbox{\kern-.75pt \reducedsf \putworderror\kern-1.5pt} % \setbox\errorbox=\hbox to \dimen0{\hfil \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right. \advance\hsize by -2\dimen2 % Rules. \vbox{% \hrule height\dimen2 \hbox{\vrule width\dimen2 \kern3pt % Space to left of text. \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below. \kern3pt\vrule width\dimen2}% Space to right. \hrule height\dimen2} \hfil} % \def\error{\leavevmode\lower.7ex\copy\errorbox} % @pounds{} is a sterling sign, which Knuth put in the CM italic font. % \def\pounds{{\it\$}} % @euro{} comes from a separate font, depending on the current style. % We use the free feym* fonts from the eurosym package by Henrik % Theiling, which support regular, slanted, bold and bold slanted (and % "outlined" (blackboard board, sort of) versions, which we don't need). % It is available from http://www.ctan.org/tex-archive/fonts/eurosym. % % Although only regular is the truly official Euro symbol, we ignore % that. The Euro is designed to be slightly taller than the regular % font height. % % feymr - regular % feymo - slanted % feybr - bold % feybo - bold slanted % % There is no good (free) typewriter version, to my knowledge. % A feymr10 euro is ~7.3pt wide, while a normal cmtt10 char is ~5.25pt wide. % Hmm. % % Also doesn't work in math. Do we need to do math with euro symbols? % Hope not. % % \def\euro{{\eurofont e}} \def\eurofont{% % We set the font at each command, rather than predefining it in % \textfonts and the other font-switching commands, so that % installations which never need the symbol don't have to have the % font installed. % % There is only one designed size (nominal 10pt), so we always scale % that to the current nominal size. % % By the way, simply using "at 1em" works for cmr10 and the like, but % does not work for cmbx10 and other extended/shrunken fonts. % \def\eurosize{\csname\curfontsize nominalsize\endcsname}% % \ifx\curfontstyle\bfstylename % bold: \font\thiseurofont = \ifusingit{feybo10}{feybr10} at \eurosize \else % regular: \font\thiseurofont = \ifusingit{feymo10}{feymr10} at \eurosize \fi \thiseurofont } % Glyphs from the EC fonts. We don't use \let for the aliases, because % sometimes we redefine the original macro, and the alias should reflect % the redefinition. % % Use LaTeX names for the Icelandic letters. \def\DH{{\ecfont \char"D0}} % Eth \def\dh{{\ecfont \char"F0}} % eth \def\TH{{\ecfont \char"DE}} % Thorn \def\th{{\ecfont \char"FE}} % thorn % \def\guillemetleft{{\ecfont \char"13}} \def\guillemotleft{\guillemetleft} \def\guillemetright{{\ecfont \char"14}} \def\guillemotright{\guillemetright} \def\guilsinglleft{{\ecfont \char"0E}} \def\guilsinglright{{\ecfont \char"0F}} \def\quotedblbase{{\ecfont \char"12}} \def\quotesinglbase{{\ecfont \char"0D}} % % This positioning is not perfect (see the ogonek LaTeX package), but % we have the precomposed glyphs for the most common cases. We put the % tests to use those glyphs in the single \ogonek macro so we have fewer % dummy definitions to worry about for index entries, etc. % % ogonek is also used with other letters in Lithuanian (IOU), but using % the precomposed glyphs for those is not so easy since they aren't in % the same EC font. \def\ogonek#1{{% \def\temp{#1}% \ifx\temp\macrocharA\Aogonek \else\ifx\temp\macrochara\aogonek \else\ifx\temp\macrocharE\Eogonek \else\ifx\temp\macrochare\eogonek \else \ecfont \setbox0=\hbox{#1}% \ifdim\ht0=1ex\accent"0C #1% \else\ooalign{\unhbox0\crcr\hidewidth\char"0C \hidewidth}% \fi \fi\fi\fi\fi }% } \def\Aogonek{{\ecfont \char"81}}\def\macrocharA{A} \def\aogonek{{\ecfont \char"A1}}\def\macrochara{a} \def\Eogonek{{\ecfont \char"86}}\def\macrocharE{E} \def\eogonek{{\ecfont \char"A6}}\def\macrochare{e} % % Use the ec* fonts (cm-super in outline format) for non-CM glyphs. \def\ecfont{% % We can't distinguish serif/sans and italic/slanted, but this % is used for crude hacks anyway (like adding French and German % quotes to documents typeset with CM, where we lose kerning), so % hopefully nobody will notice/care. \edef\ecsize{\csname\curfontsize ecsize\endcsname}% \edef\nominalsize{\csname\curfontsize nominalsize\endcsname}% \ifmonospace % typewriter: \font\thisecfont = ectt\ecsize \space at \nominalsize \else \ifx\curfontstyle\bfstylename % bold: \font\thisecfont = ecb\ifusingit{i}{x}\ecsize \space at \nominalsize \else % regular: \font\thisecfont = ec\ifusingit{ti}{rm}\ecsize \space at \nominalsize \fi \fi \thisecfont } % @registeredsymbol - R in a circle. The font for the R should really % be smaller yet, but lllsize is the best we can do for now. % Adapted from the plain.tex definition of \copyright. % \def\registeredsymbol{% $^{{\ooalign{\hfil\raise.07ex\hbox{\selectfonts\lllsize R}% \hfil\crcr\Orb}}% }$% } % @textdegree - the normal degrees sign. % \def\textdegree{$^\circ$} % Laurent Siebenmann reports \Orb undefined with: % Textures 1.7.7 (preloaded format=plain 93.10.14) (68K) 16 APR 2004 02:38 % so we'll define it if necessary. % \ifx\Orb\thisisundefined \def\Orb{\mathhexbox20D} \fi % Quotes. \chardef\quotedblleft="5C \chardef\quotedblright=`\" \chardef\quoteleft=`\` \chardef\quoteright=`\' \message{page headings,} \newskip\titlepagetopglue \titlepagetopglue = 1.5in \newskip\titlepagebottomglue \titlepagebottomglue = 2pc % First the title page. Must do @settitle before @titlepage. \newif\ifseenauthor \newif\iffinishedtitlepage % Do an implicit @contents or @shortcontents after @end titlepage if the % user says @setcontentsaftertitlepage or @setshortcontentsaftertitlepage. % \newif\ifsetcontentsaftertitlepage \let\setcontentsaftertitlepage = \setcontentsaftertitlepagetrue \newif\ifsetshortcontentsaftertitlepage \let\setshortcontentsaftertitlepage = \setshortcontentsaftertitlepagetrue \parseargdef\shorttitlepage{% \begingroup \hbox{}\vskip 1.5in \chaprm \centerline{#1}% \endgroup\page\hbox{}\page} \envdef\titlepage{% % Open one extra group, as we want to close it in the middle of \Etitlepage. \begingroup \parindent=0pt \textfonts % Leave some space at the very top of the page. \vglue\titlepagetopglue % No rule at page bottom unless we print one at the top with @title. \finishedtitlepagetrue % % Most title ``pages'' are actually two pages long, with space % at the top of the second. We don't want the ragged left on the second. \let\oldpage = \page \def\page{% \iffinishedtitlepage\else \finishtitlepage \fi \let\page = \oldpage \page \null }% } \def\Etitlepage{% \iffinishedtitlepage\else \finishtitlepage \fi % It is important to do the page break before ending the group, % because the headline and footline are only empty inside the group. % If we use the new definition of \page, we always get a blank page % after the title page, which we certainly don't want. \oldpage \endgroup % % Need this before the \...aftertitlepage checks so that if they are % in effect the toc pages will come out with page numbers. \HEADINGSon % % If they want short, they certainly want long too. \ifsetshortcontentsaftertitlepage \shortcontents \contents \global\let\shortcontents = \relax \global\let\contents = \relax \fi % \ifsetcontentsaftertitlepage \contents \global\let\contents = \relax \global\let\shortcontents = \relax \fi } \def\finishtitlepage{% \vskip4pt \hrule height 2pt width \hsize \vskip\titlepagebottomglue \finishedtitlepagetrue } % Settings used for typesetting titles: no hyphenation, no indentation, % don't worry much about spacing, ragged right. This should be used % inside a \vbox, and fonts need to be set appropriately first. Because % it is always used for titles, nothing else, we call \rmisbold. \par % should be specified before the end of the \vbox, since a vbox is a group. % \def\raggedtitlesettings{% \rmisbold \hyphenpenalty=10000 \parindent=0pt \tolerance=5000 \ptexraggedright } % Macros to be used within @titlepage: \let\subtitlerm=\tenrm \def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines} \parseargdef\title{% \checkenv\titlepage \vbox{\titlefonts \raggedtitlesettings #1\par}% % print a rule at the page bottom also. \finishedtitlepagefalse \vskip4pt \hrule height 4pt width \hsize \vskip4pt } \parseargdef\subtitle{% \checkenv\titlepage {\subtitlefont \rightline{#1}}% } % @author should come last, but may come many times. % It can also be used inside @quotation. % \parseargdef\author{% \def\temp{\quotation}% \ifx\thisenv\temp \def\quotationauthor{#1}% printed in \Equotation. \else \checkenv\titlepage \ifseenauthor\else \vskip 0pt plus 1filll \seenauthortrue \fi {\secfonts\rmisbold \leftline{#1}}% \fi } % Set up page headings and footings. \let\thispage=\folio \newtoks\evenheadline % headline on even pages \newtoks\oddheadline % headline on odd pages \newtoks\evenfootline % footline on even pages \newtoks\oddfootline % footline on odd pages % Now make TeX use those variables \headline={{\textfonts\rm \ifodd\pageno \the\oddheadline \else \the\evenheadline \fi}} \footline={{\textfonts\rm \ifodd\pageno \the\oddfootline \else \the\evenfootline \fi}\HEADINGShook} \let\HEADINGShook=\relax % Commands to set those variables. % For example, this is what @headings on does % @evenheading @thistitle|@thispage|@thischapter % @oddheading @thischapter|@thispage|@thistitle % @evenfooting @thisfile|| % @oddfooting ||@thisfile \def\evenheading{\parsearg\evenheadingxxx} \def\evenheadingxxx #1{\evenheadingyyy #1\|\|\|\|\finish} \def\evenheadingyyy #1\|#2\|#3\|#4\finish{% \global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} \def\oddheading{\parsearg\oddheadingxxx} \def\oddheadingxxx #1{\oddheadingyyy #1\|\|\|\|\finish} \def\oddheadingyyy #1\|#2\|#3\|#4\finish{% \global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} \parseargdef\everyheading{\oddheadingxxx{#1}\evenheadingxxx{#1}}% \def\evenfooting{\parsearg\evenfootingxxx} \def\evenfootingxxx #1{\evenfootingyyy #1\|\|\|\|\finish} \def\evenfootingyyy #1\|#2\|#3\|#4\finish{% \global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} \def\oddfooting{\parsearg\oddfootingxxx} \def\oddfootingxxx #1{\oddfootingyyy #1\|\|\|\|\finish} \def\oddfootingyyy #1\|#2\|#3\|#4\finish{% \global\oddfootline = {\rlap{\centerline{#2}}\line{#1\hfil#3}}% % % Leave some space for the footline. Hopefully ok to assume % @evenfooting will not be used by itself. \global\advance\pageheight by -12pt \global\advance\vsize by -12pt } \parseargdef\everyfooting{\oddfootingxxx{#1}\evenfootingxxx{#1}} % @evenheadingmarks top \thischapter <- chapter at the top of a page % @evenheadingmarks bottom \thischapter <- chapter at the bottom of a page % % The same set of arguments for: % % @oddheadingmarks % @evenfootingmarks % @oddfootingmarks % @everyheadingmarks % @everyfootingmarks \def\evenheadingmarks{\headingmarks{even}{heading}} \def\oddheadingmarks{\headingmarks{odd}{heading}} \def\evenfootingmarks{\headingmarks{even}{footing}} \def\oddfootingmarks{\headingmarks{odd}{footing}} \def\everyheadingmarks#1 {\headingmarks{even}{heading}{#1} \headingmarks{odd}{heading}{#1} } \def\everyfootingmarks#1 {\headingmarks{even}{footing}{#1} \headingmarks{odd}{footing}{#1} } % #1 = even/odd, #2 = heading/footing, #3 = top/bottom. \def\headingmarks#1#2#3 {% \expandafter\let\expandafter\temp \csname get#3headingmarks\endcsname \global\expandafter\let\csname get#1#2marks\endcsname \temp } \everyheadingmarks bottom \everyfootingmarks bottom % @headings double turns headings on for double-sided printing. % @headings single turns headings on for single-sided printing. % @headings off turns them off. % @headings on same as @headings double, retained for compatibility. % @headings after turns on double-sided headings after this page. % @headings doubleafter turns on double-sided headings after this page. % @headings singleafter turns on single-sided headings after this page. % By default, they are off at the start of a document, % and turned `on' after @end titlepage. \def\headings #1 {\csname HEADINGS#1\endcsname} \def\headingsoff{% non-global headings elimination \evenheadline={\hfil}\evenfootline={\hfil}% \oddheadline={\hfil}\oddfootline={\hfil}% } \def\HEADINGSoff{{\globaldefs=1 \headingsoff}} % global setting \HEADINGSoff % it's the default % When we turn headings on, set the page number to 1. % For double-sided printing, put current file name in lower left corner, % chapter name on inside top of right hand pages, document % title on inside top of left hand pages, and page numbers on outside top % edge of all pages. \def\HEADINGSdouble{% \global\pageno=1 \global\evenfootline={\hfil} \global\oddfootline={\hfil} \global\evenheadline={\line{\folio\hfil\thistitle}} \global\oddheadline={\line{\thischapter\hfil\folio}} \global\let\contentsalignmacro = \chapoddpage } \let\contentsalignmacro = \chappager % For single-sided printing, chapter title goes across top left of page, % page number on top right. \def\HEADINGSsingle{% \global\pageno=1 \global\evenfootline={\hfil} \global\oddfootline={\hfil} \global\evenheadline={\line{\thischapter\hfil\folio}} \global\oddheadline={\line{\thischapter\hfil\folio}} \global\let\contentsalignmacro = \chappager } \def\HEADINGSon{\HEADINGSdouble} \def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex} \let\HEADINGSdoubleafter=\HEADINGSafter \def\HEADINGSdoublex{% \global\evenfootline={\hfil} \global\oddfootline={\hfil} \global\evenheadline={\line{\folio\hfil\thistitle}} \global\oddheadline={\line{\thischapter\hfil\folio}} \global\let\contentsalignmacro = \chapoddpage } \def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex} \def\HEADINGSsinglex{% \global\evenfootline={\hfil} \global\oddfootline={\hfil} \global\evenheadline={\line{\thischapter\hfil\folio}} \global\oddheadline={\line{\thischapter\hfil\folio}} \global\let\contentsalignmacro = \chappager } % Subroutines used in generating headings % This produces Day Month Year style of output. % Only define if not already defined, in case a txi-??.tex file has set % up a different format (e.g., txi-cs.tex does this). \ifx\today\thisisundefined \def\today{% \number\day\space \ifcase\month \or\putwordMJan\or\putwordMFeb\or\putwordMMar\or\putwordMApr \or\putwordMMay\or\putwordMJun\or\putwordMJul\or\putwordMAug \or\putwordMSep\or\putwordMOct\or\putwordMNov\or\putwordMDec \fi \space\number\year} \fi % @settitle line... specifies the title of the document, for headings. % It generates no output of its own. \def\thistitle{\putwordNoTitle} \def\settitle{\parsearg{\gdef\thistitle}} \message{tables,} % Tables -- @table, @ftable, @vtable, @item(x). % default indentation of table text \newdimen\tableindent \tableindent=.8in % default indentation of @itemize and @enumerate text \newdimen\itemindent \itemindent=.3in % margin between end of table item and start of table text. \newdimen\itemmargin \itemmargin=.1in % used internally for \itemindent minus \itemmargin \newdimen\itemmax % Note @table, @ftable, and @vtable define @item, @itemx, etc., with % these defs. % They also define \itemindex % to index the item name in whatever manner is desired (perhaps none). \newif\ifitemxneedsnegativevskip \def\itemxpar{\par\ifitemxneedsnegativevskip\nobreak\vskip-\parskip\nobreak\fi} \def\internalBitem{\smallbreak \parsearg\itemzzz} \def\internalBitemx{\itemxpar \parsearg\itemzzz} \def\itemzzz #1{\begingroup % \advance\hsize by -\rightskip \advance\hsize by -\tableindent \setbox0=\hbox{\itemindicate{#1}}% \itemindex{#1}% \nobreak % This prevents a break before @itemx. % % If the item text does not fit in the space we have, put it on a line % by itself, and do not allow a page break either before or after that % line. We do not start a paragraph here because then if the next % command is, e.g., @kindex, the whatsit would get put into the % horizontal list on a line by itself, resulting in extra blank space. \ifdim \wd0>\itemmax % % Make this a paragraph so we get the \parskip glue and wrapping, % but leave it ragged-right. \begingroup \advance\leftskip by-\tableindent \advance\hsize by\tableindent \advance\rightskip by0pt plus1fil\relax \leavevmode\unhbox0\par \endgroup % % We're going to be starting a paragraph, but we don't want the % \parskip glue -- logically it's part of the @item we just started. \nobreak \vskip-\parskip % % Stop a page break at the \parskip glue coming up. However, if % what follows is an environment such as @example, there will be no % \parskip glue; then the negative vskip we just inserted would % cause the example and the item to crash together. So we use this % bizarre value of 10001 as a signal to \aboveenvbreak to insert % \parskip glue after all. Section titles are handled this way also. % \penalty 10001 \endgroup \itemxneedsnegativevskipfalse \else % The item text fits into the space. Start a paragraph, so that the % following text (if any) will end up on the same line. \noindent % Do this with kerns and \unhbox so that if there is a footnote in % the item text, it can migrate to the main vertical list and % eventually be printed. \nobreak\kern-\tableindent \dimen0 = \itemmax \advance\dimen0 by \itemmargin \advance\dimen0 by -\wd0 \unhbox0 \nobreak\kern\dimen0 \endgroup \itemxneedsnegativevskiptrue \fi } \def\item{\errmessage{@item while not in a list environment}} \def\itemx{\errmessage{@itemx while not in a list environment}} % @table, @ftable, @vtable. \envdef\table{% \let\itemindex\gobble \tablecheck{table}% } \envdef\ftable{% \def\itemindex ##1{\doind {fn}{\code{##1}}}% \tablecheck{ftable}% } \envdef\vtable{% \def\itemindex ##1{\doind {vr}{\code{##1}}}% \tablecheck{vtable}% } \def\tablecheck#1{% \ifnum \the\catcode`\^^M=\active \endgroup \errmessage{This command won't work in this context; perhaps the problem is that we are \inenvironment\thisenv}% \def\next{\doignore{#1}}% \else \let\next\tablex \fi \next } \def\tablex#1{% \def\itemindicate{#1}% \parsearg\tabley } \def\tabley#1{% {% \makevalueexpandable \edef\temp{\noexpand\tablez #1\space\space\space}% \expandafter }\temp \endtablez } \def\tablez #1 #2 #3 #4\endtablez{% \aboveenvbreak \ifnum 0#1>0 \advance \leftskip by #1\mil \fi \ifnum 0#2>0 \tableindent=#2\mil \fi \ifnum 0#3>0 \advance \rightskip by #3\mil \fi \itemmax=\tableindent \advance \itemmax by -\itemmargin \advance \leftskip by \tableindent \exdentamount=\tableindent \parindent = 0pt \parskip = \smallskipamount \ifdim \parskip=0pt \parskip=2pt \fi \let\item = \internalBitem \let\itemx = \internalBitemx } \def\Etable{\endgraf\afterenvbreak} \let\Eftable\Etable \let\Evtable\Etable \let\Eitemize\Etable \let\Eenumerate\Etable % This is the counter used by @enumerate, which is really @itemize \newcount \itemno \envdef\itemize{\parsearg\doitemize} \def\doitemize#1{% \aboveenvbreak \itemmax=\itemindent \advance\itemmax by -\itemmargin \advance\leftskip by \itemindent \exdentamount=\itemindent \parindent=0pt \parskip=\smallskipamount \ifdim\parskip=0pt \parskip=2pt \fi % % Try typesetting the item mark that if the document erroneously says % something like @itemize @samp (intending @table), there's an error % right away at the @itemize. It's not the best error message in the % world, but it's better than leaving it to the @item. This means if % the user wants an empty mark, they have to say @w{} not just @w. \def\itemcontents{#1}% \setbox0 = \hbox{\itemcontents}% % % @itemize with no arg is equivalent to @itemize @bullet. \ifx\itemcontents\empty\def\itemcontents{\bullet}\fi % \let\item=\itemizeitem } % Definition of @item while inside @itemize and @enumerate. % \def\itemizeitem{% \advance\itemno by 1 % for enumerations {\let\par=\endgraf \smallbreak}% reasonable place to break {% % If the document has an @itemize directly after a section title, a % \nobreak will be last on the list, and \sectionheading will have % done a \vskip-\parskip. In that case, we don't want to zero % parskip, or the item text will crash with the heading. On the % other hand, when there is normal text preceding the item (as there % usually is), we do want to zero parskip, or there would be too much % space. In that case, we won't have a \nobreak before. At least % that's the theory. \ifnum\lastpenalty<10000 \parskip=0in \fi \noindent \hbox to 0pt{\hss \itemcontents \kern\itemmargin}% % \vadjust{\penalty 1200}}% not good to break after first line of item. \flushcr } % \splitoff TOKENS\endmark defines \first to be the first token in % TOKENS, and \rest to be the remainder. % \def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}% % Allow an optional argument of an uppercase letter, lowercase letter, % or number, to specify the first label in the enumerated list. No % argument is the same as `1'. % \envparseargdef\enumerate{\enumeratey #1 \endenumeratey} \def\enumeratey #1 #2\endenumeratey{% % If we were given no argument, pretend we were given `1'. \def\thearg{#1}% \ifx\thearg\empty \def\thearg{1}\fi % % Detect if the argument is a single token. If so, it might be a % letter. Otherwise, the only valid thing it can be is a number. % (We will always have one token, because of the test we just made. % This is a good thing, since \splitoff doesn't work given nothing at % all -- the first parameter is undelimited.) \expandafter\splitoff\thearg\endmark \ifx\rest\empty % Only one token in the argument. It could still be anything. % A ``lowercase letter'' is one whose \lccode is nonzero. % An ``uppercase letter'' is one whose \lccode is both nonzero, and % not equal to itself. % Otherwise, we assume it's a number. % % We need the \relax at the end of the \ifnum lines to stop TeX from % continuing to look for a . % \ifnum\lccode\expandafter`\thearg=0\relax \numericenumerate % a number (we hope) \else % It's a letter. \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax \lowercaseenumerate % lowercase letter \else \uppercaseenumerate % uppercase letter \fi \fi \else % Multiple tokens in the argument. We hope it's a number. \numericenumerate \fi } % An @enumerate whose labels are integers. The starting integer is % given in \thearg. % \def\numericenumerate{% \itemno = \thearg \startenumeration{\the\itemno}% } % The starting (lowercase) letter is in \thearg. \def\lowercaseenumerate{% \itemno = \expandafter`\thearg \startenumeration{% % Be sure we're not beyond the end of the alphabet. \ifnum\itemno=0 \errmessage{No more lowercase letters in @enumerate; get a bigger alphabet}% \fi \char\lccode\itemno }% } % The starting (uppercase) letter is in \thearg. \def\uppercaseenumerate{% \itemno = \expandafter`\thearg \startenumeration{% % Be sure we're not beyond the end of the alphabet. \ifnum\itemno=0 \errmessage{No more uppercase letters in @enumerate; get a bigger alphabet} \fi \char\uccode\itemno }% } % Call \doitemize, adding a period to the first argument and supplying the % common last two arguments. Also subtract one from the initial value in % \itemno, since @item increments \itemno. % \def\startenumeration#1{% \advance\itemno by -1 \doitemize{#1.}\flushcr } % @alphaenumerate and @capsenumerate are abbreviations for giving an arg % to @enumerate. % \def\alphaenumerate{\enumerate{a}} \def\capsenumerate{\enumerate{A}} \def\Ealphaenumerate{\Eenumerate} \def\Ecapsenumerate{\Eenumerate} % @multitable macros % Amy Hendrickson, 8/18/94, 3/6/96 % % @multitable ... @end multitable will make as many columns as desired. % Contents of each column will wrap at width given in preamble. Width % can be specified either with sample text given in a template line, % or in percent of \hsize, the current width of text on page. % Table can continue over pages but will only break between lines. % To make preamble: % % Either define widths of columns in terms of percent of \hsize: % @multitable @columnfractions .25 .3 .45 % @item ... % % Numbers following @columnfractions are the percent of the total % current hsize to be used for each column. You may use as many % columns as desired. % Or use a template: % @multitable {Column 1 template} {Column 2 template} {Column 3 template} % @item ... % using the widest term desired in each column. % Each new table line starts with @item, each subsequent new column % starts with @tab. Empty columns may be produced by supplying @tab's % with nothing between them for as many times as empty columns are needed, % ie, @tab@tab@tab will produce two empty columns. % @item, @tab do not need to be on their own lines, but it will not hurt % if they are. % Sample multitable: % @multitable {Column 1 template} {Column 2 template} {Column 3 template} % @item first col stuff @tab second col stuff @tab third col % @item % first col stuff % @tab % second col stuff % @tab % third col % @item first col stuff @tab second col stuff % @tab Many paragraphs of text may be used in any column. % % They will wrap at the width determined by the template. % @item@tab@tab This will be in third column. % @end multitable % Default dimensions may be reset by user. % @multitableparskip is vertical space between paragraphs in table. % @multitableparindent is paragraph indent in table. % @multitablecolmargin is horizontal space to be left between columns. % @multitablelinespace is space to leave between table items, baseline % to baseline. % 0pt means it depends on current normal line spacing. % \newskip\multitableparskip \newskip\multitableparindent \newdimen\multitablecolspace \newskip\multitablelinespace \multitableparskip=0pt \multitableparindent=6pt \multitablecolspace=12pt \multitablelinespace=0pt % Macros used to set up halign preamble: % \let\endsetuptable\relax \def\xendsetuptable{\endsetuptable} \let\columnfractions\relax \def\xcolumnfractions{\columnfractions} \newif\ifsetpercent % #1 is the @columnfraction, usually a decimal number like .5, but might % be just 1. We just use it, whatever it is. % \def\pickupwholefraction#1 {% \global\advance\colcount by 1 \expandafter\xdef\csname col\the\colcount\endcsname{#1\hsize}% \setuptable } \newcount\colcount \def\setuptable#1{% \def\firstarg{#1}% \ifx\firstarg\xendsetuptable \let\go = \relax \else \ifx\firstarg\xcolumnfractions \global\setpercenttrue \else \ifsetpercent \let\go\pickupwholefraction \else \global\advance\colcount by 1 \setbox0=\hbox{#1\unskip\space}% Add a normal word space as a % separator; typically that is always in the input, anyway. \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}% \fi \fi \ifx\go\pickupwholefraction % Put the argument back for the \pickupwholefraction call, so % we'll always have a period there to be parsed. \def\go{\pickupwholefraction#1}% \else \let\go = \setuptable \fi% \fi \go } % multitable-only commands. % % @headitem starts a heading row, which we typeset in bold. % Assignments have to be global since we are inside the implicit group % of an alignment entry. \everycr resets \everytab so we don't have to % undo it ourselves. \def\headitemfont{\b}% for people to use in the template row; not changeable \def\headitem{% \checkenv\multitable \crcr \global\everytab={\bf}% can't use \headitemfont since the parsing differs \the\everytab % for the first item }% % % A \tab used to include \hskip1sp. But then the space in a template % line is not enough. That is bad. So let's go back to just `&' until % we again encounter the problem the 1sp was intended to solve. % --karl, nathan@acm.org, 20apr99. \def\tab{\checkenv\multitable &\the\everytab}% % @multitable ... @end multitable definitions: % \newtoks\everytab % insert after every tab. % \envdef\multitable{% \vskip\parskip \startsavinginserts % % @item within a multitable starts a normal row. % We use \def instead of \let so that if one of the multitable entries % contains an @itemize, we don't choke on the \item (seen as \crcr aka % \endtemplate) expanding \doitemize. \def\item{\crcr}% % \tolerance=9500 \hbadness=9500 \setmultitablespacing \parskip=\multitableparskip \parindent=\multitableparindent \overfullrule=0pt \global\colcount=0 % \everycr = {% \noalign{% \global\everytab={}% \global\colcount=0 % Reset the column counter. % Check for saved footnotes, etc. \checkinserts % Keeps underfull box messages off when table breaks over pages. %\filbreak % Maybe so, but it also creates really weird page breaks when the % table breaks over pages. Wouldn't \vfil be better? Wait until the % problem manifests itself, so it can be fixed for real --karl. }% }% % \parsearg\domultitable } \def\domultitable#1{% % To parse everything between @multitable and @item: \setuptable#1 \endsetuptable % % This preamble sets up a generic column definition, which will % be used as many times as user calls for columns. % \vtop will set a single line and will also let text wrap and % continue for many paragraphs if desired. \halign\bgroup &% \global\advance\colcount by 1 \multistrut \vtop{% % Use the current \colcount to find the correct column width: \hsize=\expandafter\csname col\the\colcount\endcsname % % In order to keep entries from bumping into each other % we will add a \leftskip of \multitablecolspace to all columns after % the first one. % % If a template has been used, we will add \multitablecolspace % to the width of each template entry. % % If the user has set preamble in terms of percent of \hsize we will % use that dimension as the width of the column, and the \leftskip % will keep entries from bumping into each other. Table will start at % left margin and final column will justify at right margin. % % Make sure we don't inherit \rightskip from the outer environment. \rightskip=0pt \ifnum\colcount=1 % The first column will be indented with the surrounding text. \advance\hsize by\leftskip \else \ifsetpercent \else % If user has not set preamble in terms of percent of \hsize % we will advance \hsize by \multitablecolspace. \advance\hsize by \multitablecolspace \fi % In either case we will make \leftskip=\multitablecolspace: \leftskip=\multitablecolspace \fi % Ignoring space at the beginning and end avoids an occasional spurious % blank line, when TeX decides to break the line at the space before the % box from the multistrut, so the strut ends up on a line by itself. % For example: % @multitable @columnfractions .11 .89 % @item @code{#} % @tab Legal holiday which is valid in major parts of the whole country. % Is automatically provided with highlighting sequences respectively % marking characters. \noindent\ignorespaces##\unskip\multistrut }\cr } \def\Emultitable{% \crcr \egroup % end the \halign \global\setpercentfalse } \def\setmultitablespacing{% \def\multistrut{\strut}% just use the standard line spacing % % Compute \multitablelinespace (if not defined by user) for use in % \multitableparskip calculation. We used define \multistrut based on % this, but (ironically) that caused the spacing to be off. % See bug-texinfo report from Werner Lemberg, 31 Oct 2004 12:52:20 +0100. \ifdim\multitablelinespace=0pt \setbox0=\vbox{X}\global\multitablelinespace=\the\baselineskip \global\advance\multitablelinespace by-\ht0 \fi % Test to see if parskip is larger than space between lines of % table. If not, do nothing. % If so, set to same dimension as multitablelinespace. \ifdim\multitableparskip>\multitablelinespace \global\multitableparskip=\multitablelinespace \global\advance\multitableparskip-7pt % to keep parskip somewhat smaller % than skip between lines in the table. \fi% \ifdim\multitableparskip=0pt \global\multitableparskip=\multitablelinespace \global\advance\multitableparskip-7pt % to keep parskip somewhat smaller % than skip between lines in the table. \fi} \message{conditionals,} % @iftex, @ifnotdocbook, @ifnothtml, @ifnotinfo, @ifnotplaintext, % @ifnotxml always succeed. They currently do nothing; we don't % attempt to check whether the conditionals are properly nested. But we % have to remember that they are conditionals, so that @end doesn't % attempt to close an environment group. % \def\makecond#1{% \expandafter\let\csname #1\endcsname = \relax \expandafter\let\csname iscond.#1\endcsname = 1 } \makecond{iftex} \makecond{ifnotdocbook} \makecond{ifnothtml} \makecond{ifnotinfo} \makecond{ifnotplaintext} \makecond{ifnotxml} % Ignore @ignore, @ifhtml, @ifinfo, and the like. % \def\direntry{\doignore{direntry}} \def\documentdescription{\doignore{documentdescription}} \def\docbook{\doignore{docbook}} \def\html{\doignore{html}} \def\ifdocbook{\doignore{ifdocbook}} \def\ifhtml{\doignore{ifhtml}} \def\ifinfo{\doignore{ifinfo}} \def\ifnottex{\doignore{ifnottex}} \def\ifplaintext{\doignore{ifplaintext}} \def\ifxml{\doignore{ifxml}} \def\ignore{\doignore{ignore}} \def\menu{\doignore{menu}} \def\xml{\doignore{xml}} % Ignore text until a line `@end #1', keeping track of nested conditionals. % % A count to remember the depth of nesting. \newcount\doignorecount \def\doignore#1{\begingroup % Scan in ``verbatim'' mode: \obeylines \catcode`\@ = \other \catcode`\{ = \other \catcode`\} = \other % % Make sure that spaces turn into tokens that match what \doignoretext wants. \spaceisspace % % Count number of #1's that we've seen. \doignorecount = 0 % % Swallow text until we reach the matching `@end #1'. \dodoignore{#1}% } { \catcode`_=11 % We want to use \_STOP_ which cannot appear in texinfo source. \obeylines % % \gdef\dodoignore#1{% % #1 contains the command name as a string, e.g., `ifinfo'. % % Define a command to find the next `@end #1'. \long\def\doignoretext##1^^M@end #1{% \doignoretextyyy##1^^M@#1\_STOP_}% % % And this command to find another #1 command, at the beginning of a % line. (Otherwise, we would consider a line `@c @ifset', for % example, to count as an @ifset for nesting.) \long\def\doignoretextyyy##1^^M@#1##2\_STOP_{\doignoreyyy{##2}\_STOP_}% % % And now expand that command. \doignoretext ^^M% }% } \def\doignoreyyy#1{% \def\temp{#1}% \ifx\temp\empty % Nothing found. \let\next\doignoretextzzz \else % Found a nested condition, ... \advance\doignorecount by 1 \let\next\doignoretextyyy % ..., look for another. % If we're here, #1 ends with ^^M\ifinfo (for example). \fi \next #1% the token \_STOP_ is present just after this macro. } % We have to swallow the remaining "\_STOP_". % \def\doignoretextzzz#1{% \ifnum\doignorecount = 0 % We have just found the outermost @end. \let\next\enddoignore \else % Still inside a nested condition. \advance\doignorecount by -1 \let\next\doignoretext % Look for the next @end. \fi \next } % Finish off ignored text. { \obeylines% % Ignore anything after the last `@end #1'; this matters in verbatim % environments, where otherwise the newline after an ignored conditional % would result in a blank line in the output. \gdef\enddoignore#1^^M{\endgroup\ignorespaces}% } % @set VAR sets the variable VAR to an empty value. % @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE. % % Since we want to separate VAR from REST-OF-LINE (which might be % empty), we can't just use \parsearg; we have to insert a space of our % own to delimit the rest of the line, and then take it out again if we % didn't need it. % We rely on the fact that \parsearg sets \catcode`\ =10. % \parseargdef\set{\setyyy#1 \endsetyyy} \def\setyyy#1 #2\endsetyyy{% {% \makevalueexpandable \def\temp{#2}% \edef\next{\gdef\makecsname{SET#1}}% \ifx\temp\empty \next{}% \else \setzzz#2\endsetzzz \fi }% } % Remove the trailing space \setxxx inserted. \def\setzzz#1 \endsetzzz{\next{#1}} % @clear VAR clears (i.e., unsets) the variable VAR. % \parseargdef\clear{% {% \makevalueexpandable \global\expandafter\let\csname SET#1\endcsname=\relax }% } % @value{foo} gets the text saved in variable foo. \def\value{\begingroup\makevalueexpandable\valuexxx} \def\valuexxx#1{\expandablevalue{#1}\endgroup} { \catcode`\- = \active \catcode`\_ = \active % \gdef\makevalueexpandable{% \let\value = \expandablevalue % We don't want these characters active, ... \catcode`\-=\other \catcode`\_=\other % ..., but we might end up with active ones in the argument if % we're called from @code, as @code{@value{foo-bar_}}, though. % So \let them to their normal equivalents. \let-\realdash \let_\normalunderscore } } % We have this subroutine so that we can handle at least some @value's % properly in indexes (we call \makevalueexpandable in \indexdummies). % The command has to be fully expandable (if the variable is set), since % the result winds up in the index file. This means that if the % variable's value contains other Texinfo commands, it's almost certain % it will fail (although perhaps we could fix that with sufficient work % to do a one-level expansion on the result, instead of complete). % \def\expandablevalue#1{% \expandafter\ifx\csname SET#1\endcsname\relax {[No value for ``#1'']}% \message{Variable `#1', used in @value, is not set.}% \else \csname SET#1\endcsname \fi } % @ifset VAR ... @end ifset reads the `...' iff VAR has been defined % with @set. % % To get special treatment of `@end ifset,' call \makeond and the redefine. % \makecond{ifset} \def\ifset{\parsearg{\doifset{\let\next=\ifsetfail}}} \def\doifset#1#2{% {% \makevalueexpandable \let\next=\empty \expandafter\ifx\csname SET#2\endcsname\relax #1% If not set, redefine \next. \fi \expandafter }\next } \def\ifsetfail{\doignore{ifset}} % @ifclear VAR ... @end executes the `...' iff VAR has never been % defined with @set, or has been undefined with @clear. % % The `\else' inside the `\doifset' parameter is a trick to reuse the % above code: if the variable is not set, do nothing, if it is set, % then redefine \next to \ifclearfail. % \makecond{ifclear} \def\ifclear{\parsearg{\doifset{\else \let\next=\ifclearfail}}} \def\ifclearfail{\doignore{ifclear}} % @ifcommandisdefined CMD ... @end executes the `...' if CMD (written % without the @) is in fact defined. We can only feasibly check at the % TeX level, so something like `mathcode' is going to considered % defined even though it is not a Texinfo command. % \makecond{ifcommanddefined} \def\ifcommanddefined{\parsearg{\doifcmddefined{\let\next=\ifcmddefinedfail}}} % \def\doifcmddefined#1#2{{% \makevalueexpandable \let\next=\empty \expandafter\ifx\csname #2\endcsname\relax #1% If not defined, \let\next as above. \fi \expandafter }\next } \def\ifcmddefinedfail{\doignore{ifcommanddefined}} % @ifcommandnotdefined CMD ... handled similar to @ifclear above. \makecond{ifcommandnotdefined} \def\ifcommandnotdefined{% \parsearg{\doifcmddefined{\else \let\next=\ifcmdnotdefinedfail}}} \def\ifcmdnotdefinedfail{\doignore{ifcommandnotdefined}} % Set the `txicommandconditionals' variable, so documents have a way to % test if the @ifcommand...defined conditionals are available. \set txicommandconditionals % @dircategory CATEGORY -- specify a category of the dir file % which this file should belong to. Ignore this in TeX. \let\dircategory=\comment % @defininfoenclose. \let\definfoenclose=\comment \message{indexing,} % Index generation facilities % Define \newwrite to be identical to plain tex's \newwrite % except not \outer, so it can be used within macros and \if's. \edef\newwrite{\makecsname{ptexnewwrite}} % \newindex {foo} defines an index named foo. % It automatically defines \fooindex such that % \fooindex ...rest of line... puts an entry in the index foo. % It also defines \fooindfile to be the number of the output channel for % the file that accumulates this index. The file's extension is foo. % The name of an index should be no more than 2 characters long % for the sake of vms. % \def\newindex#1{% \iflinks \expandafter\newwrite \csname#1indfile\endcsname \openout \csname#1indfile\endcsname \jobname.#1 % Open the file \fi \expandafter\xdef\csname#1index\endcsname{% % Define @#1index \noexpand\doindex{#1}} } % @defindex foo == \newindex{foo} % \def\defindex{\parsearg\newindex} % Define @defcodeindex, like @defindex except put all entries in @code. % \def\defcodeindex{\parsearg\newcodeindex} % \def\newcodeindex#1{% \iflinks \expandafter\newwrite \csname#1indfile\endcsname \openout \csname#1indfile\endcsname \jobname.#1 \fi \expandafter\xdef\csname#1index\endcsname{% \noexpand\docodeindex{#1}}% } % @synindex foo bar makes index foo feed into index bar. % Do this instead of @defindex foo if you don't want it as a separate index. % % @syncodeindex foo bar similar, but put all entries made for index foo % inside @code. % \def\synindex#1 #2 {\dosynindex\doindex{#1}{#2}} \def\syncodeindex#1 #2 {\dosynindex\docodeindex{#1}{#2}} % #1 is \doindex or \docodeindex, #2 the index getting redefined (foo), % #3 the target index (bar). \def\dosynindex#1#2#3{% % Only do \closeout if we haven't already done it, else we'll end up % closing the target index. \expandafter \ifx\csname donesynindex#2\endcsname \relax % The \closeout helps reduce unnecessary open files; the limit on the % Acorn RISC OS is a mere 16 files. \expandafter\closeout\csname#2indfile\endcsname \expandafter\let\csname donesynindex#2\endcsname = 1 \fi % redefine \fooindfile: \expandafter\let\expandafter\temp\expandafter=\csname#3indfile\endcsname \expandafter\let\csname#2indfile\endcsname=\temp % redefine \fooindex: \expandafter\xdef\csname#2index\endcsname{\noexpand#1{#3}}% } % Define \doindex, the driver for all \fooindex macros. % Argument #1 is generated by the calling \fooindex macro, % and it is "foo", the name of the index. % \doindex just uses \parsearg; it calls \doind for the actual work. % This is because \doind is more useful to call from other macros. % There is also \dosubind {index}{topic}{subtopic} % which makes an entry in a two-level index such as the operation index. \def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer} \def\singleindexer #1{\doind{\indexname}{#1}} % like the previous two, but they put @code around the argument. \def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer} \def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}} % Take care of Texinfo commands that can appear in an index entry. % Since there are some commands we want to expand, and others we don't, % we have to laboriously prevent expansion for those that we don't. % \def\indexdummies{% \escapechar = `\\ % use backslash in output files. \def\@{@}% change to @@ when we switch to @ as escape char in index files. \def\ {\realbackslash\space }% % % Need these unexpandable (because we define \tt as a dummy) % definitions when @{ or @} appear in index entry text. Also, more % complicated, when \tex is in effect and \{ is a \delimiter again. % We can't use \lbracecmd and \rbracecmd because texindex assumes % braces and backslashes are used only as delimiters. Perhaps we % should define @lbrace and @rbrace commands a la @comma. \def\{{{\tt\char123}}% \def\}{{\tt\char125}}% % % I don't entirely understand this, but when an index entry is % generated from a macro call, the \endinput which \scanmacro inserts % causes processing to be prematurely terminated. This is, % apparently, because \indexsorttmp is fully expanded, and \endinput % is an expandable command. The redefinition below makes \endinput % disappear altogether for that purpose -- although logging shows that % processing continues to some further point. On the other hand, it % seems \endinput does not hurt in the printed index arg, since that % is still getting written without apparent harm. % % Sample source (mac-idx3.tex, reported by Graham Percival to % help-texinfo, 22may06): % @macro funindex {WORD} % @findex xyz % @end macro % ... % @funindex commtest % % The above is not enough to reproduce the bug, but it gives the flavor. % % Sample whatsit resulting: % .@write3{\entry{xyz}{@folio }{@code {xyz@endinput }}} % % So: \let\endinput = \empty % % Do the redefinitions. \commondummies } % For the aux and toc files, @ is the escape character. So we want to % redefine everything using @ as the escape character (instead of % \realbackslash, still used for index files). When everything uses @, % this will be simpler. % \def\atdummies{% \def\@{@@}% \def\ {@ }% \let\{ = \lbraceatcmd \let\} = \rbraceatcmd % % Do the redefinitions. \commondummies \otherbackslash } % Called from \indexdummies and \atdummies. % \def\commondummies{% % % \definedummyword defines \#1 as \string\#1\space, thus effectively % preventing its expansion. This is used only for control words, % not control letters, because the \space would be incorrect for % control characters, but is needed to separate the control word % from whatever follows. % % For control letters, we have \definedummyletter, which omits the % space. % % These can be used both for control words that take an argument and % those that do not. If it is followed by {arg} in the input, then % that will dutifully get written to the index (or wherever). % \def\definedummyword ##1{\def##1{\string##1\space}}% \def\definedummyletter##1{\def##1{\string##1}}% \let\definedummyaccent\definedummyletter % \commondummiesnofonts % \definedummyletter\_% \definedummyletter\-% % % Non-English letters. \definedummyword\AA \definedummyword\AE \definedummyword\DH \definedummyword\L \definedummyword\O \definedummyword\OE \definedummyword\TH \definedummyword\aa \definedummyword\ae \definedummyword\dh \definedummyword\exclamdown \definedummyword\l \definedummyword\o \definedummyword\oe \definedummyword\ordf \definedummyword\ordm \definedummyword\questiondown \definedummyword\ss \definedummyword\th % % Although these internal commands shouldn't show up, sometimes they do. \definedummyword\bf \definedummyword\gtr \definedummyword\hat \definedummyword\less \definedummyword\sf \definedummyword\sl \definedummyword\tclose \definedummyword\tt % \definedummyword\LaTeX \definedummyword\TeX % % Assorted special characters. \definedummyword\arrow \definedummyword\bullet \definedummyword\comma \definedummyword\copyright \definedummyword\registeredsymbol \definedummyword\dots \definedummyword\enddots \definedummyword\entrybreak \definedummyword\equiv \definedummyword\error \definedummyword\euro \definedummyword\expansion \definedummyword\geq \definedummyword\guillemetleft \definedummyword\guillemetright \definedummyword\guilsinglleft \definedummyword\guilsinglright \definedummyword\lbracechar \definedummyword\leq \definedummyword\minus \definedummyword\ogonek \definedummyword\pounds \definedummyword\point \definedummyword\print \definedummyword\quotedblbase \definedummyword\quotedblleft \definedummyword\quotedblright \definedummyword\quoteleft \definedummyword\quoteright \definedummyword\quotesinglbase \definedummyword\rbracechar \definedummyword\result \definedummyword\textdegree % % We want to disable all macros so that they are not expanded by \write. \macrolist % \normalturnoffactive % % Handle some cases of @value -- where it does not contain any % (non-fully-expandable) commands. \makevalueexpandable } % \commondummiesnofonts: common to \commondummies and \indexnofonts. % \def\commondummiesnofonts{% % Control letters and accents. \definedummyletter\!% \definedummyaccent\"% \definedummyaccent\'% \definedummyletter\*% \definedummyaccent\,% \definedummyletter\.% \definedummyletter\/% \definedummyletter\:% \definedummyaccent\=% \definedummyletter\?% \definedummyaccent\^% \definedummyaccent\`% \definedummyaccent\~% \definedummyword\u \definedummyword\v \definedummyword\H \definedummyword\dotaccent \definedummyword\ogonek \definedummyword\ringaccent \definedummyword\tieaccent \definedummyword\ubaraccent \definedummyword\udotaccent \definedummyword\dotless % % Texinfo font commands. \definedummyword\b \definedummyword\i \definedummyword\r \definedummyword\sansserif \definedummyword\sc \definedummyword\slanted \definedummyword\t % % Commands that take arguments. \definedummyword\abbr \definedummyword\acronym \definedummyword\anchor \definedummyword\cite \definedummyword\code \definedummyword\command \definedummyword\dfn \definedummyword\dmn \definedummyword\email \definedummyword\emph \definedummyword\env \definedummyword\file \definedummyword\image \definedummyword\indicateurl \definedummyword\inforef \definedummyword\kbd \definedummyword\key \definedummyword\math \definedummyword\option \definedummyword\pxref \definedummyword\ref \definedummyword\samp \definedummyword\strong \definedummyword\tie \definedummyword\uref \definedummyword\url \definedummyword\var \definedummyword\verb \definedummyword\w \definedummyword\xref } % \indexnofonts is used when outputting the strings to sort the index % by, and when constructing control sequence names. It eliminates all % control sequences and just writes whatever the best ASCII sort string % would be for a given command (usually its argument). % \def\indexnofonts{% % Accent commands should become @asis. \def\definedummyaccent##1{\let##1\asis}% % We can just ignore other control letters. \def\definedummyletter##1{\let##1\empty}% % All control words become @asis by default; overrides below. \let\definedummyword\definedummyaccent % \commondummiesnofonts % % Don't no-op \tt, since it isn't a user-level command % and is used in the definitions of the active chars like <, >, |, etc. % Likewise with the other plain tex font commands. %\let\tt=\asis % \def\ { }% \def\@{@}% \def\_{\normalunderscore}% \def\-{}% @- shouldn't affect sorting % % Unfortunately, texindex is not prepared to handle braces in the % content at all. So for index sorting, we map @{ and @} to strings % starting with |, since that ASCII character is between ASCII { and }. \def\{{|a}% \def\lbracechar{|a}% % \def\}{|b}% \def\rbracechar{|b}% % % Non-English letters. \def\AA{AA}% \def\AE{AE}% \def\DH{DZZ}% \def\L{L}% \def\OE{OE}% \def\O{O}% \def\TH{ZZZ}% \def\aa{aa}% \def\ae{ae}% \def\dh{dzz}% \def\exclamdown{!}% \def\l{l}% \def\oe{oe}% \def\ordf{a}% \def\ordm{o}% \def\o{o}% \def\questiondown{?}% \def\ss{ss}% \def\th{zzz}% % \def\LaTeX{LaTeX}% \def\TeX{TeX}% % % Assorted special characters. % (The following {} will end up in the sort string, but that's ok.) \def\arrow{->}% \def\bullet{bullet}% \def\comma{,}% \def\copyright{copyright}% \def\dots{...}% \def\enddots{...}% \def\equiv{==}% \def\error{error}% \def\euro{euro}% \def\expansion{==>}% \def\geq{>=}% \def\guillemetleft{<<}% \def\guillemetright{>>}% \def\guilsinglleft{<}% \def\guilsinglright{>}% \def\leq{<=}% \def\minus{-}% \def\point{.}% \def\pounds{pounds}% \def\print{-|}% \def\quotedblbase{"}% \def\quotedblleft{"}% \def\quotedblright{"}% \def\quoteleft{`}% \def\quoteright{'}% \def\quotesinglbase{,}% \def\registeredsymbol{R}% \def\result{=>}% \def\textdegree{o}% % \expandafter\ifx\csname SETtxiindexlquoteignore\endcsname\relax \else \indexlquoteignore \fi % % We need to get rid of all macros, leaving only the arguments (if present). % Of course this is not nearly correct, but it is the best we can do for now. % makeinfo does not expand macros in the argument to @deffn, which ends up % writing an index entry, and texindex isn't prepared for an index sort entry % that starts with \. % % Since macro invocations are followed by braces, we can just redefine them % to take a single TeX argument. The case of a macro invocation that % goes to end-of-line is not handled. % \macrolist } % Undocumented (for FSFS 2nd ed.): @set txiindexlquoteignore makes us % ignore left quotes in the sort term. {\catcode`\`=\active \gdef\indexlquoteignore{\let`=\empty}} \let\indexbackslash=0 %overridden during \printindex. \let\SETmarginindex=\relax % put index entries in margin (undocumented)? % Most index entries go through here, but \dosubind is the general case. % #1 is the index name, #2 is the entry text. \def\doind#1#2{\dosubind{#1}{#2}{}} % Workhorse for all \fooindexes. % #1 is name of index, #2 is stuff to put there, #3 is subentry -- % empty if called from \doind, as we usually are (the main exception % is with most defuns, which call us directly). % \def\dosubind#1#2#3{% \iflinks {% % Store the main index entry text (including the third arg). \toks0 = {#2}% % If third arg is present, precede it with a space. \def\thirdarg{#3}% \ifx\thirdarg\empty \else \toks0 = \expandafter{\the\toks0 \space #3}% \fi % \edef\writeto{\csname#1indfile\endcsname}% % \safewhatsit\dosubindwrite }% \fi } % Write the entry in \toks0 to the index file: % \def\dosubindwrite{% % Put the index entry in the margin if desired. \ifx\SETmarginindex\relax\else \insert\margin{\hbox{\vrule height8pt depth3pt width0pt \the\toks0}}% \fi % % Remember, we are within a group. \indexdummies % Must do this here, since \bf, etc expand at this stage \def\backslashcurfont{\indexbackslash}% \indexbackslash isn't defined now % so it will be output as is; and it will print as backslash. % % Process the index entry with all font commands turned off, to % get the string to sort by. {\indexnofonts \edef\temp{\the\toks0}% need full expansion \xdef\indexsorttmp{\temp}% }% % % Set up the complete index entry, with both the sort key and % the original text, including any font commands. We write % three arguments to \entry to the .?? file (four in the % subentry case), texindex reduces to two when writing the .??s % sorted result. \edef\temp{% \write\writeto{% \string\entry{\indexsorttmp}{\noexpand\folio}{\the\toks0}}% }% \temp } % Take care of unwanted page breaks/skips around a whatsit: % % If a skip is the last thing on the list now, preserve it % by backing up by \lastskip, doing the \write, then inserting % the skip again. Otherwise, the whatsit generated by the % \write or \pdfdest will make \lastskip zero. The result is that % sequences like this: % @end defun % @tindex whatever % @defun ... % will have extra space inserted, because the \medbreak in the % start of the @defun won't see the skip inserted by the @end of % the previous defun. % % But don't do any of this if we're not in vertical mode. We % don't want to do a \vskip and prematurely end a paragraph. % % Avoid page breaks due to these extra skips, too. % % But wait, there is a catch there: % We'll have to check whether \lastskip is zero skip. \ifdim is not % sufficient for this purpose, as it ignores stretch and shrink parts % of the skip. The only way seems to be to check the textual % representation of the skip. % % The following is almost like \def\zeroskipmacro{0.0pt} except that % the ``p'' and ``t'' characters have catcode \other, not 11 (letter). % \edef\zeroskipmacro{\expandafter\the\csname z@skip\endcsname} % \newskip\whatsitskip \newcount\whatsitpenalty % % ..., ready, GO: % \def\safewhatsit#1{\ifhmode #1% \else % \lastskip and \lastpenalty cannot both be nonzero simultaneously. \whatsitskip = \lastskip \edef\lastskipmacro{\the\lastskip}% \whatsitpenalty = \lastpenalty % % If \lastskip is nonzero, that means the last item was a % skip. And since a skip is discardable, that means this % -\whatsitskip glue we're inserting is preceded by a % non-discardable item, therefore it is not a potential % breakpoint, therefore no \nobreak needed. \ifx\lastskipmacro\zeroskipmacro \else \vskip-\whatsitskip \fi % #1% % \ifx\lastskipmacro\zeroskipmacro % If \lastskip was zero, perhaps the last item was a penalty, and % perhaps it was >=10000, e.g., a \nobreak. In that case, we want % to re-insert the same penalty (values >10000 are used for various % signals); since we just inserted a non-discardable item, any % following glue (such as a \parskip) would be a breakpoint. For example: % @deffn deffn-whatever % @vindex index-whatever % Description. % would allow a break between the index-whatever whatsit % and the "Description." paragraph. \ifnum\whatsitpenalty>9999 \penalty\whatsitpenalty \fi \else % On the other hand, if we had a nonzero \lastskip, % this make-up glue would be preceded by a non-discardable item % (the whatsit from the \write), so we must insert a \nobreak. \nobreak\vskip\whatsitskip \fi \fi} % The index entry written in the file actually looks like % \entry {sortstring}{page}{topic} % or % \entry {sortstring}{page}{topic}{subtopic} % The texindex program reads in these files and writes files % containing these kinds of lines: % \initial {c} % before the first topic whose initial is c % \entry {topic}{pagelist} % for a topic that is used without subtopics % \primary {topic} % for the beginning of a topic that is used with subtopics % \secondary {subtopic}{pagelist} % for each subtopic. % Define the user-accessible indexing commands % @findex, @vindex, @kindex, @cindex. \def\findex {\fnindex} \def\kindex {\kyindex} \def\cindex {\cpindex} \def\vindex {\vrindex} \def\tindex {\tpindex} \def\pindex {\pgindex} \def\cindexsub {\begingroup\obeylines\cindexsub} {\obeylines % \gdef\cindexsub "#1" #2^^M{\endgroup % \dosubind{cp}{#2}{#1}}} % Define the macros used in formatting output of the sorted index material. % @printindex causes a particular index (the ??s file) to get printed. % It does not print any chapter heading (usually an @unnumbered). % \parseargdef\printindex{\begingroup \dobreak \chapheadingskip{10000}% % \smallfonts \rm \tolerance = 9500 \plainfrenchspacing \everypar = {}% don't want the \kern\-parindent from indentation suppression. % % See if the index file exists and is nonempty. % Change catcode of @ here so that if the index file contains % \initial {@} % as its first line, TeX doesn't complain about mismatched braces % (because it thinks @} is a control sequence). \catcode`\@ = 11 \openin 1 \jobname.#1s \ifeof 1 % \enddoublecolumns gets confused if there is no text in the index, % and it loses the chapter title and the aux file entries for the % index. The easiest way to prevent this problem is to make sure % there is some text. \putwordIndexNonexistent \else % % If the index file exists but is empty, then \openin leaves \ifeof % false. We have to make TeX try to read something from the file, so % it can discover if there is anything in it. \read 1 to \temp \ifeof 1 \putwordIndexIsEmpty \else % Index files are almost Texinfo source, but we use \ as the escape % character. It would be better to use @, but that's too big a change % to make right now. \def\indexbackslash{\backslashcurfont}% \catcode`\\ = 0 \escapechar = `\\ \begindoublecolumns \input \jobname.#1s \enddoublecolumns \fi \fi \closein 1 \endgroup} % These macros are used by the sorted index file itself. % Change them to control the appearance of the index. \def\initial#1{{% % Some minor font changes for the special characters. \let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt % % Remove any glue we may have, we'll be inserting our own. \removelastskip % % We like breaks before the index initials, so insert a bonus. \nobreak \vskip 0pt plus 3\baselineskip \penalty 0 \vskip 0pt plus -3\baselineskip % % Typeset the initial. Making this add up to a whole number of % baselineskips increases the chance of the dots lining up from column % to column. It still won't often be perfect, because of the stretch % we need before each entry, but it's better. % % No shrink because it confuses \balancecolumns. \vskip 1.67\baselineskip plus .5\baselineskip \leftline{\secbf #1}% % Do our best not to break after the initial. \nobreak \vskip .33\baselineskip plus .1\baselineskip }} % \entry typesets a paragraph consisting of the text (#1), dot leaders, and % then page number (#2) flushed to the right margin. It is used for index % and table of contents entries. The paragraph is indented by \leftskip. % % A straightforward implementation would start like this: % \def\entry#1#2{... % But this freezes the catcodes in the argument, and can cause problems to % @code, which sets - active. This problem was fixed by a kludge--- % ``-'' was active throughout whole index, but this isn't really right. % The right solution is to prevent \entry from swallowing the whole text. % --kasal, 21nov03 \def\entry{% \begingroup % % Start a new paragraph if necessary, so our assignments below can't % affect previous text. \par % % Do not fill out the last line with white space. \parfillskip = 0in % % No extra space above this paragraph. \parskip = 0in % % Do not prefer a separate line ending with a hyphen to fewer lines. \finalhyphendemerits = 0 % % \hangindent is only relevant when the entry text and page number % don't both fit on one line. In that case, bob suggests starting the % dots pretty far over on the line. Unfortunately, a large % indentation looks wrong when the entry text itself is broken across % lines. So we use a small indentation and put up with long leaders. % % \hangafter is reset to 1 (which is the value we want) at the start % of each paragraph, so we need not do anything with that. \hangindent = 2em % % When the entry text needs to be broken, just fill out the first line % with blank space. \rightskip = 0pt plus1fil % % A bit of stretch before each entry for the benefit of balancing % columns. \vskip 0pt plus1pt % % When reading the text of entry, convert explicit line breaks % from @* into spaces. The user might give these in long section % titles, for instance. \def\*{\unskip\space\ignorespaces}% \def\entrybreak{\hfil\break}% % % Swallow the left brace of the text (first parameter): \afterassignment\doentry \let\temp = } \def\entrybreak{\unskip\space\ignorespaces}% \def\doentry{% \bgroup % Instead of the swallowed brace. \noindent \aftergroup\finishentry % And now comes the text of the entry. } \def\finishentry#1{% % #1 is the page number. % % The following is kludged to not output a line of dots in the index if % there are no page numbers. The next person who breaks this will be % cursed by a Unix daemon. \setbox\boxA = \hbox{#1}% \ifdim\wd\boxA = 0pt \ % \else % % If we must, put the page number on a line of its own, and fill out % this line with blank space. (The \hfil is overwhelmed with the % fill leaders glue in \indexdotfill if the page number does fit.) \hfil\penalty50 \null\nobreak\indexdotfill % Have leaders before the page number. % % The `\ ' here is removed by the implicit \unskip that TeX does as % part of (the primitive) \par. Without it, a spurious underfull % \hbox ensues. \ifpdf \pdfgettoks#1.% \ \the\toksA \else \ #1% \fi \fi \par \endgroup } % Like plain.tex's \dotfill, except uses up at least 1 em. \def\indexdotfill{\cleaders \hbox{$\mathsurround=0pt \mkern1.5mu.\mkern1.5mu$}\hskip 1em plus 1fill} \def\primary #1{\line{#1\hfil}} \newskip\secondaryindent \secondaryindent=0.5cm \def\secondary#1#2{{% \parfillskip=0in \parskip=0in \hangindent=1in \hangafter=1 \noindent\hskip\secondaryindent\hbox{#1}\indexdotfill \ifpdf \pdfgettoks#2.\ \the\toksA % The page number ends the paragraph. \else #2 \fi \par }} % Define two-column mode, which we use to typeset indexes. % Adapted from the TeXbook, page 416, which is to say, % the manmac.tex format used to print the TeXbook itself. \catcode`\@=11 \newbox\partialpage \newdimen\doublecolumnhsize \def\begindoublecolumns{\begingroup % ended by \enddoublecolumns % Grab any single-column material above us. \output = {% % % Here is a possibility not foreseen in manmac: if we accumulate a % whole lot of material, we might end up calling this \output % routine twice in a row (see the doublecol-lose test, which is % essentially a couple of indexes with @setchapternewpage off). In % that case we just ship out what is in \partialpage with the normal % output routine. Generally, \partialpage will be empty when this % runs and this will be a no-op. See the indexspread.tex test case. \ifvoid\partialpage \else \onepageout{\pagecontents\partialpage}% \fi % \global\setbox\partialpage = \vbox{% % Unvbox the main output page. \unvbox\PAGE \kern-\topskip \kern\baselineskip }% }% \eject % run that output routine to set \partialpage % % Use the double-column output routine for subsequent pages. \output = {\doublecolumnout}% % % Change the page size parameters. We could do this once outside this % routine, in each of @smallbook, @afourpaper, and the default 8.5x11 % format, but then we repeat the same computation. Repeating a couple % of assignments once per index is clearly meaningless for the % execution time, so we may as well do it in one place. % % First we halve the line length, less a little for the gutter between % the columns. We compute the gutter based on the line length, so it % changes automatically with the paper format. The magic constant % below is chosen so that the gutter has the same value (well, +-<1pt) % as it did when we hard-coded it. % % We put the result in a separate register, \doublecolumhsize, so we % can restore it in \pagesofar, after \hsize itself has (potentially) % been clobbered. % \doublecolumnhsize = \hsize \advance\doublecolumnhsize by -.04154\hsize \divide\doublecolumnhsize by 2 \hsize = \doublecolumnhsize % % Double the \vsize as well. (We don't need a separate register here, % since nobody clobbers \vsize.) \vsize = 2\vsize } % The double-column output routine for all double-column pages except % the last. % \def\doublecolumnout{% \splittopskip=\topskip \splitmaxdepth=\maxdepth % Get the available space for the double columns -- the normal % (undoubled) page height minus any material left over from the % previous page. \dimen@ = \vsize \divide\dimen@ by 2 \advance\dimen@ by -\ht\partialpage % % box0 will be the left-hand column, box2 the right. \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@ \onepageout\pagesofar \unvbox255 \penalty\outputpenalty } % % Re-output the contents of the output page -- any previous material, % followed by the two boxes we just split, in box0 and box2. \def\pagesofar{% \unvbox\partialpage % \hsize = \doublecolumnhsize \wd0=\hsize \wd2=\hsize \hbox to\pagewidth{\box0\hfil\box2}% } % % All done with double columns. \def\enddoublecolumns{% % The following penalty ensures that the page builder is exercised % _before_ we change the output routine. This is necessary in the % following situation: % % The last section of the index consists only of a single entry. % Before this section, \pagetotal is less than \pagegoal, so no % break occurs before the last section starts. However, the last % section, consisting of \initial and the single \entry, does not % fit on the page and has to be broken off. Without the following % penalty the page builder will not be exercised until \eject % below, and by that time we'll already have changed the output % routine to the \balancecolumns version, so the next-to-last % double-column page will be processed with \balancecolumns, which % is wrong: The two columns will go to the main vertical list, with % the broken-off section in the recent contributions. As soon as % the output routine finishes, TeX starts reconsidering the page % break. The two columns and the broken-off section both fit on the % page, because the two columns now take up only half of the page % goal. When TeX sees \eject from below which follows the final % section, it invokes the new output routine that we've set after % \balancecolumns below; \onepageout will try to fit the two columns % and the final section into the vbox of \pageheight (see % \pagebody), causing an overfull box. % % Note that glue won't work here, because glue does not exercise the % page builder, unlike penalties (see The TeXbook, pp. 280-281). \penalty0 % \output = {% % Split the last of the double-column material. Leave it on the % current page, no automatic page break. \balancecolumns % % If we end up splitting too much material for the current page, % though, there will be another page break right after this \output % invocation ends. Having called \balancecolumns once, we do not % want to call it again. Therefore, reset \output to its normal % definition right away. (We hope \balancecolumns will never be % called on to balance too much material, but if it is, this makes % the output somewhat more palatable.) \global\output = {\onepageout{\pagecontents\PAGE}}% }% \eject \endgroup % started in \begindoublecolumns % % \pagegoal was set to the doubled \vsize above, since we restarted % the current page. We're now back to normal single-column % typesetting, so reset \pagegoal to the normal \vsize (after the % \endgroup where \vsize got restored). \pagegoal = \vsize } % % Called at the end of the double column material. \def\balancecolumns{% \setbox0 = \vbox{\unvbox255}% like \box255 but more efficient, see p.120. \dimen@ = \ht0 \advance\dimen@ by \topskip \advance\dimen@ by-\baselineskip \divide\dimen@ by 2 % target to split to %debug\message{final 2-column material height=\the\ht0, target=\the\dimen@.}% \splittopskip = \topskip % Loop until we get a decent breakpoint. {% \vbadness = 10000 \loop \global\setbox3 = \copy0 \global\setbox1 = \vsplit3 to \dimen@ \ifdim\ht3>\dimen@ \global\advance\dimen@ by 1pt \repeat }% %debug\message{split to \the\dimen@, column heights: \the\ht1, \the\ht3.}% \setbox0=\vbox to\dimen@{\unvbox1}% \setbox2=\vbox to\dimen@{\unvbox3}% % \pagesofar } \catcode`\@ = \other \message{sectioning,} % Chapters, sections, etc. % Let's start with @part. \outer\parseargdef\part{\partzzz{#1}} \def\partzzz#1{% \chapoddpage \null \vskip.3\vsize % move it down on the page a bit \begingroup \noindent \titlefonts\rmisbold #1\par % the text \let\lastnode=\empty % no node to associate with \writetocentry{part}{#1}{}% but put it in the toc \headingsoff % no headline or footline on the part page \chapoddpage \endgroup } % \unnumberedno is an oxymoron. But we count the unnumbered % sections so that we can refer to them unambiguously in the pdf % outlines by their "section number". We avoid collisions with chapter % numbers by starting them at 10000. (If a document ever has 10000 % chapters, we're in trouble anyway, I'm sure.) \newcount\unnumberedno \unnumberedno = 10000 \newcount\chapno \newcount\secno \secno=0 \newcount\subsecno \subsecno=0 \newcount\subsubsecno \subsubsecno=0 % This counter is funny since it counts through charcodes of letters A, B, ... \newcount\appendixno \appendixno = `\@ % % \def\appendixletter{\char\the\appendixno} % We do the following ugly conditional instead of the above simple % construct for the sake of pdftex, which needs the actual % letter in the expansion, not just typeset. % \def\appendixletter{% \ifnum\appendixno=`A A% \else\ifnum\appendixno=`B B% \else\ifnum\appendixno=`C C% \else\ifnum\appendixno=`D D% \else\ifnum\appendixno=`E E% \else\ifnum\appendixno=`F F% \else\ifnum\appendixno=`G G% \else\ifnum\appendixno=`H H% \else\ifnum\appendixno=`I I% \else\ifnum\appendixno=`J J% \else\ifnum\appendixno=`K K% \else\ifnum\appendixno=`L L% \else\ifnum\appendixno=`M M% \else\ifnum\appendixno=`N N% \else\ifnum\appendixno=`O O% \else\ifnum\appendixno=`P P% \else\ifnum\appendixno=`Q Q% \else\ifnum\appendixno=`R R% \else\ifnum\appendixno=`S S% \else\ifnum\appendixno=`T T% \else\ifnum\appendixno=`U U% \else\ifnum\appendixno=`V V% \else\ifnum\appendixno=`W W% \else\ifnum\appendixno=`X X% \else\ifnum\appendixno=`Y Y% \else\ifnum\appendixno=`Z Z% % The \the is necessary, despite appearances, because \appendixletter is % expanded while writing the .toc file. \char\appendixno is not % expandable, thus it is written literally, thus all appendixes come out % with the same letter (or @) in the toc without it. \else\char\the\appendixno \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi} % Each @chapter defines these (using marks) as the number+name, number % and name of the chapter. Page headings and footings can use % these. @section does likewise. \def\thischapter{} \def\thischapternum{} \def\thischaptername{} \def\thissection{} \def\thissectionnum{} \def\thissectionname{} \newcount\absseclevel % used to calculate proper heading level \newcount\secbase\secbase=0 % @raisesections/@lowersections modify this count % @raisesections: treat @section as chapter, @subsection as section, etc. \def\raisesections{\global\advance\secbase by -1} \let\up=\raisesections % original BFox name % @lowersections: treat @chapter as section, @section as subsection, etc. \def\lowersections{\global\advance\secbase by 1} \let\down=\lowersections % original BFox name % we only have subsub. \chardef\maxseclevel = 3 % % A numbered section within an unnumbered changes to unnumbered too. % To achieve this, remember the "biggest" unnum. sec. we are currently in: \chardef\unnlevel = \maxseclevel % % Trace whether the current chapter is an appendix or not: % \chapheadtype is "N" or "A", unnumbered chapters are ignored. \def\chapheadtype{N} % Choose a heading macro % #1 is heading type % #2 is heading level % #3 is text for heading \def\genhead#1#2#3{% % Compute the abs. sec. level: \absseclevel=#2 \advance\absseclevel by \secbase % Make sure \absseclevel doesn't fall outside the range: \ifnum \absseclevel < 0 \absseclevel = 0 \else \ifnum \absseclevel > 3 \absseclevel = 3 \fi \fi % The heading type: \def\headtype{#1}% \if \headtype U% \ifnum \absseclevel < \unnlevel \chardef\unnlevel = \absseclevel \fi \else % Check for appendix sections: \ifnum \absseclevel = 0 \edef\chapheadtype{\headtype}% \else \if \headtype A\if \chapheadtype N% \errmessage{@appendix... within a non-appendix chapter}% \fi\fi \fi % Check for numbered within unnumbered: \ifnum \absseclevel > \unnlevel \def\headtype{U}% \else \chardef\unnlevel = 3 \fi \fi % Now print the heading: \if \headtype U% \ifcase\absseclevel \unnumberedzzz{#3}% \or \unnumberedseczzz{#3}% \or \unnumberedsubseczzz{#3}% \or \unnumberedsubsubseczzz{#3}% \fi \else \if \headtype A% \ifcase\absseclevel \appendixzzz{#3}% \or \appendixsectionzzz{#3}% \or \appendixsubseczzz{#3}% \or \appendixsubsubseczzz{#3}% \fi \else \ifcase\absseclevel \chapterzzz{#3}% \or \seczzz{#3}% \or \numberedsubseczzz{#3}% \or \numberedsubsubseczzz{#3}% \fi \fi \fi \suppressfirstparagraphindent } % an interface: \def\numhead{\genhead N} \def\apphead{\genhead A} \def\unnmhead{\genhead U} % @chapter, @appendix, @unnumbered. Increment top-level counter, reset % all lower-level sectioning counters to zero. % % Also set \chaplevelprefix, which we prepend to @float sequence numbers % (e.g., figures), q.v. By default (before any chapter), that is empty. \let\chaplevelprefix = \empty % \outer\parseargdef\chapter{\numhead0{#1}} % normally numhead0 calls chapterzzz \def\chapterzzz#1{% % section resetting is \global in case the chapter is in a group, such % as an @include file. \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 \global\advance\chapno by 1 % % Used for \float. \gdef\chaplevelprefix{\the\chapno.}% \resetallfloatnos % % \putwordChapter can contain complex things in translations. \toks0=\expandafter{\putwordChapter}% \message{\the\toks0 \space \the\chapno}% % % Write the actual heading. \chapmacro{#1}{Ynumbered}{\the\chapno}% % % So @section and the like are numbered underneath this chapter. \global\let\section = \numberedsec \global\let\subsection = \numberedsubsec \global\let\subsubsection = \numberedsubsubsec } \outer\parseargdef\appendix{\apphead0{#1}} % normally calls appendixzzz % \def\appendixzzz#1{% \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 \global\advance\appendixno by 1 \gdef\chaplevelprefix{\appendixletter.}% \resetallfloatnos % % \putwordAppendix can contain complex things in translations. \toks0=\expandafter{\putwordAppendix}% \message{\the\toks0 \space \appendixletter}% % \chapmacro{#1}{Yappendix}{\appendixletter}% % \global\let\section = \appendixsec \global\let\subsection = \appendixsubsec \global\let\subsubsection = \appendixsubsubsec } % normally unnmhead0 calls unnumberedzzz: \outer\parseargdef\unnumbered{\unnmhead0{#1}} \def\unnumberedzzz#1{% \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 \global\advance\unnumberedno by 1 % % Since an unnumbered has no number, no prefix for figures. \global\let\chaplevelprefix = \empty \resetallfloatnos % % This used to be simply \message{#1}, but TeX fully expands the % argument to \message. Therefore, if #1 contained @-commands, TeX % expanded them. For example, in `@unnumbered The @cite{Book}', TeX % expanded @cite (which turns out to cause errors because \cite is meant % to be executed, not expanded). % % Anyway, we don't want the fully-expanded definition of @cite to appear % as a result of the \message, we just want `@cite' itself. We use % \the to achieve this: TeX expands \the only once, % simply yielding the contents of . (We also do this for % the toc entries.) \toks0 = {#1}% \message{(\the\toks0)}% % \chapmacro{#1}{Ynothing}{\the\unnumberedno}% % \global\let\section = \unnumberedsec \global\let\subsection = \unnumberedsubsec \global\let\subsubsection = \unnumberedsubsubsec } % @centerchap is like @unnumbered, but the heading is centered. \outer\parseargdef\centerchap{% % Well, we could do the following in a group, but that would break % an assumption that \chapmacro is called at the outermost level. % Thus we are safer this way: --kasal, 24feb04 \let\centerparametersmaybe = \centerparameters \unnmhead0{#1}% \let\centerparametersmaybe = \relax } % @top is like @unnumbered. \let\top\unnumbered % Sections. % \outer\parseargdef\numberedsec{\numhead1{#1}} % normally calls seczzz \def\seczzz#1{% \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 \sectionheading{#1}{sec}{Ynumbered}{\the\chapno.\the\secno}% } % normally calls appendixsectionzzz: \outer\parseargdef\appendixsection{\apphead1{#1}} \def\appendixsectionzzz#1{% \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 \sectionheading{#1}{sec}{Yappendix}{\appendixletter.\the\secno}% } \let\appendixsec\appendixsection % normally calls unnumberedseczzz: \outer\parseargdef\unnumberedsec{\unnmhead1{#1}} \def\unnumberedseczzz#1{% \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 \sectionheading{#1}{sec}{Ynothing}{\the\unnumberedno.\the\secno}% } % Subsections. % % normally calls numberedsubseczzz: \outer\parseargdef\numberedsubsec{\numhead2{#1}} \def\numberedsubseczzz#1{% \global\subsubsecno=0 \global\advance\subsecno by 1 \sectionheading{#1}{subsec}{Ynumbered}{\the\chapno.\the\secno.\the\subsecno}% } % normally calls appendixsubseczzz: \outer\parseargdef\appendixsubsec{\apphead2{#1}} \def\appendixsubseczzz#1{% \global\subsubsecno=0 \global\advance\subsecno by 1 \sectionheading{#1}{subsec}{Yappendix}% {\appendixletter.\the\secno.\the\subsecno}% } % normally calls unnumberedsubseczzz: \outer\parseargdef\unnumberedsubsec{\unnmhead2{#1}} \def\unnumberedsubseczzz#1{% \global\subsubsecno=0 \global\advance\subsecno by 1 \sectionheading{#1}{subsec}{Ynothing}% {\the\unnumberedno.\the\secno.\the\subsecno}% } % Subsubsections. % % normally numberedsubsubseczzz: \outer\parseargdef\numberedsubsubsec{\numhead3{#1}} \def\numberedsubsubseczzz#1{% \global\advance\subsubsecno by 1 \sectionheading{#1}{subsubsec}{Ynumbered}% {\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno}% } % normally appendixsubsubseczzz: \outer\parseargdef\appendixsubsubsec{\apphead3{#1}} \def\appendixsubsubseczzz#1{% \global\advance\subsubsecno by 1 \sectionheading{#1}{subsubsec}{Yappendix}% {\appendixletter.\the\secno.\the\subsecno.\the\subsubsecno}% } % normally unnumberedsubsubseczzz: \outer\parseargdef\unnumberedsubsubsec{\unnmhead3{#1}} \def\unnumberedsubsubseczzz#1{% \global\advance\subsubsecno by 1 \sectionheading{#1}{subsubsec}{Ynothing}% {\the\unnumberedno.\the\secno.\the\subsecno.\the\subsubsecno}% } % These macros control what the section commands do, according % to what kind of chapter we are in (ordinary, appendix, or unnumbered). % Define them by default for a numbered chapter. \let\section = \numberedsec \let\subsection = \numberedsubsec \let\subsubsection = \numberedsubsubsec % Define @majorheading, @heading and @subheading \def\majorheading{% {\advance\chapheadingskip by 10pt \chapbreak }% \parsearg\chapheadingzzz } \def\chapheading{\chapbreak \parsearg\chapheadingzzz} \def\chapheadingzzz#1{% \vbox{\chapfonts \raggedtitlesettings #1\par}% \nobreak\bigskip \nobreak \suppressfirstparagraphindent } % @heading, @subheading, @subsubheading. \parseargdef\heading{\sectionheading{#1}{sec}{Yomitfromtoc}{} \suppressfirstparagraphindent} \parseargdef\subheading{\sectionheading{#1}{subsec}{Yomitfromtoc}{} \suppressfirstparagraphindent} \parseargdef\subsubheading{\sectionheading{#1}{subsubsec}{Yomitfromtoc}{} \suppressfirstparagraphindent} % These macros generate a chapter, section, etc. heading only % (including whitespace, linebreaking, etc. around it), % given all the information in convenient, parsed form. % Args are the skip and penalty (usually negative) \def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi} % Parameter controlling skip before chapter headings (if needed) \newskip\chapheadingskip % Define plain chapter starts, and page on/off switching for it. \def\chapbreak{\dobreak \chapheadingskip {-4000}} \def\chappager{\par\vfill\supereject} % Because \domark is called before \chapoddpage, the filler page will % get the headings for the next chapter, which is wrong. But we don't % care -- we just disable all headings on the filler page. \def\chapoddpage{% \chappager \ifodd\pageno \else \begingroup \headingsoff \null \chappager \endgroup \fi } \def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname} \def\CHAPPAGoff{% \global\let\contentsalignmacro = \chappager \global\let\pchapsepmacro=\chapbreak \global\let\pagealignmacro=\chappager} \def\CHAPPAGon{% \global\let\contentsalignmacro = \chappager \global\let\pchapsepmacro=\chappager \global\let\pagealignmacro=\chappager \global\def\HEADINGSon{\HEADINGSsingle}} \def\CHAPPAGodd{% \global\let\contentsalignmacro = \chapoddpage \global\let\pchapsepmacro=\chapoddpage \global\let\pagealignmacro=\chapoddpage \global\def\HEADINGSon{\HEADINGSdouble}} \CHAPPAGon % Chapter opening. % % #1 is the text, #2 is the section type (Ynumbered, Ynothing, % Yappendix, Yomitfromtoc), #3 the chapter number. % % To test against our argument. \def\Ynothingkeyword{Ynothing} \def\Yomitfromtockeyword{Yomitfromtoc} \def\Yappendixkeyword{Yappendix} % \def\chapmacro#1#2#3{% % Insert the first mark before the heading break (see notes for \domark). \let\prevchapterdefs=\lastchapterdefs \let\prevsectiondefs=\lastsectiondefs \gdef\lastsectiondefs{\gdef\thissectionname{}\gdef\thissectionnum{}% \gdef\thissection{}}% % \def\temptype{#2}% \ifx\temptype\Ynothingkeyword \gdef\lastchapterdefs{\gdef\thischaptername{#1}\gdef\thischapternum{}% \gdef\thischapter{\thischaptername}}% \else\ifx\temptype\Yomitfromtockeyword \gdef\lastchapterdefs{\gdef\thischaptername{#1}\gdef\thischapternum{}% \gdef\thischapter{}}% \else\ifx\temptype\Yappendixkeyword \toks0={#1}% \xdef\lastchapterdefs{% \gdef\noexpand\thischaptername{\the\toks0}% \gdef\noexpand\thischapternum{\appendixletter}% % \noexpand\putwordAppendix avoids expanding indigestible % commands in some of the translations. \gdef\noexpand\thischapter{\noexpand\putwordAppendix{} \noexpand\thischapternum: \noexpand\thischaptername}% }% \else \toks0={#1}% \xdef\lastchapterdefs{% \gdef\noexpand\thischaptername{\the\toks0}% \gdef\noexpand\thischapternum{\the\chapno}% % \noexpand\putwordChapter avoids expanding indigestible % commands in some of the translations. \gdef\noexpand\thischapter{\noexpand\putwordChapter{} \noexpand\thischapternum: \noexpand\thischaptername}% }% \fi\fi\fi % % Output the mark. Pass it through \safewhatsit, to take care of % the preceding space. \safewhatsit\domark % % Insert the chapter heading break. \pchapsepmacro % % Now the second mark, after the heading break. No break points % between here and the heading. \let\prevchapterdefs=\lastchapterdefs \let\prevsectiondefs=\lastsectiondefs \domark % {% \chapfonts \rmisbold % % Have to define \lastsection before calling \donoderef, because the % xref code eventually uses it. On the other hand, it has to be called % after \pchapsepmacro, or the headline will change too soon. \gdef\lastsection{#1}% % % Only insert the separating space if we have a chapter/appendix % number, and don't print the unnumbered ``number''. \ifx\temptype\Ynothingkeyword \setbox0 = \hbox{}% \def\toctype{unnchap}% \else\ifx\temptype\Yomitfromtockeyword \setbox0 = \hbox{}% contents like unnumbered, but no toc entry \def\toctype{omit}% \else\ifx\temptype\Yappendixkeyword \setbox0 = \hbox{\putwordAppendix{} #3\enspace}% \def\toctype{app}% \else \setbox0 = \hbox{#3\enspace}% \def\toctype{numchap}% \fi\fi\fi % % Write the toc entry for this chapter. Must come before the % \donoderef, because we include the current node name in the toc % entry, and \donoderef resets it to empty. \writetocentry{\toctype}{#1}{#3}% % % For pdftex, we have to write out the node definition (aka, make % the pdfdest) after any page break, but before the actual text has % been typeset. If the destination for the pdf outline is after the % text, then jumping from the outline may wind up with the text not % being visible, for instance under high magnification. \donoderef{#2}% % % Typeset the actual heading. \nobreak % Avoid page breaks at the interline glue. \vbox{\raggedtitlesettings \hangindent=\wd0 \centerparametersmaybe \unhbox0 #1\par}% }% \nobreak\bigskip % no page break after a chapter title \nobreak } % @centerchap -- centered and unnumbered. \let\centerparametersmaybe = \relax \def\centerparameters{% \advance\rightskip by 3\rightskip \leftskip = \rightskip \parfillskip = 0pt } % I don't think this chapter style is supported any more, so I'm not % updating it with the new noderef stuff. We'll see. --karl, 11aug03. % \def\setchapterstyle #1 {\csname CHAPF#1\endcsname} % \def\unnchfopen #1{% \chapoddpage \vbox{\chapfonts \raggedtitlesettings #1\par}% \nobreak\bigskip\nobreak } \def\chfopen #1#2{\chapoddpage {\chapfonts \vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}% \par\penalty 5000 % } \def\centerchfopen #1{% \chapoddpage \vbox{\chapfonts \raggedtitlesettings \hfill #1\hfill}% \nobreak\bigskip \nobreak } \def\CHAPFopen{% \global\let\chapmacro=\chfopen \global\let\centerchapmacro=\centerchfopen} % Section titles. These macros combine the section number parts and % call the generic \sectionheading to do the printing. % \newskip\secheadingskip \def\secheadingbreak{\dobreak \secheadingskip{-1000}} % Subsection titles. \newskip\subsecheadingskip \def\subsecheadingbreak{\dobreak \subsecheadingskip{-500}} % Subsubsection titles. \def\subsubsecheadingskip{\subsecheadingskip} \def\subsubsecheadingbreak{\subsecheadingbreak} % Print any size, any type, section title. % % #1 is the text, #2 is the section level (sec/subsec/subsubsec), #3 is % the section type for xrefs (Ynumbered, Ynothing, Yappendix), #4 is the % section number. % \def\seckeyword{sec} % \def\sectionheading#1#2#3#4{% {% \checkenv{}% should not be in an environment. % % Switch to the right set of fonts. \csname #2fonts\endcsname \rmisbold % \def\sectionlevel{#2}% \def\temptype{#3}% % % Insert first mark before the heading break (see notes for \domark). \let\prevsectiondefs=\lastsectiondefs \ifx\temptype\Ynothingkeyword \ifx\sectionlevel\seckeyword \gdef\lastsectiondefs{\gdef\thissectionname{#1}\gdef\thissectionnum{}% \gdef\thissection{\thissectionname}}% \fi \else\ifx\temptype\Yomitfromtockeyword % Don't redefine \thissection. \else\ifx\temptype\Yappendixkeyword \ifx\sectionlevel\seckeyword \toks0={#1}% \xdef\lastsectiondefs{% \gdef\noexpand\thissectionname{\the\toks0}% \gdef\noexpand\thissectionnum{#4}% % \noexpand\putwordSection avoids expanding indigestible % commands in some of the translations. \gdef\noexpand\thissection{\noexpand\putwordSection{} \noexpand\thissectionnum: \noexpand\thissectionname}% }% \fi \else \ifx\sectionlevel\seckeyword \toks0={#1}% \xdef\lastsectiondefs{% \gdef\noexpand\thissectionname{\the\toks0}% \gdef\noexpand\thissectionnum{#4}% % \noexpand\putwordSection avoids expanding indigestible % commands in some of the translations. \gdef\noexpand\thissection{\noexpand\putwordSection{} \noexpand\thissectionnum: \noexpand\thissectionname}% }% \fi \fi\fi\fi % % Go into vertical mode. Usually we'll already be there, but we % don't want the following whatsit to end up in a preceding paragraph % if the document didn't happen to have a blank line. \par % % Output the mark. Pass it through \safewhatsit, to take care of % the preceding space. \safewhatsit\domark % % Insert space above the heading. \csname #2headingbreak\endcsname % % Now the second mark, after the heading break. No break points % between here and the heading. \let\prevsectiondefs=\lastsectiondefs \domark % % Only insert the space after the number if we have a section number. \ifx\temptype\Ynothingkeyword \setbox0 = \hbox{}% \def\toctype{unn}% \gdef\lastsection{#1}% \else\ifx\temptype\Yomitfromtockeyword % for @headings -- no section number, don't include in toc, % and don't redefine \lastsection. \setbox0 = \hbox{}% \def\toctype{omit}% \let\sectionlevel=\empty \else\ifx\temptype\Yappendixkeyword \setbox0 = \hbox{#4\enspace}% \def\toctype{app}% \gdef\lastsection{#1}% \else \setbox0 = \hbox{#4\enspace}% \def\toctype{num}% \gdef\lastsection{#1}% \fi\fi\fi % % Write the toc entry (before \donoderef). See comments in \chapmacro. \writetocentry{\toctype\sectionlevel}{#1}{#4}% % % Write the node reference (= pdf destination for pdftex). % Again, see comments in \chapmacro. \donoderef{#3}% % % Interline glue will be inserted when the vbox is completed. % That glue will be a valid breakpoint for the page, since it'll be % preceded by a whatsit (usually from the \donoderef, or from the % \writetocentry if there was no node). We don't want to allow that % break, since then the whatsits could end up on page n while the % section is on page n+1, thus toc/etc. are wrong. Debian bug 276000. \nobreak % % Output the actual section heading. \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \ptexraggedright \hangindent=\wd0 % zero if no section number \unhbox0 #1}% }% % Add extra space after the heading -- half of whatever came above it. % Don't allow stretch, though. \kern .5 \csname #2headingskip\endcsname % % Do not let the kern be a potential breakpoint, as it would be if it % was followed by glue. \nobreak % % We'll almost certainly start a paragraph next, so don't let that % glue accumulate. (Not a breakpoint because it's preceded by a % discardable item.) However, when a paragraph is not started next % (\startdefun, \cartouche, \center, etc.), this needs to be wiped out % or the negative glue will cause weirdly wrong output, typically % obscuring the section heading with something else. \vskip-\parskip % % This is so the last item on the main vertical list is a known % \penalty > 10000, so \startdefun, etc., can recognize the situation % and do the needful. \penalty 10001 } \message{toc,} % Table of contents. \newwrite\tocfile % Write an entry to the toc file, opening it if necessary. % Called from @chapter, etc. % % Example usage: \writetocentry{sec}{Section Name}{\the\chapno.\the\secno} % We append the current node name (if any) and page number as additional % arguments for the \{chap,sec,...}entry macros which will eventually % read this. The node name is used in the pdf outlines as the % destination to jump to. % % We open the .toc file for writing here instead of at @setfilename (or % any other fixed time) so that @contents can be anywhere in the document. % But if #1 is `omit', then we don't do anything. This is used for the % table of contents chapter openings themselves. % \newif\iftocfileopened \def\omitkeyword{omit}% % \def\writetocentry#1#2#3{% \edef\writetoctype{#1}% \ifx\writetoctype\omitkeyword \else \iftocfileopened\else \immediate\openout\tocfile = \jobname.toc \global\tocfileopenedtrue \fi % \iflinks {\atdummies \edef\temp{% \write\tocfile{@#1entry{#2}{#3}{\lastnode}{\noexpand\folio}}}% \temp }% \fi \fi % % Tell \shipout to create a pdf destination on each page, if we're % writing pdf. These are used in the table of contents. We can't % just write one on every page because the title pages are numbered % 1 and 2 (the page numbers aren't printed), and so are the first % two pages of the document. Thus, we'd have two destinations named % `1', and two named `2'. \ifpdf \global\pdfmakepagedesttrue \fi } % These characters do not print properly in the Computer Modern roman % fonts, so we must take special care. This is more or less redundant % with the Texinfo input format setup at the end of this file. % \def\activecatcodes{% \catcode`\"=\active \catcode`\$=\active \catcode`\<=\active \catcode`\>=\active \catcode`\\=\active \catcode`\^=\active \catcode`\_=\active \catcode`\|=\active \catcode`\~=\active } % Read the toc file, which is essentially Texinfo input. \def\readtocfile{% \setupdatafile \activecatcodes \input \tocreadfilename } \newskip\contentsrightmargin \contentsrightmargin=1in \newcount\savepageno \newcount\lastnegativepageno \lastnegativepageno = -1 % Prepare to read what we've written to \tocfile. % \def\startcontents#1{% % If @setchapternewpage on, and @headings double, the contents should % start on an odd page, unlike chapters. Thus, we maintain % \contentsalignmacro in parallel with \pagealignmacro. % From: Torbjorn Granlund \contentsalignmacro \immediate\closeout\tocfile % % Don't need to put `Contents' or `Short Contents' in the headline. % It is abundantly clear what they are. \chapmacro{#1}{Yomitfromtoc}{}% % \savepageno = \pageno \begingroup % Set up to handle contents files properly. \raggedbottom % Worry more about breakpoints than the bottom. \advance\hsize by -\contentsrightmargin % Don't use the full line length. % % Roman numerals for page numbers. \ifnum \pageno>0 \global\pageno = \lastnegativepageno \fi } % redefined for the two-volume lispref. We always output on % \jobname.toc even if this is redefined. % \def\tocreadfilename{\jobname.toc} % Normal (long) toc. % \def\contents{% \startcontents{\putwordTOC}% \openin 1 \tocreadfilename\space \ifeof 1 \else \readtocfile \fi \vfill \eject \contentsalignmacro % in case @setchapternewpage odd is in effect \ifeof 1 \else \pdfmakeoutlines \fi \closein 1 \endgroup \lastnegativepageno = \pageno \global\pageno = \savepageno } % And just the chapters. \def\summarycontents{% \startcontents{\putwordShortTOC}% % \let\partentry = \shortpartentry \let\numchapentry = \shortchapentry \let\appentry = \shortchapentry \let\unnchapentry = \shortunnchapentry % We want a true roman here for the page numbers. \secfonts \let\rm=\shortcontrm \let\bf=\shortcontbf \let\sl=\shortcontsl \let\tt=\shortconttt \rm \hyphenpenalty = 10000 \advance\baselineskip by 1pt % Open it up a little. \def\numsecentry##1##2##3##4{} \let\appsecentry = \numsecentry \let\unnsecentry = \numsecentry \let\numsubsecentry = \numsecentry \let\appsubsecentry = \numsecentry \let\unnsubsecentry = \numsecentry \let\numsubsubsecentry = \numsecentry \let\appsubsubsecentry = \numsecentry \let\unnsubsubsecentry = \numsecentry \openin 1 \tocreadfilename\space \ifeof 1 \else \readtocfile \fi \closein 1 \vfill \eject \contentsalignmacro % in case @setchapternewpage odd is in effect \endgroup \lastnegativepageno = \pageno \global\pageno = \savepageno } \let\shortcontents = \summarycontents % Typeset the label for a chapter or appendix for the short contents. % The arg is, e.g., `A' for an appendix, or `3' for a chapter. % \def\shortchaplabel#1{% % This space should be enough, since a single number is .5em, and the % widest letter (M) is 1em, at least in the Computer Modern fonts. % But use \hss just in case. % (This space doesn't include the extra space that gets added after % the label; that gets put in by \shortchapentry above.) % % We'd like to right-justify chapter numbers, but that looks strange % with appendix letters. And right-justifying numbers and % left-justifying letters looks strange when there is less than 10 % chapters. Have to read the whole toc once to know how many chapters % there are before deciding ... \hbox to 1em{#1\hss}% } % These macros generate individual entries in the table of contents. % The first argument is the chapter or section name. % The last argument is the page number. % The arguments in between are the chapter number, section number, ... % Parts, in the main contents. Replace the part number, which doesn't % exist, with an empty box. Let's hope all the numbers have the same width. % Also ignore the page number, which is conventionally not printed. \def\numeralbox{\setbox0=\hbox{8}\hbox to \wd0{\hfil}} \def\partentry#1#2#3#4{\dochapentry{\numeralbox\labelspace#1}{}} % % Parts, in the short toc. \def\shortpartentry#1#2#3#4{% \penalty-300 \vskip.5\baselineskip plus.15\baselineskip minus.1\baselineskip \shortchapentry{{\bf #1}}{\numeralbox}{}{}% } % Chapters, in the main contents. \def\numchapentry#1#2#3#4{\dochapentry{#2\labelspace#1}{#4}} % % Chapters, in the short toc. % See comments in \dochapentry re vbox and related settings. \def\shortchapentry#1#2#3#4{% \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno\bgroup#4\egroup}% } % Appendices, in the main contents. % Need the word Appendix, and a fixed-size box. % \def\appendixbox#1{% % We use M since it's probably the widest letter. \setbox0 = \hbox{\putwordAppendix{} M}% \hbox to \wd0{\putwordAppendix{} #1\hss}} % \def\appentry#1#2#3#4{\dochapentry{\appendixbox{#2}\labelspace#1}{#4}} % Unnumbered chapters. \def\unnchapentry#1#2#3#4{\dochapentry{#1}{#4}} \def\shortunnchapentry#1#2#3#4{\tocentry{#1}{\doshortpageno\bgroup#4\egroup}} % Sections. \def\numsecentry#1#2#3#4{\dosecentry{#2\labelspace#1}{#4}} \let\appsecentry=\numsecentry \def\unnsecentry#1#2#3#4{\dosecentry{#1}{#4}} % Subsections. \def\numsubsecentry#1#2#3#4{\dosubsecentry{#2\labelspace#1}{#4}} \let\appsubsecentry=\numsubsecentry \def\unnsubsecentry#1#2#3#4{\dosubsecentry{#1}{#4}} % And subsubsections. \def\numsubsubsecentry#1#2#3#4{\dosubsubsecentry{#2\labelspace#1}{#4}} \let\appsubsubsecentry=\numsubsubsecentry \def\unnsubsubsecentry#1#2#3#4{\dosubsubsecentry{#1}{#4}} % This parameter controls the indentation of the various levels. % Same as \defaultparindent. \newdimen\tocindent \tocindent = 15pt % Now for the actual typesetting. In all these, #1 is the text and #2 is the % page number. % % If the toc has to be broken over pages, we want it to be at chapters % if at all possible; hence the \penalty. \def\dochapentry#1#2{% \penalty-300 \vskip1\baselineskip plus.33\baselineskip minus.25\baselineskip \begingroup \chapentryfonts \tocentry{#1}{\dopageno\bgroup#2\egroup}% \endgroup \nobreak\vskip .25\baselineskip plus.1\baselineskip } \def\dosecentry#1#2{\begingroup \secentryfonts \leftskip=\tocindent \tocentry{#1}{\dopageno\bgroup#2\egroup}% \endgroup} \def\dosubsecentry#1#2{\begingroup \subsecentryfonts \leftskip=2\tocindent \tocentry{#1}{\dopageno\bgroup#2\egroup}% \endgroup} \def\dosubsubsecentry#1#2{\begingroup \subsubsecentryfonts \leftskip=3\tocindent \tocentry{#1}{\dopageno\bgroup#2\egroup}% \endgroup} % We use the same \entry macro as for the index entries. \let\tocentry = \entry % Space between chapter (or whatever) number and the title. \def\labelspace{\hskip1em \relax} \def\dopageno#1{{\rm #1}} \def\doshortpageno#1{{\rm #1}} \def\chapentryfonts{\secfonts \rm} \def\secentryfonts{\textfonts} \def\subsecentryfonts{\textfonts} \def\subsubsecentryfonts{\textfonts} \message{environments,} % @foo ... @end foo. % @tex ... @end tex escapes into raw TeX temporarily. % One exception: @ is still an escape character, so that @end tex works. % But \@ or @@ will get a plain @ character. \envdef\tex{% \setupmarkupstyle{tex}% \catcode `\\=0 \catcode `\{=1 \catcode `\}=2 \catcode `\$=3 \catcode `\&=4 \catcode `\#=6 \catcode `\^=7 \catcode `\_=8 \catcode `\~=\active \let~=\tie \catcode `\%=14 \catcode `\+=\other \catcode `\"=\other \catcode `\|=\other \catcode `\<=\other \catcode `\>=\other \catcode`\`=\other \catcode`\'=\other \escapechar=`\\ % % ' is active in math mode (mathcode"8000). So reset it, and all our % other math active characters (just in case), to plain's definitions. \mathactive % \let\b=\ptexb \let\bullet=\ptexbullet \let\c=\ptexc \let\,=\ptexcomma \let\.=\ptexdot \let\dots=\ptexdots \let\equiv=\ptexequiv \let\!=\ptexexclam \let\i=\ptexi \let\indent=\ptexindent \let\noindent=\ptexnoindent \let\{=\ptexlbrace \let\+=\tabalign \let\}=\ptexrbrace \let\/=\ptexslash \let\*=\ptexstar \let\t=\ptext \expandafter \let\csname top\endcsname=\ptextop % outer \let\frenchspacing=\plainfrenchspacing % \def\endldots{\mathinner{\ldots\ldots\ldots\ldots}}% \def\enddots{\relax\ifmmode\endldots\else$\mathsurround=0pt \endldots\,$\fi}% \def\@{@}% } % There is no need to define \Etex. % Define @lisp ... @end lisp. % @lisp environment forms a group so it can rebind things, % including the definition of @end lisp (which normally is erroneous). % Amount to narrow the margins by for @lisp. \newskip\lispnarrowing \lispnarrowing=0.4in % This is the definition that ^^M gets inside @lisp, @example, and other % such environments. \null is better than a space, since it doesn't % have any width. \def\lisppar{\null\endgraf} % This space is always present above and below environments. \newskip\envskipamount \envskipamount = 0pt % Make spacing and below environment symmetrical. We use \parskip here % to help in doing that, since in @example-like environments \parskip % is reset to zero; thus the \afterenvbreak inserts no space -- but the % start of the next paragraph will insert \parskip. % \def\aboveenvbreak{{% % =10000 instead of <10000 because of a special case in \itemzzz and % \sectionheading, q.v. \ifnum \lastpenalty=10000 \else \advance\envskipamount by \parskip \endgraf \ifdim\lastskip<\envskipamount \removelastskip % it's not a good place to break if the last penalty was \nobreak % or better ... \ifnum\lastpenalty<10000 \penalty-50 \fi \vskip\envskipamount \fi \fi }} \let\afterenvbreak = \aboveenvbreak % \nonarrowing is a flag. If "set", @lisp etc don't narrow margins; it will % also clear it, so that its embedded environments do the narrowing again. \let\nonarrowing=\relax % @cartouche ... @end cartouche: draw rectangle w/rounded corners around % environment contents. \font\circle=lcircle10 \newdimen\circthick \newdimen\cartouter\newdimen\cartinner \newskip\normbskip\newskip\normpskip\newskip\normlskip \circthick=\fontdimen8\circle % \def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth \def\ctr{{\hskip 6pt\circle\char'010}} \def\cbl{{\circle\char'012\hskip -6pt}} \def\cbr{{\hskip 6pt\circle\char'011}} \def\carttop{\hbox to \cartouter{\hskip\lskip \ctl\leaders\hrule height\circthick\hfil\ctr \hskip\rskip}} \def\cartbot{\hbox to \cartouter{\hskip\lskip \cbl\leaders\hrule height\circthick\hfil\cbr \hskip\rskip}} % \newskip\lskip\newskip\rskip \envdef\cartouche{% \ifhmode\par\fi % can't be in the midst of a paragraph. \startsavinginserts \lskip=\leftskip \rskip=\rightskip \leftskip=0pt\rightskip=0pt % we want these *outside*. \cartinner=\hsize \advance\cartinner by-\lskip \advance\cartinner by-\rskip \cartouter=\hsize \advance\cartouter by 18.4pt % allow for 3pt kerns on either % side, and for 6pt waste from % each corner char, and rule thickness \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip % Flag to tell @lisp, etc., not to narrow margin. \let\nonarrowing = t% % % If this cartouche directly follows a sectioning command, we need the % \parskip glue (backspaced over by default) or the cartouche can % collide with the section heading. \ifnum\lastpenalty>10000 \vskip\parskip \penalty\lastpenalty \fi % \vbox\bgroup \baselineskip=0pt\parskip=0pt\lineskip=0pt \carttop \hbox\bgroup \hskip\lskip \vrule\kern3pt \vbox\bgroup \kern3pt \hsize=\cartinner \baselineskip=\normbskip \lineskip=\normlskip \parskip=\normpskip \vskip -\parskip \comment % For explanation, see the end of def\group. } \def\Ecartouche{% \ifhmode\par\fi \kern3pt \egroup \kern3pt\vrule \hskip\rskip \egroup \cartbot \egroup \checkinserts } % This macro is called at the beginning of all the @example variants, % inside a group. \newdimen\nonfillparindent \def\nonfillstart{% \aboveenvbreak \hfuzz = 12pt % Don't be fussy \sepspaces % Make spaces be word-separators rather than space tokens. \let\par = \lisppar % don't ignore blank lines \obeylines % each line of input is a line of output \parskip = 0pt % Turn off paragraph indentation but redefine \indent to emulate % the normal \indent. \nonfillparindent=\parindent \parindent = 0pt \let\indent\nonfillindent % \emergencystretch = 0pt % don't try to avoid overfull boxes \ifx\nonarrowing\relax \advance \leftskip by \lispnarrowing \exdentamount=\lispnarrowing \else \let\nonarrowing = \relax \fi \let\exdent=\nofillexdent } \begingroup \obeyspaces % We want to swallow spaces (but not other tokens) after the fake % @indent in our nonfill-environments, where spaces are normally % active and set to @tie, resulting in them not being ignored after % @indent. \gdef\nonfillindent{\futurelet\temp\nonfillindentcheck}% \gdef\nonfillindentcheck{% \ifx\temp % \expandafter\nonfillindentgobble% \else% \leavevmode\nonfillindentbox% \fi% }% \endgroup \def\nonfillindentgobble#1{\nonfillindent} \def\nonfillindentbox{\hbox to \nonfillparindent{\hss}} % If you want all examples etc. small: @set dispenvsize small. % If you want even small examples the full size: @set dispenvsize nosmall. % This affects the following displayed environments: % @example, @display, @format, @lisp % \def\smallword{small} \def\nosmallword{nosmall} \let\SETdispenvsize\relax \def\setnormaldispenv{% \ifx\SETdispenvsize\smallword % end paragraph for sake of leading, in case document has no blank % line. This is redundant with what happens in \aboveenvbreak, but % we need to do it before changing the fonts, and it's inconvenient % to change the fonts afterward. \ifnum \lastpenalty=10000 \else \endgraf \fi \smallexamplefonts \rm \fi } \def\setsmalldispenv{% \ifx\SETdispenvsize\nosmallword \else \ifnum \lastpenalty=10000 \else \endgraf \fi \smallexamplefonts \rm \fi } % We often define two environments, @foo and @smallfoo. % Let's do it in one command. #1 is the env name, #2 the definition. \def\makedispenvdef#1#2{% \expandafter\envdef\csname#1\endcsname {\setnormaldispenv #2}% \expandafter\envdef\csname small#1\endcsname {\setsmalldispenv #2}% \expandafter\let\csname E#1\endcsname \afterenvbreak \expandafter\let\csname Esmall#1\endcsname \afterenvbreak } % Define two environment synonyms (#1 and #2) for an environment. \def\maketwodispenvdef#1#2#3{% \makedispenvdef{#1}{#3}% \makedispenvdef{#2}{#3}% } % % @lisp: indented, narrowed, typewriter font; % @example: same as @lisp. % % @smallexample and @smalllisp: use smaller fonts. % Originally contributed by Pavel@xerox. % \maketwodispenvdef{lisp}{example}{% \nonfillstart \tt\setupmarkupstyle{example}% \let\kbdfont = \kbdexamplefont % Allow @kbd to do something special. \gobble % eat return } % @display/@smalldisplay: same as @lisp except keep current font. % \makedispenvdef{display}{% \nonfillstart \gobble } % @format/@smallformat: same as @display except don't narrow margins. % \makedispenvdef{format}{% \let\nonarrowing = t% \nonfillstart \gobble } % @flushleft: same as @format, but doesn't obey \SETdispenvsize. \envdef\flushleft{% \let\nonarrowing = t% \nonfillstart \gobble } \let\Eflushleft = \afterenvbreak % @flushright. % \envdef\flushright{% \let\nonarrowing = t% \nonfillstart \advance\leftskip by 0pt plus 1fill\relax \gobble } \let\Eflushright = \afterenvbreak % @raggedright does more-or-less normal line breaking but no right % justification. From plain.tex. \envdef\raggedright{% \rightskip0pt plus2em \spaceskip.3333em \xspaceskip.5em\relax } \let\Eraggedright\par \envdef\raggedleft{% \parindent=0pt \leftskip0pt plus2em \spaceskip.3333em \xspaceskip.5em \parfillskip=0pt \hbadness=10000 % Last line will usually be underfull, so turn off % badness reporting. } \let\Eraggedleft\par \envdef\raggedcenter{% \parindent=0pt \rightskip0pt plus1em \leftskip0pt plus1em \spaceskip.3333em \xspaceskip.5em \parfillskip=0pt \hbadness=10000 % Last line will usually be underfull, so turn off % badness reporting. } \let\Eraggedcenter\par % @quotation does normal linebreaking (hence we can't use \nonfillstart) % and narrows the margins. We keep \parskip nonzero in general, since % we're doing normal filling. So, when using \aboveenvbreak and % \afterenvbreak, temporarily make \parskip 0. % \makedispenvdef{quotation}{\quotationstart} % \def\quotationstart{% \indentedblockstart % same as \indentedblock, but increase right margin too. \ifx\nonarrowing\relax \advance\rightskip by \lispnarrowing \fi \parsearg\quotationlabel } % We have retained a nonzero parskip for the environment, since we're % doing normal filling. % \def\Equotation{% \par \ifx\quotationauthor\thisisundefined\else % indent a bit. \leftline{\kern 2\leftskip \sl ---\quotationauthor}% \fi {\parskip=0pt \afterenvbreak}% } \def\Esmallquotation{\Equotation} % If we're given an argument, typeset it in bold with a colon after. \def\quotationlabel#1{% \def\temp{#1}% \ifx\temp\empty \else {\bf #1: }% \fi } % @indentedblock is like @quotation, but indents only on the left and % has no optional argument. % \makedispenvdef{indentedblock}{\indentedblockstart} % \def\indentedblockstart{% {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip \parindent=0pt % % @cartouche defines \nonarrowing to inhibit narrowing at next level down. \ifx\nonarrowing\relax \advance\leftskip by \lispnarrowing \exdentamount = \lispnarrowing \else \let\nonarrowing = \relax \fi } % Keep a nonzero parskip for the environment, since we're doing normal filling. % \def\Eindentedblock{% \par {\parskip=0pt \afterenvbreak}% } \def\Esmallindentedblock{\Eindentedblock} % LaTeX-like @verbatim...@end verbatim and @verb{...} % If we want to allow any as delimiter, % we need the curly braces so that makeinfo sees the @verb command, eg: % `@verbx...x' would look like the '@verbx' command. --janneke@gnu.org % % [Knuth]: Donald Ervin Knuth, 1996. The TeXbook. % % [Knuth] p.344; only we need to do the other characters Texinfo sets % active too. Otherwise, they get lost as the first character on a % verbatim line. \def\dospecials{% \do\ \do\\\do\{\do\}\do\$\do\&% \do\#\do\^\do\^^K\do\_\do\^^A\do\%\do\~% \do\<\do\>\do\|\do\@\do+\do\"% % Don't do the quotes -- if we do, @set txicodequoteundirected and % @set txicodequotebacktick will not have effect on @verb and % @verbatim, and ?` and !` ligatures won't get disabled. %\do\`\do\'% } % % [Knuth] p. 380 \def\uncatcodespecials{% \def\do##1{\catcode`##1=\other}\dospecials} % % Setup for the @verb command. % % Eight spaces for a tab \begingroup \catcode`\^^I=\active \gdef\tabeightspaces{\catcode`\^^I=\active\def^^I{\ \ \ \ \ \ \ \ }} \endgroup % \def\setupverb{% \tt % easiest (and conventionally used) font for verbatim \def\par{\leavevmode\endgraf}% \setupmarkupstyle{verb}% \tabeightspaces % Respect line breaks, % print special symbols as themselves, and % make each space count % must do in this order: \obeylines \uncatcodespecials \sepspaces } % Setup for the @verbatim environment % % Real tab expansion. \newdimen\tabw \setbox0=\hbox{\tt\space} \tabw=8\wd0 % tab amount % % We typeset each line of the verbatim in an \hbox, so we can handle % tabs. The \global is in case the verbatim line starts with an accent, % or some other command that starts with a begin-group. Otherwise, the % entire \verbbox would disappear at the corresponding end-group, before % it is typeset. Meanwhile, we can't have nested verbatim commands % (can we?), so the \global won't be overwriting itself. \newbox\verbbox \def\starttabbox{\global\setbox\verbbox=\hbox\bgroup} % \begingroup \catcode`\^^I=\active \gdef\tabexpand{% \catcode`\^^I=\active \def^^I{\leavevmode\egroup \dimen\verbbox=\wd\verbbox % the width so far, or since the previous tab \divide\dimen\verbbox by\tabw \multiply\dimen\verbbox by\tabw % compute previous multiple of \tabw \advance\dimen\verbbox by\tabw % advance to next multiple of \tabw \wd\verbbox=\dimen\verbbox \box\verbbox \starttabbox }% } \endgroup % start the verbatim environment. \def\setupverbatim{% \let\nonarrowing = t% \nonfillstart \tt % easiest (and conventionally used) font for verbatim % The \leavevmode here is for blank lines. Otherwise, we would % never \starttabox and the \egroup would end verbatim mode. \def\par{\leavevmode\egroup\box\verbbox\endgraf}% \tabexpand \setupmarkupstyle{verbatim}% % Respect line breaks, % print special symbols as themselves, and % make each space count. % Must do in this order: \obeylines \uncatcodespecials \sepspaces \everypar{\starttabbox}% } % Do the @verb magic: verbatim text is quoted by unique % delimiter characters. Before first delimiter expect a % right brace, after last delimiter expect closing brace: % % \def\doverb'{'#1'}'{#1} % % [Knuth] p. 382; only eat outer {} \begingroup \catcode`[=1\catcode`]=2\catcode`\{=\other\catcode`\}=\other \gdef\doverb{#1[\def\next##1#1}[##1\endgroup]\next] \endgroup % \def\verb{\begingroup\setupverb\doverb} % % % Do the @verbatim magic: define the macro \doverbatim so that % the (first) argument ends when '@end verbatim' is reached, ie: % % \def\doverbatim#1@end verbatim{#1} % % For Texinfo it's a lot easier than for LaTeX, % because texinfo's \verbatim doesn't stop at '\end{verbatim}': % we need not redefine '\', '{' and '}'. % % Inspired by LaTeX's verbatim command set [latex.ltx] % \begingroup \catcode`\ =\active \obeylines % % ignore everything up to the first ^^M, that's the newline at the end % of the @verbatim input line itself. Otherwise we get an extra blank % line in the output. \xdef\doverbatim#1^^M#2@end verbatim{#2\noexpand\end\gobble verbatim}% % We really want {...\end verbatim} in the body of the macro, but % without the active space; thus we have to use \xdef and \gobble. \endgroup % \envdef\verbatim{% \setupverbatim\doverbatim } \let\Everbatim = \afterenvbreak % @verbatiminclude FILE - insert text of file in verbatim environment. % \def\verbatiminclude{\parseargusing\filenamecatcodes\doverbatiminclude} % \def\doverbatiminclude#1{% {% \makevalueexpandable \setupverbatim \indexnofonts % Allow `@@' and other weird things in file names. \wlog{texinfo.tex: doing @verbatiminclude of #1^^J}% \input #1 \afterenvbreak }% } % @copying ... @end copying. % Save the text away for @insertcopying later. % % We save the uninterpreted tokens, rather than creating a box. % Saving the text in a box would be much easier, but then all the % typesetting commands (@smallbook, font changes, etc.) have to be done % beforehand -- and a) we want @copying to be done first in the source % file; b) letting users define the frontmatter in as flexible order as % possible is very desirable. % \def\copying{\checkenv{}\begingroup\scanargctxt\docopying} \def\docopying#1@end copying{\endgroup\def\copyingtext{#1}} % \def\insertcopying{% \begingroup \parindent = 0pt % paragraph indentation looks wrong on title page \scanexp\copyingtext \endgroup } \message{defuns,} % @defun etc. \newskip\defbodyindent \defbodyindent=.4in \newskip\defargsindent \defargsindent=50pt \newskip\deflastargmargin \deflastargmargin=18pt \newcount\defunpenalty % Start the processing of @deffn: \def\startdefun{% \ifnum\lastpenalty<10000 \medbreak \defunpenalty=10003 % Will keep this @deffn together with the % following @def command, see below. \else % If there are two @def commands in a row, we'll have a \nobreak, % which is there to keep the function description together with its % header. But if there's nothing but headers, we need to allow a % break somewhere. Check specifically for penalty 10002, inserted % by \printdefunline, instead of 10000, since the sectioning % commands also insert a nobreak penalty, and we don't want to allow % a break between a section heading and a defun. % % As a further refinement, we avoid "club" headers by signalling % with penalty of 10003 after the very first @deffn in the % sequence (see above), and penalty of 10002 after any following % @def command. \ifnum\lastpenalty=10002 \penalty2000 \else \defunpenalty=10002 \fi % % Similarly, after a section heading, do not allow a break. % But do insert the glue. \medskip % preceded by discardable penalty, so not a breakpoint \fi % \parindent=0in \advance\leftskip by \defbodyindent \exdentamount=\defbodyindent } \def\dodefunx#1{% % First, check whether we are in the right environment: \checkenv#1% % % As above, allow line break if we have multiple x headers in a row. % It's not a great place, though. \ifnum\lastpenalty=10002 \penalty3000 \else \defunpenalty=10002 \fi % % And now, it's time to reuse the body of the original defun: \expandafter\gobbledefun#1% } \def\gobbledefun#1\startdefun{} % \printdefunline \deffnheader{text} % \def\printdefunline#1#2{% \begingroup % call \deffnheader: #1#2 \endheader % common ending: \interlinepenalty = 10000 \advance\rightskip by 0pt plus 1fil\relax \endgraf \nobreak\vskip -\parskip \penalty\defunpenalty % signal to \startdefun and \dodefunx % Some of the @defun-type tags do not enable magic parentheses, % rendering the following check redundant. But we don't optimize. \checkparencounts \endgroup } \def\Edefun{\endgraf\medbreak} % \makedefun{deffn} creates \deffn, \deffnx and \Edeffn; % the only thing remaining is to define \deffnheader. % \def\makedefun#1{% \expandafter\let\csname E#1\endcsname = \Edefun \edef\temp{\noexpand\domakedefun \makecsname{#1}\makecsname{#1x}\makecsname{#1header}}% \temp } % \domakedefun \deffn \deffnx \deffnheader % % Define \deffn and \deffnx, without parameters. % \deffnheader has to be defined explicitly. % \def\domakedefun#1#2#3{% \envdef#1{% \startdefun \doingtypefnfalse % distinguish typed functions from all else \parseargusing\activeparens{\printdefunline#3}% }% \def#2{\dodefunx#1}% \def#3% } \newif\ifdoingtypefn % doing typed function? \newif\ifrettypeownline % typeset return type on its own line? % @deftypefnnewline on|off says whether the return type of typed functions % are printed on their own line. This affects @deftypefn, @deftypefun, % @deftypeop, and @deftypemethod. % \parseargdef\deftypefnnewline{% \def\temp{#1}% \ifx\temp\onword \expandafter\let\csname SETtxideftypefnnl\endcsname = \empty \else\ifx\temp\offword \expandafter\let\csname SETtxideftypefnnl\endcsname = \relax \else \errhelp = \EMsimple \errmessage{Unknown @txideftypefnnl value `\temp', must be on|off}% \fi\fi } % Untyped functions: % @deffn category name args \makedefun{deffn}{\deffngeneral{}} % @deffn category class name args \makedefun{defop}#1 {\defopon{#1\ \putwordon}} % \defopon {category on}class name args \def\defopon#1#2 {\deffngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} } % \deffngeneral {subind}category name args % \def\deffngeneral#1#2 #3 #4\endheader{% % Remember that \dosubind{fn}{foo}{} is equivalent to \doind{fn}{foo}. \dosubind{fn}{\code{#3}}{#1}% \defname{#2}{}{#3}\magicamp\defunargs{#4\unskip}% } % Typed functions: % @deftypefn category type name args \makedefun{deftypefn}{\deftypefngeneral{}} % @deftypeop category class type name args \makedefun{deftypeop}#1 {\deftypeopon{#1\ \putwordon}} % \deftypeopon {category on}class type name args \def\deftypeopon#1#2 {\deftypefngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} } % \deftypefngeneral {subind}category type name args % \def\deftypefngeneral#1#2 #3 #4 #5\endheader{% \dosubind{fn}{\code{#4}}{#1}% \doingtypefntrue \defname{#2}{#3}{#4}\defunargs{#5\unskip}% } % Typed variables: % @deftypevr category type var args \makedefun{deftypevr}{\deftypecvgeneral{}} % @deftypecv category class type var args \makedefun{deftypecv}#1 {\deftypecvof{#1\ \putwordof}} % \deftypecvof {category of}class type var args \def\deftypecvof#1#2 {\deftypecvgeneral{\putwordof\ \code{#2}}{#1\ \code{#2}} } % \deftypecvgeneral {subind}category type var args % \def\deftypecvgeneral#1#2 #3 #4 #5\endheader{% \dosubind{vr}{\code{#4}}{#1}% \defname{#2}{#3}{#4}\defunargs{#5\unskip}% } % Untyped variables: % @defvr category var args \makedefun{defvr}#1 {\deftypevrheader{#1} {} } % @defcv category class var args \makedefun{defcv}#1 {\defcvof{#1\ \putwordof}} % \defcvof {category of}class var args \def\defcvof#1#2 {\deftypecvof{#1}#2 {} } % Types: % @deftp category name args \makedefun{deftp}#1 #2 #3\endheader{% \doind{tp}{\code{#2}}% \defname{#1}{}{#2}\defunargs{#3\unskip}% } % Remaining @defun-like shortcuts: \makedefun{defun}{\deffnheader{\putwordDeffunc} } \makedefun{defmac}{\deffnheader{\putwordDefmac} } \makedefun{defspec}{\deffnheader{\putwordDefspec} } \makedefun{deftypefun}{\deftypefnheader{\putwordDeffunc} } \makedefun{defvar}{\defvrheader{\putwordDefvar} } \makedefun{defopt}{\defvrheader{\putwordDefopt} } \makedefun{deftypevar}{\deftypevrheader{\putwordDefvar} } \makedefun{defmethod}{\defopon\putwordMethodon} \makedefun{deftypemethod}{\deftypeopon\putwordMethodon} \makedefun{defivar}{\defcvof\putwordInstanceVariableof} \makedefun{deftypeivar}{\deftypecvof\putwordInstanceVariableof} % \defname, which formats the name of the @def (not the args). % #1 is the category, such as "Function". % #2 is the return type, if any. % #3 is the function name. % % We are followed by (but not passed) the arguments, if any. % \def\defname#1#2#3{% \par % Get the values of \leftskip and \rightskip as they were outside the @def... \advance\leftskip by -\defbodyindent % % Determine if we are typesetting the return type of a typed function % on a line by itself. \rettypeownlinefalse \ifdoingtypefn % doing a typed function specifically? % then check user option for putting return type on its own line: \expandafter\ifx\csname SETtxideftypefnnl\endcsname\relax \else \rettypeownlinetrue \fi \fi % % How we'll format the category name. Putting it in brackets helps % distinguish it from the body text that may end up on the next line % just below it. \def\temp{#1}% \setbox0=\hbox{\kern\deflastargmargin \ifx\temp\empty\else [\rm\temp]\fi} % % Figure out line sizes for the paragraph shape. We'll always have at % least two. \tempnum = 2 % % The first line needs space for \box0; but if \rightskip is nonzero, % we need only space for the part of \box0 which exceeds it: \dimen0=\hsize \advance\dimen0 by -\wd0 \advance\dimen0 by \rightskip % % If doing a return type on its own line, we'll have another line. \ifrettypeownline \advance\tempnum by 1 \def\maybeshapeline{0in \hsize}% \else \def\maybeshapeline{}% \fi % % The continuations: \dimen2=\hsize \advance\dimen2 by -\defargsindent % % The final paragraph shape: \parshape \tempnum 0in \dimen0 \maybeshapeline \defargsindent \dimen2 % % Put the category name at the right margin. \noindent \hbox to 0pt{% \hfil\box0 \kern-\hsize % \hsize has to be shortened this way: \kern\leftskip % Intentionally do not respect \rightskip, since we need the space. }% % % Allow all lines to be underfull without complaint: \tolerance=10000 \hbadness=10000 \exdentamount=\defbodyindent {% % defun fonts. We use typewriter by default (used to be bold) because: % . we're printing identifiers, they should be in tt in principle. % . in languages with many accents, such as Czech or French, it's % common to leave accents off identifiers. The result looks ok in % tt, but exceedingly strange in rm. % . we don't want -- and --- to be treated as ligatures. % . this still does not fix the ?` and !` ligatures, but so far no % one has made identifiers using them :). \df \tt \def\temp{#2}% text of the return type \ifx\temp\empty\else \tclose{\temp}% typeset the return type \ifrettypeownline % put return type on its own line; prohibit line break following: \hfil\vadjust{\nobreak}\break \else \space % type on same line, so just followed by a space \fi \fi % no return type #3% output function name }% {\rm\enskip}% hskip 0.5 em of \tenrm % \boldbrax % arguments will be output next, if any. } % Print arguments in slanted roman (not ttsl), inconsistently with using % tt for the name. This is because literal text is sometimes needed in % the argument list (groff manual), and ttsl and tt are not very % distinguishable. Prevent hyphenation at `-' chars. % \def\defunargs#1{% % use sl by default (not ttsl), % tt for the names. \df \sl \hyphenchar\font=0 % % On the other hand, if an argument has two dashes (for instance), we % want a way to get ttsl. We used to recommend @var for that, so % leave the code in, but it's strange for @var to lead to typewriter. % Nowadays we recommend @code, since the difference between a ttsl hyphen % and a tt hyphen is pretty tiny. @code also disables ?` !`. \def\var##1{{\setupmarkupstyle{var}\ttslanted{##1}}}% #1% \sl\hyphenchar\font=45 } % We want ()&[] to print specially on the defun line. % \def\activeparens{% \catcode`\(=\active \catcode`\)=\active \catcode`\[=\active \catcode`\]=\active \catcode`\&=\active } % Make control sequences which act like normal parenthesis chars. \let\lparen = ( \let\rparen = ) % Be sure that we always have a definition for `(', etc. For example, % if the fn name has parens in it, \boldbrax will not be in effect yet, % so TeX would otherwise complain about undefined control sequence. { \activeparens \global\let(=\lparen \global\let)=\rparen \global\let[=\lbrack \global\let]=\rbrack \global\let& = \& \gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb} \gdef\magicamp{\let&=\amprm} } \newcount\parencount % If we encounter &foo, then turn on ()-hacking afterwards \newif\ifampseen \def\amprm#1 {\ampseentrue{\bf\ }} \def\parenfont{% \ifampseen % At the first level, print parens in roman, % otherwise use the default font. \ifnum \parencount=1 \rm \fi \else % The \sf parens (in \boldbrax) actually are a little bolder than % the contained text. This is especially needed for [ and ] . \sf \fi } \def\infirstlevel#1{% \ifampseen \ifnum\parencount=1 #1% \fi \fi } \def\bfafterword#1 {#1 \bf} \def\opnr{% \global\advance\parencount by 1 {\parenfont(}% \infirstlevel \bfafterword } \def\clnr{% {\parenfont)}% \infirstlevel \sl \global\advance\parencount by -1 } \newcount\brackcount \def\lbrb{% \global\advance\brackcount by 1 {\bf[}% } \def\rbrb{% {\bf]}% \global\advance\brackcount by -1 } \def\checkparencounts{% \ifnum\parencount=0 \else \badparencount \fi \ifnum\brackcount=0 \else \badbrackcount \fi } % these should not use \errmessage; the glibc manual, at least, actually % has such constructs (when documenting function pointers). \def\badparencount{% \message{Warning: unbalanced parentheses in @def...}% \global\parencount=0 } \def\badbrackcount{% \message{Warning: unbalanced square brackets in @def...}% \global\brackcount=0 } \message{macros,} % @macro. % To do this right we need a feature of e-TeX, \scantokens, % which we arrange to emulate with a temporary file in ordinary TeX. \ifx\eTeXversion\thisisundefined \newwrite\macscribble \def\scantokens#1{% \toks0={#1}% \immediate\openout\macscribble=\jobname.tmp \immediate\write\macscribble{\the\toks0}% \immediate\closeout\macscribble \input \jobname.tmp } \fi \def\scanmacro#1{\begingroup \newlinechar`\^^M \let\xeatspaces\eatspaces % % Undo catcode changes of \startcontents and \doprintindex % When called from @insertcopying or (short)caption, we need active % backslash to get it printed correctly. Previously, we had % \catcode`\\=\other instead. We'll see whether a problem appears % with macro expansion. --kasal, 19aug04 \catcode`\@=0 \catcode`\\=\active \escapechar=`\@ % % ... and for \example: \spaceisspace % % The \empty here causes a following catcode 5 newline to be eaten as % part of reading whitespace after a control sequence. It does not % eat a catcode 13 newline. There's no good way to handle the two % cases (untried: maybe e-TeX's \everyeof could help, though plain TeX % would then have different behavior). See the Macro Details node in % the manual for the workaround we recommend for macros and % line-oriented commands. % \scantokens{#1\empty}% \endgroup} \def\scanexp#1{% \edef\temp{\noexpand\scanmacro{#1}}% \temp } \newcount\paramno % Count of parameters \newtoks\macname % Macro name \newif\ifrecursive % Is it recursive? % List of all defined macros in the form % \definedummyword\macro1\definedummyword\macro2... % Currently is also contains all @aliases; the list can be split % if there is a need. \def\macrolist{} % Add the macro to \macrolist \def\addtomacrolist#1{\expandafter \addtomacrolistxxx \csname#1\endcsname} \def\addtomacrolistxxx#1{% \toks0 = \expandafter{\macrolist\definedummyword#1}% \xdef\macrolist{\the\toks0}% } % Utility routines. % This does \let #1 = #2, with \csnames; that is, % \let \csname#1\endcsname = \csname#2\endcsname % (except of course we have to play expansion games). % \def\cslet#1#2{% \expandafter\let \csname#1\expandafter\endcsname \csname#2\endcsname } % Trim leading and trailing spaces off a string. % Concepts from aro-bend problem 15 (see CTAN). {\catcode`\@=11 \gdef\eatspaces #1{\expandafter\trim@\expandafter{#1 }} \gdef\trim@ #1{\trim@@ @#1 @ #1 @ @@} \gdef\trim@@ #1@ #2@ #3@@{\trim@@@\empty #2 @} \def\unbrace#1{#1} \unbrace{\gdef\trim@@@ #1 } #2@{#1} } % Trim a single trailing ^^M off a string. {\catcode`\^^M=\other \catcode`\Q=3% \gdef\eatcr #1{\eatcra #1Q^^MQ}% \gdef\eatcra#1^^MQ{\eatcrb#1Q}% \gdef\eatcrb#1Q#2Q{#1}% } % Macro bodies are absorbed as an argument in a context where % all characters are catcode 10, 11 or 12, except \ which is active % (as in normal texinfo). It is necessary to change the definition of \ % to recognize macro arguments; this is the job of \mbodybackslash. % % Non-ASCII encodings make 8-bit characters active, so un-activate % them to avoid their expansion. Must do this non-globally, to % confine the change to the current group. % % It's necessary to have hard CRs when the macro is executed. This is % done by making ^^M (\endlinechar) catcode 12 when reading the macro % body, and then making it the \newlinechar in \scanmacro. % \def\scanctxt{% used as subroutine \catcode`\"=\other \catcode`\+=\other \catcode`\<=\other \catcode`\>=\other \catcode`\@=\other \catcode`\^=\other \catcode`\_=\other \catcode`\|=\other \catcode`\~=\other \ifx\declaredencoding\ascii \else \setnonasciicharscatcodenonglobal\other \fi } \def\scanargctxt{% used for copying and captions, not macros. \scanctxt \catcode`\\=\other \catcode`\^^M=\other } \def\macrobodyctxt{% used for @macro definitions \scanctxt \catcode`\{=\other \catcode`\}=\other \catcode`\^^M=\other \usembodybackslash } \def\macroargctxt{% used when scanning invocations \scanctxt \catcode`\\=0 } % why catcode 0 for \ in the above? To recognize \\ \{ \} as "escapes" % for the single characters \ { }. Thus, we end up with the "commands" % that would be written @\ @{ @} in a Texinfo document. % % We already have @{ and @}. For @\, we define it here, and only for % this purpose, to produce a typewriter backslash (so, the @\ that we % define for @math can't be used with @macro calls): % \def\\{\normalbackslash}% % % We would like to do this for \, too, since that is what makeinfo does. % But it is not possible, because Texinfo already has a command @, for a % cedilla accent. Documents must use @comma{} instead. % % \anythingelse will almost certainly be an error of some kind. % \mbodybackslash is the definition of \ in @macro bodies. % It maps \foo\ => \csname macarg.foo\endcsname => #N % where N is the macro parameter number. % We define \csname macarg.\endcsname to be \realbackslash, so % \\ in macro replacement text gets you a backslash. % {\catcode`@=0 @catcode`@\=@active @gdef@usembodybackslash{@let\=@mbodybackslash} @gdef@mbodybackslash#1\{@csname macarg.#1@endcsname} } \expandafter\def\csname macarg.\endcsname{\realbackslash} \def\margbackslash#1{\char`\#1 } \def\macro{\recursivefalse\parsearg\macroxxx} \def\rmacro{\recursivetrue\parsearg\macroxxx} \def\macroxxx#1{% \getargs{#1}% now \macname is the macname and \argl the arglist \ifx\argl\empty % no arguments \paramno=0\relax \else \expandafter\parsemargdef \argl;% \if\paramno>256\relax \ifx\eTeXversion\thisisundefined \errhelp = \EMsimple \errmessage{You need eTeX to compile a file with macros with more than 256 arguments} \fi \fi \fi \if1\csname ismacro.\the\macname\endcsname \message{Warning: redefining \the\macname}% \else \expandafter\ifx\csname \the\macname\endcsname \relax \else \errmessage{Macro name \the\macname\space already defined}\fi \global\cslet{macsave.\the\macname}{\the\macname}% \global\expandafter\let\csname ismacro.\the\macname\endcsname=1% \addtomacrolist{\the\macname}% \fi \begingroup \macrobodyctxt \ifrecursive \expandafter\parsermacbody \else \expandafter\parsemacbody \fi} \parseargdef\unmacro{% \if1\csname ismacro.#1\endcsname \global\cslet{#1}{macsave.#1}% \global\expandafter\let \csname ismacro.#1\endcsname=0% % Remove the macro name from \macrolist: \begingroup \expandafter\let\csname#1\endcsname \relax \let\definedummyword\unmacrodo \xdef\macrolist{\macrolist}% \endgroup \else \errmessage{Macro #1 not defined}% \fi } % Called by \do from \dounmacro on each macro. The idea is to omit any % macro definitions that have been changed to \relax. % \def\unmacrodo#1{% \ifx #1\relax % remove this \else \noexpand\definedummyword \noexpand#1% \fi } % This makes use of the obscure feature that if the last token of a % is #, then the preceding argument is delimited by % an opening brace, and that opening brace is not consumed. \def\getargs#1{\getargsxxx#1{}} \def\getargsxxx#1#{\getmacname #1 \relax\getmacargs} \def\getmacname#1 #2\relax{\macname={#1}} \def\getmacargs#1{\def\argl{#1}} % For macro processing make @ a letter so that we can make Texinfo private macro names. \edef\texiatcatcode{\the\catcode`\@} \catcode `@=11\relax % Parse the optional {params} list. Set up \paramno and \paramlist % so \defmacro knows what to do. Define \macarg.BLAH for each BLAH % in the params list to some hook where the argument si to be expanded. If % there are less than 10 arguments that hook is to be replaced by ##N where N % is the position in that list, that is to say the macro arguments are to be % defined `a la TeX in the macro body. % % That gets used by \mbodybackslash (above). % % We need to get `macro parameter char #' into several definitions. % The technique used is stolen from LaTeX: let \hash be something % unexpandable, insert that wherever you need a #, and then redefine % it to # just before using the token list produced. % % The same technique is used to protect \eatspaces till just before % the macro is used. % % If there are 10 or more arguments, a different technique is used, where the % hook remains in the body, and when macro is to be expanded the body is % processed again to replace the arguments. % % In that case, the hook is \the\toks N-1, and we simply set \toks N-1 to the % argument N value and then \edef the body (nothing else will expand because of % the catcode regime underwhich the body was input). % % If you compile with TeX (not eTeX), and you have macros with 10 or more % arguments, you need that no macro has more than 256 arguments, otherwise an % error is produced. \def\parsemargdef#1;{% \paramno=0\def\paramlist{}% \let\hash\relax \let\xeatspaces\relax \parsemargdefxxx#1,;,% % In case that there are 10 or more arguments we parse again the arguments % list to set new definitions for the \macarg.BLAH macros corresponding to % each BLAH argument. It was anyhow needed to parse already once this list % in order to count the arguments, and as macros with at most 9 arguments % are by far more frequent than macro with 10 or more arguments, defining % twice the \macarg.BLAH macros does not cost too much processing power. \ifnum\paramno<10\relax\else \paramno0\relax \parsemmanyargdef@@#1,;,% 10 or more arguments \fi } \def\parsemargdefxxx#1,{% \if#1;\let\next=\relax \else \let\next=\parsemargdefxxx \advance\paramno by 1 \expandafter\edef\csname macarg.\eatspaces{#1}\endcsname {\xeatspaces{\hash\the\paramno}}% \edef\paramlist{\paramlist\hash\the\paramno,}% \fi\next} \def\parsemmanyargdef@@#1,{% \if#1;\let\next=\relax \else \let\next=\parsemmanyargdef@@ \edef\tempb{\eatspaces{#1}}% \expandafter\def\expandafter\tempa \expandafter{\csname macarg.\tempb\endcsname}% % Note that we need some extra \noexpand\noexpand, this is because we % don't want \the to be expanded in the \parsermacbody as it uses an % \xdef . \expandafter\edef\tempa {\noexpand\noexpand\noexpand\the\toks\the\paramno}% \advance\paramno by 1\relax \fi\next} % These two commands read recursive and nonrecursive macro bodies. % (They're different since rec and nonrec macros end differently.) % \catcode `\@\texiatcatcode \long\def\parsemacbody#1@end macro% {\xdef\temp{\eatcr{#1}}\endgroup\defmacro}% \long\def\parsermacbody#1@end rmacro% {\xdef\temp{\eatcr{#1}}\endgroup\defmacro}% \catcode `\@=11\relax \let\endargs@\relax \let\nil@\relax \def\nilm@{\nil@}% \long\def\nillm@{\nil@}% % This macro is expanded during the Texinfo macro expansion, not during its % definition. It gets all the arguments values and assigns them to macros % macarg.ARGNAME % % #1 is the macro name % #2 is the list of argument names % #3 is the list of argument values \def\getargvals@#1#2#3{% \def\macargdeflist@{}% \def\saveparamlist@{#2}% Need to keep a copy for parameter expansion. \def\paramlist{#2,\nil@}% \def\macroname{#1}% \begingroup \macroargctxt \def\argvaluelist{#3,\nil@}% \def\@tempa{#3}% \ifx\@tempa\empty \setemptyargvalues@ \else \getargvals@@ \fi } % \def\getargvals@@{% \ifx\paramlist\nilm@ % Some sanity check needed here that \argvaluelist is also empty. \ifx\argvaluelist\nillm@ \else \errhelp = \EMsimple \errmessage{Too many arguments in macro `\macroname'!}% \fi \let\next\macargexpandinbody@ \else \ifx\argvaluelist\nillm@ % No more arguments values passed to macro. Set remaining named-arg % macros to empty. \let\next\setemptyargvalues@ \else % pop current arg name into \@tempb \def\@tempa##1{\pop@{\@tempb}{\paramlist}##1\endargs@}% \expandafter\@tempa\expandafter{\paramlist}% % pop current argument value into \@tempc \def\@tempa##1{\longpop@{\@tempc}{\argvaluelist}##1\endargs@}% \expandafter\@tempa\expandafter{\argvaluelist}% % Here \@tempb is the current arg name and \@tempc is the current arg value. % First place the new argument macro definition into \@tempd \expandafter\macname\expandafter{\@tempc}% \expandafter\let\csname macarg.\@tempb\endcsname\relax \expandafter\def\expandafter\@tempe\expandafter{% \csname macarg.\@tempb\endcsname}% \edef\@tempd{\long\def\@tempe{\the\macname}}% \push@\@tempd\macargdeflist@ \let\next\getargvals@@ \fi \fi \next } \def\push@#1#2{% \expandafter\expandafter\expandafter\def \expandafter\expandafter\expandafter#2% \expandafter\expandafter\expandafter{% \expandafter#1#2}% } % Replace arguments by their values in the macro body, and place the result % in macro \@tempa \def\macvalstoargs@{% % To do this we use the property that token registers that are \the'ed % within an \edef expand only once. So we are going to place all argument % values into respective token registers. % % First we save the token context, and initialize argument numbering. \begingroup \paramno0\relax % Then, for each argument number #N, we place the corresponding argument % value into a new token list register \toks#N \expandafter\putargsintokens@\saveparamlist@,;,% % Then, we expand the body so that argument are replaced by their % values. The trick for values not to be expanded themselves is that they % are within tokens and that tokens expand only once in an \edef . \edef\@tempc{\csname mac.\macroname .body\endcsname}% % Now we restore the token stack pointer to free the token list registers % which we have used, but we make sure that expanded body is saved after % group. \expandafter \endgroup \expandafter\def\expandafter\@tempa\expandafter{\@tempc}% } \def\macargexpandinbody@{% %% Define the named-macro outside of this group and then close this group. \expandafter \endgroup \macargdeflist@ % First the replace in body the macro arguments by their values, the result % is in \@tempa . \macvalstoargs@ % Then we point at the \norecurse or \gobble (for recursive) macro value % with \@tempb . \expandafter\let\expandafter\@tempb\csname mac.\macroname .recurse\endcsname % Depending on whether it is recursive or not, we need some tailing % \egroup . \ifx\@tempb\gobble \let\@tempc\relax \else \let\@tempc\egroup \fi % And now we do the real job: \edef\@tempd{\noexpand\@tempb{\macroname}\noexpand\scanmacro{\@tempa}\@tempc}% \@tempd } \def\putargsintokens@#1,{% \if#1;\let\next\relax \else \let\next\putargsintokens@ % First we allocate the new token list register, and give it a temporary % alias \@tempb . \toksdef\@tempb\the\paramno % Then we place the argument value into that token list register. \expandafter\let\expandafter\@tempa\csname macarg.#1\endcsname \expandafter\@tempb\expandafter{\@tempa}% \advance\paramno by 1\relax \fi \next } % Save the token stack pointer into macro #1 \def\texisavetoksstackpoint#1{\edef#1{\the\@cclvi}} % Restore the token stack pointer from number in macro #1 \def\texirestoretoksstackpoint#1{\expandafter\mathchardef\expandafter\@cclvi#1\relax} % newtoks that can be used non \outer . \def\texinonouternewtoks{\alloc@ 5\toks \toksdef \@cclvi} % Tailing missing arguments are set to empty \def\setemptyargvalues@{% \ifx\paramlist\nilm@ \let\next\macargexpandinbody@ \else \expandafter\setemptyargvaluesparser@\paramlist\endargs@ \let\next\setemptyargvalues@ \fi \next } \def\setemptyargvaluesparser@#1,#2\endargs@{% \expandafter\def\expandafter\@tempa\expandafter{% \expandafter\def\csname macarg.#1\endcsname{}}% \push@\@tempa\macargdeflist@ \def\paramlist{#2}% } % #1 is the element target macro % #2 is the list macro % #3,#4\endargs@ is the list value \def\pop@#1#2#3,#4\endargs@{% \def#1{#3}% \def#2{#4}% } \long\def\longpop@#1#2#3,#4\endargs@{% \long\def#1{#3}% \long\def#2{#4}% } % This defines a Texinfo @macro. There are eight cases: recursive and % nonrecursive macros of zero, one, up to nine, and many arguments. % Much magic with \expandafter here. % \xdef is used so that macro definitions will survive the file % they're defined in; @include reads the file inside a group. % \def\defmacro{% \let\hash=##% convert placeholders to macro parameter chars \ifrecursive \ifcase\paramno % 0 \expandafter\xdef\csname\the\macname\endcsname{% \noexpand\scanmacro{\temp}}% \or % 1 \expandafter\xdef\csname\the\macname\endcsname{% \bgroup\noexpand\macroargctxt \noexpand\braceorline \expandafter\noexpand\csname\the\macname xxx\endcsname}% \expandafter\xdef\csname\the\macname xxx\endcsname##1{% \egroup\noexpand\scanmacro{\temp}}% \else \ifnum\paramno<10\relax % at most 9 \expandafter\xdef\csname\the\macname\endcsname{% \bgroup\noexpand\macroargctxt \noexpand\csname\the\macname xx\endcsname}% \expandafter\xdef\csname\the\macname xx\endcsname##1{% \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}% \expandafter\expandafter \expandafter\xdef \expandafter\expandafter \csname\the\macname xxx\endcsname \paramlist{\egroup\noexpand\scanmacro{\temp}}% \else % 10 or more \expandafter\xdef\csname\the\macname\endcsname{% \noexpand\getargvals@{\the\macname}{\argl}% }% \global\expandafter\let\csname mac.\the\macname .body\endcsname\temp \global\expandafter\let\csname mac.\the\macname .recurse\endcsname\gobble \fi \fi \else \ifcase\paramno % 0 \expandafter\xdef\csname\the\macname\endcsname{% \noexpand\norecurse{\the\macname}% \noexpand\scanmacro{\temp}\egroup}% \or % 1 \expandafter\xdef\csname\the\macname\endcsname{% \bgroup\noexpand\macroargctxt \noexpand\braceorline \expandafter\noexpand\csname\the\macname xxx\endcsname}% \expandafter\xdef\csname\the\macname xxx\endcsname##1{% \egroup \noexpand\norecurse{\the\macname}% \noexpand\scanmacro{\temp}\egroup}% \else % at most 9 \ifnum\paramno<10\relax \expandafter\xdef\csname\the\macname\endcsname{% \bgroup\noexpand\macroargctxt \expandafter\noexpand\csname\the\macname xx\endcsname}% \expandafter\xdef\csname\the\macname xx\endcsname##1{% \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}% \expandafter\expandafter \expandafter\xdef \expandafter\expandafter \csname\the\macname xxx\endcsname \paramlist{% \egroup \noexpand\norecurse{\the\macname}% \noexpand\scanmacro{\temp}\egroup}% \else % 10 or more: \expandafter\xdef\csname\the\macname\endcsname{% \noexpand\getargvals@{\the\macname}{\argl}% }% \global\expandafter\let\csname mac.\the\macname .body\endcsname\temp \global\expandafter\let\csname mac.\the\macname .recurse\endcsname\norecurse \fi \fi \fi} \catcode `\@\texiatcatcode\relax \def\norecurse#1{\bgroup\cslet{#1}{macsave.#1}} % \braceorline decides whether the next nonwhitespace character is a % {. If so it reads up to the closing }, if not, it reads the whole % line. Whatever was read is then fed to the next control sequence % as an argument (by \parsebrace or \parsearg). % \def\braceorline#1{\let\macnamexxx=#1\futurelet\nchar\braceorlinexxx} \def\braceorlinexxx{% \ifx\nchar\bgroup\else \expandafter\parsearg \fi \macnamexxx} % @alias. % We need some trickery to remove the optional spaces around the equal % sign. Make them active and then expand them all to nothing. % \def\alias{\parseargusing\obeyspaces\aliasxxx} \def\aliasxxx #1{\aliasyyy#1\relax} \def\aliasyyy #1=#2\relax{% {% \expandafter\let\obeyedspace=\empty \addtomacrolist{#1}% \xdef\next{\global\let\makecsname{#1}=\makecsname{#2}}% }% \next } \message{cross references,} \newwrite\auxfile \newif\ifhavexrefs % True if xref values are known. \newif\ifwarnedxrefs % True if we warned once that they aren't known. % @inforef is relatively simple. \def\inforef #1{\inforefzzz #1,,,,**} \def\inforefzzz #1,#2,#3,#4**{% \putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}}, node \samp{\ignorespaces#1{}}} % @node's only job in TeX is to define \lastnode, which is used in % cross-references. The @node line might or might not have commas, and % might or might not have spaces before the first comma, like: % @node foo , bar , ... % We don't want such trailing spaces in the node name. % \parseargdef\node{\checkenv{}\donode #1 ,\finishnodeparse} % % also remove a trailing comma, in case of something like this: % @node Help-Cross, , , Cross-refs \def\donode#1 ,#2\finishnodeparse{\dodonode #1,\finishnodeparse} \def\dodonode#1,#2\finishnodeparse{\gdef\lastnode{#1}} \let\nwnode=\node \let\lastnode=\empty % Write a cross-reference definition for the current node. #1 is the % type (Ynumbered, Yappendix, Ynothing). % \def\donoderef#1{% \ifx\lastnode\empty\else \setref{\lastnode}{#1}% \global\let\lastnode=\empty \fi } % @anchor{NAME} -- define xref target at arbitrary point. % \newcount\savesfregister % \def\savesf{\relax \ifhmode \savesfregister=\spacefactor \fi} \def\restoresf{\relax \ifhmode \spacefactor=\savesfregister \fi} \def\anchor#1{\savesf \setref{#1}{Ynothing}\restoresf \ignorespaces} % \setref{NAME}{SNT} defines a cross-reference point NAME (a node or an % anchor), which consists of three parts: % 1) NAME-title - the current sectioning name taken from \lastsection, % or the anchor name. % 2) NAME-snt - section number and type, passed as the SNT arg, or % empty for anchors. % 3) NAME-pg - the page number. % % This is called from \donoderef, \anchor, and \dofloat. In the case of % floats, there is an additional part, which is not written here: % 4) NAME-lof - the text as it should appear in a @listoffloats. % \def\setref#1#2{% \pdfmkdest{#1}% \iflinks {% \atdummies % preserve commands, but don't expand them \edef\writexrdef##1##2{% \write\auxfile{@xrdef{#1-% #1 of \setref, expanded by the \edef ##1}{##2}}% these are parameters of \writexrdef }% \toks0 = \expandafter{\lastsection}% \immediate \writexrdef{title}{\the\toks0 }% \immediate \writexrdef{snt}{\csname #2\endcsname}% \Ynumbered etc. \safewhatsit{\writexrdef{pg}{\folio}}% will be written later, at \shipout }% \fi } % @xrefautosectiontitle on|off says whether @section(ing) names are used % automatically in xrefs, if the third arg is not explicitly specified. % This was provided as a "secret" @set xref-automatic-section-title % variable, now it's official. % \parseargdef\xrefautomaticsectiontitle{% \def\temp{#1}% \ifx\temp\onword \expandafter\let\csname SETxref-automatic-section-title\endcsname = \empty \else\ifx\temp\offword \expandafter\let\csname SETxref-automatic-section-title\endcsname = \relax \else \errhelp = \EMsimple \errmessage{Unknown @xrefautomaticsectiontitle value `\temp', must be on|off}% \fi\fi } % % @xref, @pxref, and @ref generate cross-references. For \xrefX, #1 is % the node name, #2 the name of the Info cross-reference, #3 the printed % node name, #4 the name of the Info file, #5 the name of the printed % manual. All but the node name can be omitted. % \def\pxref#1{\putwordsee{} \xrefX[#1,,,,,,,]} \def\xref#1{\putwordSee{} \xrefX[#1,,,,,,,]} \def\ref#1{\xrefX[#1,,,,,,,]} % \newbox\toprefbox \newbox\printedrefnamebox \newbox\infofilenamebox \newbox\printedmanualbox % \def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup \unsepspaces % % Get args without leading/trailing spaces. \def\printedrefname{\ignorespaces #3}% \setbox\printedrefnamebox = \hbox{\printedrefname\unskip}% % \def\infofilename{\ignorespaces #4}% \setbox\infofilenamebox = \hbox{\infofilename\unskip}% % \def\printedmanual{\ignorespaces #5}% \setbox\printedmanualbox = \hbox{\printedmanual\unskip}% % % If the printed reference name (arg #3) was not explicitly given in % the @xref, figure out what we want to use. \ifdim \wd\printedrefnamebox = 0pt % No printed node name was explicitly given. \expandafter\ifx\csname SETxref-automatic-section-title\endcsname \relax % Not auto section-title: use node name inside the square brackets. \def\printedrefname{\ignorespaces #1}% \else % Auto section-title: use chapter/section title inside % the square brackets if we have it. \ifdim \wd\printedmanualbox > 0pt % It is in another manual, so we don't have it; use node name. \def\printedrefname{\ignorespaces #1}% \else \ifhavexrefs % We (should) know the real title if we have the xref values. \def\printedrefname{\refx{#1-title}{}}% \else % Otherwise just copy the Info node name. \def\printedrefname{\ignorespaces #1}% \fi% \fi \fi \fi % % Make link in pdf output. \ifpdf {\indexnofonts \turnoffactive \makevalueexpandable % This expands tokens, so do it after making catcode changes, so _ % etc. don't get their TeX definitions. This ignores all spaces in % #4, including (wrongly) those in the middle of the filename. \getfilename{#4}% % % This (wrongly) does not take account of leading or trailing % spaces in #1, which should be ignored. \edef\pdfxrefdest{#1}% \ifx\pdfxrefdest\empty \def\pdfxrefdest{Top}% no empty targets \else \txiescapepdf\pdfxrefdest % escape PDF special chars \fi % \leavevmode \startlink attr{/Border [0 0 0]}% \ifnum\filenamelength>0 goto file{\the\filename.pdf} name{\pdfxrefdest}% \else goto name{\pdfmkpgn{\pdfxrefdest}}% \fi }% \setcolor{\linkcolor}% \fi % % Float references are printed completely differently: "Figure 1.2" % instead of "[somenode], p.3". We distinguish them by the % LABEL-title being set to a magic string. {% % Have to otherify everything special to allow the \csname to % include an _ in the xref name, etc. \indexnofonts \turnoffactive \expandafter\global\expandafter\let\expandafter\Xthisreftitle \csname XR#1-title\endcsname }% \iffloat\Xthisreftitle % If the user specified the print name (third arg) to the ref, % print it instead of our usual "Figure 1.2". \ifdim\wd\printedrefnamebox = 0pt \refx{#1-snt}{}% \else \printedrefname \fi % % If the user also gave the printed manual name (fifth arg), append % "in MANUALNAME". \ifdim \wd\printedmanualbox > 0pt \space \putwordin{} \cite{\printedmanual}% \fi \else % node/anchor (non-float) references. % % If we use \unhbox to print the node names, TeX does not insert % empty discretionaries after hyphens, which means that it will not % find a line break at a hyphen in a node names. Since some manuals % are best written with fairly long node names, containing hyphens, % this is a loss. Therefore, we give the text of the node name % again, so it is as if TeX is seeing it for the first time. % \ifdim \wd\printedmanualbox > 0pt % Cross-manual reference with a printed manual name. % \crossmanualxref{\cite{\printedmanual\unskip}}% % \else\ifdim \wd\infofilenamebox > 0pt % Cross-manual reference with only an info filename (arg 4), no % printed manual name (arg 5). This is essentially the same as % the case above; we output the filename, since we have nothing else. % \crossmanualxref{\code{\infofilename\unskip}}% % \else % Reference within this manual. % % _ (for example) has to be the character _ for the purposes of the % control sequence corresponding to the node, but it has to expand % into the usual \leavevmode...\vrule stuff for purposes of % printing. So we \turnoffactive for the \refx-snt, back on for the % printing, back off for the \refx-pg. {\turnoffactive % Only output a following space if the -snt ref is nonempty; for % @unnumbered and @anchor, it won't be. \setbox2 = \hbox{\ignorespaces \refx{#1-snt}{}}% \ifdim \wd2 > 0pt \refx{#1-snt}\space\fi }% % output the `[mynode]' via the macro below so it can be overridden. \xrefprintnodename\printedrefname % % But we always want a comma and a space: ,\space % % output the `page 3'. \turnoffactive \putwordpage\tie\refx{#1-pg}{}% \fi\fi \fi \endlink \endgroup} % Output a cross-manual xref to #1. Used just above (twice). % % Only include the text "Section ``foo'' in" if the foo is neither % missing or Top. Thus, @xref{,,,foo,The Foo Manual} outputs simply % "see The Foo Manual", the idea being to refer to the whole manual. % % But, this being TeX, we can't easily compare our node name against the % string "Top" while ignoring the possible spaces before and after in % the input. By adding the arbitrary 7sp below, we make it much less % likely that a real node name would have the same width as "Top" (e.g., % in a monospaced font). Hopefully it will never happen in practice. % % For the same basic reason, we retypeset the "Top" at every % reference, since the current font is indeterminate. % \def\crossmanualxref#1{% \setbox\toprefbox = \hbox{Top\kern7sp}% \setbox2 = \hbox{\ignorespaces \printedrefname \unskip \kern7sp}% \ifdim \wd2 > 7sp % nonempty? \ifdim \wd2 = \wd\toprefbox \else % same as Top? \putwordSection{} ``\printedrefname'' \putwordin{}\space \fi \fi #1% } % This macro is called from \xrefX for the `[nodename]' part of xref % output. It's a separate macro only so it can be changed more easily, % since square brackets don't work well in some documents. Particularly % one that Bob is working on :). % \def\xrefprintnodename#1{[#1]} % Things referred to by \setref. % \def\Ynothing{} \def\Yomitfromtoc{} \def\Ynumbered{% \ifnum\secno=0 \putwordChapter@tie \the\chapno \else \ifnum\subsecno=0 \putwordSection@tie \the\chapno.\the\secno \else \ifnum\subsubsecno=0 \putwordSection@tie \the\chapno.\the\secno.\the\subsecno \else \putwordSection@tie \the\chapno.\the\secno.\the\subsecno.\the\subsubsecno \fi\fi\fi } \def\Yappendix{% \ifnum\secno=0 \putwordAppendix@tie @char\the\appendixno{}% \else \ifnum\subsecno=0 \putwordSection@tie @char\the\appendixno.\the\secno \else \ifnum\subsubsecno=0 \putwordSection@tie @char\the\appendixno.\the\secno.\the\subsecno \else \putwordSection@tie @char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno \fi\fi\fi } % Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME. % If its value is nonempty, SUFFIX is output afterward. % \def\refx#1#2{% {% \indexnofonts \otherbackslash \expandafter\global\expandafter\let\expandafter\thisrefX \csname XR#1\endcsname }% \ifx\thisrefX\relax % If not defined, say something at least. \angleleft un\-de\-fined\angleright \iflinks \ifhavexrefs {\toks0 = {#1}% avoid expansion of possibly-complex value \message{\linenumber Undefined cross reference `\the\toks0'.}}% \else \ifwarnedxrefs\else \global\warnedxrefstrue \message{Cross reference values unknown; you must run TeX again.}% \fi \fi \fi \else % It's defined, so just use it. \thisrefX \fi #2% Output the suffix in any case. } % This is the macro invoked by entries in the aux file. Usually it's % just a \def (we prepend XR to the control sequence name to avoid % collisions). But if this is a float type, we have more work to do. % \def\xrdef#1#2{% {% The node name might contain 8-bit characters, which in our current % implementation are changed to commands like @'e. Don't let these % mess up the control sequence name. \indexnofonts \turnoffactive \xdef\safexrefname{#1}% }% % \expandafter\gdef\csname XR\safexrefname\endcsname{#2}% remember this xref % % Was that xref control sequence that we just defined for a float? \expandafter\iffloat\csname XR\safexrefname\endcsname % it was a float, and we have the (safe) float type in \iffloattype. \expandafter\let\expandafter\floatlist \csname floatlist\iffloattype\endcsname % % Is this the first time we've seen this float type? \expandafter\ifx\floatlist\relax \toks0 = {\do}% yes, so just \do \else % had it before, so preserve previous elements in list. \toks0 = \expandafter{\floatlist\do}% \fi % % Remember this xref in the control sequence \floatlistFLOATTYPE, % for later use in \listoffloats. \expandafter\xdef\csname floatlist\iffloattype\endcsname{\the\toks0 {\safexrefname}}% \fi } % Read the last existing aux file, if any. No error if none exists. % \def\tryauxfile{% \openin 1 \jobname.aux \ifeof 1 \else \readdatafile{aux}% \global\havexrefstrue \fi \closein 1 } \def\setupdatafile{% \catcode`\^^@=\other \catcode`\^^A=\other \catcode`\^^B=\other \catcode`\^^C=\other \catcode`\^^D=\other \catcode`\^^E=\other \catcode`\^^F=\other \catcode`\^^G=\other \catcode`\^^H=\other \catcode`\^^K=\other \catcode`\^^L=\other \catcode`\^^N=\other \catcode`\^^P=\other \catcode`\^^Q=\other \catcode`\^^R=\other \catcode`\^^S=\other \catcode`\^^T=\other \catcode`\^^U=\other \catcode`\^^V=\other \catcode`\^^W=\other \catcode`\^^X=\other \catcode`\^^Z=\other \catcode`\^^[=\other \catcode`\^^\=\other \catcode`\^^]=\other \catcode`\^^^=\other \catcode`\^^_=\other % It was suggested to set the catcode of ^ to 7, which would allow ^^e4 etc. % in xref tags, i.e., node names. But since ^^e4 notation isn't % supported in the main text, it doesn't seem desirable. Furthermore, % that is not enough: for node names that actually contain a ^ % character, we would end up writing a line like this: 'xrdef {'hat % b-title}{'hat b} and \xrdef does a \csname...\endcsname on the first % argument, and \hat is not an expandable control sequence. It could % all be worked out, but why? Either we support ^^ or we don't. % % The other change necessary for this was to define \auxhat: % \def\auxhat{\def^{'hat }}% extra space so ok if followed by letter % and then to call \auxhat in \setq. % \catcode`\^=\other % % Special characters. Should be turned off anyway, but... \catcode`\~=\other \catcode`\[=\other \catcode`\]=\other \catcode`\"=\other \catcode`\_=\other \catcode`\|=\other \catcode`\<=\other \catcode`\>=\other \catcode`\$=\other \catcode`\#=\other \catcode`\&=\other \catcode`\%=\other \catcode`+=\other % avoid \+ for paranoia even though we've turned it off % % This is to support \ in node names and titles, since the \ % characters end up in a \csname. It's easier than % leaving it active and making its active definition an actual \ % character. What I don't understand is why it works in the *value* % of the xrdef. Seems like it should be a catcode12 \, and that % should not typeset properly. But it works, so I'm moving on for % now. --karl, 15jan04. \catcode`\\=\other % % Make the characters 128-255 be printing characters. {% \count1=128 \def\loop{% \catcode\count1=\other \advance\count1 by 1 \ifnum \count1<256 \loop \fi }% }% % % @ is our escape character in .aux files, and we need braces. \catcode`\{=1 \catcode`\}=2 \catcode`\@=0 } \def\readdatafile#1{% \begingroup \setupdatafile \input\jobname.#1 \endgroup} \message{insertions,} % including footnotes. \newcount \footnoteno % The trailing space in the following definition for supereject is % vital for proper filling; pages come out unaligned when you do a % pagealignmacro call if that space before the closing brace is % removed. (Generally, numeric constants should always be followed by a % space to prevent strange expansion errors.) \def\supereject{\par\penalty -20000\footnoteno =0 } % @footnotestyle is meaningful for Info output only. \let\footnotestyle=\comment {\catcode `\@=11 % % Auto-number footnotes. Otherwise like plain. \gdef\footnote{% \let\indent=\ptexindent \let\noindent=\ptexnoindent \global\advance\footnoteno by \@ne \edef\thisfootno{$^{\the\footnoteno}$}% % % In case the footnote comes at the end of a sentence, preserve the % extra spacing after we do the footnote number. \let\@sf\empty \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\ptexslash\fi % % Remove inadvertent blank space before typesetting the footnote number. \unskip \thisfootno\@sf \dofootnote }% % Don't bother with the trickery in plain.tex to not require the % footnote text as a parameter. Our footnotes don't need to be so general. % % Oh yes, they do; otherwise, @ifset (and anything else that uses % \parseargline) fails inside footnotes because the tokens are fixed when % the footnote is read. --karl, 16nov96. % \gdef\dofootnote{% \insert\footins\bgroup % We want to typeset this text as a normal paragraph, even if the % footnote reference occurs in (for example) a display environment. % So reset some parameters. \hsize=\pagewidth \interlinepenalty\interfootnotelinepenalty \splittopskip\ht\strutbox % top baseline for broken footnotes \splitmaxdepth\dp\strutbox \floatingpenalty\@MM \leftskip\z@skip \rightskip\z@skip \spaceskip\z@skip \xspaceskip\z@skip \parindent\defaultparindent % \smallfonts \rm % % Because we use hanging indentation in footnotes, a @noindent appears % to exdent this text, so make it be a no-op. makeinfo does not use % hanging indentation so @noindent can still be needed within footnote % text after an @example or the like (not that this is good style). \let\noindent = \relax % % Hang the footnote text off the number. Use \everypar in case the % footnote extends for more than one paragraph. \everypar = {\hang}% \textindent{\thisfootno}% % % Don't crash into the line above the footnote text. Since this % expands into a box, it must come within the paragraph, lest it % provide a place where TeX can split the footnote. \footstrut % % Invoke rest of plain TeX footnote routine. \futurelet\next\fo@t } }%end \catcode `\@=11 % In case a @footnote appears in a vbox, save the footnote text and create % the real \insert just after the vbox finished. Otherwise, the insertion % would be lost. % Similarly, if a @footnote appears inside an alignment, save the footnote % text to a box and make the \insert when a row of the table is finished. % And the same can be done for other insert classes. --kasal, 16nov03. % Replace the \insert primitive by a cheating macro. % Deeper inside, just make sure that the saved insertions are not spilled % out prematurely. % \def\startsavinginserts{% \ifx \insert\ptexinsert \let\insert\saveinsert \else \let\checkinserts\relax \fi } % This \insert replacement works for both \insert\footins{foo} and % \insert\footins\bgroup foo\egroup, but it doesn't work for \insert27{foo}. % \def\saveinsert#1{% \edef\next{\noexpand\savetobox \makeSAVEname#1}% \afterassignment\next % swallow the left brace \let\temp = } \def\makeSAVEname#1{\makecsname{SAVE\expandafter\gobble\string#1}} \def\savetobox#1{\global\setbox#1 = \vbox\bgroup \unvbox#1} \def\checksaveins#1{\ifvoid#1\else \placesaveins#1\fi} \def\placesaveins#1{% \ptexinsert \csname\expandafter\gobblesave\string#1\endcsname {\box#1}% } % eat @SAVE -- beware, all of them have catcode \other: { \def\dospecials{\do S\do A\do V\do E} \uncatcodespecials % ;-) \gdef\gobblesave @SAVE{} } % initialization: \def\newsaveins #1{% \edef\next{\noexpand\newsaveinsX \makeSAVEname#1}% \next } \def\newsaveinsX #1{% \csname newbox\endcsname #1% \expandafter\def\expandafter\checkinserts\expandafter{\checkinserts \checksaveins #1}% } % initialize: \let\checkinserts\empty \newsaveins\footins \newsaveins\margin % @image. We use the macros from epsf.tex to support this. % If epsf.tex is not installed and @image is used, we complain. % % Check for and read epsf.tex up front. If we read it only at @image % time, we might be inside a group, and then its definitions would get % undone and the next image would fail. \openin 1 = epsf.tex \ifeof 1 \else % Do not bother showing banner with epsf.tex v2.7k (available in % doc/epsf.tex and on ctan). \def\epsfannounce{\toks0 = }% \input epsf.tex \fi \closein 1 % % We will only complain once about lack of epsf.tex. \newif\ifwarnednoepsf \newhelp\noepsfhelp{epsf.tex must be installed for images to work. It is also included in the Texinfo distribution, or you can get it from ftp://tug.org/tex/epsf.tex.} % \def\image#1{% \ifx\epsfbox\thisisundefined \ifwarnednoepsf \else \errhelp = \noepsfhelp \errmessage{epsf.tex not found, images will be ignored}% \global\warnednoepsftrue \fi \else \imagexxx #1,,,,,\finish \fi } % % Arguments to @image: % #1 is (mandatory) image filename; we tack on .eps extension. % #2 is (optional) width, #3 is (optional) height. % #4 is (ignored optional) html alt text. % #5 is (ignored optional) extension. % #6 is just the usual extra ignored arg for parsing stuff. \newif\ifimagevmode \def\imagexxx#1,#2,#3,#4,#5,#6\finish{\begingroup \catcode`\^^M = 5 % in case we're inside an example \normalturnoffactive % allow _ et al. in names % If the image is by itself, center it. \ifvmode \imagevmodetrue \else \ifx\centersub\centerV % for @center @image, we need a vbox so we can have our vertical space \imagevmodetrue \vbox\bgroup % vbox has better behavior than vtop herev \fi\fi % \ifimagevmode \nobreak\medskip % Usually we'll have text after the image which will insert % \parskip glue, so insert it here too to equalize the space % above and below. \nobreak\vskip\parskip \nobreak \fi % % Leave vertical mode so that indentation from an enclosing % environment such as @quotation is respected. % However, if we're at the top level, we don't want the % normal paragraph indentation. % On the other hand, if we are in the case of @center @image, we don't % want to start a paragraph, which will create a hsize-width box and % eradicate the centering. \ifx\centersub\centerV\else \noindent \fi % % Output the image. \ifpdf \dopdfimage{#1}{#2}{#3}% \else % \epsfbox itself resets \epsf?size at each figure. \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \epsfxsize=#2\relax \fi \setbox0 = \hbox{\ignorespaces #3}\ifdim\wd0 > 0pt \epsfysize=#3\relax \fi \epsfbox{#1.eps}% \fi % \ifimagevmode \medskip % space after a standalone image \fi \ifx\centersub\centerV \egroup \fi \endgroup} % @float FLOATTYPE,LABEL,LOC ... @end float for displayed figures, tables, % etc. We don't actually implement floating yet, we always include the % float "here". But it seemed the best name for the future. % \envparseargdef\float{\eatcommaspace\eatcommaspace\dofloat#1, , ,\finish} % There may be a space before second and/or third parameter; delete it. \def\eatcommaspace#1, {#1,} % #1 is the optional FLOATTYPE, the text label for this float, typically % "Figure", "Table", "Example", etc. Can't contain commas. If omitted, % this float will not be numbered and cannot be referred to. % % #2 is the optional xref label. Also must be present for the float to % be referable. % % #3 is the optional positioning argument; for now, it is ignored. It % will somehow specify the positions allowed to float to (here, top, bottom). % % We keep a separate counter for each FLOATTYPE, which we reset at each % chapter-level command. \let\resetallfloatnos=\empty % \def\dofloat#1,#2,#3,#4\finish{% \let\thiscaption=\empty \let\thisshortcaption=\empty % % don't lose footnotes inside @float. % % BEWARE: when the floats start float, we have to issue warning whenever an % insert appears inside a float which could possibly float. --kasal, 26may04 % \startsavinginserts % % We can't be used inside a paragraph. \par % \vtop\bgroup \def\floattype{#1}% \def\floatlabel{#2}% \def\floatloc{#3}% we do nothing with this yet. % \ifx\floattype\empty \let\safefloattype=\empty \else {% % the floattype might have accents or other special characters, % but we need to use it in a control sequence name. \indexnofonts \turnoffactive \xdef\safefloattype{\floattype}% }% \fi % % If label is given but no type, we handle that as the empty type. \ifx\floatlabel\empty \else % We want each FLOATTYPE to be numbered separately (Figure 1, % Table 1, Figure 2, ...). (And if no label, no number.) % \expandafter\getfloatno\csname\safefloattype floatno\endcsname \global\advance\floatno by 1 % {% % This magic value for \lastsection is output by \setref as the % XREFLABEL-title value. \xrefX uses it to distinguish float % labels (which have a completely different output format) from % node and anchor labels. And \xrdef uses it to construct the % lists of floats. % \edef\lastsection{\floatmagic=\safefloattype}% \setref{\floatlabel}{Yfloat}% }% \fi % % start with \parskip glue, I guess. \vskip\parskip % % Don't suppress indentation if a float happens to start a section. \restorefirstparagraphindent } % we have these possibilities: % @float Foo,lbl & @caption{Cap}: Foo 1.1: Cap % @float Foo,lbl & no caption: Foo 1.1 % @float Foo & @caption{Cap}: Foo: Cap % @float Foo & no caption: Foo % @float ,lbl & Caption{Cap}: 1.1: Cap % @float ,lbl & no caption: 1.1 % @float & @caption{Cap}: Cap % @float & no caption: % \def\Efloat{% \let\floatident = \empty % % In all cases, if we have a float type, it comes first. \ifx\floattype\empty \else \def\floatident{\floattype}\fi % % If we have an xref label, the number comes next. \ifx\floatlabel\empty \else \ifx\floattype\empty \else % if also had float type, need tie first. \appendtomacro\floatident{\tie}% \fi % the number. \appendtomacro\floatident{\chaplevelprefix\the\floatno}% \fi % % Start the printed caption with what we've constructed in % \floatident, but keep it separate; we need \floatident again. \let\captionline = \floatident % \ifx\thiscaption\empty \else \ifx\floatident\empty \else \appendtomacro\captionline{: }% had ident, so need a colon between \fi % % caption text. \appendtomacro\captionline{\scanexp\thiscaption}% \fi % % If we have anything to print, print it, with space before. % Eventually this needs to become an \insert. \ifx\captionline\empty \else \vskip.5\parskip \captionline % % Space below caption. \vskip\parskip \fi % % If have an xref label, write the list of floats info. Do this % after the caption, to avoid chance of it being a breakpoint. \ifx\floatlabel\empty \else % Write the text that goes in the lof to the aux file as % \floatlabel-lof. Besides \floatident, we include the short % caption if specified, else the full caption if specified, else nothing. {% \atdummies % % since we read the caption text in the macro world, where ^^M % is turned into a normal character, we have to scan it back, so % we don't write the literal three characters "^^M" into the aux file. \scanexp{% \xdef\noexpand\gtemp{% \ifx\thisshortcaption\empty \thiscaption \else \thisshortcaption \fi }% }% \immediate\write\auxfile{@xrdef{\floatlabel-lof}{\floatident \ifx\gtemp\empty \else : \gtemp \fi}}% }% \fi \egroup % end of \vtop % % place the captured inserts % % BEWARE: when the floats start floating, we have to issue warning % whenever an insert appears inside a float which could possibly % float. --kasal, 26may04 % \checkinserts } % Append the tokens #2 to the definition of macro #1, not expanding either. % \def\appendtomacro#1#2{% \expandafter\def\expandafter#1\expandafter{#1#2}% } % @caption, @shortcaption % \def\caption{\docaption\thiscaption} \def\shortcaption{\docaption\thisshortcaption} \def\docaption{\checkenv\float \bgroup\scanargctxt\defcaption} \def\defcaption#1#2{\egroup \def#1{#2}} % The parameter is the control sequence identifying the counter we are % going to use. Create it if it doesn't exist and assign it to \floatno. \def\getfloatno#1{% \ifx#1\relax % Haven't seen this figure type before. \csname newcount\endcsname #1% % % Remember to reset this floatno at the next chap. \expandafter\gdef\expandafter\resetallfloatnos \expandafter{\resetallfloatnos #1=0 }% \fi \let\floatno#1% } % \setref calls this to get the XREFLABEL-snt value. We want an @xref % to the FLOATLABEL to expand to "Figure 3.1". We call \setref when we % first read the @float command. % \def\Yfloat{\floattype@tie \chaplevelprefix\the\floatno}% % Magic string used for the XREFLABEL-title value, so \xrefX can % distinguish floats from other xref types. \def\floatmagic{!!float!!} % #1 is the control sequence we are passed; we expand into a conditional % which is true if #1 represents a float ref. That is, the magic % \lastsection value which we \setref above. % \def\iffloat#1{\expandafter\doiffloat#1==\finish} % % #1 is (maybe) the \floatmagic string. If so, #2 will be the % (safe) float type for this float. We set \iffloattype to #2. % \def\doiffloat#1=#2=#3\finish{% \def\temp{#1}% \def\iffloattype{#2}% \ifx\temp\floatmagic } % @listoffloats FLOATTYPE - print a list of floats like a table of contents. % \parseargdef\listoffloats{% \def\floattype{#1}% floattype {% % the floattype might have accents or other special characters, % but we need to use it in a control sequence name. \indexnofonts \turnoffactive \xdef\safefloattype{\floattype}% }% % % \xrdef saves the floats as a \do-list in \floatlistSAFEFLOATTYPE. \expandafter\ifx\csname floatlist\safefloattype\endcsname \relax \ifhavexrefs % if the user said @listoffloats foo but never @float foo. \message{\linenumber No `\safefloattype' floats to list.}% \fi \else \begingroup \leftskip=\tocindent % indent these entries like a toc \let\do=\listoffloatsdo \csname floatlist\safefloattype\endcsname \endgroup \fi } % This is called on each entry in a list of floats. We're passed the % xref label, in the form LABEL-title, which is how we save it in the % aux file. We strip off the -title and look up \XRLABEL-lof, which % has the text we're supposed to typeset here. % % Figures without xref labels will not be included in the list (since % they won't appear in the aux file). % \def\listoffloatsdo#1{\listoffloatsdoentry#1\finish} \def\listoffloatsdoentry#1-title\finish{{% % Can't fully expand XR#1-lof because it can contain anything. Just % pass the control sequence. On the other hand, XR#1-pg is just the % page number, and we want to fully expand that so we can get a link % in pdf output. \toksA = \expandafter{\csname XR#1-lof\endcsname}% % % use the same \entry macro we use to generate the TOC and index. \edef\writeentry{\noexpand\entry{\the\toksA}{\csname XR#1-pg\endcsname}}% \writeentry }} \message{localization,} % For single-language documents, @documentlanguage is usually given very % early, just after @documentencoding. Single argument is the language % (de) or locale (de_DE) abbreviation. % { \catcode`\_ = \active \globaldefs=1 \parseargdef\documentlanguage{\begingroup \let_=\normalunderscore % normal _ character for filenames \tex % read txi-??.tex file in plain TeX. % Read the file by the name they passed if it exists. \openin 1 txi-#1.tex \ifeof 1 \documentlanguagetrywithoutunderscore{#1_\finish}% \else \globaldefs = 1 % everything in the txi-LL files needs to persist \input txi-#1.tex \fi \closein 1 \endgroup % end raw TeX \endgroup} % % If they passed de_DE, and txi-de_DE.tex doesn't exist, % try txi-de.tex. % \gdef\documentlanguagetrywithoutunderscore#1_#2\finish{% \openin 1 txi-#1.tex \ifeof 1 \errhelp = \nolanghelp \errmessage{Cannot read language file txi-#1.tex}% \else \globaldefs = 1 % everything in the txi-LL files needs to persist \input txi-#1.tex \fi \closein 1 } }% end of special _ catcode % \newhelp\nolanghelp{The given language definition file cannot be found or is empty. Maybe you need to install it? Putting it in the current directory should work if nowhere else does.} % This macro is called from txi-??.tex files; the first argument is the % \language name to set (without the "\lang@" prefix), the second and % third args are \{left,right}hyphenmin. % % The language names to pass are determined when the format is built. % See the etex.log file created at that time, e.g., % /usr/local/texlive/2008/texmf-var/web2c/pdftex/etex.log. % % With TeX Live 2008, etex now includes hyphenation patterns for all % available languages. This means we can support hyphenation in % Texinfo, at least to some extent. (This still doesn't solve the % accented characters problem.) % \catcode`@=11 \def\txisetlanguage#1#2#3{% % do not set the language if the name is undefined in the current TeX. \expandafter\ifx\csname lang@#1\endcsname \relax \message{no patterns for #1}% \else \global\language = \csname lang@#1\endcsname \fi % but there is no harm in adjusting the hyphenmin values regardless. \global\lefthyphenmin = #2\relax \global\righthyphenmin = #3\relax } % Helpers for encodings. % Set the catcode of characters 128 through 255 to the specified number. % \def\setnonasciicharscatcode#1{% \count255=128 \loop\ifnum\count255<256 \global\catcode\count255=#1\relax \advance\count255 by 1 \repeat } \def\setnonasciicharscatcodenonglobal#1{% \count255=128 \loop\ifnum\count255<256 \catcode\count255=#1\relax \advance\count255 by 1 \repeat } % @documentencoding sets the definition of non-ASCII characters % according to the specified encoding. % \parseargdef\documentencoding{% % Encoding being declared for the document. \def\declaredencoding{\csname #1.enc\endcsname}% % % Supported encodings: names converted to tokens in order to be able % to compare them with \ifx. \def\ascii{\csname US-ASCII.enc\endcsname}% \def\latnine{\csname ISO-8859-15.enc\endcsname}% \def\latone{\csname ISO-8859-1.enc\endcsname}% \def\lattwo{\csname ISO-8859-2.enc\endcsname}% \def\utfeight{\csname UTF-8.enc\endcsname}% % \ifx \declaredencoding \ascii \asciichardefs % \else \ifx \declaredencoding \lattwo \setnonasciicharscatcode\active \lattwochardefs % \else \ifx \declaredencoding \latone \setnonasciicharscatcode\active \latonechardefs % \else \ifx \declaredencoding \latnine \setnonasciicharscatcode\active \latninechardefs % \else \ifx \declaredencoding \utfeight \setnonasciicharscatcode\active \utfeightchardefs % \else \message{Unknown document encoding #1, ignoring.}% % \fi % utfeight \fi % latnine \fi % latone \fi % lattwo \fi % ascii } % A message to be logged when using a character that isn't available % the default font encoding (OT1). % \def\missingcharmsg#1{\message{Character missing in OT1 encoding: #1.}} % Take account of \c (plain) vs. \, (Texinfo) difference. \def\cedilla#1{\ifx\c\ptexc\c{#1}\else\,{#1}\fi} % First, make active non-ASCII characters in order for them to be % correctly categorized when TeX reads the replacement text of % macros containing the character definitions. \setnonasciicharscatcode\active % % Latin1 (ISO-8859-1) character definitions. \def\latonechardefs{% \gdef^^a0{\tie} \gdef^^a1{\exclamdown} \gdef^^a2{\missingcharmsg{CENT SIGN}} \gdef^^a3{{\pounds}} \gdef^^a4{\missingcharmsg{CURRENCY SIGN}} \gdef^^a5{\missingcharmsg{YEN SIGN}} \gdef^^a6{\missingcharmsg{BROKEN BAR}} \gdef^^a7{\S} \gdef^^a8{\"{}} \gdef^^a9{\copyright} \gdef^^aa{\ordf} \gdef^^ab{\guillemetleft} \gdef^^ac{$\lnot$} \gdef^^ad{\-} \gdef^^ae{\registeredsymbol} \gdef^^af{\={}} % \gdef^^b0{\textdegree} \gdef^^b1{$\pm$} \gdef^^b2{$^2$} \gdef^^b3{$^3$} \gdef^^b4{\'{}} \gdef^^b5{$\mu$} \gdef^^b6{\P} % \gdef^^b7{$^.$} \gdef^^b8{\cedilla\ } \gdef^^b9{$^1$} \gdef^^ba{\ordm} % \gdef^^bb{\guillemetright} \gdef^^bc{$1\over4$} \gdef^^bd{$1\over2$} \gdef^^be{$3\over4$} \gdef^^bf{\questiondown} % \gdef^^c0{\`A} \gdef^^c1{\'A} \gdef^^c2{\^A} \gdef^^c3{\~A} \gdef^^c4{\"A} \gdef^^c5{\ringaccent A} \gdef^^c6{\AE} \gdef^^c7{\cedilla C} \gdef^^c8{\`E} \gdef^^c9{\'E} \gdef^^ca{\^E} \gdef^^cb{\"E} \gdef^^cc{\`I} \gdef^^cd{\'I} \gdef^^ce{\^I} \gdef^^cf{\"I} % \gdef^^d0{\DH} \gdef^^d1{\~N} \gdef^^d2{\`O} \gdef^^d3{\'O} \gdef^^d4{\^O} \gdef^^d5{\~O} \gdef^^d6{\"O} \gdef^^d7{$\times$} \gdef^^d8{\O} \gdef^^d9{\`U} \gdef^^da{\'U} \gdef^^db{\^U} \gdef^^dc{\"U} \gdef^^dd{\'Y} \gdef^^de{\TH} \gdef^^df{\ss} % \gdef^^e0{\`a} \gdef^^e1{\'a} \gdef^^e2{\^a} \gdef^^e3{\~a} \gdef^^e4{\"a} \gdef^^e5{\ringaccent a} \gdef^^e6{\ae} \gdef^^e7{\cedilla c} \gdef^^e8{\`e} \gdef^^e9{\'e} \gdef^^ea{\^e} \gdef^^eb{\"e} \gdef^^ec{\`{\dotless i}} \gdef^^ed{\'{\dotless i}} \gdef^^ee{\^{\dotless i}} \gdef^^ef{\"{\dotless i}} % \gdef^^f0{\dh} \gdef^^f1{\~n} \gdef^^f2{\`o} \gdef^^f3{\'o} \gdef^^f4{\^o} \gdef^^f5{\~o} \gdef^^f6{\"o} \gdef^^f7{$\div$} \gdef^^f8{\o} \gdef^^f9{\`u} \gdef^^fa{\'u} \gdef^^fb{\^u} \gdef^^fc{\"u} \gdef^^fd{\'y} \gdef^^fe{\th} \gdef^^ff{\"y} } % Latin9 (ISO-8859-15) encoding character definitions. \def\latninechardefs{% % Encoding is almost identical to Latin1. \latonechardefs % \gdef^^a4{\euro} \gdef^^a6{\v S} \gdef^^a8{\v s} \gdef^^b4{\v Z} \gdef^^b8{\v z} \gdef^^bc{\OE} \gdef^^bd{\oe} \gdef^^be{\"Y} } % Latin2 (ISO-8859-2) character definitions. \def\lattwochardefs{% \gdef^^a0{\tie} \gdef^^a1{\ogonek{A}} \gdef^^a2{\u{}} \gdef^^a3{\L} \gdef^^a4{\missingcharmsg{CURRENCY SIGN}} \gdef^^a5{\v L} \gdef^^a6{\'S} \gdef^^a7{\S} \gdef^^a8{\"{}} \gdef^^a9{\v S} \gdef^^aa{\cedilla S} \gdef^^ab{\v T} \gdef^^ac{\'Z} \gdef^^ad{\-} \gdef^^ae{\v Z} \gdef^^af{\dotaccent Z} % \gdef^^b0{\textdegree} \gdef^^b1{\ogonek{a}} \gdef^^b2{\ogonek{ }} \gdef^^b3{\l} \gdef^^b4{\'{}} \gdef^^b5{\v l} \gdef^^b6{\'s} \gdef^^b7{\v{}} \gdef^^b8{\cedilla\ } \gdef^^b9{\v s} \gdef^^ba{\cedilla s} \gdef^^bb{\v t} \gdef^^bc{\'z} \gdef^^bd{\H{}} \gdef^^be{\v z} \gdef^^bf{\dotaccent z} % \gdef^^c0{\'R} \gdef^^c1{\'A} \gdef^^c2{\^A} \gdef^^c3{\u A} \gdef^^c4{\"A} \gdef^^c5{\'L} \gdef^^c6{\'C} \gdef^^c7{\cedilla C} \gdef^^c8{\v C} \gdef^^c9{\'E} \gdef^^ca{\ogonek{E}} \gdef^^cb{\"E} \gdef^^cc{\v E} \gdef^^cd{\'I} \gdef^^ce{\^I} \gdef^^cf{\v D} % \gdef^^d0{\DH} \gdef^^d1{\'N} \gdef^^d2{\v N} \gdef^^d3{\'O} \gdef^^d4{\^O} \gdef^^d5{\H O} \gdef^^d6{\"O} \gdef^^d7{$\times$} \gdef^^d8{\v R} \gdef^^d9{\ringaccent U} \gdef^^da{\'U} \gdef^^db{\H U} \gdef^^dc{\"U} \gdef^^dd{\'Y} \gdef^^de{\cedilla T} \gdef^^df{\ss} % \gdef^^e0{\'r} \gdef^^e1{\'a} \gdef^^e2{\^a} \gdef^^e3{\u a} \gdef^^e4{\"a} \gdef^^e5{\'l} \gdef^^e6{\'c} \gdef^^e7{\cedilla c} \gdef^^e8{\v c} \gdef^^e9{\'e} \gdef^^ea{\ogonek{e}} \gdef^^eb{\"e} \gdef^^ec{\v e} \gdef^^ed{\'{\dotless{i}}} \gdef^^ee{\^{\dotless{i}}} \gdef^^ef{\v d} % \gdef^^f0{\dh} \gdef^^f1{\'n} \gdef^^f2{\v n} \gdef^^f3{\'o} \gdef^^f4{\^o} \gdef^^f5{\H o} \gdef^^f6{\"o} \gdef^^f7{$\div$} \gdef^^f8{\v r} \gdef^^f9{\ringaccent u} \gdef^^fa{\'u} \gdef^^fb{\H u} \gdef^^fc{\"u} \gdef^^fd{\'y} \gdef^^fe{\cedilla t} \gdef^^ff{\dotaccent{}} } % UTF-8 character definitions. % % This code to support UTF-8 is based on LaTeX's utf8.def, with some % changes for Texinfo conventions. It is included here under the GPL by % permission from Frank Mittelbach and the LaTeX team. % \newcount\countUTFx \newcount\countUTFy \newcount\countUTFz \gdef\UTFviiiTwoOctets#1#2{\expandafter \UTFviiiDefined\csname u8:#1\string #2\endcsname} % \gdef\UTFviiiThreeOctets#1#2#3{\expandafter \UTFviiiDefined\csname u8:#1\string #2\string #3\endcsname} % \gdef\UTFviiiFourOctets#1#2#3#4{\expandafter \UTFviiiDefined\csname u8:#1\string #2\string #3\string #4\endcsname} \gdef\UTFviiiDefined#1{% \ifx #1\relax \message{\linenumber Unicode char \string #1 not defined for Texinfo}% \else \expandafter #1% \fi } \begingroup \catcode`\~13 \catcode`\"12 \def\UTFviiiLoop{% \global\catcode\countUTFx\active \uccode`\~\countUTFx \uppercase\expandafter{\UTFviiiTmp}% \advance\countUTFx by 1 \ifnum\countUTFx < \countUTFy \expandafter\UTFviiiLoop \fi} \countUTFx = "C2 \countUTFy = "E0 \def\UTFviiiTmp{% \xdef~{\noexpand\UTFviiiTwoOctets\string~}} \UTFviiiLoop \countUTFx = "E0 \countUTFy = "F0 \def\UTFviiiTmp{% \xdef~{\noexpand\UTFviiiThreeOctets\string~}} \UTFviiiLoop \countUTFx = "F0 \countUTFy = "F4 \def\UTFviiiTmp{% \xdef~{\noexpand\UTFviiiFourOctets\string~}} \UTFviiiLoop \endgroup \begingroup \catcode`\"=12 \catcode`\<=12 \catcode`\.=12 \catcode`\,=12 \catcode`\;=12 \catcode`\!=12 \catcode`\~=13 \gdef\DeclareUnicodeCharacter#1#2{% \countUTFz = "#1\relax %\wlog{\space\space defining Unicode char U+#1 (decimal \the\countUTFz)}% \begingroup \parseXMLCharref \def\UTFviiiTwoOctets##1##2{% \csname u8:##1\string ##2\endcsname}% \def\UTFviiiThreeOctets##1##2##3{% \csname u8:##1\string ##2\string ##3\endcsname}% \def\UTFviiiFourOctets##1##2##3##4{% \csname u8:##1\string ##2\string ##3\string ##4\endcsname}% \expandafter\expandafter\expandafter\expandafter \expandafter\expandafter\expandafter \gdef\UTFviiiTmp{#2}% \endgroup} \gdef\parseXMLCharref{% \ifnum\countUTFz < "A0\relax \errhelp = \EMsimple \errmessage{Cannot define Unicode char value < 00A0}% \else\ifnum\countUTFz < "800\relax \parseUTFviiiA,% \parseUTFviiiB C\UTFviiiTwoOctets.,% \else\ifnum\countUTFz < "10000\relax \parseUTFviiiA;% \parseUTFviiiA,% \parseUTFviiiB E\UTFviiiThreeOctets.{,;}% \else \parseUTFviiiA;% \parseUTFviiiA,% \parseUTFviiiA!% \parseUTFviiiB F\UTFviiiFourOctets.{!,;}% \fi\fi\fi } \gdef\parseUTFviiiA#1{% \countUTFx = \countUTFz \divide\countUTFz by 64 \countUTFy = \countUTFz \multiply\countUTFz by 64 \advance\countUTFx by -\countUTFz \advance\countUTFx by 128 \uccode `#1\countUTFx \countUTFz = \countUTFy} \gdef\parseUTFviiiB#1#2#3#4{% \advance\countUTFz by "#10\relax \uccode `#3\countUTFz \uppercase{\gdef\UTFviiiTmp{#2#3#4}}} \endgroup \def\utfeightchardefs{% \DeclareUnicodeCharacter{00A0}{\tie} \DeclareUnicodeCharacter{00A1}{\exclamdown} \DeclareUnicodeCharacter{00A3}{\pounds} \DeclareUnicodeCharacter{00A8}{\"{ }} \DeclareUnicodeCharacter{00A9}{\copyright} \DeclareUnicodeCharacter{00AA}{\ordf} \DeclareUnicodeCharacter{00AB}{\guillemetleft} \DeclareUnicodeCharacter{00AD}{\-} \DeclareUnicodeCharacter{00AE}{\registeredsymbol} \DeclareUnicodeCharacter{00AF}{\={ }} \DeclareUnicodeCharacter{00B0}{\ringaccent{ }} \DeclareUnicodeCharacter{00B4}{\'{ }} \DeclareUnicodeCharacter{00B8}{\cedilla{ }} \DeclareUnicodeCharacter{00BA}{\ordm} \DeclareUnicodeCharacter{00BB}{\guillemetright} \DeclareUnicodeCharacter{00BF}{\questiondown} \DeclareUnicodeCharacter{00C0}{\`A} \DeclareUnicodeCharacter{00C1}{\'A} \DeclareUnicodeCharacter{00C2}{\^A} \DeclareUnicodeCharacter{00C3}{\~A} \DeclareUnicodeCharacter{00C4}{\"A} \DeclareUnicodeCharacter{00C5}{\AA} \DeclareUnicodeCharacter{00C6}{\AE} \DeclareUnicodeCharacter{00C7}{\cedilla{C}} \DeclareUnicodeCharacter{00C8}{\`E} \DeclareUnicodeCharacter{00C9}{\'E} \DeclareUnicodeCharacter{00CA}{\^E} \DeclareUnicodeCharacter{00CB}{\"E} \DeclareUnicodeCharacter{00CC}{\`I} \DeclareUnicodeCharacter{00CD}{\'I} \DeclareUnicodeCharacter{00CE}{\^I} \DeclareUnicodeCharacter{00CF}{\"I} \DeclareUnicodeCharacter{00D0}{\DH} \DeclareUnicodeCharacter{00D1}{\~N} \DeclareUnicodeCharacter{00D2}{\`O} \DeclareUnicodeCharacter{00D3}{\'O} \DeclareUnicodeCharacter{00D4}{\^O} \DeclareUnicodeCharacter{00D5}{\~O} \DeclareUnicodeCharacter{00D6}{\"O} \DeclareUnicodeCharacter{00D8}{\O} \DeclareUnicodeCharacter{00D9}{\`U} \DeclareUnicodeCharacter{00DA}{\'U} \DeclareUnicodeCharacter{00DB}{\^U} \DeclareUnicodeCharacter{00DC}{\"U} \DeclareUnicodeCharacter{00DD}{\'Y} \DeclareUnicodeCharacter{00DE}{\TH} \DeclareUnicodeCharacter{00DF}{\ss} \DeclareUnicodeCharacter{00E0}{\`a} \DeclareUnicodeCharacter{00E1}{\'a} \DeclareUnicodeCharacter{00E2}{\^a} \DeclareUnicodeCharacter{00E3}{\~a} \DeclareUnicodeCharacter{00E4}{\"a} \DeclareUnicodeCharacter{00E5}{\aa} \DeclareUnicodeCharacter{00E6}{\ae} \DeclareUnicodeCharacter{00E7}{\cedilla{c}} \DeclareUnicodeCharacter{00E8}{\`e} \DeclareUnicodeCharacter{00E9}{\'e} \DeclareUnicodeCharacter{00EA}{\^e} \DeclareUnicodeCharacter{00EB}{\"e} \DeclareUnicodeCharacter{00EC}{\`{\dotless{i}}} \DeclareUnicodeCharacter{00ED}{\'{\dotless{i}}} \DeclareUnicodeCharacter{00EE}{\^{\dotless{i}}} \DeclareUnicodeCharacter{00EF}{\"{\dotless{i}}} \DeclareUnicodeCharacter{00F0}{\dh} \DeclareUnicodeCharacter{00F1}{\~n} \DeclareUnicodeCharacter{00F2}{\`o} \DeclareUnicodeCharacter{00F3}{\'o} \DeclareUnicodeCharacter{00F4}{\^o} \DeclareUnicodeCharacter{00F5}{\~o} \DeclareUnicodeCharacter{00F6}{\"o} \DeclareUnicodeCharacter{00F8}{\o} \DeclareUnicodeCharacter{00F9}{\`u} \DeclareUnicodeCharacter{00FA}{\'u} \DeclareUnicodeCharacter{00FB}{\^u} \DeclareUnicodeCharacter{00FC}{\"u} \DeclareUnicodeCharacter{00FD}{\'y} \DeclareUnicodeCharacter{00FE}{\th} \DeclareUnicodeCharacter{00FF}{\"y} \DeclareUnicodeCharacter{0100}{\=A} \DeclareUnicodeCharacter{0101}{\=a} \DeclareUnicodeCharacter{0102}{\u{A}} \DeclareUnicodeCharacter{0103}{\u{a}} \DeclareUnicodeCharacter{0104}{\ogonek{A}} \DeclareUnicodeCharacter{0105}{\ogonek{a}} \DeclareUnicodeCharacter{0106}{\'C} \DeclareUnicodeCharacter{0107}{\'c} \DeclareUnicodeCharacter{0108}{\^C} \DeclareUnicodeCharacter{0109}{\^c} \DeclareUnicodeCharacter{0118}{\ogonek{E}} \DeclareUnicodeCharacter{0119}{\ogonek{e}} \DeclareUnicodeCharacter{010A}{\dotaccent{C}} \DeclareUnicodeCharacter{010B}{\dotaccent{c}} \DeclareUnicodeCharacter{010C}{\v{C}} \DeclareUnicodeCharacter{010D}{\v{c}} \DeclareUnicodeCharacter{010E}{\v{D}} \DeclareUnicodeCharacter{0112}{\=E} \DeclareUnicodeCharacter{0113}{\=e} \DeclareUnicodeCharacter{0114}{\u{E}} \DeclareUnicodeCharacter{0115}{\u{e}} \DeclareUnicodeCharacter{0116}{\dotaccent{E}} \DeclareUnicodeCharacter{0117}{\dotaccent{e}} \DeclareUnicodeCharacter{011A}{\v{E}} \DeclareUnicodeCharacter{011B}{\v{e}} \DeclareUnicodeCharacter{011C}{\^G} \DeclareUnicodeCharacter{011D}{\^g} \DeclareUnicodeCharacter{011E}{\u{G}} \DeclareUnicodeCharacter{011F}{\u{g}} \DeclareUnicodeCharacter{0120}{\dotaccent{G}} \DeclareUnicodeCharacter{0121}{\dotaccent{g}} \DeclareUnicodeCharacter{0124}{\^H} \DeclareUnicodeCharacter{0125}{\^h} \DeclareUnicodeCharacter{0128}{\~I} \DeclareUnicodeCharacter{0129}{\~{\dotless{i}}} \DeclareUnicodeCharacter{012A}{\=I} \DeclareUnicodeCharacter{012B}{\={\dotless{i}}} \DeclareUnicodeCharacter{012C}{\u{I}} \DeclareUnicodeCharacter{012D}{\u{\dotless{i}}} \DeclareUnicodeCharacter{0130}{\dotaccent{I}} \DeclareUnicodeCharacter{0131}{\dotless{i}} \DeclareUnicodeCharacter{0132}{IJ} \DeclareUnicodeCharacter{0133}{ij} \DeclareUnicodeCharacter{0134}{\^J} \DeclareUnicodeCharacter{0135}{\^{\dotless{j}}} \DeclareUnicodeCharacter{0139}{\'L} \DeclareUnicodeCharacter{013A}{\'l} \DeclareUnicodeCharacter{0141}{\L} \DeclareUnicodeCharacter{0142}{\l} \DeclareUnicodeCharacter{0143}{\'N} \DeclareUnicodeCharacter{0144}{\'n} \DeclareUnicodeCharacter{0147}{\v{N}} \DeclareUnicodeCharacter{0148}{\v{n}} \DeclareUnicodeCharacter{014C}{\=O} \DeclareUnicodeCharacter{014D}{\=o} \DeclareUnicodeCharacter{014E}{\u{O}} \DeclareUnicodeCharacter{014F}{\u{o}} \DeclareUnicodeCharacter{0150}{\H{O}} \DeclareUnicodeCharacter{0151}{\H{o}} \DeclareUnicodeCharacter{0152}{\OE} \DeclareUnicodeCharacter{0153}{\oe} \DeclareUnicodeCharacter{0154}{\'R} \DeclareUnicodeCharacter{0155}{\'r} \DeclareUnicodeCharacter{0158}{\v{R}} \DeclareUnicodeCharacter{0159}{\v{r}} \DeclareUnicodeCharacter{015A}{\'S} \DeclareUnicodeCharacter{015B}{\'s} \DeclareUnicodeCharacter{015C}{\^S} \DeclareUnicodeCharacter{015D}{\^s} \DeclareUnicodeCharacter{015E}{\cedilla{S}} \DeclareUnicodeCharacter{015F}{\cedilla{s}} \DeclareUnicodeCharacter{0160}{\v{S}} \DeclareUnicodeCharacter{0161}{\v{s}} \DeclareUnicodeCharacter{0162}{\cedilla{t}} \DeclareUnicodeCharacter{0163}{\cedilla{T}} \DeclareUnicodeCharacter{0164}{\v{T}} \DeclareUnicodeCharacter{0168}{\~U} \DeclareUnicodeCharacter{0169}{\~u} \DeclareUnicodeCharacter{016A}{\=U} \DeclareUnicodeCharacter{016B}{\=u} \DeclareUnicodeCharacter{016C}{\u{U}} \DeclareUnicodeCharacter{016D}{\u{u}} \DeclareUnicodeCharacter{016E}{\ringaccent{U}} \DeclareUnicodeCharacter{016F}{\ringaccent{u}} \DeclareUnicodeCharacter{0170}{\H{U}} \DeclareUnicodeCharacter{0171}{\H{u}} \DeclareUnicodeCharacter{0174}{\^W} \DeclareUnicodeCharacter{0175}{\^w} \DeclareUnicodeCharacter{0176}{\^Y} \DeclareUnicodeCharacter{0177}{\^y} \DeclareUnicodeCharacter{0178}{\"Y} \DeclareUnicodeCharacter{0179}{\'Z} \DeclareUnicodeCharacter{017A}{\'z} \DeclareUnicodeCharacter{017B}{\dotaccent{Z}} \DeclareUnicodeCharacter{017C}{\dotaccent{z}} \DeclareUnicodeCharacter{017D}{\v{Z}} \DeclareUnicodeCharacter{017E}{\v{z}} \DeclareUnicodeCharacter{01C4}{D\v{Z}} \DeclareUnicodeCharacter{01C5}{D\v{z}} \DeclareUnicodeCharacter{01C6}{d\v{z}} \DeclareUnicodeCharacter{01C7}{LJ} \DeclareUnicodeCharacter{01C8}{Lj} \DeclareUnicodeCharacter{01C9}{lj} \DeclareUnicodeCharacter{01CA}{NJ} \DeclareUnicodeCharacter{01CB}{Nj} \DeclareUnicodeCharacter{01CC}{nj} \DeclareUnicodeCharacter{01CD}{\v{A}} \DeclareUnicodeCharacter{01CE}{\v{a}} \DeclareUnicodeCharacter{01CF}{\v{I}} \DeclareUnicodeCharacter{01D0}{\v{\dotless{i}}} \DeclareUnicodeCharacter{01D1}{\v{O}} \DeclareUnicodeCharacter{01D2}{\v{o}} \DeclareUnicodeCharacter{01D3}{\v{U}} \DeclareUnicodeCharacter{01D4}{\v{u}} \DeclareUnicodeCharacter{01E2}{\={\AE}} \DeclareUnicodeCharacter{01E3}{\={\ae}} \DeclareUnicodeCharacter{01E6}{\v{G}} \DeclareUnicodeCharacter{01E7}{\v{g}} \DeclareUnicodeCharacter{01E8}{\v{K}} \DeclareUnicodeCharacter{01E9}{\v{k}} \DeclareUnicodeCharacter{01F0}{\v{\dotless{j}}} \DeclareUnicodeCharacter{01F1}{DZ} \DeclareUnicodeCharacter{01F2}{Dz} \DeclareUnicodeCharacter{01F3}{dz} \DeclareUnicodeCharacter{01F4}{\'G} \DeclareUnicodeCharacter{01F5}{\'g} \DeclareUnicodeCharacter{01F8}{\`N} \DeclareUnicodeCharacter{01F9}{\`n} \DeclareUnicodeCharacter{01FC}{\'{\AE}} \DeclareUnicodeCharacter{01FD}{\'{\ae}} \DeclareUnicodeCharacter{01FE}{\'{\O}} \DeclareUnicodeCharacter{01FF}{\'{\o}} \DeclareUnicodeCharacter{021E}{\v{H}} \DeclareUnicodeCharacter{021F}{\v{h}} \DeclareUnicodeCharacter{0226}{\dotaccent{A}} \DeclareUnicodeCharacter{0227}{\dotaccent{a}} \DeclareUnicodeCharacter{0228}{\cedilla{E}} \DeclareUnicodeCharacter{0229}{\cedilla{e}} \DeclareUnicodeCharacter{022E}{\dotaccent{O}} \DeclareUnicodeCharacter{022F}{\dotaccent{o}} \DeclareUnicodeCharacter{0232}{\=Y} \DeclareUnicodeCharacter{0233}{\=y} \DeclareUnicodeCharacter{0237}{\dotless{j}} \DeclareUnicodeCharacter{02DB}{\ogonek{ }} \DeclareUnicodeCharacter{1E02}{\dotaccent{B}} \DeclareUnicodeCharacter{1E03}{\dotaccent{b}} \DeclareUnicodeCharacter{1E04}{\udotaccent{B}} \DeclareUnicodeCharacter{1E05}{\udotaccent{b}} \DeclareUnicodeCharacter{1E06}{\ubaraccent{B}} \DeclareUnicodeCharacter{1E07}{\ubaraccent{b}} \DeclareUnicodeCharacter{1E0A}{\dotaccent{D}} \DeclareUnicodeCharacter{1E0B}{\dotaccent{d}} \DeclareUnicodeCharacter{1E0C}{\udotaccent{D}} \DeclareUnicodeCharacter{1E0D}{\udotaccent{d}} \DeclareUnicodeCharacter{1E0E}{\ubaraccent{D}} \DeclareUnicodeCharacter{1E0F}{\ubaraccent{d}} \DeclareUnicodeCharacter{1E1E}{\dotaccent{F}} \DeclareUnicodeCharacter{1E1F}{\dotaccent{f}} \DeclareUnicodeCharacter{1E20}{\=G} \DeclareUnicodeCharacter{1E21}{\=g} \DeclareUnicodeCharacter{1E22}{\dotaccent{H}} \DeclareUnicodeCharacter{1E23}{\dotaccent{h}} \DeclareUnicodeCharacter{1E24}{\udotaccent{H}} \DeclareUnicodeCharacter{1E25}{\udotaccent{h}} \DeclareUnicodeCharacter{1E26}{\"H} \DeclareUnicodeCharacter{1E27}{\"h} \DeclareUnicodeCharacter{1E30}{\'K} \DeclareUnicodeCharacter{1E31}{\'k} \DeclareUnicodeCharacter{1E32}{\udotaccent{K}} \DeclareUnicodeCharacter{1E33}{\udotaccent{k}} \DeclareUnicodeCharacter{1E34}{\ubaraccent{K}} \DeclareUnicodeCharacter{1E35}{\ubaraccent{k}} \DeclareUnicodeCharacter{1E36}{\udotaccent{L}} \DeclareUnicodeCharacter{1E37}{\udotaccent{l}} \DeclareUnicodeCharacter{1E3A}{\ubaraccent{L}} \DeclareUnicodeCharacter{1E3B}{\ubaraccent{l}} \DeclareUnicodeCharacter{1E3E}{\'M} \DeclareUnicodeCharacter{1E3F}{\'m} \DeclareUnicodeCharacter{1E40}{\dotaccent{M}} \DeclareUnicodeCharacter{1E41}{\dotaccent{m}} \DeclareUnicodeCharacter{1E42}{\udotaccent{M}} \DeclareUnicodeCharacter{1E43}{\udotaccent{m}} \DeclareUnicodeCharacter{1E44}{\dotaccent{N}} \DeclareUnicodeCharacter{1E45}{\dotaccent{n}} \DeclareUnicodeCharacter{1E46}{\udotaccent{N}} \DeclareUnicodeCharacter{1E47}{\udotaccent{n}} \DeclareUnicodeCharacter{1E48}{\ubaraccent{N}} \DeclareUnicodeCharacter{1E49}{\ubaraccent{n}} \DeclareUnicodeCharacter{1E54}{\'P} \DeclareUnicodeCharacter{1E55}{\'p} \DeclareUnicodeCharacter{1E56}{\dotaccent{P}} \DeclareUnicodeCharacter{1E57}{\dotaccent{p}} \DeclareUnicodeCharacter{1E58}{\dotaccent{R}} \DeclareUnicodeCharacter{1E59}{\dotaccent{r}} \DeclareUnicodeCharacter{1E5A}{\udotaccent{R}} \DeclareUnicodeCharacter{1E5B}{\udotaccent{r}} \DeclareUnicodeCharacter{1E5E}{\ubaraccent{R}} \DeclareUnicodeCharacter{1E5F}{\ubaraccent{r}} \DeclareUnicodeCharacter{1E60}{\dotaccent{S}} \DeclareUnicodeCharacter{1E61}{\dotaccent{s}} \DeclareUnicodeCharacter{1E62}{\udotaccent{S}} \DeclareUnicodeCharacter{1E63}{\udotaccent{s}} \DeclareUnicodeCharacter{1E6A}{\dotaccent{T}} \DeclareUnicodeCharacter{1E6B}{\dotaccent{t}} \DeclareUnicodeCharacter{1E6C}{\udotaccent{T}} \DeclareUnicodeCharacter{1E6D}{\udotaccent{t}} \DeclareUnicodeCharacter{1E6E}{\ubaraccent{T}} \DeclareUnicodeCharacter{1E6F}{\ubaraccent{t}} \DeclareUnicodeCharacter{1E7C}{\~V} \DeclareUnicodeCharacter{1E7D}{\~v} \DeclareUnicodeCharacter{1E7E}{\udotaccent{V}} \DeclareUnicodeCharacter{1E7F}{\udotaccent{v}} \DeclareUnicodeCharacter{1E80}{\`W} \DeclareUnicodeCharacter{1E81}{\`w} \DeclareUnicodeCharacter{1E82}{\'W} \DeclareUnicodeCharacter{1E83}{\'w} \DeclareUnicodeCharacter{1E84}{\"W} \DeclareUnicodeCharacter{1E85}{\"w} \DeclareUnicodeCharacter{1E86}{\dotaccent{W}} \DeclareUnicodeCharacter{1E87}{\dotaccent{w}} \DeclareUnicodeCharacter{1E88}{\udotaccent{W}} \DeclareUnicodeCharacter{1E89}{\udotaccent{w}} \DeclareUnicodeCharacter{1E8A}{\dotaccent{X}} \DeclareUnicodeCharacter{1E8B}{\dotaccent{x}} \DeclareUnicodeCharacter{1E8C}{\"X} \DeclareUnicodeCharacter{1E8D}{\"x} \DeclareUnicodeCharacter{1E8E}{\dotaccent{Y}} \DeclareUnicodeCharacter{1E8F}{\dotaccent{y}} \DeclareUnicodeCharacter{1E90}{\^Z} \DeclareUnicodeCharacter{1E91}{\^z} \DeclareUnicodeCharacter{1E92}{\udotaccent{Z}} \DeclareUnicodeCharacter{1E93}{\udotaccent{z}} \DeclareUnicodeCharacter{1E94}{\ubaraccent{Z}} \DeclareUnicodeCharacter{1E95}{\ubaraccent{z}} \DeclareUnicodeCharacter{1E96}{\ubaraccent{h}} \DeclareUnicodeCharacter{1E97}{\"t} \DeclareUnicodeCharacter{1E98}{\ringaccent{w}} \DeclareUnicodeCharacter{1E99}{\ringaccent{y}} \DeclareUnicodeCharacter{1EA0}{\udotaccent{A}} \DeclareUnicodeCharacter{1EA1}{\udotaccent{a}} \DeclareUnicodeCharacter{1EB8}{\udotaccent{E}} \DeclareUnicodeCharacter{1EB9}{\udotaccent{e}} \DeclareUnicodeCharacter{1EBC}{\~E} \DeclareUnicodeCharacter{1EBD}{\~e} \DeclareUnicodeCharacter{1ECA}{\udotaccent{I}} \DeclareUnicodeCharacter{1ECB}{\udotaccent{i}} \DeclareUnicodeCharacter{1ECC}{\udotaccent{O}} \DeclareUnicodeCharacter{1ECD}{\udotaccent{o}} \DeclareUnicodeCharacter{1EE4}{\udotaccent{U}} \DeclareUnicodeCharacter{1EE5}{\udotaccent{u}} \DeclareUnicodeCharacter{1EF2}{\`Y} \DeclareUnicodeCharacter{1EF3}{\`y} \DeclareUnicodeCharacter{1EF4}{\udotaccent{Y}} \DeclareUnicodeCharacter{1EF8}{\~Y} \DeclareUnicodeCharacter{1EF9}{\~y} \DeclareUnicodeCharacter{2013}{--} \DeclareUnicodeCharacter{2014}{---} \DeclareUnicodeCharacter{2018}{\quoteleft} \DeclareUnicodeCharacter{2019}{\quoteright} \DeclareUnicodeCharacter{201A}{\quotesinglbase} \DeclareUnicodeCharacter{201C}{\quotedblleft} \DeclareUnicodeCharacter{201D}{\quotedblright} \DeclareUnicodeCharacter{201E}{\quotedblbase} \DeclareUnicodeCharacter{2022}{\bullet} \DeclareUnicodeCharacter{2026}{\dots} \DeclareUnicodeCharacter{2039}{\guilsinglleft} \DeclareUnicodeCharacter{203A}{\guilsinglright} \DeclareUnicodeCharacter{20AC}{\euro} \DeclareUnicodeCharacter{2192}{\expansion} \DeclareUnicodeCharacter{21D2}{\result} \DeclareUnicodeCharacter{2212}{\minus} \DeclareUnicodeCharacter{2217}{\point} \DeclareUnicodeCharacter{2261}{\equiv} }% end of \utfeightchardefs % US-ASCII character definitions. \def\asciichardefs{% nothing need be done \relax } % Make non-ASCII characters printable again for compatibility with % existing Texinfo documents that may use them, even without declaring a % document encoding. % \setnonasciicharscatcode \other \message{formatting,} \newdimen\defaultparindent \defaultparindent = 15pt \chapheadingskip = 15pt plus 4pt minus 2pt \secheadingskip = 12pt plus 3pt minus 2pt \subsecheadingskip = 9pt plus 2pt minus 2pt % Prevent underfull vbox error messages. \vbadness = 10000 % Don't be very finicky about underfull hboxes, either. \hbadness = 6666 % Following George Bush, get rid of widows and orphans. \widowpenalty=10000 \clubpenalty=10000 % Use TeX 3.0's \emergencystretch to help line breaking, but if we're % using an old version of TeX, don't do anything. We want the amount of % stretch added to depend on the line length, hence the dependence on % \hsize. We call this whenever the paper size is set. % \def\setemergencystretch{% \ifx\emergencystretch\thisisundefined % Allow us to assign to \emergencystretch anyway. \def\emergencystretch{\dimen0}% \else \emergencystretch = .15\hsize \fi } % Parameters in order: 1) textheight; 2) textwidth; % 3) voffset; 4) hoffset; 5) binding offset; 6) topskip; % 7) physical page height; 8) physical page width. % % We also call \setleading{\textleading}, so the caller should define % \textleading. The caller should also set \parskip. % \def\internalpagesizes#1#2#3#4#5#6#7#8{% \voffset = #3\relax \topskip = #6\relax \splittopskip = \topskip % \vsize = #1\relax \advance\vsize by \topskip \outervsize = \vsize \advance\outervsize by 2\topandbottommargin \pageheight = \vsize % \hsize = #2\relax \outerhsize = \hsize \advance\outerhsize by 0.5in \pagewidth = \hsize % \normaloffset = #4\relax \bindingoffset = #5\relax % \ifpdf \pdfpageheight #7\relax \pdfpagewidth #8\relax % if we don't reset these, they will remain at "1 true in" of % whatever layout pdftex was dumped with. \pdfhorigin = 1 true in \pdfvorigin = 1 true in \fi % \setleading{\textleading} % \parindent = \defaultparindent \setemergencystretch } % @letterpaper (the default). \def\letterpaper{{\globaldefs = 1 \parskip = 3pt plus 2pt minus 1pt \textleading = 13.2pt % % If page is nothing but text, make it come out even. \internalpagesizes{607.2pt}{6in}% that's 46 lines {\voffset}{.25in}% {\bindingoffset}{36pt}% {11in}{8.5in}% }} % Use @smallbook to reset parameters for 7x9.25 trim size. \def\smallbook{{\globaldefs = 1 \parskip = 2pt plus 1pt \textleading = 12pt % \internalpagesizes{7.5in}{5in}% {-.2in}{0in}% {\bindingoffset}{16pt}% {9.25in}{7in}% % \lispnarrowing = 0.3in \tolerance = 700 \hfuzz = 1pt \contentsrightmargin = 0pt \defbodyindent = .5cm }} % Use @smallerbook to reset parameters for 6x9 trim size. % (Just testing, parameters still in flux.) \def\smallerbook{{\globaldefs = 1 \parskip = 1.5pt plus 1pt \textleading = 12pt % \internalpagesizes{7.4in}{4.8in}% {-.2in}{-.4in}% {0pt}{14pt}% {9in}{6in}% % \lispnarrowing = 0.25in \tolerance = 700 \hfuzz = 1pt \contentsrightmargin = 0pt \defbodyindent = .4cm }} % Use @afourpaper to print on European A4 paper. \def\afourpaper{{\globaldefs = 1 \parskip = 3pt plus 2pt minus 1pt \textleading = 13.2pt % % Double-side printing via postscript on Laserjet 4050 % prints double-sided nicely when \bindingoffset=10mm and \hoffset=-6mm. % To change the settings for a different printer or situation, adjust % \normaloffset until the front-side and back-side texts align. Then % do the same for \bindingoffset. You can set these for testing in % your texinfo source file like this: % @tex % \global\normaloffset = -6mm % \global\bindingoffset = 10mm % @end tex \internalpagesizes{673.2pt}{160mm}% that's 51 lines {\voffset}{\hoffset}% {\bindingoffset}{44pt}% {297mm}{210mm}% % \tolerance = 700 \hfuzz = 1pt \contentsrightmargin = 0pt \defbodyindent = 5mm }} % Use @afivepaper to print on European A5 paper. % From romildo@urano.iceb.ufop.br, 2 July 2000. % He also recommends making @example and @lisp be small. \def\afivepaper{{\globaldefs = 1 \parskip = 2pt plus 1pt minus 0.1pt \textleading = 12.5pt % \internalpagesizes{160mm}{120mm}% {\voffset}{\hoffset}% {\bindingoffset}{8pt}% {210mm}{148mm}% % \lispnarrowing = 0.2in \tolerance = 800 \hfuzz = 1.2pt \contentsrightmargin = 0pt \defbodyindent = 2mm \tableindent = 12mm }} % A specific text layout, 24x15cm overall, intended for A4 paper. \def\afourlatex{{\globaldefs = 1 \afourpaper \internalpagesizes{237mm}{150mm}% {\voffset}{4.6mm}% {\bindingoffset}{7mm}% {297mm}{210mm}% % % Must explicitly reset to 0 because we call \afourpaper. \globaldefs = 0 }} % Use @afourwide to print on A4 paper in landscape format. \def\afourwide{{\globaldefs = 1 \afourpaper \internalpagesizes{241mm}{165mm}% {\voffset}{-2.95mm}% {\bindingoffset}{7mm}% {297mm}{210mm}% \globaldefs = 0 }} % @pagesizes TEXTHEIGHT[,TEXTWIDTH] % Perhaps we should allow setting the margins, \topskip, \parskip, % and/or leading, also. Or perhaps we should compute them somehow. % \parseargdef\pagesizes{\pagesizesyyy #1,,\finish} \def\pagesizesyyy#1,#2,#3\finish{{% \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \hsize=#2\relax \fi \globaldefs = 1 % \parskip = 3pt plus 2pt minus 1pt \setleading{\textleading}% % \dimen0 = #1\relax \advance\dimen0 by \voffset % \dimen2 = \hsize \advance\dimen2 by \normaloffset % \internalpagesizes{#1}{\hsize}% {\voffset}{\normaloffset}% {\bindingoffset}{44pt}% {\dimen0}{\dimen2}% }} % Set default to letter. % \letterpaper \message{and turning on texinfo input format.} \def^^L{\par} % remove \outer, so ^L can appear in an @comment % DEL is a comment character, in case @c does not suffice. \catcode`\^^? = 14 % Define macros to output various characters with catcode for normal text. \catcode`\"=\other \def\normaldoublequote{"} \catcode`\$=\other \def\normaldollar{$}%$ font-lock fix \catcode`\+=\other \def\normalplus{+} \catcode`\<=\other \def\normalless{<} \catcode`\>=\other \def\normalgreater{>} \catcode`\^=\other \def\normalcaret{^} \catcode`\_=\other \def\normalunderscore{_} \catcode`\|=\other \def\normalverticalbar{|} \catcode`\~=\other \def\normaltilde{~} % This macro is used to make a character print one way in \tt % (where it can probably be output as-is), and another way in other fonts, % where something hairier probably needs to be done. % % #1 is what to print if we are indeed using \tt; #2 is what to print % otherwise. Since all the Computer Modern typewriter fonts have zero % interword stretch (and shrink), and it is reasonable to expect all % typewriter fonts to have this, we can check that font parameter. % \def\ifusingtt#1#2{\ifdim \fontdimen3\font=0pt #1\else #2\fi} % Same as above, but check for italic font. Actually this also catches % non-italic slanted fonts since it is impossible to distinguish them from % italic fonts. But since this is only used by $ and it uses \sl anyway % this is not a problem. \def\ifusingit#1#2{\ifdim \fontdimen1\font>0pt #1\else #2\fi} % Turn off all special characters except @ % (and those which the user can use as if they were ordinary). % Most of these we simply print from the \tt font, but for some, we can % use math or other variants that look better in normal text. \catcode`\"=\active \def\activedoublequote{{\tt\char34}} \let"=\activedoublequote \catcode`\~=\active \def~{{\tt\char126}} \chardef\hat=`\^ \catcode`\^=\active \def^{{\tt \hat}} \catcode`\_=\active \def_{\ifusingtt\normalunderscore\_} \let\realunder=_ % Subroutine for the previous macro. \def\_{\leavevmode \kern.07em \vbox{\hrule width.3em height.1ex}\kern .07em } \catcode`\|=\active \def|{{\tt\char124}} \chardef \less=`\< \catcode`\<=\active \def<{{\tt \less}} \chardef \gtr=`\> \catcode`\>=\active \def>{{\tt \gtr}} \catcode`\+=\active \def+{{\tt \char 43}} \catcode`\$=\active \def${\ifusingit{{\sl\$}}\normaldollar}%$ font-lock fix % If a .fmt file is being used, characters that might appear in a file % name cannot be active until we have parsed the command line. % So turn them off again, and have \everyjob (or @setfilename) turn them on. % \otherifyactive is called near the end of this file. \def\otherifyactive{\catcode`+=\other \catcode`\_=\other} % Used sometimes to turn off (effectively) the active characters even after % parsing them. \def\turnoffactive{% \normalturnoffactive \otherbackslash } \catcode`\@=0 % \backslashcurfont outputs one backslash character in current font, % as in \char`\\. \global\chardef\backslashcurfont=`\\ \global\let\rawbackslashxx=\backslashcurfont % let existing .??s files work % \realbackslash is an actual character `\' with catcode other, and % \doublebackslash is two of them (for the pdf outlines). {\catcode`\\=\other @gdef@realbackslash{\} @gdef@doublebackslash{\\}} % In texinfo, backslash is an active character; it prints the backslash % in fixed width font. \catcode`\\=\active % @ for escape char from now on. % The story here is that in math mode, the \char of \backslashcurfont % ends up printing the roman \ from the math symbol font (because \char % in math mode uses the \mathcode, and plain.tex sets % \mathcode`\\="026E). It seems better for @backslashchar{} to always % print a typewriter backslash, hence we use an explicit \mathchar, % which is the decimal equivalent of "715c (class 7, e.g., use \fam; % ignored family value; char position "5C). We can't use " for the % usual hex value because it has already been made active. @def@normalbackslash{{@tt @ifmmode @mathchar29020 @else @backslashcurfont @fi}} @let@backslashchar = @normalbackslash % @backslashchar{} is for user documents. % On startup, @fixbackslash assigns: % @let \ = @normalbackslash % \rawbackslash defines an active \ to do \backslashcurfont. % \otherbackslash defines an active \ to be a literal `\' character with % catcode other. We switch back and forth between these. @gdef@rawbackslash{@let\=@backslashcurfont} @gdef@otherbackslash{@let\=@realbackslash} % Same as @turnoffactive except outputs \ as {\tt\char`\\} instead of % the literal character `\'. % @def@normalturnoffactive{% @let"=@normaldoublequote @let$=@normaldollar %$ font-lock fix @let+=@normalplus @let<=@normalless @let>=@normalgreater @let\=@normalbackslash @let^=@normalcaret @let_=@normalunderscore @let|=@normalverticalbar @let~=@normaltilde @markupsetuplqdefault @markupsetuprqdefault @unsepspaces } % Make _ and + \other characters, temporarily. % This is canceled by @fixbackslash. @otherifyactive % If a .fmt file is being used, we don't want the `\input texinfo' to show up. % That is what \eatinput is for; after that, the `\' should revert to printing % a backslash. % @gdef@eatinput input texinfo{@fixbackslash} @global@let\ = @eatinput % On the other hand, perhaps the file did not have a `\input texinfo'. Then % the first `\' in the file would cause an error. This macro tries to fix % that, assuming it is called before the first `\' could plausibly occur. % Also turn back on active characters that might appear in the input % file name, in case not using a pre-dumped format. % @gdef@fixbackslash{% @ifx\@eatinput @let\ = @normalbackslash @fi @catcode`+=@active @catcode`@_=@active } % Say @foo, not \foo, in error messages. @escapechar = `@@ % These (along with & and #) are made active for url-breaking, so need % active definitions as the normal characters. @def@normaldot{.} @def@normalquest{?} @def@normalslash{/} % These look ok in all fonts, so just make them not special. % @hashchar{} gets its own user-level command, because of #line. @catcode`@& = @other @def@normalamp{&} @catcode`@# = @other @def@normalhash{#} @catcode`@% = @other @def@normalpercent{%} @let @hashchar = @normalhash @c Finally, make ` and ' active, so that txicodequoteundirected and @c txicodequotebacktick work right in, e.g., @w{@code{`foo'}}. If we @c don't make ` and ' active, @code will not get them as active chars. @c Do this last of all since we use ` in the previous @catcode assignments. @catcode`@'=@active @catcode`@`=@active @markupsetuplqdefault @markupsetuprqdefault @c Local variables: @c eval: (add-hook 'write-file-hooks 'time-stamp) @c page-delimiter: "^\\\\message" @c time-stamp-start: "def\\\\texinfoversion{" @c time-stamp-format: "%:y-%02m-%02d.%02H" @c time-stamp-end: "}" @c End: @c vim:sw=2: @ignore arch-tag: e1b36e32-c96e-4135-a41a-0b2efa2ea115 @end ignore openocd-0.7.0/doc/stamp-vti0000644000175000001440000000013212141414310012461 00000000000000@set UPDATED 4 May 2013 @set UPDATED-MONTH May 2013 @set EDITION 0.7.0 @set VERSION 0.7.0 openocd-0.7.0/doc/fdl.texi0000644000175000001440000005107612134336410012275 00000000000000@c -*-texinfo-*- @node License @appendix The GNU Free Documentation License. @center Version 1.2, November 2002 @c This file is intended to be included within another document, @c hence no sectioning command or @node. @display Copyright @copyright{} 2000,2001,2002 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @end display @enumerate 0 @item PREAMBLE The purpose of this License is to make a manual, textbook, or other functional and useful document @dfn{free} in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others. This License is a kind of ``copyleft'', which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software. We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference. @item APPLICABILITY AND DEFINITIONS This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The ``Document'', below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as ``you''. You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law. A ``Modified Version'' of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language. A ``Secondary Section'' is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document's overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them. The ``Invariant Sections'' are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none. The ``Cover Texts'' are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words. A ``Transparent'' copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not ``Transparent'' is called ``Opaque''. Examples of suitable formats for Transparent copies include plain @sc{ascii} without markup, Texinfo input format, La@TeX{} input format, @acronym{SGML} or @acronym{XML} using a publicly available @acronym{DTD}, and standard-conforming simple @acronym{HTML}, PostScript or @acronym{PDF} designed for human modification. Examples of transparent image formats include @acronym{PNG}, @acronym{XCF} and @acronym{JPG}. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, @acronym{SGML} or @acronym{XML} for which the @acronym{DTD} and/or processing tools are not generally available, and the machine-generated @acronym{HTML}, PostScript or @acronym{PDF} produced by some word processors for output purposes only. The ``Title Page'' means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, ``Title Page'' means the text near the most prominent appearance of the work's title, preceding the beginning of the body of the text. A section ``Entitled XYZ'' means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as ``Acknowledgements'', ``Dedications'', ``Endorsements'', or ``History''.) To ``Preserve the Title'' of such a section when you modify the Document means that it remains a section ``Entitled XYZ'' according to this definition. The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License. @item VERBATIM COPYING You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3. You may also lend copies, under the same conditions stated above, and you may publicly display copies. @item COPYING IN QUANTITY If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document's license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects. If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages. If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public. It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document. @item MODIFICATIONS You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version: @enumerate A @item Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission. @item List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has fewer than five), unless they release you from this requirement. @item State on the Title page the name of the publisher of the Modified Version, as the publisher. @item Preserve all the copyright notices of the Document. @item Add an appropriate copyright notice for your modifications adjacent to the other copyright notices. @item Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below. @item Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document's license notice. @item Include an unaltered copy of this License. @item Preserve the section Entitled ``History'', Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section Entitled ``History'' in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence. @item Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the ``History'' section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission. @item For any section Entitled ``Acknowledgements'' or ``Dedications'', Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein. @item Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles. @item Delete any section Entitled ``Endorsements''. Such a section may not be included in the Modified Version. @item Do not retitle any existing section to be Entitled ``Endorsements'' or to conflict in title with any Invariant Section. @item Preserve any Warranty Disclaimers. @end enumerate If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version's license notice. These titles must be distinct from any other section titles. You may add a section Entitled ``Endorsements'', provided it contains nothing but endorsements of your Modified Version by various parties---for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard. You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one. The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version. @item COMBINING DOCUMENTS You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers. The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work. In the combination, you must combine any sections Entitled ``History'' in the various original documents, forming one section Entitled ``History''; likewise combine any sections Entitled ``Acknowledgements'', and any sections Entitled ``Dedications''. You must delete all sections Entitled ``Endorsements.'' @item COLLECTIONS OF DOCUMENTS You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects. You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document. @item AGGREGATION WITH INDEPENDENT WORKS A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an ``aggregate'' if the copyright resulting from the compilation is not used to limit the legal rights of the compilation's users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document. If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document's Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate. @item TRANSLATION Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail. If a section in the Document is Entitled ``Acknowledgements'', ``Dedications'', or ``History'', the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title. @item TERMINATION You may not copy, modify, sublicense, or distribute the Document except as expressly provided for under this License. Any other attempt to copy, modify, sublicense or distribute the Document 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. @item FUTURE REVISIONS OF THIS LICENSE The Free Software Foundation may publish new, revised versions of the GNU Free Documentation 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. See @uref{http://www.gnu.org/copyleft/}. Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License ``or any later version'' applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. @end enumerate @unnumberedsec ADDENDUM: How to use this License for your documents To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page: @smallexample @group Copyright (C) @var{year} @var{your name}. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled ``GNU Free Documentation License''. @end group @end smallexample If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace the ``with@dots{}Texts.'' line with this: @smallexample @group with the Invariant Sections being @var{list their titles}, with the Front-Cover Texts being @var{list}, and with the Back-Cover Texts being @var{list}. @end group @end smallexample If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation. If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software. @c Local Variables: @c ispell-local-pdict: "ispell-dict" @c End: openocd-0.7.0/doc/openocd.info-20000644000175000001440000035074012141414411013274 00000000000000This is openocd.info, produced by makeinfo version 5.1 from openocd.texi. This User's Guide documents release 0.7.0, dated 4 May 2013, of the Open On-Chip Debugger (OpenOCD). * Copyright (C) 2008 The OpenOCD Project * Copyright (C) 2007-2008 Spencer Oliver * Copyright (C) 2008-2010 Oyvind Harboe * Copyright (C) 2008 Duane Ellis * Copyright (C) 2009-2010 David Brownell Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, with no Front-Cover Texts, and with no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License". INFO-DIR-SECTION Development START-INFO-DIR-ENTRY * OpenOCD: (openocd). OpenOCD User's Guide END-INFO-DIR-ENTRY  File: openocd.info, Node: Boundary Scan Commands, Next: TFTP, Prev: JTAG Commands, Up: Top 19 Boundary Scan Commands ************************* One of the original purposes of JTAG was to support boundary scan based hardware testing. Although its primary focus is to support On-Chip Debugging, OpenOCD also includes some boundary scan commands. 19.1 SVF: Serial Vector Format ============================== The Serial Vector Format, better known as "SVF", is a way to represent JTAG test patterns in text files. In a debug session using JTAG for its transport protocol, OpenOCD supports running such test files. -- Command: svf filename ['quiet'] This issues a JTAG reset (Test-Logic-Reset) and then runs the SVF script from 'filename'. Unless the 'quiet' option is specified, each command is logged before it is executed. 19.2 XSVF: Xilinx Serial Vector Format ====================================== The Xilinx Serial Vector Format, better known as "XSVF", is a binary representation of SVF which is optimized for use with Xilinx devices. In a debug session using JTAG for its transport protocol, OpenOCD supports running such test files. Important: Not all XSVF commands are supported. -- Command: xsvf (tapname|'plain') filename ['virt2'] ['quiet'] This issues a JTAG reset (Test-Logic-Reset) and then runs the XSVF script from 'filename'. When a TAPNAME is specified, the commands are directed at that TAP. When 'virt2' is specified, the XRUNTEST command counts are interpreted as TCK cycles instead of microseconds. Unless the 'quiet' option is specified, messages are logged for comments and some retries. The OpenOCD sources also include two utility scripts for working with XSVF; they are not currently installed after building the software. You may find them useful: * _svf2xsvf_ ... converts SVF files into the extended XSVF syntax understood by the 'xsvf' command; see notes below. * _xsvfdump_ ... converts XSVF files into a text output format; understands the OpenOCD extensions. The input format accepts a handful of non-standard extensions. These include three opcodes corresponding to SVF extensions from Lattice Semiconductor (LCOUNT, LDELAY, LDSR), and two opcodes supporting a more accurate translation of SVF (XTRST, XWAITSTATE). If _xsvfdump_ shows a file is using those opcodes, it probably will not be usable with other XSVF tools.  File: openocd.info, Node: TFTP, Next: GDB and OpenOCD, Prev: Boundary Scan Commands, Up: Top 20 TFTP ******* If OpenOCD runs on an embedded host(as ZY1000 does), then TFTP can be used to access files on PCs (either the developer's PC or some other PC). The way this works on the ZY1000 is to prefix a filename by "/tftp/ip/" and append the TFTP path on the TFTP server (tftpd). For example, load_image /tftp/10.0.0.96/c:\temp\abc.elf will load c:\temp\abc.elf from the developer pc (10.0.0.96) into memory as if the file was hosted on the embedded host. In order to achieve decent performance, you must choose a TFTP server that supports a packet size bigger than the default packet size (512 bytes). There are numerous TFTP servers out there (free and commercial) and you will have to do a bit of googling to find something that fits your requirements.  File: openocd.info, Node: GDB and OpenOCD, Next: Tcl Scripting API, Prev: TFTP, Up: Top 21 GDB and OpenOCD ****************** OpenOCD complies with the remote gdbserver protocol, and as such can be used to debug remote targets. Setting up GDB to work with OpenOCD can involve several components: * The OpenOCD server support for GDB may need to be configured. *Note GDB Configuration: gdbconfiguration. * GDB's support for OpenOCD may need configuration, as shown in this chapter. * If you have a GUI environment like Eclipse, that also will probably need to be configured. Of course, the version of GDB you use will need to be one which has been built to know about the target CPU you're using. It's probably part of the tool chain you're using. For example, if you are doing cross-development for ARM on an x86 PC, instead of using the native x86 'gdb' command you might use 'arm-none-eabi-gdb' if that's the tool chain used to compile your code. 21.1 Connecting to GDB ====================== Use GDB 6.7 or newer with OpenOCD if you run into trouble. For instance GDB 6.3 has a known bug that produces bogus memory access errors, which has since been fixed; see OpenOCD can communicate with GDB in two ways: 1. A socket (TCP/IP) connection is typically started as follows: target remote localhost:3333 This would cause GDB to connect to the gdbserver on the local pc using port 3333. It is also possible to use the GDB extended remote protocol as follows: target extended-remote localhost:3333 2. A pipe connection is typically started as follows: target remote | openocd -c "gdb_port pipe; log_output openocd.log" This would cause GDB to run OpenOCD and communicate using pipes (stdin/stdout). Using this method has the advantage of GDB starting/stopping OpenOCD for the debug session. log_output sends the log output to a file to ensure that the pipe is not saturated when using higher debug level outputs. To list the available OpenOCD commands type 'monitor help' on the GDB command line. 21.2 Sample GDB session startup =============================== With the remote protocol, GDB sessions start a little differently than they do when you're debugging locally. Here's an examples showing how to start a debug session with a small ARM program. In this case the program was linked to be loaded into SRAM on a Cortex-M3. Most programs would be written into flash (address 0) and run from there. $ arm-none-eabi-gdb example.elf (gdb) target remote localhost:3333 Remote debugging using localhost:3333 ... (gdb) monitor reset halt ... (gdb) load Loading section .vectors, size 0x100 lma 0x20000000 Loading section .text, size 0x5a0 lma 0x20000100 Loading section .data, size 0x18 lma 0x200006a0 Start address 0x2000061c, load size 1720 Transfer rate: 22 KB/sec, 573 bytes/write. (gdb) continue Continuing. ... You could then interrupt the GDB session to make the program break, type 'where' to show the stack, 'list' to show the code around the program counter, 'step' through code, set breakpoints or watchpoints, and so on. 21.3 Configuring GDB for OpenOCD ================================ OpenOCD supports the gdb 'qSupported' packet, this enables information to be sent by the GDB remote server (i.e. OpenOCD) to GDB. Typical information includes packet size and the device's memory map. You do not need to configure the packet size by hand, and the relevant parts of the memory map should be automatically set up when you declare (NOR) flash banks. However, there are other things which GDB can't currently query. You may need to set those up by hand. As OpenOCD starts up, you will often see a line reporting something like: Info : lm3s.cpu: hardware has 6 breakpoints, 4 watchpoints You can pass that information to GDB with these commands: set remote hardware-breakpoint-limit 6 set remote hardware-watchpoint-limit 4 With that particular hardware (Cortex-M3) the hardware breakpoints only work for code running from flash memory. Most other ARM systems do not have such restrictions. Another example of useful GDB configuration came from a user who found that single stepping his Cortex-M3 didn't work well with IRQs and an RTOS until he told GDB to disable the IRQs while stepping: define hook-step mon cortex_m maskisr on end define hookpost-step mon cortex_m maskisr off end Rather than typing such commands interactively, you may prefer to save them in a file and have GDB execute them as it starts, perhaps using a '.gdbinit' in your project directory or starting GDB using 'gdb -x filename'. 21.4 Programming using GDB ========================== By default the target memory map is sent to GDB. This can be disabled by the following OpenOCD configuration option: gdb_memory_map disable For this to function correctly a valid flash configuration must also be set in OpenOCD. For faster performance you should also configure a valid working area. Informing GDB of the memory map of the target will enable GDB to protect any flash areas of the target and use hardware breakpoints by default. This means that the OpenOCD option 'gdb_breakpoint_override' is not required when using a memory map. *Note gdb_breakpoint_override: gdbbreakpointoverride. To view the configured memory map in GDB, use the GDB command 'info mem' All other unassigned addresses within GDB are treated as RAM. GDB 6.8 and higher set any memory area not in the memory map as inaccessible. This can be changed to the old behaviour by using the following GDB command set mem inaccessible-by-default off If 'gdb_flash_program enable' is also used, GDB will be able to program any flash memory using the vFlash interface. GDB will look at the target memory map when a load command is given, if any areas to be programmed lie within the target flash area the vFlash packets will be used. If the target needs configuring before GDB programming, an event script can be executed: $_TARGETNAME configure -event EVENTNAME BODY To verify any flash programming the GDB command 'compare-sections' can be used. 21.5 Using OpenOCD SMP with GDB =============================== For SMP support following GDB serial protocol packet have been defined : * j - smp status request * J - smp set request OpenOCD implements : * 'jc' packet for reading core id displayed by GDB connection. Reply is 'XXXXXXXX' (8 hex digits giving core id) or 'E01' for target not smp. * 'JcXXXXXXXX' (8 hex digits) packet for setting core id displayed at next GDB continue (core id -1 is reserved for returning to normal resume mode). Reply 'E01' for target not smp or 'OK' on success. Handling of this packet within GDB can be done : * by the creation of an internal variable (i.e '_core') by mean of function allocate_computed_value allowing following GDB command. set $_core 1 #Jc01 packet is sent print $_core #jc packet is sent and result is affected in $ * by the usage of GDB maintenance command as described in following example (2 cpus in SMP with core id 0 and 1 *note Define CPU targets working in SMP: definecputargetsworkinginsmp.). # toggle0 : force display of coreid 0 define toggle0 maint packet Jc0 continue main packet Jc-1 end # toggle1 : force display of coreid 1 define toggle1 maint packet Jc1 continue main packet Jc-1 end  File: openocd.info, Node: Tcl Scripting API, Next: FAQ, Prev: GDB and OpenOCD, Up: Top 22 Tcl Scripting API ******************** 22.1 API rules ============== The commands are stateless. E.g. the telnet command line has a concept of currently active target, the Tcl API proc's take this sort of state information as an argument to each proc. There are three main types of return values: single value, name value pair list and lists. Name value pair. The proc 'foo' below returns a name/value pair list. > set foo(me) Duane > set foo(you) Oyvind > set foo(mouse) Micky > set foo(duck) Donald If one does this: > set foo The result is: me Duane you Oyvind mouse Micky duck Donald Thus, to get the names of the associative array is easy: foreach { name value } [set foo] { puts "Name: $name, Value: $value" } Lists returned must be relatively small. Otherwise a range should be passed in to the proc in question. 22.2 Internal low-level Commands ================================ By low-level, the intent is a human would not directly use these commands. Low-level commands are (should be) prefixed with "ocd_", e.g. 'ocd_flash_banks' is the low level API upon which 'flash banks' is implemented. * mem2array Read memory and return as a Tcl array for script processing * array2mem Convert a Tcl array to memory locations and write the values * ocd_flash_banks ['driver options' ...] Return information about the flash banks OpenOCD commands can consist of two words, e.g. "flash banks". The 'startup.tcl' "unknown" proc will translate this into a Tcl proc called "flash_banks". 22.3 OpenOCD specific Global Variables ====================================== Real Tcl has ::tcl_platform(), and platform::identify, and many other variables. JimTCL, as implemented in OpenOCD creates $ocd_HOSTOS which holds one of the following values: * cygwin Running under Cygwin * darwin Darwin (Mac-OS) is the underlying operating sytem. * freebsd Running under FreeBSD * linux Linux is the underlying operating sytem * mingw32 Running under MingW32 * winxx Built using Microsoft Visual Studio * other Unknown, none of the above. Note: 'winxx' was choosen because today (March-2009) no distinction is made between Win32 and Win64. Note: We should add support for a variable like Tcl variable 'tcl_platform(platform)', it should be called 'jim_platform' (because it is jim, not real tcl).  File: openocd.info, Node: FAQ, Next: Tcl Crash Course, Prev: Tcl Scripting API, Up: Top 23 FAQ ****** 1. RTCK, also known as: Adaptive Clocking - What is it? In digital circuit design it is often refered to as "clock synchronisation" the JTAG interface uses one clock (TCK or TCLK) operating at some speed, your CPU target is operating at another. The two clocks are not synchronised, they are "asynchronous" In order for the two to work together they must be synchronised well enough to work; JTAG can't go ten times faster than the CPU, for example. There are 2 basic options: 1. Use a special "adaptive clocking" circuit to change the JTAG clock rate to match what the CPU currently supports. 2. The JTAG clock must be fixed at some speed that's enough slower than the CPU clock that all TMS and TDI transitions can be detected. Does this really matter? For some chips and some situations, this is a non-issue, like a 500MHz ARM926 with a 5 MHz JTAG link; the CPU has no difficulty keeping up with JTAG. Startup sequences are often problematic though, as are other situations where the CPU clock rate changes (perhaps to save power). For example, Atmel AT91SAM chips start operation from reset with a 32kHz system clock. Boot firmware may activate the main oscillator and PLL before switching to a faster clock (perhaps that 500 MHz ARM926 scenario). If you're using JTAG to debug that startup sequence, you must slow the JTAG clock to sometimes 1 to 4kHz. After startup completes, JTAG can use a faster clock. Consider also debugging a 500MHz ARM926 hand held battery powered device that enters a low power "deep sleep" mode, at 32kHz CPU clock, between keystrokes unless it has work to do. When would that 5 MHz JTAG clock be usable? Solution #1 - A special circuit In order to make use of this, your CPU, board, and JTAG adapter must all support the RTCK feature. Not all of them support this; keep reading! The RTCK ("Return TCK") signal in some ARM chips is used to help with this problem. ARM has a good description of the problem described at this link: [checked 28/nov/2008]. Link title: "How does the JTAG synchronisation logic work? / how does adaptive clocking work?". The nice thing about adaptive clocking is that "battery powered hand held device example" - the adaptiveness works perfectly all the time. One can set a break point or halt the system in the deep power down code, slow step out until the system speeds up. Note that adaptive clocking may also need to work at the board level, when a board-level scan chain has multiple chips. Parallel clock voting schemes are good way to implement this, both within and between chips, and can easily be implemented with a CPLD. It's not difficult to have logic fan a module's input TCK signal out to each TAP in the scan chain, and then wait until each TAP's RTCK comes back with the right polarity before changing the output RTCK signal. Texas Instruments makes some clock voting logic available for free (with no support) in VHDL form; see Solution #2 - Always works - but may be slower Often this is a perfectly acceptable solution. In most simple terms: Often the JTAG clock must be 1/10 to 1/12 of the target clock speed. But what that "magic division" is varies depending on the chips on your board. ARM rule of thumb Most ARM based systems require an 6:1 division; ARM11 cores use an 8:1 division. Xilinx rule of thumb is 1/12 the clock speed. Note: most full speed FT2232 based JTAG adapters are limited to a maximum of 6MHz. The ones using USB high speed chips (FT2232H) often support faster clock rates (and adaptive clocking). You can still debug the 'low power' situations - you just need to either use a fixed and very slow JTAG clock rate ... or else manually adjust the clock speed at every step. (Adjusting is painful and tedious, and is not always practical.) It is however easy to "code your way around it" - i.e.: Cheat a little, have a special debug mode in your application that does a "high power sleep". If you are careful - 98% of your problems can be debugged this way. Note that on ARM you may need to avoid using the _wait for interrupt_ operation in your idle loops even if you don't otherwise change the CPU clock rate. That operation gates the CPU clock, and thus the JTAG clock; which prevents JTAG access. One consequence is not being able to 'halt' cores which are executing that _wait for interrupt_ operation. To set the JTAG frequency use the command: # Example: 1.234MHz adapter_khz 1234 2. Win32 Pathnames Why don't backslashes work in Windows paths? OpenOCD uses Tcl and a backslash is an escape char. Use { and } around Windows filenames. > echo \a > echo {\a} \a > echo "\a" > 3. Missing: cygwin1.dll OpenOCD complains about a missing cygwin1.dll. Make sure you have Cygwin installed, or at least a version of OpenOCD that claims to come with all the necessary DLLs. When using Cygwin, try launching OpenOCD from the Cygwin shell. 4. Breakpoint Issue I'm trying to set a breakpoint using GDB (or a frontend like Insight or Eclipse), but OpenOCD complains that "Info: arm7_9_common.c:213 arm7_9_add_breakpoint(): sw breakpoint requested, but software breakpoints not enabled". GDB issues software breakpoints when a normal breakpoint is requested, or to implement source-line single-stepping. On ARMv4T systems, like ARM7TDMI, ARM720T or ARM920T, software breakpoints consume one of the two available hardware breakpoints. 5. LPC2000 Flash When erasing or writing LPC2000 on-chip flash, the operation fails at random. Make sure the core frequency specified in the 'flash lpc2000' line matches the clock at the time you're programming the flash. If you've specified the crystal's frequency, make sure the PLL is disabled. If you've specified the full core speed (e.g. 60MHz), make sure the PLL is enabled. 6. Amontec Chameleon When debugging using an Amontec Chameleon in its JTAG Accelerator configuration, I keep getting "Error: amt_jtagaccel.c:184 amt_wait_scan_busy(): amt_jtagaccel timed out while waiting for end of scan, rtck was disabled". Make sure your PC's parallel port operates in EPP mode. You might have to try several settings in your PC BIOS (ECP, EPP, and different versions of those). 7. Data Aborts When debugging with OpenOCD and GDB (plain GDB, Insight, or Eclipse), I get lots of "Error: arm7_9_common.c:1771 arm7_9_read_memory(): memory read caused data abort". The errors are non-fatal, and are the result of GDB trying to trace stack frames beyond the last valid frame. It might be possible to prevent this by setting up a proper "initial" stack frame, if you happen to know what exactly has to be done, feel free to add this here. Simple: In your startup code - push 8 registers of zeros onto the stack before calling main(). What GDB is doing is "climbing" the run time stack by reading various values on the stack using the standard call frame for the target. GDB keeps going - until one of 2 things happen #1 an invalid frame is found, or #2 some huge number of stackframes have been processed. By pushing zeros on the stack, GDB gracefully stops. Debugging Interrupt Service Routines - In your ISR before you call your C code, do the same - artifically push some zeros onto the stack, remember to pop them off when the ISR is done. Also note: If you have a multi-threaded operating system, they often do not in the intrest of saving memory waste these few bytes. Painful... 8. JTAG Reset Config I get the following message in the OpenOCD console (or log file): "Warning: arm7_9_common.c:679 arm7_9_assert_reset(): srst resets test logic, too". This warning doesn't indicate any serious problem, as long as you don't want to debug your core right out of reset. Your .cfg file specified 'jtag_reset trst_and_srst srst_pulls_trst' to tell OpenOCD that either your board, your debugger or your target uC (e.g. LPC2000) can't assert the two reset signals independently. With this setup, it's not possible to halt the core right out of reset, everything else should work fine. 9. USB Power When using OpenOCD in conjunction with Amontec JTAGkey and the Yagarto toolchain (Eclipse, arm-elf-gcc, arm-elf-gdb), the debugging seems to be unstable. When single-stepping over large blocks of code, GDB and OpenOCD quit with an error message. Is there a stability issue with OpenOCD? No, this is not a stability issue concerning OpenOCD. Most users have solved this issue by simply using a self-powered USB hub, which they connect their Amontec JTAGkey to. Apparently, some computers do not provide a USB power supply stable enough for the Amontec JTAGkey to be operated. Laptops running on battery have this problem too... 10. USB Power When using the Amontec JTAGkey, sometimes OpenOCD crashes with the following error messages: "Error: ft2232.c:201 ft2232_read(): FT_Read returned: 4" and "Error: ft2232.c:365 ft2232_send_and_recv(): couldn't read from FT2232". What does that mean and what might be the reason for this? First of all, the reason might be the USB power supply. Try using a self-powered hub instead of a direct connection to your computer. Secondly, the error code 4 corresponds to an FT_IO_ERROR, which means that the driver for the FTDI USB chip ran into some sort of error - this points us to a USB problem. 11. GDB Disconnects When using the Amontec JTAGkey, sometimes OpenOCD crashes with the following error message: "Error: gdb_server.c:101 gdb_get_char(): read: 10054". What does that mean and what might be the reason for this? Error code 10054 corresponds to WSAECONNRESET, which means that the debugger (GDB) has closed the connection to OpenOCD. This might be a GDB issue. 12. LPC2000 Flash In the configuration file in the section where flash device configurations are described, there is a parameter for specifying the clock frequency for LPC2000 internal flash devices (e.g. 'flash bank $_FLASHNAME lpc2000 0x0 0x40000 0 0 $_TARGETNAME lpc2000_v1 14746 calc_checksum'), which must be specified in kilohertz. However, I do have a quartz crystal of a frequency that contains fractions of kilohertz (e.g. 14,745,600 Hz, i.e. 14,745.600 kHz). Is it possible to specify real numbers for the clock frequency? No. The clock frequency specified here must be given as an integral number. However, this clock frequency is used by the In-Application-Programming (IAP) routines of the LPC2000 family only, which seems to be very tolerant concerning the given clock frequency, so a slight difference between the specified clock frequency and the actual clock frequency will not cause any trouble. 13. Command Order Do I have to keep a specific order for the commands in the configuration file? Well, yes and no. Commands can be given in arbitrary order, yet the devices listed for the JTAG scan chain must be given in the right order (jtag newdevice), with the device closest to the TDO-Pin being listed first. In general, whenever objects of the same type exist which require an index number, then these objects must be given in the right order (jtag newtap, targets and flash banks - a target references a jtag newtap and a flash bank references a target). You can use the "scan_chain" command to verify and display the tap order. Also, some commands can't execute until after 'init' has been processed. Such commands include 'nand probe' and everything else that needs to write to controller registers, perhaps for setting up DRAM and loading it with code. 14. JTAG TAP Order Do I have to declare the TAPS in some particular order? Yes; whenever you have more than one, you must declare them in the same order used by the hardware. Many newer devices have multiple JTAG TAPs. For example: ST Microsystems STM32 chips have two TAPs, a "boundary scan TAP" and "Cortex-M3" TAP. Example: The STM32 reference manual, Document ID: RM0008, Section 26.5, Figure 259, page 651/681, the "TDI" pin is connected to the boundary scan TAP, which then connects to the Cortex-M3 TAP, which then connects to the TDO pin. Thus, the proper order for the STM32 chip is: (1) The Cortex-M3, then (2) The boundary scan TAP. If your board includes an additional JTAG chip in the scan chain (for example a Xilinx CPLD or FPGA) you could place it before or after the STM32 chip in the chain. For example: * OpenOCD_TDI(output) -> STM32 TDI Pin (BS Input) * STM32 BS TDO (output) -> STM32 Cortex-M3 TDI (input) * STM32 Cortex-M3 TDO (output) -> SM32 TDO Pin * STM32 TDO Pin (output) -> Xilinx TDI Pin (input) * Xilinx TDO Pin -> OpenOCD TDO (input) The "jtag device" commands would thus be in the order shown below. Note: * jtag newtap Xilinx tap -irlen ... * jtag newtap stm32 cpu -irlen ... * jtag newtap stm32 bs -irlen ... * # Create the debug target and say where it is * target create stm32.cpu -chain-position stm32.cpu ... 15. SYSCOMP Sometimes my debugging session terminates with an error. When I look into the log file, I can see these error messages: Error: arm7_9_common.c:561 arm7_9_execute_sys_speed(): timeout waiting for SYSCOMP TODO.  File: openocd.info, Node: Tcl Crash Course, Next: License, Prev: FAQ, Up: Top 24 Tcl Crash Course ******************* Not everyone knows Tcl - this is not intended to be a replacement for learning Tcl, the intent of this chapter is to give you some idea of how the Tcl scripts work. This chapter is written with two audiences in mind. (1) OpenOCD users who need to understand a bit more of how Jim-Tcl works so they can do something useful, and (2) those that want to add a new command to OpenOCD. 24.1 Tcl Rule #1 ================ There is a famous joke, it goes like this: 1. Rule #1: The wife is always correct 2. Rule #2: If you think otherwise, See Rule #1 The Tcl equal is this: 1. Rule #1: Everything is a string 2. Rule #2: If you think otherwise, See Rule #1 As in the famous joke, the consequences of Rule #1 are profound. Once you understand Rule #1, you will understand Tcl. 24.2 Tcl Rule #1b ================= There is a second pair of rules. 1. Rule #1: Control flow does not exist. Only commands For example: the classic FOR loop or IF statement is not a control flow item, they are commands, there is no such thing as control flow in Tcl. 2. Rule #2: If you think otherwise, See Rule #1 Actually what happens is this: There are commands that by convention, act like control flow key words in other languages. One of those commands is the word "for", another command is "if". 24.3 Per Rule #1 - All Results are strings ========================================== Every Tcl command results in a string. The word "result" is used deliberatly. No result is just an empty string. Remember: Rule #1 - Everything is a string 24.4 Tcl Quoting Operators ========================== In life of a Tcl script, there are two important periods of time, the difference is subtle. 1. Parse Time 2. Evaluation Time The two key items here are how "quoted things" work in Tcl. Tcl has three primary quoting constructs, the [square-brackets] the {curly-braces} and "double-quotes" By now you should know $VARIABLES always start with a $DOLLAR sign. BTW: To set a variable, you actually use the command "set", as in "set VARNAME VALUE" much like the ancient BASIC langauge "let x = 1" statement, but without the equal sign. * [square-brackets] [square-brackets] are command substitutions. It operates much like Unix Shell 'back-ticks'. The result of a [square-bracket] operation is exactly 1 string. Remember Rule #1 - Everything is a string. These two statements are roughly identical: # bash example X=`date` echo "The Date is: $X" # Tcl example set X [date] puts "The Date is: $X" * "double-quoted-things" "double-quoted-things" are just simply quoted text. $VARIABLES and [square-brackets] are expanded in place - the result however is exactly 1 string. Remember Rule #1 - Everything is a string set x "Dinner" puts "It is now \"[date]\", $x is in 1 hour" * {Curly-Braces} {Curly-Braces} are magic: $VARIABLES and [square-brackets] are parsed, but are NOT expanded or executed. {Curly-Braces} are like 'single-quote' operators in BASH shell scripts, with the added feature: {curly-braces} can be nested, single quotes can not. {{{this is nested 3 times}}} NOTE: [date] is a bad example; at this writing, Jim/OpenOCD does not have a date command. 24.5 Consequences of Rule 1/2/3/4 ================================= The consequences of Rule 1 are profound. 24.5.1 Tokenisation & Execution. -------------------------------- Of course, whitespace, blank lines and #comment lines are handled in the normal way. As a script is parsed, each (multi) line in the script file is tokenised and according to the quoting rules. After tokenisation, that line is immedatly executed. Multi line statements end with one or more "still-open" {curly-braces} which - eventually - closes a few lines later. 24.5.2 Command Execution ------------------------ Remember earlier: There are no "control flow" statements in Tcl. Instead there are COMMANDS that simply act like control flow operators. Commands are executed like this: 1. Parse the next line into (argc) and (argv[]). 2. Look up (argv[0]) in a table and call its function. 3. Repeat until End Of File. It sort of works like this: for(;;){ ReadAndParse( &argc, &argv ); cmdPtr = LookupCommand( argv[0] ); (*cmdPtr->Execute)( argc, argv ); } When the command "proc" is parsed (which creates a procedure function) it gets 3 parameters on the command line. 1 the name of the proc (function), 2 the list of parameters, and 3 the body of the function. Not the choice of words: LIST and BODY. The PROC command stores these items in a table somewhere so it can be found by "LookupCommand()" 24.5.3 The FOR command ---------------------- The most interesting command to look at is the FOR command. In Tcl, the FOR command is normally implemented in C. Remember, FOR is a command just like any other command. When the ascii text containing the FOR command is parsed, the parser produces 5 parameter strings, (If in doubt: Refer to Rule #1) they are: 0. The ascii text 'for' 1. The start text 2. The test expression 3. The next text 4. The body text Sort of reminds you of "main( int argc, char **argv )" does it not? Remember Rule #1 - Everything is a string. The key point is this: Often many of those parameters are in {curly-braces} - thus the variables inside are not expanded or replaced until later. Remember that every Tcl command looks like the classic "main( argc, argv )" function in C. In JimTCL - they actually look like this: int MyCommand( Jim_Interp *interp, int *argc, Jim_Obj * const *argvs ); Real Tcl is nearly identical. Although the newer versions have introduced a byte-code parser and intepreter, but at the core, it still operates in the same basic way. 24.5.4 FOR command implementation --------------------------------- To understand Tcl it is perhaps most helpful to see the FOR command. Remember, it is a COMMAND not a control flow structure. In Tcl there are two underlying C helper functions. Remember Rule #1 - You are a string. The first helper parses and executes commands found in an ascii string. Commands can be seperated by semicolons, or newlines. While parsing, variables are expanded via the quoting rules. The second helper evaluates an ascii string as a numerical expression and returns a value. Here is an example of how the FOR command could be implemented. The pseudo code below does not show error handling. void Execute_AsciiString( void *interp, const char *string ); int Evaluate_AsciiExpression( void *interp, const char *string ); int MyForCommand( void *interp, int argc, char **argv ) { if( argc != 5 ){ SetResult( interp, "WRONG number of parameters"); return ERROR; } // argv[0] = the ascii string just like C // Execute the start statement. Execute_AsciiString( interp, argv[1] ); // Top of loop test for(;;){ i = Evaluate_AsciiExpression(interp, argv[2]); if( i == 0 ) break; // Execute the body Execute_AsciiString( interp, argv[3] ); // Execute the LOOP part Execute_AsciiString( interp, argv[4] ); } // Return no error SetResult( interp, "" ); return SUCCESS; } Every other command IF, WHILE, FORMAT, PUTS, EXPR, everything works in the same basic way. 24.6 OpenOCD Tcl Usage ====================== 24.6.1 source and find commands ------------------------------- Where: In many configuration files Example: source [find FILENAME] Remember the parsing rules 1. The 'find' command is in square brackets, and is executed with the parameter FILENAME. It should find and return the full path to a file with that name; it uses an internal search path. The RESULT is a string, which is substituted into the command line in place of the bracketed 'find' command. (Don't try to use a FILENAME which includes the "#" character. That character begins Tcl comments.) 2. The 'source' command is executed with the resulting filename; it reads a file and executes as a script. 24.6.2 format command --------------------- Where: Generally occurs in numerous places. Tcl has no command like printf(), instead it has format, which is really more like sprintf(). Example set x 6 set y 7 puts [format "The answer: %d" [expr $x * $y]] 1. The SET command creates 2 variables, X and Y. 2. The double [nested] EXPR command performs math The EXPR command produces numerical result as a string. Refer to Rule #1 3. The format command is executed, producing a single string Refer to Rule #1. 4. The PUTS command outputs the text. 24.6.3 Body or Inlined Text --------------------------- Where: Various TARGET scripts. #1 Good proc someproc {} { ... multiple lines of stuff ... } $_TARGETNAME configure -event FOO someproc #2 Good - no variables $_TARGETNAME confgure -event foo "this ; that;" #3 Good Curly Braces $_TARGETNAME configure -event FOO { puts "Time: [date]" } #4 DANGER DANGER DANGER $_TARGETNAME configure -event foo "puts \"Time: [date]\"" 1. The $_TARGETNAME is an OpenOCD variable convention. $_TARGETNAME represents the last target created, the value changes each time a new target is created. Remember the parsing rules. When the ascii text is parsed, the $_TARGETNAME becomes a simple string, the name of the target which happens to be a TARGET (object) command. 2. The 2nd parameter to the '-event' parameter is a TCBODY There are 4 examples: 1. The TCLBODY is a simple string that happens to be a proc name 2. The TCLBODY is several simple commands seperated by semicolons 3. The TCLBODY is a multi-line {curly-brace} quoted string 4. The TCLBODY is a string with variables that get expanded. In the end, when the target event FOO occurs the TCLBODY is evaluated. Method #1 and #2 are functionally identical. For Method #3 and #4 it is more interesting. What is the TCLBODY? Remember the parsing rules. In case #3, {curly-braces} mean the $VARS and [square-brackets] are expanded later, when the EVENT occurs, and the text is evaluated. In case #4, they are replaced before the "Target Object Command" is executed. This occurs at the same time $_TARGETNAME is replaced. In case #4 the date will never change. {BTW: [date] is a bad example; at this writing, Jim/OpenOCD does not have a date command} 24.6.4 Global Variables ----------------------- Where: You might discover this when writing your own procs In simple terms: Inside a PROC, if you need to access a global variable you must say so. See also "upvar". Example: proc myproc { } { set y 0 #Local variable Y global x #Global variable X puts [format "X=%d, Y=%d" $x $y] } 24.7 Other Tcl Hacks ==================== Dynamic variable creation # Dynamically create a bunch of variables. for { set x 0 } { $x < 32 } { set x [expr $x + 1]} { # Create var name set vn [format "BIT%d" $x] # Make it a global global $vn # Set it. set $vn [expr (1 << $x)] } Dynamic proc/command creation # One "X" function - 5 uart functions. foreach who {A B C D E} proc [format "show_uart%c" $who] { } "show_UARTx $who" }  File: openocd.info, Node: License, Next: OpenOCD Concept Index, Prev: Tcl Crash Course, Up: Top Appendix A The GNU Free Documentation License. ********************************************** Version 1.2, November 2002 Copyright (C) 2000,2001,2002 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. 0. PREAMBLE The purpose of this License is to make a manual, textbook, or other functional and useful document "free" in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others. This License is a kind of "copyleft", which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software. We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference. 1. APPLICABILITY AND DEFINITIONS This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The "Document", below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as "you". You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law. A "Modified Version" of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language. A "Secondary Section" is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document's overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them. The "Invariant Sections" are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none. The "Cover Texts" are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words. A "Transparent" copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not "Transparent" is called "Opaque". Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modification. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only. The "Title Page" means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, "Title Page" means the text near the most prominent appearance of the work's title, preceding the beginning of the body of the text. A section "Entitled XYZ" means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as "Acknowledgements", "Dedications", "Endorsements", or "History".) To "Preserve the Title" of such a section when you modify the Document means that it remains a section "Entitled XYZ" according to this definition. The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License. 2. VERBATIM COPYING You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3. You may also lend copies, under the same conditions stated above, and you may publicly display copies. 3. COPYING IN QUANTITY If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document's license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects. If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages. If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public. It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document. 4. MODIFICATIONS You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version: A. Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission. B. List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has fewer than five), unless they release you from this requirement. C. State on the Title page the name of the publisher of the Modified Version, as the publisher. D. Preserve all the copyright notices of the Document. E. Add an appropriate copyright notice for your modifications adjacent to the other copyright notices. F. Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below. G. Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document's license notice. H. Include an unaltered copy of this License. I. Preserve the section Entitled "History", Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section Entitled "History" in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence. J. Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the "History" section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission. K. For any section Entitled "Acknowledgements" or "Dedications", Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein. L. Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles. M. Delete any section Entitled "Endorsements". Such a section may not be included in the Modified Version. N. Do not retitle any existing section to be Entitled "Endorsements" or to conflict in title with any Invariant Section. O. Preserve any Warranty Disclaimers. If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version's license notice. These titles must be distinct from any other section titles. You may add a section Entitled "Endorsements", provided it contains nothing but endorsements of your Modified Version by various parties--for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard. You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one. The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version. 5. COMBINING DOCUMENTS You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers. The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work. In the combination, you must combine any sections Entitled "History" in the various original documents, forming one section Entitled "History"; likewise combine any sections Entitled "Acknowledgements", and any sections Entitled "Dedications". You must delete all sections Entitled "Endorsements." 6. COLLECTIONS OF DOCUMENTS You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects. You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document. 7. AGGREGATION WITH INDEPENDENT WORKS A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an "aggregate" if the copyright resulting from the compilation is not used to limit the legal rights of the compilation's users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document. If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document's Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate. 8. TRANSLATION Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail. If a section in the Document is Entitled "Acknowledgements", "Dedications", or "History", the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title. 9. TERMINATION You may not copy, modify, sublicense, or distribute the Document except as expressly provided for under this License. Any other attempt to copy, modify, sublicense or distribute the Document 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. 10. FUTURE REVISIONS OF THIS LICENSE The Free Software Foundation may publish new, revised versions of the GNU Free Documentation 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. See . Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License "or any later version" applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. ADDENDUM: How to use this License for your documents ==================================================== To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page: Copyright (C) YEAR YOUR NAME. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled ``GNU Free Documentation License''. If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace the "with...Texts." line with this: with the Invariant Sections being LIST THEIR TITLES, with the Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation. If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software.  File: openocd.info, Node: OpenOCD Concept Index, Next: Command and Driver Index, Prev: License, Up: Top OpenOCD Concept Index ********************* [index] * Menu: * about: About. (line 6) * adaptive clocking: Debug Adapter Configuration. (line 661) * adaptive clocking <1>: FAQ. (line 6) * Architecture Specific Commands: Architecture and Core Commands. (line 6) * ARM: Architecture and Core Commands. (line 244) * ARM semihosting: OpenOCD Project Setup. (line 313) * ARM semihosting <1>: Architecture and Core Commands. (line 285) * ARM11: Architecture and Core Commands. (line 585) * ARM7: Architecture and Core Commands. (line 305) * ARM720T: Architecture and Core Commands. (line 343) * ARM9: Architecture and Core Commands. (line 305) * ARM9 <1>: Architecture and Core Commands. (line 359) * ARM920T: Architecture and Core Commands. (line 379) * ARM926ej-s: Architecture and Core Commands. (line 414) * ARM966E: Architecture and Core Commands. (line 428) * ARMv4: Architecture and Core Commands. (line 298) * ARMv5: Architecture and Core Commands. (line 298) * ARMv6: Architecture and Core Commands. (line 581) * ARMv7: Architecture and Core Commands. (line 618) * at91sam3: Flash Commands. (line 290) * at91sam4: Flash Commands. (line 345) * autoprobe: TAP Declaration. (line 316) * board config file: Config File Guidelines. (line 256) * breakpoint: General Commands. (line 309) * CFI: Flash Commands. (line 210) * command line options: Running. (line 6) * commands: General Commands. (line 6) * Common Flash Interface: Flash Commands. (line 210) * config command: Daemon Configuration. (line 13) * config file, board: Config File Guidelines. (line 256) * config file, interface: Debug Adapter Configuration. (line 6) * config file, overview: OpenOCD Project Setup. (line 138) * config file, target: Config File Guidelines. (line 483) * config file, user: OpenOCD Project Setup. (line 138) * configuration stage: Daemon Configuration. (line 13) * Connecting to GDB: GDB and OpenOCD. (line 27) * Core Specific Commands: Architecture and Core Commands. (line 6) * Cortex-M: Architecture and Core Commands. (line 653) * CPU type: CPU Configuration. (line 82) * CPU variant: CPU Configuration. (line 82) * DAP: Architecture and Core Commands. (line 622) * DCC: Architecture and Core Commands. (line 321) * DCC <1>: Architecture and Core Commands. (line 703) * Debug Access Port: Architecture and Core Commands. (line 622) * developers: Developers. (line 6) * directory search: Running. (line 6) * disassemble: Architecture and Core Commands. (line 255) * dongles: Debug Adapter Hardware. (line 6) * dotted name: TAP Declaration. (line 97) * ETB: Architecture and Core Commands. (line 14) * ETM: Architecture and Core Commands. (line 14) * event, reset-init: Config File Guidelines. (line 372) * events: Reset Configuration. (line 226) * events <1>: TAP Declaration. (line 215) * events <2>: CPU Configuration. (line 363) * faq: FAQ. (line 6) * flash configuration: Flash Commands. (line 36) * flash erasing: Flash Commands. (line 87) * flash programming: Flash Commands. (line 87) * flash protection: Flash Commands. (line 178) * flash reading: Flash Commands. (line 87) * flash writing: Flash Commands. (line 87) * FPGA: PLD/FPGA Commands. (line 6) * FTDI: Debug Adapter Hardware. (line 6) * GDB: Daemon Configuration. (line 131) * GDB <1>: GDB and OpenOCD. (line 6) * GDB configuration: Daemon Configuration. (line 131) * GDB server: Daemon Configuration. (line 91) * GDB target: CPU Configuration. (line 6) * halt: General Commands. (line 77) * image dumping: General Commands. (line 261) * image loading: General Commands. (line 261) * initialization: Daemon Configuration. (line 6) * init_board procedure: Config File Guidelines. (line 437) * init_targets procedure: Config File Guidelines. (line 706) * interface config file: Debug Adapter Configuration. (line 6) * Jim-Tcl: About Jim-Tcl. (line 6) * jrc: TAP Declaration. (line 253) * JTAG: About. (line 15) * JTAG <1>: Debug Adapter Configuration. (line 580) * JTAG autoprobe: TAP Declaration. (line 316) * JTAG Commands: JTAG Commands. (line 6) * JTAG Route Controller: TAP Declaration. (line 253) * libdcc: Architecture and Core Commands. (line 703) * Linux-ARM DCC support: Architecture and Core Commands. (line 703) * logfile: Running. (line 6) * lpcspifi: Flash Commands. (line 241) * memory access: General Commands. (line 228) * message level: General Commands. (line 54) * mFlash commands: Flash Commands. (line 839) * mFlash Configuration: Flash Commands. (line 823) * NAND: NAND Flash Commands. (line 6) * NAND configuration: NAND Flash Commands. (line 61) * NAND erasing: NAND Flash Commands. (line 141) * NAND other commands: NAND Flash Commands. (line 232) * NAND programming: NAND Flash Commands. (line 141) * NAND programming <1>: NAND Flash Commands. (line 154) * NAND programming <2>: NAND Flash Commands. (line 207) * NAND reading: NAND Flash Commands. (line 108) * NAND verification: NAND Flash Commands. (line 207) * NAND writing: NAND Flash Commands. (line 154) * NXP SPI Flash Interface: Flash Commands. (line 241) * object command: CPU Configuration. (line 257) * PLD: PLD/FPGA Commands. (line 6) * port: Daemon Configuration. (line 81) * printer port: Debug Adapter Hardware. (line 6) * profiling: General Commands. (line 341) * Programming using GDB: GDB and OpenOCD. (line 126) * reset: General Commands. (line 77) * Reset Configuration: Reset Configuration. (line 6) * reset-init handler: Config File Guidelines. (line 372) * RTCK: Debug Adapter Hardware. (line 6) * RTCK <1>: Debug Adapter Configuration. (line 661) * RTCK <2>: FAQ. (line 6) * scan chain: TAP Declaration. (line 28) * security: Daemon Configuration. (line 81) * Serial Peripheral Interface: Debug Adapter Configuration. (line 604) * Serial Vector Format: Boundary Scan Commands. (line 13) * Serial Wire Debug: Debug Adapter Configuration. (line 589) * server: Daemon Configuration. (line 81) * SMI: Flash Commands. (line 258) * SMP: Config File Guidelines. (line 610) * SMP <1>: GDB and OpenOCD. (line 164) * SPI: Debug Adapter Configuration. (line 604) * SPIFI: Flash Commands. (line 241) * STMicroelectronics Serial Memory Interface: Flash Commands. (line 258) * stmsmi: Flash Commands. (line 258) * str9xpec: Flash Commands. (line 741) * SVF: Boundary Scan Commands. (line 13) * SWD: Debug Adapter Configuration. (line 589) * TAP: About. (line 15) * TAP configuration: TAP Declaration. (line 6) * TAP declaration: TAP Declaration. (line 6) * TAP events: TAP Declaration. (line 215) * TAP naming convention: TAP Declaration. (line 128) * TAP state names: JTAG Commands. (line 142) * target config file: Config File Guidelines. (line 483) * target events: CPU Configuration. (line 363) * target initialization: General Commands. (line 77) * target type: CPU Configuration. (line 82) * target, current: CPU Configuration. (line 18) * target, list: CPU Configuration. (line 18) * tcl: About Jim-Tcl. (line 6) * Tcl: Tcl Crash Course. (line 6) * Tcl Scripting API: Tcl Scripting API. (line 6) * Tcl scripts: Tcl Scripting API. (line 5) * TCP port: Daemon Configuration. (line 81) * TFTP: TFTP. (line 6) * tracing: Architecture and Core Commands. (line 14) * tracing <1>: Architecture and Core Commands. (line 703) * translation: Config File Guidelines. (line 787) * Transport: Debug Adapter Configuration. (line 563) * USB Adapter: Debug Adapter Hardware. (line 6) * user config file: OpenOCD Project Setup. (line 138) * variable names: Config File Guidelines. (line 340) * vector_catch: OpenOCD Project Setup. (line 212) * vector_catch <1>: Architecture and Core Commands. (line 364) * vector_catch <2>: Architecture and Core Commands. (line 554) * vector_catch <3>: Architecture and Core Commands. (line 607) * vector_catch <4>: Architecture and Core Commands. (line 672) * vector_table: Architecture and Core Commands. (line 569) * watchpoint: General Commands. (line 309) * wiggler: Debug Adapter Hardware. (line 6) * Xilinx Serial Vector Format: Boundary Scan Commands. (line 25) * XScale: Architecture and Core Commands. (line 442) * XSVF: Boundary Scan Commands. (line 25) * zy1000: Debug Adapter Hardware. (line 6)  File: openocd.info, Node: Command and Driver Index, Prev: OpenOCD Concept Index, Up: Top Command and Driver Index ************************ [index] * Menu: * $target_name arp_examine: CPU Configuration. (line 282) * $target_name arp_halt: CPU Configuration. (line 283) * $target_name arp_poll: CPU Configuration. (line 284) * $target_name arp_reset: CPU Configuration. (line 285) * $target_name arp_waitstate: CPU Configuration. (line 286) * $target_name array2mem: CPU Configuration. (line 291) * $target_name cget: CPU Configuration. (line 309) * $target_name configure: CPU Configuration. (line 206) * $target_name curstate: CPU Configuration. (line 332) * $target_name eventlist: CPU Configuration. (line 337) * $target_name invoke-event: CPU Configuration. (line 341) * $target_name mdb: CPU Configuration. (line 348) * $target_name mdh: CPU Configuration. (line 347) * $target_name mdw: CPU Configuration. (line 346) * $target_name mem2array: CPU Configuration. (line 292) * $target_name mwb: CPU Configuration. (line 356) * $target_name mwh: CPU Configuration. (line 355) * $target_name mww: CPU Configuration. (line 354) * adapter_khz: Debug Adapter Configuration. (line 644) * adapter_name: Debug Adapter Configuration. (line 54) * adapter_nsrst_assert_width: Reset Configuration. (line 121) * adapter_nsrst_delay: Reset Configuration. (line 126) * add_script_search_dir: General Commands. (line 71) * aduc702x: Flash Commands. (line 280) * amt_jtagaccel: Debug Adapter Configuration. (line 63) * append_file: General Commands. (line 189) * arm core_state: Architecture and Core Commands. (line 248) * arm disassemble: Architecture and Core Commands. (line 254) * arm mcr: Architecture and Core Commands. (line 268) * arm mrc: Architecture and Core Commands. (line 274) * arm reg: Architecture and Core Commands. (line 280) * arm semihosting: Architecture and Core Commands. (line 284) * arm-jtag-ew: Debug Adapter Configuration. (line 76) * arm11 memwrite burst: Architecture and Core Commands. (line 585) * arm11 memwrite error_fatal: Architecture and Core Commands. (line 595) * arm11 step_irq_enable: Architecture and Core Commands. (line 601) * arm11 vcr: Architecture and Core Commands. (line 606) * arm720t cp15: Architecture and Core Commands. (line 348) * arm7_9 dbgrq: Architecture and Core Commands. (line 310) * arm7_9 dcc_downloads: Architecture and Core Commands. (line 320) * arm7_9 fast_memory_access: Architecture and Core Commands. (line 331) * arm9 vector_catch: Architecture and Core Commands. (line 363) * arm920t cache_info: Architecture and Core Commands. (line 384) * arm920t cp15: Architecture and Core Commands. (line 389) * arm920t cp15i: Architecture and Core Commands. (line 395) * arm920t read_cache: Architecture and Core Commands. (line 405) * arm920t read_mmu: Architecture and Core Commands. (line 408) * arm926ejs cache_info: Architecture and Core Commands. (line 422) * arm966e cp15: Architecture and Core Commands. (line 432) * armjtagew_info: Debug Adapter Configuration. (line 80) * at91rm9200: Debug Adapter Configuration. (line 83) * at91sam3: Flash Commands. (line 289) * at91sam3 gpnvm: Flash Commands. (line 321) * at91sam3 gpnvm clear: Flash Commands. (line 322) * at91sam3 gpnvm set: Flash Commands. (line 323) * at91sam3 gpnvm show: Flash Commands. (line 324) * at91sam3 info: Flash Commands. (line 330) * at91sam3 slowclk: Flash Commands. (line 340) * at91sam4: Flash Commands. (line 344) * at91sam7: Flash Commands. (line 349) * at91sam7 gpnvm: Flash Commands. (line 382) * at91sam9: NAND Flash Commands. (line 273) * at91sam9 ale: NAND Flash Commands. (line 287) * at91sam9 ce: NAND Flash Commands. (line 298) * at91sam9 cle: NAND Flash Commands. (line 284) * at91sam9 rdy_busy: NAND Flash Commands. (line 293) * avr: Flash Commands. (line 390) * bp: General Commands. (line 313) * cat: General Commands. (line 194) * cfi: Flash Commands. (line 209) * cortex_m maskisr: Architecture and Core Commands. (line 653) * cortex_m reset_config: Architecture and Core Commands. (line 687) * cortex_m vector_catch: Architecture and Core Commands. (line 671) * cp: General Commands. (line 197) * dap apcsw: Architecture and Core Commands. (line 646) * dap apid: Architecture and Core Commands. (line 626) * dap apsel: Architecture and Core Commands. (line 630) * dap baseaddr: Architecture and Core Commands. (line 633) * dap info: Architecture and Core Commands. (line 637) * dap memaccess: Architecture and Core Commands. (line 641) * davinci: NAND Flash Commands. (line 304) * debug_level: General Commands. (line 53) * drscan: JTAG Commands. (line 42) * dummy: Debug Adapter Configuration. (line 87) * dummy <1>: Architecture and Core Commands. (line 190) * dump_image: General Commands. (line 261) * echo: General Commands. (line 62) * efm32: Flash Commands. (line 394) * ep93xx: Debug Adapter Configuration. (line 90) * etb: Architecture and Core Commands. (line 198) * etb config: Architecture and Core Commands. (line 201) * etb trigger_percent: Architecture and Core Commands. (line 204) * etm analyze: Architecture and Core Commands. (line 166) * etm config: Architecture and Core Commands. (line 63) * etm dump: Architecture and Core Commands. (line 170) * etm image: Architecture and Core Commands. (line 173) * etm info: Architecture and Core Commands. (line 89) * etm load: Architecture and Core Commands. (line 176) * etm start: Architecture and Core Commands. (line 179) * etm status: Architecture and Core Commands. (line 95) * etm stop: Architecture and Core Commands. (line 182) * etm tracemode: Architecture and Core Commands. (line 100) * etm trigger_debug: Architecture and Core Commands. (line 119) * etm_dummy config: Architecture and Core Commands. (line 195) * exit: General Commands. (line 30) * fast_load: General Commands. (line 265) * fast_load_image: General Commands. (line 269) * flash bank: Flash Commands. (line 36) * flash banks: Flash Commands. (line 67) * flash erase_address: Flash Commands. (line 120) * flash erase_check: Flash Commands. (line 178) * flash erase_sector: Flash Commands. (line 114) * flash fillb: Flash Commands. (line 133) * flash fillh: Flash Commands. (line 132) * flash fillw: Flash Commands. (line 131) * flash info: Flash Commands. (line 182) * flash list: Flash Commands. (line 72) * flash probe: Flash Commands. (line 77) * flash protect: Flash Commands. (line 187) * flash write_bank: Flash Commands. (line 143) * flash write_image: Flash Commands. (line 148) * flush_count: JTAG Commands. (line 70) * fm3: Flash Commands. (line 729) * ft2232: Debug Adapter Configuration. (line 94) * ft2232_channel: Debug Adapter Configuration. (line 171) * ft2232_device_desc: Debug Adapter Configuration. (line 104) * ft2232_latency: Debug Adapter Configuration. (line 160) * ft2232_layout: Debug Adapter Configuration. (line 118) * ft2232_serial: Debug Adapter Configuration. (line 110) * ft2232_vid_pid: Debug Adapter Configuration. (line 154) * ftdi: Debug Adapter Configuration. (line 183) * ftdi_channel: Debug Adapter Configuration. (line 241) * ftdi_device_desc: Debug Adapter Configuration. (line 228) * ftdi_layout_init: Debug Adapter Configuration. (line 246) * ftdi_layout_signal: Debug Adapter Configuration. (line 256) * ftdi_serial: Debug Adapter Configuration. (line 233) * ftdi_set_signal: Debug Adapter Configuration. (line 285) * ftdi_vid_pid: Debug Adapter Configuration. (line 222) * gdb_breakpoint_override: Daemon Configuration. (line 136) * gdb_flash_program: Daemon Configuration. (line 143) * gdb_memory_map: Daemon Configuration. (line 147) * gdb_port: Daemon Configuration. (line 90) * gdb_report_data_abort: Daemon Configuration. (line 155) * gw16012: Debug Adapter Configuration. (line 355) * halt: General Commands. (line 115) * help: General Commands. (line 33) * hla: Debug Adapter Configuration. (line 522) * hla_device_desc: Debug Adapter Configuration. (line 529) * hla_layout: Debug Adapter Configuration. (line 535) * hla_serial: Debug Adapter Configuration. (line 532) * hla_vid_pid: Debug Adapter Configuration. (line 538) * init: Daemon Configuration. (line 47) * init_reset: Reset Configuration. (line 257) * interface: Debug Adapter Configuration. (line 42) * interface transports: Debug Adapter Configuration. (line 48) * interface_list: Debug Adapter Configuration. (line 45) * ip: General Commands. (line 200) * irscan: JTAG Commands. (line 81) * jlink: Debug Adapter Configuration. (line 365) * jlink caps: Debug Adapter Configuration. (line 382) * jlink config: Debug Adapter Configuration. (line 390) * jlink config ip: Debug Adapter Configuration. (line 398) * jlink config kickstart: Debug Adapter Configuration. (line 392) * jlink config mac_address: Debug Adapter Configuration. (line 395) * jlink config reset: Debug Adapter Configuration. (line 405) * jlink config save: Debug Adapter Configuration. (line 407) * jlink config usb_address: Debug Adapter Configuration. (line 402) * jlink hw_jtag: Debug Adapter Configuration. (line 387) * jlink info: Debug Adapter Configuration. (line 384) * jlink pid: Debug Adapter Configuration. (line 410) * jtag arp_init: Reset Configuration. (line 275) * jtag arp_init-reset: Reset Configuration. (line 285) * jtag cget: TAP Declaration. (line 201) * jtag configure: TAP Declaration. (line 202) * jtag names: TAP Declaration. (line 80) * jtag newtap: TAP Declaration. (line 120) * jtag tapdisable: TAP Declaration. (line 296) * jtag tapenable: TAP Declaration. (line 301) * jtag tapisenabled: TAP Declaration. (line 306) * jtag_init: Daemon Configuration. (line 65) * jtag_ntrst_assert_width: Reset Configuration. (line 133) * jtag_ntrst_delay: Reset Configuration. (line 138) * jtag_rclk: Debug Adapter Configuration. (line 660) * jtag_reset: JTAG Commands. (line 98) * load_image: General Commands. (line 280) * log_output: General Commands. (line 67) * lpc2000: Flash Commands. (line 403) * lpc2000 part_id: Flash Commands. (line 438) * lpc288x: Flash Commands. (line 442) * lpc2900: Flash Commands. (line 450) * lpc2900 password: Flash Commands. (line 506) * lpc2900 read_custom: Flash Commands. (line 495) * lpc2900 secure_jtag: Flash Commands. (line 541) * lpc2900 secure_sector: Flash Commands. (line 527) * lpc2900 signature: Flash Commands. (line 486) * lpc2900 write_custom: Flash Commands. (line 516) * lpc3180: NAND Flash Commands. (line 317) * lpc3180 select: NAND Flash Commands. (line 320) * lpcspifi: Flash Commands. (line 240) * ls: General Commands. (line 203) * mac: General Commands. (line 206) * mdb: General Commands. (line 240) * mdh: General Commands. (line 239) * mdw: General Commands. (line 238) * meminfo: General Commands. (line 209) * mflash bank: Flash Commands. (line 823) * mflash config boot: Flash Commands. (line 846) * mflash config pll: Flash Commands. (line 839) * mflash config storage: Flash Commands. (line 850) * mflash dump: Flash Commands. (line 854) * mflash probe: Flash Commands. (line 858) * mflash write: Flash Commands. (line 861) * mwb: General Commands. (line 251) * mwh: General Commands. (line 250) * mww: General Commands. (line 249) * mx3: NAND Flash Commands. (line 330) * mxc: NAND Flash Commands. (line 334) * mxc biswap: NAND Flash Commands. (line 342) * nand check_bad_blocks: NAND Flash Commands. (line 232) * nand device: NAND Flash Commands. (line 64) * nand dump: NAND Flash Commands. (line 107) * nand erase: NAND Flash Commands. (line 140) * nand info: NAND Flash Commands. (line 244) * nand list: NAND Flash Commands. (line 87) * nand probe: NAND Flash Commands. (line 97) * nand raw_access: NAND Flash Commands. (line 249) * nand verify: NAND Flash Commands. (line 206) * nand write: NAND Flash Commands. (line 153) * ocl: Flash Commands. (line 548) * oocd_trace: Architecture and Core Commands. (line 222) * oocd_trace config: Architecture and Core Commands. (line 231) * oocd_trace resync: Architecture and Core Commands. (line 235) * oocd_trace status: Architecture and Core Commands. (line 238) * opendous: Debug Adapter Configuration. (line 545) * orion: NAND Flash Commands. (line 346) * parport: Debug Adapter Configuration. (line 414) * parport_cable: Debug Adapter Configuration. (line 420) * parport_port: Debug Adapter Configuration. (line 68) * parport_port <1>: Debug Adapter Configuration. (line 359) * parport_port <2>: Debug Adapter Configuration. (line 449) * parport_toggling_time: Debug Adapter Configuration. (line 459) * parport_write_on_exit: Debug Adapter Configuration. (line 493) * pathmove: JTAG Commands. (line 115) * peek: General Commands. (line 213) * pic32mx: Flash Commands. (line 553) * pic32mx pgm_word: Flash Commands. (line 561) * pic32mx unlock: Flash Commands. (line 564) * pld device: PLD/FPGA Commands. (line 23) * pld devices: PLD/FPGA Commands. (line 28) * pld load: PLD/FPGA Commands. (line 31) * poke: General Commands. (line 216) * poll: Daemon Configuration. (line 195) * power: Debug Adapter Configuration. (line 557) * presto: Debug Adapter Configuration. (line 505) * presto_serial: Debug Adapter Configuration. (line 507) * profile: General Commands. (line 341) * program: Flash Commands. (line 194) * rbp: General Commands. (line 323) * reg: General Commands. (line 83) * remote_bitbang: Debug Adapter Configuration. (line 294) * remote_bitbang_host: Debug Adapter Configuration. (line 306) * remote_bitbang_port: Debug Adapter Configuration. (line 302) * reset: General Commands. (line 154) * reset halt: General Commands. (line 156) * reset init: General Commands. (line 157) * reset run: General Commands. (line 155) * reset_config: Reset Configuration. (line 143) * resume: General Commands. (line 145) * rlink: Debug Adapter Configuration. (line 510) * rm: General Commands. (line 219) * rtck: Debug Adapter Configuration. (line 72) * runtest: JTAG Commands. (line 123) * rwp: General Commands. (line 326) * s3c2410: NAND Flash Commands. (line 354) * s3c2412: NAND Flash Commands. (line 355) * s3c2440: NAND Flash Commands. (line 356) * s3c2443: NAND Flash Commands. (line 357) * s3c6400: NAND Flash Commands. (line 358) * scan_chain: TAP Declaration. (line 88) * shutdown: General Commands. (line 49) * sleep: General Commands. (line 43) * soft_reset_halt: General Commands. (line 172) * stellaris: Flash Commands. (line 568) * stellaris recover bank_id: Flash Commands. (line 577) * step: General Commands. (line 150) * stlink_api: Debug Adapter Configuration. (line 541) * stm32f1x: Flash Commands. (line 590) * stm32f1x lock: Flash Commands. (line 611) * stm32f1x options_read: Flash Commands. (line 619) * stm32f1x options_write: Flash Commands. (line 624) * stm32f1x unlock: Flash Commands. (line 615) * stm32f2x: Flash Commands. (line 629) * stm32f2x lock: Flash Commands. (line 644) * stm32f2x unlock: Flash Commands. (line 648) * stm32lx: Flash Commands. (line 652) * stmsmi: Flash Commands. (line 257) * str7x: Flash Commands. (line 664) * str7x disable_jtag: Flash Commands. (line 672) * str9x: Flash Commands. (line 676) * str9x flash_config: Flash Commands. (line 685) * str9xpec: Flash Commands. (line 774) * str9xpec disable_turbo: Flash Commands. (line 782) * str9xpec enable_turbo: Flash Commands. (line 785) * str9xpec lock: Flash Commands. (line 789) * str9xpec options_cmap: Flash Commands. (line 796) * str9xpec options_lvdsel: Flash Commands. (line 799) * str9xpec options_lvdthd: Flash Commands. (line 802) * str9xpec options_lvdwarn: Flash Commands. (line 805) * str9xpec options_read: Flash Commands. (line 808) * str9xpec options_write: Flash Commands. (line 811) * str9xpec part_id: Flash Commands. (line 793) * str9xpec unlock: Flash Commands. (line 814) * svf: Boundary Scan Commands. (line 17) * swd newdap: Debug Adapter Configuration. (line 594) * swd wcr trn prescale: Debug Adapter Configuration. (line 597) * target count: CPU Configuration. (line 37) * target create: CPU Configuration. (line 183) * target current: CPU Configuration. (line 50) * target names: CPU Configuration. (line 53) * target number: CPU Configuration. (line 59) * target types: CPU Configuration. (line 99) * targets: CPU Configuration. (line 68) * target_request debugmsgs: Architecture and Core Commands. (line 742) * tcl_port: Daemon Configuration. (line 114) * telnet_port: Daemon Configuration. (line 121) * test_image: General Commands. (line 294) * tms470: Flash Commands. (line 694) * tms470 flash_keyset: Flash Commands. (line 701) * tms470 osc_mhz: Flash Commands. (line 705) * tms470 plldis: Flash Commands. (line 708) * trace history: Architecture and Core Commands. (line 752) * trace point: Architecture and Core Commands. (line 758) * transport list: Debug Adapter Configuration. (line 566) * transport select: Debug Adapter Configuration. (line 570) * trunc: General Commands. (line 222) * ulink: Debug Adapter Configuration. (line 548) * usbprog: Debug Adapter Configuration. (line 513) * usb_blaster: Debug Adapter Configuration. (line 325) * usb_blaster <1>: Debug Adapter Configuration. (line 345) * usb_blaster_device_desc: Debug Adapter Configuration. (line 331) * usb_blaster_vid_pid: Debug Adapter Configuration. (line 337) * verify_image: General Commands. (line 300) * verify_ircapture: JTAG Commands. (line 128) * verify_jtag: JTAG Commands. (line 134) * version: General Commands. (line 346) * virt2phys: General Commands. (line 349) * virtex2: PLD/FPGA Commands. (line 42) * virtex2 read_stat: PLD/FPGA Commands. (line 48) * virtual: Flash Commands. (line 712) * vsllink: Debug Adapter Configuration. (line 516) * wait_halt: General Commands. (line 116) * wp: General Commands. (line 329) * xscale analyze_trace: Architecture and Core Commands. (line 514) * xscale cache_clean_address: Architecture and Core Commands. (line 517) * xscale cache_info: Architecture and Core Commands. (line 520) * xscale cp15: Architecture and Core Commands. (line 523) * xscale dcache: Architecture and Core Commands. (line 530) * xscale debug_handler: Architecture and Core Commands. (line 527) * xscale dump_trace: Architecture and Core Commands. (line 533) * xscale icache: Architecture and Core Commands. (line 536) * xscale mmu: Architecture and Core Commands. (line 539) * xscale trace_buffer: Architecture and Core Commands. (line 542) * xscale trace_image: Architecture and Core Commands. (line 547) * xscale vector_catch: Architecture and Core Commands. (line 553) * xscale vector_table: Architecture and Core Commands. (line 568) * xsvf: Boundary Scan Commands. (line 32) * ZY1000: Debug Adapter Configuration. (line 551) openocd-0.7.0/doc/openocd.texi0000644000175000001440000122772512141300571013163 00000000000000\input texinfo @c -*-texinfo-*- @c %**start of header @setfilename openocd.info @settitle OpenOCD User's Guide @dircategory Development @direntry * OpenOCD: (openocd). OpenOCD User's Guide @end direntry @paragraphindent 0 @c %**end of header @include version.texi @copying This User's Guide documents release @value{VERSION}, dated @value{UPDATED}, of the Open On-Chip Debugger (OpenOCD). @itemize @bullet @item Copyright @copyright{} 2008 The OpenOCD Project @item Copyright @copyright{} 2007-2008 Spencer Oliver @email{spen@@spen-soft.co.uk} @item Copyright @copyright{} 2008-2010 Oyvind Harboe @email{oyvind.harboe@@zylin.com} @item Copyright @copyright{} 2008 Duane Ellis @email{openocd@@duaneellis.com} @item Copyright @copyright{} 2009-2010 David Brownell @end itemize @quotation Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, with no Front-Cover Texts, and with no Back-Cover Texts. A copy of the license is included in the section entitled ``GNU Free Documentation License''. @end quotation @end copying @titlepage @titlefont{@emph{Open On-Chip Debugger:}} @sp 1 @title OpenOCD User's Guide @subtitle for release @value{VERSION} @subtitle @value{UPDATED} @page @vskip 0pt plus 1filll @insertcopying @end titlepage @summarycontents @contents @ifnottex @node Top @top OpenOCD User's Guide @insertcopying @end ifnottex @menu * About:: About OpenOCD * Developers:: OpenOCD Developer Resources * Debug Adapter Hardware:: Debug Adapter Hardware * About Jim-Tcl:: About Jim-Tcl * Running:: Running OpenOCD * OpenOCD Project Setup:: OpenOCD Project Setup * Config File Guidelines:: Config File Guidelines * Daemon Configuration:: Daemon Configuration * Debug Adapter Configuration:: Debug Adapter Configuration * Reset Configuration:: Reset Configuration * TAP Declaration:: TAP Declaration * CPU Configuration:: CPU Configuration * Flash Commands:: Flash Commands * Flash Programming:: Flash Programming * NAND Flash Commands:: NAND Flash Commands * PLD/FPGA Commands:: PLD/FPGA Commands * General Commands:: General Commands * Architecture and Core Commands:: Architecture and Core Commands * JTAG Commands:: JTAG Commands * Boundary Scan Commands:: Boundary Scan Commands * TFTP:: TFTP * GDB and OpenOCD:: Using GDB and OpenOCD * Tcl Scripting API:: Tcl Scripting API * FAQ:: Frequently Asked Questions * Tcl Crash Course:: Tcl Crash Course * License:: GNU Free Documentation License @comment DO NOT use the plain word ``Index'', reason: CYGWIN filename @comment case issue with ``Index.html'' and ``index.html'' @comment Occurs when creating ``--html --no-split'' output @comment This fix is based on: http://sourceware.org/ml/binutils/2006-05/msg00215.html * OpenOCD Concept Index:: Concept Index * Command and Driver Index:: Command and Driver Index @end menu @node About @unnumbered About @cindex about OpenOCD was created by Dominic Rath as part of a diploma thesis written at the University of Applied Sciences Augsburg (@uref{http://www.fh-augsburg.de}). Since that time, the project has grown into an active open-source project, supported by a diverse community of software and hardware developers from around the world. @section What is OpenOCD? @cindex TAP @cindex JTAG The Open On-Chip Debugger (OpenOCD) aims to provide debugging, in-system programming and boundary-scan testing for embedded target devices. It does so with the assistance of a @dfn{debug adapter}, which is a small hardware module which helps provide the right kind of electrical signaling to the target being debugged. These are required since the debug host (on which OpenOCD runs) won't usually have native support for such signaling, or the connector needed to hook up to the target. Such debug adapters support one or more @dfn{transport} protocols, each of which involves different electrical signaling (and uses different messaging protocols on top of that signaling). There are many types of debug adapter, and little uniformity in what they are called. (There are also product naming differences.) These adapters are sometimes packaged as discrete dongles, which may generically be called @dfn{hardware interface dongles}. Some development boards also integrate them directly, which may let the development board can be directly connected to the debug host over USB (and sometimes also to power it over USB). For example, a @dfn{JTAG Adapter} supports JTAG signaling, and is used to communicate with JTAG (IEEE 1149.1) compliant TAPs on your target board. A @dfn{TAP} is a ``Test Access Port'', a module which processes special instructions and data. TAPs are daisy-chained within and between chips and boards. JTAG supports debugging and boundary scan operations. There are also @dfn{SWD Adapters} that support Serial Wire Debug (SWD) signaling to communicate with some newer ARM cores, as well as debug adapters which support both JTAG and SWD transports. SWD only supports debugging, whereas JTAG also supports boundary scan operations. For some chips, there are also @dfn{Programming Adapters} supporting special transports used only to write code to flash memory, without support for on-chip debugging or boundary scan. (At this writing, OpenOCD does not support such non-debug adapters.) @b{Dongles:} OpenOCD currently supports many types of hardware dongles: USB based, parallel port based, and other standalone boxes that run OpenOCD internally. @xref{Debug Adapter Hardware}. @b{GDB Debug:} It allows ARM7 (ARM7TDMI and ARM720t), ARM9 (ARM920T, ARM922T, ARM926EJ--S, ARM966E--S), XScale (PXA25x, IXP42x) and Cortex-M3 (Stellaris LM3, ST STM32 and Energy Micro EFM32) based cores to be debugged via the GDB protocol. @b{Flash Programing:} Flash writing is supported for external CFI compatible NOR flashes (Intel and AMD/Spansion command set) and several internal flashes (LPC1700, LPC1800, LPC2000, LPC4300, AT91SAM7, AT91SAM3U, STR7x, STR9x, LM3, STM32x and EFM32). Preliminary support for various NAND flash controllers (LPC3180, Orion, S3C24xx, more) controller is included. @section OpenOCD Web Site The OpenOCD web site provides the latest public news from the community: @uref{http://openocd.sourceforge.net/} @section Latest User's Guide: The user's guide you are now reading may not be the latest one available. A version for more recent code may be available. Its HTML form is published regularly at: @uref{http://openocd.sourceforge.net/doc/html/index.html} PDF form is likewise published at: @uref{http://openocd.sourceforge.net/doc/pdf/openocd.pdf} @section OpenOCD User's Forum There is an OpenOCD forum (phpBB) hosted by SparkFun, which might be helpful to you. Note that if you want anything to come to the attention of developers, you should post it to the OpenOCD Developer Mailing List instead of this forum. @uref{http://forum.sparkfun.com/viewforum.php?f=18} @section OpenOCD User's Mailing List The OpenOCD User Mailing List provides the primary means of communication between users: @uref{https://lists.sourceforge.net/mailman/listinfo/openocd-user} @section OpenOCD IRC Support can also be found on irc: @uref{irc://irc.freenode.net/openocd} @node Developers @chapter OpenOCD Developer Resources @cindex developers If you are interested in improving the state of OpenOCD's debugging and testing support, new contributions will be welcome. Motivated developers can produce new target, flash or interface drivers, improve the documentation, as well as more conventional bug fixes and enhancements. The resources in this chapter are available for developers wishing to explore or expand the OpenOCD source code. @section OpenOCD GIT Repository During the 0.3.x release cycle, OpenOCD switched from Subversion to a GIT repository hosted at SourceForge. The repository URL is: @uref{git://git.code.sf.net/p/openocd/code} or via http @uref{http://git.code.sf.net/p/openocd/code} You may prefer to use a mirror and the HTTP protocol: @uref{http://repo.or.cz/r/openocd.git} With standard GIT tools, use @command{git clone} to initialize a local repository, and @command{git pull} to update it. There are also gitweb pages letting you browse the repository with a web browser, or download arbitrary snapshots without needing a GIT client: @uref{http://repo.or.cz/w/openocd.git} The @file{README} file contains the instructions for building the project from the repository or a snapshot. Developers that want to contribute patches to the OpenOCD system are @b{strongly} encouraged to work against mainline. Patches created against older versions may require additional work from their submitter in order to be updated for newer releases. @section Doxygen Developer Manual During the 0.2.x release cycle, the OpenOCD project began providing a Doxygen reference manual. This document contains more technical information about the software internals, development processes, and similar documentation: @uref{http://openocd.sourceforge.net/doc/doxygen/html/index.html} This document is a work-in-progress, but contributions would be welcome to fill in the gaps. All of the source files are provided in-tree, listed in the Doxyfile configuration in the top of the source tree. @section OpenOCD Developer Mailing List The OpenOCD Developer Mailing List provides the primary means of communication between developers: @uref{https://lists.sourceforge.net/mailman/listinfo/openocd-devel} Discuss and submit patches to this list. The @file{HACKING} file contains basic information about how to prepare patches. @section OpenOCD Bug Database During the 0.4.x release cycle the OpenOCD project team began using Trac for its bug database: @uref{https://sourceforge.net/apps/trac/openocd} @node Debug Adapter Hardware @chapter Debug Adapter Hardware @cindex dongles @cindex FTDI @cindex wiggler @cindex zy1000 @cindex printer port @cindex USB Adapter @cindex RTCK Defined: @b{dongle}: A small device that plugins into a computer and serves as an adapter .... [snip] In the OpenOCD case, this generally refers to @b{a small adapter} that attaches to your computer via USB or the Parallel Printer Port. One exception is the Zylin ZY1000, packaged as a small box you attach via an ethernet cable. The Zylin ZY1000 has the advantage that it does not require any drivers to be installed on the developer PC. It also has a built in web interface. It supports RTCK/RCLK or adaptive clocking and has a built in relay to power cycle targets remotely. @section Choosing a Dongle There are several things you should keep in mind when choosing a dongle. @enumerate @item @b{Transport} Does it support the kind of communication that you need? OpenOCD focusses mostly on JTAG. Your version may also support other ways to communicate with target devices. @item @b{Voltage} What voltage is your target - 1.8, 2.8, 3.3, or 5V? Does your dongle support it? You might need a level converter. @item @b{Pinout} What pinout does your target board use? Does your dongle support it? You may be able to use jumper wires, or an "octopus" connector, to convert pinouts. @item @b{Connection} Does your computer have the USB, printer, or Ethernet port needed? @item @b{RTCK} Do you expect to use it with ARM chips and boards with RTCK support? Also known as ``adaptive clocking'' @end enumerate @section Stand alone Systems @b{ZY1000} See: @url{http://www.ultsol.com/index.php/component/content/article/8/33-zylin-zy1000-jtag-probe} Technically, not a dongle, but a standalone box. The ZY1000 has the advantage that it does not require any drivers installed on the developer PC. It also has a built in web interface. It supports RTCK/RCLK or adaptive clocking and has a built in relay to power cycle targets remotely. @section USB FT2232 Based There are many USB JTAG dongles on the market, many of them are based on a chip from ``Future Technology Devices International'' (FTDI) known as the FTDI FT2232; this is a USB full speed (12 Mbps) chip. See: @url{http://www.ftdichip.com} for more information. In summer 2009, USB high speed (480 Mbps) versions of these FTDI chips are starting to become available in JTAG adapters. Around 2012 a new variant appeared - FT232H - this is a single-channel version of FT2232H. (Adapters using those high speed FT2232H or FT232H chips may support adaptive clocking.) The FT2232 chips are flexible enough to support some other transport options, such as SWD or the SPI variants used to program some chips. They have two communications channels, and one can be used for a UART adapter at the same time the other one is used to provide a debug adapter. Also, some development boards integrate an FT2232 chip to serve as a built-in low cost debug adapter and usb-to-serial solution. @itemize @bullet @item @b{usbjtag} @* Link @url{http://elk.informatik.fh-augsburg.de/hhweb/doc/openocd/usbjtag/usbjtag.html} @item @b{jtagkey} @* See: @url{http://www.amontec.com/jtagkey.shtml} @item @b{jtagkey2} @* See: @url{http://www.amontec.com/jtagkey2.shtml} @item @b{oocdlink} @* See: @url{http://www.oocdlink.com} By Joern Kaipf @item @b{signalyzer} @* See: @url{http://www.signalyzer.com} @item @b{Stellaris Eval Boards} @* See: @url{http://www.ti.com} - The Stellaris eval boards bundle FT2232-based JTAG and SWD support, which can be used to debug the Stellaris chips. Using separate JTAG adapters is optional. These boards can also be used in a "pass through" mode as JTAG adapters to other target boards, disabling the Stellaris chip. @item @b{TI/Luminary ICDI} @* See: @url{http://www.ti.com} - TI/Luminary In-Circuit Debug Interface (ICDI) Boards are included in Stellaris LM3S9B9x Evaluation Kits. Like the non-detachable FT2232 support on the other Stellaris eval boards, they can be used to debug other target boards. @item @b{olimex-jtag} @* See: @url{http://www.olimex.com} @item @b{Flyswatter/Flyswatter2} @* See: @url{http://www.tincantools.com} @item @b{turtelizer2} @* See: @uref{http://www.ethernut.de/en/hardware/turtelizer/index.html, Turtelizer 2}, or @url{http://www.ethernut.de} @item @b{comstick} @* Link: @url{http://www.hitex.com/index.php?id=383} @item @b{stm32stick} @* Link @url{http://www.hitex.com/stm32-stick} @item @b{axm0432_jtag} @* Axiom AXM-0432 Link @url{http://www.axman.com} - NOTE: This JTAG does not appear to be available anymore as of April 2012. @item @b{cortino} @* Link @url{http://www.hitex.com/index.php?id=cortino} @item @b{dlp-usb1232h} @* Link @url{http://www.dlpdesign.com/usb/usb1232h.shtml} @item @b{digilent-hs1} @* Link @url{http://www.digilentinc.com/Products/Detail.cfm?Prod=JTAG-HS1} @item @b{opendous} @* Link @url{http://code.google.com/p/opendous/wiki/JTAG} FT2232H-based (OpenHardware). @item @b{JTAG-lock-pick Tiny 2} @* Link @url{http://www.distortec.com/jtag-lock-pick-tiny-2} FT232H-based @end itemize @section USB-JTAG / Altera USB-Blaster compatibles These devices also show up as FTDI devices, but are not protocol-compatible with the FT2232 devices. They are, however, protocol-compatible among themselves. USB-JTAG devices typically consist of a FT245 followed by a CPLD that understands a particular protocol, or emulate this protocol using some other hardware. They may appear under different USB VID/PID depending on the particular product. The driver can be configured to search for any VID/PID pair (see the section on driver commands). @itemize @item @b{USB-JTAG} Kolja Waschk's USB Blaster-compatible adapter @* Link: @url{http://ixo-jtag.sourceforge.net/} @item @b{Altera USB-Blaster} @* Link: @url{http://www.altera.com/literature/ug/ug_usb_blstr.pdf} @end itemize @section USB JLINK based There are several OEM versions of the Segger @b{JLINK} adapter. It is an example of a micro controller based JTAG adapter, it uses an AT91SAM764 internally. @itemize @bullet @item @b{ATMEL SAMICE} Only works with ATMEL chips! @* Link: @url{http://www.atmel.com/dyn/products/tools_card.asp?tool_id=3892} @item @b{SEGGER JLINK} @* Link: @url{http://www.segger.com/jlink.html} @item @b{IAR J-Link} @* Link: @url{http://www.iar.com/en/products/hardware-debug-probes/iar-j-link/} @end itemize @section USB RLINK based Raisonance has an adapter called @b{RLink}. It exists in a stripped-down form on the STM32 Primer, permanently attached to the JTAG lines. It also exists on the STM32 Primer2, but that is wired for SWD and not JTAG, thus not supported. @itemize @bullet @item @b{Raisonance RLink} @* Link: @url{http://www.mcu-raisonance.com/~rlink-debugger-programmer__microcontrollers__tool~tool__T018:4cn9ziz4bnx6.html} @item @b{STM32 Primer} @* Link: @url{http://www.stm32circle.com/resources/stm32primer.php} @item @b{STM32 Primer2} @* Link: @url{http://www.stm32circle.com/resources/stm32primer2.php} @end itemize @section USB ST-LINK based ST Micro has an adapter called @b{ST-LINK}. They only work with ST Micro chips, notably STM32 and STM8. @itemize @bullet @item @b{ST-LINK} @* This is available standalone and as part of some kits, eg. STM32VLDISCOVERY. @* Link: @url{http://www.st.com/internet/evalboard/product/219866.jsp} @item @b{ST-LINK/V2} @* This is available standalone and as part of some kits, eg. STM32F4DISCOVERY. @* Link: @url{http://www.st.com/internet/evalboard/product/251168.jsp} @end itemize For info the original ST-LINK enumerates using the mass storage usb class, however it's implementation is completely broken. The result is this causes issues under linux. The simplest solution is to get linux to ignore the ST-LINK using one of the following methods: @itemize @bullet @item modprobe -r usb-storage && modprobe usb-storage quirks=483:3744:i @item add "options usb-storage quirks=483:3744:i" to /etc/modprobe.conf @end itemize @section USB TI/Stellaris ICDI based Texas Instruments has an adapter called @b{ICDI}. It is not to be confused with the FTDI based adapters that were originally fitted to their evaluation boards. This is the adapter fitted to the Stellaris LaunchPad. @section USB Other @itemize @bullet @item @b{USBprog} @* Link: @url{http://shop.embedded-projects.net/} - which uses an Atmel MEGA32 and a UBN9604 @item @b{USB - Presto} @* Link: @url{http://tools.asix.net/prg_presto.htm} @item @b{Versaloon-Link} @* Link: @url{http://www.versaloon.com} @item @b{ARM-JTAG-EW} @* Link: @url{http://www.olimex.com/dev/arm-jtag-ew.html} @item @b{Buspirate} @* Link: @url{http://dangerousprototypes.com/bus-pirate-manual/} @item @b{opendous} @* Link: @url{http://code.google.com/p/opendous-jtag/} - which uses an AT90USB162 @item @b{estick} @* Link: @url{http://code.google.com/p/estick-jtag/} @item @b{Keil ULINK v1} @* Link: @url{http://www.keil.com/ulink1/} @end itemize @section IBM PC Parallel Printer Port Based The two well known ``JTAG Parallel Ports'' cables are the Xilnx DLC5 and the Macraigor Wiggler. There are many clones and variations of these on the market. Note that parallel ports are becoming much less common, so if you have the choice you should probably avoid these adapters in favor of USB-based ones. @itemize @bullet @item @b{Wiggler} - There are many clones of this. @* Link: @url{http://www.macraigor.com/wiggler.htm} @item @b{DLC5} - From XILINX - There are many clones of this @* Link: Search the web for: ``XILINX DLC5'' - it is no longer produced, PDF schematics are easily found and it is easy to make. @item @b{Amontec - JTAG Accelerator} @* Link: @url{http://www.amontec.com/jtag_accelerator.shtml} @item @b{GW16402} @* Link: @url{http://www.gateworks.com/products/avila_accessories/gw16042.php} @item @b{Wiggler2} @* Link: @url{http://www.ccac.rwth-aachen.de/~michaels/index.php/hardware/armjtag} @item @b{Wiggler_ntrst_inverted} @* Yet another variation - See the source code, src/jtag/parport.c @item @b{old_amt_wiggler} @* Unknown - probably not on the market today @item @b{arm-jtag} @* Link: Most likely @url{http://www.olimex.com/dev/arm-jtag.html} [another wiggler clone] @item @b{chameleon} @* Link: @url{http://www.amontec.com/chameleon.shtml} @item @b{Triton} @* Unknown. @item @b{Lattice} @* ispDownload from Lattice Semiconductor @url{http://www.latticesemi.com/lit/docs/@/devtools/dlcable.pdf} @item @b{flashlink} @* From ST Microsystems; @* Link: @url{http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATA_BRIEF/DM00039500.pdf} @end itemize @section Other... @itemize @bullet @item @b{ep93xx} @* An EP93xx based Linux machine using the GPIO pins directly. @item @b{at91rm9200} @* Like the EP93xx - but an ATMEL AT91RM9200 based solution using the GPIO pins on the chip. @end itemize @node About Jim-Tcl @chapter About Jim-Tcl @cindex Jim-Tcl @cindex tcl OpenOCD uses a small ``Tcl Interpreter'' known as Jim-Tcl. This programming language provides a simple and extensible command interpreter. All commands presented in this Guide are extensions to Jim-Tcl. You can use them as simple commands, without needing to learn much of anything about Tcl. Alternatively, can write Tcl programs with them. You can learn more about Jim at its website, @url{http://jim.berlios.de}. There is an active and responsive community, get on the mailing list if you have any questions. Jim-Tcl maintainers also lurk on the OpenOCD mailing list. @itemize @bullet @item @b{Jim vs. Tcl} @* Jim-Tcl is a stripped down version of the well known Tcl language, which can be found here: @url{http://www.tcl.tk}. Jim-Tcl has far fewer features. Jim-Tcl is several dozens of .C files and .H files and implements the basic Tcl command set. In contrast: Tcl 8.6 is a 4.2 MB .zip file containing 1540 files. @item @b{Missing Features} @* Our practice has been: Add/clone the real Tcl feature if/when needed. We welcome Jim-Tcl improvements, not bloat. Also there are a large number of optional Jim-Tcl features that are not enabled in OpenOCD. @item @b{Scripts} @* OpenOCD configuration scripts are Jim-Tcl Scripts. OpenOCD's command interpreter today is a mixture of (newer) Jim-Tcl commands, and (older) the orginal command interpreter. @item @b{Commands} @* At the OpenOCD telnet command line (or via the GDB monitor command) one can type a Tcl for() loop, set variables, etc. Some of the commands documented in this guide are implemented as Tcl scripts, from a @file{startup.tcl} file internal to the server. @item @b{Historical Note} @* Jim-Tcl was introduced to OpenOCD in spring 2008. Fall 2010, before OpenOCD 0.5 release OpenOCD switched to using Jim Tcl as a git submodule, which greatly simplified upgrading Jim Tcl to benefit from new features and bugfixes in Jim Tcl. @item @b{Need a crash course in Tcl?} @*@xref{Tcl Crash Course}. @end itemize @node Running @chapter Running @cindex command line options @cindex logfile @cindex directory search Properly installing OpenOCD sets up your operating system to grant it access to the debug adapters. On Linux, this usually involves installing a file in @file{/etc/udev/rules.d,} so OpenOCD has permissions. MS-Windows needs complex and confusing driver configuration for every peripheral. Such issues are unique to each operating system, and are not detailed in this User's Guide. Then later you will invoke the OpenOCD server, with various options to tell it how each debug session should work. The @option{--help} option shows: @verbatim bash$ openocd --help --help | -h display this help --version | -v display OpenOCD version --file | -f use configuration file --search | -s dir to search for config files and scripts --debug | -d set debug level <0-3> --log_output | -l redirect log output to file --command | -c run @end verbatim If you don't give any @option{-f} or @option{-c} options, OpenOCD tries to read the configuration file @file{openocd.cfg}. To specify one or more different configuration files, use @option{-f} options. For example: @example openocd -f config1.cfg -f config2.cfg -f config3.cfg @end example Configuration files and scripts are searched for in @enumerate @item the current directory, @item any search dir specified on the command line using the @option{-s} option, @item any search dir specified using the @command{add_script_search_dir} command, @item @file{$HOME/.openocd} (not on Windows), @item the site wide script library @file{$pkgdatadir/site} and @item the OpenOCD-supplied script library @file{$pkgdatadir/scripts}. @end enumerate The first found file with a matching file name will be used. @quotation Note Don't try to use configuration script names or paths which include the "#" character. That character begins Tcl comments. @end quotation @section Simple setup, no customization In the best case, you can use two scripts from one of the script libraries, hook up your JTAG adapter, and start the server ... and your JTAG setup will just work "out of the box". Always try to start by reusing those scripts, but assume you'll need more customization even if this works. @xref{OpenOCD Project Setup}. If you find a script for your JTAG adapter, and for your board or target, you may be able to hook up your JTAG adapter then start the server like: @example openocd -f interface/ADAPTER.cfg -f board/MYBOARD.cfg @end example You might also need to configure which reset signals are present, using @option{-c 'reset_config trst_and_srst'} or something similar. If all goes well you'll see output something like @example Open On-Chip Debugger 0.4.0 (2010-01-14-15:06) For bug reports, read http://openocd.sourceforge.net/doc/doxygen/bugs.html Info : JTAG tap: lm3s.cpu tap/device found: 0x3ba00477 (mfg: 0x23b, part: 0xba00, ver: 0x3) @end example Seeing that "tap/device found" message, and no warnings, means the JTAG communication is working. That's a key milestone, but you'll probably need more project-specific setup. @section What OpenOCD does as it starts OpenOCD starts by processing the configuration commands provided on the command line or, if there were no @option{-c command} or @option{-f file.cfg} options given, in @file{openocd.cfg}. @xref{configurationstage,,Configuration Stage}. At the end of the configuration stage it verifies the JTAG scan chain defined using those commands; your configuration should ensure that this always succeeds. Normally, OpenOCD then starts running as a daemon. Alternatively, commands may be used to terminate the configuration stage early, perform work (such as updating some flash memory), and then shut down without acting as a daemon. Once OpenOCD starts running as a daemon, it waits for connections from clients (Telnet, GDB, Other) and processes the commands issued through those channels. If you are having problems, you can enable internal debug messages via the @option{-d} option. Also it is possible to interleave Jim-Tcl commands w/config scripts using the @option{-c} command line switch. To enable debug output (when reporting problems or working on OpenOCD itself), use the @option{-d} command line switch. This sets the @option{debug_level} to "3", outputting the most information, including debug messages. The default setting is "2", outputting only informational messages, warnings and errors. You can also change this setting from within a telnet or gdb session using @command{debug_level} (@pxref{debuglevel,,debug_level}). You can redirect all output from the daemon to a file using the @option{-l } switch. Note! OpenOCD will launch the GDB & telnet server even if it can not establish a connection with the target. In general, it is possible for the JTAG controller to be unresponsive until the target is set up correctly via e.g. GDB monitor commands in a GDB init script. @node OpenOCD Project Setup @chapter OpenOCD Project Setup To use OpenOCD with your development projects, you need to do more than just connecting the JTAG adapter hardware (dongle) to your development board and then starting the OpenOCD server. You also need to configure that server so that it knows about that adapter and board, and helps your work. You may also want to connect OpenOCD to GDB, possibly using Eclipse or some other GUI. @section Hooking up the JTAG Adapter Today's most common case is a dongle with a JTAG cable on one side (such as a ribbon cable with a 10-pin or 20-pin IDC connector) and a USB cable on the other. Instead of USB, some cables use Ethernet; older ones may use a PC parallel port, or even a serial port. @enumerate @item @emph{Start with power to your target board turned off}, and nothing connected to your JTAG adapter. If you're particularly paranoid, unplug power to the board. It's important to have the ground signal properly set up, unless you are using a JTAG adapter which provides galvanic isolation between the target board and the debugging host. @item @emph{Be sure it's the right kind of JTAG connector.} If your dongle has a 20-pin ARM connector, you need some kind of adapter (or octopus, see below) to hook it up to boards using 14-pin or 10-pin connectors ... or to 20-pin connectors which don't use ARM's pinout. In the same vein, make sure the voltage levels are compatible. Not all JTAG adapters have the level shifters needed to work with 1.2 Volt boards. @item @emph{Be certain the cable is properly oriented} or you might damage your board. In most cases there are only two possible ways to connect the cable. Connect the JTAG cable from your adapter to the board. Be sure it's firmly connected. In the best case, the connector is keyed to physically prevent you from inserting it wrong. This is most often done using a slot on the board's male connector housing, which must match a key on the JTAG cable's female connector. If there's no housing, then you must look carefully and make sure pin 1 on the cable hooks up to pin 1 on the board. Ribbon cables are frequently all grey except for a wire on one edge, which is red. The red wire is pin 1. Sometimes dongles provide cables where one end is an ``octopus'' of color coded single-wire connectors, instead of a connector block. These are great when converting from one JTAG pinout to another, but are tedious to set up. Use these with connector pinout diagrams to help you match up the adapter signals to the right board pins. @item @emph{Connect the adapter's other end} once the JTAG cable is connected. A USB, parallel, or serial port connector will go to the host which you are using to run OpenOCD. For Ethernet, consult the documentation and your network administrator. For USB based JTAG adapters you have an easy sanity check at this point: does the host operating system see the JTAG adapter? If that host is an MS-Windows host, you'll need to install a driver before OpenOCD works. @item @emph{Connect the adapter's power supply, if needed.} This step is primarily for non-USB adapters, but sometimes USB adapters need extra power. @item @emph{Power up the target board.} Unless you just let the magic smoke escape, you're now ready to set up the OpenOCD server so you can use JTAG to work with that board. @end enumerate Talk with the OpenOCD server using telnet (@code{telnet localhost 4444} on many systems) or GDB. @xref{GDB and OpenOCD}. @section Project Directory There are many ways you can configure OpenOCD and start it up. A simple way to organize them all involves keeping a single directory for your work with a given board. When you start OpenOCD from that directory, it searches there first for configuration files, scripts, files accessed through semihosting, and for code you upload to the target board. It is also the natural place to write files, such as log files and data you download from the board. @section Configuration Basics There are two basic ways of configuring OpenOCD, and a variety of ways you can mix them. Think of the difference as just being how you start the server: @itemize @item Many @option{-f file} or @option{-c command} options on the command line @item No options, but a @dfn{user config file} in the current directory named @file{openocd.cfg} @end itemize Here is an example @file{openocd.cfg} file for a setup using a Signalyzer FT2232-based JTAG adapter to talk to a board with an Atmel AT91SAM7X256 microcontroller: @example source [find interface/signalyzer.cfg] # GDB can also flash my flash! gdb_memory_map enable gdb_flash_program enable source [find target/sam7x256.cfg] @end example Here is the command line equivalent of that configuration: @example openocd -f interface/signalyzer.cfg \ -c "gdb_memory_map enable" \ -c "gdb_flash_program enable" \ -f target/sam7x256.cfg @end example You could wrap such long command lines in shell scripts, each supporting a different development task. One might re-flash the board with a specific firmware version. Another might set up a particular debugging or run-time environment. @quotation Important At this writing (October 2009) the command line method has problems with how it treats variables. For example, after @option{-c "set VAR value"}, or doing the same in a script, the variable @var{VAR} will have no value that can be tested in a later script. @end quotation Here we will focus on the simpler solution: one user config file, including basic configuration plus any TCL procedures to simplify your work. @section User Config Files @cindex config file, user @cindex user config file @cindex config file, overview A user configuration file ties together all the parts of a project in one place. One of the following will match your situation best: @itemize @item Ideally almost everything comes from configuration files provided by someone else. For example, OpenOCD distributes a @file{scripts} directory (probably in @file{/usr/share/openocd/scripts} on Linux). Board and tool vendors can provide these too, as can individual user sites; the @option{-s} command line option lets you say where to find these files. (@xref{Running}.) The AT91SAM7X256 example above works this way. Three main types of non-user configuration file each have their own subdirectory in the @file{scripts} directory: @enumerate @item @b{interface} -- one for each different debug adapter; @item @b{board} -- one for each different board @item @b{target} -- the chips which integrate CPUs and other JTAG TAPs @end enumerate Best case: include just two files, and they handle everything else. The first is an interface config file. The second is board-specific, and it sets up the JTAG TAPs and their GDB targets (by deferring to some @file{target.cfg} file), declares all flash memory, and leaves you nothing to do except meet your deadline: @example source [find interface/olimex-jtag-tiny.cfg] source [find board/csb337.cfg] @end example Boards with a single microcontroller often won't need more than the target config file, as in the AT91SAM7X256 example. That's because there is no external memory (flash, DDR RAM), and the board differences are encapsulated by application code. @item Maybe you don't know yet what your board looks like to JTAG. Once you know the @file{interface.cfg} file to use, you may need help from OpenOCD to discover what's on the board. Once you find the JTAG TAPs, you can just search for appropriate target and board configuration files ... or write your own, from the bottom up. @xref{autoprobing,,Autoprobing}. @item You can often reuse some standard config files but need to write a few new ones, probably a @file{board.cfg} file. You will be using commands described later in this User's Guide, and working with the guidelines in the next chapter. For example, there may be configuration files for your JTAG adapter and target chip, but you need a new board-specific config file giving access to your particular flash chips. Or you might need to write another target chip configuration file for a new chip built around the Cortex M3 core. @quotation Note When you write new configuration files, please submit them for inclusion in the next OpenOCD release. For example, a @file{board/newboard.cfg} file will help the next users of that board, and a @file{target/newcpu.cfg} will help support users of any board using that chip. @end quotation @item You may may need to write some C code. It may be as simple as a supporting a new ft2232 or parport based adapter; a bit more involved, like a NAND or NOR flash controller driver; or a big piece of work like supporting a new chip architecture. @end itemize Reuse the existing config files when you can. Look first in the @file{scripts/boards} area, then @file{scripts/targets}. You may find a board configuration that's a good example to follow. When you write config files, separate the reusable parts (things every user of that interface, chip, or board needs) from ones specific to your environment and debugging approach. @itemize @item For example, a @code{gdb-attach} event handler that invokes the @command{reset init} command will interfere with debugging early boot code, which performs some of the same actions that the @code{reset-init} event handler does. @item Likewise, the @command{arm9 vector_catch} command (or @cindex vector_catch its siblings @command{xscale vector_catch} and @command{cortex_m vector_catch}) can be a timesaver during some debug sessions, but don't make everyone use that either. Keep those kinds of debugging aids in your user config file, along with messaging and tracing setup. (@xref{softwaredebugmessagesandtracing,,Software Debug Messages and Tracing}.) @item You might need to override some defaults. For example, you might need to move, shrink, or back up the target's work area if your application needs much SRAM. @item TCP/IP port configuration is another example of something which is environment-specific, and should only appear in a user config file. @xref{tcpipports,,TCP/IP Ports}. @end itemize @section Project-Specific Utilities A few project-specific utility routines may well speed up your work. Write them, and keep them in your project's user config file. For example, if you are making a boot loader work on a board, it's nice to be able to debug the ``after it's loaded to RAM'' parts separately from the finicky early code which sets up the DDR RAM controller and clocks. A script like this one, or a more GDB-aware sibling, may help: @example proc ramboot @{ @} @{ # Reset, running the target's "reset-init" scripts # to initialize clocks and the DDR RAM controller. # Leave the CPU halted. reset init # Load CONFIG_SKIP_LOWLEVEL_INIT version into DDR RAM. load_image u-boot.bin 0x20000000 # Start running. resume 0x20000000 @} @end example Then once that code is working you will need to make it boot from NOR flash; a different utility would help. Alternatively, some developers write to flash using GDB. (You might use a similar script if you're working with a flash based microcontroller application instead of a boot loader.) @example proc newboot @{ @} @{ # Reset, leaving the CPU halted. The "reset-init" event # proc gives faster access to the CPU and to NOR flash; # "reset halt" would be slower. reset init # Write standard version of U-Boot into the first two # sectors of NOR flash ... the standard version should # do the same lowlevel init as "reset-init". flash protect 0 0 1 off flash erase_sector 0 0 1 flash write_bank 0 u-boot.bin 0x0 flash protect 0 0 1 on # Reboot from scratch using that new boot loader. reset run @} @end example You may need more complicated utility procedures when booting from NAND. That often involves an extra bootloader stage, running from on-chip SRAM to perform DDR RAM setup so it can load the main bootloader code (which won't fit into that SRAM). Other helper scripts might be used to write production system images, involving considerably more than just a three stage bootloader. @section Target Software Changes Sometimes you may want to make some small changes to the software you're developing, to help make JTAG debugging work better. For example, in C or assembly language code you might use @code{#ifdef JTAG_DEBUG} (or its converse) around code handling issues like: @itemize @bullet @item @b{Watchdog Timers}... Watchog timers are typically used to automatically reset systems if some application task doesn't periodically reset the timer. (The assumption is that the system has locked up if the task can't run.) When a JTAG debugger halts the system, that task won't be able to run and reset the timer ... potentially causing resets in the middle of your debug sessions. It's rarely a good idea to disable such watchdogs, since their usage needs to be debugged just like all other parts of your firmware. That might however be your only option. Look instead for chip-specific ways to stop the watchdog from counting while the system is in a debug halt state. It may be simplest to set that non-counting mode in your debugger startup scripts. You may however need a different approach when, for example, a motor could be physically damaged by firmware remaining inactive in a debug halt state. That might involve a type of firmware mode where that "non-counting" mode is disabled at the beginning then re-enabled at the end; a watchdog reset might fire and complicate the debug session, but hardware (or people) would be protected.@footnote{Note that many systems support a "monitor mode" debug that is a somewhat cleaner way to address such issues. You can think of it as only halting part of the system, maybe just one task, instead of the whole thing. At this writing, January 2010, OpenOCD based debugging does not support monitor mode debug, only "halt mode" debug.} @item @b{ARM Semihosting}... @cindex ARM semihosting When linked with a special runtime library provided with many toolchains@footnote{See chapter 8 "Semihosting" in @uref{http://infocenter.arm.com/help/topic/com.arm.doc.dui0203i/DUI0203I_rvct_developer_guide.pdf, ARM DUI 0203I}, the "RealView Compilation Tools Developer Guide". The CodeSourcery EABI toolchain also includes a semihosting library.}, your target code can use I/O facilities on the debug host. That library provides a small set of system calls which are handled by OpenOCD. It can let the debugger provide your system console and a file system, helping with early debugging or providing a more capable environment for sometimes-complex tasks like installing system firmware onto NAND or SPI flash. @item @b{ARM Wait-For-Interrupt}... Many ARM chips synchronize the JTAG clock using the core clock. Low power states which stop that core clock thus prevent JTAG access. Idle loops in tasking environments often enter those low power states via the @code{WFI} instruction (or its coprocessor equivalent, before ARMv7). You may want to @emph{disable that instruction} in source code, or otherwise prevent using that state, to ensure you can get JTAG access at any time.@footnote{As a more polite alternative, some processors have special debug-oriented registers which can be used to change various features including how the low power states are clocked while debugging. The STM32 DBGMCU_CR register is an example; at the cost of extra power consumption, JTAG can be used during low power states.} For example, the OpenOCD @command{halt} command may not work for an idle processor otherwise. @item @b{Delay after reset}... Not all chips have good support for debugger access right after reset; many LPC2xxx chips have issues here. Similarly, applications that reconfigure pins used for JTAG access as they start will also block debugger access. To work with boards like this, @emph{enable a short delay loop} the first thing after reset, before "real" startup activities. For example, one second's delay is usually more than enough time for a JTAG debugger to attach, so that early code execution can be debugged or firmware can be replaced. @item @b{Debug Communications Channel (DCC)}... Some processors include mechanisms to send messages over JTAG. Many ARM cores support these, as do some cores from other vendors. (OpenOCD may be able to use this DCC internally, speeding up some operations like writing to memory.) Your application may want to deliver various debugging messages over JTAG, by @emph{linking with a small library of code} provided with OpenOCD and using the utilities there to send various kinds of message. @xref{softwaredebugmessagesandtracing,,Software Debug Messages and Tracing}. @end itemize @section Target Hardware Setup Chip vendors often provide software development boards which are highly configurable, so that they can support all options that product boards may require. @emph{Make sure that any jumpers or switches match the system configuration you are working with.} Common issues include: @itemize @bullet @item @b{JTAG setup} ... Boards may support more than one JTAG configuration. Examples include jumpers controlling pullups versus pulldowns on the nTRST and/or nSRST signals, and choice of connectors (e.g. which of two headers on the base board, or one from a daughtercard). For some Texas Instruments boards, you may need to jumper the EMU0 and EMU1 signals (which OpenOCD won't currently control). @item @b{Boot Modes} ... Complex chips often support multiple boot modes, controlled by external jumpers. Make sure this is set up correctly. For example many i.MX boards from NXP need to be jumpered to "ATX mode" to start booting using the on-chip ROM, when using second stage bootloader code stored in a NAND flash chip. Such explicit configuration is common, and not limited to booting from NAND. You might also need to set jumpers to start booting using code loaded from an MMC/SD card; external SPI flash; Ethernet, UART, or USB links; NOR flash; OneNAND flash; some external host; or various other sources. @item @b{Memory Addressing} ... Boards which support multiple boot modes may also have jumpers to configure memory addressing. One board, for example, jumpers external chipselect 0 (used for booting) to address either a large SRAM (which must be pre-loaded via JTAG), NOR flash, or NAND flash. When it's jumpered to address NAND flash, that board must also be told to start booting from on-chip ROM. Your @file{board.cfg} file may also need to be told this jumper configuration, so that it can know whether to declare NOR flash using @command{flash bank} or instead declare NAND flash with @command{nand device}; and likewise which probe to perform in its @code{reset-init} handler. A closely related issue is bus width. Jumpers might need to distinguish between 8 bit or 16 bit bus access for the flash used to start booting. @item @b{Peripheral Access} ... Development boards generally provide access to every peripheral on the chip, sometimes in multiple modes (such as by providing multiple audio codec chips). This interacts with software configuration of pin multiplexing, where for example a given pin may be routed either to the MMC/SD controller or the GPIO controller. It also often interacts with configuration jumpers. One jumper may be used to route signals to an MMC/SD card slot or an expansion bus (which might in turn affect booting); others might control which audio or video codecs are used. @end itemize Plus you should of course have @code{reset-init} event handlers which set up the hardware to match that jumper configuration. That includes in particular any oscillator or PLL used to clock the CPU, and any memory controllers needed to access external memory and peripherals. Without such handlers, you won't be able to access those resources without working target firmware which can do that setup ... this can be awkward when you're trying to debug that target firmware. Even if there's a ROM bootloader which handles a few issues, it rarely provides full access to all board-specific capabilities. @node Config File Guidelines @chapter Config File Guidelines This chapter is aimed at any user who needs to write a config file, including developers and integrators of OpenOCD and any user who needs to get a new board working smoothly. It provides guidelines for creating those files. You should find the following directories under @t{$(INSTALLDIR)/scripts}, with files including the ones listed here. Use them as-is where you can; or as models for new files. @itemize @bullet @item @file{interface} ... These are for debug adapters. Files that configure JTAG adapters go here. @example $ ls interface -R interface/: altera-usb-blaster.cfg hilscher_nxhx50_re.cfg openocd-usb-hs.cfg arm-jtag-ew.cfg hitex_str9-comstick.cfg openrd.cfg at91rm9200.cfg icebear.cfg osbdm.cfg axm0432.cfg jlink.cfg parport.cfg busblaster.cfg jtagkey2.cfg parport_dlc5.cfg buspirate.cfg jtagkey2p.cfg redbee-econotag.cfg calao-usb-a9260-c01.cfg jtagkey.cfg redbee-usb.cfg calao-usb-a9260-c02.cfg jtagkey-tiny.cfg rlink.cfg calao-usb-a9260.cfg jtag-lock-pick_tiny_2.cfg sheevaplug.cfg chameleon.cfg kt-link.cfg signalyzer.cfg cortino.cfg lisa-l.cfg signalyzer-h2.cfg digilent-hs1.cfg luminary.cfg signalyzer-h4.cfg dlp-usb1232h.cfg luminary-icdi.cfg signalyzer-lite.cfg dummy.cfg luminary-lm3s811.cfg stlink-v1.cfg estick.cfg minimodule.cfg stlink-v2.cfg flashlink.cfg neodb.cfg stm32-stick.cfg flossjtag.cfg ngxtech.cfg sysfsgpio-raspberrypi.cfg flossjtag-noeeprom.cfg olimex-arm-usb-ocd.cfg ti-icdi.cfg flyswatter2.cfg olimex-arm-usb-ocd-h.cfg turtelizer2.cfg flyswatter.cfg olimex-arm-usb-tiny-h.cfg ulink.cfg ftdi olimex-jtag-tiny.cfg usb-jtag.cfg hilscher_nxhx10_etm.cfg oocdlink.cfg usbprog.cfg hilscher_nxhx500_etm.cfg opendous.cfg vpaclink.cfg hilscher_nxhx500_re.cfg opendous_ftdi.cfg vsllink.cfg hilscher_nxhx50_etm.cfg openocd-usb.cfg xds100v2.cfg interface/ftdi: axm0432.cfg icebear.cfg oocdlink.cfg calao-usb-a9260-c01.cfg jtagkey2.cfg opendous_ftdi.cfg calao-usb-a9260-c02.cfg jtagkey2p.cfg openocd-usb.cfg cortino.cfg jtagkey.cfg openocd-usb-hs.cfg dlp-usb1232h.cfg jtag-lock-pick_tiny_2.cfg openrd.cfg dp_busblaster.cfg kt-link.cfg redbee-econotag.cfg flossjtag.cfg lisa-l.cfg redbee-usb.cfg flossjtag-noeeprom.cfg luminary.cfg sheevaplug.cfg flyswatter2.cfg luminary-icdi.cfg signalyzer.cfg flyswatter.cfg luminary-lm3s811.cfg signalyzer-lite.cfg hilscher_nxhx10_etm.cfg minimodule.cfg stm32-stick.cfg hilscher_nxhx500_etm.cfg neodb.cfg turtelizer2-revB.cfg hilscher_nxhx500_re.cfg ngxtech.cfg turtelizer2-revC.cfg hilscher_nxhx50_etm.cfg olimex-arm-usb-ocd.cfg vpaclink.cfg hilscher_nxhx50_re.cfg olimex-arm-usb-ocd-h.cfg xds100v2.cfg hitex_lpc1768stick.cfg olimex-arm-usb-tiny-h.cfg hitex_str9-comstick.cfg olimex-jtag-tiny.cfg $ @end example @item @file{board} ... think Circuit Board, PWA, PCB, they go by many names. Board files contain initialization items that are specific to a board. They reuse target configuration files, since the same microprocessor chips are used on many boards, but support for external parts varies widely. For example, the SDRAM initialization sequence for the board, or the type of external flash and what address it uses. Any initialization sequence to enable that external flash or SDRAM should be found in the board file. Boards may also contain multiple targets: two CPUs; or a CPU and an FPGA. @example $ ls board actux3.cfg lpc1850_spifi_generic.cfg am3517evm.cfg lpc4350_spifi_generic.cfg arm_evaluator7t.cfg lubbock.cfg at91cap7a-stk-sdram.cfg mcb1700.cfg at91eb40a.cfg microchip_explorer16.cfg at91rm9200-dk.cfg mini2440.cfg at91rm9200-ek.cfg mini6410.cfg at91sam9261-ek.cfg netgear-dg834v3.cfg at91sam9263-ek.cfg olimex_LPC2378STK.cfg at91sam9g20-ek.cfg olimex_lpc_h2148.cfg atmel_at91sam7s-ek.cfg olimex_sam7_ex256.cfg atmel_at91sam9260-ek.cfg olimex_sam9_l9260.cfg atmel_at91sam9rl-ek.cfg olimex_stm32_h103.cfg atmel_sam3n_ek.cfg olimex_stm32_h107.cfg atmel_sam3s_ek.cfg olimex_stm32_p107.cfg atmel_sam3u_ek.cfg omap2420_h4.cfg atmel_sam3x_ek.cfg open-bldc.cfg atmel_sam4s_ek.cfg openrd.cfg balloon3-cpu.cfg osk5912.cfg colibri.cfg phone_se_j100i.cfg crossbow_tech_imote2.cfg phytec_lpc3250.cfg csb337.cfg pic-p32mx.cfg csb732.cfg propox_mmnet1001.cfg da850evm.cfg pxa255_sst.cfg digi_connectcore_wi-9c.cfg redbee.cfg diolan_lpc4350-db1.cfg rsc-w910.cfg dm355evm.cfg sheevaplug.cfg dm365evm.cfg smdk6410.cfg dm6446evm.cfg spear300evb.cfg efikamx.cfg spear300evb_mod.cfg eir.cfg spear310evb20.cfg ek-lm3s1968.cfg spear310evb20_mod.cfg ek-lm3s3748.cfg spear320cpu.cfg ek-lm3s6965.cfg spear320cpu_mod.cfg ek-lm3s811.cfg steval_pcc010.cfg ek-lm3s811-revb.cfg stm320518_eval_stlink.cfg ek-lm3s8962.cfg stm32100b_eval.cfg ek-lm3s9b9x.cfg stm3210b_eval.cfg ek-lm3s9d92.cfg stm3210c_eval.cfg ek-lm4f120xl.cfg stm3210e_eval.cfg ek-lm4f232.cfg stm3220g_eval.cfg embedded-artists_lpc2478-32.cfg stm3220g_eval_stlink.cfg ethernut3.cfg stm3241g_eval.cfg glyn_tonga2.cfg stm3241g_eval_stlink.cfg hammer.cfg stm32f0discovery.cfg hilscher_nxdb500sys.cfg stm32f3discovery.cfg hilscher_nxeb500hmi.cfg stm32f4discovery.cfg hilscher_nxhx10.cfg stm32ldiscovery.cfg hilscher_nxhx500.cfg stm32vldiscovery.cfg hilscher_nxhx50.cfg str910-eval.cfg hilscher_nxsb100.cfg telo.cfg hitex_lpc1768stick.cfg ti_am335xevm.cfg hitex_lpc2929.cfg ti_beagleboard.cfg hitex_stm32-performancestick.cfg ti_beagleboard_xm.cfg hitex_str9-comstick.cfg ti_beaglebone.cfg iar_lpc1768.cfg ti_blaze.cfg iar_str912_sk.cfg ti_pandaboard.cfg icnova_imx53_sodimm.cfg ti_pandaboard_es.cfg icnova_sam9g45_sodimm.cfg topas910.cfg imx27ads.cfg topasa900.cfg imx27lnst.cfg twr-k60f120m.cfg imx28evk.cfg twr-k60n512.cfg imx31pdk.cfg tx25_stk5.cfg imx35pdk.cfg tx27_stk5.cfg imx53loco.cfg unknown_at91sam9260.cfg keil_mcb1700.cfg uptech_2410.cfg keil_mcb2140.cfg verdex.cfg kwikstik.cfg voipac.cfg linksys_nslu2.cfg voltcraft_dso-3062c.cfg lisa-l.cfg x300t.cfg logicpd_imx27.cfg zy1000.cfg $ @end example @item @file{target} ... think chip. The ``target'' directory represents the JTAG TAPs on a chip which OpenOCD should control, not a board. Two common types of targets are ARM chips and FPGA or CPLD chips. When a chip has multiple TAPs (maybe it has both ARM and DSP cores), the target config file defines all of them. @example $ ls target aduc702x.cfg lpc1763.cfg am335x.cfg lpc1764.cfg amdm37x.cfg lpc1765.cfg ar71xx.cfg lpc1766.cfg at32ap7000.cfg lpc1767.cfg at91r40008.cfg lpc1768.cfg at91rm9200.cfg lpc1769.cfg at91sam3ax_4x.cfg lpc1788.cfg at91sam3ax_8x.cfg lpc17xx.cfg at91sam3ax_xx.cfg lpc1850.cfg at91sam3nXX.cfg lpc2103.cfg at91sam3sXX.cfg lpc2124.cfg at91sam3u1c.cfg lpc2129.cfg at91sam3u1e.cfg lpc2148.cfg at91sam3u2c.cfg lpc2294.cfg at91sam3u2e.cfg lpc2378.cfg at91sam3u4c.cfg lpc2460.cfg at91sam3u4e.cfg lpc2478.cfg at91sam3uxx.cfg lpc2900.cfg at91sam3XXX.cfg lpc2xxx.cfg at91sam4sd32x.cfg lpc3131.cfg at91sam4sXX.cfg lpc3250.cfg at91sam4XXX.cfg lpc4350.cfg at91sam7se512.cfg lpc4350.cfg.orig at91sam7sx.cfg mc13224v.cfg at91sam7x256.cfg nuc910.cfg at91sam7x512.cfg omap2420.cfg at91sam9260.cfg omap3530.cfg at91sam9260_ext_RAM_ext_flash.cfg omap4430.cfg at91sam9261.cfg omap4460.cfg at91sam9263.cfg omap5912.cfg at91sam9.cfg omapl138.cfg at91sam9g10.cfg pic32mx.cfg at91sam9g20.cfg pxa255.cfg at91sam9g45.cfg pxa270.cfg at91sam9rl.cfg pxa3xx.cfg atmega128.cfg readme.txt avr32.cfg samsung_s3c2410.cfg c100.cfg samsung_s3c2440.cfg c100config.tcl samsung_s3c2450.cfg c100helper.tcl samsung_s3c4510.cfg c100regs.tcl samsung_s3c6410.cfg cs351x.cfg sharp_lh79532.cfg davinci.cfg smp8634.cfg dragonite.cfg spear3xx.cfg dsp56321.cfg stellaris.cfg dsp568013.cfg stellaris_icdi.cfg dsp568037.cfg stm32f0x_stlink.cfg efm32_stlink.cfg stm32f1x.cfg epc9301.cfg stm32f1x_stlink.cfg faux.cfg stm32f2x.cfg feroceon.cfg stm32f2x_stlink.cfg fm3.cfg stm32f3x.cfg hilscher_netx10.cfg stm32f3x_stlink.cfg hilscher_netx500.cfg stm32f4x.cfg hilscher_netx50.cfg stm32f4x_stlink.cfg icepick.cfg stm32l.cfg imx21.cfg stm32lx_dual_bank.cfg imx25.cfg stm32lx_stlink.cfg imx27.cfg stm32_stlink.cfg imx28.cfg stm32w108_stlink.cfg imx31.cfg stm32xl.cfg imx35.cfg str710.cfg imx51.cfg str730.cfg imx53.cfg str750.cfg imx6.cfg str912.cfg imx.cfg swj-dp.tcl is5114.cfg test_reset_syntax_error.cfg ixp42x.cfg test_syntax_error.cfg k40.cfg ti-ar7.cfg k60.cfg ti_calypso.cfg lpc1751.cfg ti_dm355.cfg lpc1752.cfg ti_dm365.cfg lpc1754.cfg ti_dm6446.cfg lpc1756.cfg tmpa900.cfg lpc1758.cfg tmpa910.cfg lpc1759.cfg u8500.cfg @end example @item @emph{more} ... browse for other library files which may be useful. For example, there are various generic and CPU-specific utilities. @end itemize The @file{openocd.cfg} user config file may override features in any of the above files by setting variables before sourcing the target file, or by adding commands specific to their situation. @section Interface Config Files The user config file should be able to source one of these files with a command like this: @example source [find interface/FOOBAR.cfg] @end example A preconfigured interface file should exist for every debug adapter in use today with OpenOCD. That said, perhaps some of these config files have only been used by the developer who created it. A separate chapter gives information about how to set these up. @xref{Debug Adapter Configuration}. Read the OpenOCD source code (and Developer's Guide) if you have a new kind of hardware interface and need to provide a driver for it. @section Board Config Files @cindex config file, board @cindex board config file The user config file should be able to source one of these files with a command like this: @example source [find board/FOOBAR.cfg] @end example The point of a board config file is to package everything about a given board that user config files need to know. In summary the board files should contain (if present) @enumerate @item One or more @command{source [target/...cfg]} statements @item NOR flash configuration (@pxref{norconfiguration,,NOR Configuration}) @item NAND flash configuration (@pxref{nandconfiguration,,NAND Configuration}) @item Target @code{reset} handlers for SDRAM and I/O configuration @item JTAG adapter reset configuration (@pxref{Reset Configuration}) @item All things that are not ``inside a chip'' @end enumerate Generic things inside target chips belong in target config files, not board config files. So for example a @code{reset-init} event handler should know board-specific oscillator and PLL parameters, which it passes to target-specific utility code. The most complex task of a board config file is creating such a @code{reset-init} event handler. Define those handlers last, after you verify the rest of the board configuration works. @subsection Communication Between Config files In addition to target-specific utility code, another way that board and target config files communicate is by following a convention on how to use certain variables. The full Tcl/Tk language supports ``namespaces'', but Jim-Tcl does not. Thus the rule we follow in OpenOCD is this: Variables that begin with a leading underscore are temporary in nature, and can be modified and used at will within a target configuration file. Complex board config files can do the things like this, for a board with three chips: @example # Chip #1: PXA270 for network side, big endian set CHIPNAME network set ENDIAN big source [find target/pxa270.cfg] # on return: _TARGETNAME = network.cpu # other commands can refer to the "network.cpu" target. $_TARGETNAME configure .... events for this CPU.. # Chip #2: PXA270 for video side, little endian set CHIPNAME video set ENDIAN little source [find target/pxa270.cfg] # on return: _TARGETNAME = video.cpu # other commands can refer to the "video.cpu" target. $_TARGETNAME configure .... events for this CPU.. # Chip #3: Xilinx FPGA for glue logic set CHIPNAME xilinx unset ENDIAN source [find target/spartan3.cfg] @end example That example is oversimplified because it doesn't show any flash memory, or the @code{reset-init} event handlers to initialize external DRAM or (assuming it needs it) load a configuration into the FPGA. Such features are usually needed for low-level work with many boards, where ``low level'' implies that the board initialization software may not be working. (That's a common reason to need JTAG tools. Another is to enable working with microcontroller-based systems, which often have no debugging support except a JTAG connector.) Target config files may also export utility functions to board and user config files. Such functions should use name prefixes, to help avoid naming collisions. Board files could also accept input variables from user config files. For example, there might be a @code{J4_JUMPER} setting used to identify what kind of flash memory a development board is using, or how to set up other clocks and peripherals. @subsection Variable Naming Convention @cindex variable names Most boards have only one instance of a chip. However, it should be easy to create a board with more than one such chip (as shown above). Accordingly, we encourage these conventions for naming variables associated with different @file{target.cfg} files, to promote consistency and so that board files can override target defaults. Inputs to target config files include: @itemize @bullet @item @code{CHIPNAME} ... This gives a name to the overall chip, and is used as part of tap identifier dotted names. While the default is normally provided by the chip manufacturer, board files may need to distinguish between instances of a chip. @item @code{ENDIAN} ... By default @option{little} - although chips may hard-wire @option{big}. Chips that can't change endianness don't need to use this variable. @item @code{CPUTAPID} ... When OpenOCD examines the JTAG chain, it can be told verify the chips against the JTAG IDCODE register. The target file will hold one or more defaults, but sometimes the chip in a board will use a different ID (perhaps a newer revision). @end itemize Outputs from target config files include: @itemize @bullet @item @code{_TARGETNAME} ... By convention, this variable is created by the target configuration script. The board configuration file may make use of this variable to configure things like a ``reset init'' script, or other things specific to that board and that target. If the chip has 2 targets, the names are @code{_TARGETNAME0}, @code{_TARGETNAME1}, ... etc. @end itemize @subsection The reset-init Event Handler @cindex event, reset-init @cindex reset-init handler Board config files run in the OpenOCD configuration stage; they can't use TAPs or targets, since they haven't been fully set up yet. This means you can't write memory or access chip registers; you can't even verify that a flash chip is present. That's done later in event handlers, of which the target @code{reset-init} handler is one of the most important. Except on microcontrollers, the basic job of @code{reset-init} event handlers is setting up flash and DRAM, as normally handled by boot loaders. Microcontrollers rarely use boot loaders; they run right out of their on-chip flash and SRAM memory. But they may want to use one of these handlers too, if just for developer convenience. @quotation Note Because this is so very board-specific, and chip-specific, no examples are included here. Instead, look at the board config files distributed with OpenOCD. If you have a boot loader, its source code will help; so will configuration files for other JTAG tools (@pxref{translatingconfigurationfiles,,Translating Configuration Files}). @end quotation Some of this code could probably be shared between different boards. For example, setting up a DRAM controller often doesn't differ by much except the bus width (16 bits or 32?) and memory timings, so a reusable TCL procedure loaded by the @file{target.cfg} file might take those as parameters. Similarly with oscillator, PLL, and clock setup; and disabling the watchdog. Structure the code cleanly, and provide comments to help the next developer doing such work. (@emph{You might be that next person} trying to reuse init code!) The last thing normally done in a @code{reset-init} handler is probing whatever flash memory was configured. For most chips that needs to be done while the associated target is halted, either because JTAG memory access uses the CPU or to prevent conflicting CPU access. @subsection JTAG Clock Rate Before your @code{reset-init} handler has set up the PLLs and clocking, you may need to run with a low JTAG clock rate. @xref{jtagspeed,,JTAG Speed}. Then you'd increase that rate after your handler has made it possible to use the faster JTAG clock. When the initial low speed is board-specific, for example because it depends on a board-specific oscillator speed, then you should probably set it up in the board config file; if it's target-specific, it belongs in the target config file. For most ARM-based processors the fastest JTAG clock@footnote{A FAQ @uref{http://www.arm.com/support/faqdev/4170.html} gives details.} is one sixth of the CPU clock; or one eighth for ARM11 cores. Consult chip documentation to determine the peak JTAG clock rate, which might be less than that. @quotation Warning On most ARMs, JTAG clock detection is coupled to the core clock, so software using a @option{wait for interrupt} operation blocks JTAG access. Adaptive clocking provides a partial workaround, but a more complete solution just avoids using that instruction with JTAG debuggers. @end quotation If both the chip and the board support adaptive clocking, use the @command{jtag_rclk} command, in case your board is used with JTAG adapter which also supports it. Otherwise use @command{adapter_khz}. Set the slow rate at the beginning of the reset sequence, and the faster rate as soon as the clocks are at full speed. @anchor{theinitboardprocedure} @subsection The init_board procedure @cindex init_board procedure The concept of @code{init_board} procedure is very similar to @code{init_targets} (@xref{theinittargetsprocedure,,The init_targets procedure}.) - it's a replacement of ``linear'' configuration scripts. This procedure is meant to be executed when OpenOCD enters run stage (@xref{enteringtherunstage,,Entering the Run Stage},) after @code{init_targets}. The idea to have spearate @code{init_targets} and @code{init_board} procedures is to allow the first one to configure everything target specific (internal flash, internal RAM, etc.) and the second one to configure everything board specific (reset signals, chip frequency, reset-init event handler, external memory, etc.). Additionally ``linear'' board config file will most likely fail when target config file uses @code{init_targets} scheme (``linear'' script is executed before @code{init} and @code{init_targets} - after), so separating these two configuration stages is very convenient, as the easiest way to overcome this problem is to convert board config file to use @code{init_board} procedure. Board config scripts don't need to override @code{init_targets} defined in target config files when they only need to to add some specifics. Just as @code{init_targets}, the @code{init_board} procedure can be overriden by ``next level'' script (which sources the original), allowing greater code reuse. @example ### board_file.cfg ### # source target file that does most of the config in init_targets source [find target/target.cfg] proc enable_fast_clock @{@} @{ # enables fast on-board clock source # configures the chip to use it @} # initialize only board specifics - reset, clock, adapter frequency proc init_board @{@} @{ reset_config trst_and_srst trst_pulls_srst $_TARGETNAME configure -event reset-init @{ adapter_khz 1 enable_fast_clock adapter_khz 10000 @} @} @end example @section Target Config Files @cindex config file, target @cindex target config file Board config files communicate with target config files using naming conventions as described above, and may source one or more target config files like this: @example source [find target/FOOBAR.cfg] @end example The point of a target config file is to package everything about a given chip that board config files need to know. In summary the target files should contain @enumerate @item Set defaults @item Add TAPs to the scan chain @item Add CPU targets (includes GDB support) @item CPU/Chip/CPU-Core specific features @item On-Chip flash @end enumerate As a rule of thumb, a target file sets up only one chip. For a microcontroller, that will often include a single TAP, which is a CPU needing a GDB target, and its on-chip flash. More complex chips may include multiple TAPs, and the target config file may need to define them all before OpenOCD can talk to the chip. For example, some phone chips have JTAG scan chains that include an ARM core for operating system use, a DSP, another ARM core embedded in an image processing engine, and other processing engines. @subsection Default Value Boiler Plate Code All target configuration files should start with code like this, letting board config files express environment-specific differences in how things should be set up. @example # Boards may override chip names, perhaps based on role, # but the default should match what the vendor uses if @{ [info exists CHIPNAME] @} @{ set _CHIPNAME $CHIPNAME @} else @{ set _CHIPNAME sam7x256 @} # ONLY use ENDIAN with targets that can change it. if @{ [info exists ENDIAN] @} @{ set _ENDIAN $ENDIAN @} else @{ set _ENDIAN little @} # TAP identifiers may change as chips mature, for example with # new revision fields (the "3" here). Pick a good default; you # can pass several such identifiers to the "jtag newtap" command. if @{ [info exists CPUTAPID ] @} @{ set _CPUTAPID $CPUTAPID @} else @{ set _CPUTAPID 0x3f0f0f0f @} @end example @c but 0x3f0f0f0f is for an str73x part ... @emph{Remember:} Board config files may include multiple target config files, or the same target file multiple times (changing at least @code{CHIPNAME}). Likewise, the target configuration file should define @code{_TARGETNAME} (or @code{_TARGETNAME0} etc) and use it later on when defining debug targets: @example set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -chain-position $_TARGETNAME @end example @subsection Adding TAPs to the Scan Chain After the ``defaults'' are set up, add the TAPs on each chip to the JTAG scan chain. @xref{TAP Declaration}, and the naming convention for taps. In the simplest case the chip has only one TAP, probably for a CPU or FPGA. The config file for the Atmel AT91SAM7X256 looks (in part) like this: @example jtag newtap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID @end example A board with two such at91sam7 chips would be able to source such a config file twice, with different values for @code{CHIPNAME}, so it adds a different TAP each time. If there are nonzero @option{-expected-id} values, OpenOCD attempts to verify the actual tap id against those values. It will issue error messages if there is mismatch, which can help to pinpoint problems in OpenOCD configurations. @example JTAG tap: sam7x256.cpu tap/device found: 0x3f0f0f0f (Manufacturer: 0x787, Part: 0xf0f0, Version: 0x3) ERROR: Tap: sam7x256.cpu - Expected id: 0x12345678, Got: 0x3f0f0f0f ERROR: expected: mfg: 0x33c, part: 0x2345, ver: 0x1 ERROR: got: mfg: 0x787, part: 0xf0f0, ver: 0x3 @end example There are more complex examples too, with chips that have multiple TAPs. Ones worth looking at include: @itemize @item @file{target/omap3530.cfg} -- with disabled ARM and DSP, plus a JRC to enable them @item @file{target/str912.cfg} -- with flash, CPU, and boundary scan @item @file{target/ti_dm355.cfg} -- with ETM, ARM, and JRC (this JRC is not currently used) @end itemize @subsection Add CPU targets After adding a TAP for a CPU, you should set it up so that GDB and other commands can use it. @xref{CPU Configuration}. For the at91sam7 example above, the command can look like this; note that @code{$_ENDIAN} is not needed, since OpenOCD defaults to little endian, and this chip doesn't support changing that. @example set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME arm7tdmi -chain-position $_TARGETNAME @end example Work areas are small RAM areas associated with CPU targets. They are used by OpenOCD to speed up downloads, and to download small snippets of code to program flash chips. If the chip includes a form of ``on-chip-ram'' - and many do - define a work area if you can. Again using the at91sam7 as an example, this can look like: @example $_TARGETNAME configure -work-area-phys 0x00200000 \ -work-area-size 0x4000 -work-area-backup 0 @end example @anchor{definecputargetsworkinginsmp} @subsection Define CPU targets working in SMP @cindex SMP After setting targets, you can define a list of targets working in SMP. @example set _TARGETNAME_1 $_CHIPNAME.cpu1 set _TARGETNAME_2 $_CHIPNAME.cpu2 target create $_TARGETNAME_1 cortex_a -chain-position $_CHIPNAME.dap \ -coreid 0 -dbgbase $_DAP_DBG1 target create $_TARGETNAME_2 cortex_a -chain-position $_CHIPNAME.dap \ -coreid 1 -dbgbase $_DAP_DBG2 #define 2 targets working in smp. target smp $_CHIPNAME.cpu2 $_CHIPNAME.cpu1 @end example In the above example on cortex_a, 2 cpus are working in SMP. In SMP only one GDB instance is created and : @itemize @bullet @item a set of hardware breakpoint sets the same breakpoint on all targets in the list. @item halt command triggers the halt of all targets in the list. @item resume command triggers the write context and the restart of all targets in the list. @item following a breakpoint: the target stopped by the breakpoint is displayed to the GDB session. @item dedicated GDB serial protocol packets are implemented for switching/retrieving the target displayed by the GDB session @pxref{usingopenocdsmpwithgdb,,Using OpenOCD SMP with GDB}. @end itemize The SMP behaviour can be disabled/enabled dynamically. On cortex_a following command have been implemented. @itemize @bullet @item cortex_a smp_on : enable SMP mode, behaviour is as described above. @item cortex_a smp_off : disable SMP mode, the current target is the one displayed in the GDB session, only this target is now controlled by GDB session. This behaviour is useful during system boot up. @item cortex_a smp_gdb : display/fix the core id displayed in GDB session see following example. @end itemize @example >cortex_a smp_gdb gdb coreid 0 -> -1 #0 : coreid 0 is displayed to GDB , #-> -1 : next resume triggers a real resume > cortex_a smp_gdb 1 gdb coreid 0 -> 1 #0 :coreid 0 is displayed to GDB , #->1 : next resume displays coreid 1 to GDB > resume > cortex_a smp_gdb gdb coreid 1 -> 1 #1 :coreid 1 is displayed to GDB , #->1 : next resume displays coreid 1 to GDB > cortex_a smp_gdb -1 gdb coreid 1 -> -1 #1 :coreid 1 is displayed to GDB, #->-1 : next resume triggers a real resume @end example @subsection Chip Reset Setup As a rule, you should put the @command{reset_config} command into the board file. Most things you think you know about a chip can be tweaked by the board. Some chips have specific ways the TRST and SRST signals are managed. In the unusual case that these are @emph{chip specific} and can never be changed by board wiring, they could go here. For example, some chips can't support JTAG debugging without both signals. Provide a @code{reset-assert} event handler if you can. Such a handler uses JTAG operations to reset the target, letting this target config be used in systems which don't provide the optional SRST signal, or on systems where you don't want to reset all targets at once. Such a handler might write to chip registers to force a reset, use a JRC to do that (preferable -- the target may be wedged!), or force a watchdog timer to trigger. (For Cortex-M targets, this is not necessary. The target driver knows how to use trigger an NVIC reset when SRST is not available.) Some chips need special attention during reset handling if they're going to be used with JTAG. An example might be needing to send some commands right after the target's TAP has been reset, providing a @code{reset-deassert-post} event handler that writes a chip register to report that JTAG debugging is being done. Another would be reconfiguring the watchdog so that it stops counting while the core is halted in the debugger. JTAG clocking constraints often change during reset, and in some cases target config files (rather than board config files) are the right places to handle some of those issues. For example, immediately after reset most chips run using a slower clock than they will use later. That means that after reset (and potentially, as OpenOCD first starts up) they must use a slower JTAG clock rate than they will use later. @xref{jtagspeed,,JTAG Speed}. @quotation Important When you are debugging code that runs right after chip reset, getting these issues right is critical. In particular, if you see intermittent failures when OpenOCD verifies the scan chain after reset, look at how you are setting up JTAG clocking. @end quotation @anchor{theinittargetsprocedure} @subsection The init_targets procedure @cindex init_targets procedure Target config files can either be ``linear'' (script executed line-by-line when parsed in configuration stage, @xref{configurationstage,,Configuration Stage},) or they can contain a special procedure called @code{init_targets}, which will be executed when entering run stage (after parsing all config files or after @code{init} command, @xref{enteringtherunstage,,Entering the Run Stage}.) Such procedure can be overriden by ``next level'' script (which sources the original). This concept faciliates code reuse when basic target config files provide generic configuration procedures and @code{init_targets} procedure, which can then be sourced and enchanced or changed in a ``more specific'' target config file. This is not possible with ``linear'' config scripts, because sourcing them executes every initialization commands they provide. @example ### generic_file.cfg ### proc setup_my_chip @{chip_name flash_size ram_size@} @{ # basic initialization procedure ... @} proc init_targets @{@} @{ # initializes generic chip with 4kB of flash and 1kB of RAM setup_my_chip MY_GENERIC_CHIP 4096 1024 @} ### specific_file.cfg ### source [find target/generic_file.cfg] proc init_targets @{@} @{ # initializes specific chip with 128kB of flash and 64kB of RAM setup_my_chip MY_CHIP_WITH_128K_FLASH_64KB_RAM 131072 65536 @} @end example The easiest way to convert ``linear'' config files to @code{init_targets} version is to enclose every line of ``code'' (i.e. not @code{source} commands, procedures, etc.) in this procedure. For an example of this scheme see LPC2000 target config files. The @code{init_boards} procedure is a similar concept concerning board config files (@xref{theinitboardprocedure,,The init_board procedure}.) @subsection ARM Core Specific Hacks If the chip has a DCC, enable it. If the chip is an ARM9 with some special high speed download features - enable it. If present, the MMU, the MPU and the CACHE should be disabled. Some ARM cores are equipped with trace support, which permits examination of the instruction and data bus activity. Trace activity is controlled through an ``Embedded Trace Module'' (ETM) on one of the core's scan chains. The ETM emits voluminous data through a ``trace port''. (@xref{armhardwaretracing,,ARM Hardware Tracing}.) If you are using an external trace port, configure it in your board config file. If you are using an on-chip ``Embedded Trace Buffer'' (ETB), configure it in your target config file. @example etm config $_TARGETNAME 16 normal full etb etb config $_TARGETNAME $_CHIPNAME.etb @end example @subsection Internal Flash Configuration This applies @b{ONLY TO MICROCONTROLLERS} that have flash built in. @b{Never ever} in the ``target configuration file'' define any type of flash that is external to the chip. (For example a BOOT flash on Chip Select 0.) Such flash information goes in a board file - not the TARGET (chip) file. Examples: @itemize @bullet @item at91sam7x256 - has 256K flash YES enable it. @item str912 - has flash internal YES enable it. @item imx27 - uses boot flash on CS0 - it goes in the board file. @item pxa270 - again - CS0 flash - it goes in the board file. @end itemize @anchor{translatingconfigurationfiles} @section Translating Configuration Files @cindex translation If you have a configuration file for another hardware debugger or toolset (Abatron, BDI2000, BDI3000, CCS, Lauterbach, Segger, Macraigor, etc.), translating it into OpenOCD syntax is often quite straightforward. The most tricky part of creating a configuration script is oftentimes the reset init sequence where e.g. PLLs, DRAM and the like is set up. One trick that you can use when translating is to write small Tcl procedures to translate the syntax into OpenOCD syntax. This can avoid manual translation errors and make it easier to convert other scripts later on. Example of transforming quirky arguments to a simple search and replace job: @example # Lauterbach syntax(?) # # Data.Set c15:0x042f %long 0x40000015 # # OpenOCD syntax when using procedure below. # # setc15 0x01 0x00050078 proc setc15 @{regs value@} @{ global TARGETNAME echo [format "set p15 0x%04x, 0x%08x" $regs $value] arm mcr 15 [expr ($regs>>12)&0x7] \ [expr ($regs>>0)&0xf] [expr ($regs>>4)&0xf] \ [expr ($regs>>8)&0x7] $value @} @end example @node Daemon Configuration @chapter Daemon Configuration @cindex initialization The commands here are commonly found in the openocd.cfg file and are used to specify what TCP/IP ports are used, and how GDB should be supported. @anchor{configurationstage} @section Configuration Stage @cindex configuration stage @cindex config command When the OpenOCD server process starts up, it enters a @emph{configuration stage} which is the only time that certain commands, @emph{configuration commands}, may be issued. Normally, configuration commands are only available inside startup scripts. In this manual, the definition of a configuration command is presented as a @emph{Config Command}, not as a @emph{Command} which may be issued interactively. The runtime @command{help} command also highlights configuration commands, and those which may be issued at any time. Those configuration commands include declaration of TAPs, flash banks, the interface used for JTAG communication, and other basic setup. The server must leave the configuration stage before it may access or activate TAPs. After it leaves this stage, configuration commands may no longer be issued. @anchor{enteringtherunstage} @section Entering the Run Stage The first thing OpenOCD does after leaving the configuration stage is to verify that it can talk to the scan chain (list of TAPs) which has been configured. It will warn if it doesn't find TAPs it expects to find, or finds TAPs that aren't supposed to be there. You should see no errors at this point. If you see errors, resolve them by correcting the commands you used to configure the server. Common errors include using an initial JTAG speed that's too fast, and not providing the right IDCODE values for the TAPs on the scan chain. Once OpenOCD has entered the run stage, a number of commands become available. A number of these relate to the debug targets you may have declared. For example, the @command{mww} command will not be available until a target has been successfuly instantiated. If you want to use those commands, you may need to force entry to the run stage. @deffn {Config Command} init This command terminates the configuration stage and enters the run stage. This helps when you need to have the startup scripts manage tasks such as resetting the target, programming flash, etc. To reset the CPU upon startup, add "init" and "reset" at the end of the config script or at the end of the OpenOCD command line using the @option{-c} command line switch. If this command does not appear in any startup/configuration file OpenOCD executes the command for you after processing all configuration files and/or command line options. @b{NOTE:} This command normally occurs at or near the end of your openocd.cfg file to force OpenOCD to ``initialize'' and make the targets ready. For example: If your openocd.cfg file needs to read/write memory on your target, @command{init} must occur before the memory read/write commands. This includes @command{nand probe}. @end deffn @deffn {Overridable Procedure} jtag_init This is invoked at server startup to verify that it can talk to the scan chain (list of TAPs) which has been configured. The default implementation first tries @command{jtag arp_init}, which uses only a lightweight JTAG reset before examining the scan chain. If that fails, it tries again, using a harder reset from the overridable procedure @command{init_reset}. Implementations must have verified the JTAG scan chain before they return. This is done by calling @command{jtag arp_init} (or @command{jtag arp_init-reset}). @end deffn @anchor{tcpipports} @section TCP/IP Ports @cindex TCP port @cindex server @cindex port @cindex security The OpenOCD server accepts remote commands in several syntaxes. Each syntax uses a different TCP/IP port, which you may specify only during configuration (before those ports are opened). For reasons including security, you may wish to prevent remote access using one or more of these ports. In such cases, just specify the relevant port number as zero. If you disable all access through TCP/IP, you will need to use the command line @option{-pipe} option. @deffn {Command} gdb_port [number] @cindex GDB server Normally gdb listens to a TCP/IP port, but GDB can also communicate via pipes(stdin/out or named pipes). The name "gdb_port" stuck because it covers probably more than 90% of the normal use cases. No arguments reports GDB port. "pipe" means listen to stdin output to stdout, an integer is base port number, "disable" disables the gdb server. When using "pipe", also use log_output to redirect the log output to a file so as not to flood the stdin/out pipes. The -p/--pipe option is deprecated and a warning is printed as it is equivalent to passing in -c "gdb_port pipe; log_output openocd.log". Any other string is interpreted as named pipe to listen to. Output pipe is the same name as input pipe, but with 'o' appended, e.g. /var/gdb, /var/gdbo. The GDB port for the first target will be the base port, the second target will listen on gdb_port + 1, and so on. When not specified during the configuration stage, the port @var{number} defaults to 3333. @end deffn @deffn {Command} tcl_port [number] Specify or query the port used for a simplified RPC connection that can be used by clients to issue TCL commands and get the output from the Tcl engine. Intended as a machine interface. When not specified during the configuration stage, the port @var{number} defaults to 6666. @end deffn @deffn {Command} telnet_port [number] Specify or query the port on which to listen for incoming telnet connections. This port is intended for interaction with one human through TCL commands. When not specified during the configuration stage, the port @var{number} defaults to 4444. When specified as zero, this port is not activated. @end deffn @anchor{gdbconfiguration} @section GDB Configuration @cindex GDB @cindex GDB configuration You can reconfigure some GDB behaviors if needed. The ones listed here are static and global. @xref{targetconfiguration,,Target Configuration}, about configuring individual targets. @xref{targetevents,,Target Events}, about configuring target-specific event handling. @anchor{gdbbreakpointoverride} @deffn {Command} gdb_breakpoint_override [@option{hard}|@option{soft}|@option{disable}] Force breakpoint type for gdb @command{break} commands. This option supports GDB GUIs which don't distinguish hard versus soft breakpoints, if the default OpenOCD and GDB behaviour is not sufficient. GDB normally uses hardware breakpoints if the memory map has been set up for flash regions. @end deffn @anchor{gdbflashprogram} @deffn {Config Command} gdb_flash_program (@option{enable}|@option{disable}) Set to @option{enable} to cause OpenOCD to program the flash memory when a vFlash packet is received. The default behaviour is @option{enable}. @end deffn @deffn {Config Command} gdb_memory_map (@option{enable}|@option{disable}) Set to @option{enable} to cause OpenOCD to send the memory configuration to GDB when requested. GDB will then know when to set hardware breakpoints, and program flash using the GDB load command. @command{gdb_flash_program enable} must also be enabled for flash programming to work. Default behaviour is @option{enable}. @xref{gdbflashprogram,,gdb_flash_program}. @end deffn @deffn {Config Command} gdb_report_data_abort (@option{enable}|@option{disable}) Specifies whether data aborts cause an error to be reported by GDB memory read packets. The default behaviour is @option{disable}; use @option{enable} see these errors reported. @end deffn @anchor{eventpolling} @section Event Polling Hardware debuggers are parts of asynchronous systems, where significant events can happen at any time. The OpenOCD server needs to detect some of these events, so it can report them to through TCL command line or to GDB. Examples of such events include: @itemize @item One of the targets can stop running ... maybe it triggers a code breakpoint or data watchpoint, or halts itself. @item Messages may be sent over ``debug message'' channels ... many targets support such messages sent over JTAG, for receipt by the person debugging or tools. @item Loss of power ... some adapters can detect these events. @item Resets not issued through JTAG ... such reset sources can include button presses or other system hardware, sometimes including the target itself (perhaps through a watchdog). @item Debug instrumentation sometimes supports event triggering such as ``trace buffer full'' (so it can quickly be emptied) or other signals (to correlate with code behavior). @end itemize None of those events are signaled through standard JTAG signals. However, most conventions for JTAG connectors include voltage level and system reset (SRST) signal detection. Some connectors also include instrumentation signals, which can imply events when those signals are inputs. In general, OpenOCD needs to periodically check for those events, either by looking at the status of signals on the JTAG connector or by sending synchronous ``tell me your status'' JTAG requests to the various active targets. There is a command to manage and monitor that polling, which is normally done in the background. @deffn Command poll [@option{on}|@option{off}] Poll the current target for its current state. (Also, @pxref{targetcurstate,,target curstate}.) If that target is in debug mode, architecture specific information about the current state is printed. An optional parameter allows background polling to be enabled and disabled. You could use this from the TCL command shell, or from GDB using @command{monitor poll} command. Leave background polling enabled while you're using GDB. @example > poll background polling: on target state: halted target halted in ARM state due to debug-request, \ current mode: Supervisor cpsr: 0x800000d3 pc: 0x11081bfc MMU: disabled, D-Cache: disabled, I-Cache: enabled > @end example @end deffn @node Debug Adapter Configuration @chapter Debug Adapter Configuration @cindex config file, interface @cindex interface config file Correctly installing OpenOCD includes making your operating system give OpenOCD access to debug adapters. Once that has been done, Tcl commands are used to select which one is used, and to configure how it is used. @quotation Note Because OpenOCD started out with a focus purely on JTAG, you may find places where it wrongly presumes JTAG is the only transport protocol in use. Be aware that recent versions of OpenOCD are removing that limitation. JTAG remains more functional than most other transports. Other transports do not support boundary scan operations, or may be specific to a given chip vendor. Some might be usable only for programming flash memory, instead of also for debugging. @end quotation Debug Adapters/Interfaces/Dongles are normally configured through commands in an interface configuration file which is sourced by your @file{openocd.cfg} file, or through a command line @option{-f interface/....cfg} option. @example source [find interface/olimex-jtag-tiny.cfg] @end example These commands tell OpenOCD what type of JTAG adapter you have, and how to talk to it. A few cases are so simple that you only need to say what driver to use: @example # jlink interface interface jlink @end example Most adapters need a bit more configuration than that. @section Interface Configuration The interface command tells OpenOCD what type of debug adapter you are using. Depending on the type of adapter, you may need to use one or more additional commands to further identify or configure the adapter. @deffn {Config Command} {interface} name Use the interface driver @var{name} to connect to the target. @end deffn @deffn Command {interface_list} List the debug adapter drivers that have been built into the running copy of OpenOCD. @end deffn @deffn Command {interface transports} transport_name+ Specifies the transports supported by this debug adapter. The adapter driver builds-in similar knowledge; use this only when external configuration (such as jumpering) changes what the hardware can support. @end deffn @deffn Command {adapter_name} Returns the name of the debug adapter driver being used. @end deffn @section Interface Drivers Each of the interface drivers listed here must be explicitly enabled when OpenOCD is configured, in order to be made available at run time. @deffn {Interface Driver} {amt_jtagaccel} Amontec Chameleon in its JTAG Accelerator configuration, connected to a PC's EPP mode parallel port. This defines some driver-specific commands: @deffn {Config Command} {parport_port} number Specifies either the address of the I/O port (default: 0x378 for LPT1) or the number of the @file{/dev/parport} device. @end deffn @deffn {Config Command} rtck [@option{enable}|@option{disable}] Displays status of RTCK option. Optionally sets that option first. @end deffn @end deffn @deffn {Interface Driver} {arm-jtag-ew} Olimex ARM-JTAG-EW USB adapter This has one driver-specific command: @deffn Command {armjtagew_info} Logs some status @end deffn @end deffn @deffn {Interface Driver} {at91rm9200} Supports bitbanged JTAG from the local system, presuming that system is an Atmel AT91rm9200 and a specific set of GPIOs is used. @c command: at91rm9200_device NAME @c chooses among list of bit configs ... only one option @end deffn @deffn {Interface Driver} {dummy} A dummy software-only driver for debugging. @end deffn @deffn {Interface Driver} {ep93xx} Cirrus Logic EP93xx based single-board computer bit-banging (in development) @end deffn @deffn {Interface Driver} {ft2232} FTDI FT2232 (USB) based devices over one of the userspace libraries. Note that this driver has several flaws and the @command{ftdi} driver is recommended as its replacement. These interfaces have several commands, used to configure the driver before initializing the JTAG scan chain: @deffn {Config Command} {ft2232_device_desc} description Provides the USB device description (the @emph{iProduct string}) of the FTDI FT2232 device. If not specified, the FTDI default value is used. This setting is only valid if compiled with FTD2XX support. @end deffn @deffn {Config Command} {ft2232_serial} serial-number Specifies the @var{serial-number} of the FTDI FT2232 device to use, in case the vendor provides unique IDs and more than one FT2232 device is connected to the host. If not specified, serial numbers are not considered. (Note that USB serial numbers can be arbitrary Unicode strings, and are not restricted to containing only decimal digits.) @end deffn @deffn {Config Command} {ft2232_layout} name Each vendor's FT2232 device can use different GPIO signals to control output-enables, reset signals, and LEDs. Currently valid layout @var{name} values include: @itemize @minus @item @b{axm0432_jtag} Axiom AXM-0432 @item @b{comstick} Hitex STR9 comstick @item @b{cortino} Hitex Cortino JTAG interface @item @b{evb_lm3s811} TI/Luminary Micro EVB_LM3S811 as a JTAG interface, either for the local Cortex-M3 (SRST only) or in a passthrough mode (neither SRST nor TRST) This layout can not support the SWO trace mechanism, and should be used only for older boards (before rev C). @item @b{luminary_icdi} This layout should be used with most TI/Luminary eval boards, including Rev C LM3S811 eval boards and the eponymous ICDI boards, to debug either the local Cortex-M3 or in passthrough mode to debug some other target. It can support the SWO trace mechanism. @item @b{flyswatter} Tin Can Tools Flyswatter @item @b{icebear} ICEbear JTAG adapter from Section 5 @item @b{jtagkey} Amontec JTAGkey and JTAGkey-Tiny (and compatibles) @item @b{jtagkey2} Amontec JTAGkey2 (and compatibles) @item @b{m5960} American Microsystems M5960 @item @b{olimex-jtag} Olimex ARM-USB-OCD and ARM-USB-Tiny @item @b{oocdlink} OOCDLink @c oocdlink ~= jtagkey_prototype_v1 @item @b{redbee-econotag} Integrated with a Redbee development board. @item @b{redbee-usb} Integrated with a Redbee USB-stick development board. @item @b{sheevaplug} Marvell Sheevaplug development kit @item @b{signalyzer} Xverve Signalyzer @item @b{stm32stick} Hitex STM32 Performance Stick @item @b{turtelizer2} egnite Software turtelizer2 @item @b{usbjtag} "USBJTAG-1" layout described in the OpenOCD diploma thesis @end itemize @end deffn @deffn {Config Command} {ft2232_vid_pid} [vid pid]+ The vendor ID and product ID of the FTDI FT2232 device. If not specified, the FTDI default values are used. Currently, up to eight [@var{vid}, @var{pid}] pairs may be given, e.g. @example ft2232_vid_pid 0x0403 0xcff8 0x15ba 0x0003 @end example @end deffn @deffn {Config Command} {ft2232_latency} ms On some systems using FT2232 based JTAG interfaces the FT_Read function call in ft2232_read() fails to return the expected number of bytes. This can be caused by USB communication delays and has proved hard to reproduce and debug. Setting the FT2232 latency timer to a larger value increases delays for short USB packets but it also reduces the risk of timeouts before receiving the expected number of bytes. The OpenOCD default value is 2 and for some systems a value of 10 has proved useful. @end deffn @deffn {Config Command} {ft2232_channel} channel Used to select the channel of the ft2232 chip to use (between 1 and 4). The default value is 1. @end deffn For example, the interface config file for a Turtelizer JTAG Adapter looks something like this: @example interface ft2232 ft2232_device_desc "Turtelizer JTAG/RS232 Adapter" ft2232_layout turtelizer2 ft2232_vid_pid 0x0403 0xbdc8 @end example @end deffn @deffn {Interface Driver} {ftdi} This driver is for adapters using the MPSSE (Multi-Protocol Synchronous Serial Engine) mode built into many FTDI chips, such as the FT2232, FT4232 and FT232H. It is a complete rewrite to address a large number of problems with the ft2232 interface driver. The driver is using libusb-1.0 in asynchronous mode to talk to the FTDI device, bypassing intermediate libraries like libftdi of D2XX. Performance-wise it is consistently faster than the ft2232 driver, sometimes several times faster. A major improvement of this driver is that support for new FTDI based adapters can be added competely through configuration files, without the need to patch and rebuild OpenOCD. The driver uses a signal abstraction to enable Tcl configuration files to define outputs for one or several FTDI GPIO. These outputs can then be controlled using the @command{ftdi_set_signal} command. Special signal names are reserved for nTRST, nSRST and LED (for blink) so that they, if defined, will be used for their customary purpose. Depending on the type of buffer attached to the FTDI GPIO, the outputs have to be controlled differently. In order to support tristateable signals such as nSRST, both a data GPIO and an output-enable GPIO can be specified for each signal. The following output buffer configurations are supported: @itemize @minus @item Push-pull with one FTDI output as (non-)inverted data line @item Open drain with one FTDI output as (non-)inverted output-enable @item Tristate with one FTDI output as (non-)inverted data line and another FTDI output as (non-)inverted output-enable @item Unbuffered, using the FTDI GPIO as a tristate output directly by switching data and direction as necessary @end itemize These interfaces have several commands, used to configure the driver before initializing the JTAG scan chain: @deffn {Config Command} {ftdi_vid_pid} [vid pid]+ The vendor ID and product ID of the adapter. If not specified, the FTDI default values are used. Currently, up to eight [@var{vid}, @var{pid}] pairs may be given, e.g. @example ftdi_vid_pid 0x0403 0xcff8 0x15ba 0x0003 @end example @end deffn @deffn {Config Command} {ftdi_device_desc} description Provides the USB device description (the @emph{iProduct string}) of the adapter. If not specified, the device description is ignored during device selection. @end deffn @deffn {Config Command} {ftdi_serial} serial-number Specifies the @var{serial-number} of the adapter to use, in case the vendor provides unique IDs and more than one adapter is connected to the host. If not specified, serial numbers are not considered. (Note that USB serial numbers can be arbitrary Unicode strings, and are not restricted to containing only decimal digits.) @end deffn @deffn {Config Command} {ftdi_channel} channel Selects the channel of the FTDI device to use for MPSSE operations. Most adapters use the default, channel 0, but there are exceptions. @end deffn @deffn {Config Command} {ftdi_layout_init} data direction Specifies the initial values of the FTDI GPIO data and direction registers. Each value is a 16-bit number corresponding to the concatenation of the high and low FTDI GPIO registers. The values should be selected based on the schematics of the adapter, such that all signals are set to safe levels with minimal impact on the target system. Avoid floating inputs, conflicting outputs and initially asserted reset signals. @end deffn @deffn {Config Command} {ftdi_layout_signal} name [@option{-data}|@option{-ndata} data_mask] [@option{-oe}|@option{-noe} oe_mask] Creates a signal with the specified @var{name}, controlled by one or more FTDI GPIO pins via a range of possible buffer connections. The masks are FTDI GPIO register bitmasks to tell the driver the connection and type of the output buffer driving the respective signal. @var{data_mask} is the bitmask for the pin(s) connected to the data input of the output buffer. @option{-ndata} is used with inverting data inputs and @option{-data} with non-inverting inputs. The @option{-oe} (or @option{-noe}) option tells where the output-enable (or not-output-enable) input to the output buffer is connected. Both @var{data_mask} and @var{oe_mask} need not be specified. For example, a simple open-collector transistor driver would be specified with @option{-oe} only. In that case the signal can only be set to drive low or to Hi-Z and the driver will complain if the signal is set to drive high. Which means that if it's a reset signal, @command{reset_config} must be specified as @option{srst_open_drain}, not @option{srst_push_pull}. A special case is provided when @option{-data} and @option{-oe} is set to the same bitmask. Then the FTDI pin is considered being connected straight to the target without any buffer. The FTDI pin is then switched between output and input as necessary to provide the full set of low, high and Hi-Z characteristics. In all other cases, the pins specified in a signal definition are always driven by the FTDI. @end deffn @deffn {Command} {ftdi_set_signal} name @option{0}|@option{1}|@option{z} Set a previously defined signal to the specified level. @itemize @minus @item @option{0}, drive low @item @option{1}, drive high @item @option{z}, set to high-impedance @end itemize @end deffn For example adapter definitions, see the configuration files shipped in the @file{interface/ftdi} directory. @end deffn @deffn {Interface Driver} {remote_bitbang} Drive JTAG from a remote process. This sets up a UNIX or TCP socket connection with a remote process and sends ASCII encoded bitbang requests to that process instead of directly driving JTAG. The remote_bitbang driver is useful for debugging software running on processors which are being simulated. @deffn {Config Command} {remote_bitbang_port} number Specifies the TCP port of the remote process to connect to or 0 to use UNIX sockets instead of TCP. @end deffn @deffn {Config Command} {remote_bitbang_host} hostname Specifies the hostname of the remote process to connect to using TCP, or the name of the UNIX socket to use if remote_bitbang_port is 0. @end deffn For example, to connect remotely via TCP to the host foobar you might have something like: @example interface remote_bitbang remote_bitbang_port 3335 remote_bitbang_host foobar @end example To connect to another process running locally via UNIX sockets with socket named mysocket: @example interface remote_bitbang remote_bitbang_port 0 remote_bitbang_host mysocket @end example @end deffn @deffn {Interface Driver} {usb_blaster} USB JTAG/USB-Blaster compatibles over one of the userspace libraries for FTDI chips. These interfaces have several commands, used to configure the driver before initializing the JTAG scan chain: @deffn {Config Command} {usb_blaster_device_desc} description Provides the USB device description (the @emph{iProduct string}) of the FTDI FT245 device. If not specified, the FTDI default value is used. This setting is only valid if compiled with FTD2XX support. @end deffn @deffn {Config Command} {usb_blaster_vid_pid} vid pid The vendor ID and product ID of the FTDI FT245 device. If not specified, default values are used. Currently, only one @var{vid}, @var{pid} pair may be given, e.g. for Altera USB-Blaster (default): @example usb_blaster_vid_pid 0x09FB 0x6001 @end example The following VID/PID is for Kolja Waschk's USB JTAG: @example usb_blaster_vid_pid 0x16C0 0x06AD @end example @end deffn @deffn {Command} {usb_blaster} (@option{pin6}|@option{pin8}) (@option{0}|@option{1}) Sets the state of the unused GPIO pins on USB-Blasters (pins 6 and 8 on the female JTAG header). These pins can be used as SRST and/or TRST provided the appropriate connections are made on the target board. For example, to use pin 6 as SRST (as with an AVR board): @example $_TARGETNAME configure -event reset-assert \ "usb_blaster pin6 1; wait 1; usb_blaster pin6 0" @end example @end deffn @end deffn @deffn {Interface Driver} {gw16012} Gateworks GW16012 JTAG programmer. This has one driver-specific command: @deffn {Config Command} {parport_port} [port_number] Display either the address of the I/O port (default: 0x378 for LPT1) or the number of the @file{/dev/parport} device. If a parameter is provided, first switch to use that port. This is a write-once setting. @end deffn @end deffn @deffn {Interface Driver} {jlink} Segger J-Link family of USB adapters. It currently supports only the JTAG transport. @quotation Compatibility Note Segger released many firmware versions for the many harware versions they produced. OpenOCD was extensively tested and intended to run on all of them, but some combinations were reported as incompatible. As a general recommendation, it is advisable to use the latest firmware version available for each hardware version. However the current V8 is a moving target, and Segger firmware versions released after the OpenOCD was released may not be compatible. In such cases it is recommended to revert to the last known functional version. For 0.5.0, this is from "Feb 8 2012 14:30:39", packed with 4.42c. For 0.6.0, the last known version is from "May 3 2012 18:36:22", packed with 4.46f. @end quotation @deffn {Command} {jlink caps} Display the device firmware capabilities. @end deffn @deffn {Command} {jlink info} Display various device information, like hardware version, firmware version, current bus status. @end deffn @deffn {Command} {jlink hw_jtag} [@option{2}|@option{3}] Set the JTAG protocol version to be used. Without argument, show the actual JTAG protocol version. @end deffn @deffn {Command} {jlink config} Display the J-Link configuration. @end deffn @deffn {Command} {jlink config kickstart} [val] Set the Kickstart power on JTAG-pin 19. Without argument, show the Kickstart configuration. @end deffn @deffn {Command} {jlink config mac_address} [@option{ff:ff:ff:ff:ff:ff}] Set the MAC address of the J-Link Pro. Without argument, show the MAC address. @end deffn @deffn {Command} {jlink config ip} [@option{A.B.C.D}(@option{/E}|@option{F.G.H.I})] Set the IP configuration of the J-Link Pro, where A.B.C.D is the IP address, E the bit of the subnet mask and F.G.H.I the subnet mask. Without arguments, show the IP configuration. @end deffn @deffn {Command} {jlink config usb_address} [@option{0x00} to @option{0x03} or @option{0xff}] Set the USB address; this will also change the product id. Without argument, show the USB address. @end deffn @deffn {Command} {jlink config reset} Reset the current configuration. @end deffn @deffn {Command} {jlink config save} Save the current configuration to the internal persistent storage. @end deffn @deffn {Config} {jlink pid} val Set the USB PID of the interface. As a configuration command, it can be used only before 'init'. @end deffn @end deffn @deffn {Interface Driver} {parport} Supports PC parallel port bit-banging cables: Wigglers, PLD download cable, and more. These interfaces have several commands, used to configure the driver before initializing the JTAG scan chain: @deffn {Config Command} {parport_cable} name Set the layout of the parallel port cable used to connect to the target. This is a write-once setting. Currently valid cable @var{name} values include: @itemize @minus @item @b{altium} Altium Universal JTAG cable. @item @b{arm-jtag} Same as original wiggler except SRST and TRST connections reversed and TRST is also inverted. @item @b{chameleon} The Amontec Chameleon's CPLD when operated in configuration mode. This is only used to program the Chameleon itself, not a connected target. @item @b{dlc5} The Xilinx Parallel cable III. @item @b{flashlink} The ST Parallel cable. @item @b{lattice} Lattice ispDOWNLOAD Cable @item @b{old_amt_wiggler} The Wiggler configuration that comes with some versions of Amontec's Chameleon Programmer. The new version available from the website uses the original Wiggler layout ('@var{wiggler}') @item @b{triton} The parallel port adapter found on the ``Karo Triton 1 Development Board''. This is also the layout used by the HollyGates design (see @uref{http://www.lartmaker.nl/projects/jtag/}). @item @b{wiggler} The original Wiggler layout, also supported by several clones, such as the Olimex ARM-JTAG @item @b{wiggler2} Same as original wiggler except an led is fitted on D5. @item @b{wiggler_ntrst_inverted} Same as original wiggler except TRST is inverted. @end itemize @end deffn @deffn {Config Command} {parport_port} [port_number] Display either the address of the I/O port (default: 0x378 for LPT1) or the number of the @file{/dev/parport} device. If a parameter is provided, first switch to use that port. This is a write-once setting. When using PPDEV to access the parallel port, use the number of the parallel port: @option{parport_port 0} (the default). If @option{parport_port 0x378} is specified you may encounter a problem. @end deffn @deffn Command {parport_toggling_time} [nanoseconds] Displays how many nanoseconds the hardware needs to toggle TCK; the parport driver uses this value to obey the @command{adapter_khz} configuration. When the optional @var{nanoseconds} parameter is given, that setting is changed before displaying the current value. The default setting should work reasonably well on commodity PC hardware. However, you may want to calibrate for your specific hardware. @quotation Tip To measure the toggling time with a logic analyzer or a digital storage oscilloscope, follow the procedure below: @example > parport_toggling_time 1000 > adapter_khz 500 @end example This sets the maximum JTAG clock speed of the hardware, but the actual speed probably deviates from the requested 500 kHz. Now, measure the time between the two closest spaced TCK transitions. You can use @command{runtest 1000} or something similar to generate a large set of samples. Update the setting to match your measurement: @example > parport_toggling_time @end example Now the clock speed will be a better match for @command{adapter_khz rate} commands given in OpenOCD scripts and event handlers. You can do something similar with many digital multimeters, but note that you'll probably need to run the clock continuously for several seconds before it decides what clock rate to show. Adjust the toggling time up or down until the measured clock rate is a good match for the adapter_khz rate you specified; be conservative. @end quotation @end deffn @deffn {Config Command} {parport_write_on_exit} (@option{on}|@option{off}) This will configure the parallel driver to write a known cable-specific value to the parallel interface on exiting OpenOCD. @end deffn For example, the interface configuration file for a classic ``Wiggler'' cable on LPT2 might look something like this: @example interface parport parport_port 0x278 parport_cable wiggler @end example @end deffn @deffn {Interface Driver} {presto} ASIX PRESTO USB JTAG programmer. @deffn {Config Command} {presto_serial} serial_string Configures the USB serial number of the Presto device to use. @end deffn @end deffn @deffn {Interface Driver} {rlink} Raisonance RLink USB adapter @end deffn @deffn {Interface Driver} {usbprog} usbprog is a freely programmable USB adapter. @end deffn @deffn {Interface Driver} {vsllink} vsllink is part of Versaloon which is a versatile USB programmer. @quotation Note This defines quite a few driver-specific commands, which are not currently documented here. @end quotation @end deffn @deffn {Interface Driver} {hla} This is a driver that supports multiple High Level Adapters. This type of adapter does not expose some of the lower level api's that OpenOCD would normally use to access the target. Currently supported adapters include the ST STLINK and TI ICDI. @deffn {Config Command} {hla_device_desc} description Currently Not Supported. @end deffn @deffn {Config Command} {hla_serial} serial Currently Not Supported. @end deffn @deffn {Config Command} {hla_layout} (@option{stlink}|@option{icdi}) Specifies the adapter layout to use. @end deffn @deffn {Config Command} {hla_vid_pid} vid pid The vendor ID and product ID of the device. @end deffn @deffn {Config Command} {stlink_api} api_level Manually sets the stlink api used, valid options are 1 or 2. (@b{STLINK Only}). @end deffn @end deffn @deffn {Interface Driver} {opendous} opendous-jtag is a freely programmable USB adapter. @end deffn @deffn {Interface Driver} {ulink} This is the Keil ULINK v1 JTAG debugger. @end deffn @deffn {Interface Driver} {ZY1000} This is the Zylin ZY1000 JTAG debugger. @end deffn @quotation Note This defines some driver-specific commands, which are not currently documented here. @end quotation @deffn Command power [@option{on}|@option{off}] Turn power switch to target on/off. No arguments: print status. @end deffn @section Transport Configuration @cindex Transport As noted earlier, depending on the version of OpenOCD you use, and the debug adapter you are using, several transports may be available to communicate with debug targets (or perhaps to program flash memory). @deffn Command {transport list} displays the names of the transports supported by this version of OpenOCD. @end deffn @deffn Command {transport select} transport_name Select which of the supported transports to use in this OpenOCD session. The transport must be supported by the debug adapter hardware and by the version of OPenOCD you are using (including the adapter's driver). No arguments: returns name of session's selected transport. @end deffn @subsection JTAG Transport @cindex JTAG JTAG is the original transport supported by OpenOCD, and most of the OpenOCD commands support it. JTAG transports expose a chain of one or more Test Access Points (TAPs), each of which must be explicitly declared. JTAG supports both debugging and boundary scan testing. Flash programming support is built on top of debug support. @subsection SWD Transport @cindex SWD @cindex Serial Wire Debug SWD (Serial Wire Debug) is an ARM-specific transport which exposes one Debug Access Point (DAP, which must be explicitly declared. (SWD uses fewer signal wires than JTAG.) SWD is debug-oriented, and does not support boundary scan testing. Flash programming support is built on top of debug support. (Some processors support both JTAG and SWD.) @deffn Command {swd newdap} ... Declares a single DAP which uses SWD transport. Parameters are currently the same as "jtag newtap" but this is expected to change. @end deffn @deffn Command {swd wcr trn prescale} Updates TRN (turnaraound delay) and prescaling.fields of the Wire Control Register (WCR). No parameters: displays current settings. @end deffn @subsection SPI Transport @cindex SPI @cindex Serial Peripheral Interface The Serial Peripheral Interface (SPI) is a general purpose transport which uses four wire signaling. Some processors use it as part of a solution for flash programming. @anchor{jtagspeed} @section JTAG Speed JTAG clock setup is part of system setup. It @emph{does not belong with interface setup} since any interface only knows a few of the constraints for the JTAG clock speed. Sometimes the JTAG speed is changed during the target initialization process: (1) slow at reset, (2) program the CPU clocks, (3) run fast. Both the "slow" and "fast" clock rates are functions of the oscillators used, the chip, the board design, and sometimes power management software that may be active. The speed used during reset, and the scan chain verification which follows reset, can be adjusted using a @code{reset-start} target event handler. It can then be reconfigured to a faster speed by a @code{reset-init} target event handler after it reprograms those CPU clocks, or manually (if something else, such as a boot loader, sets up those clocks). @xref{targetevents,,Target Events}. When the initial low JTAG speed is a chip characteristic, perhaps because of a required oscillator speed, provide such a handler in the target config file. When that speed is a function of a board-specific characteristic such as which speed oscillator is used, it belongs in the board config file instead. In both cases it's safest to also set the initial JTAG clock rate to that same slow speed, so that OpenOCD never starts up using a clock speed that's faster than the scan chain can support. @example jtag_rclk 3000 $_TARGET.cpu configure -event reset-start @{ jtag_rclk 3000 @} @end example If your system supports adaptive clocking (RTCK), configuring JTAG to use that is probably the most robust approach. However, it introduces delays to synchronize clocks; so it may not be the fastest solution. @b{NOTE:} Script writers should consider using @command{jtag_rclk} instead of @command{adapter_khz}, but only for (ARM) cores and boards which support adaptive clocking. @deffn {Command} adapter_khz max_speed_kHz A non-zero speed is in KHZ. Hence: 3000 is 3mhz. JTAG interfaces usually support a limited number of speeds. The speed actually used won't be faster than the speed specified. Chip data sheets generally include a top JTAG clock rate. The actual rate is often a function of a CPU core clock, and is normally less than that peak rate. For example, most ARM cores accept at most one sixth of the CPU clock. Speed 0 (khz) selects RTCK method. @xref{faqrtck,,FAQ RTCK}. If your system uses RTCK, you won't need to change the JTAG clocking after setup. Not all interfaces, boards, or targets support ``rtck''. If the interface device can not support it, an error is returned when you try to use RTCK. @end deffn @defun jtag_rclk fallback_speed_kHz @cindex adaptive clocking @cindex RTCK This Tcl proc (defined in @file{startup.tcl}) attempts to enable RTCK/RCLK. If that fails (maybe the interface, board, or target doesn't support it), falls back to the specified frequency. @example # Fall back to 3mhz if RTCK is not supported jtag_rclk 3000 @end example @end defun @node Reset Configuration @chapter Reset Configuration @cindex Reset Configuration Every system configuration may require a different reset configuration. This can also be quite confusing. Resets also interact with @var{reset-init} event handlers, which do things like setting up clocks and DRAM, and JTAG clock rates. (@xref{jtagspeed,,JTAG Speed}.) They can also interact with JTAG routers. Please see the various board files for examples. @quotation Note To maintainers and integrators: Reset configuration touches several things at once. Normally the board configuration file should define it and assume that the JTAG adapter supports everything that's wired up to the board's JTAG connector. However, the target configuration file could also make note of something the silicon vendor has done inside the chip, which will be true for most (or all) boards using that chip. And when the JTAG adapter doesn't support everything, the user configuration file will need to override parts of the reset configuration provided by other files. @end quotation @section Types of Reset There are many kinds of reset possible through JTAG, but they may not all work with a given board and adapter. That's part of why reset configuration can be error prone. @itemize @bullet @item @emph{System Reset} ... the @emph{SRST} hardware signal resets all chips connected to the JTAG adapter, such as processors, power management chips, and I/O controllers. Normally resets triggered with this signal behave exactly like pressing a RESET button. @item @emph{JTAG TAP Reset} ... the @emph{TRST} hardware signal resets just the TAP controllers connected to the JTAG adapter. Such resets should not be visible to the rest of the system; resetting a device's TAP controller just puts that controller into a known state. @item @emph{Emulation Reset} ... many devices can be reset through JTAG commands. These resets are often distinguishable from system resets, either explicitly (a "reset reason" register says so) or implicitly (not all parts of the chip get reset). @item @emph{Other Resets} ... system-on-chip devices often support several other types of reset. You may need to arrange that a watchdog timer stops while debugging, preventing a watchdog reset. There may be individual module resets. @end itemize In the best case, OpenOCD can hold SRST, then reset the TAPs via TRST and send commands through JTAG to halt the CPU at the reset vector before the 1st instruction is executed. Then when it finally releases the SRST signal, the system is halted under debugger control before any code has executed. This is the behavior required to support the @command{reset halt} and @command{reset init} commands; after @command{reset init} a board-specific script might do things like setting up DRAM. (@xref{resetcommand,,Reset Command}.) @anchor{srstandtrstissues} @section SRST and TRST Issues Because SRST and TRST are hardware signals, they can have a variety of system-specific constraints. Some of the most common issues are: @itemize @bullet @item @emph{Signal not available} ... Some boards don't wire SRST or TRST to the JTAG connector. Some JTAG adapters don't support such signals even if they are wired up. Use the @command{reset_config} @var{signals} options to say when either of those signals is not connected. When SRST is not available, your code might not be able to rely on controllers having been fully reset during code startup. Missing TRST is not a problem, since JTAG-level resets can be triggered using with TMS signaling. @item @emph{Signals shorted} ... Sometimes a chip, board, or adapter will connect SRST to TRST, instead of keeping them separate. Use the @command{reset_config} @var{combination} options to say when those signals aren't properly independent. @item @emph{Timing} ... Reset circuitry like a resistor/capacitor delay circuit, reset supervisor, or on-chip features can extend the effect of a JTAG adapter's reset for some time after the adapter stops issuing the reset. For example, there may be chip or board requirements that all reset pulses last for at least a certain amount of time; and reset buttons commonly have hardware debouncing. Use the @command{adapter_nsrst_delay} and @command{jtag_ntrst_delay} commands to say when extra delays are needed. @item @emph{Drive type} ... Reset lines often have a pullup resistor, letting the JTAG interface treat them as open-drain signals. But that's not a requirement, so the adapter may need to use push/pull output drivers. Also, with weak pullups it may be advisable to drive signals to both levels (push/pull) to minimize rise times. Use the @command{reset_config} @var{trst_type} and @var{srst_type} parameters to say how to drive reset signals. @item @emph{Special initialization} ... Targets sometimes need special JTAG initialization sequences to handle chip-specific issues (not limited to errata). For example, certain JTAG commands might need to be issued while the system as a whole is in a reset state (SRST active) but the JTAG scan chain is usable (TRST inactive). Many systems treat combined assertion of SRST and TRST as a trigger for a harder reset than SRST alone. Such custom reset handling is discussed later in this chapter. @end itemize There can also be other issues. Some devices don't fully conform to the JTAG specifications. Trivial system-specific differences are common, such as SRST and TRST using slightly different names. There are also vendors who distribute key JTAG documentation for their chips only to developers who have signed a Non-Disclosure Agreement (NDA). Sometimes there are chip-specific extensions like a requirement to use the normally-optional TRST signal (precluding use of JTAG adapters which don't pass TRST through), or needing extra steps to complete a TAP reset. In short, SRST and especially TRST handling may be very finicky, needing to cope with both architecture and board specific constraints. @section Commands for Handling Resets @deffn {Command} adapter_nsrst_assert_width milliseconds Minimum amount of time (in milliseconds) OpenOCD should wait after asserting nSRST (active-low system reset) before allowing it to be deasserted. @end deffn @deffn {Command} adapter_nsrst_delay milliseconds How long (in milliseconds) OpenOCD should wait after deasserting nSRST (active-low system reset) before starting new JTAG operations. When a board has a reset button connected to SRST line it will probably have hardware debouncing, implying you should use this. @end deffn @deffn {Command} jtag_ntrst_assert_width milliseconds Minimum amount of time (in milliseconds) OpenOCD should wait after asserting nTRST (active-low JTAG TAP reset) before allowing it to be deasserted. @end deffn @deffn {Command} jtag_ntrst_delay milliseconds How long (in milliseconds) OpenOCD should wait after deasserting nTRST (active-low JTAG TAP reset) before starting new JTAG operations. @end deffn @deffn {Command} reset_config mode_flag ... This command displays or modifies the reset configuration of your combination of JTAG board and target in target configuration scripts. Information earlier in this section describes the kind of problems the command is intended to address (@pxref{srstandtrstissues,,SRST and TRST Issues}). As a rule this command belongs only in board config files, describing issues like @emph{board doesn't connect TRST}; or in user config files, addressing limitations derived from a particular combination of interface and board. (An unlikely example would be using a TRST-only adapter with a board that only wires up SRST.) The @var{mode_flag} options can be specified in any order, but only one of each type -- @var{signals}, @var{combination}, @var{gates}, @var{trst_type}, @var{srst_type} and @var{connect_type} -- may be specified at a time. If you don't provide a new value for a given type, its previous value (perhaps the default) is unchanged. For example, this means that you don't need to say anything at all about TRST just to declare that if the JTAG adapter should want to drive SRST, it must explicitly be driven high (@option{srst_push_pull}). @itemize @item @var{signals} can specify which of the reset signals are connected. For example, If the JTAG interface provides SRST, but the board doesn't connect that signal properly, then OpenOCD can't use it. Possible values are @option{none} (the default), @option{trst_only}, @option{srst_only} and @option{trst_and_srst}. @quotation Tip If your board provides SRST and/or TRST through the JTAG connector, you must declare that so those signals can be used. @end quotation @item The @var{combination} is an optional value specifying broken reset signal implementations. The default behaviour if no option given is @option{separate}, indicating everything behaves normally. @option{srst_pulls_trst} states that the test logic is reset together with the reset of the system (e.g. NXP LPC2000, "broken" board layout), @option{trst_pulls_srst} says that the system is reset together with the test logic (only hypothetical, I haven't seen hardware with such a bug, and can be worked around). @option{combined} implies both @option{srst_pulls_trst} and @option{trst_pulls_srst}. @item The @var{gates} tokens control flags that describe some cases where JTAG may be unvailable during reset. @option{srst_gates_jtag} (default) indicates that asserting SRST gates the JTAG clock. This means that no communication can happen on JTAG while SRST is asserted. Its converse is @option{srst_nogate}, indicating that JTAG commands can safely be issued while SRST is active. @item The @var{connect_type} tokens control flags that describe some cases where SRST is asserted while connecting to the target. @option{srst_nogate} is required to use this option. @option{connect_deassert_srst} (default) indicates that SRST will not be asserted while connecting to the target. Its converse is @option{connect_assert_srst}, indicating that SRST will be asserted before any target connection. Only some targets support this feature, STM32 and STR9 are examples. This feature is useful if you are unable to connect to your target due to incorrect options byte config or illegal program execution. @end itemize The optional @var{trst_type} and @var{srst_type} parameters allow the driver mode of each reset line to be specified. These values only affect JTAG interfaces with support for different driver modes, like the Amontec JTAGkey and JTAG Accelerator. Also, they are necessarily ignored if the relevant signal (TRST or SRST) is not connected. @itemize @item Possible @var{trst_type} driver modes for the test reset signal (TRST) are the default @option{trst_push_pull}, and @option{trst_open_drain}. Most boards connect this signal to a pulldown, so the JTAG TAPs never leave reset unless they are hooked up to a JTAG adapter. @item Possible @var{srst_type} driver modes for the system reset signal (SRST) are the default @option{srst_open_drain}, and @option{srst_push_pull}. Most boards connect this signal to a pullup, and allow the signal to be pulled low by various events including system powerup and pressing a reset button. @end itemize @end deffn @section Custom Reset Handling @cindex events OpenOCD has several ways to help support the various reset mechanisms provided by chip and board vendors. The commands shown in the previous section give standard parameters. There are also @emph{event handlers} associated with TAPs or Targets. Those handlers are Tcl procedures you can provide, which are invoked at particular points in the reset sequence. @emph{When SRST is not an option} you must set up a @code{reset-assert} event handler for your target. For example, some JTAG adapters don't include the SRST signal; and some boards have multiple targets, and you won't always want to reset everything at once. After configuring those mechanisms, you might still find your board doesn't start up or reset correctly. For example, maybe it needs a slightly different sequence of SRST and/or TRST manipulations, because of quirks that the @command{reset_config} mechanism doesn't address; or asserting both might trigger a stronger reset, which needs special attention. Experiment with lower level operations, such as @command{jtag_reset} and the @command{jtag arp_*} operations shown here, to find a sequence of operations that works. @xref{JTAG Commands}. When you find a working sequence, it can be used to override @command{jtag_init}, which fires during OpenOCD startup (@pxref{configurationstage,,Configuration Stage}); or @command{init_reset}, which fires during reset processing. You might also want to provide some project-specific reset schemes. For example, on a multi-target board the standard @command{reset} command would reset all targets, but you may need the ability to reset only one target at time and thus want to avoid using the board-wide SRST signal. @deffn {Overridable Procedure} init_reset mode This is invoked near the beginning of the @command{reset} command, usually to provide as much of a cold (power-up) reset as practical. By default it is also invoked from @command{jtag_init} if the scan chain does not respond to pure JTAG operations. The @var{mode} parameter is the parameter given to the low level reset command (@option{halt}, @option{init}, or @option{run}), @option{setup}, or potentially some other value. The default implementation just invokes @command{jtag arp_init-reset}. Replacements will normally build on low level JTAG operations such as @command{jtag_reset}. Operations here must not address individual TAPs (or their associated targets) until the JTAG scan chain has first been verified to work. Implementations must have verified the JTAG scan chain before they return. This is done by calling @command{jtag arp_init} (or @command{jtag arp_init-reset}). @end deffn @deffn Command {jtag arp_init} This validates the scan chain using just the four standard JTAG signals (TMS, TCK, TDI, TDO). It starts by issuing a JTAG-only reset. Then it performs checks to verify that the scan chain configuration matches the TAPs it can observe. Those checks include checking IDCODE values for each active TAP, and verifying the length of their instruction registers using TAP @code{-ircapture} and @code{-irmask} values. If these tests all pass, TAP @code{setup} events are issued to all TAPs with handlers for that event. @end deffn @deffn Command {jtag arp_init-reset} This uses TRST and SRST to try resetting everything on the JTAG scan chain (and anything else connected to SRST). It then invokes the logic of @command{jtag arp_init}. @end deffn @node TAP Declaration @chapter TAP Declaration @cindex TAP declaration @cindex TAP configuration @emph{Test Access Ports} (TAPs) are the core of JTAG. TAPs serve many roles, including: @itemize @bullet @item @b{Debug Target} A CPU TAP can be used as a GDB debug target @item @b{Flash Programing} Some chips program the flash directly via JTAG. Others do it indirectly, making a CPU do it. @item @b{Program Download} Using the same CPU support GDB uses, you can initialize a DRAM controller, download code to DRAM, and then start running that code. @item @b{Boundary Scan} Most chips support boundary scan, which helps test for board assembly problems like solder bridges and missing connections @end itemize OpenOCD must know about the active TAPs on your board(s). Setting up the TAPs is the core task of your configuration files. Once those TAPs are set up, you can pass their names to code which sets up CPUs and exports them as GDB targets, probes flash memory, performs low-level JTAG operations, and more. @section Scan Chains @cindex scan chain TAPs are part of a hardware @dfn{scan chain}, which is daisy chain of TAPs. They also need to be added to OpenOCD's software mirror of that hardware list, giving each member a name and associating other data with it. Simple scan chains, with a single TAP, are common in systems with a single microcontroller or microprocessor. More complex chips may have several TAPs internally. Very complex scan chains might have a dozen or more TAPs: several in one chip, more in the next, and connecting to other boards with their own chips and TAPs. You can display the list with the @command{scan_chain} command. (Don't confuse this with the list displayed by the @command{targets} command, presented in the next chapter. That only displays TAPs for CPUs which are configured as debugging targets.) Here's what the scan chain might look like for a chip more than one TAP: @verbatim TapName Enabled IdCode Expected IrLen IrCap IrMask -- ------------------ ------- ---------- ---------- ----- ----- ------ 0 omap5912.dsp Y 0x03df1d81 0x03df1d81 38 0x01 0x03 1 omap5912.arm Y 0x0692602f 0x0692602f 4 0x01 0x0f 2 omap5912.unknown Y 0x00000000 0x00000000 8 0x01 0x03 @end verbatim OpenOCD can detect some of that information, but not all of it. @xref{autoprobing,,Autoprobing}. Unfortunately those TAPs can't always be autoconfigured, because not all devices provide good support for that. JTAG doesn't require supporting IDCODE instructions, and chips with JTAG routers may not link TAPs into the chain until they are told to do so. The configuration mechanism currently supported by OpenOCD requires explicit configuration of all TAP devices using @command{jtag newtap} commands, as detailed later in this chapter. A command like this would declare one tap and name it @code{chip1.cpu}: @example jtag newtap chip1 cpu -irlen 4 -expected-id 0x3ba00477 @end example Each target configuration file lists the TAPs provided by a given chip. Board configuration files combine all the targets on a board, and so forth. Note that @emph{the order in which TAPs are declared is very important.} It must match the order in the JTAG scan chain, both inside a single chip and between them. @xref{faqtaporder,,FAQ TAP Order}. For example, the ST Microsystems STR912 chip has three separate TAPs@footnote{See the ST document titled: @emph{STR91xFAxxx, Section 3.15 Jtag Interface, Page: 28/102, Figure 3: JTAG chaining inside the STR91xFA}. @url{http://eu.st.com/stonline/products/literature/ds/13495.pdf}}. To configure those taps, @file{target/str912.cfg} includes commands something like this: @example jtag newtap str912 flash ... params ... jtag newtap str912 cpu ... params ... jtag newtap str912 bs ... params ... @end example Actual config files use a variable instead of literals like @option{str912}, to support more than one chip of each type. @xref{Config File Guidelines}. @deffn Command {jtag names} Returns the names of all current TAPs in the scan chain. Use @command{jtag cget} or @command{jtag tapisenabled} to examine attributes and state of each TAP. @example foreach t [jtag names] @{ puts [format "TAP: %s\n" $t] @} @end example @end deffn @deffn Command {scan_chain} Displays the TAPs in the scan chain configuration, and their status. The set of TAPs listed by this command is fixed by exiting the OpenOCD configuration stage, but systems with a JTAG router can enable or disable TAPs dynamically. @end deffn @c FIXME! "jtag cget" should be able to return all TAP @c attributes, like "$target_name cget" does for targets. @c Probably want "jtag eventlist", and a "tap-reset" event @c (on entry to RESET state). @section TAP Names @cindex dotted name When TAP objects are declared with @command{jtag newtap}, a @dfn{dotted.name} is created for the TAP, combining the name of a module (usually a chip) and a label for the TAP. For example: @code{xilinx.tap}, @code{str912.flash}, @code{omap3530.jrc}, @code{dm6446.dsp}, or @code{stm32.cpu}. Many other commands use that dotted.name to manipulate or refer to the TAP. For example, CPU configuration uses the name, as does declaration of NAND or NOR flash banks. The components of a dotted name should follow ``C'' symbol name rules: start with an alphabetic character, then numbers and underscores are OK; while others (including dots!) are not. @quotation Tip In older code, JTAG TAPs were numbered from 0..N. This feature is still present. However its use is highly discouraged, and should not be relied on; it will be removed by mid-2010. Update all of your scripts to use TAP names rather than numbers, by paying attention to the runtime warnings they trigger. Using TAP numbers in target configuration scripts prevents reusing those scripts on boards with multiple targets. @end quotation @section TAP Declaration Commands @c shouldn't this be(come) a {Config Command}? @deffn Command {jtag newtap} chipname tapname configparams... Declares a new TAP with the dotted name @var{chipname}.@var{tapname}, and configured according to the various @var{configparams}. The @var{chipname} is a symbolic name for the chip. Conventionally target config files use @code{$_CHIPNAME}, defaulting to the model name given by the chip vendor but overridable. @cindex TAP naming convention The @var{tapname} reflects the role of that TAP, and should follow this convention: @itemize @bullet @item @code{bs} -- For boundary scan if this is a seperate TAP; @item @code{cpu} -- The main CPU of the chip, alternatively @code{arm} and @code{dsp} on chips with both ARM and DSP CPUs, @code{arm1} and @code{arm2} on chips two ARMs, and so forth; @item @code{etb} -- For an embedded trace buffer (example: an ARM ETB11); @item @code{flash} -- If the chip has a flash TAP, like the str912; @item @code{jrc} -- For JTAG route controller (example: the ICEpick modules on many Texas Instruments chips, like the OMAP3530 on Beagleboards); @item @code{tap} -- Should be used only FPGA or CPLD like devices with a single TAP; @item @code{unknownN} -- If you have no idea what the TAP is for (N is a number); @item @emph{when in doubt} -- Use the chip maker's name in their data sheet. For example, the Freescale IMX31 has a SDMA (Smart DMA) with a JTAG TAP; that TAP should be named @code{sdma}. @end itemize Every TAP requires at least the following @var{configparams}: @itemize @bullet @item @code{-irlen} @var{NUMBER} @*The length in bits of the instruction register, such as 4 or 5 bits. @end itemize A TAP may also provide optional @var{configparams}: @itemize @bullet @item @code{-disable} (or @code{-enable}) @*Use the @code{-disable} parameter to flag a TAP which is not linked in to the scan chain after a reset using either TRST or the JTAG state machine's @sc{reset} state. You may use @code{-enable} to highlight the default state (the TAP is linked in). @xref{enablinganddisablingtaps,,Enabling and Disabling TAPs}. @item @code{-expected-id} @var{number} @*A non-zero @var{number} represents a 32-bit IDCODE which you expect to find when the scan chain is examined. These codes are not required by all JTAG devices. @emph{Repeat the option} as many times as required if more than one ID code could appear (for example, multiple versions). Specify @var{number} as zero to suppress warnings about IDCODE values that were found but not included in the list. Provide this value if at all possible, since it lets OpenOCD tell when the scan chain it sees isn't right. These values are provided in vendors' chip documentation, usually a technical reference manual. Sometimes you may need to probe the JTAG hardware to find these values. @xref{autoprobing,,Autoprobing}. @item @code{-ignore-version} @*Specify this to ignore the JTAG version field in the @code{-expected-id} option. When vendors put out multiple versions of a chip, or use the same JTAG-level ID for several largely-compatible chips, it may be more practical to ignore the version field than to update config files to handle all of the various chip IDs. The version field is defined as bit 28-31 of the IDCODE. @item @code{-ircapture} @var{NUMBER} @*The bit pattern loaded by the TAP into the JTAG shift register on entry to the @sc{ircapture} state, such as 0x01. JTAG requires the two LSBs of this value to be 01. By default, @code{-ircapture} and @code{-irmask} are set up to verify that two-bit value. You may provide additional bits, if you know them, or indicate that a TAP doesn't conform to the JTAG specification. @item @code{-irmask} @var{NUMBER} @*A mask used with @code{-ircapture} to verify that instruction scans work correctly. Such scans are not used by OpenOCD except to verify that there seems to be no problems with JTAG scan chain operations. @end itemize @end deffn @section Other TAP commands @deffn Command {jtag cget} dotted.name @option{-event} name @deffnx Command {jtag configure} dotted.name @option{-event} name string At this writing this TAP attribute mechanism is used only for event handling. (It is not a direct analogue of the @code{cget}/@code{configure} mechanism for debugger targets.) See the next section for information about the available events. The @code{configure} subcommand assigns an event handler, a TCL string which is evaluated when the event is triggered. The @code{cget} subcommand returns that handler. @end deffn @section TAP Events @cindex events @cindex TAP events OpenOCD includes two event mechanisms. The one presented here applies to all JTAG TAPs. The other applies to debugger targets, which are associated with certain TAPs. The TAP events currently defined are: @itemize @bullet @item @b{post-reset} @* The TAP has just completed a JTAG reset. The tap may still be in the JTAG @sc{reset} state. Handlers for these events might perform initialization sequences such as issuing TCK cycles, TMS sequences to ensure exit from the ARM SWD mode, and more. Because the scan chain has not yet been verified, handlers for these events @emph{should not issue commands which scan the JTAG IR or DR registers} of any particular target. @b{NOTE:} As this is written (September 2009), nothing prevents such access. @item @b{setup} @* The scan chain has been reset and verified. This handler may enable TAPs as needed. @item @b{tap-disable} @* The TAP needs to be disabled. This handler should implement @command{jtag tapdisable} by issuing the relevant JTAG commands. @item @b{tap-enable} @* The TAP needs to be enabled. This handler should implement @command{jtag tapenable} by issuing the relevant JTAG commands. @end itemize If you need some action after each JTAG reset, which isn't actually specific to any TAP (since you can't yet trust the scan chain's contents to be accurate), you might: @example jtag configure CHIP.jrc -event post-reset @{ echo "JTAG Reset done" ... non-scan jtag operations to be done after reset @} @end example @anchor{enablinganddisablingtaps} @section Enabling and Disabling TAPs @cindex JTAG Route Controller @cindex jrc In some systems, a @dfn{JTAG Route Controller} (JRC) is used to enable and/or disable specific JTAG TAPs. Many ARM based chips from Texas Instruments include an ``ICEpick'' module, which is a JRC. Such chips include DaVinci and OMAP3 processors. A given TAP may not be visible until the JRC has been told to link it into the scan chain; and if the JRC has been told to unlink that TAP, it will no longer be visible. Such routers address problems that JTAG ``bypass mode'' ignores, such as: @itemize @item The scan chain can only go as fast as its slowest TAP. @item Having many TAPs slows instruction scans, since all TAPs receive new instructions. @item TAPs in the scan chain must be powered up, which wastes power and prevents debugging some power management mechanisms. @end itemize The IEEE 1149.1 JTAG standard has no concept of a ``disabled'' tap, as implied by the existence of JTAG routers. However, the upcoming IEEE 1149.7 framework (layered on top of JTAG) does include a kind of JTAG router functionality. @c (a) currently the event handlers don't seem to be able to @c fail in a way that could lead to no-change-of-state. In OpenOCD, tap enabling/disabling is invoked by the Tcl commands shown below, and is implemented using TAP event handlers. So for example, when defining a TAP for a CPU connected to a JTAG router, your @file{target.cfg} file should define TAP event handlers using code that looks something like this: @example jtag configure CHIP.cpu -event tap-enable @{ ... jtag operations using CHIP.jrc @} jtag configure CHIP.cpu -event tap-disable @{ ... jtag operations using CHIP.jrc @} @end example Then you might want that CPU's TAP enabled almost all the time: @example jtag configure $CHIP.jrc -event setup "jtag tapenable $CHIP.cpu" @end example Note how that particular setup event handler declaration uses quotes to evaluate @code{$CHIP} when the event is configured. Using brackets @{ @} would cause it to be evaluated later, at runtime, when it might have a different value. @deffn Command {jtag tapdisable} dotted.name If necessary, disables the tap by sending it a @option{tap-disable} event. Returns the string "1" if the tap specified by @var{dotted.name} is enabled, and "0" if it is disabled. @end deffn @deffn Command {jtag tapenable} dotted.name If necessary, enables the tap by sending it a @option{tap-enable} event. Returns the string "1" if the tap specified by @var{dotted.name} is enabled, and "0" if it is disabled. @end deffn @deffn Command {jtag tapisenabled} dotted.name Returns the string "1" if the tap specified by @var{dotted.name} is enabled, and "0" if it is disabled. @quotation Note Humans will find the @command{scan_chain} command more helpful for querying the state of the JTAG taps. @end quotation @end deffn @anchor{autoprobing} @section Autoprobing @cindex autoprobe @cindex JTAG autoprobe TAP configuration is the first thing that needs to be done after interface and reset configuration. Sometimes it's hard finding out what TAPs exist, or how they are identified. Vendor documentation is not always easy to find and use. To help you get past such problems, OpenOCD has a limited @emph{autoprobing} ability to look at the scan chain, doing a @dfn{blind interrogation} and then reporting the TAPs it finds. To use this mechanism, start the OpenOCD server with only data that configures your JTAG interface, and arranges to come up with a slow clock (many devices don't support fast JTAG clocks right when they come out of reset). For example, your @file{openocd.cfg} file might have: @example source [find interface/olimex-arm-usb-tiny-h.cfg] reset_config trst_and_srst jtag_rclk 8 @end example When you start the server without any TAPs configured, it will attempt to autoconfigure the TAPs. There are two parts to this: @enumerate @item @emph{TAP discovery} ... After a JTAG reset (sometimes a system reset may be needed too), each TAP's data registers will hold the contents of either the IDCODE or BYPASS register. If JTAG communication is working, OpenOCD will see each TAP, and report what @option{-expected-id} to use with it. @item @emph{IR Length discovery} ... Unfortunately JTAG does not provide a reliable way to find out the value of the @option{-irlen} parameter to use with a TAP that is discovered. If OpenOCD can discover the length of a TAP's instruction register, it will report it. Otherwise you may need to consult vendor documentation, such as chip data sheets or BSDL files. @end enumerate In many cases your board will have a simple scan chain with just a single device. Here's what OpenOCD reported with one board that's a bit more complex: @example clock speed 8 kHz There are no enabled taps. AUTO PROBING MIGHT NOT WORK!! AUTO auto0.tap - use "jtag newtap auto0 tap -expected-id 0x2b900f0f ..." AUTO auto1.tap - use "jtag newtap auto1 tap -expected-id 0x07926001 ..." AUTO auto2.tap - use "jtag newtap auto2 tap -expected-id 0x0b73b02f ..." AUTO auto0.tap - use "... -irlen 4" AUTO auto1.tap - use "... -irlen 4" AUTO auto2.tap - use "... -irlen 6" no gdb ports allocated as no target has been specified @end example Given that information, you should be able to either find some existing config files to use, or create your own. If you create your own, you would configure from the bottom up: first a @file{target.cfg} file with these TAPs, any targets associated with them, and any on-chip resources; then a @file{board.cfg} with off-chip resources, clocking, and so forth. @node CPU Configuration @chapter CPU Configuration @cindex GDB target This chapter discusses how to set up GDB debug targets for CPUs. You can also access these targets without GDB (@pxref{Architecture and Core Commands}, and @ref{targetstatehandling,,Target State handling}) and through various kinds of NAND and NOR flash commands. If you have multiple CPUs you can have multiple such targets. We'll start by looking at how to examine the targets you have, then look at how to add one more target and how to configure it. @section Target List @cindex target, current @cindex target, list All targets that have been set up are part of a list, where each member has a name. That name should normally be the same as the TAP name. You can display the list with the @command{targets} (plural!) command. This display often has only one CPU; here's what it might look like with more than one: @verbatim TargetName Type Endian TapName State -- ------------------ ---------- ------ ------------------ ------------ 0* at91rm9200.cpu arm920t little at91rm9200.cpu running 1 MyTarget cortex_m little mychip.foo tap-disabled @end verbatim One member of that list is the @dfn{current target}, which is implicitly referenced by many commands. It's the one marked with a @code{*} near the target name. In particular, memory addresses often refer to the address space seen by that current target. Commands like @command{mdw} (memory display words) and @command{flash erase_address} (erase NOR flash blocks) are examples; and there are many more. Several commands let you examine the list of targets: @deffn Command {target count} @emph{Note: target numbers are deprecated; don't use them. They will be removed shortly after August 2010, including this command. Iterate target using @command{target names}, not by counting.} Returns the number of targets, @math{N}. The highest numbered target is @math{N - 1}. @example set c [target count] for @{ set x 0 @} @{ $x < $c @} @{ incr x @} @{ # Assuming you have created this function print_target_details $x @} @end example @end deffn @deffn Command {target current} Returns the name of the current target. @end deffn @deffn Command {target names} Lists the names of all current targets in the list. @example foreach t [target names] @{ puts [format "Target: %s\n" $t] @} @end example @end deffn @deffn Command {target number} number @emph{Note: target numbers are deprecated; don't use them. They will be removed shortly after August 2010, including this command.} The list of targets is numbered starting at zero. This command returns the name of the target at index @var{number}. @example set thename [target number $x] puts [format "Target %d is: %s\n" $x $thename] @end example @end deffn @c yep, "target list" would have been better. @c plus maybe "target setdefault". @deffn Command targets [name] @emph{Note: the name of this command is plural. Other target command names are singular.} With no parameter, this command displays a table of all known targets in a user friendly form. With a parameter, this command sets the current target to the given target with the given @var{name}; this is only relevant on boards which have more than one target. @end deffn @section Target CPU Types and Variants @cindex target type @cindex CPU type @cindex CPU variant Each target has a @dfn{CPU type}, as shown in the output of the @command{targets} command. You need to specify that type when calling @command{target create}. The CPU type indicates more than just the instruction set. It also indicates how that instruction set is implemented, what kind of debug support it integrates, whether it has an MMU (and if so, what kind), what core-specific commands may be available (@pxref{Architecture and Core Commands}), and more. For some CPU types, OpenOCD also defines @dfn{variants} which indicate differences that affect their handling. For example, a particular implementation bug might need to be worked around in some chip versions. It's easy to see what target types are supported, since there's a command to list them. However, there is currently no way to list what target variants are supported (other than by reading the OpenOCD source code). @anchor{targettypes} @deffn Command {target types} Lists all supported target types. At this writing, the supported CPU types and variants are: @itemize @bullet @item @code{arm11} -- this is a generation of ARMv6 cores @item @code{arm720t} -- this is an ARMv4 core with an MMU @item @code{arm7tdmi} -- this is an ARMv4 core @item @code{arm920t} -- this is an ARMv4 core with an MMU @item @code{arm926ejs} -- this is an ARMv5 core with an MMU @item @code{arm966e} -- this is an ARMv5 core @item @code{arm9tdmi} -- this is an ARMv4 core @item @code{avr} -- implements Atmel's 8-bit AVR instruction set. (Support for this is preliminary and incomplete.) @item @code{cortex_a} -- this is an ARMv7 core with an MMU @item @code{cortex_m} -- this is an ARMv7 core, supporting only the compact Thumb2 instruction set. @item @code{dragonite} -- resembles arm966e @item @code{dsp563xx} -- implements Freescale's 24-bit DSP. (Support for this is still incomplete.) @item @code{fa526} -- resembles arm920 (w/o Thumb) @item @code{feroceon} -- resembles arm926 @item @code{mips_m4k} -- a MIPS core. This supports one variant: @item @code{xscale} -- this is actually an architecture, not a CPU type. It is based on the ARMv5 architecture. There are several variants defined: @itemize @minus @item @code{ixp42x}, @code{ixp45x}, @code{ixp46x}, @code{pxa27x} ... instruction register length is 7 bits @item @code{pxa250}, @code{pxa255}, @code{pxa26x} ... instruction register length is 5 bits @item @code{pxa3xx} ... instruction register length is 11 bits @end itemize @end itemize @end deffn To avoid being confused by the variety of ARM based cores, remember this key point: @emph{ARM is a technology licencing company}. (See: @url{http://www.arm.com}.) The CPU name used by OpenOCD will reflect the CPU design that was licenced, not a vendor brand which incorporates that design. Name prefixes like arm7, arm9, arm11, and cortex reflect design generations; while names like ARMv4, ARMv5, ARMv6, and ARMv7 reflect an architecture version implemented by a CPU design. @anchor{targetconfiguration} @section Target Configuration Before creating a ``target'', you must have added its TAP to the scan chain. When you've added that TAP, you will have a @code{dotted.name} which is used to set up the CPU support. The chip-specific configuration file will normally configure its CPU(s) right after it adds all of the chip's TAPs to the scan chain. Although you can set up a target in one step, it's often clearer if you use shorter commands and do it in two steps: create it, then configure optional parts. All operations on the target after it's created will use a new command, created as part of target creation. The two main things to configure after target creation are a work area, which usually has target-specific defaults even if the board setup code overrides them later; and event handlers (@pxref{targetevents,,Target Events}), which tend to be much more board-specific. The key steps you use might look something like this @example target create MyTarget cortex_m -chain-position mychip.cpu $MyTarget configure -work-area-phys 0x08000 -work-area-size 8096 $MyTarget configure -event reset-deassert-pre @{ jtag_rclk 5 @} $MyTarget configure -event reset-init @{ myboard_reinit @} @end example You should specify a working area if you can; typically it uses some on-chip SRAM. Such a working area can speed up many things, including bulk writes to target memory; flash operations like checking to see if memory needs to be erased; GDB memory checksumming; and more. @quotation Warning On more complex chips, the work area can become inaccessible when application code (such as an operating system) enables or disables the MMU. For example, the particular MMU context used to acess the virtual address will probably matter ... and that context might not have easy access to other addresses needed. At this writing, OpenOCD doesn't have much MMU intelligence. @end quotation It's often very useful to define a @code{reset-init} event handler. For systems that are normally used with a boot loader, common tasks include updating clocks and initializing memory controllers. That may be needed to let you write the boot loader into flash, in order to ``de-brick'' your board; or to load programs into external DDR memory without having run the boot loader. @deffn Command {target create} target_name type configparams... This command creates a GDB debug target that refers to a specific JTAG tap. It enters that target into a list, and creates a new command (@command{@var{target_name}}) which is used for various purposes including additional configuration. @itemize @bullet @item @var{target_name} ... is the name of the debug target. By convention this should be the same as the @emph{dotted.name} of the TAP associated with this target, which must be specified here using the @code{-chain-position @var{dotted.name}} configparam. This name is also used to create the target object command, referred to here as @command{$target_name}, and in other places the target needs to be identified. @item @var{type} ... specifies the target type. @xref{targettypes,,target types}. @item @var{configparams} ... all parameters accepted by @command{$target_name configure} are permitted. If the target is big-endian, set it here with @code{-endian big}. If the variant matters, set it here with @code{-variant}. You @emph{must} set the @code{-chain-position @var{dotted.name}} here. @end itemize @end deffn @deffn Command {$target_name configure} configparams... The options accepted by this command may also be specified as parameters to @command{target create}. Their values can later be queried one at a time by using the @command{$target_name cget} command. @emph{Warning:} changing some of these after setup is dangerous. For example, moving a target from one TAP to another; and changing its endianness or variant. @itemize @bullet @item @code{-chain-position} @var{dotted.name} -- names the TAP used to access this target. @item @code{-endian} (@option{big}|@option{little}) -- specifies whether the CPU uses big or little endian conventions @item @code{-event} @var{event_name} @var{event_body} -- @xref{targetevents,,Target Events}. Note that this updates a list of named event handlers. Calling this twice with two different event names assigns two different handlers, but calling it twice with the same event name assigns only one handler. @item @code{-variant} @var{name} -- specifies a variant of the target, which OpenOCD needs to know about. @item @code{-work-area-backup} (@option{0}|@option{1}) -- says whether the work area gets backed up; by default, @emph{it is not backed up.} When possible, use a working_area that doesn't need to be backed up, since performing a backup slows down operations. For example, the beginning of an SRAM block is likely to be used by most build systems, but the end is often unused. @item @code{-work-area-size} @var{size} -- specify work are size, in bytes. The same size applies regardless of whether its physical or virtual address is being used. @item @code{-work-area-phys} @var{address} -- set the work area base @var{address} to be used when no MMU is active. @item @code{-work-area-virt} @var{address} -- set the work area base @var{address} to be used when an MMU is active. @emph{Do not specify a value for this except on targets with an MMU.} The value should normally correspond to a static mapping for the @code{-work-area-phys} address, set up by the current operating system. @item @code{-rtos} @var{rtos_type} -- enable rtos support for target, @var{rtos_type} can be one of @option{auto}|@option{eCos}|@option{ThreadX}| @option{FreeRTOS}|@option{linux}|@option{ChibiOS}. @end itemize @end deffn @section Other $target_name Commands @cindex object command The Tcl/Tk language has the concept of object commands, and OpenOCD adopts that same model for targets. A good Tk example is a on screen button. Once a button is created a button has a name (a path in Tk terms) and that name is useable as a first class command. For example in Tk, one can create a button and later configure it like this: @example # Create button .foobar -background red -command @{ foo @} # Modify .foobar configure -foreground blue # Query set x [.foobar cget -background] # Report puts [format "The button is %s" $x] @end example In OpenOCD's terms, the ``target'' is an object just like a Tcl/Tk button, and its object commands are invoked the same way. @example str912.cpu mww 0x1234 0x42 omap3530.cpu mww 0x5555 123 @end example The commands supported by OpenOCD target objects are: @deffn Command {$target_name arp_examine} @deffnx Command {$target_name arp_halt} @deffnx Command {$target_name arp_poll} @deffnx Command {$target_name arp_reset} @deffnx Command {$target_name arp_waitstate} Internal OpenOCD scripts (most notably @file{startup.tcl}) use these to deal with specific reset cases. They are not otherwise documented here. @end deffn @deffn Command {$target_name array2mem} arrayname width address count @deffnx Command {$target_name mem2array} arrayname width address count These provide an efficient script-oriented interface to memory. The @code{array2mem} primitive writes bytes, halfwords, or words; while @code{mem2array} reads them. In both cases, the TCL side uses an array, and the target side uses raw memory. The efficiency comes from enabling the use of bulk JTAG data transfer operations. The script orientation comes from working with data values that are packaged for use by TCL scripts; @command{mdw} type primitives only print data they retrieve, and neither store nor return those values. @itemize @item @var{arrayname} ... is the name of an array variable @item @var{width} ... is 8/16/32 - indicating the memory access size @item @var{address} ... is the target memory address @item @var{count} ... is the number of elements to process @end itemize @end deffn @deffn Command {$target_name cget} queryparm Each configuration parameter accepted by @command{$target_name configure} can be individually queried, to return its current value. The @var{queryparm} is a parameter name accepted by that command, such as @code{-work-area-phys}. There are a few special cases: @itemize @bullet @item @code{-event} @var{event_name} -- returns the handler for the event named @var{event_name}. This is a special case because setting a handler requires two parameters. @item @code{-type} -- returns the target type. This is a special case because this is set using @command{target create} and can't be changed using @command{$target_name configure}. @end itemize For example, if you wanted to summarize information about all the targets you might use something like this: @example foreach name [target names] @{ set y [$name cget -endian] set z [$name cget -type] puts [format "Chip %d is %s, Endian: %s, type: %s" \ $x $name $y $z] @} @end example @end deffn @anchor{targetcurstate} @deffn Command {$target_name curstate} Displays the current target state: @code{debug-running}, @code{halted}, @code{reset}, @code{running}, or @code{unknown}. (Also, @pxref{eventpolling,,Event Polling}.) @end deffn @deffn Command {$target_name eventlist} Displays a table listing all event handlers currently associated with this target. @xref{targetevents,,Target Events}. @end deffn @deffn Command {$target_name invoke-event} event_name Invokes the handler for the event named @var{event_name}. (This is primarily intended for use by OpenOCD framework code, for example by the reset code in @file{startup.tcl}.) @end deffn @deffn Command {$target_name mdw} addr [count] @deffnx Command {$target_name mdh} addr [count] @deffnx Command {$target_name mdb} addr [count] Display contents of address @var{addr}, as 32-bit words (@command{mdw}), 16-bit halfwords (@command{mdh}), or 8-bit bytes (@command{mdb}). If @var{count} is specified, displays that many units. (If you want to manipulate the data instead of displaying it, see the @code{mem2array} primitives.) @end deffn @deffn Command {$target_name mww} addr word @deffnx Command {$target_name mwh} addr halfword @deffnx Command {$target_name mwb} addr byte Writes the specified @var{word} (32 bits), @var{halfword} (16 bits), or @var{byte} (8-bit) pattern, at the specified address @var{addr}. @end deffn @anchor{targetevents} @section Target Events @cindex target events @cindex events At various times, certain things can happen, or you want them to happen. For example: @itemize @bullet @item What should happen when GDB connects? Should your target reset? @item When GDB tries to flash the target, do you need to enable the flash via a special command? @item Is using SRST appropriate (and possible) on your system? Or instead of that, do you need to issue JTAG commands to trigger reset? SRST usually resets everything on the scan chain, which can be inappropriate. @item During reset, do you need to write to certain memory locations to set up system clocks or to reconfigure the SDRAM? How about configuring the watchdog timer, or other peripherals, to stop running while you hold the core stopped for debugging? @end itemize All of the above items can be addressed by target event handlers. These are set up by @command{$target_name configure -event} or @command{target create ... -event}. The programmer's model matches the @code{-command} option used in Tcl/Tk buttons and events. The two examples below act the same, but one creates and invokes a small procedure while the other inlines it. @example proc my_attach_proc @{ @} @{ echo "Reset..." reset halt @} mychip.cpu configure -event gdb-attach my_attach_proc mychip.cpu configure -event gdb-attach @{ echo "Reset..." # To make flash probe and gdb load to flash work we need a reset init. reset init @} @end example The following target events are defined: @itemize @bullet @item @b{debug-halted} @* The target has halted for debug reasons (i.e.: breakpoint) @item @b{debug-resumed} @* The target has resumed (i.e.: gdb said run) @item @b{early-halted} @* Occurs early in the halt process @item @b{examine-start} @* Before target examine is called. @item @b{examine-end} @* After target examine is called with no errors. @item @b{gdb-attach} @* When GDB connects. This is before any communication with the target, so this can be used to set up the target so it is possible to probe flash. Probing flash is necessary during gdb connect if gdb load is to write the image to flash. Another use of the flash memory map is for GDB to automatically hardware/software breakpoints depending on whether the breakpoint is in RAM or read only memory. @item @b{gdb-detach} @* When GDB disconnects @item @b{gdb-end} @* When the target has halted and GDB is not doing anything (see early halt) @item @b{gdb-flash-erase-start} @* Before the GDB flash process tries to erase the flash @item @b{gdb-flash-erase-end} @* After the GDB flash process has finished erasing the flash @item @b{gdb-flash-write-start} @* Before GDB writes to the flash @item @b{gdb-flash-write-end} @* After GDB writes to the flash @item @b{gdb-start} @* Before the target steps, gdb is trying to start/resume the target @item @b{halted} @* The target has halted @item @b{reset-assert-pre} @* Issued as part of @command{reset} processing after @command{reset_init} was triggered but before either SRST alone is re-asserted on the scan chain, or @code{reset-assert} is triggered. @item @b{reset-assert} @* Issued as part of @command{reset} processing after @command{reset-assert-pre} was triggered. When such a handler is present, cores which support this event will use it instead of asserting SRST. This support is essential for debugging with JTAG interfaces which don't include an SRST line (JTAG doesn't require SRST), and for selective reset on scan chains that have multiple targets. @item @b{reset-assert-post} @* Issued as part of @command{reset} processing after @code{reset-assert} has been triggered. or the target asserted SRST on the entire scan chain. @item @b{reset-deassert-pre} @* Issued as part of @command{reset} processing after @code{reset-assert-post} has been triggered. @item @b{reset-deassert-post} @* Issued as part of @command{reset} processing after @code{reset-deassert-pre} has been triggered and (if the target is using it) after SRST has been released on the scan chain. @item @b{reset-end} @* Issued as the final step in @command{reset} processing. @ignore @item @b{reset-halt-post} @* Currently not used @item @b{reset-halt-pre} @* Currently not used @end ignore @item @b{reset-init} @* Used by @b{reset init} command for board-specific initialization. This event fires after @emph{reset-deassert-post}. This is where you would configure PLLs and clocking, set up DRAM so you can download programs that don't fit in on-chip SRAM, set up pin multiplexing, and so on. (You may be able to switch to a fast JTAG clock rate here, after the target clocks are fully set up.) @item @b{reset-start} @* Issued as part of @command{reset} processing before @command{reset_init} is called. This is the most robust place to use @command{jtag_rclk} or @command{adapter_khz} to switch to a low JTAG clock rate, when reset disables PLLs needed to use a fast clock. @ignore @item @b{reset-wait-pos} @* Currently not used @item @b{reset-wait-pre} @* Currently not used @end ignore @item @b{resume-start} @* Before any target is resumed @item @b{resume-end} @* After all targets have resumed @item @b{resumed} @* Target has resumed @end itemize @node Flash Commands @chapter Flash Commands OpenOCD has different commands for NOR and NAND flash; the ``flash'' command works with NOR flash, while the ``nand'' command works with NAND flash. This partially reflects different hardware technologies: NOR flash usually supports direct CPU instruction and data bus access, while data from a NAND flash must be copied to memory before it can be used. (SPI flash must also be copied to memory before use.) However, the documentation also uses ``flash'' as a generic term; for example, ``Put flash configuration in board-specific files''. Flash Steps: @enumerate @item Configure via the command @command{flash bank} @* Do this in a board-specific configuration file, passing parameters as needed by the driver. @item Operate on the flash via @command{flash subcommand} @* Often commands to manipulate the flash are typed by a human, or run via a script in some automated way. Common tasks include writing a boot loader, operating system, or other data. @item GDB Flashing @* Flashing via GDB requires the flash be configured via ``flash bank'', and the GDB flash features be enabled. @xref{gdbconfiguration,,GDB Configuration}. @end enumerate Many CPUs have the ablity to ``boot'' from the first flash bank. This means that misprogramming that bank can ``brick'' a system, so that it can't boot. JTAG tools, like OpenOCD, are often then used to ``de-brick'' the board by (re)installing working boot firmware. @anchor{norconfiguration} @section Flash Configuration Commands @cindex flash configuration @deffn {Config Command} {flash bank} name driver base size chip_width bus_width target [driver_options] Configures a flash bank which provides persistent storage for addresses from @math{base} to @math{base + size - 1}. These banks will often be visible to GDB through the target's memory map. In some cases, configuring a flash bank will activate extra commands; see the driver-specific documentation. @itemize @bullet @item @var{name} ... may be used to reference the flash bank in other flash commands. A number is also available. @item @var{driver} ... identifies the controller driver associated with the flash bank being declared. This is usually @code{cfi} for external flash, or else the name of a microcontroller with embedded flash memory. @xref{flashdriverlist,,Flash Driver List}. @item @var{base} ... Base address of the flash chip. @item @var{size} ... Size of the chip, in bytes. For some drivers, this value is detected from the hardware. @item @var{chip_width} ... Width of the flash chip, in bytes; ignored for most microcontroller drivers. @item @var{bus_width} ... Width of the data bus used to access the chip, in bytes; ignored for most microcontroller drivers. @item @var{target} ... Names the target used to issue commands to the flash controller. @comment Actually, it's currently a controller-specific parameter... @item @var{driver_options} ... drivers may support, or require, additional parameters. See the driver-specific documentation for more information. @end itemize @quotation Note This command is not available after OpenOCD initialization has completed. Use it in board specific configuration files, not interactively. @end quotation @end deffn @comment the REAL name for this command is "ocd_flash_banks" @comment less confusing would be: "flash list" (like "nand list") @deffn Command {flash banks} Prints a one-line summary of each device that was declared using @command{flash bank}, numbered from zero. Note that this is the @emph{plural} form; the @emph{singular} form is a very different command. @end deffn @deffn Command {flash list} Retrieves a list of associative arrays for each device that was declared using @command{flash bank}, numbered from zero. This returned list can be manipulated easily from within scripts. @end deffn @deffn Command {flash probe} num Identify the flash, or validate the parameters of the configured flash. Operation depends on the flash type. The @var{num} parameter is a value shown by @command{flash banks}. Most flash commands will implicitly @emph{autoprobe} the bank; flash drivers can distinguish between probing and autoprobing, but most don't bother. @end deffn @section Erasing, Reading, Writing to Flash @cindex flash erasing @cindex flash reading @cindex flash writing @cindex flash programming @anchor{flashprogrammingcommands} One feature distinguishing NOR flash from NAND or serial flash technologies is that for read access, it acts exactly like any other addressible memory. This means you can use normal memory read commands like @command{mdw} or @command{dump_image} with it, with no special @command{flash} subcommands. @xref{memoryaccess,,Memory access}, and @ref{imageaccess,,Image access}. Write access works differently. Flash memory normally needs to be erased before it's written. Erasing a sector turns all of its bits to ones, and writing can turn ones into zeroes. This is why there are special commands for interactive erasing and writing, and why GDB needs to know which parts of the address space hold NOR flash memory. @quotation Note Most of these erase and write commands leverage the fact that NOR flash chips consume target address space. They implicitly refer to the current JTAG target, and map from an address in that target's address space back to a flash bank. @comment In May 2009, those mappings may fail if any bank associated @comment with that target doesn't succesfuly autoprobe ... bug worth fixing? A few commands use abstract addressing based on bank and sector numbers, and don't depend on searching the current target and its address space. Avoid confusing the two command models. @end quotation Some flash chips implement software protection against accidental writes, since such buggy writes could in some cases ``brick'' a system. For such systems, erasing and writing may require sector protection to be disabled first. Examples include CFI flash such as ``Intel Advanced Bootblock flash'', and AT91SAM7 on-chip flash. @xref{flashprotect,,flash protect}. @deffn Command {flash erase_sector} num first last Erase sectors in bank @var{num}, starting at sector @var{first} up to and including @var{last}. Sector numbering starts at 0. Providing a @var{last} sector of @option{last} specifies "to the end of the flash bank". The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn Command {flash erase_address} [@option{pad}] [@option{unlock}] address length Erase sectors starting at @var{address} for @var{length} bytes. Unless @option{pad} is specified, @math{address} must begin a flash sector, and @math{address + length - 1} must end a sector. Specifying @option{pad} erases extra data at the beginning and/or end of the specified region, as needed to erase only full sectors. The flash bank to use is inferred from the @var{address}, and the specified length must stay within that bank. As a special case, when @var{length} is zero and @var{address} is the start of the bank, the whole flash is erased. If @option{unlock} is specified, then the flash is unprotected before erase starts. @end deffn @deffn Command {flash fillw} address word length @deffnx Command {flash fillh} address halfword length @deffnx Command {flash fillb} address byte length Fills flash memory with the specified @var{word} (32 bits), @var{halfword} (16 bits), or @var{byte} (8-bit) pattern, starting at @var{address} and continuing for @var{length} units (word/halfword/byte). No erasure is done before writing; when needed, that must be done before issuing this command. Writes are done in blocks of up to 1024 bytes, and each write is verified by reading back the data and comparing it to what was written. The flash bank to use is inferred from the @var{address} of each block, and the specified length must stay within that bank. @end deffn @comment no current checks for errors if fill blocks touch multiple banks! @deffn Command {flash write_bank} num filename offset Write the binary @file{filename} to flash bank @var{num}, starting at @var{offset} bytes from the beginning of the bank. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn Command {flash write_image} [erase] [unlock] filename [offset] [type] Write the image @file{filename} to the current target's flash bank(s). A relocation @var{offset} may be specified, in which case it is added to the base address for each section in the image. The file [@var{type}] can be specified explicitly as @option{bin} (binary), @option{ihex} (Intel hex), @option{elf} (ELF file), @option{s19} (Motorola s19). @option{mem}, or @option{builder}. The relevant flash sectors will be erased prior to programming if the @option{erase} parameter is given. If @option{unlock} is provided, then the flash banks are unlocked before erase and program. The flash bank to use is inferred from the address of each image section. @quotation Warning Be careful using the @option{erase} flag when the flash is holding data you want to preserve. Portions of the flash outside those described in the image's sections might be erased with no notice. @itemize @item When a section of the image being written does not fill out all the sectors it uses, the unwritten parts of those sectors are necessarily also erased, because sectors can't be partially erased. @item Data stored in sector "holes" between image sections are also affected. For example, "@command{flash write_image erase ...}" of an image with one byte at the beginning of a flash bank and one byte at the end erases the entire bank -- not just the two sectors being written. @end itemize Also, when flash protection is important, you must re-apply it after it has been removed by the @option{unlock} flag. @end quotation @end deffn @section Other Flash commands @cindex flash protection @deffn Command {flash erase_check} num Check erase state of sectors in flash bank @var{num}, and display that status. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn Command {flash info} num Print info about flash bank @var{num} The @var{num} parameter is a value shown by @command{flash banks}. This command will first query the hardware, it does not print cached and possibly stale information. @end deffn @anchor{flashprotect} @deffn Command {flash protect} num first last (@option{on}|@option{off}) Enable (@option{on}) or disable (@option{off}) protection of flash sectors in flash bank @var{num}, starting at sector @var{first} and continuing up to and including @var{last}. Providing a @var{last} sector of @option{last} specifies "to the end of the flash bank". The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @anchor{program} @deffn Command {program} filename [verify] [reset] [offset] This is a helper script that simplifies using OpenOCD as a standalone programmer. The only required parameter is @option{filename}, the others are optional. @xref{Flash Programming}. @end deffn @anchor{flashdriverlist} @section Flash Driver List As noted above, the @command{flash bank} command requires a driver name, and allows driver-specific options and behaviors. Some drivers also activate driver-specific commands. @subsection External Flash @deffn {Flash Driver} cfi @cindex Common Flash Interface @cindex CFI The ``Common Flash Interface'' (CFI) is the main standard for external NOR flash chips, each of which connects to a specific external chip select on the CPU. Frequently the first such chip is used to boot the system. Your board's @code{reset-init} handler might need to configure additional chip selects using other commands (like: @command{mww} to configure a bus and its timings), or perhaps configure a GPIO pin that controls the ``write protect'' pin on the flash chip. The CFI driver can use a target-specific working area to significantly speed up operation. The CFI driver can accept the following optional parameters, in any order: @itemize @item @var{jedec_probe} ... is used to detect certain non-CFI flash ROMs, like AM29LV010 and similar types. @item @var{x16_as_x8} ... when a 16-bit flash is hooked up to an 8-bit bus. @end itemize To configure two adjacent banks of 16 MBytes each, both sixteen bits (two bytes) wide on a sixteen bit bus: @example flash bank $_FLASHNAME cfi 0x00000000 0x01000000 2 2 $_TARGETNAME flash bank $_FLASHNAME cfi 0x01000000 0x01000000 2 2 $_TARGETNAME @end example To configure one bank of 32 MBytes built from two sixteen bit (two byte) wide parts wired in parallel to create a thirty-two bit (four byte) bus with doubled throughput: @example flash bank $_FLASHNAME cfi 0x00000000 0x02000000 2 4 $_TARGETNAME @end example @c "cfi part_id" disabled @end deffn @deffn {Flash Driver} lpcspifi @cindex NXP SPI Flash Interface @cindex SPIFI @cindex lpcspifi NXP's LPC43xx and LPC18xx families include a proprietary SPI Flash Interface (SPIFI) peripheral that can drive and provide memory mapped access to external SPI flash devices. The lpcspifi driver initializes this interface and provides program and erase functionality for these serial flash devices. Use of this driver @b{requires} a working area of at least 1kB to be configured on the target device; more than this will significantly reduce flash programming times. The setup command only requires the @var{base} parameter. All other parameters are ignored, and the flash size and layout are configured by the driver. @example flash bank $_FLASHNAME lpcspifi 0x14000000 0 0 0 $_TARGETNAME @end example @end deffn @deffn {Flash Driver} stmsmi @cindex STMicroelectronics Serial Memory Interface @cindex SMI @cindex stmsmi Some devices form STMicroelectronics (e.g. STR75x MCU family, SPEAr MPU family) include a proprietary ``Serial Memory Interface'' (SMI) controller able to drive external SPI flash devices. Depending on specific device and board configuration, up to 4 external flash devices can be connected. SMI makes the flash content directly accessible in the CPU address space; each external device is mapped in a memory bank. CPU can directly read data, execute code and boot from SMI banks. Normal OpenOCD commands like @command{mdw} can be used to display the flash content. The setup command only requires the @var{base} parameter in order to identify the memory bank. All other parameters are ignored. Additional information, like flash size, are detected automatically. @example flash bank $_FLASHNAME stmsmi 0xf8000000 0 0 0 $_TARGETNAME @end example @end deffn @subsection Internal Flash (Microcontrollers) @deffn {Flash Driver} aduc702x The ADUC702x analog microcontrollers from Analog Devices include internal flash and use ARM7TDMI cores. The aduc702x flash driver works with models ADUC7019 through ADUC7028. The setup command only requires the @var{target} argument since all devices in this family have the same memory layout. @example flash bank $_FLASHNAME aduc702x 0 0 0 0 $_TARGETNAME @end example @end deffn @anchor{at91sam3} @deffn {Flash Driver} at91sam3 @cindex at91sam3 All members of the AT91SAM3 microcontroller family from Atmel include internal flash and use ARM's Cortex-M3 core. The driver currently (6/22/09) recognizes the AT91SAM3U[1/2/4][C/E] chips. Note that the driver was orginaly developed and tested using the AT91SAM3U4E, using a SAM3U-EK eval board. Support for other chips in the family was cribbed from the data sheet. @emph{Note to future readers/updaters: Please remove this worrysome comment after other chips are confirmed.} The AT91SAM3U4[E/C] (256K) chips have two flash banks; most other chips have one flash bank. In all cases the flash banks are at the following fixed locations: @example # Flash bank 0 - all chips flash bank $_FLASHNAME at91sam3 0x00080000 0 1 1 $_TARGETNAME # Flash bank 1 - only 256K chips flash bank $_FLASHNAME at91sam3 0x00100000 0 1 1 $_TARGETNAME @end example Internally, the AT91SAM3 flash memory is organized as follows. Unlike the AT91SAM7 chips, these are not used as parameters to the @command{flash bank} command: @itemize @item @emph{N-Banks:} 256K chips have 2 banks, others have 1 bank. @item @emph{Bank Size:} 128K/64K Per flash bank @item @emph{Sectors:} 16 or 8 per bank @item @emph{SectorSize:} 8K Per Sector @item @emph{PageSize:} 256 bytes per page. Note that OpenOCD operates on 'sector' sizes, not page sizes. @end itemize The AT91SAM3 driver adds some additional commands: @deffn Command {at91sam3 gpnvm} @deffnx Command {at91sam3 gpnvm clear} number @deffnx Command {at91sam3 gpnvm set} number @deffnx Command {at91sam3 gpnvm show} [@option{all}|number] With no parameters, @command{show} or @command{show all}, shows the status of all GPNVM bits. With @command{show} @var{number}, displays that bit. With @command{set} @var{number} or @command{clear} @var{number}, modifies that GPNVM bit. @end deffn @deffn Command {at91sam3 info} This command attempts to display information about the AT91SAM3 chip. @emph{First} it read the @code{CHIPID_CIDR} [address 0x400e0740, see Section 28.2.1, page 505 of the AT91SAM3U 29/may/2009 datasheet, document id: doc6430A] and decodes the values. @emph{Second} it reads the various clock configuration registers and attempts to display how it believes the chip is configured. By default, the SLOWCLK is assumed to be 32768 Hz, see the command @command{at91sam3 slowclk}. @end deffn @deffn Command {at91sam3 slowclk} [value] This command shows/sets the slow clock frequency used in the @command{at91sam3 info} command calculations above. @end deffn @end deffn @deffn {Flash Driver} at91sam4 @cindex at91sam4 All members of the AT91SAM4 microcontroller family from Atmel include internal flash and use ARM's Cortex-M4 core. This driver uses the same cmd names/syntax as @xref{at91sam3}. @end deffn @deffn {Flash Driver} at91sam7 All members of the AT91SAM7 microcontroller family from Atmel include internal flash and use ARM7TDMI cores. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. @example flash bank $_FLASHNAME at91sam7 0 0 0 0 $_TARGETNAME @end example For chips which are not recognized by the controller driver, you must provide additional parameters in the following order: @itemize @item @var{chip_model} ... label used with @command{flash info} @item @var{banks} @item @var{sectors_per_bank} @item @var{pages_per_sector} @item @var{pages_size} @item @var{num_nvm_bits} @item @var{freq_khz} ... required if an external clock is provided, optional (but recommended) when the oscillator frequency is known @end itemize It is recommended that you provide zeroes for all of those values except the clock frequency, so that everything except that frequency will be autoconfigured. Knowing the frequency helps ensure correct timings for flash access. The flash controller handles erases automatically on a page (128/256 byte) basis, so explicit erase commands are not necessary for flash programming. However, there is an ``EraseAll`` command that can erase an entire flash plane (of up to 256KB), and it will be used automatically when you issue @command{flash erase_sector} or @command{flash erase_address} commands. @deffn Command {at91sam7 gpnvm} bitnum (@option{set}|@option{clear}) Set or clear a ``General Purpose Non-Volatile Memory'' (GPNVM) bit for the processor. Each processor has a number of such bits, used for controlling features such as brownout detection (so they are not truly general purpose). @quotation Note This assumes that the first flash bank (number 0) is associated with the appropriate at91sam7 target. @end quotation @end deffn @end deffn @deffn {Flash Driver} avr The AVR 8-bit microcontrollers from Atmel integrate flash memory. @emph{The current implementation is incomplete.} @comment - defines mass_erase ... pointless given flash_erase_address @end deffn @deffn {Flash Driver} efm32 All members of the EFM32 microcontroller family from Energy Micro include internal flash and use ARM Cortex M3 cores. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. @example flash bank $_FLASHNAME efm32 0 0 0 0 $_TARGETNAME @end example @emph{The current implementation is incomplete. Unprotecting flash pages is not supported.} @end deffn @deffn {Flash Driver} lpc2000 Most members of the LPC1700, LPC1800, LPC2000 and LPC4300 microcontroller families from NXP include internal flash and use Cortex-M3 (LPC1700, LPC1800), Cortex-M4 (LPC4300) or ARM7TDMI (LPC2000) cores. @quotation Note There are LPC2000 devices which are not supported by the @var{lpc2000} driver: The LPC2888 is supported by the @var{lpc288x} driver. The LPC29xx family is supported by the @var{lpc2900} driver. @end quotation The @var{lpc2000} driver defines two mandatory and one optional parameters, which must appear in the following order: @itemize @item @var{variant} ... required, may be @option{lpc2000_v1} (older LPC21xx and LPC22xx) @option{lpc2000_v2} (LPC213x, LPC214x, LPC210[123], LPC23xx and LPC24xx) @option{lpc1700} (LPC175x and LPC176x) or @option{lpc4300} - available also as @option{lpc1800} alias (LPC18x[2357] and LPC43x[2357]) @item @var{clock_kHz} ... the frequency, in kiloHertz, at which the core is running @item @option{calc_checksum} ... optional (but you probably want to provide this!), telling the driver to calculate a valid checksum for the exception vector table. @quotation Note If you don't provide @option{calc_checksum} when you're writing the vector table, the boot ROM will almost certainly ignore your flash image. However, if you do provide it, with most tool chains @command{verify_image} will fail. @end quotation @end itemize LPC flashes don't require the chip and bus width to be specified. @example flash bank $_FLASHNAME lpc2000 0x0 0x7d000 0 0 $_TARGETNAME \ lpc2000_v2 14765 calc_checksum @end example @deffn {Command} {lpc2000 part_id} bank Displays the four byte part identifier associated with the specified flash @var{bank}. @end deffn @end deffn @deffn {Flash Driver} lpc288x The LPC2888 microcontroller from NXP needs slightly different flash support from its lpc2000 siblings. The @var{lpc288x} driver defines one mandatory parameter, the programming clock rate in Hz. LPC flashes don't require the chip and bus width to be specified. @example flash bank $_FLASHNAME lpc288x 0 0 0 0 $_TARGETNAME 12000000 @end example @end deffn @deffn {Flash Driver} lpc2900 This driver supports the LPC29xx ARM968E based microcontroller family from NXP. The predefined parameters @var{base}, @var{size}, @var{chip_width} and @var{bus_width} of the @code{flash bank} command are ignored. Flash size and sector layout are auto-configured by the driver. The driver has one additional mandatory parameter: The CPU clock rate (in kHz) at the time the flash operations will take place. Most of the time this will not be the crystal frequency, but a higher PLL frequency. The @code{reset-init} event handler in the board script is usually the place where you start the PLL. The driver rejects flashless devices (currently the LPC2930). The EEPROM in LPC2900 devices is not mapped directly into the address space. It must be handled much more like NAND flash memory, and will therefore be handled by a separate @code{lpc2900_eeprom} driver (not yet available). Sector protection in terms of the LPC2900 is handled transparently. Every time a sector needs to be erased or programmed, it is automatically unprotected. What is shown as protection status in the @code{flash info} command, is actually the LPC2900 @emph{sector security}. This is a mechanism to prevent a sector from ever being erased or programmed again. As this is an irreversible mechanism, it is handled by a special command (@code{lpc2900 secure_sector}), and not by the standard @code{flash protect} command. Example for a 125 MHz clock frequency: @example flash bank $_FLASHNAME lpc2900 0 0 0 0 $_TARGETNAME 125000 @end example Some @code{lpc2900}-specific commands are defined. In the following command list, the @var{bank} parameter is the bank number as obtained by the @code{flash banks} command. @deffn Command {lpc2900 signature} bank Calculates a 128-bit hash value, the @emph{signature}, from the whole flash content. This is a hardware feature of the flash block, hence the calculation is very fast. You may use this to verify the content of a programmed device against a known signature. Example: @example lpc2900 signature 0 signature: 0x5f40cdc8:0xc64e592e:0x10490f89:0x32a0f317 @end example @end deffn @deffn Command {lpc2900 read_custom} bank filename Reads the 912 bytes of customer information from the flash index sector, and saves it to a file in binary format. Example: @example lpc2900 read_custom 0 /path_to/customer_info.bin @end example @end deffn The index sector of the flash is a @emph{write-only} sector. It cannot be erased! In order to guard against unintentional write access, all following commands need to be preceeded by a successful call to the @code{password} command: @deffn Command {lpc2900 password} bank password You need to use this command right before each of the following commands: @code{lpc2900 write_custom}, @code{lpc2900 secure_sector}, @code{lpc2900 secure_jtag}. The password string is fixed to "I_know_what_I_am_doing". Example: @example lpc2900 password 0 I_know_what_I_am_doing Potentially dangerous operation allowed in next command! @end example @end deffn @deffn Command {lpc2900 write_custom} bank filename type Writes the content of the file into the customer info space of the flash index sector. The filetype can be specified with the @var{type} field. Possible values for @var{type} are: @var{bin} (binary), @var{ihex} (Intel hex format), @var{elf} (ELF binary) or @var{s19} (Motorola S-records). The file must contain a single section, and the contained data length must be exactly 912 bytes. @quotation Attention This cannot be reverted! Be careful! @end quotation Example: @example lpc2900 write_custom 0 /path_to/customer_info.bin bin @end example @end deffn @deffn Command {lpc2900 secure_sector} bank first last Secures the sector range from @var{first} to @var{last} (including) against further program and erase operations. The sector security will be effective after the next power cycle. @quotation Attention This cannot be reverted! Be careful! @end quotation Secured sectors appear as @emph{protected} in the @code{flash info} command. Example: @example lpc2900 secure_sector 0 1 1 flash info 0 #0 : lpc2900 at 0x20000000, size 0x000c0000, (...) # 0: 0x00000000 (0x2000 8kB) not protected # 1: 0x00002000 (0x2000 8kB) protected # 2: 0x00004000 (0x2000 8kB) not protected @end example @end deffn @deffn Command {lpc2900 secure_jtag} bank Irreversibly disable the JTAG port. The new JTAG security setting will be effective after the next power cycle. @quotation Attention This cannot be reverted! Be careful! @end quotation Examples: @example lpc2900 secure_jtag 0 @end example @end deffn @end deffn @deffn {Flash Driver} ocl @emph{No idea what this is, other than using some arm7/arm9 core.} @example flash bank $_FLASHNAME ocl 0 0 0 0 $_TARGETNAME @end example @end deffn @deffn {Flash Driver} pic32mx The PIC32MX microcontrollers are based on the MIPS 4K cores, and integrate flash memory. @example flash bank $_FLASHNAME pix32mx 0x1fc00000 0 0 0 $_TARGETNAME flash bank $_FLASHNAME pix32mx 0x1d000000 0 0 0 $_TARGETNAME @end example @comment numerous *disabled* commands are defined: @comment - chip_erase ... pointless given flash_erase_address @comment - lock, unlock ... pointless given protect on/off (yes?) @comment - pgm_word ... shouldn't bank be deduced from address?? Some pic32mx-specific commands are defined: @deffn Command {pic32mx pgm_word} address value bank Programs the specified 32-bit @var{value} at the given @var{address} in the specified chip @var{bank}. @end deffn @deffn Command {pic32mx unlock} bank Unlock and erase specified chip @var{bank}. This will remove any Code Protection. @end deffn @end deffn @deffn {Flash Driver} stellaris All members of the Stellaris LM3Sxxx microcontroller family from Texas Instruments include internal flash and use ARM Cortex M3 cores. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. @footnote{Currently there is a @command{stellaris mass_erase} command. That seems pointless since the same effect can be had using the standard @command{flash erase_address} command.} @example flash bank $_FLASHNAME stellaris 0 0 0 0 $_TARGETNAME @end example @deffn Command {stellaris recover bank_id} Performs the @emph{Recovering a "Locked" Device} procedure to restore the flash specified by @var{bank_id} and its associated nonvolatile registers to their factory default values (erased). This is the only way to remove flash protection or re-enable debugging if that capability has been disabled. Note that the final "power cycle the chip" step in this procedure must be performed by hand, since OpenOCD can't do it. @quotation Warning if more than one Stellaris chip is connected, the procedure is applied to all of them. @end quotation @end deffn @end deffn @deffn {Flash Driver} stm32f1x All members of the STM32F0, STM32F1 and STM32F3 microcontroller families from ST Microelectronics include internal flash and use ARM Cortex-M0/M3/M4 cores. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. @example flash bank $_FLASHNAME stm32f1x 0 0 0 0 $_TARGETNAME @end example Note that some devices have been found that have a flash size register that contains an invalid value, to workaround this issue you can override the probed value used by the flash driver. @example flash bank $_FLASHNAME stm32f1x 0 0x20000 0 0 $_TARGETNAME @end example If you have a target with dual flash banks then define the second bank as per the following example. @example flash bank $_FLASHNAME stm32f1x 0x08080000 0 0 0 $_TARGETNAME @end example Some stm32f1x-specific commands @footnote{Currently there is a @command{stm32f1x mass_erase} command. That seems pointless since the same effect can be had using the standard @command{flash erase_address} command.} are defined: @deffn Command {stm32f1x lock} num Locks the entire stm32 device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn Command {stm32f1x unlock} num Unlocks the entire stm32 device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn Command {stm32f1x options_read} num Read and display the stm32 option bytes written by the @command{stm32f1x options_write} command. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn Command {stm32f1x options_write} num (@option{SWWDG}|@option{HWWDG}) (@option{RSTSTNDBY}|@option{NORSTSTNDBY}) (@option{RSTSTOP}|@option{NORSTSTOP}) Writes the stm32 option byte with the specified values. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @end deffn @deffn {Flash Driver} stm32f2x All members of the STM32F2 and STM32F4 microcontroller families from ST Microelectronics include internal flash and use ARM Cortex-M3/M4 cores. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. Note that some devices have been found that have a flash size register that contains an invalid value, to workaround this issue you can override the probed value used by the flash driver. @example flash bank $_FLASHNAME stm32f2x 0 0x20000 0 0 $_TARGETNAME @end example Some stm32f2x-specific commands are defined: @deffn Command {stm32f2x lock} num Locks the entire stm32 device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn Command {stm32f2x unlock} num Unlocks the entire stm32 device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @end deffn @deffn {Flash Driver} stm32lx All members of the STM32L microcontroller families from ST Microelectronics include internal flash and use ARM Cortex-M3 cores. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. Note that some devices have been found that have a flash size register that contains an invalid value, to workaround this issue you can override the probed value used by the flash driver. @example flash bank $_FLASHNAME stm32lx 0 0x20000 0 0 $_TARGETNAME @end example @end deffn @deffn {Flash Driver} str7x All members of the STR7 microcontroller family from ST Microelectronics include internal flash and use ARM7TDMI cores. The @var{str7x} driver defines one mandatory parameter, @var{variant}, which is either @code{STR71x}, @code{STR73x} or @code{STR75x}. @example flash bank $_FLASHNAME str7x 0x40000000 0x00040000 0 0 $_TARGETNAME STR71x @end example @deffn Command {str7x disable_jtag} bank Activate the Debug/Readout protection mechanism for the specified flash bank. @end deffn @end deffn @deffn {Flash Driver} str9x Most members of the STR9 microcontroller family from ST Microelectronics include internal flash and use ARM966E cores. The str9 needs the flash controller to be configured using the @command{str9x flash_config} command prior to Flash programming. @example flash bank $_FLASHNAME str9x 0x40000000 0x00040000 0 0 $_TARGETNAME str9x flash_config 0 4 2 0 0x80000 @end example @deffn Command {str9x flash_config} num bbsr nbbsr bbadr nbbadr Configures the str9 flash controller. The @var{num} parameter is a value shown by @command{flash banks}. @itemize @bullet @item @var{bbsr} - Boot Bank Size register @item @var{nbbsr} - Non Boot Bank Size register @item @var{bbadr} - Boot Bank Start Address register @item @var{nbbadr} - Boot Bank Start Address register @end itemize @end deffn @end deffn @deffn {Flash Driver} tms470 Most members of the TMS470 microcontroller family from Texas Instruments include internal flash and use ARM7TDMI cores. This driver doesn't require the chip and bus width to be specified. Some tms470-specific commands are defined: @deffn Command {tms470 flash_keyset} key0 key1 key2 key3 Saves programming keys in a register, to enable flash erase and write commands. @end deffn @deffn Command {tms470 osc_mhz} clock_mhz Reports the clock speed, which is used to calculate timings. @end deffn @deffn Command {tms470 plldis} (0|1) Disables (@var{1}) or enables (@var{0}) use of the PLL to speed up the flash clock. @end deffn @end deffn @deffn {Flash Driver} virtual This is a special driver that maps a previously defined bank to another address. All bank settings will be copied from the master physical bank. The @var{virtual} driver defines one mandatory parameters, @itemize @item @var{master_bank} The bank that this virtual address refers to. @end itemize So in the following example addresses 0xbfc00000 and 0x9fc00000 refer to the flash bank defined at address 0x1fc00000. Any cmds executed on the virtual banks are actually performed on the physical banks. @example flash bank $_FLASHNAME pic32mx 0x1fc00000 0 0 0 $_TARGETNAME flash bank vbank0 virtual 0xbfc00000 0 0 0 $_TARGETNAME $_FLASHNAME flash bank vbank1 virtual 0x9fc00000 0 0 0 $_TARGETNAME $_FLASHNAME @end example @end deffn @deffn {Flash Driver} fm3 All members of the FM3 microcontroller family from Fujitsu include internal flash and use ARM Cortex M3 cores. The @var{fm3} driver uses the @var{target} parameter to select the correct bank config, it can currently be one of the following: @code{mb9bfxx1.cpu}, @code{mb9bfxx2.cpu}, @code{mb9bfxx3.cpu}, @code{mb9bfxx4.cpu}, @code{mb9bfxx5.cpu} or @code{mb9bfxx6.cpu}. @example flash bank $_FLASHNAME fm3 0 0 0 0 $_TARGETNAME @end example @end deffn @subsection str9xpec driver @cindex str9xpec Here is some background info to help you better understand how this driver works. OpenOCD has two flash drivers for the str9: @enumerate @item Standard driver @option{str9x} programmed via the str9 core. Normally used for flash programming as it is faster than the @option{str9xpec} driver. @item Direct programming @option{str9xpec} using the flash controller. This is an ISC compilant (IEEE 1532) tap connected in series with the str9 core. The str9 core does not need to be running to program using this flash driver. Typical use for this driver is locking/unlocking the target and programming the option bytes. @end enumerate Before we run any commands using the @option{str9xpec} driver we must first disable the str9 core. This example assumes the @option{str9xpec} driver has been configured for flash bank 0. @example # assert srst, we do not want core running # while accessing str9xpec flash driver jtag_reset 0 1 # turn off target polling poll off # disable str9 core str9xpec enable_turbo 0 # read option bytes str9xpec options_read 0 # re-enable str9 core str9xpec disable_turbo 0 poll on reset halt @end example The above example will read the str9 option bytes. When performing a unlock remember that you will not be able to halt the str9 - it has been locked. Halting the core is not required for the @option{str9xpec} driver as mentioned above, just issue the commands above manually or from a telnet prompt. @deffn {Flash Driver} str9xpec Only use this driver for locking/unlocking the device or configuring the option bytes. Use the standard str9 driver for programming. Before using the flash commands the turbo mode must be enabled using the @command{str9xpec enable_turbo} command. Several str9xpec-specific commands are defined: @deffn Command {str9xpec disable_turbo} num Restore the str9 into JTAG chain. @end deffn @deffn Command {str9xpec enable_turbo} num Enable turbo mode, will simply remove the str9 from the chain and talk directly to the embedded flash controller. @end deffn @deffn Command {str9xpec lock} num Lock str9 device. The str9 will only respond to an unlock command that will erase the device. @end deffn @deffn Command {str9xpec part_id} num Prints the part identifier for bank @var{num}. @end deffn @deffn Command {str9xpec options_cmap} num (@option{bank0}|@option{bank1}) Configure str9 boot bank. @end deffn @deffn Command {str9xpec options_lvdsel} num (@option{vdd}|@option{vdd_vddq}) Configure str9 lvd source. @end deffn @deffn Command {str9xpec options_lvdthd} num (@option{2.4v}|@option{2.7v}) Configure str9 lvd threshold. @end deffn @deffn Command {str9xpec options_lvdwarn} bank (@option{vdd}|@option{vdd_vddq}) Configure str9 lvd reset warning source. @end deffn @deffn Command {str9xpec options_read} num Read str9 option bytes. @end deffn @deffn Command {str9xpec options_write} num Write str9 option bytes. @end deffn @deffn Command {str9xpec unlock} num unlock str9 device. @end deffn @end deffn @section mFlash @subsection mFlash Configuration @cindex mFlash Configuration @deffn {Config Command} {mflash bank} soc base RST_pin target Configures a mflash for @var{soc} host bank at address @var{base}. The pin number format depends on the host GPIO naming convention. Currently, the mflash driver supports s3c2440 and pxa270. Example for s3c2440 mflash where @var{RST pin} is GPIO B1: @example mflash bank $_FLASHNAME s3c2440 0x10000000 1b 0 @end example Example for pxa270 mflash where @var{RST pin} is GPIO 43: @example mflash bank $_FLASHNAME pxa270 0x08000000 43 0 @end example @end deffn @subsection mFlash commands @cindex mFlash commands @deffn Command {mflash config pll} frequency Configure mflash PLL. The @var{frequency} is the mflash input frequency, in Hz. Issuing this command will erase mflash's whole internal nand and write new pll. After this command, mflash needs power-on-reset for normal operation. If pll was newly configured, storage and boot(optional) info also need to be update. @end deffn @deffn Command {mflash config boot} Configure bootable option. If bootable option is set, mflash offer the first 8 sectors (4kB) for boot. @end deffn @deffn Command {mflash config storage} Configure storage information. For the normal storage operation, this information must be written. @end deffn @deffn Command {mflash dump} num filename offset size Dump @var{size} bytes, starting at @var{offset} bytes from the beginning of the bank @var{num}, to the file named @var{filename}. @end deffn @deffn Command {mflash probe} Probe mflash. @end deffn @deffn Command {mflash write} num filename offset Write the binary file @var{filename} to mflash bank @var{num}, starting at @var{offset} bytes from the beginning of the bank. @end deffn @node Flash Programming @chapter Flash Programming OpenOCD implements numerous ways to program the target flash, whether internal or external. Programming can be acheived by either using GDB @ref{programmingusinggdb,,Programming using GDB}, or using the cmds given in @ref{flashprogrammingcommands,,Flash Programming Commands}. @*To simplify using the flash cmds directly a jimtcl script is available that handles the programming and verify stage. OpenOCD will program/verify/reset the target and shutdown. The script is executed as follows and by default the following actions will be peformed. @enumerate @item 'init' is executed. @item 'reset init' is called to reset and halt the target, any 'reset init' scripts are executed. @item @code{flash write_image} is called to erase and write any flash using the filename given. @item @code{verify_image} is called if @option{verify} parameter is given. @item @code{reset run} is called if @option{reset} parameter is given. @item OpenOCD is shutdown. @end enumerate An example of usage is given below. @xref{program}. @example # program and verify using elf/hex/s19. verify and reset # are optional parameters openocd -f board/stm32f3discovery.cfg \ -c "program filename.elf verify reset" # binary files need the flash address passing openocd -f board/stm32f3discovery.cfg \ -c "program filename.bin 0x08000000" @end example @node NAND Flash Commands @chapter NAND Flash Commands @cindex NAND Compared to NOR or SPI flash, NAND devices are inexpensive and high density. Today's NAND chips, and multi-chip modules, commonly hold multiple GigaBytes of data. NAND chips consist of a number of ``erase blocks'' of a given size (such as 128 KBytes), each of which is divided into a number of pages (of perhaps 512 or 2048 bytes each). Each page of a NAND flash has an ``out of band'' (OOB) area to hold Error Correcting Code (ECC) and other metadata, usually 16 bytes of OOB for every 512 bytes of page data. One key characteristic of NAND flash is that its error rate is higher than that of NOR flash. In normal operation, that ECC is used to correct and detect errors. However, NAND blocks can also wear out and become unusable; those blocks are then marked "bad". NAND chips are even shipped from the manufacturer with a few bad blocks. The highest density chips use a technology (MLC) that wears out more quickly, so ECC support is increasingly important as a way to detect blocks that have begun to fail, and help to preserve data integrity with techniques such as wear leveling. Software is used to manage the ECC. Some controllers don't support ECC directly; in those cases, software ECC is used. Other controllers speed up the ECC calculations with hardware. Single-bit error correction hardware is routine. Controllers geared for newer MLC chips may correct 4 or more errors for every 512 bytes of data. You will need to make sure that any data you write using OpenOCD includes the apppropriate kind of ECC. For example, that may mean passing the @code{oob_softecc} flag when writing NAND data, or ensuring that the correct hardware ECC mode is used. The basic steps for using NAND devices include: @enumerate @item Declare via the command @command{nand device} @* Do this in a board-specific configuration file, passing parameters as needed by the controller. @item Configure each device using @command{nand probe}. @* Do this only after the associated target is set up, such as in its reset-init script or in procures defined to access that device. @item Operate on the flash via @command{nand subcommand} @* Often commands to manipulate the flash are typed by a human, or run via a script in some automated way. Common task include writing a boot loader, operating system, or other data needed to initialize or de-brick a board. @end enumerate @b{NOTE:} At the time this text was written, the largest NAND flash fully supported by OpenOCD is 2 GiBytes (16 GiBits). This is because the variables used to hold offsets and lengths are only 32 bits wide. (Larger chips may work in some cases, unless an offset or length is larger than 0xffffffff, the largest 32-bit unsigned integer.) Some larger devices will work, since they are actually multi-chip modules with two smaller chips and individual chipselect lines. @anchor{nandconfiguration} @section NAND Configuration Commands @cindex NAND configuration NAND chips must be declared in configuration scripts, plus some additional configuration that's done after OpenOCD has initialized. @deffn {Config Command} {nand device} name driver target [configparams...] Declares a NAND device, which can be read and written to after it has been configured through @command{nand probe}. In OpenOCD, devices are single chips; this is unlike some operating systems, which may manage multiple chips as if they were a single (larger) device. In some cases, configuring a device will activate extra commands; see the controller-specific documentation. @b{NOTE:} This command is not available after OpenOCD initialization has completed. Use it in board specific configuration files, not interactively. @itemize @bullet @item @var{name} ... may be used to reference the NAND bank in most other NAND commands. A number is also available. @item @var{driver} ... identifies the NAND controller driver associated with the NAND device being declared. @xref{nanddriverlist,,NAND Driver List}. @item @var{target} ... names the target used when issuing commands to the NAND controller. @comment Actually, it's currently a controller-specific parameter... @item @var{configparams} ... controllers may support, or require, additional parameters. See the controller-specific documentation for more information. @end itemize @end deffn @deffn Command {nand list} Prints a summary of each device declared using @command{nand device}, numbered from zero. Note that un-probed devices show no details. @example > nand list #0: NAND 1GiB 3,3V 8-bit (Micron) pagesize: 2048, buswidth: 8, blocksize: 131072, blocks: 8192 #1: NAND 1GiB 3,3V 8-bit (Micron) pagesize: 2048, buswidth: 8, blocksize: 131072, blocks: 8192 > @end example @end deffn @deffn Command {nand probe} num Probes the specified device to determine key characteristics like its page and block sizes, and how many blocks it has. The @var{num} parameter is the value shown by @command{nand list}. You must (successfully) probe a device before you can use it with most other NAND commands. @end deffn @section Erasing, Reading, Writing to NAND Flash @deffn Command {nand dump} num filename offset length [oob_option] @cindex NAND reading Reads binary data from the NAND device and writes it to the file, starting at the specified offset. The @var{num} parameter is the value shown by @command{nand list}. Use a complete path name for @var{filename}, so you don't depend on the directory used to start the OpenOCD server. The @var{offset} and @var{length} must be exact multiples of the device's page size. They describe a data region; the OOB data associated with each such page may also be accessed. @b{NOTE:} At the time this text was written, no error correction was done on the data that's read, unless raw access was disabled and the underlying NAND controller driver had a @code{read_page} method which handled that error correction. By default, only page data is saved to the specified file. Use an @var{oob_option} parameter to save OOB data: @itemize @bullet @item no oob_* parameter @*Output file holds only page data; OOB is discarded. @item @code{oob_raw} @*Output file interleaves page data and OOB data; the file will be longer than "length" by the size of the spare areas associated with each data page. Note that this kind of "raw" access is different from what's implied by @command{nand raw_access}, which just controls whether a hardware-aware access method is used. @item @code{oob_only} @*Output file has only raw OOB data, and will be smaller than "length" since it will contain only the spare areas associated with each data page. @end itemize @end deffn @deffn Command {nand erase} num [offset length] @cindex NAND erasing @cindex NAND programming Erases blocks on the specified NAND device, starting at the specified @var{offset} and continuing for @var{length} bytes. Both of those values must be exact multiples of the device's block size, and the region they specify must fit entirely in the chip. If those parameters are not specified, the whole NAND chip will be erased. The @var{num} parameter is the value shown by @command{nand list}. @b{NOTE:} This command will try to erase bad blocks, when told to do so, which will probably invalidate the manufacturer's bad block marker. For the remainder of the current server session, @command{nand info} will still report that the block ``is'' bad. @end deffn @deffn Command {nand write} num filename offset [option...] @cindex NAND writing @cindex NAND programming Writes binary data from the file into the specified NAND device, starting at the specified offset. Those pages should already have been erased; you can't change zero bits to one bits. The @var{num} parameter is the value shown by @command{nand list}. Use a complete path name for @var{filename}, so you don't depend on the directory used to start the OpenOCD server. The @var{offset} must be an exact multiple of the device's page size. All data in the file will be written, assuming it doesn't run past the end of the device. Only full pages are written, and any extra space in the last page will be filled with 0xff bytes. (That includes OOB data, if that's being written.) @b{NOTE:} At the time this text was written, bad blocks are ignored. That is, this routine will not skip bad blocks, but will instead try to write them. This can cause problems. Provide at most one @var{option} parameter. With some NAND drivers, the meanings of these parameters may change if @command{nand raw_access} was used to disable hardware ECC. @itemize @bullet @item no oob_* parameter @*File has only page data, which is written. If raw acccess is in use, the OOB area will not be written. Otherwise, if the underlying NAND controller driver has a @code{write_page} routine, that routine may write the OOB with hardware-computed ECC data. @item @code{oob_only} @*File has only raw OOB data, which is written to the OOB area. Each page's data area stays untouched. @i{This can be a dangerous option}, since it can invalidate the ECC data. You may need to force raw access to use this mode. @item @code{oob_raw} @*File interleaves data and OOB data, both of which are written If raw access is enabled, the data is written first, then the un-altered OOB. Otherwise, if the underlying NAND controller driver has a @code{write_page} routine, that routine may modify the OOB before it's written, to include hardware-computed ECC data. @item @code{oob_softecc} @*File has only page data, which is written. The OOB area is filled with 0xff, except for a standard 1-bit software ECC code stored in conventional locations. You might need to force raw access to use this mode, to prevent the underlying driver from applying hardware ECC. @item @code{oob_softecc_kw} @*File has only page data, which is written. The OOB area is filled with 0xff, except for a 4-bit software ECC specific to the boot ROM in Marvell Kirkwood SoCs. You might need to force raw access to use this mode, to prevent the underlying driver from applying hardware ECC. @end itemize @end deffn @deffn Command {nand verify} num filename offset [option...] @cindex NAND verification @cindex NAND programming Verify the binary data in the file has been programmed to the specified NAND device, starting at the specified offset. The @var{num} parameter is the value shown by @command{nand list}. Use a complete path name for @var{filename}, so you don't depend on the directory used to start the OpenOCD server. The @var{offset} must be an exact multiple of the device's page size. All data in the file will be read and compared to the contents of the flash, assuming it doesn't run past the end of the device. As with @command{nand write}, only full pages are verified, so any extra space in the last page will be filled with 0xff bytes. The same @var{options} accepted by @command{nand write}, and the file will be processed similarly to produce the buffers that can be compared against the contents produced from @command{nand dump}. @b{NOTE:} This will not work when the underlying NAND controller driver's @code{write_page} routine must update the OOB with a hardward-computed ECC before the data is written. This limitation may be removed in a future release. @end deffn @section Other NAND commands @cindex NAND other commands @deffn Command {nand check_bad_blocks} num [offset length] Checks for manufacturer bad block markers on the specified NAND device. If no parameters are provided, checks the whole device; otherwise, starts at the specified @var{offset} and continues for @var{length} bytes. Both of those values must be exact multiples of the device's block size, and the region they specify must fit entirely in the chip. The @var{num} parameter is the value shown by @command{nand list}. @b{NOTE:} Before using this command you should force raw access with @command{nand raw_access enable} to ensure that the underlying driver will not try to apply hardware ECC. @end deffn @deffn Command {nand info} num The @var{num} parameter is the value shown by @command{nand list}. This prints the one-line summary from "nand list", plus for devices which have been probed this also prints any known status for each block. @end deffn @deffn Command {nand raw_access} num (@option{enable}|@option{disable}) Sets or clears an flag affecting how page I/O is done. The @var{num} parameter is the value shown by @command{nand list}. This flag is cleared (disabled) by default, but changing that value won't affect all NAND devices. The key factor is whether the underlying driver provides @code{read_page} or @code{write_page} methods. If it doesn't provide those methods, the setting of this flag is irrelevant; all access is effectively ``raw''. When those methods exist, they are normally used when reading data (@command{nand dump} or reading bad block markers) or writing it (@command{nand write}). However, enabling raw access (setting the flag) prevents use of those methods, bypassing hardware ECC logic. @i{This can be a dangerous option}, since writing blocks with the wrong ECC data can cause them to be marked as bad. @end deffn @anchor{nanddriverlist} @section NAND Driver List As noted above, the @command{nand device} command allows driver-specific options and behaviors. Some controllers also activate controller-specific commands. @deffn {NAND Driver} at91sam9 This driver handles the NAND controllers found on AT91SAM9 family chips from Atmel. It takes two extra parameters: address of the NAND chip; address of the ECC controller. @example nand device $NANDFLASH at91sam9 $CHIPNAME 0x40000000 0xfffffe800 @end example AT91SAM9 chips support single-bit ECC hardware. The @code{write_page} and @code{read_page} methods are used to utilize the ECC hardware unless they are disabled by using the @command{nand raw_access} command. There are four additional commands that are needed to fully configure the AT91SAM9 NAND controller. Two are optional; most boards use the same wiring for ALE/CLE: @deffn Command {at91sam9 cle} num addr_line Configure the address line used for latching commands. The @var{num} parameter is the value shown by @command{nand list}. @end deffn @deffn Command {at91sam9 ale} num addr_line Configure the address line used for latching addresses. The @var{num} parameter is the value shown by @command{nand list}. @end deffn For the next two commands, it is assumed that the pins have already been properly configured for input or output. @deffn Command {at91sam9 rdy_busy} num pio_base_addr pin Configure the RDY/nBUSY input from the NAND device. The @var{num} parameter is the value shown by @command{nand list}. @var{pio_base_addr} is the base address of the PIO controller and @var{pin} is the pin number. @end deffn @deffn Command {at91sam9 ce} num pio_base_addr pin Configure the chip enable input to the NAND device. The @var{num} parameter is the value shown by @command{nand list}. @var{pio_base_addr} is the base address of the PIO controller and @var{pin} is the pin number. @end deffn @end deffn @deffn {NAND Driver} davinci This driver handles the NAND controllers found on DaVinci family chips from Texas Instruments. It takes three extra parameters: address of the NAND chip; hardware ECC mode to use (@option{hwecc1}, @option{hwecc4}, @option{hwecc4_infix}); address of the AEMIF controller on this processor. @example nand device davinci dm355.arm 0x02000000 hwecc4 0x01e10000 @end example All DaVinci processors support the single-bit ECC hardware, and newer ones also support the four-bit ECC hardware. The @code{write_page} and @code{read_page} methods are used to implement those ECC modes, unless they are disabled using the @command{nand raw_access} command. @end deffn @deffn {NAND Driver} lpc3180 These controllers require an extra @command{nand device} parameter: the clock rate used by the controller. @deffn Command {lpc3180 select} num [mlc|slc] Configures use of the MLC or SLC controller mode. MLC implies use of hardware ECC. The @var{num} parameter is the value shown by @command{nand list}. @end deffn At this writing, this driver includes @code{write_page} and @code{read_page} methods. Using @command{nand raw_access} to disable those methods will prevent use of hardware ECC in the MLC controller mode, but won't change SLC behavior. @end deffn @comment current lpc3180 code won't issue 5-byte address cycles @deffn {NAND Driver} mx3 This driver handles the NAND controller in i.MX31. The mxc driver should work for this chip aswell. @end deffn @deffn {NAND Driver} mxc This driver handles the NAND controller found in Freescale i.MX chips. It has support for v1 (i.MX27 and i.MX31) and v2 (i.MX35). The driver takes 3 extra arguments, chip (@option{mx27}, @option{mx31}, @option{mx35}), ecc (@option{noecc}, @option{hwecc}) and optionally if bad block information should be swapped between main area and spare area (@option{biswap}), defaults to off. @example nand device mx35.nand mxc imx35.cpu mx35 hwecc biswap @end example @deffn Command {mxc biswap} bank_num [enable|disable] Turns on/off bad block information swaping from main area, without parameter query status. @end deffn @end deffn @deffn {NAND Driver} orion These controllers require an extra @command{nand device} parameter: the address of the controller. @example nand device orion 0xd8000000 @end example These controllers don't define any specialized commands. At this writing, their drivers don't include @code{write_page} or @code{read_page} methods, so @command{nand raw_access} won't change any behavior. @end deffn @deffn {NAND Driver} s3c2410 @deffnx {NAND Driver} s3c2412 @deffnx {NAND Driver} s3c2440 @deffnx {NAND Driver} s3c2443 @deffnx {NAND Driver} s3c6400 These S3C family controllers don't have any special @command{nand device} options, and don't define any specialized commands. At this writing, their drivers don't include @code{write_page} or @code{read_page} methods, so @command{nand raw_access} won't change any behavior. @end deffn @node PLD/FPGA Commands @chapter PLD/FPGA Commands @cindex PLD @cindex FPGA Programmable Logic Devices (PLDs) and the more flexible Field Programmable Gate Arrays (FPGAs) are both types of programmable hardware. OpenOCD can support programming them. Although PLDs are generally restrictive (cells are less functional, and there are no special purpose cells for memory or computational tasks), they share the same OpenOCD infrastructure. Accordingly, both are called PLDs here. @section PLD/FPGA Configuration and Commands As it does for JTAG TAPs, debug targets, and flash chips (both NOR and NAND), OpenOCD maintains a list of PLDs available for use in various commands. Also, each such PLD requires a driver. They are referenced by the number shown by the @command{pld devices} command, and new PLDs are defined by @command{pld device driver_name}. @deffn {Config Command} {pld device} driver_name tap_name [driver_options] Defines a new PLD device, supported by driver @var{driver_name}, using the TAP named @var{tap_name}. The driver may make use of any @var{driver_options} to configure its behavior. @end deffn @deffn {Command} {pld devices} Lists the PLDs and their numbers. @end deffn @deffn {Command} {pld load} num filename Loads the file @file{filename} into the PLD identified by @var{num}. The file format must be inferred by the driver. @end deffn @section PLD/FPGA Drivers, Options, and Commands Drivers may support PLD-specific options to the @command{pld device} definition command, and may also define commands usable only with that particular type of PLD. @deffn {FPGA Driver} virtex2 Virtex-II is a family of FPGAs sold by Xilinx. It supports the IEEE 1532 standard for In-System Configuration (ISC). No driver-specific PLD definition options are used, and one driver-specific command is defined. @deffn {Command} {virtex2 read_stat} num Reads and displays the Virtex-II status register (STAT) for FPGA @var{num}. @end deffn @end deffn @node General Commands @chapter General Commands @cindex commands The commands documented in this chapter here are common commands that you, as a human, may want to type and see the output of. Configuration type commands are documented elsewhere. Intent: @itemize @bullet @item @b{Source Of Commands} @* OpenOCD commands can occur in a configuration script (discussed elsewhere) or typed manually by a human or supplied programatically, or via one of several TCP/IP Ports. @item @b{From the human} @* A human should interact with the telnet interface (default port: 4444) or via GDB (default port 3333). To issue commands from within a GDB session, use the @option{monitor} command, e.g. use @option{monitor poll} to issue the @option{poll} command. All output is relayed through the GDB session. @item @b{Machine Interface} The Tcl interface's intent is to be a machine interface. The default Tcl port is 5555. @end itemize @section Daemon Commands @deffn {Command} exit Exits the current telnet session. @end deffn @deffn {Command} help [string] With no parameters, prints help text for all commands. Otherwise, prints each helptext containing @var{string}. Not every command provides helptext. Configuration commands, and commands valid at any time, are explicitly noted in parenthesis. In most cases, no such restriction is listed; this indicates commands which are only available after the configuration stage has completed. @end deffn @deffn Command sleep msec [@option{busy}] Wait for at least @var{msec} milliseconds before resuming. If @option{busy} is passed, busy-wait instead of sleeping. (This option is strongly discouraged.) Useful in connection with script files (@command{script} command and @command{target_name} configuration). @end deffn @deffn Command shutdown Close the OpenOCD daemon, disconnecting all clients (GDB, telnet, other). @end deffn @anchor{debuglevel} @deffn Command debug_level [n] @cindex message level Display debug level. If @var{n} (from 0..3) is provided, then set it to that level. This affects the kind of messages sent to the server log. Level 0 is error messages only; level 1 adds warnings; level 2 adds informational messages; and level 3 adds debugging messages. The default is level 2, but that can be overridden on the command line along with the location of that log file (which is normally the server's standard output). @xref{Running}. @end deffn @deffn Command echo [-n] message Logs a message at "user" priority. Output @var{message} to stdout. Option "-n" suppresses trailing newline. @example echo "Downloading kernel -- please wait" @end example @end deffn @deffn Command log_output [filename] Redirect logging to @var{filename}; the initial log output channel is stderr. @end deffn @deffn Command add_script_search_dir [directory] Add @var{directory} to the file/script search path. @end deffn @anchor{targetstatehandling} @section Target State handling @cindex reset @cindex halt @cindex target initialization In this section ``target'' refers to a CPU configured as shown earlier (@pxref{CPU Configuration}). These commands, like many, implicitly refer to a current target which is used to perform the various operations. The current target may be changed by using @command{targets} command with the name of the target which should become current. @deffn Command reg [(number|name) [value]] Access a single register by @var{number} or by its @var{name}. The target must generally be halted before access to CPU core registers is allowed. Depending on the hardware, some other registers may be accessible while the target is running. @emph{With no arguments}: list all available registers for the current target, showing number, name, size, value, and cache status. For valid entries, a value is shown; valid entries which are also dirty (and will be written back later) are flagged as such. @emph{With number/name}: display that register's value. @emph{With both number/name and value}: set register's value. Writes may be held in a writeback cache internal to OpenOCD, so that setting the value marks the register as dirty instead of immediately flushing that value. Resuming CPU execution (including by single stepping) or otherwise activating the relevant module will flush such values. Cores may have surprisingly many registers in their Debug and trace infrastructure: @example > reg ===== ARM registers (0) r0 (/32): 0x0000D3C2 (dirty) (1) r1 (/32): 0xFD61F31C (2) r2 (/32) ... (164) ETM_contextid_comparator_mask (/32) > @end example @end deffn @deffn Command halt [ms] @deffnx Command wait_halt [ms] The @command{halt} command first sends a halt request to the target, which @command{wait_halt} doesn't. Otherwise these behave the same: wait up to @var{ms} milliseconds, or 5 seconds if there is no parameter, for the target to halt (and enter debug mode). Using 0 as the @var{ms} parameter prevents OpenOCD from waiting. @quotation Warning On ARM cores, software using the @emph{wait for interrupt} operation often blocks the JTAG access needed by a @command{halt} command. This is because that operation also puts the core into a low power mode by gating the core clock; but the core clock is needed to detect JTAG clock transitions. One partial workaround uses adaptive clocking: when the core is interrupted the operation completes, then JTAG clocks are accepted at least until the interrupt handler completes. However, this workaround is often unusable since the processor, board, and JTAG adapter must all support adaptive JTAG clocking. Also, it can't work until an interrupt is issued. A more complete workaround is to not use that operation while you work with a JTAG debugger. Tasking environments generaly have idle loops where the body is the @emph{wait for interrupt} operation. (On older cores, it is a coprocessor action; newer cores have a @option{wfi} instruction.) Such loops can just remove that operation, at the cost of higher power consumption (because the CPU is needlessly clocked). @end quotation @end deffn @deffn Command resume [address] Resume the target at its current code position, or the optional @var{address} if it is provided. OpenOCD will wait 5 seconds for the target to resume. @end deffn @deffn Command step [address] Single-step the target at its current code position, or the optional @var{address} if it is provided. @end deffn @anchor{resetcommand} @deffn Command reset @deffnx Command {reset run} @deffnx Command {reset halt} @deffnx Command {reset init} Perform as hard a reset as possible, using SRST if possible. @emph{All defined targets will be reset, and target events will fire during the reset sequence.} The optional parameter specifies what should happen after the reset. If there is no parameter, a @command{reset run} is executed. The other options will not work on all systems. @xref{Reset Configuration}. @itemize @minus @item @b{run} Let the target run @item @b{halt} Immediately halt the target @item @b{init} Immediately halt the target, and execute the reset-init script @end itemize @end deffn @deffn Command soft_reset_halt Requesting target halt and executing a soft reset. This is often used when a target cannot be reset and halted. The target, after reset is released begins to execute code. OpenOCD attempts to stop the CPU and then sets the program counter back to the reset vector. Unfortunately the code that was executed may have left the hardware in an unknown state. @end deffn @section I/O Utilities These commands are available when OpenOCD is built with @option{--enable-ioutil}. They are mainly useful on embedded targets, notably the ZY1000. Hosts with operating systems have complementary tools. @emph{Note:} there are several more such commands. @deffn Command append_file filename [string]* Appends the @var{string} parameters to the text file @file{filename}. Each string except the last one is followed by one space. The last string is followed by a newline. @end deffn @deffn Command cat filename Reads and displays the text file @file{filename}. @end deffn @deffn Command cp src_filename dest_filename Copies contents from the file @file{src_filename} into @file{dest_filename}. @end deffn @deffn Command ip @emph{No description provided.} @end deffn @deffn Command ls @emph{No description provided.} @end deffn @deffn Command mac @emph{No description provided.} @end deffn @deffn Command meminfo Display available RAM memory on OpenOCD host. Used in OpenOCD regression testing scripts. @end deffn @deffn Command peek @emph{No description provided.} @end deffn @deffn Command poke @emph{No description provided.} @end deffn @deffn Command rm filename @c "rm" has both normal and Jim-level versions?? Unlinks the file @file{filename}. @end deffn @deffn Command trunc filename Removes all data in the file @file{filename}. @end deffn @anchor{memoryaccess} @section Memory access commands @cindex memory access These commands allow accesses of a specific size to the memory system. Often these are used to configure the current target in some special way. For example - one may need to write certain values to the SDRAM controller to enable SDRAM. @enumerate @item Use the @command{targets} (plural) command to change the current target. @item In system level scripts these commands are deprecated. Please use their TARGET object siblings to avoid making assumptions about what TAP is the current target, or about MMU configuration. @end enumerate @deffn Command mdw [phys] addr [count] @deffnx Command mdh [phys] addr [count] @deffnx Command mdb [phys] addr [count] Display contents of address @var{addr}, as 32-bit words (@command{mdw}), 16-bit halfwords (@command{mdh}), or 8-bit bytes (@command{mdb}). When the current target has an MMU which is present and active, @var{addr} is interpreted as a virtual address. Otherwise, or if the optional @var{phys} flag is specified, @var{addr} is interpreted as a physical address. If @var{count} is specified, displays that many units. (If you want to manipulate the data instead of displaying it, see the @code{mem2array} primitives.) @end deffn @deffn Command mww [phys] addr word @deffnx Command mwh [phys] addr halfword @deffnx Command mwb [phys] addr byte Writes the specified @var{word} (32 bits), @var{halfword} (16 bits), or @var{byte} (8-bit) value, at the specified address @var{addr}. When the current target has an MMU which is present and active, @var{addr} is interpreted as a virtual address. Otherwise, or if the optional @var{phys} flag is specified, @var{addr} is interpreted as a physical address. @end deffn @anchor{imageaccess} @section Image loading commands @cindex image loading @cindex image dumping @deffn Command {dump_image} filename address size Dump @var{size} bytes of target memory starting at @var{address} to the binary file named @var{filename}. @end deffn @deffn Command {fast_load} Loads an image stored in memory by @command{fast_load_image} to the current target. Must be preceeded by fast_load_image. @end deffn @deffn Command {fast_load_image} filename address [@option{bin}|@option{ihex}|@option{elf}|@option{s19}] Normally you should be using @command{load_image} or GDB load. However, for testing purposes or when I/O overhead is significant(OpenOCD running on an embedded host), storing the image in memory and uploading the image to the target can be a way to upload e.g. multiple debug sessions when the binary does not change. Arguments are the same as @command{load_image}, but the image is stored in OpenOCD host memory, i.e. does not affect target. This approach is also useful when profiling target programming performance as I/O and target programming can easily be profiled separately. @end deffn @deffn Command {load_image} filename address [[@option{bin}|@option{ihex}|@option{elf}|@option{s19}] @option{min_addr} @option{max_length}] Load image from file @var{filename} to target memory offset by @var{address} from its load address. The file format may optionally be specified (@option{bin}, @option{ihex}, @option{elf}, or @option{s19}). In addition the following arguments may be specifed: @var{min_addr} - ignore data below @var{min_addr} (this is w.r.t. to the target's load address + @var{address}) @var{max_length} - maximum number of bytes to load. @example proc load_image_bin @{fname foffset address length @} @{ # Load data from fname filename at foffset offset to # target at address. Load at most length bytes. load_image $fname [expr $address - $foffset] bin $address $length @} @end example @end deffn @deffn Command {test_image} filename [address [@option{bin}|@option{ihex}|@option{elf}]] Displays image section sizes and addresses as if @var{filename} were loaded into target memory starting at @var{address} (defaults to zero). The file format may optionally be specified (@option{bin}, @option{ihex}, or @option{elf}) @end deffn @deffn Command {verify_image} filename address [@option{bin}|@option{ihex}|@option{elf}] Verify @var{filename} against target memory starting at @var{address}. The file format may optionally be specified (@option{bin}, @option{ihex}, or @option{elf}) This will first attempt a comparison using a CRC checksum, if this fails it will try a binary compare. @end deffn @section Breakpoint and Watchpoint commands @cindex breakpoint @cindex watchpoint CPUs often make debug modules accessible through JTAG, with hardware support for a handful of code breakpoints and data watchpoints. In addition, CPUs almost always support software breakpoints. @deffn Command {bp} [address len [@option{hw}]] With no parameters, lists all active breakpoints. Else sets a breakpoint on code execution starting at @var{address} for @var{length} bytes. This is a software breakpoint, unless @option{hw} is specified in which case it will be a hardware breakpoint. (@xref{arm9vectorcatch,,arm9 vector_catch}, or @pxref{xscalevectorcatch,,xscale vector_catch}, for similar mechanisms that do not consume hardware breakpoints.) @end deffn @deffn Command {rbp} address Remove the breakpoint at @var{address}. @end deffn @deffn Command {rwp} address Remove data watchpoint on @var{address} @end deffn @deffn Command {wp} [address len [(@option{r}|@option{w}|@option{a}) [value [mask]]]] With no parameters, lists all active watchpoints. Else sets a data watchpoint on data from @var{address} for @var{length} bytes. The watch point is an "access" watchpoint unless the @option{r} or @option{w} parameter is provided, defining it as respectively a read or write watchpoint. If a @var{value} is provided, that value is used when determining if the watchpoint should trigger. The value may be first be masked using @var{mask} to mark ``don't care'' fields. @end deffn @section Misc Commands @cindex profiling @deffn Command {profile} seconds filename Profiling samples the CPU's program counter as quickly as possible, which is useful for non-intrusive stochastic profiling. Saves up to 10000 sampines in @file{filename} using ``gmon.out'' format. @end deffn @deffn Command {version} Displays a string identifying the version of this OpenOCD server. @end deffn @deffn Command {virt2phys} virtual_address Requests the current target to map the specified @var{virtual_address} to its corresponding physical address, and displays the result. @end deffn @node Architecture and Core Commands @chapter Architecture and Core Commands @cindex Architecture Specific Commands @cindex Core Specific Commands Most CPUs have specialized JTAG operations to support debugging. OpenOCD packages most such operations in its standard command framework. Some of those operations don't fit well in that framework, so they are exposed here as architecture or implementation (core) specific commands. @anchor{armhardwaretracing} @section ARM Hardware Tracing @cindex tracing @cindex ETM @cindex ETB CPUs based on ARM cores may include standard tracing interfaces, based on an ``Embedded Trace Module'' (ETM) which sends voluminous address and data bus trace records to a ``Trace Port''. @itemize @item Development-oriented boards will sometimes provide a high speed trace connector for collecting that data, when the particular CPU supports such an interface. (The standard connector is a 38-pin Mictor, with both JTAG and trace port support.) Those trace connectors are supported by higher end JTAG adapters and some logic analyzer modules; frequently those modules can buffer several megabytes of trace data. Configuring an ETM coupled to such an external trace port belongs in the board-specific configuration file. @item If the CPU doesn't provide an external interface, it probably has an ``Embedded Trace Buffer'' (ETB) on the chip, which is a dedicated SRAM. 4KBytes is one common ETB size. Configuring an ETM coupled only to an ETB belongs in the CPU-specific (target) configuration file, since it works the same on all boards. @end itemize ETM support in OpenOCD doesn't seem to be widely used yet. @quotation Issues ETM support may be buggy, and at least some @command{etm config} parameters should be detected by asking the ETM for them. ETM trigger events could also implement a kind of complex hardware breakpoint, much more powerful than the simple watchpoint hardware exported by EmbeddedICE modules. @emph{Such breakpoints can be triggered even when using the dummy trace port driver}. It seems like a GDB hookup should be possible, as well as tracing only during specific states (perhaps @emph{handling IRQ 23} or @emph{calls foo()}). There should be GUI tools to manipulate saved trace data and help analyse it in conjunction with the source code. It's unclear how much of a common interface is shared with the current XScale trace support, or should be shared with eventual Nexus-style trace module support. At this writing (November 2009) only ARM7, ARM9, and ARM11 support for ETM modules is available. The code should be able to work with some newer cores; but not all of them support this original style of JTAG access. @end quotation @subsection ETM Configuration ETM setup is coupled with the trace port driver configuration. @deffn {Config Command} {etm config} target width mode clocking driver Declares the ETM associated with @var{target}, and associates it with a given trace port @var{driver}. @xref{traceportdrivers,,Trace Port Drivers}. Several of the parameters must reflect the trace port capabilities, which are a function of silicon capabilties (exposed later using @command{etm info}) and of what hardware is connected to that port (such as an external pod, or ETB). The @var{width} must be either 4, 8, or 16, except with ETMv3.0 and newer modules which may also support 1, 2, 24, 32, 48, and 64 bit widths. (With those versions, @command{etm info} also shows whether the selected port width and mode are supported.) The @var{mode} must be @option{normal}, @option{multiplexed}, or @option{demultiplexed}. The @var{clocking} must be @option{half} or @option{full}. @quotation Warning With ETMv3.0 and newer, the bits set with the @var{mode} and @var{clocking} parameters both control the mode. This modified mode does not map to the values supported by previous ETM modules, so this syntax is subject to change. @end quotation @quotation Note You can see the ETM registers using the @command{reg} command. Not all possible registers are present in every ETM. Most of the registers are write-only, and are used to configure what CPU activities are traced. @end quotation @end deffn @deffn Command {etm info} Displays information about the current target's ETM. This includes resource counts from the @code{ETM_CONFIG} register, as well as silicon capabilities (except on rather old modules). from the @code{ETM_SYS_CONFIG} register. @end deffn @deffn Command {etm status} Displays status of the current target's ETM and trace port driver: is the ETM idle, or is it collecting data? Did trace data overflow? Was it triggered? @end deffn @deffn Command {etm tracemode} [type context_id_bits cycle_accurate branch_output] Displays what data that ETM will collect. If arguments are provided, first configures that data. When the configuration changes, tracing is stopped and any buffered trace data is invalidated. @itemize @item @var{type} ... describing how data accesses are traced, when they pass any ViewData filtering that that was set up. The value is one of @option{none} (save nothing), @option{data} (save data), @option{address} (save addresses), @option{all} (save data and addresses) @item @var{context_id_bits} ... 0, 8, 16, or 32 @item @var{cycle_accurate} ... @option{enable} or @option{disable} cycle-accurate instruction tracing. Before ETMv3, enabling this causes much extra data to be recorded. @item @var{branch_output} ... @option{enable} or @option{disable}. Disable this unless you need to try reconstructing the instruction trace stream without an image of the code. @end itemize @end deffn @deffn Command {etm trigger_debug} (@option{enable}|@option{disable}) Displays whether ETM triggering debug entry (like a breakpoint) is enabled or disabled, after optionally modifying that configuration. The default behaviour is @option{disable}. Any change takes effect after the next @command{etm start}. By using script commands to configure ETM registers, you can make the processor enter debug state automatically when certain conditions, more complex than supported by the breakpoint hardware, happen. @end deffn @subsection ETM Trace Operation After setting up the ETM, you can use it to collect data. That data can be exported to files for later analysis. It can also be parsed with OpenOCD, for basic sanity checking. To configure what is being traced, you will need to write various trace registers using @command{reg ETM_*} commands. For the definitions of these registers, read ARM publication @emph{IHI 0014, ``Embedded Trace Macrocell, Architecture Specification''}. Be aware that most of the relevant registers are write-only, and that ETM resources are limited. There are only a handful of address comparators, data comparators, counters, and so on. Examples of scenarios you might arrange to trace include: @itemize @item Code flow within a function, @emph{excluding} subroutines it calls. Use address range comparators to enable tracing for instruction access within that function's body. @item Code flow within a function, @emph{including} subroutines it calls. Use the sequencer and address comparators to activate tracing on an ``entered function'' state, then deactivate it by exiting that state when the function's exit code is invoked. @item Code flow starting at the fifth invocation of a function, combining one of the above models with a counter. @item CPU data accesses to the registers for a particular device, using address range comparators and the ViewData logic. @item Such data accesses only during IRQ handling, combining the above model with sequencer triggers which on entry and exit to the IRQ handler. @item @emph{... more} @end itemize At this writing, September 2009, there are no Tcl utility procedures to help set up any common tracing scenarios. @deffn Command {etm analyze} Reads trace data into memory, if it wasn't already present. Decodes and prints the data that was collected. @end deffn @deffn Command {etm dump} filename Stores the captured trace data in @file{filename}. @end deffn @deffn Command {etm image} filename [base_address] [type] Opens an image file. @end deffn @deffn Command {etm load} filename Loads captured trace data from @file{filename}. @end deffn @deffn Command {etm start} Starts trace data collection. @end deffn @deffn Command {etm stop} Stops trace data collection. @end deffn @anchor{traceportdrivers} @subsection Trace Port Drivers To use an ETM trace port it must be associated with a driver. @deffn {Trace Port Driver} dummy Use the @option{dummy} driver if you are configuring an ETM that's not connected to anything (on-chip ETB or off-chip trace connector). @emph{This driver lets OpenOCD talk to the ETM, but it does not expose any trace data collection.} @deffn {Config Command} {etm_dummy config} target Associates the ETM for @var{target} with a dummy driver. @end deffn @end deffn @deffn {Trace Port Driver} etb Use the @option{etb} driver if you are configuring an ETM to use on-chip ETB memory. @deffn {Config Command} {etb config} target etb_tap Associates the ETM for @var{target} with the ETB at @var{etb_tap}. You can see the ETB registers using the @command{reg} command. @end deffn @deffn Command {etb trigger_percent} [percent] This displays, or optionally changes, ETB behavior after the ETM's configured @emph{trigger} event fires. It controls how much more trace data is saved after the (single) trace trigger becomes active. @itemize @item The default corresponds to @emph{trace around} usage, recording 50 percent data before the event and the rest afterwards. @item The minimum value of @var{percent} is 2 percent, recording almost exclusively data before the trigger. Such extreme @emph{trace before} usage can help figure out what caused that event to happen. @item The maximum value of @var{percent} is 100 percent, recording data almost exclusively after the event. This extreme @emph{trace after} usage might help sort out how the event caused trouble. @end itemize @c REVISIT allow "break" too -- enter debug mode. @end deffn @end deffn @deffn {Trace Port Driver} oocd_trace This driver isn't available unless OpenOCD was explicitly configured with the @option{--enable-oocd_trace} option. You probably don't want to configure it unless you've built the appropriate prototype hardware; it's @emph{proof-of-concept} software. Use the @option{oocd_trace} driver if you are configuring an ETM that's connected to an off-chip trace connector. @deffn {Config Command} {oocd_trace config} target tty Associates the ETM for @var{target} with a trace driver which collects data through the serial port @var{tty}. @end deffn @deffn Command {oocd_trace resync} Re-synchronizes with the capture clock. @end deffn @deffn Command {oocd_trace status} Reports whether the capture clock is locked or not. @end deffn @end deffn @section Generic ARM @cindex ARM These commands should be available on all ARM processors. They are available in addition to other core-specific commands that may be available. @deffn Command {arm core_state} [@option{arm}|@option{thumb}] Displays the core_state, optionally changing it to process either @option{arm} or @option{thumb} instructions. The target may later be resumed in the currently set core_state. (Processors may also support the Jazelle state, but that is not currently supported in OpenOCD.) @end deffn @deffn Command {arm disassemble} address [count [@option{thumb}]] @cindex disassemble Disassembles @var{count} instructions starting at @var{address}. If @var{count} is not specified, a single instruction is disassembled. If @option{thumb} is specified, or the low bit of the address is set, Thumb2 (mixed 16/32-bit) instructions are used; else ARM (32-bit) instructions are used. (Processors may also support the Jazelle state, but those instructions are not currently understood by OpenOCD.) Note that all Thumb instructions are Thumb2 instructions, so older processors (without Thumb2 support) will still see correct disassembly of Thumb code. Also, ThumbEE opcodes are the same as Thumb2, with a handful of exceptions. ThumbEE disassembly currently has no explicit support. @end deffn @deffn Command {arm mcr} pX op1 CRn CRm op2 value Write @var{value} to a coprocessor @var{pX} register passing parameters @var{CRn}, @var{CRm}, opcodes @var{opc1} and @var{opc2}, and using the MCR instruction. (Parameter sequence matches the ARM instruction, but omits an ARM register.) @end deffn @deffn Command {arm mrc} pX coproc op1 CRn CRm op2 Read a coprocessor @var{pX} register passing parameters @var{CRn}, @var{CRm}, opcodes @var{opc1} and @var{opc2}, and the MRC instruction. Returns the result so it can be manipulated by Jim scripts. (Parameter sequence matches the ARM instruction, but omits an ARM register.) @end deffn @deffn Command {arm reg} Display a table of all banked core registers, fetching the current value from every core mode if necessary. @end deffn @deffn Command {arm semihosting} [@option{enable}|@option{disable}] @cindex ARM semihosting Display status of semihosting, after optionally changing that status. Semihosting allows for code executing on an ARM target to use the I/O facilities on the host computer i.e. the system where OpenOCD is running. The target application must be linked against a library implementing the ARM semihosting convention that forwards operation requests by using a special SVC instruction that is trapped at the Supervisor Call vector by OpenOCD. @end deffn @section ARMv4 and ARMv5 Architecture @cindex ARMv4 @cindex ARMv5 The ARMv4 and ARMv5 architectures are widely used in embedded systems, and introduced core parts of the instruction set in use today. That includes the Thumb instruction set, introduced in the ARMv4T variant. @subsection ARM7 and ARM9 specific commands @cindex ARM7 @cindex ARM9 These commands are specific to ARM7 and ARM9 cores, like ARM7TDMI, ARM720T, ARM9TDMI, ARM920T or ARM926EJ-S. They are available in addition to the ARM commands, and any other core-specific commands that may be available. @deffn Command {arm7_9 dbgrq} [@option{enable}|@option{disable}] Displays the value of the flag controlling use of the the EmbeddedIce DBGRQ signal to force entry into debug mode, instead of breakpoints. If a boolean parameter is provided, first assigns that flag. This should be safe for all but ARM7TDMI-S cores (like NXP LPC). This feature is enabled by default on most ARM9 cores, including ARM9TDMI, ARM920T, and ARM926EJ-S. @end deffn @deffn Command {arm7_9 dcc_downloads} [@option{enable}|@option{disable}] @cindex DCC Displays the value of the flag controlling use of the debug communications channel (DCC) to write larger (>128 byte) amounts of memory. If a boolean parameter is provided, first assigns that flag. DCC downloads offer a huge speed increase, but might be unsafe, especially with targets running at very low speeds. This command was introduced with OpenOCD rev. 60, and requires a few bytes of working area. @end deffn @deffn Command {arm7_9 fast_memory_access} [@option{enable}|@option{disable}] Displays the value of the flag controlling use of memory writes and reads that don't check completion of the operation. If a boolean parameter is provided, first assigns that flag. This provides a huge speed increase, especially with USB JTAG cables (FT2232), but might be unsafe if used with targets running at very low speeds, like the 32kHz startup clock of an AT91RM9200. @end deffn @subsection ARM720T specific commands @cindex ARM720T These commands are available to ARM720T based CPUs, which are implementations of the ARMv4T architecture based on the ARM7TDMI-S integer core. They are available in addition to the ARM and ARM7/ARM9 commands. @deffn Command {arm720t cp15} opcode [value] @emph{DEPRECATED -- avoid using this. Use the @command{arm mrc} or @command{arm mcr} commands instead.} Display cp15 register returned by the ARM instruction @var{opcode}; else if a @var{value} is provided, that value is written to that register. The @var{opcode} should be the value of either an MRC or MCR instruction. @end deffn @subsection ARM9 specific commands @cindex ARM9 ARM9-family cores are built around ARM9TDMI or ARM9E (including ARM9EJS) integer processors. Such cores include the ARM920T, ARM926EJ-S, and ARM966. @c 9-june-2009: tried this on arm920t, it didn't work. @c no-params always lists nothing caught, and that's how it acts. @c 23-oct-2009: doesn't work _consistently_ ... as if the ICE @c versions have different rules about when they commit writes. @anchor{arm9vectorcatch} @deffn Command {arm9 vector_catch} [@option{all}|@option{none}|list] @cindex vector_catch Vector Catch hardware provides a sort of dedicated breakpoint for hardware events such as reset, interrupt, and abort. You can use this to conserve normal breakpoint resources, so long as you're not concerned with code that branches directly to those hardware vectors. This always finishes by listing the current configuration. If parameters are provided, it first reconfigures the vector catch hardware to intercept @option{all} of the hardware vectors, @option{none} of them, or a list with one or more of the following: @option{reset} @option{undef} @option{swi} @option{pabt} @option{dabt} @option{irq} @option{fiq}. @end deffn @subsection ARM920T specific commands @cindex ARM920T These commands are available to ARM920T based CPUs, which are implementations of the ARMv4T architecture built using the ARM9TDMI integer core. They are available in addition to the ARM, ARM7/ARM9, and ARM9 commands. @deffn Command {arm920t cache_info} Print information about the caches found. This allows to see whether your target is an ARM920T (2x16kByte cache) or ARM922T (2x8kByte cache). @end deffn @deffn Command {arm920t cp15} regnum [value] Display cp15 register @var{regnum}; else if a @var{value} is provided, that value is written to that register. This uses "physical access" and the register number is as shown in bits 38..33 of table 9-9 in the ARM920T TRM. (Not all registers can be written.) @end deffn @deffn Command {arm920t cp15i} opcode [value [address]] @emph{DEPRECATED -- avoid using this. Use the @command{arm mrc} or @command{arm mcr} commands instead.} Interpreted access using ARM instruction @var{opcode}, which should be the value of either an MRC or MCR instruction (as shown tables 9-11, 9-12, and 9-13 in the ARM920T TRM). If no @var{value} is provided, the result is displayed. Else if that value is written using the specified @var{address}, or using zero if no other address is provided. @end deffn @deffn Command {arm920t read_cache} filename Dump the content of ICache and DCache to a file named @file{filename}. @end deffn @deffn Command {arm920t read_mmu} filename Dump the content of the ITLB and DTLB to a file named @file{filename}. @end deffn @subsection ARM926ej-s specific commands @cindex ARM926ej-s These commands are available to ARM926ej-s based CPUs, which are implementations of the ARMv5TEJ architecture based on the ARM9EJ-S integer core. They are available in addition to the ARM, ARM7/ARM9, and ARM9 commands. The Feroceon cores also support these commands, although they are not built from ARM926ej-s designs. @deffn Command {arm926ejs cache_info} Print information about the caches found. @end deffn @subsection ARM966E specific commands @cindex ARM966E These commands are available to ARM966 based CPUs, which are implementations of the ARMv5TE architecture. They are available in addition to the ARM, ARM7/ARM9, and ARM9 commands. @deffn Command {arm966e cp15} regnum [value] Display cp15 register @var{regnum}; else if a @var{value} is provided, that value is written to that register. The six bit @var{regnum} values are bits 37..32 from table 7-2 of the ARM966E-S TRM. There is no current control over bits 31..30 from that table, as required for BIST support. @end deffn @subsection XScale specific commands @cindex XScale Some notes about the debug implementation on the XScale CPUs: The XScale CPU provides a special debug-only mini-instruction cache (mini-IC) in which exception vectors and target-resident debug handler code are placed by OpenOCD. In order to get access to the CPU, OpenOCD must point vector 0 (the reset vector) to the entry of the debug handler. However, this means that the complete first cacheline in the mini-IC is marked valid, which makes the CPU fetch all exception handlers from the mini-IC, ignoring the code in RAM. To address this situation, OpenOCD provides the @code{xscale vector_table} command, which allows the user to explicity write individual entries to either the high or low vector table stored in the mini-IC. It is recommended to place a pc-relative indirect branch in the vector table, and put the branch destination somewhere in memory. Doing so makes sure the code in the vector table stays constant regardless of code layout in memory: @example _vectors: ldr pc,[pc,#0x100-8] ldr pc,[pc,#0x100-8] ldr pc,[pc,#0x100-8] ldr pc,[pc,#0x100-8] ldr pc,[pc,#0x100-8] ldr pc,[pc,#0x100-8] ldr pc,[pc,#0x100-8] ldr pc,[pc,#0x100-8] .org 0x100 .long real_reset_vector .long real_ui_handler .long real_swi_handler .long real_pf_abort .long real_data_abort .long 0 /* unused */ .long real_irq_handler .long real_fiq_handler @end example Alternatively, you may choose to keep some or all of the mini-IC vector table entries synced with those written to memory by your system software. The mini-IC can not be modified while the processor is executing, but for each vector table entry not previously defined using the @code{xscale vector_table} command, OpenOCD will copy the value from memory to the mini-IC every time execution resumes from a halt. This is done for both high and low vector tables (although the table not in use may not be mapped to valid memory, and in this case that copy operation will silently fail). This means that you will need to briefly halt execution at some strategic point during system start-up; e.g., after the software has initialized the vector table, but before exceptions are enabled. A breakpoint can be used to accomplish this once the appropriate location in the start-up code has been identified. A watchpoint over the vector table region is helpful in finding the location if you're not sure. Note that the same situation exists any time the vector table is modified by the system software. The debug handler must be placed somewhere in the address space using the @code{xscale debug_handler} command. The allowed locations for the debug handler are either (0x800 - 0x1fef800) or (0xfe000800 - 0xfffff800). The default value is 0xfe000800. XScale has resources to support two hardware breakpoints and two watchpoints. However, the following restrictions on watchpoint functionality apply: (1) the value and mask arguments to the @code{wp} command are not supported, (2) the watchpoint length must be a power of two and not less than four, and can not be greater than the watchpoint address, and (3) a watchpoint with a length greater than four consumes all the watchpoint hardware resources. This means that at any one time, you can have enabled either two watchpoints with a length of four, or one watchpoint with a length greater than four. These commands are available to XScale based CPUs, which are implementations of the ARMv5TE architecture. @deffn Command {xscale analyze_trace} Displays the contents of the trace buffer. @end deffn @deffn Command {xscale cache_clean_address} address Changes the address used when cleaning the data cache. @end deffn @deffn Command {xscale cache_info} Displays information about the CPU caches. @end deffn @deffn Command {xscale cp15} regnum [value] Display cp15 register @var{regnum}; else if a @var{value} is provided, that value is written to that register. @end deffn @deffn Command {xscale debug_handler} target address Changes the address used for the specified target's debug handler. @end deffn @deffn Command {xscale dcache} [@option{enable}|@option{disable}] Enables or disable the CPU's data cache. @end deffn @deffn Command {xscale dump_trace} filename Dumps the raw contents of the trace buffer to @file{filename}. @end deffn @deffn Command {xscale icache} [@option{enable}|@option{disable}] Enables or disable the CPU's instruction cache. @end deffn @deffn Command {xscale mmu} [@option{enable}|@option{disable}] Enables or disable the CPU's memory management unit. @end deffn @deffn Command {xscale trace_buffer} [@option{enable}|@option{disable} [@option{fill} [n] | @option{wrap}]] Displays the trace buffer status, after optionally enabling or disabling the trace buffer and modifying how it is emptied. @end deffn @deffn Command {xscale trace_image} filename [offset [type]] Opens a trace image from @file{filename}, optionally rebasing its segment addresses by @var{offset}. The image @var{type} may be one of @option{bin} (binary), @option{ihex} (Intel hex), @option{elf} (ELF file), @option{s19} (Motorola s19), @option{mem}, or @option{builder}. @end deffn @anchor{xscalevectorcatch} @deffn Command {xscale vector_catch} [mask] @cindex vector_catch Display a bitmask showing the hardware vectors to catch. If the optional parameter is provided, first set the bitmask to that value. The mask bits correspond with bit 16..23 in the DCSR: @example 0x01 Trap Reset 0x02 Trap Undefined Instructions 0x04 Trap Software Interrupt 0x08 Trap Prefetch Abort 0x10 Trap Data Abort 0x20 reserved 0x40 Trap IRQ 0x80 Trap FIQ @end example @end deffn @deffn Command {xscale vector_table} [(@option{low}|@option{high}) index value] @cindex vector_table Set an entry in the mini-IC vector table. There are two tables: one for low vectors (at 0x00000000), and one for high vectors (0xFFFF0000), each holding the 8 exception vectors. @var{index} can be 1-7, because vector 0 points to the debug handler entry and can not be overwritten. @var{value} holds the 32-bit opcode that is placed in the mini-IC. Without arguments, the current settings are displayed. @end deffn @section ARMv6 Architecture @cindex ARMv6 @subsection ARM11 specific commands @cindex ARM11 @deffn Command {arm11 memwrite burst} [@option{enable}|@option{disable}] Displays the value of the memwrite burst-enable flag, which is enabled by default. If a boolean parameter is provided, first assigns that flag. Burst writes are only used for memory writes larger than 1 word. They improve performance by assuming that the CPU has read each data word over JTAG and completed its write before the next word arrives, instead of polling for a status flag to verify that completion. This is usually safe, because JTAG runs much slower than the CPU. @end deffn @deffn Command {arm11 memwrite error_fatal} [@option{enable}|@option{disable}] Displays the value of the memwrite error_fatal flag, which is enabled by default. If a boolean parameter is provided, first assigns that flag. When set, certain memory write errors cause earlier transfer termination. @end deffn @deffn Command {arm11 step_irq_enable} [@option{enable}|@option{disable}] Displays the value of the flag controlling whether IRQs are enabled during single stepping; they are disabled by default. If a boolean parameter is provided, first assigns that. @end deffn @deffn Command {arm11 vcr} [value] @cindex vector_catch Displays the value of the @emph{Vector Catch Register (VCR)}, coprocessor 14 register 7. If @var{value} is defined, first assigns that. Vector Catch hardware provides dedicated breakpoints for certain hardware events. The specific bit values are core-specific (as in fact is using coprocessor 14 register 7 itself) but all current ARM11 cores @emph{except the ARM1176} use the same six bits. @end deffn @section ARMv7 Architecture @cindex ARMv7 @subsection ARMv7 Debug Access Port (DAP) specific commands @cindex Debug Access Port @cindex DAP These commands are specific to ARM architecture v7 Debug Access Port (DAP), included on Cortex-M and Cortex-A systems. They are available in addition to other core-specific commands that may be available. @deffn Command {dap apid} [num] Displays ID register from AP @var{num}, defaulting to the currently selected AP. @end deffn @deffn Command {dap apsel} [num] Select AP @var{num}, defaulting to 0. @end deffn @deffn Command {dap baseaddr} [num] Displays debug base address from MEM-AP @var{num}, defaulting to the currently selected AP. @end deffn @deffn Command {dap info} [num] Displays the ROM table for MEM-AP @var{num}, defaulting to the currently selected AP. @end deffn @deffn Command {dap memaccess} [value] Displays the number of extra tck cycles in the JTAG idle to use for MEM-AP memory bus access [0-255], giving additional time to respond to reads. If @var{value} is defined, first assigns that. @end deffn @deffn Command {dap apcsw} [0 / 1] fix CSW_SPROT from register AP_REG_CSW on selected dap. Defaulting to 0. @end deffn @subsection Cortex-M specific commands @cindex Cortex-M @deffn Command {cortex_m maskisr} (@option{auto}|@option{on}|@option{off}) Control masking (disabling) interrupts during target step/resume. The @option{auto} option handles interrupts during stepping a way they get served but don't disturb the program flow. The step command first allows pending interrupt handlers to execute, then disables interrupts and steps over the next instruction where the core was halted. After the step interrupts are enabled again. If the interrupt handlers don't complete within 500ms, the step command leaves with the core running. Note that a free breakpoint is required for the @option{auto} option. If no breakpoint is available at the time of the step, then the step is taken with interrupts enabled, i.e. the same way the @option{off} option does. Default is @option{auto}. @end deffn @deffn Command {cortex_m vector_catch} [@option{all}|@option{none}|list] @cindex vector_catch Vector Catch hardware provides dedicated breakpoints for certain hardware events. Parameters request interception of @option{all} of these hardware event vectors, @option{none} of them, or one or more of the following: @option{hard_err} for a HardFault exception; @option{mm_err} for a MemManage exception; @option{bus_err} for a BusFault exception; @option{irq_err}, @option{state_err}, @option{chk_err}, or @option{nocp_err} for various UsageFault exceptions; or @option{reset}. If NVIC setup code does not enable them, MemManage, BusFault, and UsageFault exceptions are mapped to HardFault. UsageFault checks for divide-by-zero and unaligned access must also be explicitly enabled. This finishes by listing the current vector catch configuration. @end deffn @deffn Command {cortex_m reset_config} (@option{srst}|@option{sysresetreq}|@option{vectreset}) Control reset handling. The default @option{srst} is to use srst if fitted, otherwise fallback to @option{vectreset}. @itemize @minus @item @option{srst} use hardware srst if fitted otherwise fallback to @option{vectreset}. @item @option{sysresetreq} use NVIC SYSRESETREQ to reset system. @item @option{vectreset} use NVIC VECTRESET to reset system. @end itemize Using @option{vectreset} is a safe option for all current Cortex-M cores. This however has the disadvantage of only resetting the core, all peripherals are uneffected. A solution would be to use a @code{reset-init} event handler to manually reset the peripherals. @xref{targetevents,,Target Events}. @end deffn @anchor{softwaredebugmessagesandtracing} @section Software Debug Messages and Tracing @cindex Linux-ARM DCC support @cindex tracing @cindex libdcc @cindex DCC OpenOCD can process certain requests from target software, when the target uses appropriate libraries. The most powerful mechanism is semihosting, but there is also a lighter weight mechanism using only the DCC channel. Currently @command{target_request debugmsgs} is supported only for @option{arm7_9} and @option{cortex_m} cores. These messages are received as part of target polling, so you need to have @command{poll on} active to receive them. They are intrusive in that they will affect program execution times. If that is a problem, @pxref{armhardwaretracing,,ARM Hardware Tracing}. See @file{libdcc} in the contrib dir for more details. In addition to sending strings, characters, and arrays of various size integers from the target, @file{libdcc} also exports a software trace point mechanism. The target being debugged may issue trace messages which include a 24-bit @dfn{trace point} number. Trace point support includes two distinct mechanisms, each supported by a command: @itemize @item @emph{History} ... A circular buffer of trace points can be set up, and then displayed at any time. This tracks where code has been, which can be invaluable in finding out how some fault was triggered. The buffer may overflow, since it collects records continuously. It may be useful to use some of the 24 bits to represent a particular event, and other bits to hold data. @item @emph{Counting} ... An array of counters can be set up, and then displayed at any time. This can help establish code coverage and identify hot spots. The array of counters is directly indexed by the trace point number, so trace points with higher numbers are not counted. @end itemize Linux-ARM kernels have a ``Kernel low-level debugging via EmbeddedICE DCC channel'' option (CONFIG_DEBUG_ICEDCC, depends on CONFIG_DEBUG_LL) which uses this mechanism to deliver messages before a serial console can be activated. This is not the same format used by @file{libdcc}. Other software, such as the U-Boot boot loader, sometimes does the same thing. @deffn Command {target_request debugmsgs} [@option{enable}|@option{disable}|@option{charmsg}] Displays current handling of target DCC message requests. These messages may be sent to the debugger while the target is running. The optional @option{enable} and @option{charmsg} parameters both enable the messages, while @option{disable} disables them. With @option{charmsg} the DCC words each contain one character, as used by Linux with CONFIG_DEBUG_ICEDCC; otherwise the libdcc format is used. @end deffn @deffn Command {trace history} [@option{clear}|count] With no parameter, displays all the trace points that have triggered in the order they triggered. With the parameter @option{clear}, erases all current trace history records. With a @var{count} parameter, allocates space for that many history records. @end deffn @deffn Command {trace point} [@option{clear}|identifier] With no parameter, displays all trace point identifiers and how many times they have been triggered. With the parameter @option{clear}, erases all current trace point counters. With a numeric @var{identifier} parameter, creates a new a trace point counter and associates it with that identifier. @emph{Important:} The identifier and the trace point number are not related except by this command. These trace point numbers always start at zero (from server startup, or after @command{trace point clear}) and count up from there. @end deffn @node JTAG Commands @chapter JTAG Commands @cindex JTAG Commands Most general purpose JTAG commands have been presented earlier. (@xref{jtagspeed,,JTAG Speed}, @ref{Reset Configuration}, and @ref{TAP Declaration}.) Lower level JTAG commands, as presented here, may be needed to work with targets which require special attention during operations such as reset or initialization. To use these commands you will need to understand some of the basics of JTAG, including: @itemize @bullet @item A JTAG scan chain consists of a sequence of individual TAP devices such as a CPUs. @item Control operations involve moving each TAP through the same standard state machine (in parallel) using their shared TMS and clock signals. @item Data transfer involves shifting data through the chain of instruction or data registers of each TAP, writing new register values while the reading previous ones. @item Data register sizes are a function of the instruction active in a given TAP, while instruction register sizes are fixed for each TAP. All TAPs support a BYPASS instruction with a single bit data register. @item The way OpenOCD differentiates between TAP devices is by shifting different instructions into (and out of) their instruction registers. @end itemize @section Low Level JTAG Commands These commands are used by developers who need to access JTAG instruction or data registers, possibly controlling the order of TAP state transitions. If you're not debugging OpenOCD internals, or bringing up a new JTAG adapter or a new type of TAP device (like a CPU or JTAG router), you probably won't need to use these commands. In a debug session that doesn't use JTAG for its transport protocol, these commands are not available. @deffn Command {drscan} tap [numbits value]+ [@option{-endstate} tap_state] Loads the data register of @var{tap} with a series of bit fields that specify the entire register. Each field is @var{numbits} bits long with a numeric @var{value} (hexadecimal encouraged). The return value holds the original value of each of those fields. For example, a 38 bit number might be specified as one field of 32 bits then one of 6 bits. @emph{For portability, never pass fields which are more than 32 bits long. Many OpenOCD implementations do not support 64-bit (or larger) integer values.} All TAPs other than @var{tap} must be in BYPASS mode. The single bit in their data registers does not matter. When @var{tap_state} is specified, the JTAG state machine is left in that state. For example @sc{drpause} might be specified, so that more instructions can be issued before re-entering the @sc{run/idle} state. If the end state is not specified, the @sc{run/idle} state is entered. @quotation Warning OpenOCD does not record information about data register lengths, so @emph{it is important that you get the bit field lengths right}. Remember that different JTAG instructions refer to different data registers, which may have different lengths. Moreover, those lengths may not be fixed; the SCAN_N instruction can change the length of the register accessed by the INTEST instruction (by connecting a different scan chain). @end quotation @end deffn @deffn Command {flush_count} Returns the number of times the JTAG queue has been flushed. This may be used for performance tuning. For example, flushing a queue over USB involves a minimum latency, often several milliseconds, which does not change with the amount of data which is written. You may be able to identify performance problems by finding tasks which waste bandwidth by flushing small transfers too often, instead of batching them into larger operations. @end deffn @deffn Command {irscan} [tap instruction]+ [@option{-endstate} tap_state] For each @var{tap} listed, loads the instruction register with its associated numeric @var{instruction}. (The number of bits in that instruction may be displayed using the @command{scan_chain} command.) For other TAPs, a BYPASS instruction is loaded. When @var{tap_state} is specified, the JTAG state machine is left in that state. For example @sc{irpause} might be specified, so the data register can be loaded before re-entering the @sc{run/idle} state. If the end state is not specified, the @sc{run/idle} state is entered. @quotation Note OpenOCD currently supports only a single field for instruction register values, unlike data register values. For TAPs where the instruction register length is more than 32 bits, portable scripts currently must issue only BYPASS instructions. @end quotation @end deffn @deffn Command {jtag_reset} trst srst Set values of reset signals. The @var{trst} and @var{srst} parameter values may be @option{0}, indicating that reset is inactive (pulled or driven high), or @option{1}, indicating it is active (pulled or driven low). The @command{reset_config} command should already have been used to configure how the board and JTAG adapter treat these two signals, and to say if either signal is even present. @xref{Reset Configuration}. Note that TRST is specially handled. It actually signifies JTAG's @sc{reset} state. So if the board doesn't support the optional TRST signal, or it doesn't support it along with the specified SRST value, JTAG reset is triggered with TMS and TCK signals instead of the TRST signal. And no matter how that JTAG reset is triggered, once the scan chain enters @sc{reset} with TRST inactive, TAP @code{post-reset} events are delivered to all TAPs with handlers for that event. @end deffn @deffn Command {pathmove} start_state [next_state ...] Start by moving to @var{start_state}, which must be one of the @emph{stable} states. Unless it is the only state given, this will often be the current state, so that no TCK transitions are needed. Then, in a series of single state transitions (conforming to the JTAG state machine) shift to each @var{next_state} in sequence, one per TCK cycle. The final state must also be stable. @end deffn @deffn Command {runtest} @var{num_cycles} Move to the @sc{run/idle} state, and execute at least @var{num_cycles} of the JTAG clock (TCK). Instructions often need some time to execute before they take effect. @end deffn @c tms_sequence (short|long) @c ... temporary, debug-only, other than USBprog bug workaround... @deffn Command {verify_ircapture} (@option{enable}|@option{disable}) Verify values captured during @sc{ircapture} and returned during IR scans. Default is enabled, but this can be overridden by @command{verify_jtag}. This flag is ignored when validating JTAG chain configuration. @end deffn @deffn Command {verify_jtag} (@option{enable}|@option{disable}) Enables verification of DR and IR scans, to help detect programming errors. For IR scans, @command{verify_ircapture} must also be enabled. Default is enabled. @end deffn @section TAP state names @cindex TAP state names The @var{tap_state} names used by OpenOCD in the @command{drscan}, @command{irscan}, and @command{pathmove} commands are the same as those used in SVF boundary scan documents, except that SVF uses @sc{idle} instead of @sc{run/idle}. @itemize @bullet @item @b{RESET} ... @emph{stable} (with TMS high); acts as if TRST were pulsed @item @b{RUN/IDLE} ... @emph{stable}; don't assume this always means IDLE @item @b{DRSELECT} @item @b{DRCAPTURE} @item @b{DRSHIFT} ... @emph{stable}; TDI/TDO shifting through the data register @item @b{DREXIT1} @item @b{DRPAUSE} ... @emph{stable}; data register ready for update or more shifting @item @b{DREXIT2} @item @b{DRUPDATE} @item @b{IRSELECT} @item @b{IRCAPTURE} @item @b{IRSHIFT} ... @emph{stable}; TDI/TDO shifting through the instruction register @item @b{IREXIT1} @item @b{IRPAUSE} ... @emph{stable}; instruction register ready for update or more shifting @item @b{IREXIT2} @item @b{IRUPDATE} @end itemize Note that only six of those states are fully ``stable'' in the face of TMS fixed (low except for @sc{reset}) and a free-running JTAG clock. For all the others, the next TCK transition changes to a new state. @itemize @bullet @item From @sc{drshift} and @sc{irshift}, clock transitions will produce side effects by changing register contents. The values to be latched in upcoming @sc{drupdate} or @sc{irupdate} states may not be as expected. @item @sc{run/idle}, @sc{drpause}, and @sc{irpause} are reasonable choices after @command{drscan} or @command{irscan} commands, since they are free of JTAG side effects. @item @sc{run/idle} may have side effects that appear at non-JTAG levels, such as advancing the ARM9E-S instruction pipeline. Consult the documentation for the TAP(s) you are working with. @end itemize @node Boundary Scan Commands @chapter Boundary Scan Commands One of the original purposes of JTAG was to support boundary scan based hardware testing. Although its primary focus is to support On-Chip Debugging, OpenOCD also includes some boundary scan commands. @section SVF: Serial Vector Format @cindex Serial Vector Format @cindex SVF The Serial Vector Format, better known as @dfn{SVF}, is a way to represent JTAG test patterns in text files. In a debug session using JTAG for its transport protocol, OpenOCD supports running such test files. @deffn Command {svf} filename [@option{quiet}] This issues a JTAG reset (Test-Logic-Reset) and then runs the SVF script from @file{filename}. Unless the @option{quiet} option is specified, each command is logged before it is executed. @end deffn @section XSVF: Xilinx Serial Vector Format @cindex Xilinx Serial Vector Format @cindex XSVF The Xilinx Serial Vector Format, better known as @dfn{XSVF}, is a binary representation of SVF which is optimized for use with Xilinx devices. In a debug session using JTAG for its transport protocol, OpenOCD supports running such test files. @quotation Important Not all XSVF commands are supported. @end quotation @deffn Command {xsvf} (tapname|@option{plain}) filename [@option{virt2}] [@option{quiet}] This issues a JTAG reset (Test-Logic-Reset) and then runs the XSVF script from @file{filename}. When a @var{tapname} is specified, the commands are directed at that TAP. When @option{virt2} is specified, the @sc{xruntest} command counts are interpreted as TCK cycles instead of microseconds. Unless the @option{quiet} option is specified, messages are logged for comments and some retries. @end deffn The OpenOCD sources also include two utility scripts for working with XSVF; they are not currently installed after building the software. You may find them useful: @itemize @item @emph{svf2xsvf} ... converts SVF files into the extended XSVF syntax understood by the @command{xsvf} command; see notes below. @item @emph{xsvfdump} ... converts XSVF files into a text output format; understands the OpenOCD extensions. @end itemize The input format accepts a handful of non-standard extensions. These include three opcodes corresponding to SVF extensions from Lattice Semiconductor (LCOUNT, LDELAY, LDSR), and two opcodes supporting a more accurate translation of SVF (XTRST, XWAITSTATE). If @emph{xsvfdump} shows a file is using those opcodes, it probably will not be usable with other XSVF tools. @node TFTP @chapter TFTP @cindex TFTP If OpenOCD runs on an embedded host(as ZY1000 does), then TFTP can be used to access files on PCs (either the developer's PC or some other PC). The way this works on the ZY1000 is to prefix a filename by "/tftp/ip/" and append the TFTP path on the TFTP server (tftpd). For example, @example load_image /tftp/10.0.0.96/c:\temp\abc.elf @end example will load c:\temp\abc.elf from the developer pc (10.0.0.96) into memory as if the file was hosted on the embedded host. In order to achieve decent performance, you must choose a TFTP server that supports a packet size bigger than the default packet size (512 bytes). There are numerous TFTP servers out there (free and commercial) and you will have to do a bit of googling to find something that fits your requirements. @node GDB and OpenOCD @chapter GDB and OpenOCD @cindex GDB OpenOCD complies with the remote gdbserver protocol, and as such can be used to debug remote targets. Setting up GDB to work with OpenOCD can involve several components: @itemize @item The OpenOCD server support for GDB may need to be configured. @xref{gdbconfiguration,,GDB Configuration}. @item GDB's support for OpenOCD may need configuration, as shown in this chapter. @item If you have a GUI environment like Eclipse, that also will probably need to be configured. @end itemize Of course, the version of GDB you use will need to be one which has been built to know about the target CPU you're using. It's probably part of the tool chain you're using. For example, if you are doing cross-development for ARM on an x86 PC, instead of using the native x86 @command{gdb} command you might use @command{arm-none-eabi-gdb} if that's the tool chain used to compile your code. @section Connecting to GDB @cindex Connecting to GDB Use GDB 6.7 or newer with OpenOCD if you run into trouble. For instance GDB 6.3 has a known bug that produces bogus memory access errors, which has since been fixed; see @url{http://osdir.com/ml/gdb.bugs.discuss/2004-12/msg00018.html} OpenOCD can communicate with GDB in two ways: @enumerate @item A socket (TCP/IP) connection is typically started as follows: @example target remote localhost:3333 @end example This would cause GDB to connect to the gdbserver on the local pc using port 3333. It is also possible to use the GDB extended remote protocol as follows: @example target extended-remote localhost:3333 @end example @item A pipe connection is typically started as follows: @example target remote | openocd -c "gdb_port pipe; log_output openocd.log" @end example This would cause GDB to run OpenOCD and communicate using pipes (stdin/stdout). Using this method has the advantage of GDB starting/stopping OpenOCD for the debug session. log_output sends the log output to a file to ensure that the pipe is not saturated when using higher debug level outputs. @end enumerate To list the available OpenOCD commands type @command{monitor help} on the GDB command line. @section Sample GDB session startup With the remote protocol, GDB sessions start a little differently than they do when you're debugging locally. Here's an examples showing how to start a debug session with a small ARM program. In this case the program was linked to be loaded into SRAM on a Cortex-M3. Most programs would be written into flash (address 0) and run from there. @example $ arm-none-eabi-gdb example.elf (gdb) target remote localhost:3333 Remote debugging using localhost:3333 ... (gdb) monitor reset halt ... (gdb) load Loading section .vectors, size 0x100 lma 0x20000000 Loading section .text, size 0x5a0 lma 0x20000100 Loading section .data, size 0x18 lma 0x200006a0 Start address 0x2000061c, load size 1720 Transfer rate: 22 KB/sec, 573 bytes/write. (gdb) continue Continuing. ... @end example You could then interrupt the GDB session to make the program break, type @command{where} to show the stack, @command{list} to show the code around the program counter, @command{step} through code, set breakpoints or watchpoints, and so on. @section Configuring GDB for OpenOCD OpenOCD supports the gdb @option{qSupported} packet, this enables information to be sent by the GDB remote server (i.e. OpenOCD) to GDB. Typical information includes packet size and the device's memory map. You do not need to configure the packet size by hand, and the relevant parts of the memory map should be automatically set up when you declare (NOR) flash banks. However, there are other things which GDB can't currently query. You may need to set those up by hand. As OpenOCD starts up, you will often see a line reporting something like: @example Info : lm3s.cpu: hardware has 6 breakpoints, 4 watchpoints @end example You can pass that information to GDB with these commands: @example set remote hardware-breakpoint-limit 6 set remote hardware-watchpoint-limit 4 @end example With that particular hardware (Cortex-M3) the hardware breakpoints only work for code running from flash memory. Most other ARM systems do not have such restrictions. Another example of useful GDB configuration came from a user who found that single stepping his Cortex-M3 didn't work well with IRQs and an RTOS until he told GDB to disable the IRQs while stepping: @example define hook-step mon cortex_m maskisr on end define hookpost-step mon cortex_m maskisr off end @end example Rather than typing such commands interactively, you may prefer to save them in a file and have GDB execute them as it starts, perhaps using a @file{.gdbinit} in your project directory or starting GDB using @command{gdb -x filename}. @section Programming using GDB @cindex Programming using GDB @anchor{programmingusinggdb} By default the target memory map is sent to GDB. This can be disabled by the following OpenOCD configuration option: @example gdb_memory_map disable @end example For this to function correctly a valid flash configuration must also be set in OpenOCD. For faster performance you should also configure a valid working area. Informing GDB of the memory map of the target will enable GDB to protect any flash areas of the target and use hardware breakpoints by default. This means that the OpenOCD option @command{gdb_breakpoint_override} is not required when using a memory map. @xref{gdbbreakpointoverride,,gdb_breakpoint_override}. To view the configured memory map in GDB, use the GDB command @option{info mem} All other unassigned addresses within GDB are treated as RAM. GDB 6.8 and higher set any memory area not in the memory map as inaccessible. This can be changed to the old behaviour by using the following GDB command @example set mem inaccessible-by-default off @end example If @command{gdb_flash_program enable} is also used, GDB will be able to program any flash memory using the vFlash interface. GDB will look at the target memory map when a load command is given, if any areas to be programmed lie within the target flash area the vFlash packets will be used. If the target needs configuring before GDB programming, an event script can be executed: @example $_TARGETNAME configure -event EVENTNAME BODY @end example To verify any flash programming the GDB command @option{compare-sections} can be used. @anchor{usingopenocdsmpwithgdb} @section Using OpenOCD SMP with GDB @cindex SMP For SMP support following GDB serial protocol packet have been defined : @itemize @bullet @item j - smp status request @item J - smp set request @end itemize OpenOCD implements : @itemize @bullet @item @option{jc} packet for reading core id displayed by GDB connection. Reply is @option{XXXXXXXX} (8 hex digits giving core id) or @option{E01} for target not smp. @item @option{JcXXXXXXXX} (8 hex digits) packet for setting core id displayed at next GDB continue (core id -1 is reserved for returning to normal resume mode). Reply @option{E01} for target not smp or @option{OK} on success. @end itemize Handling of this packet within GDB can be done : @itemize @bullet @item by the creation of an internal variable (i.e @option{_core}) by mean of function allocate_computed_value allowing following GDB command. @example set $_core 1 #Jc01 packet is sent print $_core #jc packet is sent and result is affected in $ @end example @item by the usage of GDB maintenance command as described in following example (2 cpus in SMP with core id 0 and 1 @pxref{definecputargetsworkinginsmp,,Define CPU targets working in SMP}). @example # toggle0 : force display of coreid 0 define toggle0 maint packet Jc0 continue main packet Jc-1 end # toggle1 : force display of coreid 1 define toggle1 maint packet Jc1 continue main packet Jc-1 end @end example @end itemize @node Tcl Scripting API @chapter Tcl Scripting API @cindex Tcl Scripting API @cindex Tcl scripts @section API rules The commands are stateless. E.g. the telnet command line has a concept of currently active target, the Tcl API proc's take this sort of state information as an argument to each proc. There are three main types of return values: single value, name value pair list and lists. Name value pair. The proc 'foo' below returns a name/value pair list. @verbatim > set foo(me) Duane > set foo(you) Oyvind > set foo(mouse) Micky > set foo(duck) Donald If one does this: > set foo The result is: me Duane you Oyvind mouse Micky duck Donald Thus, to get the names of the associative array is easy: foreach { name value } [set foo] { puts "Name: $name, Value: $value" } @end verbatim Lists returned must be relatively small. Otherwise a range should be passed in to the proc in question. @section Internal low-level Commands By low-level, the intent is a human would not directly use these commands. Low-level commands are (should be) prefixed with "ocd_", e.g. @command{ocd_flash_banks} is the low level API upon which @command{flash banks} is implemented. @itemize @bullet @item @b{mem2array} <@var{varname}> <@var{width}> <@var{addr}> <@var{nelems}> Read memory and return as a Tcl array for script processing @item @b{array2mem} <@var{varname}> <@var{width}> <@var{addr}> <@var{nelems}> Convert a Tcl array to memory locations and write the values @item @b{ocd_flash_banks} <@var{driver}> <@var{base}> <@var{size}> <@var{chip_width}> <@var{bus_width}> <@var{target}> [@option{driver options} ...] Return information about the flash banks @end itemize OpenOCD commands can consist of two words, e.g. "flash banks". The @file{startup.tcl} "unknown" proc will translate this into a Tcl proc called "flash_banks". @section OpenOCD specific Global Variables Real Tcl has ::tcl_platform(), and platform::identify, and many other variables. JimTCL, as implemented in OpenOCD creates $ocd_HOSTOS which holds one of the following values: @itemize @bullet @item @b{cygwin} Running under Cygwin @item @b{darwin} Darwin (Mac-OS) is the underlying operating sytem. @item @b{freebsd} Running under FreeBSD @item @b{linux} Linux is the underlying operating sytem @item @b{mingw32} Running under MingW32 @item @b{winxx} Built using Microsoft Visual Studio @item @b{other} Unknown, none of the above. @end itemize Note: 'winxx' was choosen because today (March-2009) no distinction is made between Win32 and Win64. @quotation Note We should add support for a variable like Tcl variable @code{tcl_platform(platform)}, it should be called @code{jim_platform} (because it is jim, not real tcl). @end quotation @node FAQ @chapter FAQ @cindex faq @enumerate @anchor{faqrtck} @item @b{RTCK, also known as: Adaptive Clocking - What is it?} @cindex RTCK @cindex adaptive clocking @* In digital circuit design it is often refered to as ``clock synchronisation'' the JTAG interface uses one clock (TCK or TCLK) operating at some speed, your CPU target is operating at another. The two clocks are not synchronised, they are ``asynchronous'' In order for the two to work together they must be synchronised well enough to work; JTAG can't go ten times faster than the CPU, for example. There are 2 basic options: @enumerate @item Use a special "adaptive clocking" circuit to change the JTAG clock rate to match what the CPU currently supports. @item The JTAG clock must be fixed at some speed that's enough slower than the CPU clock that all TMS and TDI transitions can be detected. @end enumerate @b{Does this really matter?} For some chips and some situations, this is a non-issue, like a 500MHz ARM926 with a 5 MHz JTAG link; the CPU has no difficulty keeping up with JTAG. Startup sequences are often problematic though, as are other situations where the CPU clock rate changes (perhaps to save power). For example, Atmel AT91SAM chips start operation from reset with a 32kHz system clock. Boot firmware may activate the main oscillator and PLL before switching to a faster clock (perhaps that 500 MHz ARM926 scenario). If you're using JTAG to debug that startup sequence, you must slow the JTAG clock to sometimes 1 to 4kHz. After startup completes, JTAG can use a faster clock. Consider also debugging a 500MHz ARM926 hand held battery powered device that enters a low power ``deep sleep'' mode, at 32kHz CPU clock, between keystrokes unless it has work to do. When would that 5 MHz JTAG clock be usable? @b{Solution #1 - A special circuit} In order to make use of this, your CPU, board, and JTAG adapter must all support the RTCK feature. Not all of them support this; keep reading! The RTCK ("Return TCK") signal in some ARM chips is used to help with this problem. ARM has a good description of the problem described at this link: @url{http://www.arm.com/support/faqdev/4170.html} [checked 28/nov/2008]. Link title: ``How does the JTAG synchronisation logic work? / how does adaptive clocking work?''. The nice thing about adaptive clocking is that ``battery powered hand held device example'' - the adaptiveness works perfectly all the time. One can set a break point or halt the system in the deep power down code, slow step out until the system speeds up. Note that adaptive clocking may also need to work at the board level, when a board-level scan chain has multiple chips. Parallel clock voting schemes are good way to implement this, both within and between chips, and can easily be implemented with a CPLD. It's not difficult to have logic fan a module's input TCK signal out to each TAP in the scan chain, and then wait until each TAP's RTCK comes back with the right polarity before changing the output RTCK signal. Texas Instruments makes some clock voting logic available for free (with no support) in VHDL form; see @url{http://tiexpressdsp.com/index.php/Adaptive_Clocking} @b{Solution #2 - Always works - but may be slower} Often this is a perfectly acceptable solution. In most simple terms: Often the JTAG clock must be 1/10 to 1/12 of the target clock speed. But what that ``magic division'' is varies depending on the chips on your board. @b{ARM rule of thumb} Most ARM based systems require an 6:1 division; ARM11 cores use an 8:1 division. @b{Xilinx rule of thumb} is 1/12 the clock speed. Note: most full speed FT2232 based JTAG adapters are limited to a maximum of 6MHz. The ones using USB high speed chips (FT2232H) often support faster clock rates (and adaptive clocking). You can still debug the 'low power' situations - you just need to either use a fixed and very slow JTAG clock rate ... or else manually adjust the clock speed at every step. (Adjusting is painful and tedious, and is not always practical.) It is however easy to ``code your way around it'' - i.e.: Cheat a little, have a special debug mode in your application that does a ``high power sleep''. If you are careful - 98% of your problems can be debugged this way. Note that on ARM you may need to avoid using the @emph{wait for interrupt} operation in your idle loops even if you don't otherwise change the CPU clock rate. That operation gates the CPU clock, and thus the JTAG clock; which prevents JTAG access. One consequence is not being able to @command{halt} cores which are executing that @emph{wait for interrupt} operation. To set the JTAG frequency use the command: @example # Example: 1.234MHz adapter_khz 1234 @end example @item @b{Win32 Pathnames} Why don't backslashes work in Windows paths? OpenOCD uses Tcl and a backslash is an escape char. Use @{ and @} around Windows filenames. @example > echo \a > echo @{\a@} \a > echo "\a" > @end example @item @b{Missing: cygwin1.dll} OpenOCD complains about a missing cygwin1.dll. Make sure you have Cygwin installed, or at least a version of OpenOCD that claims to come with all the necessary DLLs. When using Cygwin, try launching OpenOCD from the Cygwin shell. @item @b{Breakpoint Issue} I'm trying to set a breakpoint using GDB (or a frontend like Insight or Eclipse), but OpenOCD complains that "Info: arm7_9_common.c:213 arm7_9_add_breakpoint(): sw breakpoint requested, but software breakpoints not enabled". GDB issues software breakpoints when a normal breakpoint is requested, or to implement source-line single-stepping. On ARMv4T systems, like ARM7TDMI, ARM720T or ARM920T, software breakpoints consume one of the two available hardware breakpoints. @item @b{LPC2000 Flash} When erasing or writing LPC2000 on-chip flash, the operation fails at random. Make sure the core frequency specified in the @option{flash lpc2000} line matches the clock at the time you're programming the flash. If you've specified the crystal's frequency, make sure the PLL is disabled. If you've specified the full core speed (e.g. 60MHz), make sure the PLL is enabled. @item @b{Amontec Chameleon} When debugging using an Amontec Chameleon in its JTAG Accelerator configuration, I keep getting "Error: amt_jtagaccel.c:184 amt_wait_scan_busy(): amt_jtagaccel timed out while waiting for end of scan, rtck was disabled". Make sure your PC's parallel port operates in EPP mode. You might have to try several settings in your PC BIOS (ECP, EPP, and different versions of those). @item @b{Data Aborts} When debugging with OpenOCD and GDB (plain GDB, Insight, or Eclipse), I get lots of "Error: arm7_9_common.c:1771 arm7_9_read_memory(): memory read caused data abort". The errors are non-fatal, and are the result of GDB trying to trace stack frames beyond the last valid frame. It might be possible to prevent this by setting up a proper "initial" stack frame, if you happen to know what exactly has to be done, feel free to add this here. @b{Simple:} In your startup code - push 8 registers of zeros onto the stack before calling main(). What GDB is doing is ``climbing'' the run time stack by reading various values on the stack using the standard call frame for the target. GDB keeps going - until one of 2 things happen @b{#1} an invalid frame is found, or @b{#2} some huge number of stackframes have been processed. By pushing zeros on the stack, GDB gracefully stops. @b{Debugging Interrupt Service Routines} - In your ISR before you call your C code, do the same - artifically push some zeros onto the stack, remember to pop them off when the ISR is done. @b{Also note:} If you have a multi-threaded operating system, they often do not @b{in the intrest of saving memory} waste these few bytes. Painful... @item @b{JTAG Reset Config} I get the following message in the OpenOCD console (or log file): "Warning: arm7_9_common.c:679 arm7_9_assert_reset(): srst resets test logic, too". This warning doesn't indicate any serious problem, as long as you don't want to debug your core right out of reset. Your .cfg file specified @option{jtag_reset trst_and_srst srst_pulls_trst} to tell OpenOCD that either your board, your debugger or your target uC (e.g. LPC2000) can't assert the two reset signals independently. With this setup, it's not possible to halt the core right out of reset, everything else should work fine. @item @b{USB Power} When using OpenOCD in conjunction with Amontec JTAGkey and the Yagarto toolchain (Eclipse, arm-elf-gcc, arm-elf-gdb), the debugging seems to be unstable. When single-stepping over large blocks of code, GDB and OpenOCD quit with an error message. Is there a stability issue with OpenOCD? No, this is not a stability issue concerning OpenOCD. Most users have solved this issue by simply using a self-powered USB hub, which they connect their Amontec JTAGkey to. Apparently, some computers do not provide a USB power supply stable enough for the Amontec JTAGkey to be operated. @b{Laptops running on battery have this problem too...} @item @b{USB Power} When using the Amontec JTAGkey, sometimes OpenOCD crashes with the following error messages: "Error: ft2232.c:201 ft2232_read(): FT_Read returned: 4" and "Error: ft2232.c:365 ft2232_send_and_recv(): couldn't read from FT2232". What does that mean and what might be the reason for this? First of all, the reason might be the USB power supply. Try using a self-powered hub instead of a direct connection to your computer. Secondly, the error code 4 corresponds to an FT_IO_ERROR, which means that the driver for the FTDI USB chip ran into some sort of error - this points us to a USB problem. @item @b{GDB Disconnects} When using the Amontec JTAGkey, sometimes OpenOCD crashes with the following error message: "Error: gdb_server.c:101 gdb_get_char(): read: 10054". What does that mean and what might be the reason for this? Error code 10054 corresponds to WSAECONNRESET, which means that the debugger (GDB) has closed the connection to OpenOCD. This might be a GDB issue. @item @b{LPC2000 Flash} In the configuration file in the section where flash device configurations are described, there is a parameter for specifying the clock frequency for LPC2000 internal flash devices (e.g. @option{flash bank $_FLASHNAME lpc2000 0x0 0x40000 0 0 $_TARGETNAME lpc2000_v1 14746 calc_checksum}), which must be specified in kilohertz. However, I do have a quartz crystal of a frequency that contains fractions of kilohertz (e.g. 14,745,600 Hz, i.e. 14,745.600 kHz). Is it possible to specify real numbers for the clock frequency? No. The clock frequency specified here must be given as an integral number. However, this clock frequency is used by the In-Application-Programming (IAP) routines of the LPC2000 family only, which seems to be very tolerant concerning the given clock frequency, so a slight difference between the specified clock frequency and the actual clock frequency will not cause any trouble. @item @b{Command Order} Do I have to keep a specific order for the commands in the configuration file? Well, yes and no. Commands can be given in arbitrary order, yet the devices listed for the JTAG scan chain must be given in the right order (jtag newdevice), with the device closest to the TDO-Pin being listed first. In general, whenever objects of the same type exist which require an index number, then these objects must be given in the right order (jtag newtap, targets and flash banks - a target references a jtag newtap and a flash bank references a target). You can use the ``scan_chain'' command to verify and display the tap order. Also, some commands can't execute until after @command{init} has been processed. Such commands include @command{nand probe} and everything else that needs to write to controller registers, perhaps for setting up DRAM and loading it with code. @anchor{faqtaporder} @item @b{JTAG TAP Order} Do I have to declare the TAPS in some particular order? Yes; whenever you have more than one, you must declare them in the same order used by the hardware. Many newer devices have multiple JTAG TAPs. For example: ST Microsystems STM32 chips have two TAPs, a ``boundary scan TAP'' and ``Cortex-M3'' TAP. Example: The STM32 reference manual, Document ID: RM0008, Section 26.5, Figure 259, page 651/681, the ``TDI'' pin is connected to the boundary scan TAP, which then connects to the Cortex-M3 TAP, which then connects to the TDO pin. Thus, the proper order for the STM32 chip is: (1) The Cortex-M3, then (2) The boundary scan TAP. If your board includes an additional JTAG chip in the scan chain (for example a Xilinx CPLD or FPGA) you could place it before or after the STM32 chip in the chain. For example: @itemize @bullet @item OpenOCD_TDI(output) -> STM32 TDI Pin (BS Input) @item STM32 BS TDO (output) -> STM32 Cortex-M3 TDI (input) @item STM32 Cortex-M3 TDO (output) -> SM32 TDO Pin @item STM32 TDO Pin (output) -> Xilinx TDI Pin (input) @item Xilinx TDO Pin -> OpenOCD TDO (input) @end itemize The ``jtag device'' commands would thus be in the order shown below. Note: @itemize @bullet @item jtag newtap Xilinx tap -irlen ... @item jtag newtap stm32 cpu -irlen ... @item jtag newtap stm32 bs -irlen ... @item # Create the debug target and say where it is @item target create stm32.cpu -chain-position stm32.cpu ... @end itemize @item @b{SYSCOMP} Sometimes my debugging session terminates with an error. When I look into the log file, I can see these error messages: Error: arm7_9_common.c:561 arm7_9_execute_sys_speed(): timeout waiting for SYSCOMP TODO. @end enumerate @node Tcl Crash Course @chapter Tcl Crash Course @cindex Tcl Not everyone knows Tcl - this is not intended to be a replacement for learning Tcl, the intent of this chapter is to give you some idea of how the Tcl scripts work. This chapter is written with two audiences in mind. (1) OpenOCD users who need to understand a bit more of how Jim-Tcl works so they can do something useful, and (2) those that want to add a new command to OpenOCD. @section Tcl Rule #1 There is a famous joke, it goes like this: @enumerate @item Rule #1: The wife is always correct @item Rule #2: If you think otherwise, See Rule #1 @end enumerate The Tcl equal is this: @enumerate @item Rule #1: Everything is a string @item Rule #2: If you think otherwise, See Rule #1 @end enumerate As in the famous joke, the consequences of Rule #1 are profound. Once you understand Rule #1, you will understand Tcl. @section Tcl Rule #1b There is a second pair of rules. @enumerate @item Rule #1: Control flow does not exist. Only commands @* For example: the classic FOR loop or IF statement is not a control flow item, they are commands, there is no such thing as control flow in Tcl. @item Rule #2: If you think otherwise, See Rule #1 @* Actually what happens is this: There are commands that by convention, act like control flow key words in other languages. One of those commands is the word ``for'', another command is ``if''. @end enumerate @section Per Rule #1 - All Results are strings Every Tcl command results in a string. The word ``result'' is used deliberatly. No result is just an empty string. Remember: @i{Rule #1 - Everything is a string} @section Tcl Quoting Operators In life of a Tcl script, there are two important periods of time, the difference is subtle. @enumerate @item Parse Time @item Evaluation Time @end enumerate The two key items here are how ``quoted things'' work in Tcl. Tcl has three primary quoting constructs, the [square-brackets] the @{curly-braces@} and ``double-quotes'' By now you should know $VARIABLES always start with a $DOLLAR sign. BTW: To set a variable, you actually use the command ``set'', as in ``set VARNAME VALUE'' much like the ancient BASIC langauge ``let x = 1'' statement, but without the equal sign. @itemize @bullet @item @b{[square-brackets]} @* @b{[square-brackets]} are command substitutions. It operates much like Unix Shell `back-ticks`. The result of a [square-bracket] operation is exactly 1 string. @i{Remember Rule #1 - Everything is a string}. These two statements are roughly identical: @example # bash example X=`date` echo "The Date is: $X" # Tcl example set X [date] puts "The Date is: $X" @end example @item @b{``double-quoted-things''} @* @b{``double-quoted-things''} are just simply quoted text. $VARIABLES and [square-brackets] are expanded in place - the result however is exactly 1 string. @i{Remember Rule #1 - Everything is a string} @example set x "Dinner" puts "It is now \"[date]\", $x is in 1 hour" @end example @item @b{@{Curly-Braces@}} @*@b{@{Curly-Braces@}} are magic: $VARIABLES and [square-brackets] are parsed, but are NOT expanded or executed. @{Curly-Braces@} are like 'single-quote' operators in BASH shell scripts, with the added feature: @{curly-braces@} can be nested, single quotes can not. @{@{@{this is nested 3 times@}@}@} NOTE: [date] is a bad example; at this writing, Jim/OpenOCD does not have a date command. @end itemize @section Consequences of Rule 1/2/3/4 The consequences of Rule 1 are profound. @subsection Tokenisation & Execution. Of course, whitespace, blank lines and #comment lines are handled in the normal way. As a script is parsed, each (multi) line in the script file is tokenised and according to the quoting rules. After tokenisation, that line is immedatly executed. Multi line statements end with one or more ``still-open'' @{curly-braces@} which - eventually - closes a few lines later. @subsection Command Execution Remember earlier: There are no ``control flow'' statements in Tcl. Instead there are COMMANDS that simply act like control flow operators. Commands are executed like this: @enumerate @item Parse the next line into (argc) and (argv[]). @item Look up (argv[0]) in a table and call its function. @item Repeat until End Of File. @end enumerate It sort of works like this: @example for(;;)@{ ReadAndParse( &argc, &argv ); cmdPtr = LookupCommand( argv[0] ); (*cmdPtr->Execute)( argc, argv ); @} @end example When the command ``proc'' is parsed (which creates a procedure function) it gets 3 parameters on the command line. @b{1} the name of the proc (function), @b{2} the list of parameters, and @b{3} the body of the function. Not the choice of words: LIST and BODY. The PROC command stores these items in a table somewhere so it can be found by ``LookupCommand()'' @subsection The FOR command The most interesting command to look at is the FOR command. In Tcl, the FOR command is normally implemented in C. Remember, FOR is a command just like any other command. When the ascii text containing the FOR command is parsed, the parser produces 5 parameter strings, @i{(If in doubt: Refer to Rule #1)} they are: @enumerate 0 @item The ascii text 'for' @item The start text @item The test expression @item The next text @item The body text @end enumerate Sort of reminds you of ``main( int argc, char **argv )'' does it not? Remember @i{Rule #1 - Everything is a string.} The key point is this: Often many of those parameters are in @{curly-braces@} - thus the variables inside are not expanded or replaced until later. Remember that every Tcl command looks like the classic ``main( argc, argv )'' function in C. In JimTCL - they actually look like this: @example int MyCommand( Jim_Interp *interp, int *argc, Jim_Obj * const *argvs ); @end example Real Tcl is nearly identical. Although the newer versions have introduced a byte-code parser and intepreter, but at the core, it still operates in the same basic way. @subsection FOR command implementation To understand Tcl it is perhaps most helpful to see the FOR command. Remember, it is a COMMAND not a control flow structure. In Tcl there are two underlying C helper functions. Remember Rule #1 - You are a string. The @b{first} helper parses and executes commands found in an ascii string. Commands can be seperated by semicolons, or newlines. While parsing, variables are expanded via the quoting rules. The @b{second} helper evaluates an ascii string as a numerical expression and returns a value. Here is an example of how the @b{FOR} command could be implemented. The pseudo code below does not show error handling. @example void Execute_AsciiString( void *interp, const char *string ); int Evaluate_AsciiExpression( void *interp, const char *string ); int MyForCommand( void *interp, int argc, char **argv ) @{ if( argc != 5 )@{ SetResult( interp, "WRONG number of parameters"); return ERROR; @} // argv[0] = the ascii string just like C // Execute the start statement. Execute_AsciiString( interp, argv[1] ); // Top of loop test for(;;)@{ i = Evaluate_AsciiExpression(interp, argv[2]); if( i == 0 ) break; // Execute the body Execute_AsciiString( interp, argv[3] ); // Execute the LOOP part Execute_AsciiString( interp, argv[4] ); @} // Return no error SetResult( interp, "" ); return SUCCESS; @} @end example Every other command IF, WHILE, FORMAT, PUTS, EXPR, everything works in the same basic way. @section OpenOCD Tcl Usage @subsection source and find commands @b{Where:} In many configuration files @* Example: @b{ source [find FILENAME] } @*Remember the parsing rules @enumerate @item The @command{find} command is in square brackets, and is executed with the parameter FILENAME. It should find and return the full path to a file with that name; it uses an internal search path. The RESULT is a string, which is substituted into the command line in place of the bracketed @command{find} command. (Don't try to use a FILENAME which includes the "#" character. That character begins Tcl comments.) @item The @command{source} command is executed with the resulting filename; it reads a file and executes as a script. @end enumerate @subsection format command @b{Where:} Generally occurs in numerous places. @* Tcl has no command like @b{printf()}, instead it has @b{format}, which is really more like @b{sprintf()}. @b{Example} @example set x 6 set y 7 puts [format "The answer: %d" [expr $x * $y]] @end example @enumerate @item The SET command creates 2 variables, X and Y. @item The double [nested] EXPR command performs math @* The EXPR command produces numerical result as a string. @* Refer to Rule #1 @item The format command is executed, producing a single string @* Refer to Rule #1. @item The PUTS command outputs the text. @end enumerate @subsection Body or Inlined Text @b{Where:} Various TARGET scripts. @example #1 Good proc someproc @{@} @{ ... multiple lines of stuff ... @} $_TARGETNAME configure -event FOO someproc #2 Good - no variables $_TARGETNAME confgure -event foo "this ; that;" #3 Good Curly Braces $_TARGETNAME configure -event FOO @{ puts "Time: [date]" @} #4 DANGER DANGER DANGER $_TARGETNAME configure -event foo "puts \"Time: [date]\"" @end example @enumerate @item The $_TARGETNAME is an OpenOCD variable convention. @*@b{$_TARGETNAME} represents the last target created, the value changes each time a new target is created. Remember the parsing rules. When the ascii text is parsed, the @b{$_TARGETNAME} becomes a simple string, the name of the target which happens to be a TARGET (object) command. @item The 2nd parameter to the @option{-event} parameter is a TCBODY @*There are 4 examples: @enumerate @item The TCLBODY is a simple string that happens to be a proc name @item The TCLBODY is several simple commands seperated by semicolons @item The TCLBODY is a multi-line @{curly-brace@} quoted string @item The TCLBODY is a string with variables that get expanded. @end enumerate In the end, when the target event FOO occurs the TCLBODY is evaluated. Method @b{#1} and @b{#2} are functionally identical. For Method @b{#3} and @b{#4} it is more interesting. What is the TCLBODY? Remember the parsing rules. In case #3, @{curly-braces@} mean the $VARS and [square-brackets] are expanded later, when the EVENT occurs, and the text is evaluated. In case #4, they are replaced before the ``Target Object Command'' is executed. This occurs at the same time $_TARGETNAME is replaced. In case #4 the date will never change. @{BTW: [date] is a bad example; at this writing, Jim/OpenOCD does not have a date command@} @end enumerate @subsection Global Variables @b{Where:} You might discover this when writing your own procs @* In simple terms: Inside a PROC, if you need to access a global variable you must say so. See also ``upvar''. Example: @example proc myproc @{ @} @{ set y 0 #Local variable Y global x #Global variable X puts [format "X=%d, Y=%d" $x $y] @} @end example @section Other Tcl Hacks @b{Dynamic variable creation} @example # Dynamically create a bunch of variables. for @{ set x 0 @} @{ $x < 32 @} @{ set x [expr $x + 1]@} @{ # Create var name set vn [format "BIT%d" $x] # Make it a global global $vn # Set it. set $vn [expr (1 << $x)] @} @end example @b{Dynamic proc/command creation} @example # One "X" function - 5 uart functions. foreach who @{A B C D E@} proc [format "show_uart%c" $who] @{ @} "show_UARTx $who" @} @end example @include fdl.texi @node OpenOCD Concept Index @comment DO NOT use the plain word ``Index'', reason: CYGWIN filename @comment case issue with ``Index.html'' and ``index.html'' @comment Occurs when creating ``--html --no-split'' output @comment This fix is based on: http://sourceware.org/ml/binutils/2006-05/msg00215.html @unnumbered OpenOCD Concept Index @printindex cp @node Command and Driver Index @unnumbered Command and Driver Index @printindex fn @bye openocd-0.7.0/doc/openocd.10000644000175000001440000000624512137151330012343 00000000000000.TH "OPENOCD" "1" "November 24, 2009" .SH "NAME" openocd \- A free and open on\-chip debugging, in\-system programming and boundary\-scan testing tool for ARM and MIPS systems .SH "SYNOPSIS" .B openocd \fR[\fB\-fsdlcphv\fR] [\fB\-\-file\fR ] [\fB\-\-search\fR ] [\fB\-\-debug\fR ] [\fB\-\-log_output\fR ] [\fB\-\-command\fR ] [\fB\-\-pipe\fR] [\fB\-\-help\fR] [\fB\-\-version\fR] .SH "DESCRIPTION" .B OpenOCD is an on\-chip debugging, in\-system programming and boundary\-scan testing tool for various ARM and MIPS systems. .PP The debugger uses an IEEE 1149\-1 compliant JTAG TAP bus master to access on\-chip debug functionality available on ARM based microcontrollers or system-on-chip solutions. For MIPS systems the EJTAG interface is supported. .PP User interaction is realized through a telnet command line interface, a gdb (the GNU debugger) remote protocol server, and a simplified RPC connection that can be used to interface with OpenOCD's Jim Tcl engine. .PP OpenOCD supports various different types of JTAG interfaces/programmers, please check the \fIopenocd\fR info page for the complete list. .SH "OPTIONS" .TP .B "\-f, \-\-file " This is a shortcut for a \fB\-c "[script \fI\fB]"\fR command, using a search path to load the configuration file .IR . In order to specify multiple config files, you can use multiple .B \-\-file arguments. If no such \fB\-c\fR options are included, the first config file .B openocd.cfg in the search path will be used. .TP .B "\-s, \-\-search " Add .I to the search path used for config files and scripts. The search path begins with the current directory, then includes these additional directories before other components such as the standard OpenOCD script libraries. .TP .B "\-d, \-\-debug " Set debug level. Possible values are: .br .RB " * " 0 " (errors)" .br .RB " * " 1 " (warnings)" .br .RB " * " 2 " (informational messages)" .br .RB " * " 3 " (debug messages)" .br The default level is .BR 2 . .TP .B "\-l, \-\-log_output " Redirect log output to the file .IR . Per default the log output is printed on .BR stderr . .TP .B "\-c, \-\-command " Add the command .I to a list of commands executed on server startup. Note that you will need to explicitly invoke .I init if the command requires access to a target or flash. .TP .B "\-p, \-\-pipe" Use pipes when talking to gdb. .TP .B "\-h, \-\-help" Show a help text and exit. .TP .B "\-v, \-\-version" Show version information and exit. .SH "BUGS" Please report any bugs on the mailing list at .BR openocd\-devel@lists.sourceforge.net . .SH "LICENCE" .B OpenOCD is covered by the GNU General Public License (GPL), version 2 or later. .SH "SEE ALSO" .BR jtag (1) .PP The full documentation for .B openocd is maintained as a Texinfo manual. If the .BR info (or .BR pinfo ) and .BR openocd programs are properly installed at your site, the command .B info openocd should give you access to the complete manual. .SH "AUTHORS" Please see the file AUTHORS. .PP This manual page was written by Uwe Hermann . It is licensed under the terms of the GNU GPL (version 2 or later). openocd-0.7.0/doc/INSTALL.txt0000644000175000001440000002030112134336410012467 00000000000000TODO!!! this should be merged into openocd.texi!!! Prerequisites ============= When building with support for FTDI FT2232 based devices, you need at least one of the following libraries: - libftdi (http://www.intra2net.com/opensource/ftdi/) - libftd2xx (http://www.ftdichip.com/Drivers/D2XX.htm) On Windows, you need either Cygwin or MinGW, but compilation for MinGW is also possible using a Cygwin host. Basic Installation ================== OpenOCD is distributed without autotools generated files, i.e. without a configure script. Run ./bootstrap in the openocd directory to have all necessary files generated. You have to explicitly enable desired JTAG interfaces during configure: ./configure --enable-parport --enable-ft2232-libftdi (OR --enable-ft2232-ftd2xx) \ --enable-amtjtagaccel Under Windows/Cygwin, only the ftd2xx driver is supported for FT2232 based devices. You have to specify the location of the FTDI driver package with the --with-ftd2xx=/full/path/name option. Under Linux you can choose to build the parport driver with support for /dev/parportN instead of the default access with direct port I/O using --enable-parport_ppdev. This has the advantage of running OpenOCD without root privileges at the expense of a slight performance decrease. This is also available on FreeBSD using PPI, but the naming of the devices is different. Generic installation instructions ================================= These are generic installation instructions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, a file `config.cache' that saves the results of its tests to speed up reconfiguring, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.in' is used to create `configure' by a program called `autoconf'. You only need `configure.in' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself. Running `configure' takes a while. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Type `make install' to install the programs and any data files and documentation. 4. You can remove the program binaries and object files from the source code directory by typing `make clean'. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. You can give `configure' initial values for variables by setting them in the environment. Using a Bourne-compatible shell, you can do that on the command line like this: CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure Or on systems that have the `env' program, you can do it like this: env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If you have to use a `make' that does not supports the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' will install the package's files in `/usr/local/bin', `/usr/local/man', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PATH'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you give `configure' the option `--exec-prefix=PATH', the package will use PATH as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Specifying the System Type ========================== There may be some features `configure' can not figure out automatically, but needs to determine by the type of host the package will run on. Usually `configure' can figure that out, but if it prints a message saying it can not guess the host type, give it the `--host=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name with three fields: CPU-COMPANY-SYSTEM See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the host type. If you are building compiler tools for cross-compiling, you can also use the `--target=TYPE' option to select the type of system they will produce code for and the `--build=TYPE' option to select the type of system on which you are compiling the package. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Operation Controls ================== `configure' recognizes the following options to control how it operates. `--cache-file=FILE' Use and save the results of the tests in FILE instead of `./config.cache'. Set FILE to `/dev/null' to disable caching, for debugging `configure'. `--help' Print a summary of the options to `configure', and exit. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `--version' Print the version of Autoconf used to generate the `configure' script, and exit. `configure' also accepts some other, not widely useful, options. openocd-0.7.0/doc/Makefile.am0000644000175000001440000000075712134336410012671 00000000000000info_TEXINFOS = openocd.texi openocd_TEXINFOS = fdl.texi man_MANS = openocd.1 EXTRA_DIST = openocd.1 \ INSTALL.txt dist-hook: mkdir $(distdir)/manual cp -p $(srcdir)/manual/*.txt $(distdir)/manual for i in $$(cd $(srcdir)/manual/ && ls -d */); do \ mkdir $(distdir)/manual/$$i; \ cp -p $(srcdir)/manual/$$i/* $(distdir)/manual/$$i/; \ done MAINTAINERCLEANFILES = \ $(srcdir)/Makefile.in \ $(srcdir)/mdate-sh \ $(srcdir)/stamp-vti \ $(srcdir)/version.texi \ $(srcdir)/texinfo.tex openocd-0.7.0/src/0000755000175000001440000000000012141414413010724 500000000000000openocd-0.7.0/src/flash/0000755000175000001440000000000012141414412012020 500000000000000openocd-0.7.0/src/flash/common.h0000644000175000001440000000500512134336410013404 00000000000000/*************************************************************************** * Copyright (C) 2009 by Zachary T Welch * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef FLASH_COMMON_H #define FLASH_COMMON_H #include /** * Parses the optional '.index' portion of a flash bank identifier. * @param name The desired driver name, passed by the user. * @returns The parsed index request, or 0 if not present. If the * name provides a suffix but it does not parse as an unsigned integer, * the routine returns ~0U. This will prevent further matching. */ unsigned get_flash_name_index(const char *name); /** * Attempt to match the @c expected name with the @c name of a driver. * @param name The name of the driver (from the bank's device structure). * @param expected The expected driver name, passed by the user. */ bool flash_driver_name_matches(const char *name, const char *expected); #define ERROR_FLASH_BANK_INVALID (-900) #define ERROR_FLASH_SECTOR_INVALID (-901) #define ERROR_FLASH_OPERATION_FAILED (-902) #define ERROR_FLASH_DST_OUT_OF_BANK (-903) #define ERROR_FLASH_DST_BREAKS_ALIGNMENT (-904) #define ERROR_FLASH_BUSY (-905) #define ERROR_FLASH_SECTOR_NOT_ERASED (-906) #define ERROR_FLASH_BANK_NOT_PROBED (-907) #define ERROR_FLASH_OPER_UNSUPPORTED (-908) #endif /* FLASH_COMMON_H */ openocd-0.7.0/src/flash/Makefile.in0000644000175000001440000005224612141414275014025 00000000000000# Makefile.in generated by automake 1.13.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ DIST_COMMON = $(top_srcdir)/common.mk $(srcdir)/Makefile.in \ $(srcdir)/Makefile.am $(top_srcdir)/depcomp $(noinst_HEADERS) @INTERNAL_JIMTCL_TRUE@am__append_1 = -I$(top_srcdir)/jimtcl \ @INTERNAL_JIMTCL_TRUE@ -I$(top_builddir)/jimtcl subdir = src/flash ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/config_subdir.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libflash_la_DEPENDENCIES = \ $(top_builddir)/src/flash/nor/libocdflashnor.la \ $(top_builddir)/src/flash/nand/libocdflashnand.la am_libflash_la_OBJECTS = common.lo mflash.lo libflash_la_OBJECTS = $(am_libflash_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libflash_la_SOURCES) DIST_SOURCES = $(libflash_la_SOURCES) RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(noinst_HEADERS) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CC_FOR_BUILD = @CC_FOR_BUILD@ CFLAGS = @CFLAGS@ CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@ FGREP = @FGREP@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ doxygen_as_html = @doxygen_as_html@ doxygen_as_pdf = @doxygen_as_pdf@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ # common flags used in openocd build AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src \ -I$(top_srcdir)/src/helper -DPKGDATADIR=\"$(pkgdatadir)\" \ -DPKGLIBDIR=\"$(pkglibdir)\" $(am__append_1) SUBDIRS = \ nor \ nand METASOURCES = AUTO noinst_LTLIBRARIES = libflash.la libflash_la_SOURCES = \ common.c \ mflash.c libflash_la_LIBADD = \ $(top_builddir)/src/flash/nor/libocdflashnor.la \ $(top_builddir)/src/flash/nand/libocdflashnand.la noinst_HEADERS = \ common.h \ mflash.h EXTRA_DIST = startup.tcl MAINTAINERCLEANFILES = $(srcdir)/Makefile.in all: all-recursive .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/common.mk $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/flash/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/flash/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_srcdir)/common.mk: $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libflash.la: $(libflash_la_OBJECTS) $(libflash_la_DEPENDENCIES) $(EXTRA_libflash_la_DEPENDENCIES) $(AM_V_CCLD)$(LINK) $(libflash_la_OBJECTS) $(libflash_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mflash.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-recursive clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-libtool \ clean-noinstLTLIBRARIES cscopelist-am ctags ctags-am distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: openocd-0.7.0/src/flash/common.c0000644000175000001440000000422712134336410013404 00000000000000/*************************************************************************** * Copyright (C) 2009 by Zachary T Welch * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "common.h" #include unsigned get_flash_name_index(const char *name) { const char *name_index = strrchr(name, '.'); if (NULL == name_index) return 0; if (name_index[1] < '0' || name_index[1] > '9') return ~0U; unsigned requested; int retval = parse_uint(name_index + 1, &requested); /* detect parsing error by forcing past end of bank list */ return (ERROR_OK == retval) ? requested : ~0U; } bool flash_driver_name_matches(const char *name, const char *expected) { unsigned blen = strlen(name); /* only match up to the length of the driver name... */ if (strncmp(name, expected, blen) != 0) return false; /* ...then check that name terminates at this spot. */ return expected[blen] == '.' || expected[blen] == '\0'; } openocd-0.7.0/src/flash/nand/0000755000175000001440000000000012141414412012740 500000000000000openocd-0.7.0/src/flash/nand/nuc910.h0000644000175000001440000000462512134336410014062 00000000000000/*************************************************************************** * Copyright (C) 2010 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /* * NAND controller interface for Nuvoton NUC910 */ #ifndef NUC910_H #define NUC910_H #define NUC910_FMICSR 0xB000D000 #define NUC910_SMCSR 0xB000D0A0 #define NUC910_SMTCR 0xB000D0A4 #define NUC910_SMIER 0xB000D0A8 #define NUC910_SMISR 0xB000D0AC #define NUC910_SMCMD 0xB000D0B0 #define NUC910_SMADDR 0xB000D0B4 #define NUC910_SMDATA 0xB000D0B8 #define NUC910_SMECC0 0xB000D0BC #define NUC910_SMECC1 0xB000D0C0 #define NUC910_SMECC2 0xB000D0C4 #define NUC910_SMECC3 0xB000D0C8 #define NUC910_ECC4ST 0xB000D114 /* Global Control and Status Register (FMICSR) */ #define NUC910_FMICSR_SM_EN (1<<3) /* NAND Flash Address Port Register (SMADDR) */ #define NUC910_SMADDR_EOA (1<<31) /* NAND Flash Control and Status Register (SMCSR) */ #define NUC910_SMCSR_PSIZE (1<<3) #define NUC910_SMCSR_DBW (1<<4) /* NAND Flash Interrupt Status Register (SMISR) */ #define NUC910_SMISR_ECC_IF (1<<2) #define NUC910_SMISR_RB_ (1<<18) /* ECC4 Correction Status (ECC4ST) */ #endif /* NUC910_H */ openocd-0.7.0/src/flash/nand/mx3.h0000644000175000001440000001035712134336410013551 00000000000000/*************************************************************************** * Copyright (C) 2009 by Alexei Babich * * Rezonans plc., Chelyabinsk, Russia * * impatt@mail.ru * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /* * Freescale iMX3* OpenOCD NAND Flash controller support. * * Many thanks to Ben Dooks for writing s3c24xx driver. */ #define MX3_NF_BASE_ADDR 0xb8000000 #define MX3_NF_BUFSIZ (MX3_NF_BASE_ADDR + 0xe00) #define MX3_NF_BUFADDR (MX3_NF_BASE_ADDR + 0xe04) #define MX3_NF_FADDR (MX3_NF_BASE_ADDR + 0xe06) #define MX3_NF_FCMD (MX3_NF_BASE_ADDR + 0xe08) #define MX3_NF_BUFCFG (MX3_NF_BASE_ADDR + 0xe0a) #define MX3_NF_ECCSTATUS (MX3_NF_BASE_ADDR + 0xe0c) #define MX3_NF_ECCMAINPOS (MX3_NF_BASE_ADDR + 0xe0e) #define MX3_NF_ECCSPAREPOS (MX3_NF_BASE_ADDR + 0xe10) #define MX3_NF_FWP (MX3_NF_BASE_ADDR + 0xe12) #define MX3_NF_LOCKSTART (MX3_NF_BASE_ADDR + 0xe14) #define MX3_NF_LOCKEND (MX3_NF_BASE_ADDR + 0xe16) #define MX3_NF_FWPSTATUS (MX3_NF_BASE_ADDR + 0xe18) /* * all bits not marked as self-clearing bit */ #define MX3_NF_CFG1 (MX3_NF_BASE_ADDR + 0xe1a) #define MX3_NF_CFG2 (MX3_NF_BASE_ADDR + 0xe1c) #define MX3_NF_MAIN_BUFFER0 (MX3_NF_BASE_ADDR + 0x0000) #define MX3_NF_MAIN_BUFFER1 (MX3_NF_BASE_ADDR + 0x0200) #define MX3_NF_MAIN_BUFFER2 (MX3_NF_BASE_ADDR + 0x0400) #define MX3_NF_MAIN_BUFFER3 (MX3_NF_BASE_ADDR + 0x0600) #define MX3_NF_SPARE_BUFFER0 (MX3_NF_BASE_ADDR + 0x0800) #define MX3_NF_SPARE_BUFFER1 (MX3_NF_BASE_ADDR + 0x0810) #define MX3_NF_SPARE_BUFFER2 (MX3_NF_BASE_ADDR + 0x0820) #define MX3_NF_SPARE_BUFFER3 (MX3_NF_BASE_ADDR + 0x0830) #define MX3_NF_MAIN_BUFFER_LEN 512 #define MX3_NF_SPARE_BUFFER_LEN 16 #define MX3_NF_LAST_BUFFER_ADDR ((MX3_NF_SPARE_BUFFER3) + MX3_NF_SPARE_BUFFER_LEN - 2) /* bits in MX3_NF_CFG1 register */ #define MX3_NF_BIT_SPARE_ONLY_EN (1<<2) #define MX3_NF_BIT_ECC_EN (1<<3) #define MX3_NF_BIT_INT_DIS (1<<4) #define MX3_NF_BIT_BE_EN (1<<5) #define MX3_NF_BIT_RESET_EN (1<<6) #define MX3_NF_BIT_FORCE_CE (1<<7) /* bits in MX3_NF_CFG2 register */ /*Flash Command Input*/ #define MX3_NF_BIT_OP_FCI (1<<0) /* * Flash Address Input */ #define MX3_NF_BIT_OP_FAI (1<<1) /* * Flash Data Input */ #define MX3_NF_BIT_OP_FDI (1<<2) /* see "enum mx_dataout_type" below */ #define MX3_NF_BIT_DATAOUT_TYPE(x) ((x)<<3) #define MX3_NF_BIT_OP_DONE (1<<15) #define MX3_CCM_CGR2 0x53f80028 #define MX3_GPR 0x43fac008 #define MX3_PCSR 0x53f8000c enum mx_dataout_type { MX3_NF_DATAOUT_PAGE = 1, MX3_NF_DATAOUT_NANDID = 2, MX3_NF_DATAOUT_NANDSTATUS = 4, }; enum mx_nf_finalize_action { MX3_NF_FIN_NONE, MX3_NF_FIN_DATAOUT, }; struct mx3_nf_flags { unsigned host_little_endian:1; unsigned target_little_endian:1; unsigned nand_readonly:1; unsigned one_kb_sram:1; unsigned hw_ecc_enabled:1; }; struct mx3_nf_controller { enum mx_dataout_type optype; enum mx_nf_finalize_action fin; struct mx3_nf_flags flags; }; openocd-0.7.0/src/flash/nand/nuc910.c0000644000175000001440000001433712134336410014056 00000000000000/*************************************************************************** * Copyright (C) 2010 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /* * NAND controller interface for Nuvoton NUC910 */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "nuc910.h" #include "arm_io.h" #include struct nuc910_nand_controller { struct arm_nand_data io; }; static int validate_target_state(struct nand_device *nand) { struct target *target = nand->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_NAND_OPERATION_FAILED; } return ERROR_OK; } static int nuc910_nand_command(struct nand_device *nand, uint8_t command) { struct target *target = nand->target; int result; result = validate_target_state(nand); if (result != ERROR_OK) return result; target_write_u8(target, NUC910_SMCMD, command); return ERROR_OK; } static int nuc910_nand_address(struct nand_device *nand, uint8_t address) { struct target *target = nand->target; int result; result = validate_target_state(nand); if (result != ERROR_OK) return result; target_write_u32(target, NUC910_SMADDR, ((address & 0xff) | NUC910_SMADDR_EOA)); return ERROR_OK; } static int nuc910_nand_read(struct nand_device *nand, void *data) { struct target *target = nand->target; int result; result = validate_target_state(nand); if (result != ERROR_OK) return result; target_read_u8(target, NUC910_SMDATA, data); return ERROR_OK; } static int nuc910_nand_write(struct nand_device *nand, uint16_t data) { struct target *target = nand->target; int result; result = validate_target_state(nand); if (result != ERROR_OK) return result; target_write_u8(target, NUC910_SMDATA, data); return ERROR_OK; } static int nuc910_nand_read_block_data(struct nand_device *nand, uint8_t *data, int data_size) { struct nuc910_nand_controller *nuc910_nand = nand->controller_priv; int result; result = validate_target_state(nand); if (result != ERROR_OK) return result; nuc910_nand->io.chunk_size = nand->page_size; /* try the fast way first */ result = arm_nandread(&nuc910_nand->io, data, data_size); if (result != ERROR_NAND_NO_BUFFER) return result; /* else do it slowly */ while (data_size--) nuc910_nand_read(nand, data++); return ERROR_OK; } static int nuc910_nand_write_block_data(struct nand_device *nand, uint8_t *data, int data_size) { struct nuc910_nand_controller *nuc910_nand = nand->controller_priv; int result; result = validate_target_state(nand); if (result != ERROR_OK) return result; nuc910_nand->io.chunk_size = nand->page_size; /* try the fast way first */ result = arm_nandwrite(&nuc910_nand->io, data, data_size); if (result != ERROR_NAND_NO_BUFFER) return result; /* else do it slowly */ while (data_size--) nuc910_nand_write(nand, *data++); return ERROR_OK; } static int nuc910_nand_reset(struct nand_device *nand) { return nuc910_nand_command(nand, NAND_CMD_RESET); } static int nuc910_nand_ready(struct nand_device *nand, int timeout) { struct target *target = nand->target; uint32_t status; do { target_read_u32(target, NUC910_SMISR, &status); if (status & NUC910_SMISR_RB_) return 1; alive_sleep(1); } while (timeout-- > 0); return 0; } NAND_DEVICE_COMMAND_HANDLER(nuc910_nand_device_command) { struct nuc910_nand_controller *nuc910_nand; nuc910_nand = calloc(1, sizeof(struct nuc910_nand_controller)); if (!nuc910_nand) { LOG_ERROR("no memory for nand controller"); return ERROR_NAND_DEVICE_INVALID; } nand->controller_priv = nuc910_nand; return ERROR_OK; } static int nuc910_nand_init(struct nand_device *nand) { struct nuc910_nand_controller *nuc910_nand = nand->controller_priv; struct target *target = nand->target; int bus_width = nand->bus_width ? : 8; int result; result = validate_target_state(nand); if (result != ERROR_OK) return result; /* nuc910 only supports 8bit */ if (bus_width != 8) { LOG_ERROR("nuc910 only supports 8 bit bus width, not %i", bus_width); return ERROR_NAND_OPERATION_NOT_SUPPORTED; } /* inform calling code about selected bus width */ nand->bus_width = bus_width; nuc910_nand->io.target = target; nuc910_nand->io.data = NUC910_SMDATA; nuc910_nand->io.op = ARM_NAND_NONE; /* configure nand controller */ target_write_u32(target, NUC910_FMICSR, NUC910_FMICSR_SM_EN); target_write_u32(target, NUC910_SMCSR, 0x010000a8); /* 2048 page size */ target_write_u32(target, NUC910_SMTCR, 0x00010204); target_write_u32(target, NUC910_SMIER, 0x00000000); return ERROR_OK; } struct nand_flash_controller nuc910_nand_controller = { .name = "nuc910", .command = nuc910_nand_command, .address = nuc910_nand_address, .read_data = nuc910_nand_read, .write_data = nuc910_nand_write, .write_block_data = nuc910_nand_write_block_data, .read_block_data = nuc910_nand_read_block_data, .nand_ready = nuc910_nand_ready, .reset = nuc910_nand_reset, .nand_device_command = nuc910_nand_device_command, .init = nuc910_nand_init, }; openocd-0.7.0/src/flash/nand/fileio.c0000644000175000001440000001557012134336410014306 00000000000000/*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Copyright (C) 2002 Thomas Gleixner * * Copyright (C) 2009 Zachary T Welch * * * * Partially based on drivers/mtd/nand_ids.c from Linux. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "core.h" #include "fileio.h" static struct nand_ecclayout nand_oob_16 = { .eccbytes = 6, .eccpos = {0, 1, 2, 3, 6, 7}, .oobfree = { {.offset = 8, .length = 8} } }; static struct nand_ecclayout nand_oob_64 = { .eccbytes = 24, .eccpos = { 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63 }, .oobfree = { {.offset = 2, .length = 38} } }; void nand_fileio_init(struct nand_fileio_state *state) { memset(state, 0, sizeof(*state)); state->oob_format = NAND_OOB_NONE; } int nand_fileio_start(struct command_context *cmd_ctx, struct nand_device *nand, const char *filename, int filemode, struct nand_fileio_state *state) { if (state->address % nand->page_size) { command_print(cmd_ctx, "only page-aligned addresses are supported"); return ERROR_COMMAND_SYNTAX_ERROR; } duration_start(&state->bench); if (NULL != filename) { int retval = fileio_open(&state->fileio, filename, filemode, FILEIO_BINARY); if (ERROR_OK != retval) { const char *msg = (FILEIO_READ == filemode) ? "read" : "write"; command_print(cmd_ctx, "failed to open '%s' for %s access", filename, msg); return retval; } state->file_opened = true; } if (!(state->oob_format & NAND_OOB_ONLY)) { state->page_size = nand->page_size; state->page = malloc(nand->page_size); } if (state->oob_format & (NAND_OOB_RAW | NAND_OOB_SW_ECC | NAND_OOB_SW_ECC_KW)) { if (nand->page_size == 512) { state->oob_size = 16; state->eccpos = nand_oob_16.eccpos; } else if (nand->page_size == 2048) { state->oob_size = 64; state->eccpos = nand_oob_64.eccpos; } state->oob = malloc(state->oob_size); } return ERROR_OK; } int nand_fileio_cleanup(struct nand_fileio_state *state) { if (state->file_opened) fileio_close(&state->fileio); if (state->oob) { free(state->oob); state->oob = NULL; } if (state->page) { free(state->page); state->page = NULL; } return ERROR_OK; } int nand_fileio_finish(struct nand_fileio_state *state) { nand_fileio_cleanup(state); return duration_measure(&state->bench); } COMMAND_HELPER(nand_fileio_parse_args, struct nand_fileio_state *state, struct nand_device **dev, enum fileio_access filemode, bool need_size, bool sw_ecc) { nand_fileio_init(state); unsigned minargs = need_size ? 4 : 3; if (CMD_ARGC < minargs) return ERROR_COMMAND_SYNTAX_ERROR; struct nand_device *nand; int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &nand); if (ERROR_OK != retval) return retval; if (NULL == nand->device) { command_print(CMD_CTX, "#%s: not probed", CMD_ARGV[0]); return ERROR_OK; } COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], state->address); if (need_size) { COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], state->size); if (state->size % nand->page_size) { command_print(CMD_CTX, "only page-aligned sizes are supported"); return ERROR_COMMAND_SYNTAX_ERROR; } } if (CMD_ARGC > minargs) { for (unsigned i = minargs; i < CMD_ARGC; i++) { if (!strcmp(CMD_ARGV[i], "oob_raw")) state->oob_format |= NAND_OOB_RAW; else if (!strcmp(CMD_ARGV[i], "oob_only")) state->oob_format |= NAND_OOB_RAW | NAND_OOB_ONLY; else if (sw_ecc && !strcmp(CMD_ARGV[i], "oob_softecc")) state->oob_format |= NAND_OOB_SW_ECC; else if (sw_ecc && !strcmp(CMD_ARGV[i], "oob_softecc_kw")) state->oob_format |= NAND_OOB_SW_ECC_KW; else { command_print(CMD_CTX, "unknown option: %s", CMD_ARGV[i]); return ERROR_COMMAND_SYNTAX_ERROR; } } } retval = nand_fileio_start(CMD_CTX, nand, CMD_ARGV[1], filemode, state); if (ERROR_OK != retval) return retval; if (!need_size) { int filesize; retval = fileio_size(&state->fileio, &filesize); if (retval != ERROR_OK) return retval; state->size = filesize; } *dev = nand; return ERROR_OK; } /** * @returns If no error occurred, returns number of bytes consumed; * otherwise, returns a negative error code.) */ int nand_fileio_read(struct nand_device *nand, struct nand_fileio_state *s) { size_t total_read = 0; size_t one_read; if (NULL != s->page) { fileio_read(&s->fileio, s->page_size, s->page, &one_read); if (one_read < s->page_size) memset(s->page + one_read, 0xff, s->page_size - one_read); total_read += one_read; } if (s->oob_format & NAND_OOB_SW_ECC) { uint8_t ecc[3]; memset(s->oob, 0xff, s->oob_size); for (uint32_t i = 0, j = 0; i < s->page_size; i += 256) { nand_calculate_ecc(nand, s->page + i, ecc); s->oob[s->eccpos[j++]] = ecc[0]; s->oob[s->eccpos[j++]] = ecc[1]; s->oob[s->eccpos[j++]] = ecc[2]; } } else if (s->oob_format & NAND_OOB_SW_ECC_KW) { /* * In this case eccpos is not used as * the ECC data is always stored contigously * at the end of the OOB area. It consists * of 10 bytes per 512-byte data block. */ uint8_t *ecc = s->oob + s->oob_size - s->page_size / 512 * 10; memset(s->oob, 0xff, s->oob_size); for (uint32_t i = 0; i < s->page_size; i += 512) { nand_calculate_ecc_kw(nand, s->page + i, ecc); ecc += 10; } } else if (NULL != s->oob) { fileio_read(&s->fileio, s->oob_size, s->oob, &one_read); if (one_read < s->oob_size) memset(s->oob + one_read, 0xff, s->oob_size - one_read); total_read += one_read; } return total_read; } openocd-0.7.0/src/flash/nand/mx3.c0000644000175000001440000005042512134336410013544 00000000000000 /*************************************************************************** * Copyright (C) 2009 by Alexei Babich * * Rezonans plc., Chelyabinsk, Russia * * impatt@mail.ru * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /* * Freescale iMX3* OpenOCD NAND Flash controller support. * * Many thanks to Ben Dooks for writing s3c24xx driver. */ /* driver tested with STMicro NAND512W3A @imx31 tested "nand probe #", "nand erase # 0 #", "nand dump # file 0 #", "nand write # file 0" get_next_halfword_from_sram_buffer() not tested */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "mx3.h" #include static const char target_not_halted_err_msg[] = "target must be halted to use mx3 NAND flash controller"; static const char data_block_size_err_msg[] = "minimal granularity is one half-word, %" PRId32 " is incorrect"; static const char sram_buffer_bounds_err_msg[] = "trying to access out of SRAM buffer bound (addr=0x%" PRIx32 ")"; static const char get_status_register_err_msg[] = "can't get NAND status"; static uint32_t in_sram_address; static unsigned char sign_of_sequental_byte_read; static int test_iomux_settings(struct target *target, uint32_t value, uint32_t mask, const char *text); static int initialize_nf_controller(struct nand_device *nand); static int get_next_byte_from_sram_buffer(struct target *target, uint8_t *value); static int get_next_halfword_from_sram_buffer(struct target *target, uint16_t *value); static int poll_for_complete_op(struct target *target, const char *text); static int validate_target_state(struct nand_device *nand); static int do_data_output(struct nand_device *nand); static int imx31_command(struct nand_device *nand, uint8_t command); static int imx31_address(struct nand_device *nand, uint8_t address); NAND_DEVICE_COMMAND_HANDLER(imx31_nand_device_command) { struct mx3_nf_controller *mx3_nf_info; mx3_nf_info = malloc(sizeof(struct mx3_nf_controller)); if (mx3_nf_info == NULL) { LOG_ERROR("no memory for nand controller"); return ERROR_FAIL; } nand->controller_priv = mx3_nf_info; if (CMD_ARGC < 3) return ERROR_COMMAND_SYNTAX_ERROR; /* * check hwecc requirements */ { int hwecc_needed; hwecc_needed = strcmp(CMD_ARGV[2], "hwecc"); if (hwecc_needed == 0) mx3_nf_info->flags.hw_ecc_enabled = 1; else mx3_nf_info->flags.hw_ecc_enabled = 0; } mx3_nf_info->optype = MX3_NF_DATAOUT_PAGE; mx3_nf_info->fin = MX3_NF_FIN_NONE; mx3_nf_info->flags.target_little_endian = (nand->target->endianness == TARGET_LITTLE_ENDIAN); /* * testing host endianness */ { int x = 1; if (*(char *) &x == 1) mx3_nf_info->flags.host_little_endian = 1; else mx3_nf_info->flags.host_little_endian = 0; } return ERROR_OK; } static int imx31_init(struct nand_device *nand) { struct mx3_nf_controller *mx3_nf_info = nand->controller_priv; struct target *target = nand->target; { /* * validate target state */ int validate_target_result; validate_target_result = validate_target_state(nand); if (validate_target_result != ERROR_OK) return validate_target_result; } { uint16_t buffsize_register_content; target_read_u16(target, MX3_NF_BUFSIZ, &buffsize_register_content); mx3_nf_info->flags.one_kb_sram = !(buffsize_register_content & 0x000f); } { uint32_t pcsr_register_content; target_read_u32(target, MX3_PCSR, &pcsr_register_content); if (!nand->bus_width) { nand->bus_width = (pcsr_register_content & 0x80000000) ? 16 : 8; } else { pcsr_register_content |= ((nand->bus_width == 16) ? 0x80000000 : 0x00000000); target_write_u32(target, MX3_PCSR, pcsr_register_content); } if (!nand->page_size) { nand->page_size = (pcsr_register_content & 0x40000000) ? 2048 : 512; } else { pcsr_register_content |= ((nand->page_size == 2048) ? 0x40000000 : 0x00000000); target_write_u32(target, MX3_PCSR, pcsr_register_content); } if (mx3_nf_info->flags.one_kb_sram && (nand->page_size == 2048)) { LOG_ERROR("NAND controller have only 1 kb SRAM, " "so pagesize 2048 is incompatible with it"); } } { uint32_t cgr_register_content; target_read_u32(target, MX3_CCM_CGR2, &cgr_register_content); if (!(cgr_register_content & 0x00000300)) { LOG_ERROR("clock gating to EMI disabled"); return ERROR_FAIL; } } { uint32_t gpr_register_content; target_read_u32(target, MX3_GPR, &gpr_register_content); if (gpr_register_content & 0x00000060) { LOG_ERROR("pins mode overrided by GPR"); return ERROR_FAIL; } } { /* * testing IOMUX settings; must be in "functional-mode output and * functional-mode input" mode */ int test_iomux; test_iomux = ERROR_OK; test_iomux |= test_iomux_settings(target, 0x43fac0c0, 0x7f7f7f00, "d0,d1,d2"); test_iomux |= test_iomux_settings(target, 0x43fac0c4, 0x7f7f7f7f, "d3,d4,d5,d6"); test_iomux |= test_iomux_settings(target, 0x43fac0c8, 0x0000007f, "d7"); if (nand->bus_width == 16) { test_iomux |= test_iomux_settings(target, 0x43fac0c8, 0x7f7f7f00, "d8,d9,d10"); test_iomux |= test_iomux_settings(target, 0x43fac0cc, 0x7f7f7f7f, "d11,d12,d13,d14"); test_iomux |= test_iomux_settings(target, 0x43fac0d0, 0x0000007f, "d15"); } test_iomux |= test_iomux_settings(target, 0x43fac0d0, 0x7f7f7f00, "nfwp,nfce,nfrb"); test_iomux |= test_iomux_settings(target, 0x43fac0d4, 0x7f7f7f7f, "nfwe,nfre,nfale,nfcle"); if (test_iomux != ERROR_OK) return ERROR_FAIL; } initialize_nf_controller(nand); { int retval; uint16_t nand_status_content; retval = ERROR_OK; retval |= imx31_command(nand, NAND_CMD_STATUS); retval |= imx31_address(nand, 0x00); retval |= do_data_output(nand); if (retval != ERROR_OK) { LOG_ERROR(get_status_register_err_msg); return ERROR_FAIL; } target_read_u16(target, MX3_NF_MAIN_BUFFER0, &nand_status_content); if (!(nand_status_content & 0x0080)) { /* * is host-big-endian correctly ?? */ LOG_INFO("NAND read-only"); mx3_nf_info->flags.nand_readonly = 1; } else mx3_nf_info->flags.nand_readonly = 0; } return ERROR_OK; } static int imx31_read_data(struct nand_device *nand, void *data) { struct target *target = nand->target; { /* * validate target state */ int validate_target_result; validate_target_result = validate_target_state(nand); if (validate_target_result != ERROR_OK) return validate_target_result; } { /* * get data from nand chip */ int try_data_output_from_nand_chip; try_data_output_from_nand_chip = do_data_output(nand); if (try_data_output_from_nand_chip != ERROR_OK) return try_data_output_from_nand_chip; } if (nand->bus_width == 16) get_next_halfword_from_sram_buffer(target, data); else get_next_byte_from_sram_buffer(target, data); return ERROR_OK; } static int imx31_write_data(struct nand_device *nand, uint16_t data) { LOG_ERROR("write_data() not implemented"); return ERROR_NAND_OPERATION_FAILED; } static int imx31_reset(struct nand_device *nand) { /* * validate target state */ int validate_target_result; validate_target_result = validate_target_state(nand); if (validate_target_result != ERROR_OK) return validate_target_result; initialize_nf_controller(nand); return ERROR_OK; } static int imx31_command(struct nand_device *nand, uint8_t command) { struct mx3_nf_controller *mx3_nf_info = nand->controller_priv; struct target *target = nand->target; { /* * validate target state */ int validate_target_result; validate_target_result = validate_target_state(nand); if (validate_target_result != ERROR_OK) return validate_target_result; } switch (command) { case NAND_CMD_READOOB: command = NAND_CMD_READ0; in_sram_address = MX3_NF_SPARE_BUFFER0; /* set read point for * data_read() and * read_block_data() to * spare area in SRAM * buffer */ break; case NAND_CMD_READ1: command = NAND_CMD_READ0; /* * offset == one half of page size */ in_sram_address = MX3_NF_MAIN_BUFFER0 + (nand->page_size >> 1); default: in_sram_address = MX3_NF_MAIN_BUFFER0; } target_write_u16(target, MX3_NF_FCMD, command); /* * start command input operation (set MX3_NF_BIT_OP_DONE==0) */ target_write_u16(target, MX3_NF_CFG2, MX3_NF_BIT_OP_FCI); { int poll_result; poll_result = poll_for_complete_op(target, "command"); if (poll_result != ERROR_OK) return poll_result; } /* * reset cursor to begin of the buffer */ sign_of_sequental_byte_read = 0; switch (command) { case NAND_CMD_READID: mx3_nf_info->optype = MX3_NF_DATAOUT_NANDID; mx3_nf_info->fin = MX3_NF_FIN_DATAOUT; break; case NAND_CMD_STATUS: mx3_nf_info->optype = MX3_NF_DATAOUT_NANDSTATUS; mx3_nf_info->fin = MX3_NF_FIN_DATAOUT; break; case NAND_CMD_READ0: mx3_nf_info->fin = MX3_NF_FIN_DATAOUT; mx3_nf_info->optype = MX3_NF_DATAOUT_PAGE; break; default: mx3_nf_info->optype = MX3_NF_DATAOUT_PAGE; } return ERROR_OK; } static int imx31_address(struct nand_device *nand, uint8_t address) { struct target *target = nand->target; { /* * validate target state */ int validate_target_result; validate_target_result = validate_target_state(nand); if (validate_target_result != ERROR_OK) return validate_target_result; } target_write_u16(target, MX3_NF_FADDR, address); /* * start address input operation (set MX3_NF_BIT_OP_DONE==0) */ target_write_u16(target, MX3_NF_CFG2, MX3_NF_BIT_OP_FAI); { int poll_result; poll_result = poll_for_complete_op(target, "address"); if (poll_result != ERROR_OK) return poll_result; } return ERROR_OK; } static int imx31_nand_ready(struct nand_device *nand, int tout) { uint16_t poll_complete_status; struct target *target = nand->target; { /* * validate target state */ int validate_target_result; validate_target_result = validate_target_state(nand); if (validate_target_result != ERROR_OK) return validate_target_result; } do { target_read_u16(target, MX3_NF_CFG2, &poll_complete_status); if (poll_complete_status & MX3_NF_BIT_OP_DONE) return tout; alive_sleep(1); } while (tout-- > 0); return tout; } static int imx31_write_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { struct mx3_nf_controller *mx3_nf_info = nand->controller_priv; struct target *target = nand->target; if (data_size % 2) { LOG_ERROR(data_block_size_err_msg, data_size); return ERROR_NAND_OPERATION_FAILED; } if (oob_size % 2) { LOG_ERROR(data_block_size_err_msg, oob_size); return ERROR_NAND_OPERATION_FAILED; } if (!data) { LOG_ERROR("nothing to program"); return ERROR_NAND_OPERATION_FAILED; } { /* * validate target state */ int retval; retval = validate_target_state(nand); if (retval != ERROR_OK) return retval; } { int retval = ERROR_OK; retval |= imx31_command(nand, NAND_CMD_SEQIN); retval |= imx31_address(nand, 0x00); retval |= imx31_address(nand, page & 0xff); retval |= imx31_address(nand, (page >> 8) & 0xff); if (nand->address_cycles >= 4) { retval |= imx31_address(nand, (page >> 16) & 0xff); if (nand->address_cycles >= 5) retval |= imx31_address(nand, (page >> 24) & 0xff); } target_write_buffer(target, MX3_NF_MAIN_BUFFER0, data_size, data); if (oob) { if (mx3_nf_info->flags.hw_ecc_enabled) { /* * part of spare block will be overrided by hardware * ECC generator */ LOG_DEBUG("part of spare block will be overrided by hardware ECC generator"); } target_write_buffer(target, MX3_NF_SPARE_BUFFER0, oob_size, oob); } /* * start data input operation (set MX3_NF_BIT_OP_DONE==0) */ target_write_u16(target, MX3_NF_CFG2, MX3_NF_BIT_OP_FDI); { int poll_result; poll_result = poll_for_complete_op(target, "data input"); if (poll_result != ERROR_OK) return poll_result; } retval |= imx31_command(nand, NAND_CMD_PAGEPROG); if (retval != ERROR_OK) return retval; /* * check status register */ { uint16_t nand_status_content; retval = ERROR_OK; retval |= imx31_command(nand, NAND_CMD_STATUS); retval |= imx31_address(nand, 0x00); retval |= do_data_output(nand); if (retval != ERROR_OK) { LOG_ERROR(get_status_register_err_msg); return retval; } target_read_u16(target, MX3_NF_MAIN_BUFFER0, &nand_status_content); if (nand_status_content & 0x0001) { /* * is host-big-endian correctly ?? */ return ERROR_NAND_OPERATION_FAILED; } } } return ERROR_OK; } static int imx31_read_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { struct target *target = nand->target; if (data_size % 2) { LOG_ERROR(data_block_size_err_msg, data_size); return ERROR_NAND_OPERATION_FAILED; } if (oob_size % 2) { LOG_ERROR(data_block_size_err_msg, oob_size); return ERROR_NAND_OPERATION_FAILED; } { /* * validate target state */ int retval; retval = validate_target_state(nand); if (retval != ERROR_OK) return retval; } { int retval = ERROR_OK; retval |= imx31_command(nand, NAND_CMD_READ0); retval |= imx31_address(nand, 0x00); retval |= imx31_address(nand, page & 0xff); retval |= imx31_address(nand, (page >> 8) & 0xff); if (nand->address_cycles >= 4) { retval |= imx31_address(nand, (page >> 16) & 0xff); if (nand->address_cycles >= 5) { retval |= imx31_address(nand, (page >> 24) & 0xff); retval |= imx31_command(nand, NAND_CMD_READSTART); } } retval |= do_data_output(nand); if (retval != ERROR_OK) return retval; if (data) { target_read_buffer(target, MX3_NF_MAIN_BUFFER0, data_size, data); } if (oob) { target_read_buffer(target, MX3_NF_SPARE_BUFFER0, oob_size, oob); } } return ERROR_OK; } static int test_iomux_settings(struct target *target, uint32_t address, uint32_t mask, const char *text) { uint32_t register_content; target_read_u32(target, address, ®ister_content); if ((register_content & mask) != (0x12121212 & mask)) { LOG_ERROR("IOMUX for {%s} is bad", text); return ERROR_FAIL; } return ERROR_OK; } static int initialize_nf_controller(struct nand_device *nand) { struct mx3_nf_controller *mx3_nf_info = nand->controller_priv; struct target *target = nand->target; /* * resets NAND flash controller in zero time ? I dont know. */ target_write_u16(target, MX3_NF_CFG1, MX3_NF_BIT_RESET_EN); { uint16_t work_mode; work_mode = MX3_NF_BIT_INT_DIS; /* disable interrupt */ if (target->endianness == TARGET_BIG_ENDIAN) work_mode |= MX3_NF_BIT_BE_EN; if (mx3_nf_info->flags.hw_ecc_enabled) work_mode |= MX3_NF_BIT_ECC_EN; target_write_u16(target, MX3_NF_CFG1, work_mode); } /* * unlock SRAM buffer for write; 2 mean "Unlock", other values means "Lock" */ target_write_u16(target, MX3_NF_BUFCFG, 2); { uint16_t temp; target_read_u16(target, MX3_NF_FWP, &temp); if ((temp & 0x0007) == 1) { LOG_ERROR("NAND flash is tight-locked, reset needed"); return ERROR_FAIL; } } /* * unlock NAND flash for write */ target_write_u16(target, MX3_NF_FWP, 4); target_write_u16(target, MX3_NF_LOCKSTART, 0x0000); target_write_u16(target, MX3_NF_LOCKEND, 0xFFFF); /* * 0x0000 means that first SRAM buffer @0xB800_0000 will be used */ target_write_u16(target, MX3_NF_BUFADDR, 0x0000); /* * address of SRAM buffer */ in_sram_address = MX3_NF_MAIN_BUFFER0; sign_of_sequental_byte_read = 0; return ERROR_OK; } static int get_next_byte_from_sram_buffer(struct target *target, uint8_t *value) { static uint8_t even_byte; /* * host-big_endian ?? */ if (sign_of_sequental_byte_read == 0) even_byte = 0; if (in_sram_address > MX3_NF_LAST_BUFFER_ADDR) { LOG_ERROR(sram_buffer_bounds_err_msg, in_sram_address); *value = 0; sign_of_sequental_byte_read = 0; even_byte = 0; return ERROR_NAND_OPERATION_FAILED; } else { uint16_t temp; target_read_u16(target, in_sram_address, &temp); if (even_byte) { *value = temp >> 8; even_byte = 0; in_sram_address += 2; } else { *value = temp & 0xff; even_byte = 1; } } sign_of_sequental_byte_read = 1; return ERROR_OK; } static int get_next_halfword_from_sram_buffer(struct target *target, uint16_t *value) { if (in_sram_address > MX3_NF_LAST_BUFFER_ADDR) { LOG_ERROR(sram_buffer_bounds_err_msg, in_sram_address); *value = 0; return ERROR_NAND_OPERATION_FAILED; } else { target_read_u16(target, in_sram_address, value); in_sram_address += 2; } return ERROR_OK; } static int poll_for_complete_op(struct target *target, const char *text) { uint16_t poll_complete_status; for (int poll_cycle_count = 0; poll_cycle_count < 100; poll_cycle_count++) { usleep(25); target_read_u16(target, MX3_NF_CFG2, &poll_complete_status); if (poll_complete_status & MX3_NF_BIT_OP_DONE) break; } if (!(poll_complete_status & MX3_NF_BIT_OP_DONE)) { LOG_ERROR("%s sending timeout", text); return ERROR_NAND_OPERATION_FAILED; } return ERROR_OK; } static int validate_target_state(struct nand_device *nand) { struct mx3_nf_controller *mx3_nf_info = nand->controller_priv; struct target *target = nand->target; if (target->state != TARGET_HALTED) { LOG_ERROR(target_not_halted_err_msg); return ERROR_NAND_OPERATION_FAILED; } if (mx3_nf_info->flags.target_little_endian != (target->endianness == TARGET_LITTLE_ENDIAN)) { /* * endianness changed after NAND controller probed */ return ERROR_NAND_OPERATION_FAILED; } return ERROR_OK; } static int do_data_output(struct nand_device *nand) { struct mx3_nf_controller *mx3_nf_info = nand->controller_priv; struct target *target = nand->target; switch (mx3_nf_info->fin) { case MX3_NF_FIN_DATAOUT: /* * start data output operation (set MX3_NF_BIT_OP_DONE==0) */ target_write_u16 (target, MX3_NF_CFG2, MX3_NF_BIT_DATAOUT_TYPE(mx3_nf_info->optype)); { int poll_result; poll_result = poll_for_complete_op(target, "data output"); if (poll_result != ERROR_OK) return poll_result; } mx3_nf_info->fin = MX3_NF_FIN_NONE; /* * ECC stuff */ if ((mx3_nf_info->optype == MX3_NF_DATAOUT_PAGE) && mx3_nf_info->flags.hw_ecc_enabled) { uint16_t ecc_status; target_read_u16 (target, MX3_NF_ECCSTATUS, &ecc_status); switch (ecc_status & 0x000c) { case 1 << 2: LOG_DEBUG("main area readed with 1 (correctable) error"); break; case 2 << 2: LOG_DEBUG("main area readed with more than 1 (incorrectable) error"); return ERROR_NAND_OPERATION_FAILED; break; } switch (ecc_status & 0x0003) { case 1: LOG_DEBUG("spare area readed with 1 (correctable) error"); break; case 2: LOG_DEBUG("main area readed with more than 1 (incorrectable) error"); return ERROR_NAND_OPERATION_FAILED; break; } } break; case MX3_NF_FIN_NONE: break; } return ERROR_OK; } struct nand_flash_controller imx31_nand_flash_controller = { .name = "imx31", .usage = "nand device imx31 target noecc|hwecc", .nand_device_command = &imx31_nand_device_command, .init = &imx31_init, .reset = &imx31_reset, .command = &imx31_command, .address = &imx31_address, .write_data = &imx31_write_data, .read_data = &imx31_read_data, .write_page = &imx31_write_page, .read_page = &imx31_read_page, .nand_ready = &imx31_nand_ready, }; openocd-0.7.0/src/flash/nand/lpc32xx.c0000644000175000001440000015172012134336410014340 00000000000000/*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2011 Bjarne Steinsbo * * Copyright (C) 2010 richard vegh * * Copyright (C) 2010 Oyvind Harboe * * * * Based on a combination of the lpc3180 driver and code from * * uboot-2009.03-lpc32xx by Kevin Wells. * * Any bugs are mine. --BSt * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "lpc32xx.h" #include static int lpc32xx_reset(struct nand_device *nand); static int lpc32xx_controller_ready(struct nand_device *nand, int timeout); static int lpc32xx_tc_ready(struct nand_device *nand, int timeout); extern int nand_correct_data(struct nand_device *nand, u_char *dat, u_char *read_ecc, u_char *calc_ecc); /* These are offset with the working area in IRAM when using DMA to * read/write data to the SLC controller. * - DMA descriptors will be put at start of working area, * - Hardware generated ECC will be stored at ECC_OFFS * - OOB wil be read/written from/to SPARE_OFFS * - Actual page data will be read from/to DATA_OFFS * There are unused holes between the used areas. */ #define ECC_OFFS 0x120 #define SPARE_OFFS 0x140 #define DATA_OFFS 0x200 static int sp_ooblayout[] = { 10, 11, 12, 13, 14, 15 }; static int lp_ooblayout[] = { 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63 }; typedef struct { volatile uint32_t dma_src; volatile uint32_t dma_dest; volatile uint32_t next_lli; volatile uint32_t next_ctrl; } dmac_ll_t; static dmac_ll_t dmalist[(2048/256) * 2 + 1]; /* nand device lpc32xx */ NAND_DEVICE_COMMAND_HANDLER(lpc32xx_nand_device_command) { if (CMD_ARGC < 3) return ERROR_COMMAND_SYNTAX_ERROR; uint32_t osc_freq; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], osc_freq); struct lpc32xx_nand_controller *lpc32xx_info; lpc32xx_info = malloc(sizeof(struct lpc32xx_nand_controller)); nand->controller_priv = lpc32xx_info; lpc32xx_info->osc_freq = osc_freq; if ((lpc32xx_info->osc_freq < 1000) || (lpc32xx_info->osc_freq > 20000)) LOG_WARNING("LPC32xx oscillator frequency should be between " "1000 and 20000 kHz, was %i", lpc32xx_info->osc_freq); lpc32xx_info->selected_controller = LPC32xx_NO_CONTROLLER; lpc32xx_info->sw_write_protection = 0; lpc32xx_info->sw_wp_lower_bound = 0x0; lpc32xx_info->sw_wp_upper_bound = 0x0; return ERROR_OK; } static int lpc32xx_pll(int fclkin, uint32_t pll_ctrl) { int bypass = (pll_ctrl & 0x8000) >> 15; int direct = (pll_ctrl & 0x4000) >> 14; int feedback = (pll_ctrl & 0x2000) >> 13; int p = (1 << ((pll_ctrl & 0x1800) >> 11) * 2); int n = ((pll_ctrl & 0x0600) >> 9) + 1; int m = ((pll_ctrl & 0x01fe) >> 1) + 1; int lock = (pll_ctrl & 0x1); if (!lock) LOG_WARNING("PLL is not locked"); if (!bypass && direct) /* direct mode */ return (m * fclkin) / n; if (bypass && !direct) /* bypass mode */ return fclkin / (2 * p); if (bypass & direct) /* direct bypass mode */ return fclkin; if (feedback) /* integer mode */ return m * (fclkin / n); else /* non-integer mode */ return (m / (2 * p)) * (fclkin / n); } static float lpc32xx_cycle_time(struct nand_device *nand) { struct lpc32xx_nand_controller *lpc32xx_info = nand->controller_priv; struct target *target = nand->target; uint32_t sysclk_ctrl, pwr_ctrl, hclkdiv_ctrl, hclkpll_ctrl; int sysclk; int hclk; int hclk_pll; float cycle; int retval; /* calculate timings */ /* determine current SYSCLK (13'MHz or main oscillator) */ retval = target_read_u32(target, 0x40004050, &sysclk_ctrl); if (ERROR_OK != retval) { LOG_ERROR("could not read SYSCLK_CTRL"); return ERROR_NAND_OPERATION_FAILED; } if ((sysclk_ctrl & 1) == 0) sysclk = lpc32xx_info->osc_freq; else sysclk = 13000; /* determine selected HCLK source */ retval = target_read_u32(target, 0x40004044, &pwr_ctrl); if (ERROR_OK != retval) { LOG_ERROR("could not read HCLK_CTRL"); return ERROR_NAND_OPERATION_FAILED; } if ((pwr_ctrl & (1 << 2)) == 0) /* DIRECT RUN mode */ hclk = sysclk; else { retval = target_read_u32(target, 0x40004058, &hclkpll_ctrl); if (ERROR_OK != retval) { LOG_ERROR("could not read HCLKPLL_CTRL"); return ERROR_NAND_OPERATION_FAILED; } hclk_pll = lpc32xx_pll(sysclk, hclkpll_ctrl); retval = target_read_u32(target, 0x40004040, &hclkdiv_ctrl); if (ERROR_OK != retval) { LOG_ERROR("could not read CLKDIV_CTRL"); return ERROR_NAND_OPERATION_FAILED; } if (pwr_ctrl & (1 << 10)) /* ARM_CLK and HCLK use PERIPH_CLK */ hclk = hclk_pll / (((hclkdiv_ctrl & 0x7c) >> 2) + 1); else /* HCLK uses HCLK_PLL */ hclk = hclk_pll / (1 << (hclkdiv_ctrl & 0x3)); } LOG_DEBUG("LPC32xx HCLK currently clocked at %i kHz", hclk); cycle = (1.0 / hclk) * 1000000.0; return cycle; } static int lpc32xx_init(struct nand_device *nand) { struct lpc32xx_nand_controller *lpc32xx_info = nand->controller_priv; struct target *target = nand->target; int bus_width = nand->bus_width ? : 8; int address_cycles = nand->address_cycles ? : 3; int page_size = nand->page_size ? : 512; int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use LPC32xx " "NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } /* sanitize arguments */ if (bus_width != 8) { LOG_ERROR("LPC32xx doesn't support %i", bus_width); return ERROR_NAND_OPERATION_NOT_SUPPORTED; } /* inform calling code about selected bus width */ nand->bus_width = bus_width; if ((address_cycles < 3) || (address_cycles > 5)) { LOG_ERROR("LPC32xx driver doesn't support %i address cycles", address_cycles); return ERROR_NAND_OPERATION_NOT_SUPPORTED; } if ((page_size != 512) && (page_size != 2048)) { LOG_ERROR("LPC32xx doesn't support page size %i", page_size); return ERROR_NAND_OPERATION_NOT_SUPPORTED; } /* select MLC controller if none is currently selected */ if (lpc32xx_info->selected_controller == LPC32xx_NO_CONTROLLER) { LOG_DEBUG("no LPC32xx NAND flash controller selected, " "using default 'slc'"); lpc32xx_info->selected_controller = LPC32xx_SLC_CONTROLLER; } if (lpc32xx_info->selected_controller == LPC32xx_MLC_CONTROLLER) { uint32_t mlc_icr_value = 0x0; float cycle; int twp, twh, trp, treh, trhz, trbwb, tcea; /* FLASHCLK_CTRL = 0x22 (enable clk for MLC) */ retval = target_write_u32(target, 0x400040c8, 0x22); if (ERROR_OK != retval) { LOG_ERROR("could not set FLASHCLK_CTRL"); return ERROR_NAND_OPERATION_FAILED; } /* MLC_CEH = 0x0 (Force nCE assert) */ retval = target_write_u32(target, 0x200b804c, 0x0); if (ERROR_OK != retval) { LOG_ERROR("could not set MLC_CEH"); return ERROR_NAND_OPERATION_FAILED; } /* MLC_LOCK = 0xa25e (unlock protected registers) */ retval = target_write_u32(target, 0x200b8044, 0xa25e); if (ERROR_OK != retval) { LOG_ERROR("could not set MLC_LOCK"); return ERROR_NAND_OPERATION_FAILED; } /* MLC_ICR = configuration */ if (lpc32xx_info->sw_write_protection) mlc_icr_value |= 0x8; if (page_size == 2048) mlc_icr_value |= 0x4; if (address_cycles == 4) mlc_icr_value |= 0x2; if (bus_width == 16) mlc_icr_value |= 0x1; retval = target_write_u32(target, 0x200b8030, mlc_icr_value); if (ERROR_OK != retval) { LOG_ERROR("could not set MLC_ICR"); return ERROR_NAND_OPERATION_FAILED; } /* calculate NAND controller timings */ cycle = lpc32xx_cycle_time(nand); twp = ((40 / cycle) + 1); twh = ((20 / cycle) + 1); trp = ((30 / cycle) + 1); treh = ((15 / cycle) + 1); trhz = ((30 / cycle) + 1); trbwb = ((100 / cycle) + 1); tcea = ((45 / cycle) + 1); /* MLC_LOCK = 0xa25e (unlock protected registers) */ retval = target_write_u32(target, 0x200b8044, 0xa25e); if (ERROR_OK != retval) { LOG_ERROR("could not set MLC_LOCK"); return ERROR_NAND_OPERATION_FAILED; } /* MLC_TIME_REG */ retval = target_write_u32(target, 0x200b8034, (twp & 0xf) | ((twh & 0xf) << 4) | ((trp & 0xf) << 8) | ((treh & 0xf) << 12) | ((trhz & 0x7) << 16) | ((trbwb & 0x1f) << 19) | ((tcea & 0x3) << 24)); if (ERROR_OK != retval) { LOG_ERROR("could not set MLC_TIME_REG"); return ERROR_NAND_OPERATION_FAILED; } retval = lpc32xx_reset(nand); if (ERROR_OK != retval) return ERROR_NAND_OPERATION_FAILED; } else if (lpc32xx_info->selected_controller == LPC32xx_SLC_CONTROLLER) { float cycle; int r_setup, r_hold, r_width, r_rdy; int w_setup, w_hold, w_width, w_rdy; /* FLASHCLK_CTRL = 0x05 (enable clk for SLC) */ retval = target_write_u32(target, 0x400040c8, 0x05); if (ERROR_OK != retval) { LOG_ERROR("could not set FLASHCLK_CTRL"); return ERROR_NAND_OPERATION_FAILED; } /* after reset set other registers of SLC, * so reset calling is here at the begining */ retval = lpc32xx_reset(nand); if (ERROR_OK != retval) return ERROR_NAND_OPERATION_FAILED; /* SLC_CFG = Force nCE assert, DMA ECC enabled, ECC enabled, DMA burst enabled, DMA read from SLC, WIDTH = bus_width) */ retval = target_write_u32(target, 0x20020014, 0x3e | (bus_width == 16) ? 1 : 0); if (ERROR_OK != retval) { LOG_ERROR("could not set SLC_CFG"); return ERROR_NAND_OPERATION_FAILED; } /* SLC_IEN = 3 (INT_RDY_EN = 1) ,(INT_TC_STAT = 1) */ retval = target_write_u32(target, 0x20020020, 0x03); if (ERROR_OK != retval) { LOG_ERROR("could not set SLC_IEN"); return ERROR_NAND_OPERATION_FAILED; } /* DMA configuration */ /* DMACLK_CTRL = 0x01 (enable clock for DMA controller) */ retval = target_write_u32(target, 0x400040e8, 0x01); if (ERROR_OK != retval) { LOG_ERROR("could not set DMACLK_CTRL"); return ERROR_NAND_OPERATION_FAILED; } /* DMACConfig = DMA enabled*/ retval = target_write_u32(target, 0x31000030, 0x01); if (ERROR_OK != retval) { LOG_ERROR("could not set DMACConfig"); return ERROR_NAND_OPERATION_FAILED; } /* calculate NAND controller timings */ cycle = lpc32xx_cycle_time(nand); r_setup = w_setup = 0; r_hold = w_hold = 10 / cycle; r_width = 30 / cycle; w_width = 40 / cycle; r_rdy = w_rdy = 100 / cycle; /* SLC_TAC: SLC timing arcs register */ retval = target_write_u32(target, 0x2002002c, (r_setup & 0xf) | ((r_hold & 0xf) << 4) | ((r_width & 0xf) << 8) | ((r_rdy & 0xf) << 12) | ((w_setup & 0xf) << 16) | ((w_hold & 0xf) << 20) | ((w_width & 0xf) << 24) | ((w_rdy & 0xf) << 28)); if (ERROR_OK != retval) { LOG_ERROR("could not set SLC_TAC"); return ERROR_NAND_OPERATION_FAILED; } } return ERROR_OK; } static int lpc32xx_reset(struct nand_device *nand) { struct lpc32xx_nand_controller *lpc32xx_info = nand->controller_priv; struct target *target = nand->target; int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use " "LPC32xx NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } if (lpc32xx_info->selected_controller == LPC32xx_NO_CONTROLLER) { LOG_ERROR("BUG: no LPC32xx NAND flash controller selected"); return ERROR_NAND_OPERATION_FAILED; } else if (lpc32xx_info->selected_controller == LPC32xx_MLC_CONTROLLER) { /* MLC_CMD = 0xff (reset controller and NAND device) */ retval = target_write_u32(target, 0x200b8000, 0xff); if (ERROR_OK != retval) { LOG_ERROR("could not set MLC_CMD"); return ERROR_NAND_OPERATION_FAILED; } if (!lpc32xx_controller_ready(nand, 100)) { LOG_ERROR("LPC32xx MLC NAND controller timed out " "after reset"); return ERROR_NAND_OPERATION_TIMEOUT; } } else if (lpc32xx_info->selected_controller == LPC32xx_SLC_CONTROLLER) { /* SLC_CTRL = 0x6 (ECC_CLEAR, SW_RESET) */ retval = target_write_u32(target, 0x20020010, 0x6); if (ERROR_OK != retval) { LOG_ERROR("could not set SLC_CTRL"); return ERROR_NAND_OPERATION_FAILED; } if (!lpc32xx_controller_ready(nand, 100)) { LOG_ERROR("LPC32xx SLC NAND controller timed out " "after reset"); return ERROR_NAND_OPERATION_TIMEOUT; } } return ERROR_OK; } static int lpc32xx_command(struct nand_device *nand, uint8_t command) { struct lpc32xx_nand_controller *lpc32xx_info = nand->controller_priv; struct target *target = nand->target; int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use " "LPC32xx NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } if (lpc32xx_info->selected_controller == LPC32xx_NO_CONTROLLER) { LOG_ERROR("BUG: no LPC32xx NAND flash controller selected"); return ERROR_NAND_OPERATION_FAILED; } else if (lpc32xx_info->selected_controller == LPC32xx_MLC_CONTROLLER) { /* MLC_CMD = command */ retval = target_write_u32(target, 0x200b8000, command); if (ERROR_OK != retval) { LOG_ERROR("could not set MLC_CMD"); return ERROR_NAND_OPERATION_FAILED; } } else if (lpc32xx_info->selected_controller == LPC32xx_SLC_CONTROLLER) { /* SLC_CMD = command */ retval = target_write_u32(target, 0x20020008, command); if (ERROR_OK != retval) { LOG_ERROR("could not set SLC_CMD"); return ERROR_NAND_OPERATION_FAILED; } } return ERROR_OK; } static int lpc32xx_address(struct nand_device *nand, uint8_t address) { struct lpc32xx_nand_controller *lpc32xx_info = nand->controller_priv; struct target *target = nand->target; int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use " "LPC32xx NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } if (lpc32xx_info->selected_controller == LPC32xx_NO_CONTROLLER) { LOG_ERROR("BUG: no LPC32xx NAND flash controller selected"); return ERROR_NAND_OPERATION_FAILED; } else if (lpc32xx_info->selected_controller == LPC32xx_MLC_CONTROLLER) { /* MLC_ADDR = address */ retval = target_write_u32(target, 0x200b8004, address); if (ERROR_OK != retval) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } } else if (lpc32xx_info->selected_controller == LPC32xx_SLC_CONTROLLER) { /* SLC_ADDR = address */ retval = target_write_u32(target, 0x20020004, address); if (ERROR_OK != retval) { LOG_ERROR("could not set SLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } } return ERROR_OK; } static int lpc32xx_write_data(struct nand_device *nand, uint16_t data) { struct lpc32xx_nand_controller *lpc32xx_info = nand->controller_priv; struct target *target = nand->target; int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use " "LPC32xx NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } if (lpc32xx_info->selected_controller == LPC32xx_NO_CONTROLLER) { LOG_ERROR("BUG: no LPC32xx NAND flash controller selected"); return ERROR_NAND_OPERATION_FAILED; } else if (lpc32xx_info->selected_controller == LPC32xx_MLC_CONTROLLER) { /* MLC_DATA = data */ retval = target_write_u32(target, 0x200b0000, data); if (ERROR_OK != retval) { LOG_ERROR("could not set MLC_DATA"); return ERROR_NAND_OPERATION_FAILED; } } else if (lpc32xx_info->selected_controller == LPC32xx_SLC_CONTROLLER) { /* SLC_DATA = data */ retval = target_write_u32(target, 0x20020000, data); if (ERROR_OK != retval) { LOG_ERROR("could not set SLC_DATA"); return ERROR_NAND_OPERATION_FAILED; } } return ERROR_OK; } static int lpc32xx_read_data(struct nand_device *nand, void *data) { struct lpc32xx_nand_controller *lpc32xx_info = nand->controller_priv; struct target *target = nand->target; int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use LPC32xx " "NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } if (lpc32xx_info->selected_controller == LPC32xx_NO_CONTROLLER) { LOG_ERROR("BUG: no LPC32xx NAND flash controller selected"); return ERROR_NAND_OPERATION_FAILED; } else if (lpc32xx_info->selected_controller == LPC32xx_MLC_CONTROLLER) { /* data = MLC_DATA, use sized access */ if (nand->bus_width == 8) { uint8_t *data8 = data; retval = target_read_u8(target, 0x200b0000, data8); } else { LOG_ERROR("BUG: bus_width neither 8 nor 16 bit"); return ERROR_NAND_OPERATION_FAILED; } if (ERROR_OK != retval) { LOG_ERROR("could not read MLC_DATA"); return ERROR_NAND_OPERATION_FAILED; } } else if (lpc32xx_info->selected_controller == LPC32xx_SLC_CONTROLLER) { uint32_t data32; /* data = SLC_DATA, must use 32-bit access */ retval = target_read_u32(target, 0x20020000, &data32); if (ERROR_OK != retval) { LOG_ERROR("could not read SLC_DATA"); return ERROR_NAND_OPERATION_FAILED; } if (nand->bus_width == 8) { uint8_t *data8 = data; *data8 = data32 & 0xff; } else { LOG_ERROR("BUG: bus_width neither 8 nor 16 bit"); return ERROR_NAND_OPERATION_FAILED; } } return ERROR_OK; } static int lpc32xx_write_page_mlc(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { struct target *target = nand->target; int retval; uint8_t status; static uint8_t page_buffer[512]; static uint8_t oob_buffer[6]; int quarter, num_quarters; /* MLC_CMD = sequential input */ retval = target_write_u32(target, 0x200b8000, NAND_CMD_SEQIN); if (ERROR_OK != retval) { LOG_ERROR("could not set MLC_CMD"); return ERROR_NAND_OPERATION_FAILED; } if (nand->page_size == 512) { /* MLC_ADDR = 0x0 (one column cycle) */ retval = target_write_u32(target, 0x200b8004, 0x0); if (ERROR_OK != retval) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } /* MLC_ADDR = row */ retval = target_write_u32(target, 0x200b8004, page & 0xff); if (ERROR_OK != retval) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } retval = target_write_u32(target, 0x200b8004, (page >> 8) & 0xff); if (ERROR_OK != retval) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } if (nand->address_cycles == 4) { retval = target_write_u32(target, 0x200b8004, (page >> 16) & 0xff); if (ERROR_OK != retval) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } } } else { /* MLC_ADDR = 0x0 (two column cycles) */ retval = target_write_u32(target, 0x200b8004, 0x0); if (ERROR_OK != retval) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } retval = target_write_u32(target, 0x200b8004, 0x0); if (ERROR_OK != retval) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } /* MLC_ADDR = row */ retval = target_write_u32(target, 0x200b8004, page & 0xff); if (ERROR_OK != retval) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } retval = target_write_u32(target, 0x200b8004, (page >> 8) & 0xff); if (ERROR_OK != retval) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } } /* when using the MLC controller, we have to treat a large page device * as being made out of four quarters, each the size of a small page * device */ num_quarters = (nand->page_size == 2048) ? 4 : 1; for (quarter = 0; quarter < num_quarters; quarter++) { int thisrun_data_size = (data_size > 512) ? 512 : data_size; int thisrun_oob_size = (oob_size > 6) ? 6 : oob_size; memset(page_buffer, 0xff, 512); if (data) { memcpy(page_buffer, data, thisrun_data_size); data_size -= thisrun_data_size; data += thisrun_data_size; } memset(oob_buffer, 0xff, 6); if (oob) { memcpy(oob_buffer, oob, thisrun_oob_size); oob_size -= thisrun_oob_size; oob += thisrun_oob_size; } /* write MLC_ECC_ENC_REG to start encode cycle */ retval = target_write_u32(target, 0x200b8008, 0x0); if (ERROR_OK != retval) { LOG_ERROR("could not set MLC_ECC_ENC_REG"); return ERROR_NAND_OPERATION_FAILED; } retval = target_write_memory(target, 0x200a8000, 4, 128, page_buffer); if (ERROR_OK != retval) { LOG_ERROR("could not set MLC_BUF (data)"); return ERROR_NAND_OPERATION_FAILED; } retval = target_write_memory(target, 0x200a8000, 1, 6, oob_buffer); if (ERROR_OK != retval) { LOG_ERROR("could not set MLC_BUF (oob)"); return ERROR_NAND_OPERATION_FAILED; } /* write MLC_ECC_AUTO_ENC_REG to start auto encode */ retval = target_write_u32(target, 0x200b8010, 0x0); if (ERROR_OK != retval) { LOG_ERROR("could not set MLC_ECC_AUTO_ENC_REG"); return ERROR_NAND_OPERATION_FAILED; } if (!lpc32xx_controller_ready(nand, 1000)) { LOG_ERROR("timeout while waiting for " "completion of auto encode cycle"); return ERROR_NAND_OPERATION_FAILED; } } /* MLC_CMD = auto program command */ retval = target_write_u32(target, 0x200b8000, NAND_CMD_PAGEPROG); if (ERROR_OK != retval) { LOG_ERROR("could not set MLC_CMD"); return ERROR_NAND_OPERATION_FAILED; } retval = nand_read_status(nand, &status); if (retval != ERROR_OK) { LOG_ERROR("couldn't read status"); return ERROR_NAND_OPERATION_FAILED; } if (status & NAND_STATUS_FAIL) { LOG_ERROR("write operation didn't pass, status: 0x%2.2x", status); return ERROR_NAND_OPERATION_FAILED; } return ERROR_OK; } /* SLC controller in !raw mode will use target cpu to read/write nand from/to * target internal memory. The transfer to/from flash is done by DMA. This * function sets up the dma linked list in host memory for later transfer to * target. */ static int lpc32xx_make_dma_list(uint32_t target_mem_base, uint32_t page_size, int do_read) { uint32_t i, dmasrc, ctrl, ecc_ctrl, oob_ctrl, dmadst; /* DMACCxControl = TransferSize =64, Source burst size =16, Destination burst size = 16, Source transfer width = 32 bit, Destination transfer width = 32 bit, Source AHB master select = M0, Destination AHB master select = M0, Source increment = 0, // set later Destination increment = 0, // set later Terminal count interrupt enable bit = 0 // set on last */ /* * Write Operation Sequence for Small Block NAND * ---------------------------------------------------------- * 1. X'fer 256 bytes of data from Memory to Flash. * 2. Copy generated ECC data from Register to Spare Area * 3. X'fer next 256 bytes of data from Memory to Flash. * 4. Copy generated ECC data from Register to Spare Area. * 5. X'fer 16 byets of Spare area from Memory to Flash. * Read Operation Sequence for Small Block NAND * ---------------------------------------------------------- * 1. X'fer 256 bytes of data from Flash to Memory. * 2. Copy generated ECC data from Register to ECC calc Buffer. * 3. X'fer next 256 bytes of data from Flash to Memory. * 4. Copy generated ECC data from Register to ECC calc Buffer. * 5. X'fer 16 bytes of Spare area from Flash to Memory. * Write Operation Sequence for Large Block NAND * ---------------------------------------------------------- * 1. Steps(1-4) of Write Operations repeate for four times * which generates 16 DMA descriptors to X'fer 2048 bytes of * data & 32 bytes of ECC data. * 2. X'fer 64 bytes of Spare area from Memory to Flash. * Read Operation Sequence for Large Block NAND * ---------------------------------------------------------- * 1. Steps(1-4) of Read Operations repeate for four times * which generates 16 DMA descriptors to X'fer 2048 bytes of * data & 32 bytes of ECC data. * 2. X'fer 64 bytes of Spare area from Flash to Memory. */ ctrl = (0x40 | 3 << 12 | 3 << 15 | 2 << 18 | 2 << 21 | 0 << 24 | 0 << 25 | 0 << 26 | 0 << 27 | 0 << 31); /* DMACCxControl = TransferSize =1, Source burst size =4, Destination burst size = 4, Source transfer width = 32 bit, Destination transfer width = 32 bit, Source AHB master select = M0, Destination AHB master select = M0, Source increment = 0, Destination increment = 1, Terminal count interrupt enable bit = 0 */ ecc_ctrl = 0x01 | 1 << 12 | 1 << 15 | 2 << 18 | 2 << 21 | 0 << 24 | 0 << 25 | 0 << 26 | 1 << 27 | 0 << 31; /* DMACCxControl = TransferSize =16 for lp or 4 for sp, Source burst size =16, Destination burst size = 16, Source transfer width = 32 bit, Destination transfer width = 32 bit, Source AHB master select = M0, Destination AHB master select = M0, Source increment = 0, // set later Destination increment = 0, // set later Terminal count interrupt enable bit = 1 // set on last */ oob_ctrl = (page_size == 2048 ? 0x10 : 0x04) | 3 << 12 | 3 << 15 | 2 << 18 | 2 << 21 | 0 << 24 | 0 << 25 | 0 << 26 | 0 << 27 | 1 << 31; if (do_read) { ctrl |= 1 << 27;/* Destination increment = 1 */ oob_ctrl |= 1 << 27; /* Destination increment = 1 */ dmasrc = 0x20020038; /* SLC_DMA_DATA */ dmadst = target_mem_base + DATA_OFFS; } else { ctrl |= 1 << 26;/* Source increment = 1 */ oob_ctrl |= 1 << 26; /* Source increment = 1 */ dmasrc = target_mem_base + DATA_OFFS; dmadst = 0x20020038; /* SLC_DMA_DATA */ } /* * Write Operation Sequence for Small Block NAND * ---------------------------------------------------------- * 1. X'fer 256 bytes of data from Memory to Flash. * 2. Copy generated ECC data from Register to Spare Area * 3. X'fer next 256 bytes of data from Memory to Flash. * 4. Copy generated ECC data from Register to Spare Area. * 5. X'fer 16 byets of Spare area from Memory to Flash. * Read Operation Sequence for Small Block NAND * ---------------------------------------------------------- * 1. X'fer 256 bytes of data from Flash to Memory. * 2. Copy generated ECC data from Register to ECC calc Buffer. * 3. X'fer next 256 bytes of data from Flash to Memory. * 4. Copy generated ECC data from Register to ECC calc Buffer. * 5. X'fer 16 bytes of Spare area from Flash to Memory. * Write Operation Sequence for Large Block NAND * ---------------------------------------------------------- * 1. Steps(1-4) of Write Operations repeate for four times * which generates 16 DMA descriptors to X'fer 2048 bytes of * data & 32 bytes of ECC data. * 2. X'fer 64 bytes of Spare area from Memory to Flash. * Read Operation Sequence for Large Block NAND * ---------------------------------------------------------- * 1. Steps(1-4) of Read Operations repeate for four times * which generates 16 DMA descriptors to X'fer 2048 bytes of * data & 32 bytes of ECC data. * 2. X'fer 64 bytes of Spare area from Flash to Memory. */ for (i = 0; i < page_size/0x100; i++) { dmalist[i*2].dma_src = (do_read ? dmasrc : (dmasrc + i * 256)); dmalist[i*2].dma_dest = (do_read ? (dmadst + i * 256) : dmadst); dmalist[i*2].next_lli = target_mem_base + (i*2 + 1) * sizeof(dmac_ll_t); dmalist[i*2].next_ctrl = ctrl; dmalist[(i*2) + 1].dma_src = 0x20020034;/* SLC_ECC */ dmalist[(i*2) + 1].dma_dest = target_mem_base + ECC_OFFS + i * 4; dmalist[(i*2) + 1].next_lli = target_mem_base + (i*2 + 2) * sizeof(dmac_ll_t); dmalist[(i*2) + 1].next_ctrl = ecc_ctrl; } if (do_read) dmadst = target_mem_base + SPARE_OFFS; else { dmasrc = target_mem_base + SPARE_OFFS; dmalist[(i*2) - 1].next_lli = 0;/* last link = null on write */ dmalist[(i*2) - 1].next_ctrl |= (1 << 31); /* Set TC enable */ } dmalist[i*2].dma_src = dmasrc; dmalist[i*2].dma_dest = dmadst; dmalist[i*2].next_lli = 0; dmalist[i*2].next_ctrl = oob_ctrl; return i * 2 + 1; /* Number of descriptors */ } static int lpc32xx_start_slc_dma(struct nand_device *nand, uint32_t count, int do_wait) { struct target *target = nand->target; int retval; /* DMACIntTCClear = ch0 */ retval = target_write_u32(target, 0x31000008, 1); if (ERROR_OK != retval) { LOG_ERROR("Could not set DMACIntTCClear"); return retval; } /* DMACIntErrClear = ch0 */ retval = target_write_u32(target, 0x31000010, 1); if (ERROR_OK != retval) { LOG_ERROR("Could not set DMACIntErrClear"); return retval; } /* DMACCxConfig= E=1, SrcPeripheral = 1 (SLC), DestPeripheral = 1 (SLC), FlowCntrl = 2 (Pher -> Mem, DMA), IE = 0, ITC = 0, L= 0, H=0 */ retval = target_write_u32(target, 0x31000110, 1 | 1<<1 | 1<<6 | 2<<11 | 0<<14 | 0<<15 | 0<<16 | 0<<18); if (ERROR_OK != retval) { LOG_ERROR("Could not set DMACC0Config"); return retval; } /* SLC_CTRL = 3 (START DMA), ECC_CLEAR */ retval = target_write_u32(target, 0x20020010, 0x3); if (ERROR_OK != retval) { LOG_ERROR("Could not set SLC_CTRL"); return retval; } /* SLC_ICR = 2, INT_TC_CLR, clear pending TC*/ retval = target_write_u32(target, 0x20020028, 2); if (ERROR_OK != retval) { LOG_ERROR("Could not set SLC_ICR"); return retval; } /* SLC_TC */ retval = target_write_u32(target, 0x20020030, count); if (ERROR_OK != retval) { LOG_ERROR("lpc32xx_start_slc_dma: Could not set SLC_TC"); return retval; } /* Wait finish */ if (do_wait && !lpc32xx_tc_ready(nand, 100)) { LOG_ERROR("timeout while waiting for completion of DMA"); return ERROR_NAND_OPERATION_FAILED; } return retval; } static int lpc32xx_dma_ready(struct nand_device *nand, int timeout) { struct target *target = nand->target; LOG_DEBUG("lpc32xx_dma_ready count start=%d", timeout); do { uint32_t tc_stat; uint32_t err_stat; int retval; /* Read DMACRawIntTCStat */ retval = target_read_u32(target, 0x31000014, &tc_stat); if (ERROR_OK != retval) { LOG_ERROR("Could not read DMACRawIntTCStat"); return 0; } /* Read DMACRawIntErrStat */ retval = target_read_u32(target, 0x31000018, &err_stat); if (ERROR_OK != retval) { LOG_ERROR("Could not read DMACRawIntErrStat"); return 0; } if ((tc_stat | err_stat) & 1) { LOG_DEBUG("lpc32xx_dma_ready count=%d", timeout); if (err_stat & 1) { LOG_ERROR("lpc32xx_dma_ready " "DMA error, aborted"); return 0; } else return 1; } alive_sleep(1); } while (timeout-- > 0); return 0; } static uint32_t slc_ecc_copy_to_buffer(uint8_t *spare, const uint32_t *ecc, int count) { int i; for (i = 0; i < (count * 3); i += 3) { uint32_t ce = ecc[i/3]; ce = ~(ce << 2) & 0xFFFFFF; spare[i+2] = (uint8_t)(ce & 0xFF); ce >>= 8; spare[i+1] = (uint8_t)(ce & 0xFF); ce >>= 8; spare[i] = (uint8_t)(ce & 0xFF); } return 0; } static void lpc32xx_dump_oob(uint8_t *oob, uint32_t oob_size) { int addr = 0; while (oob_size > 0) { LOG_DEBUG("%02x: %02x %02x %02x %02x %02x %02x %02x %02x", addr, oob[0], oob[1], oob[2], oob[3], oob[4], oob[5], oob[6], oob[7]); oob += 8; addr += 8; oob_size -= 8; } } static int lpc32xx_write_page_slc(struct nand_device *nand, struct working_area *pworking_area, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { struct target *target = nand->target; int retval; uint32_t target_mem_base; LOG_DEBUG("SLC write page %x data=%d, oob=%d, " "data_size=%d, oob_size=%d", page, data != 0, oob != 0, data_size, oob_size); target_mem_base = pworking_area->address; /* * Skip writting page which has all 0xFF data as this will * generate 0x0 value. */ if (data && !oob) { uint32_t i, all_ff = 1; for (i = 0; i < data_size; i++) if (data[i] != 0xFF) { all_ff = 0; break; } if (all_ff) return ERROR_OK; } /* Make the dma descriptors in local memory */ int nll = lpc32xx_make_dma_list(target_mem_base, nand->page_size, 0); /* Write them to target. XXX: Assumes host and target have same byte sex. */ retval = target_write_memory(target, target_mem_base, 4, nll * sizeof(dmac_ll_t) / 4, (uint8_t *)dmalist); if (ERROR_OK != retval) { LOG_ERROR("Could not write DMA descriptors to IRAM"); return retval; } retval = nand_page_command(nand, page, NAND_CMD_SEQIN, !data); if (ERROR_OK != retval) { LOG_ERROR("NAND_CMD_SEQIN failed"); return retval; } /* SLC_CFG = Force nCE assert, DMA ECC enabled, ECC enabled, DMA burst enabled, DMA write to SLC, WIDTH = bus_width */ retval = target_write_u32(target, 0x20020014, 0x3c); if (ERROR_OK != retval) { LOG_ERROR("Could not set SLC_CFG"); return retval; } if (data) { /* Write data to target */ static uint8_t fdata[2048]; memset(fdata, 0xFF, nand->page_size); memcpy(fdata, data, data_size); retval = target_write_memory(target, target_mem_base + DATA_OFFS, 4, nand->page_size/4, fdata); if (ERROR_OK != retval) { LOG_ERROR("Could not write data to IRAM"); return retval; } /* Write first decriptor to DMA controller */ retval = target_write_memory(target, 0x31000100, 4, sizeof(dmac_ll_t) / 4, (uint8_t *)dmalist); if (ERROR_OK != retval) { LOG_ERROR("Could not write DMA descriptor to DMAC"); return retval; } /* Start xfer of data from iram to flash using DMA */ int tot_size = nand->page_size; tot_size += tot_size == 2048 ? 64 : 16; retval = lpc32xx_start_slc_dma(nand, tot_size, 0); if (ERROR_OK != retval) { LOG_ERROR("DMA failed"); return retval; } /* Wait for DMA to finish. SLC is not finished at this stage */ if (!lpc32xx_dma_ready(nand, 100)) { LOG_ERROR("Data DMA failed during write"); return ERROR_FLASH_OPERATION_FAILED; } } /* data xfer */ /* Copy OOB to iram */ static uint8_t foob[64]; int foob_size = nand->page_size == 2048 ? 64 : 16; memset(foob, 0xFF, foob_size); if (oob) /* Raw mode */ memcpy(foob, oob, oob_size); else { /* Get HW generated ECC, made while writing data */ int ecc_count = nand->page_size == 2048 ? 8 : 2; static uint32_t hw_ecc[8]; retval = target_read_memory(target, target_mem_base + ECC_OFFS, 4, ecc_count, (uint8_t *)hw_ecc); if (ERROR_OK != retval) { LOG_ERROR("Reading hw generated ECC from IRAM failed"); return retval; } /* Copy to oob, at correct offsets */ static uint8_t ecc[24]; slc_ecc_copy_to_buffer(ecc, hw_ecc, ecc_count); int *layout = nand->page_size == 2048 ? lp_ooblayout : sp_ooblayout; int i; for (i = 0; i < ecc_count * 3; i++) foob[layout[i]] = ecc[i]; lpc32xx_dump_oob(foob, foob_size); } retval = target_write_memory(target, target_mem_base + SPARE_OFFS, 4, foob_size / 4, foob); if (ERROR_OK != retval) { LOG_ERROR("Writing OOB to IRAM failed"); return retval; } /* Write OOB decriptor to DMA controller */ retval = target_write_memory(target, 0x31000100, 4, sizeof(dmac_ll_t) / 4, (uint8_t *)(&dmalist[nll-1])); if (ERROR_OK != retval) { LOG_ERROR("Could not write OOB DMA descriptor to DMAC"); return retval; } if (data) { /* Only restart DMA with last descriptor, * don't setup SLC again */ /* DMACIntTCClear = ch0 */ retval = target_write_u32(target, 0x31000008, 1); if (ERROR_OK != retval) { LOG_ERROR("Could not set DMACIntTCClear"); return retval; } /* DMACCxConfig= * E=1, * SrcPeripheral = 1 (SLC), * DestPeripheral = 1 (SLC), * FlowCntrl = 2 (Pher -> Mem, DMA), * IE = 0, * ITC = 0, * L= 0, * H=0 */ retval = target_write_u32(target, 0x31000110, 1 | 1<<1 | 1<<6 | 2<<11 | 0<<14 | 0<<15 | 0<<16 | 0<<18); if (ERROR_OK != retval) { LOG_ERROR("Could not set DMACC0Config"); return retval; } /* Wait finish */ if (!lpc32xx_tc_ready(nand, 100)) { LOG_ERROR("timeout while waiting for " "completion of DMA"); return ERROR_NAND_OPERATION_FAILED; } } else { /* Start xfer of data from iram to flash using DMA */ retval = lpc32xx_start_slc_dma(nand, foob_size, 1); if (ERROR_OK != retval) { LOG_ERROR("DMA OOB failed"); return retval; } } /* Let NAND start actual writing */ retval = nand_write_finish(nand); if (ERROR_OK != retval) { LOG_ERROR("nand_write_finish failed"); return retval; } return ERROR_OK; } static int lpc32xx_write_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { struct lpc32xx_nand_controller *lpc32xx_info = nand->controller_priv; struct target *target = nand->target; int retval = ERROR_OK; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use LPC32xx " "NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } if (lpc32xx_info->selected_controller == LPC32xx_NO_CONTROLLER) { LOG_ERROR("BUG: no LPC32xx NAND flash controller selected"); return ERROR_NAND_OPERATION_FAILED; } else if (lpc32xx_info->selected_controller == LPC32xx_MLC_CONTROLLER) { if (!data && oob) { LOG_ERROR("LPC32xx MLC controller can't write " "OOB data only"); return ERROR_NAND_OPERATION_NOT_SUPPORTED; } if (oob && (oob_size > 24)) { LOG_ERROR("LPC32xx MLC controller can't write more " "than 6 bytes for each quarter's OOB data"); return ERROR_NAND_OPERATION_NOT_SUPPORTED; } if (data_size > (uint32_t)nand->page_size) { LOG_ERROR("data size exceeds page size"); return ERROR_NAND_OPERATION_NOT_SUPPORTED; } retval = lpc32xx_write_page_mlc(nand, page, data, data_size, oob, oob_size); } else if (lpc32xx_info->selected_controller == LPC32xx_SLC_CONTROLLER) { struct working_area *pworking_area; if (!data && oob) { /* * if oob only mode is active original method is used * as SLC controller hangs during DMA interworking. (?) * Anyway the code supports the oob only mode below. */ return nand_write_page_raw(nand, page, data, data_size, oob, oob_size); } retval = target_alloc_working_area(target, nand->page_size + DATA_OFFS, &pworking_area); if (retval != ERROR_OK) { LOG_ERROR("Can't allocate working area in " "LPC internal RAM"); return ERROR_FLASH_OPERATION_FAILED; } retval = lpc32xx_write_page_slc(nand, pworking_area, page, data, data_size, oob, oob_size); target_free_working_area(target, pworking_area); } return retval; } static int lpc32xx_read_page_mlc(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { struct target *target = nand->target; static uint8_t page_buffer[2048]; static uint8_t oob_buffer[64]; uint32_t page_bytes_done = 0; uint32_t oob_bytes_done = 0; uint32_t mlc_isr; int retval; if (!data && oob) { /* MLC_CMD = Read OOB * we can use the READOOB command on both small and large page * devices, as the controller translates the 0x50 command to * a 0x0 with appropriate positioning of the serial buffer * read pointer */ retval = target_write_u32(target, 0x200b8000, NAND_CMD_READOOB); } else { /* MLC_CMD = Read0 */ retval = target_write_u32(target, 0x200b8000, NAND_CMD_READ0); } if (ERROR_OK != retval) { LOG_ERROR("could not set MLC_CMD"); return ERROR_NAND_OPERATION_FAILED; } if (nand->page_size == 512) { /* small page device * MLC_ADDR = 0x0 (one column cycle) */ retval = target_write_u32(target, 0x200b8004, 0x0); if (ERROR_OK != retval) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } /* MLC_ADDR = row */ retval = target_write_u32(target, 0x200b8004, page & 0xff); if (ERROR_OK != retval) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } retval = target_write_u32(target, 0x200b8004, (page >> 8) & 0xff); if (ERROR_OK != retval) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } if (nand->address_cycles == 4) { retval = target_write_u32(target, 0x200b8004, (page >> 16) & 0xff); if (ERROR_OK != retval) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } } } else { /* large page device * MLC_ADDR = 0x0 (two column cycles) */ retval = target_write_u32(target, 0x200b8004, 0x0); if (ERROR_OK != retval) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } retval = target_write_u32(target, 0x200b8004, 0x0); if (ERROR_OK != retval) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } /* MLC_ADDR = row */ retval = target_write_u32(target, 0x200b8004, page & 0xff); if (ERROR_OK != retval) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } retval = target_write_u32(target, 0x200b8004, (page >> 8) & 0xff); if (ERROR_OK != retval) { LOG_ERROR("could not set MLC_ADDR"); return ERROR_NAND_OPERATION_FAILED; } /* MLC_CMD = Read Start */ retval = target_write_u32(target, 0x200b8000, NAND_CMD_READSTART); if (ERROR_OK != retval) { LOG_ERROR("could not set MLC_CMD"); return ERROR_NAND_OPERATION_FAILED; } } while (page_bytes_done < (uint32_t)nand->page_size) { /* MLC_ECC_AUTO_DEC_REG = dummy */ retval = target_write_u32(target, 0x200b8014, 0xaa55aa55); if (ERROR_OK != retval) { LOG_ERROR("could not set MLC_ECC_AUTO_DEC_REG"); return ERROR_NAND_OPERATION_FAILED; } if (!lpc32xx_controller_ready(nand, 1000)) { LOG_ERROR("timeout while waiting for " "completion of auto decode cycle"); return ERROR_NAND_OPERATION_FAILED; } retval = target_read_u32(target, 0x200b8048, &mlc_isr); if (ERROR_OK != retval) { LOG_ERROR("could not read MLC_ISR"); return ERROR_NAND_OPERATION_FAILED; } if (mlc_isr & 0x8) { if (mlc_isr & 0x40) { LOG_ERROR("uncorrectable error detected: " "0x%2.2x", (unsigned)mlc_isr); return ERROR_NAND_OPERATION_FAILED; } LOG_WARNING("%i symbol error detected and corrected", ((int)(((mlc_isr & 0x30) >> 4) + 1))); } if (data) { retval = target_read_memory(target, 0x200a8000, 4, 128, page_buffer + page_bytes_done); if (ERROR_OK != retval) { LOG_ERROR("could not read MLC_BUF (data)"); return ERROR_NAND_OPERATION_FAILED; } } if (oob) { retval = target_read_memory(target, 0x200a8000, 4, 4, oob_buffer + oob_bytes_done); if (ERROR_OK != retval) { LOG_ERROR("could not read MLC_BUF (oob)"); return ERROR_NAND_OPERATION_FAILED; } } page_bytes_done += 512; oob_bytes_done += 16; } if (data) memcpy(data, page_buffer, data_size); if (oob) memcpy(oob, oob_buffer, oob_size); return ERROR_OK; } static int lpc32xx_read_page_slc(struct nand_device *nand, struct working_area *pworking_area, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { struct target *target = nand->target; int retval; uint32_t target_mem_base; LOG_DEBUG("SLC read page %x data=%d, oob=%d", page, data_size, oob_size); target_mem_base = pworking_area->address; /* Make the dma descriptors in local memory */ int nll = lpc32xx_make_dma_list(target_mem_base, nand->page_size, 1); /* Write them to target. XXX: Assumes host and target have same byte sex. */ retval = target_write_memory(target, target_mem_base, 4, nll * sizeof(dmac_ll_t) / 4, (uint8_t *)dmalist); if (ERROR_OK != retval) { LOG_ERROR("Could not write DMA descriptors to IRAM"); return retval; } retval = nand_page_command(nand, page, NAND_CMD_READ0, 0); if (ERROR_OK != retval) { LOG_ERROR("lpc32xx_read_page_slc: NAND_CMD_READ0 failed"); return retval; } /* SLC_CFG = Force nCE assert, DMA ECC enabled, ECC enabled, DMA burst enabled, DMA read from SLC, WIDTH = bus_width */ retval = target_write_u32(target, 0x20020014, 0x3e); if (ERROR_OK != retval) { LOG_ERROR("lpc32xx_read_page_slc: Could not set SLC_CFG"); return retval; } /* Write first decriptor to DMA controller */ retval = target_write_memory(target, 0x31000100, 4, sizeof(dmac_ll_t) / 4, (uint8_t *)dmalist); if (ERROR_OK != retval) { LOG_ERROR("Could not write DMA descriptor to DMAC"); return retval; } /* Start xfer of data from flash to iram using DMA */ int tot_size = nand->page_size; tot_size += nand->page_size == 2048 ? 64 : 16; retval = lpc32xx_start_slc_dma(nand, tot_size, 1); if (ERROR_OK != retval) { LOG_ERROR("lpc32xx_read_page_slc: DMA read failed"); return retval; } /* Copy data from iram */ if (data) { retval = target_read_memory(target, target_mem_base + DATA_OFFS, 4, data_size/4, data); if (ERROR_OK != retval) { LOG_ERROR("Could not read data from IRAM"); return retval; } } if (oob) { /* No error correction, just return data as read from flash */ retval = target_read_memory(target, target_mem_base + SPARE_OFFS, 4, oob_size/4, oob); if (ERROR_OK != retval) { LOG_ERROR("Could not read OOB from IRAM"); return retval; } return ERROR_OK; } /* Copy OOB from flash, stored in IRAM */ static uint8_t foob[64]; retval = target_read_memory(target, target_mem_base + SPARE_OFFS, 4, nand->page_size == 2048 ? 16 : 4, foob); lpc32xx_dump_oob(foob, nand->page_size == 2048 ? 64 : 16); if (ERROR_OK != retval) { LOG_ERROR("Could not read OOB from IRAM"); return retval; } /* Copy ECC from HW, generated while reading */ int ecc_count = nand->page_size == 2048 ? 8 : 2; static uint32_t hw_ecc[8]; /* max size */ retval = target_read_memory(target, target_mem_base + ECC_OFFS, 4, ecc_count, (uint8_t *)hw_ecc); if (ERROR_OK != retval) { LOG_ERROR("Could not read hw generated ECC from IRAM"); return retval; } static uint8_t ecc[24]; slc_ecc_copy_to_buffer(ecc, hw_ecc, ecc_count); /* Copy ECC from flash using correct layout */ static uint8_t fecc[24];/* max size */ int *layout = nand->page_size == 2048 ? lp_ooblayout : sp_ooblayout; int i; for (i = 0; i < ecc_count * 3; i++) fecc[i] = foob[layout[i]]; /* Compare ECC and possibly correct data */ for (i = 0; i < ecc_count; i++) { retval = nand_correct_data(nand, data + 256*i, &fecc[i * 3], &ecc[i * 3]); if (retval > 0) LOG_WARNING("error detected and corrected: %d/%d", page, i); if (retval < 0) break; } if (i == ecc_count) retval = ERROR_OK; else { LOG_ERROR("uncorrectable error detected: %d/%d", page, i); retval = ERROR_NAND_OPERATION_FAILED; } return retval; } static int lpc32xx_read_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { struct lpc32xx_nand_controller *lpc32xx_info = nand->controller_priv; struct target *target = nand->target; int retval = ERROR_OK; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use LPC32xx " "NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } if (lpc32xx_info->selected_controller == LPC32xx_NO_CONTROLLER) { LOG_ERROR("BUG: no LPC32xx NAND flash controller selected"); return ERROR_NAND_OPERATION_FAILED; } else if (lpc32xx_info->selected_controller == LPC32xx_MLC_CONTROLLER) { if (data_size > (uint32_t)nand->page_size) { LOG_ERROR("data size exceeds page size"); return ERROR_NAND_OPERATION_NOT_SUPPORTED; } retval = lpc32xx_read_page_mlc(nand, page, data, data_size, oob, oob_size); } else if (lpc32xx_info->selected_controller == LPC32xx_SLC_CONTROLLER) { struct working_area *pworking_area; retval = target_alloc_working_area(target, nand->page_size + 0x200, &pworking_area); if (retval != ERROR_OK) { LOG_ERROR("Can't allocate working area in " "LPC internal RAM"); return ERROR_FLASH_OPERATION_FAILED; } retval = lpc32xx_read_page_slc(nand, pworking_area, page, data, data_size, oob, oob_size); target_free_working_area(target, pworking_area); } return retval; } static int lpc32xx_controller_ready(struct nand_device *nand, int timeout) { struct lpc32xx_nand_controller *lpc32xx_info = nand->controller_priv; struct target *target = nand->target; int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use LPC32xx " "NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } LOG_DEBUG("lpc32xx_controller_ready count start=%d", timeout); do { if (lpc32xx_info->selected_controller == LPC32xx_MLC_CONTROLLER) { uint8_t status; /* Read MLC_ISR, wait for controller to become ready */ retval = target_read_u8(target, 0x200b8048, &status); if (ERROR_OK != retval) { LOG_ERROR("could not set MLC_STAT"); return ERROR_NAND_OPERATION_FAILED; } if (status & 2) { LOG_DEBUG("lpc32xx_controller_ready count=%d", timeout); return 1; } } else if (lpc32xx_info->selected_controller == LPC32xx_SLC_CONTROLLER) { uint32_t status; /* Read SLC_STAT and check READY bit */ retval = target_read_u32(target, 0x20020018, &status); if (ERROR_OK != retval) { LOG_ERROR("could not set SLC_STAT"); return ERROR_NAND_OPERATION_FAILED; } if (status & 1) { LOG_DEBUG("lpc32xx_controller_ready count=%d", timeout); return 1; } } alive_sleep(1); } while (timeout-- > 0); return 0; } static int lpc32xx_nand_ready(struct nand_device *nand, int timeout) { struct lpc32xx_nand_controller *lpc32xx_info = nand->controller_priv; struct target *target = nand->target; int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use LPC32xx " "NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } LOG_DEBUG("lpc32xx_nand_ready count start=%d", timeout); do { if (lpc32xx_info->selected_controller == LPC32xx_MLC_CONTROLLER) { uint8_t status = 0x0; /* Read MLC_ISR, wait for NAND flash device to * become ready */ retval = target_read_u8(target, 0x200b8048, &status); if (ERROR_OK != retval) { LOG_ERROR("could not read MLC_ISR"); return ERROR_NAND_OPERATION_FAILED; } if (status & 1) { LOG_DEBUG("lpc32xx_nand_ready count end=%d", timeout); return 1; } } else if (lpc32xx_info->selected_controller == LPC32xx_SLC_CONTROLLER) { uint32_t status = 0x0; /* Read SLC_STAT and check READY bit */ retval = target_read_u32(target, 0x20020018, &status); if (ERROR_OK != retval) { LOG_ERROR("could not read SLC_STAT"); return ERROR_NAND_OPERATION_FAILED; } if (status & 1) { LOG_DEBUG("lpc32xx_nand_ready count end=%d", timeout); return 1; } } alive_sleep(1); } while (timeout-- > 0); return 0; } static int lpc32xx_tc_ready(struct nand_device *nand, int timeout) { struct target *target = nand->target; LOG_DEBUG("lpc32xx_tc_ready count start=%d", timeout); do { uint32_t status = 0x0; int retval; /* Read SLC_INT_STAT and check INT_TC_STAT bit */ retval = target_read_u32(target, 0x2002001c, &status); if (ERROR_OK != retval) { LOG_ERROR("Could not read SLC_INT_STAT"); return 0; } if (status & 2) { LOG_DEBUG("lpc32xx_tc_ready count=%d", timeout); return 1; } alive_sleep(1); } while (timeout-- > 0); return 0; } COMMAND_HANDLER(handle_lpc32xx_select_command) { struct lpc32xx_nand_controller *lpc32xx_info = NULL; char *selected[] = { "no", "mlc", "slc" }; if ((CMD_ARGC < 1) || (CMD_ARGC > 3)) return ERROR_COMMAND_SYNTAX_ERROR; unsigned num; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num); struct nand_device *nand = get_nand_device_by_num(num); if (!nand) { command_print(CMD_CTX, "nand device '#%s' is out of bounds", CMD_ARGV[0]); return ERROR_OK; } lpc32xx_info = nand->controller_priv; if (CMD_ARGC >= 2) { if (strcmp(CMD_ARGV[1], "mlc") == 0) { lpc32xx_info->selected_controller = LPC32xx_MLC_CONTROLLER; } else if (strcmp(CMD_ARGV[1], "slc") == 0) { lpc32xx_info->selected_controller = LPC32xx_SLC_CONTROLLER; } else return ERROR_COMMAND_SYNTAX_ERROR; } command_print(CMD_CTX, "%s controller selected", selected[lpc32xx_info->selected_controller]); return ERROR_OK; } static const struct command_registration lpc32xx_exec_command_handlers[] = { { .name = "select", .handler = handle_lpc32xx_select_command, .mode = COMMAND_EXEC, .help = "select MLC or SLC controller (default is MLC)", .usage = "bank_id ['mlc'|'slc' ]", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration lpc32xx_command_handler[] = { { .name = "lpc32xx", .mode = COMMAND_ANY, .help = "LPC32xx NAND flash controller commands", .usage = "", .chain = lpc32xx_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct nand_flash_controller lpc32xx_nand_controller = { .name = "lpc32xx", .commands = lpc32xx_command_handler, .nand_device_command = lpc32xx_nand_device_command, .init = lpc32xx_init, .reset = lpc32xx_reset, .command = lpc32xx_command, .address = lpc32xx_address, .write_data = lpc32xx_write_data, .read_data = lpc32xx_read_data, .write_page = lpc32xx_write_page, .read_page = lpc32xx_read_page, .nand_ready = lpc32xx_nand_ready, }; openocd-0.7.0/src/flash/nand/ecc_kw.c0000644000175000001440000001060712134336410014266 00000000000000/* * Reed-Solomon ECC handling for the Marvell Kirkwood SOC * Copyright (C) 2009 Marvell Semiconductor, Inc. * * Authors: Lennert Buytenhek * Nicolas Pitre * * 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 or (at your option) any * later version. * * This file 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. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "core.h" /***************************************************************************** * Arithmetic in GF(2^10) ("F") modulo x^10 + x^3 + 1. * * For multiplication, a discrete log/exponent table is used, with * primitive element x (F is a primitive field, so x is primitive). */ #define MODPOLY 0x409 /* x^10 + x^3 + 1 in binary */ /* * Maps an integer a [0..1022] to a polynomial b = gf_exp[a] in * GF(2^10) mod x^10 + x^3 + 1 such that b = x ^ a. There's two * identical copies of this array back-to-back so that we can save * the mod 1023 operation when doing a GF multiplication. */ static uint16_t gf_exp[1023 + 1023]; /* * Maps a polynomial b in GF(2^10) mod x^10 + x^3 + 1 to an index * a = gf_log[b] in [0..1022] such that b = x ^ a. */ static uint16_t gf_log[1024]; static void gf_build_log_exp_table(void) { int i; int p_i; /* * p_i = x ^ i * * Initialise to 1 for i = 0. */ p_i = 1; for (i = 0; i < 1023; i++) { gf_exp[i] = p_i; gf_exp[i + 1023] = p_i; gf_log[p_i] = i; /* * p_i = p_i * x */ p_i <<= 1; if (p_i & (1 << 10)) p_i ^= MODPOLY; } } /***************************************************************************** * Reed-Solomon code * * This implements a (1023,1015) Reed-Solomon ECC code over GF(2^10) * mod x^10 + x^3 + 1, shortened to (520,512). The ECC data consists * of 8 10-bit symbols, or 10 8-bit bytes. * * Given 512 bytes of data, computes 10 bytes of ECC. * * This is done by converting the 512 bytes to 512 10-bit symbols * (elements of F), interpreting those symbols as a polynomial in F[X] * by taking symbol 0 as the coefficient of X^8 and symbol 511 as the * coefficient of X^519, and calculating the residue of that polynomial * divided by the generator polynomial, which gives us the 8 ECC symbols * as the remainder. Finally, we convert the 8 10-bit ECC symbols to 10 * 8-bit bytes. * * The generator polynomial is hardcoded, as that is faster, but it * can be computed by taking the primitive element a = x (in F), and * constructing a polynomial in F[X] with roots a, a^2, a^3, ..., a^8 * by multiplying the minimal polynomials for those roots (which are * just 'x - a^i' for each i). * * Note: due to unfortunate circumstances, the bootrom in the Kirkwood SOC * expects the ECC to be computed backward, i.e. from the last byte down * to the first one. */ int nand_calculate_ecc_kw(struct nand_device *nand, const uint8_t *data, uint8_t *ecc) { unsigned int r7, r6, r5, r4, r3, r2, r1, r0; int i; static int tables_initialized; if (!tables_initialized) { gf_build_log_exp_table(); tables_initialized = 1; } /* * Load bytes 504..511 of the data into r. */ r0 = data[504]; r1 = data[505]; r2 = data[506]; r3 = data[507]; r4 = data[508]; r5 = data[509]; r6 = data[510]; r7 = data[511]; /* * Shift bytes 503..0 (in that order) into r0, followed * by eight zero bytes, while reducing the polynomial by the * generator polynomial in every step. */ for (i = 503; i >= -8; i--) { unsigned int d; d = 0; if (i >= 0) d = data[i]; if (r7) { uint16_t *t = gf_exp + gf_log[r7]; r7 = r6 ^ t[0x21c]; r6 = r5 ^ t[0x181]; r5 = r4 ^ t[0x18e]; r4 = r3 ^ t[0x25f]; r3 = r2 ^ t[0x197]; r2 = r1 ^ t[0x193]; r1 = r0 ^ t[0x237]; r0 = d ^ t[0x024]; } else { r7 = r6; r6 = r5; r5 = r4; r4 = r3; r3 = r2; r2 = r1; r1 = r0; r0 = d; } } ecc[0] = r0; ecc[1] = (r0 >> 8) | (r1 << 2); ecc[2] = (r1 >> 6) | (r2 << 4); ecc[3] = (r2 >> 4) | (r3 << 6); ecc[4] = (r3 >> 2); ecc[5] = r4; ecc[6] = (r4 >> 8) | (r5 << 2); ecc[7] = (r5 >> 6) | (r6 << 4); ecc[8] = (r6 >> 4) | (r7 << 6); ecc[9] = (r7 >> 2); return 0; } openocd-0.7.0/src/flash/nand/s3c24xx_regs.h0000644000175000001440000001276212134336410015302 00000000000000/*************************************************************************** * Copyright (C) 2004, 2005 by Simtec Electronics * * linux@simtec.co.uk * * http://www.simtec.co.uk/products/SWLINUX/ * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; version 2 of the License. * * * * 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. * ***************************************************************************/ /* * S3C2410 NAND register definitions */ #ifndef __ASM_ARM_REGS_NAND #define __ASM_ARM_REGS_NAND #define S3C2410_NFREG(x) (x) #define S3C2410_NFCONF S3C2410_NFREG(0x00) #define S3C2410_NFCMD S3C2410_NFREG(0x04) #define S3C2410_NFADDR S3C2410_NFREG(0x08) #define S3C2410_NFDATA S3C2410_NFREG(0x0C) #define S3C2410_NFSTAT S3C2410_NFREG(0x10) #define S3C2410_NFECC S3C2410_NFREG(0x14) #define S3C2440_NFCONT S3C2410_NFREG(0x04) #define S3C2440_NFCMD S3C2410_NFREG(0x08) #define S3C2440_NFADDR S3C2410_NFREG(0x0C) #define S3C2440_NFDATA S3C2410_NFREG(0x10) #define S3C2440_NFECCD0 S3C2410_NFREG(0x14) #define S3C2440_NFECCD1 S3C2410_NFREG(0x18) #define S3C2440_NFECCD S3C2410_NFREG(0x1C) #define S3C2440_NFSTAT S3C2410_NFREG(0x20) #define S3C2440_NFESTAT0 S3C2410_NFREG(0x24) #define S3C2440_NFESTAT1 S3C2410_NFREG(0x28) #define S3C2440_NFMECC0 S3C2410_NFREG(0x2C) #define S3C2440_NFMECC1 S3C2410_NFREG(0x30) #define S3C2440_NFSECC S3C2410_NFREG(0x34) #define S3C2440_NFSBLK S3C2410_NFREG(0x38) #define S3C2440_NFEBLK S3C2410_NFREG(0x3C) #define S3C2412_NFSBLK S3C2410_NFREG(0x20) #define S3C2412_NFEBLK S3C2410_NFREG(0x24) #define S3C2412_NFSTAT S3C2410_NFREG(0x28) #define S3C2412_NFMECC_ERR0 S3C2410_NFREG(0x2C) #define S3C2412_NFMECC_ERR1 S3C2410_NFREG(0x30) #define S3C2412_NFMECC0 S3C2410_NFREG(0x34) #define S3C2412_NFMECC1 S3C2410_NFREG(0x38) #define S3C2412_NFSECC S3C2410_NFREG(0x3C) #define S3C2410_NFCONF_EN (1 << 15) #define S3C2410_NFCONF_512BYTE (1 << 14) #define S3C2410_NFCONF_4STEP (1 << 13) #define S3C2410_NFCONF_INITECC (1 << 12) #define S3C2410_NFCONF_nFCE (1 << 11) #define S3C2410_NFCONF_TACLS(x) ((x) << 8) #define S3C2410_NFCONF_TWRPH0(x) ((x) << 4) #define S3C2410_NFCONF_TWRPH1(x) ((x) << 0) #define S3C2410_NFSTAT_BUSY (1 << 0) #define S3C2440_NFCONF_BUSWIDTH_8 (0 << 0) #define S3C2440_NFCONF_BUSWIDTH_16 (1 << 0) #define S3C2440_NFCONF_ADVFLASH (1 << 3) #define S3C2440_NFCONF_TACLS(x) ((x) << 12) #define S3C2440_NFCONF_TWRPH0(x) ((x) << 8) #define S3C2440_NFCONF_TWRPH1(x) ((x) << 4) #define S3C2440_NFCONT_LOCKTIGHT (1 << 13) #define S3C2440_NFCONT_SOFTLOCK (1 << 12) #define S3C2440_NFCONT_ILLEGALACC_EN (1 << 10) #define S3C2440_NFCONT_RNBINT_EN (1 << 9) #define S3C2440_NFCONT_RN_FALLING (1 << 8) #define S3C2440_NFCONT_SPARE_ECCLOCK (1 << 6) #define S3C2440_NFCONT_MAIN_ECCLOCK (1 << 5) #define S3C2440_NFCONT_INITECC (1 << 4) #define S3C2440_NFCONT_nFCE (1 << 1) #define S3C2440_NFCONT_ENABLE (1 << 0) #define S3C2440_NFSTAT_READY (1 << 0) #define S3C2440_NFSTAT_nCE (1 << 1) #define S3C2440_NFSTAT_RnB_CHANGE (1 << 2) #define S3C2440_NFSTAT_ILLEGAL_ACCESS (1 << 3) #define S3C2412_NFCONF_NANDBOOT (1 << 31) #define S3C2412_NFCONF_ECCCLKCON (1 << 30) #define S3C2412_NFCONF_ECC_MLC (1 << 24) #define S3C2412_NFCONF_TACLS_MASK (7 << 12) /* 1 extra bit of Tacls */ #define S3C2412_NFCONT_ECC4_DIRWR (1 << 18) #define S3C2412_NFCONT_LOCKTIGHT (1 << 17) #define S3C2412_NFCONT_SOFTLOCK (1 << 16) #define S3C2412_NFCONT_ECC4_ENCINT (1 << 13) #define S3C2412_NFCONT_ECC4_DECINT (1 << 12) #define S3C2412_NFCONT_MAIN_ECC_LOCK (1 << 7) #define S3C2412_NFCONT_INIT_MAIN_ECC (1 << 5) #define S3C2412_NFCONT_nFCE1 (1 << 2) #define S3C2412_NFCONT_nFCE0 (1 << 1) #define S3C2412_NFSTAT_ECC_ENCDONE (1 << 7) #define S3C2412_NFSTAT_ECC_DECDONE (1 << 6) #define S3C2412_NFSTAT_ILLEGAL_ACCESS (1 << 5) #define S3C2412_NFSTAT_RnB_CHANGE (1 << 4) #define S3C2412_NFSTAT_nFCE1 (1 << 3) #define S3C2412_NFSTAT_nFCE0 (1 << 2) #define S3C2412_NFSTAT_Res1 (1 << 1) #define S3C2412_NFSTAT_READY (1 << 0) #define S3C2412_NFECCERR_SERRDATA(x) (((x) >> 21) & 0xf) #define S3C2412_NFECCERR_SERRBIT(x) (((x) >> 18) & 0x7) #define S3C2412_NFECCERR_MERRDATA(x) (((x) >> 7) & 0x3ff) #define S3C2412_NFECCERR_MERRBIT(x) (((x) >> 4) & 0x7) #define S3C2412_NFECCERR_SPARE_ERR(x) (((x) >> 2) & 0x3) #define S3C2412_NFECCERR_MAIN_ERR(x) (((x) >> 2) & 0x3) #define S3C2412_NFECCERR_NONE (0) #define S3C2412_NFECCERR_1BIT (1) #define S3C2412_NFECCERR_MULTIBIT (2) #define S3C2412_NFECCERR_ECCAREA (3) #endif /* __ASM_ARM_REGS_NAND */ openocd-0.7.0/src/flash/nand/lpc3180.c0000644000175000001440000012710412134336410014126 00000000000000/*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * Copyright (C) 2010 richard vegh * * Copyright (C) 2010 Oyvind Harboe * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "lpc3180.h" #include static int lpc3180_reset(struct nand_device *nand); static int lpc3180_controller_ready(struct nand_device *nand, int timeout); static int lpc3180_tc_ready(struct nand_device *nand, int timeout); #define ECC_OFFS 0x120 #define SPARE_OFFS 0x140 #define DATA_OFFS 0x200 /* nand device lpc3180 */ NAND_DEVICE_COMMAND_HANDLER(lpc3180_nand_device_command) { if (CMD_ARGC < 3) return ERROR_COMMAND_SYNTAX_ERROR; uint32_t osc_freq; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], osc_freq); struct lpc3180_nand_controller *lpc3180_info; lpc3180_info = malloc(sizeof(struct lpc3180_nand_controller)); nand->controller_priv = lpc3180_info; lpc3180_info->osc_freq = osc_freq; if ((lpc3180_info->osc_freq < 1000) || (lpc3180_info->osc_freq > 20000)) LOG_WARNING( "LPC3180 oscillator frequency should be between 1000 and 20000 kHz, was %i", lpc3180_info->osc_freq); lpc3180_info->selected_controller = LPC3180_NO_CONTROLLER; lpc3180_info->sw_write_protection = 0; lpc3180_info->sw_wp_lower_bound = 0x0; lpc3180_info->sw_wp_upper_bound = 0x0; return ERROR_OK; } static int lpc3180_pll(int fclkin, uint32_t pll_ctrl) { int bypass = (pll_ctrl & 0x8000) >> 15; int direct = (pll_ctrl & 0x4000) >> 14; int feedback = (pll_ctrl & 0x2000) >> 13; int p = (1 << ((pll_ctrl & 0x1800) >> 11) * 2); int n = ((pll_ctrl & 0x0600) >> 9) + 1; int m = ((pll_ctrl & 0x01fe) >> 1) + 1; int lock = (pll_ctrl & 0x1); if (!lock) LOG_WARNING("PLL is not locked"); if (!bypass && direct) /* direct mode */ return (m * fclkin) / n; if (bypass && !direct) /* bypass mode */ return fclkin / (2 * p); if (bypass & direct) /* direct bypass mode */ return fclkin; if (feedback) /* integer mode */ return m * (fclkin / n); else /* non-integer mode */ return (m / (2 * p)) * (fclkin / n); } static float lpc3180_cycle_time(struct nand_device *nand) { struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; struct target *target = nand->target; uint32_t sysclk_ctrl, pwr_ctrl, hclkdiv_ctrl, hclkpll_ctrl; int sysclk; int hclk; int hclk_pll; float cycle; /* calculate timings */ /* determine current SYSCLK (13'MHz or main oscillator) */ target_read_u32(target, 0x40004050, &sysclk_ctrl); if ((sysclk_ctrl & 1) == 0) sysclk = lpc3180_info->osc_freq; else sysclk = 13000; /* determine selected HCLK source */ target_read_u32(target, 0x40004044, &pwr_ctrl); if ((pwr_ctrl & (1 << 2)) == 0) /* DIRECT RUN mode */ hclk = sysclk; else { target_read_u32(target, 0x40004058, &hclkpll_ctrl); hclk_pll = lpc3180_pll(sysclk, hclkpll_ctrl); target_read_u32(target, 0x40004040, &hclkdiv_ctrl); if (pwr_ctrl & (1 << 10)) /* ARM_CLK and HCLK use PERIPH_CLK */ hclk = hclk_pll / (((hclkdiv_ctrl & 0x7c) >> 2) + 1); else /* HCLK uses HCLK_PLL */ hclk = hclk_pll / (1 << (hclkdiv_ctrl & 0x3)); } LOG_DEBUG("LPC3180 HCLK currently clocked at %i kHz", hclk); cycle = (1.0 / hclk) * 1000000.0; return cycle; } static int lpc3180_init(struct nand_device *nand) { struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; struct target *target = nand->target; int bus_width = nand->bus_width ? : 8; int address_cycles = nand->address_cycles ? : 3; int page_size = nand->page_size ? : 512; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } /* sanitize arguments */ if ((bus_width != 8) && (bus_width != 16)) { LOG_ERROR("LPC3180 only supports 8 or 16 bit bus width, not %i", bus_width); return ERROR_NAND_OPERATION_NOT_SUPPORTED; } /* The LPC3180 only brings out 8 bit NAND data bus, but the controller * would support 16 bit, too, so we just warn about this for now */ if (bus_width == 16) LOG_WARNING("LPC3180 only supports 8 bit bus width"); /* inform calling code about selected bus width */ nand->bus_width = bus_width; if ((address_cycles != 3) && (address_cycles != 4)) { LOG_ERROR("LPC3180 only supports 3 or 4 address cycles, not %i", address_cycles); return ERROR_NAND_OPERATION_NOT_SUPPORTED; } if ((page_size != 512) && (page_size != 2048)) { LOG_ERROR("LPC3180 only supports 512 or 2048 byte pages, not %i", page_size); return ERROR_NAND_OPERATION_NOT_SUPPORTED; } /* select MLC controller if none is currently selected */ if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER) { LOG_DEBUG("no LPC3180 NAND flash controller selected, using default 'mlc'"); lpc3180_info->selected_controller = LPC3180_MLC_CONTROLLER; } if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) { uint32_t mlc_icr_value = 0x0; float cycle; int twp, twh, trp, treh, trhz, trbwb, tcea; /* FLASHCLK_CTRL = 0x22 (enable clock for MLC flash controller) */ target_write_u32(target, 0x400040c8, 0x22); /* MLC_CEH = 0x0 (Force nCE assert) */ target_write_u32(target, 0x200b804c, 0x0); /* MLC_LOCK = 0xa25e (unlock protected registers) */ target_write_u32(target, 0x200b8044, 0xa25e); /* MLC_ICR = configuration */ if (lpc3180_info->sw_write_protection) mlc_icr_value |= 0x8; if (page_size == 2048) mlc_icr_value |= 0x4; if (address_cycles == 4) mlc_icr_value |= 0x2; if (bus_width == 16) mlc_icr_value |= 0x1; target_write_u32(target, 0x200b8030, mlc_icr_value); /* calculate NAND controller timings */ cycle = lpc3180_cycle_time(nand); twp = ((40 / cycle) + 1); twh = ((20 / cycle) + 1); trp = ((30 / cycle) + 1); treh = ((15 / cycle) + 1); trhz = ((30 / cycle) + 1); trbwb = ((100 / cycle) + 1); tcea = ((45 / cycle) + 1); /* MLC_LOCK = 0xa25e (unlock protected registers) */ target_write_u32(target, 0x200b8044, 0xa25e); /* MLC_TIME_REG */ target_write_u32(target, 0x200b8034, (twp & 0xf) | ((twh & 0xf) << 4) | ((trp & 0xf) << 8) | ((treh & 0xf) << 12) | ((trhz & 0x7) << 16) | ((trbwb & 0x1f) << 19) | ((tcea & 0x3) << 24)); lpc3180_reset(nand); } else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) { float cycle; int r_setup, r_hold, r_width, r_rdy; int w_setup, w_hold, w_width, w_rdy; /* FLASHCLK_CTRL = 0x05 (enable clock for SLC flash controller) */ target_write_u32(target, 0x400040c8, 0x05); /* after reset set other registers of SLC so reset calling is here at the begining*/ lpc3180_reset(nand); /* SLC_CFG = 0x (Force nCE assert, DMA ECC enabled, ECC enabled, DMA burst enabled, *DMA read from SLC, WIDTH = bus_width) */ target_write_u32(target, 0x20020014, 0x3e | (bus_width == 16) ? 1 : 0); /* SLC_IEN = 3 (INT_RDY_EN = 1) ,(INT_TC_STAT = 1) */ target_write_u32(target, 0x20020020, 0x03); /* DMA configuration * DMACLK_CTRL = 0x01 (enable clock for DMA controller) */ target_write_u32(target, 0x400040e8, 0x01); /* DMACConfig = DMA enabled*/ target_write_u32(target, 0x31000030, 0x01); /* calculate NAND controller timings */ cycle = lpc3180_cycle_time(nand); r_setup = w_setup = 0; r_hold = w_hold = 10 / cycle; r_width = 30 / cycle; w_width = 40 / cycle; r_rdy = w_rdy = 100 / cycle; /* SLC_TAC: SLC timing arcs register */ target_write_u32(target, 0x2002002c, (r_setup & 0xf) | ((r_hold & 0xf) << 4) | ((r_width & 0xf) << 8) | ((r_rdy & 0xf) << 12) | ((w_setup & 0xf) << 16) | ((w_hold & 0xf) << 20) | ((w_width & 0xf) << 24) | ((w_rdy & 0xf) << 28)); } return ERROR_OK; } static int lpc3180_reset(struct nand_device *nand) { struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; struct target *target = nand->target; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER) { LOG_ERROR("BUG: no LPC3180 NAND flash controller selected"); return ERROR_NAND_OPERATION_FAILED; } else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) { /* MLC_CMD = 0xff (reset controller and NAND device) */ target_write_u32(target, 0x200b8000, 0xff); if (!lpc3180_controller_ready(nand, 100)) { LOG_ERROR("LPC3180 NAND controller timed out after reset"); return ERROR_NAND_OPERATION_TIMEOUT; } } else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) { /* SLC_CTRL = 0x6 (ECC_CLEAR, SW_RESET) */ target_write_u32(target, 0x20020010, 0x6); if (!lpc3180_controller_ready(nand, 100)) { LOG_ERROR("LPC3180 NAND controller timed out after reset"); return ERROR_NAND_OPERATION_TIMEOUT; } } return ERROR_OK; } static int lpc3180_command(struct nand_device *nand, uint8_t command) { struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; struct target *target = nand->target; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER) { LOG_ERROR("BUG: no LPC3180 NAND flash controller selected"); return ERROR_NAND_OPERATION_FAILED; } else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) { /* MLC_CMD = command */ target_write_u32(target, 0x200b8000, command); } else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) { /* SLC_CMD = command */ target_write_u32(target, 0x20020008, command); } return ERROR_OK; } static int lpc3180_address(struct nand_device *nand, uint8_t address) { struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; struct target *target = nand->target; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER) { LOG_ERROR("BUG: no LPC3180 NAND flash controller selected"); return ERROR_NAND_OPERATION_FAILED; } else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) { /* MLC_ADDR = address */ target_write_u32(target, 0x200b8004, address); } else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) { /* SLC_ADDR = address */ target_write_u32(target, 0x20020004, address); } return ERROR_OK; } static int lpc3180_write_data(struct nand_device *nand, uint16_t data) { struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; struct target *target = nand->target; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER) { LOG_ERROR("BUG: no LPC3180 NAND flash controller selected"); return ERROR_NAND_OPERATION_FAILED; } else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) { /* MLC_DATA = data */ target_write_u32(target, 0x200b0000, data); } else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) { /* SLC_DATA = data */ target_write_u32(target, 0x20020000, data); } return ERROR_OK; } static int lpc3180_read_data(struct nand_device *nand, void *data) { struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; struct target *target = nand->target; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER) { LOG_ERROR("BUG: no LPC3180 NAND flash controller selected"); return ERROR_NAND_OPERATION_FAILED; } else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) { /* data = MLC_DATA, use sized access */ if (nand->bus_width == 8) { uint8_t *data8 = data; target_read_u8(target, 0x200b0000, data8); } else if (nand->bus_width == 16) { uint16_t *data16 = data; target_read_u16(target, 0x200b0000, data16); } else { LOG_ERROR("BUG: bus_width neither 8 nor 16 bit"); return ERROR_NAND_OPERATION_FAILED; } } else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) { uint32_t data32; /* data = SLC_DATA, must use 32-bit access */ target_read_u32(target, 0x20020000, &data32); if (nand->bus_width == 8) { uint8_t *data8 = data; *data8 = data32 & 0xff; } else if (nand->bus_width == 16) { uint16_t *data16 = data; *data16 = data32 & 0xffff; } else { LOG_ERROR("BUG: bus_width neither 8 nor 16 bit"); return ERROR_NAND_OPERATION_FAILED; } } return ERROR_OK; } static int lpc3180_write_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; struct target *target = nand->target; int retval; uint8_t status; uint8_t *page_buffer; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER) { LOG_ERROR("BUG: no LPC3180 NAND flash controller selected"); return ERROR_NAND_OPERATION_FAILED; } else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) { uint8_t *oob_buffer; int quarter, num_quarters; if (!data && oob) { LOG_ERROR("LPC3180 MLC controller can't write OOB data only"); return ERROR_NAND_OPERATION_NOT_SUPPORTED; } if (oob && (oob_size > 24)) { LOG_ERROR("LPC3180 MLC controller can't write more " "than 6 bytes for each quarter's OOB data"); return ERROR_NAND_OPERATION_NOT_SUPPORTED; } if (data_size > (uint32_t)nand->page_size) { LOG_ERROR("data size exceeds page size"); return ERROR_NAND_OPERATION_NOT_SUPPORTED; } /* MLC_CMD = sequential input */ target_write_u32(target, 0x200b8000, NAND_CMD_SEQIN); page_buffer = malloc(512); oob_buffer = malloc(6); if (nand->page_size == 512) { /* MLC_ADDR = 0x0 (one column cycle) */ target_write_u32(target, 0x200b8004, 0x0); /* MLC_ADDR = row */ target_write_u32(target, 0x200b8004, page & 0xff); target_write_u32(target, 0x200b8004, (page >> 8) & 0xff); if (nand->address_cycles == 4) target_write_u32(target, 0x200b8004, (page >> 16) & 0xff); } else { /* MLC_ADDR = 0x0 (two column cycles) */ target_write_u32(target, 0x200b8004, 0x0); target_write_u32(target, 0x200b8004, 0x0); /* MLC_ADDR = row */ target_write_u32(target, 0x200b8004, page & 0xff); target_write_u32(target, 0x200b8004, (page >> 8) & 0xff); } /* when using the MLC controller, we have to treat a large page device * as being made out of four quarters, each the size of a small page device */ num_quarters = (nand->page_size == 2048) ? 4 : 1; for (quarter = 0; quarter < num_quarters; quarter++) { int thisrun_data_size = (data_size > 512) ? 512 : data_size; int thisrun_oob_size = (oob_size > 6) ? 6 : oob_size; memset(page_buffer, 0xff, 512); if (data) { memcpy(page_buffer, data, thisrun_data_size); data_size -= thisrun_data_size; data += thisrun_data_size; } memset(oob_buffer, 0xff, 6); if (oob) { memcpy(oob_buffer, oob, thisrun_oob_size); oob_size -= thisrun_oob_size; oob += thisrun_oob_size; } /* write MLC_ECC_ENC_REG to start encode cycle */ target_write_u32(target, 0x200b8008, 0x0); target_write_memory(target, 0x200a8000, 4, 128, page_buffer); target_write_memory(target, 0x200a8000, 1, 6, oob_buffer); /* write MLC_ECC_AUTO_ENC_REG to start auto encode */ target_write_u32(target, 0x200b8010, 0x0); if (!lpc3180_controller_ready(nand, 1000)) { LOG_ERROR("timeout while waiting for completion of auto encode cycle"); free(page_buffer); free(oob_buffer); return ERROR_NAND_OPERATION_FAILED; } } /* MLC_CMD = auto program command */ target_write_u32(target, 0x200b8000, NAND_CMD_PAGEPROG); retval = nand_read_status(nand, &status); if (retval != ERROR_OK) { LOG_ERROR("couldn't read status"); free(page_buffer); free(oob_buffer); return ERROR_NAND_OPERATION_FAILED; } if (status & NAND_STATUS_FAIL) { LOG_ERROR("write operation didn't pass, status: 0x%2.2x", status); free(page_buffer); free(oob_buffer); return ERROR_NAND_OPERATION_FAILED; } free(page_buffer); free(oob_buffer); } else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) { /********************************************************************** * Write both SLC NAND flash page main area and spare area. * Small page - * ------------------------------------------ * | 512 bytes main | 16 bytes spare | * ------------------------------------------ * Large page - * ------------------------------------------ * | 2048 bytes main | 64 bytes spare | * ------------------------------------------ * If DMA & ECC enabled, then the ECC generated for the 1st 256-byte * data is written to the 3rd word of the spare area. The ECC * generated for the 2nd 256-byte data is written to the 4th word * of the spare area. The ECC generated for the 3rd 256-byte data is * written to the 7th word of the spare area. The ECC generated * for the 4th 256-byte data is written to the 8th word of the * spare area and so on. * **********************************************************************/ int i = 0, target_mem_base; uint8_t *ecc_flash_buffer; struct working_area *pworking_area; if (lpc3180_info->is_bulk) { if (!data && oob) { /*if oob only mode is active original method is used as SLC *controller hangs during DMA interworking. Anyway the code supports *the oob only mode below. */ return nand_write_page_raw(nand, page, data, data_size, oob, oob_size); } retval = nand_page_command(nand, page, NAND_CMD_SEQIN, !data); if (ERROR_OK != retval) return retval; /* allocate a working area */ if (target->working_area_size < (uint32_t) nand->page_size + 0x200) { LOG_ERROR("Reserve at least 0x%x physical target working area", nand->page_size + 0x200); return ERROR_FLASH_OPERATION_FAILED; } if (target->working_area_phys%4) { LOG_ERROR( "Reserve the physical target working area at word boundary"); return ERROR_FLASH_OPERATION_FAILED; } if (target_alloc_working_area(target, target->working_area_size, &pworking_area) != ERROR_OK) { LOG_ERROR("no working area specified, can't read LPC internal flash"); return ERROR_FLASH_OPERATION_FAILED; } target_mem_base = target->working_area_phys; if (nand->page_size == 2048) page_buffer = malloc(2048); else page_buffer = malloc(512); ecc_flash_buffer = malloc(64); /* SLC_CFG = 0x (Force nCE assert, DMA ECC enabled, ECC enabled, DMA burst *enabled, DMA write to SLC, WIDTH = bus_width) */ target_write_u32(target, 0x20020014, 0x3c); if (data && !oob) { /* set DMA LLI-s in target memory and in DMA*/ for (i = 0; i < nand->page_size/0x100; i++) { int tmp; /* -------LLI for 256 byte block--------- * DMACC0SrcAddr = SRAM */ target_write_u32(target, target_mem_base+0+i*32, target_mem_base+DATA_OFFS+i*256); if (i == 0) target_write_u32(target, 0x31000100, target_mem_base+DATA_OFFS); /* DMACCxDestAddr = SLC_DMA_DATA */ target_write_u32(target, target_mem_base+4+i*32, 0x20020038); if (i == 0) target_write_u32(target, 0x31000104, 0x20020038); /* DMACCxLLI = next element */ tmp = (target_mem_base+(1+i*2)*16)&0xfffffffc; target_write_u32(target, target_mem_base+8+i*32, tmp); if (i == 0) target_write_u32(target, 0x31000108, tmp); /* DMACCxControl = TransferSize =64, Source burst size =16, * Destination burst size = 16, Source transfer width = 32 bit, * Destination transfer width = 32 bit, Source AHB master select = M0, * Destination AHB master select = M0, Source increment = 1, * Destination increment = 0, Terminal count interrupt enable bit = 0*/ target_write_u32(target, target_mem_base+12+i*32, 0x40 | 3<<12 | 3<<15 | 2<<18 | 2<<21 | 0<<24 | 0<<25 | 1<<26 | 0<<27 | 0<<31); if (i == 0) target_write_u32(target, 0x3100010c, 0x40 | 3<<12 | 3<<15 | 2<<18 | 2<<21 | 0<<24 | 0<<25 | 1<<26 | 0<<27 | 0<<31); /* -------LLI for 3 byte ECC--------- * DMACC0SrcAddr = SLC_ECC*/ target_write_u32(target, target_mem_base+16+i*32, 0x20020034); /* DMACCxDestAddr = SRAM */ target_write_u32(target, target_mem_base+20+i*32, target_mem_base+SPARE_OFFS+8+16*(i>>1)+(i%2)*4); /* DMACCxLLI = next element */ tmp = (target_mem_base+(2+i*2)*16)&0xfffffffc; target_write_u32(target, target_mem_base+24+i*32, tmp); /* DMACCxControl = TransferSize =1, Source burst size =4, * Destination burst size = 4, Source transfer width = 32 bit, * Destination transfer width = 32 bit, Source AHB master select = M0, * Destination AHB master select = M0, Source increment = 0, * Destination increment = 1, Terminal count interrupt enable bit = 0*/ target_write_u32(target, target_mem_base+28+i*32, 0x01 | 1<<12 | 1<<15 | 2<<18 | 2<<21 | 0<<24 | 0<<25 | 0<<26 | 1<<27 | 0<< 31); } } else if (data && oob) { /* -------LLI for 512 or 2048 bytes page--------- * DMACC0SrcAddr = SRAM */ target_write_u32(target, target_mem_base, target_mem_base+DATA_OFFS); target_write_u32(target, 0x31000100, target_mem_base+DATA_OFFS); /* DMACCxDestAddr = SLC_DMA_DATA */ target_write_u32(target, target_mem_base+4, 0x20020038); target_write_u32(target, 0x31000104, 0x20020038); /* DMACCxLLI = next element */ target_write_u32(target, target_mem_base+8, (target_mem_base+32)&0xfffffffc); target_write_u32(target, 0x31000108, (target_mem_base+32)&0xfffffffc); /* DMACCxControl = TransferSize =512 or 128, Source burst size =16, * Destination burst size = 16, Source transfer width = 32 bit, * Destination transfer width = 32 bit, Source AHB master select = M0, * Destination AHB master select = M0, Source increment = 1, * Destination increment = 0, Terminal count interrupt enable bit = 0*/ target_write_u32(target, target_mem_base+12, (nand->page_size == 2048 ? 512 : 128) | 3<<12 | 3<<15 | 2<<18 | 2<<21 | 0<<24 | 0<<25 | 1<<26 | 0<<27 | 0<<31); target_write_u32(target, 0x3100010c, (nand->page_size == 2048 ? 512 : 128) | 3<<12 | 3<<15 | 2<<18 | 2<<21 | 0<<24 | 0<<25 | 1<<26 | 0<<27 | 0<<31); i = 1; } else if (!data && oob) i = 0; /* -------LLI for spare area--------- * DMACC0SrcAddr = SRAM*/ target_write_u32(target, target_mem_base+0+i*32, target_mem_base+SPARE_OFFS); if (i == 0) target_write_u32(target, 0x31000100, target_mem_base+SPARE_OFFS); /* DMACCxDestAddr = SLC_DMA_DATA */ target_write_u32(target, target_mem_base+4+i*32, 0x20020038); if (i == 0) target_write_u32(target, 0x31000104, 0x20020038); /* DMACCxLLI = next element = NULL */ target_write_u32(target, target_mem_base+8+i*32, 0); if (i == 0) target_write_u32(target, 0x31000108, 0); /* DMACCxControl = TransferSize =16 for large page or 4 for small page, * Source burst size =16, Destination burst size = 16, Source transfer width = 32 bit, * Destination transfer width = 32 bit, Source AHB master select = M0, * Destination AHB master select = M0, Source increment = 1, * Destination increment = 0, Terminal count interrupt enable bit = 0*/ target_write_u32(target, target_mem_base+12+i*32, (nand->page_size == 2048 ? 0x10 : 0x04) | 3<<12 | 3<<15 | 2<<18 | 2<<21 | 0<<24 | 0<<25 | 1<<26 | 0<<27 | 0<<31); if (i == 0) target_write_u32(target, 0x3100010c, (nand->page_size == 2048 ? 0x10 : 0x04) | 3<<12 | 3<<15 | 2<<18 | 2<<21 | 0<<24 | 0<<25 | 1<<26 | 0<<27 | 0<<31); memset(ecc_flash_buffer, 0xff, 64); if (oob) memcpy(ecc_flash_buffer, oob, oob_size); target_write_memory(target, target_mem_base+SPARE_OFFS, 4, 16, ecc_flash_buffer); if (data) { memset(page_buffer, 0xff, nand->page_size == 2048 ? 2048 : 512); memcpy(page_buffer, data, data_size); target_write_memory(target, target_mem_base+DATA_OFFS, 4, nand->page_size == 2048 ? 512 : 128, page_buffer); } free(page_buffer); free(ecc_flash_buffer); /* Enable DMA after channel set up ! LLI only works when DMA is the flow controller! */ /* DMACCxConfig= E=1, SrcPeripheral = 1 (SLC), DestPeripheral = 1 (SLC), *FlowCntrl = 2 (Pher -> Mem, DMA), IE = 0, ITC = 0, L= 0, H=0*/ target_write_u32(target, 0x31000110, 1 | 1<<1 | 1<<6 | 2<<11 | 0<<14 | 0<<15 | 0<<16 | 0<<18); /* SLC_CTRL = 3 (START DMA), ECC_CLEAR */ target_write_u32(target, 0x20020010, 0x3); /* SLC_ICR = 2, INT_TC_CLR, clear pending TC*/ target_write_u32(target, 0x20020028, 2); /* SLC_TC */ if (!data && oob) target_write_u32(target, 0x20020030, (nand->page_size == 2048 ? 0x10 : 0x04)); else target_write_u32(target, 0x20020030, (nand->page_size == 2048 ? 0x840 : 0x210)); nand_write_finish(nand); if (!lpc3180_tc_ready(nand, 1000)) { LOG_ERROR("timeout while waiting for completion of DMA"); return ERROR_NAND_OPERATION_FAILED; } target_free_working_area(target, pworking_area); LOG_INFO("Page = 0x%" PRIx32 " was written.", page); } else return nand_write_page_raw(nand, page, data, data_size, oob, oob_size); } return ERROR_OK; } static int lpc3180_read_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; struct target *target = nand->target; uint8_t *page_buffer; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } if (lpc3180_info->selected_controller == LPC3180_NO_CONTROLLER) { LOG_ERROR("BUG: no LPC3180 NAND flash controller selected"); return ERROR_NAND_OPERATION_FAILED; } else if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) { uint8_t *oob_buffer; uint32_t page_bytes_done = 0; uint32_t oob_bytes_done = 0; uint32_t mlc_isr; #if 0 if (oob && (oob_size > 6)) { LOG_ERROR("LPC3180 MLC controller can't read more than 6 bytes of OOB data"); return ERROR_NAND_OPERATION_NOT_SUPPORTED; } #endif if (data_size > (uint32_t)nand->page_size) { LOG_ERROR("data size exceeds page size"); return ERROR_NAND_OPERATION_NOT_SUPPORTED; } if (nand->page_size == 2048) { page_buffer = malloc(2048); oob_buffer = malloc(64); } else { page_buffer = malloc(512); oob_buffer = malloc(16); } if (!data && oob) { /* MLC_CMD = Read OOB * we can use the READOOB command on both small and large page devices, * as the controller translates the 0x50 command to a 0x0 with appropriate * positioning of the serial buffer read pointer */ target_write_u32(target, 0x200b8000, NAND_CMD_READOOB); } else { /* MLC_CMD = Read0 */ target_write_u32(target, 0x200b8000, NAND_CMD_READ0); } if (nand->page_size == 512) { /* small page device * MLC_ADDR = 0x0 (one column cycle) */ target_write_u32(target, 0x200b8004, 0x0); /* MLC_ADDR = row */ target_write_u32(target, 0x200b8004, page & 0xff); target_write_u32(target, 0x200b8004, (page >> 8) & 0xff); if (nand->address_cycles == 4) target_write_u32(target, 0x200b8004, (page >> 16) & 0xff); } else { /* large page device * MLC_ADDR = 0x0 (two column cycles) */ target_write_u32(target, 0x200b8004, 0x0); target_write_u32(target, 0x200b8004, 0x0); /* MLC_ADDR = row */ target_write_u32(target, 0x200b8004, page & 0xff); target_write_u32(target, 0x200b8004, (page >> 8) & 0xff); /* MLC_CMD = Read Start */ target_write_u32(target, 0x200b8000, NAND_CMD_READSTART); } while (page_bytes_done < (uint32_t)nand->page_size) { /* MLC_ECC_AUTO_DEC_REG = dummy */ target_write_u32(target, 0x200b8014, 0xaa55aa55); if (!lpc3180_controller_ready(nand, 1000)) { LOG_ERROR("timeout while waiting for completion of auto decode cycle"); free(page_buffer); free(oob_buffer); return ERROR_NAND_OPERATION_FAILED; } target_read_u32(target, 0x200b8048, &mlc_isr); if (mlc_isr & 0x8) { if (mlc_isr & 0x40) { LOG_ERROR("uncorrectable error detected: 0x%2.2x", (unsigned)mlc_isr); free(page_buffer); free(oob_buffer); return ERROR_NAND_OPERATION_FAILED; } LOG_WARNING("%i symbol error detected and corrected", ((int)(((mlc_isr & 0x30) >> 4) + 1))); } if (data) target_read_memory(target, 0x200a8000, 4, 128, page_buffer + page_bytes_done); if (oob) target_read_memory(target, 0x200a8000, 4, 4, oob_buffer + oob_bytes_done); page_bytes_done += 512; oob_bytes_done += 16; } if (data) memcpy(data, page_buffer, data_size); if (oob) memcpy(oob, oob_buffer, oob_size); free(page_buffer); free(oob_buffer); } else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) { /********************************************************************** * Read both SLC NAND flash page main area and spare area. * Small page - * ------------------------------------------ * | 512 bytes main | 16 bytes spare | * ------------------------------------------ * Large page - * ------------------------------------------ * | 2048 bytes main | 64 bytes spare | * ------------------------------------------ * If DMA & ECC enabled, then the ECC generated for the 1st 256-byte * data is compared with the 3rd word of the spare area. The ECC * generated for the 2nd 256-byte data is compared with the 4th word * of the spare area. The ECC generated for the 3rd 256-byte data is * compared with the 7th word of the spare area. The ECC generated * for the 4th 256-byte data is compared with the 8th word of the * spare area and so on. * **********************************************************************/ int retval, i, target_mem_base; uint8_t *ecc_hw_buffer; uint8_t *ecc_flash_buffer; struct working_area *pworking_area; if (lpc3180_info->is_bulk) { /* read always the data and also oob areas*/ retval = nand_page_command(nand, page, NAND_CMD_READ0, 0); if (ERROR_OK != retval) return retval; /* allocate a working area */ if (target->working_area_size < (uint32_t) nand->page_size + 0x200) { LOG_ERROR("Reserve at least 0x%x physical target working area", nand->page_size + 0x200); return ERROR_FLASH_OPERATION_FAILED; } if (target->working_area_phys%4) { LOG_ERROR( "Reserve the physical target working area at word boundary"); return ERROR_FLASH_OPERATION_FAILED; } if (target_alloc_working_area(target, target->working_area_size, &pworking_area) != ERROR_OK) { LOG_ERROR("no working area specified, can't read LPC internal flash"); return ERROR_FLASH_OPERATION_FAILED; } target_mem_base = target->working_area_phys; if (nand->page_size == 2048) page_buffer = malloc(2048); else page_buffer = malloc(512); ecc_hw_buffer = malloc(32); ecc_flash_buffer = malloc(64); /* SLC_CFG = 0x (Force nCE assert, DMA ECC enabled, ECC enabled, DMA burst *enabled, DMA read from SLC, WIDTH = bus_width) */ target_write_u32(target, 0x20020014, 0x3e); /* set DMA LLI-s in target memory and in DMA*/ for (i = 0; i < nand->page_size/0x100; i++) { int tmp; /* -------LLI for 256 byte block--------- * DMACC0SrcAddr = SLC_DMA_DATA*/ target_write_u32(target, target_mem_base+0+i*32, 0x20020038); if (i == 0) target_write_u32(target, 0x31000100, 0x20020038); /* DMACCxDestAddr = SRAM */ target_write_u32(target, target_mem_base+4+i*32, target_mem_base+DATA_OFFS+i*256); if (i == 0) target_write_u32(target, 0x31000104, target_mem_base+DATA_OFFS); /* DMACCxLLI = next element */ tmp = (target_mem_base+(1+i*2)*16)&0xfffffffc; target_write_u32(target, target_mem_base+8+i*32, tmp); if (i == 0) target_write_u32(target, 0x31000108, tmp); /* DMACCxControl = TransferSize =64, Source burst size =16, * Destination burst size = 16, Source transfer width = 32 bit, * Destination transfer width = 32 bit, Source AHB master select = M0, * Destination AHB master select = M0, Source increment = 0, * Destination increment = 1, Terminal count interrupt enable bit = 0*/ target_write_u32(target, target_mem_base+12+i*32, 0x40 | 3<<12 | 3<<15 | 2<<18 | 2<<21 | 0<<24 | 0<<25 | 0<<26 | 1<<27 | 0<< 31); if (i == 0) target_write_u32(target, 0x3100010c, 0x40 | 3<<12 | 3<<15 | 2<<18 | 2<<21 | 0<<24 | 0<<25 | 0<<26 | 1<<27 | 0<< 31); /* -------LLI for 3 byte ECC--------- * DMACC0SrcAddr = SLC_ECC*/ target_write_u32(target, target_mem_base+16+i*32, 0x20020034); /* DMACCxDestAddr = SRAM */ target_write_u32(target, target_mem_base+20+i*32, target_mem_base+ECC_OFFS+i*4); /* DMACCxLLI = next element */ tmp = (target_mem_base+(2+i*2)*16)&0xfffffffc; target_write_u32(target, target_mem_base+24+i*32, tmp); /* DMACCxControl = TransferSize =1, Source burst size =4, * Destination burst size = 4, Source transfer width = 32 bit, * Destination transfer width = 32 bit, Source AHB master select = M0, * Destination AHB master select = M0, Source increment = 0, * Destination increment = 1, Terminal count interrupt enable bit = 0*/ target_write_u32(target, target_mem_base+28+i*32, 0x01 | 1<<12 | 1<<15 | 2<<18 | 2<<21 | 0<<24 | 0<<25 | 0<<26 | 1<<27 | 0<< 31); } /* -------LLI for spare area--------- * DMACC0SrcAddr = SLC_DMA_DATA*/ target_write_u32(target, target_mem_base+0+i*32, 0x20020038); /* DMACCxDestAddr = SRAM */ target_write_u32(target, target_mem_base+4+i*32, target_mem_base+SPARE_OFFS); /* DMACCxLLI = next element = NULL */ target_write_u32(target, target_mem_base+8+i*32, 0); /* DMACCxControl = TransferSize =16 for large page or 4 for small page, * Source burst size =16, Destination burst size = 16, Source transfer width = 32 bit, * Destination transfer width = 32 bit, Source AHB master select = M0, * Destination AHB master select = M0, Source increment = 0, * Destination increment = 1, Terminal count interrupt enable bit = 0*/ target_write_u32(target, target_mem_base + 12 + i * 32, (nand->page_size == 2048 ? 0x10 : 0x04) | 3<<12 | 3<<15 | 2<<18 | 2<<21 | 0<<24 | 0<<25 | 0<<26 | 1<<27 | 0<<31); /* Enable DMA after channel set up ! LLI only works when DMA is the flow controller! */ /* DMACCxConfig= E=1, SrcPeripheral = 1 (SLC), DestPeripheral = 1 (SLC), *FlowCntrl = 2 (Pher-> Mem, DMA), IE = 0, ITC = 0, L= 0, H=0*/ target_write_u32(target, 0x31000110, 1 | 1<<1 | 1<<6 | 2<<11 | 0<<14 | 0<<15 | 0<<16 | 0<<18); /* SLC_CTRL = 3 (START DMA), ECC_CLEAR */ target_write_u32(target, 0x20020010, 0x3); /* SLC_ICR = 2, INT_TC_CLR, clear pending TC*/ target_write_u32(target, 0x20020028, 2); /* SLC_TC */ target_write_u32(target, 0x20020030, (nand->page_size == 2048 ? 0x840 : 0x210)); if (!lpc3180_tc_ready(nand, 1000)) { LOG_ERROR("timeout while waiting for completion of DMA"); free(page_buffer); free(ecc_hw_buffer); free(ecc_flash_buffer); target_free_working_area(target, pworking_area); return ERROR_NAND_OPERATION_FAILED; } if (data) { target_read_memory(target, target_mem_base+DATA_OFFS, 4, nand->page_size == 2048 ? 512 : 128, page_buffer); memcpy(data, page_buffer, data_size); LOG_INFO("Page = 0x%" PRIx32 " was read.", page); /* check hw generated ECC for each 256 bytes block with the saved *ECC in flash spare area*/ int idx = nand->page_size/0x200; target_read_memory(target, target_mem_base+SPARE_OFFS, 4, 16, ecc_flash_buffer); target_read_memory(target, target_mem_base+ECC_OFFS, 4, 8, ecc_hw_buffer); for (i = 0; i < idx; i++) { if ((0x00ffffff & *(uint32_t *)(void *)(ecc_hw_buffer+i*8)) != (0x00ffffff & *(uint32_t *)(void *)(ecc_flash_buffer+8+i*16))) LOG_WARNING( "ECC mismatch at 256 bytes size block= %d at page= 0x%" PRIx32, i * 2 + 1, page); if ((0x00ffffff & *(uint32_t *)(void *)(ecc_hw_buffer+4+i*8)) != (0x00ffffff & *(uint32_t *)(void *)(ecc_flash_buffer+12+i*16))) LOG_WARNING( "ECC mismatch at 256 bytes size block= %d at page= 0x%" PRIx32, i * 2 + 2, page); } } if (oob) memcpy(oob, ecc_flash_buffer, oob_size); free(page_buffer); free(ecc_hw_buffer); free(ecc_flash_buffer); target_free_working_area(target, pworking_area); } else return nand_read_page_raw(nand, page, data, data_size, oob, oob_size); } return ERROR_OK; } static int lpc3180_controller_ready(struct nand_device *nand, int timeout) { struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; struct target *target = nand->target; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } LOG_DEBUG("lpc3180_controller_ready count start=%d", timeout); do { if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) { uint8_t status; /* Read MLC_ISR, wait for controller to become ready */ target_read_u8(target, 0x200b8048, &status); if (status & 2) { LOG_DEBUG("lpc3180_controller_ready count=%d", timeout); return 1; } } else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) { uint32_t status; /* Read SLC_STAT and check READY bit */ target_read_u32(target, 0x20020018, &status); if (status & 1) { LOG_DEBUG("lpc3180_controller_ready count=%d", timeout); return 1; } } alive_sleep(1); } while (timeout-- > 0); return 0; } static int lpc3180_nand_ready(struct nand_device *nand, int timeout) { struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; struct target *target = nand->target; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } LOG_DEBUG("lpc3180_nand_ready count start=%d", timeout); do { if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) { uint8_t status = 0x0; /* Read MLC_ISR, wait for NAND flash device to become ready */ target_read_u8(target, 0x200b8048, &status); if (status & 1) { LOG_DEBUG("lpc3180_nand_ready count end=%d", timeout); return 1; } } else if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) { uint32_t status = 0x0; /* Read SLC_STAT and check READY bit */ target_read_u32(target, 0x20020018, &status); if (status & 1) { LOG_DEBUG("lpc3180_nand_ready count end=%d", timeout); return 1; } } alive_sleep(1); } while (timeout-- > 0); return 0; } static int lpc3180_tc_ready(struct nand_device *nand, int timeout) { struct lpc3180_nand_controller *lpc3180_info = nand->controller_priv; struct target *target = nand->target; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use LPC3180 NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } LOG_DEBUG("lpc3180_tc_ready count start=%d", timeout); do { if (lpc3180_info->selected_controller == LPC3180_SLC_CONTROLLER) { uint32_t status = 0x0; /* Read SLC_INT_STAT and check INT_TC_STAT bit */ target_read_u32(target, 0x2002001c, &status); if (status & 2) { LOG_DEBUG("lpc3180_tc_ready count=%d", timeout); return 1; } } alive_sleep(1); } while (timeout-- > 0); return 0; } COMMAND_HANDLER(handle_lpc3180_select_command) { struct lpc3180_nand_controller *lpc3180_info = NULL; char *selected[] = { "no", "mlc", "slc" }; if ((CMD_ARGC < 1) || (CMD_ARGC > 3)) return ERROR_COMMAND_SYNTAX_ERROR; unsigned num; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num); struct nand_device *nand = get_nand_device_by_num(num); if (!nand) { command_print(CMD_CTX, "nand device '#%s' is out of bounds", CMD_ARGV[0]); return ERROR_OK; } lpc3180_info = nand->controller_priv; if (CMD_ARGC >= 2) { if (strcmp(CMD_ARGV[1], "mlc") == 0) lpc3180_info->selected_controller = LPC3180_MLC_CONTROLLER; else if (strcmp(CMD_ARGV[1], "slc") == 0) { lpc3180_info->selected_controller = LPC3180_SLC_CONTROLLER; if (CMD_ARGC == 3 && strcmp(CMD_ARGV[2], "bulk") == 0) lpc3180_info->is_bulk = 1; else lpc3180_info->is_bulk = 0; } else return ERROR_COMMAND_SYNTAX_ERROR; } if (lpc3180_info->selected_controller == LPC3180_MLC_CONTROLLER) command_print(CMD_CTX, "%s controller selected", selected[lpc3180_info->selected_controller]); else command_print(CMD_CTX, lpc3180_info->is_bulk ? "%s controller selected bulk mode is available" : "%s controller selected bulk mode is not available", selected[lpc3180_info->selected_controller]); return ERROR_OK; } static const struct command_registration lpc3180_exec_command_handlers[] = { { .name = "select", .handler = handle_lpc3180_select_command, .mode = COMMAND_EXEC, .help = "select MLC or SLC controller (default is MLC), SLC can be set to bulk mode", .usage = "bank_id ['mlc'|'slc' ['bulk'] ]", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration lpc3180_command_handler[] = { { .name = "lpc3180", .mode = COMMAND_ANY, .help = "LPC3180 NAND flash controller commands", .usage = "", .chain = lpc3180_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct nand_flash_controller lpc3180_nand_controller = { .name = "lpc3180", .commands = lpc3180_command_handler, .nand_device_command = lpc3180_nand_device_command, .init = lpc3180_init, .reset = lpc3180_reset, .command = lpc3180_command, .address = lpc3180_address, .write_data = lpc3180_write_data, .read_data = lpc3180_read_data, .write_page = lpc3180_write_page, .read_page = lpc3180_read_page, .nand_ready = lpc3180_nand_ready, }; openocd-0.7.0/src/flash/nand/core.h0000644000175000001440000001663612134336410014000 00000000000000/*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Copyright (C) 2009 Zachary T Welch * * * * Partially based on linux/include/linux/mtd/nand.h * * Copyright (C) 2000 David Woodhouse * * Copyright (C) 2000 Steven J. Hill * * Copyright (C) 2000 Thomas Gleixner * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef FLASH_NAND_CORE_H #define FLASH_NAND_CORE_H #include /** * Representation of a single NAND block in a NAND device. */ struct nand_block { /** Offset to the block. */ uint32_t offset; /** Size of the block. */ uint32_t size; /** True if the block has been erased. */ int is_erased; /** True if the block is bad. */ int is_bad; }; struct nand_oobfree { int offset; int length; }; struct nand_ecclayout { int eccbytes; int eccpos[64]; int oobavail; struct nand_oobfree oobfree[2]; }; struct nand_device { const char *name; struct target *target; struct nand_flash_controller *controller; void *controller_priv; struct nand_manufacturer *manufacturer; struct nand_info *device; int bus_width; int address_cycles; int page_size; int erase_size; int use_raw; int num_blocks; struct nand_block *blocks; struct nand_device *next; }; /* NAND Flash Manufacturer ID Codes */ enum { NAND_MFR_TOSHIBA = 0x98, NAND_MFR_SAMSUNG = 0xec, NAND_MFR_FUJITSU = 0x04, NAND_MFR_NATIONAL = 0x8f, NAND_MFR_RENESAS = 0x07, NAND_MFR_STMICRO = 0x20, NAND_MFR_HYNIX = 0xad, NAND_MFR_MICRON = 0x2c, }; struct nand_manufacturer { int id; const char *name; }; struct nand_info { int mfr_id; int id; int page_size; int chip_size; int erase_size; int options; const char *name; }; /* Option constants for bizarre disfunctionality and real features */ enum { /* Chip can not auto increment pages */ NAND_NO_AUTOINCR = 0x00000001, /* Buswitdh is 16 bit */ NAND_BUSWIDTH_16 = 0x00000002, /* Device supports partial programming without padding */ NAND_NO_PADDING = 0x00000004, /* Chip has cache program function */ NAND_CACHEPRG = 0x00000008, /* Chip has copy back function */ NAND_COPYBACK = 0x00000010, /* AND Chip which has 4 banks and a confusing page / block * assignment. See Renesas datasheet for further information */ NAND_IS_AND = 0x00000020, /* Chip has a array of 4 pages which can be read without * additional ready /busy waits */ NAND_4PAGE_ARRAY = 0x00000040, /* Chip requires that BBT is periodically rewritten to prevent * bits from adjacent blocks from 'leaking' in altering data. * This happens with the Renesas AG-AND chips, possibly others. */ BBT_AUTO_REFRESH = 0x00000080, /* Chip does not require ready check on read. True * for all large page devices, as they do not support * autoincrement.*/ NAND_NO_READRDY = 0x00000100, /* Options valid for Samsung large page devices */ NAND_SAMSUNG_LP_OPTIONS = (NAND_NO_PADDING | NAND_CACHEPRG | NAND_COPYBACK), /* Options for new chips with large page size. The pagesize and the * erasesize is determined from the extended id bytes */ LP_OPTIONS = (NAND_SAMSUNG_LP_OPTIONS | NAND_NO_READRDY | NAND_NO_AUTOINCR), LP_OPTIONS16 = (LP_OPTIONS | NAND_BUSWIDTH_16), }; enum { /* Standard NAND flash commands */ NAND_CMD_READ0 = 0x0, NAND_CMD_READ1 = 0x1, NAND_CMD_RNDOUT = 0x5, NAND_CMD_PAGEPROG = 0x10, NAND_CMD_READOOB = 0x50, NAND_CMD_ERASE1 = 0x60, NAND_CMD_STATUS = 0x70, NAND_CMD_STATUS_MULTI = 0x71, NAND_CMD_SEQIN = 0x80, NAND_CMD_RNDIN = 0x85, NAND_CMD_READID = 0x90, NAND_CMD_ERASE2 = 0xd0, NAND_CMD_RESET = 0xff, /* Extended commands for large page devices */ NAND_CMD_READSTART = 0x30, NAND_CMD_RNDOUTSTART = 0xE0, NAND_CMD_CACHEDPROG = 0x15, }; /* Status bits */ enum { NAND_STATUS_FAIL = 0x01, NAND_STATUS_FAIL_N1 = 0x02, NAND_STATUS_TRUE_READY = 0x20, NAND_STATUS_READY = 0x40, NAND_STATUS_WP = 0x80, }; /* OOB (spare) data formats */ enum oob_formats { NAND_OOB_NONE = 0x0, /* no OOB data at all */ NAND_OOB_RAW = 0x1, /* raw OOB data (16 bytes for 512b page sizes, 64 bytes for *2048b page sizes) */ NAND_OOB_ONLY = 0x2, /* only OOB data */ NAND_OOB_SW_ECC = 0x10, /* when writing, use SW ECC (as opposed to no ECC) */ NAND_OOB_HW_ECC = 0x20, /* when writing, use HW ECC (as opposed to no ECC) */ NAND_OOB_SW_ECC_KW = 0x40, /* when writing, use Marvell's Kirkwood bootrom format */ NAND_OOB_JFFS2 = 0x100, /* when writing, use JFFS2 OOB layout */ NAND_OOB_YAFFS2 = 0x100,/* when writing, use YAFFS2 OOB layout */ }; struct nand_device *get_nand_device_by_num(int num); int nand_page_command(struct nand_device *nand, uint32_t page, uint8_t cmd, bool oob_only); int nand_read_data_page(struct nand_device *nand, uint8_t *data, uint32_t size); int nand_write_data_page(struct nand_device *nand, uint8_t *data, uint32_t size); int nand_write_finish(struct nand_device *nand); int nand_read_page_raw(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size); int nand_write_page_raw(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size); int nand_read_status(struct nand_device *nand, uint8_t *status); int nand_calculate_ecc(struct nand_device *nand, const uint8_t *dat, uint8_t *ecc_code); int nand_calculate_ecc_kw(struct nand_device *nand, const uint8_t *dat, uint8_t *ecc_code); int nand_register_commands(struct command_context *cmd_ctx); /** helper for parsing a nand device command argument string */ COMMAND_HELPER(nand_command_get_device, unsigned name_index, struct nand_device **nand); #define ERROR_NAND_DEVICE_INVALID (-1100) #define ERROR_NAND_OPERATION_FAILED (-1101) #define ERROR_NAND_OPERATION_TIMEOUT (-1102) #define ERROR_NAND_OPERATION_NOT_SUPPORTED (-1103) #define ERROR_NAND_DEVICE_NOT_PROBED (-1104) #define ERROR_NAND_ERROR_CORRECTION_FAILED (-1105) #define ERROR_NAND_NO_BUFFER (-1106) #endif /* FLASH_NAND_CORE_H */ openocd-0.7.0/src/flash/nand/nonce.c0000644000175000001440000000510012134336410014125 00000000000000/*************************************************************************** * Copyright (C) 2009 Zachary T Welch * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "hello.h" static int nonce_nand_command(struct nand_device *nand, uint8_t command) { return ERROR_OK; } static int nonce_nand_address(struct nand_device *nand, uint8_t address) { return ERROR_OK; } static int nonce_nand_read(struct nand_device *nand, void *data) { return ERROR_OK; } static int nonce_nand_write(struct nand_device *nand, uint16_t data) { return ERROR_OK; } static int nonce_nand_fast_block_write(struct nand_device *nand, uint8_t *data, int size) { return ERROR_OK; } static int nonce_nand_reset(struct nand_device *nand) { return nonce_nand_command(nand, NAND_CMD_RESET); } NAND_DEVICE_COMMAND_HANDLER(nonce_nand_device_command) { return ERROR_OK; } static int nonce_nand_init(struct nand_device *nand) { return ERROR_OK; } struct nand_flash_controller nonce_nand_controller = { .name = "nonce", .commands = hello_command_handlers, .nand_device_command = &nonce_nand_device_command, .init = &nonce_nand_init, .reset = &nonce_nand_reset, .command = &nonce_nand_command, .address = &nonce_nand_address, .read_data = &nonce_nand_read, .write_data = &nonce_nand_write, .write_block_data = &nonce_nand_fast_block_write, }; openocd-0.7.0/src/flash/nand/fileio.h0000644000175000001440000000447312134336410014313 00000000000000/*************************************************************************** * Copyright (C) 2009 Zachary T Welch * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef FLASH_NAND_FILEIO_H #define FLASH_NAND_FILEIO_H #include #include struct nand_fileio_state { uint32_t address; uint32_t size; uint8_t *page; uint32_t page_size; enum oob_formats oob_format; uint8_t *oob; uint32_t oob_size; const int *eccpos; bool file_opened; struct fileio fileio; struct duration bench; }; void nand_fileio_init(struct nand_fileio_state *state); int nand_fileio_start(struct command_context *cmd_ctx, struct nand_device *nand, const char *filename, int filemode, struct nand_fileio_state *state); int nand_fileio_cleanup(struct nand_fileio_state *state); int nand_fileio_finish(struct nand_fileio_state *state); COMMAND_HELPER(nand_fileio_parse_args, struct nand_fileio_state *state, struct nand_device **dev, enum fileio_access filemode, bool need_size, bool sw_ecc); int nand_fileio_read(struct nand_device *nand, struct nand_fileio_state *s); #endif /* FLASH_NAND_FILEIO_H */ openocd-0.7.0/src/flash/nand/imp.h0000644000175000001440000000373012134336410013624 00000000000000/*************************************************************************** * Copyright (C) 2009 Zachary T Welch * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef FLASH_NAND_IMP_H #define FLASH_NAND_IMP_H #include "core.h" #include "driver.h" void nand_device_add(struct nand_device *c); int nand_write_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size); int nand_read_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size); int nand_probe(struct nand_device *nand); int nand_erase(struct nand_device *nand, int first_block, int last_block); int nand_build_bbt(struct nand_device *nand, int first, int last); #endif /* FLASH_NAND_IMP_H */ openocd-0.7.0/src/flash/nand/s3c2412.c0000644000175000001440000000546012134336410014035 00000000000000/*************************************************************************** * Copyright (C) 2007, 2008 by Ben Dooks * * ben@fluff.org * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /* * S3C2412 OpenOCD NAND Flash controller support. * * Many thanks to Simtec Electronics for sponsoring this work. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "s3c24xx.h" NAND_DEVICE_COMMAND_HANDLER(s3c2412_nand_device_command) { struct s3c24xx_nand_controller *info; CALL_S3C24XX_DEVICE_COMMAND(nand, &info); /* fill in the address fields for the core device */ info->cmd = S3C2440_NFCMD; info->addr = S3C2440_NFADDR; info->data = S3C2440_NFDATA; info->nfstat = S3C2412_NFSTAT; return ERROR_OK; } static int s3c2412_init(struct nand_device *nand) { struct target *target = nand->target; target_write_u32(target, S3C2410_NFCONF, S3C2440_NFCONF_TACLS(3) | S3C2440_NFCONF_TWRPH0(7) | S3C2440_NFCONF_TWRPH1(7)); target_write_u32(target, S3C2440_NFCONT, S3C2412_NFCONT_INIT_MAIN_ECC | S3C2440_NFCONT_ENABLE); return ERROR_OK; } struct nand_flash_controller s3c2412_nand_controller = { .name = "s3c2412", .nand_device_command = &s3c2412_nand_device_command, .init = &s3c2412_init, .reset = &s3c24xx_reset, .command = &s3c24xx_command, .address = &s3c24xx_address, .write_data = &s3c24xx_write_data, .read_data = &s3c24xx_read_data, .write_page = s3c24xx_write_page, .read_page = s3c24xx_read_page, .write_block_data = &s3c2440_write_block_data, .read_block_data = &s3c2440_read_block_data, .nand_ready = &s3c2440_nand_ready, }; openocd-0.7.0/src/flash/nand/lpc3180.h0000644000175000001440000000354212134336410014132 00000000000000/*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef LPC3180_NAND_CONTROLLER_H #define LPC3180_NAND_CONTROLLER_H enum lpc3180_selected_controller { LPC3180_NO_CONTROLLER, LPC3180_MLC_CONTROLLER, LPC3180_SLC_CONTROLLER, }; struct lpc3180_nand_controller { int osc_freq; enum lpc3180_selected_controller selected_controller; int is_bulk; int sw_write_protection; uint32_t sw_wp_lower_bound; uint32_t sw_wp_upper_bound; }; #endif /*LPC3180_NAND_CONTROLLER_H */ openocd-0.7.0/src/flash/nand/s3c24xx.c0000644000175000001440000000765412134336410014261 00000000000000/*************************************************************************** * Copyright (C) 2007, 2008 by Ben Dooks * * ben@fluff.org * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /* * S3C24XX Series OpenOCD NAND Flash controller support. * * Many thanks to Simtec Electronics for sponsoring this work. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "s3c24xx.h" S3C24XX_DEVICE_COMMAND() { *info = NULL; struct s3c24xx_nand_controller *s3c24xx_info; s3c24xx_info = malloc(sizeof(struct s3c24xx_nand_controller)); if (s3c24xx_info == NULL) { LOG_ERROR("no memory for nand controller"); return -ENOMEM; } nand->controller_priv = s3c24xx_info; *info = s3c24xx_info; return ERROR_OK; } int s3c24xx_reset(struct nand_device *nand) { struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; struct target *target = nand->target; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } target_write_u32(target, s3c24xx_info->cmd, 0xff); return ERROR_OK; } int s3c24xx_command(struct nand_device *nand, uint8_t command) { struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; struct target *target = nand->target; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } target_write_u16(target, s3c24xx_info->cmd, command); return ERROR_OK; } int s3c24xx_address(struct nand_device *nand, uint8_t address) { struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; struct target *target = nand->target; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } target_write_u16(target, s3c24xx_info->addr, address); return ERROR_OK; } int s3c24xx_write_data(struct nand_device *nand, uint16_t data) { struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; struct target *target = nand->target; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } target_write_u8(target, s3c24xx_info->data, data); return ERROR_OK; } int s3c24xx_read_data(struct nand_device *nand, void *data) { struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; struct target *target = nand->target; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } target_read_u8(target, s3c24xx_info->data, data); return ERROR_OK; } openocd-0.7.0/src/flash/nand/Makefile.in0000644000175000001440000004530512141414275014743 00000000000000# Makefile.in generated by automake 1.13.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ DIST_COMMON = $(top_srcdir)/common.mk $(srcdir)/Makefile.in \ $(srcdir)/Makefile.am $(top_srcdir)/depcomp $(noinst_HEADERS) @INTERNAL_JIMTCL_TRUE@am__append_1 = -I$(top_srcdir)/jimtcl \ @INTERNAL_JIMTCL_TRUE@ -I$(top_builddir)/jimtcl subdir = src/flash/nand ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/config_subdir.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libocdflashnand_la_LIBADD = am__objects_1 = nonce.lo davinci.lo lpc3180.lo lpc32xx.lo mxc.lo \ mx3.lo orion.lo s3c24xx.lo s3c2410.lo s3c2412.lo s3c2440.lo \ s3c2443.lo s3c6400.lo at91sam9.lo nuc910.lo am_libocdflashnand_la_OBJECTS = ecc.lo ecc_kw.lo core.lo fileio.lo \ tcl.lo arm_io.lo $(am__objects_1) driver.lo libocdflashnand_la_OBJECTS = $(am_libocdflashnand_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libocdflashnand_la_SOURCES) DIST_SOURCES = $(libocdflashnand_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CC_FOR_BUILD = @CC_FOR_BUILD@ CFLAGS = @CFLAGS@ CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@ FGREP = @FGREP@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ doxygen_as_html = @doxygen_as_html@ doxygen_as_pdf = @doxygen_as_pdf@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ # common flags used in openocd build AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src \ -I$(top_srcdir)/src/helper -DPKGDATADIR=\"$(pkgdatadir)\" \ -DPKGLIBDIR=\"$(pkglibdir)\" $(am__append_1) noinst_LTLIBRARIES = libocdflashnand.la libocdflashnand_la_SOURCES = \ ecc.c \ ecc_kw.c \ core.c \ fileio.c \ tcl.c \ arm_io.c \ $(NAND_DRIVERS) \ driver.c NAND_DRIVERS = \ nonce.c \ davinci.c \ lpc3180.c \ lpc32xx.c \ mxc.c \ mx3.c \ orion.c \ s3c24xx.c \ s3c2410.c \ s3c2412.c \ s3c2440.c \ s3c2443.c \ s3c6400.c \ at91sam9.c \ nuc910.c noinst_HEADERS = \ arm_io.h \ core.h \ driver.h \ fileio.h \ imp.h \ lpc3180.h \ lpc32xx.h \ mxc.h \ mx3.h \ s3c24xx.h \ s3c24xx_regs.h \ nuc910.h MAINTAINERCLEANFILES = $(srcdir)/Makefile.in all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/common.mk $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/flash/nand/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/flash/nand/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_srcdir)/common.mk: $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libocdflashnand.la: $(libocdflashnand_la_OBJECTS) $(libocdflashnand_la_DEPENDENCIES) $(EXTRA_libocdflashnand_la_DEPENDENCIES) $(AM_V_CCLD)$(LINK) $(libocdflashnand_la_OBJECTS) $(libocdflashnand_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm_io.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/at91sam9.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/core.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/davinci.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/driver.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ecc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ecc_kw.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fileio.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lpc3180.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lpc32xx.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mx3.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mxc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nonce.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nuc910.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/orion.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s3c2410.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s3c2412.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s3c2440.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s3c2443.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s3c24xx.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/s3c6400.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tcl.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: openocd-0.7.0/src/flash/nand/arm_io.h0000644000175000001440000000341612134336410014306 00000000000000/* * Copyright (C) 2009 by David Brownell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 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. */ #ifndef __ARM_NANDIO_H #define __ARM_NANDIO_H /** * Available operational states the arm_nand_data struct can be in. */ enum arm_nand_op { ARM_NAND_NONE, /**< No operation performed. */ ARM_NAND_READ, /**< Read operation performed. */ ARM_NAND_WRITE, /**< Write operation performed. */ }; /** * The arm_nand_data struct is used for defining NAND I/O operations on an ARM * core. */ struct arm_nand_data { /** Target is proxy for some ARM core. */ struct target *target; /** The copy area holds code loop and data for I/O operations. */ struct working_area *copy_area; /** The chunk size is the page size or ECC chunk. */ unsigned chunk_size; /** Where data is read from or written to. */ uint32_t data; /** Last operation executed using this struct. */ enum arm_nand_op op; /* currently implicit: data width == 8 bits (not 16) */ }; int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size); int arm_nandread(struct arm_nand_data *nand, uint8_t *data, uint32_t size); #endif /* __ARM_NANDIO_H */ openocd-0.7.0/src/flash/nand/at91sam9.c0000644000175000001440000004625412134336410014412 00000000000000/* * Copyright (C) 2009 by Dean Glazeski * dnglaze@gmail.com * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 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. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "imp.h" #include "arm_io.h" #define AT91C_PIOx_SODR (0x30) /**< Offset to PIO SODR. */ #define AT91C_PIOx_CODR (0x34) /**< Offset to PIO CODR. */ #define AT91C_PIOx_PDSR (0x3C) /**< Offset to PIO PDSR. */ #define AT91C_ECCx_CR (0x00) /**< Offset to ECC CR. */ #define AT91C_ECCx_SR (0x08) /**< Offset to ECC SR. */ #define AT91C_ECCx_PR (0x0C) /**< Offset to ECC PR. */ #define AT91C_ECCx_NPR (0x10) /**< Offset to ECC NPR. */ /** * Representation of a pin on an AT91SAM9 chip. */ struct at91sam9_pin { /** Address of the PIO controller. */ uint32_t pioc; /** Pin number. */ uint32_t num; }; /** * Private data for the controller that is stored in the NAND device structure. */ struct at91sam9_nand { /** Address of the ECC controller for NAND. */ uint32_t ecc; /** Address data is written to. */ uint32_t data; /** Address commands are written to. */ uint32_t cmd; /** Address addresses are written to. */ uint32_t addr; /** I/O structure for hosted reads/writes. */ struct arm_nand_data io; /** Pin representing the ready/~busy line. */ struct at91sam9_pin busy; /** Pin representing the chip enable. */ struct at91sam9_pin ce; }; /** * Checks if the target is halted and prints an error message if it isn't. * * @param target Target to be checked. * @param label String label for where function is called from. * @return True if the target is halted. */ static int at91sam9_halted(struct target *target, const char *label) { if (target->state == TARGET_HALTED) return true; LOG_ERROR("Target must be halted to use NAND controller (%s)", label); return false; } /** * Initialize the AT91SAM9 NAND controller. * * @param nand NAND device the controller is attached to. * @return Success or failure of initialization. */ static int at91sam9_init(struct nand_device *nand) { struct target *target = nand->target; if (!at91sam9_halted(target, "init")) return ERROR_NAND_OPERATION_FAILED; return ERROR_OK; } /** * Enable NAND device attached to a controller. * * @param info NAND controller information for controlling NAND device. * @return Success or failure of the enabling. */ static int at91sam9_enable(struct nand_device *nand) { struct at91sam9_nand *info = nand->controller_priv; struct target *target = nand->target; return target_write_u32(target, info->ce.pioc + AT91C_PIOx_CODR, 1 << info->ce.num); } /** * Disable NAND device attached to a controller. * * @param info NAND controller information for controlling NAND device. * @return Success or failure of the disabling. */ static int at91sam9_disable(struct nand_device *nand) { struct at91sam9_nand *info = nand->controller_priv; struct target *target = nand->target; return target_write_u32(target, info->ce.pioc + AT91C_PIOx_SODR, 1 << info->ce.num); } /** * Send a command to the NAND device. * * @param nand NAND device to write the command to. * @param command Command to be written. * @return Success or failure of writing the command. */ static int at91sam9_command(struct nand_device *nand, uint8_t command) { struct at91sam9_nand *info = nand->controller_priv; struct target *target = nand->target; if (!at91sam9_halted(target, "command")) return ERROR_NAND_OPERATION_FAILED; at91sam9_enable(nand); return target_write_u8(target, info->cmd, command); } /** * Reset the AT91SAM9 NAND controller. * * @param nand NAND device to be reset. * @return Success or failure of reset. */ static int at91sam9_reset(struct nand_device *nand) { if (!at91sam9_halted(nand->target, "reset")) return ERROR_NAND_OPERATION_FAILED; return at91sam9_disable(nand); } /** * Send an address to the NAND device attached to an AT91SAM9 NAND controller. * * @param nand NAND device to send the address to. * @param address Address to be sent. * @return Success or failure of sending the address. */ static int at91sam9_address(struct nand_device *nand, uint8_t address) { struct at91sam9_nand *info = nand->controller_priv; struct target *target = nand->target; if (!at91sam9_halted(nand->target, "address")) return ERROR_NAND_OPERATION_FAILED; return target_write_u8(target, info->addr, address); } /** * Read data directly from the NAND device attached to an AT91SAM9 NAND * controller. * * @param nand NAND device to read from. * @param data Pointer to where the data should be put. * @return Success or failure of reading the data. */ static int at91sam9_read_data(struct nand_device *nand, void *data) { struct at91sam9_nand *info = nand->controller_priv; struct target *target = nand->target; if (!at91sam9_halted(nand->target, "read data")) return ERROR_NAND_OPERATION_FAILED; return target_read_u8(target, info->data, data); } /** * Write data directly to the NAND device attached to an AT91SAM9 NAND * controller. * * @param nand NAND device to be written to. * @param data Data to be written. * @return Success or failure of the data write. */ static int at91sam9_write_data(struct nand_device *nand, uint16_t data) { struct at91sam9_nand *info = nand->controller_priv; struct target *target = nand->target; if (!at91sam9_halted(target, "write data")) return ERROR_NAND_OPERATION_FAILED; return target_write_u8(target, info->data, data); } /** * Determine if the NAND device is ready by looking at the ready/~busy pin. * * @param nand NAND device to check. * @param timeout Time in milliseconds to wait for NAND to be ready. * @return True if the NAND is ready in the timeout period. */ static int at91sam9_nand_ready(struct nand_device *nand, int timeout) { struct at91sam9_nand *info = nand->controller_priv; struct target *target = nand->target; uint32_t status; if (!at91sam9_halted(target, "nand ready")) return 0; do { target_read_u32(target, info->busy.pioc + AT91C_PIOx_PDSR, &status); if (status & (1 << info->busy.num)) return 1; alive_sleep(1); } while (timeout-- > 0); return 0; } /** * Read a block of data from the NAND device attached to an AT91SAM9. This * utilizes the ARM hosted NAND read function. * * @param nand NAND device to read from. * @param data Pointer to where the read data should be placed. * @param size Size of the data being read. * @return Success or failure of the hosted read. */ static int at91sam9_read_block_data(struct nand_device *nand, uint8_t *data, int size) { struct at91sam9_nand *info = nand->controller_priv; struct arm_nand_data *io = &info->io; int status; if (!at91sam9_halted(nand->target, "read block")) return ERROR_NAND_OPERATION_FAILED; io->chunk_size = nand->page_size; status = arm_nandread(io, data, size); return status; } /** * Write a block of data to a NAND device attached to an AT91SAM9. This uses * the ARM hosted write function to write the data. * * @param nand NAND device to write to. * @param data Data to be written to device. * @param size Size of the data being written. * @return Success or failure of the hosted write. */ static int at91sam9_write_block_data(struct nand_device *nand, uint8_t *data, int size) { struct at91sam9_nand *info = nand->controller_priv; struct arm_nand_data *io = &info->io; int status; if (!at91sam9_halted(nand->target, "write block")) return ERROR_NAND_OPERATION_FAILED; io->chunk_size = nand->page_size; status = arm_nandwrite(io, data, size); return status; } /** * Initialize the ECC controller on the AT91SAM9. * * @param target Target to configure ECC on. * @param info NAND controller information for where the ECC is. * @return Success or failure of initialization. */ static int at91sam9_ecc_init(struct target *target, struct at91sam9_nand *info) { if (!info->ecc) { LOG_ERROR("ECC controller address must be set when not reading raw NAND data"); return ERROR_NAND_OPERATION_FAILED; } /* reset ECC parity registers */ return target_write_u32(target, info->ecc + AT91C_ECCx_CR, 1); } /** * Initialize an area for the OOB based on whether a user is requesting the OOB * data. This determines the size of the OOB and allocates the space in case * the user has not requested the OOB data. * * @param nand NAND device we are creating an OOB for. * @param oob Pointer to the user supplied OOB area. * @param size Size of the OOB. * @return Pointer to an area to store OOB data. */ static uint8_t *at91sam9_oob_init(struct nand_device *nand, uint8_t *oob, uint32_t *size) { if (!oob) { /* user doesn't want OOB, allocate it */ if (nand->page_size == 512) *size = 16; else if (nand->page_size == 2048) *size = 64; oob = malloc(*size); if (!oob) { LOG_ERROR("Unable to allocate space for OOB"); return NULL; } memset(oob, 0xFF, *size); } return oob; } /** * Reads a page from an AT91SAM9 NAND controller and verifies using 1-bit ECC * controller on chip. This makes an attempt to correct any errors that are * encountered while reading the page of data. * * @param nand NAND device to read from * @param page Page to be read. * @param data Pointer to where data should be read to. * @param data_size Size of the data to be read. * @param oob Pointer to where OOB data should be read to. * @param oob_size Size of the OOB data to be read. * @return Success or failure of reading the NAND page. */ static int at91sam9_read_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { int retval; struct at91sam9_nand *info = nand->controller_priv; struct target *target = nand->target; uint8_t *oob_data; uint32_t status; retval = at91sam9_ecc_init(target, info); if (ERROR_OK != retval) return retval; retval = nand_page_command(nand, page, NAND_CMD_READ0, !data); if (ERROR_OK != retval) return retval; if (data) { retval = nand_read_data_page(nand, data, data_size); if (ERROR_OK != retval) return retval; } oob_data = at91sam9_oob_init(nand, oob, &oob_size); retval = nand_read_data_page(nand, oob_data, oob_size); if (ERROR_OK == retval && data) { target_read_u32(target, info->ecc + AT91C_ECCx_SR, &status); if (status & 1) { LOG_ERROR("Error detected!"); if (status & 4) LOG_ERROR("Multiple errors encountered; unrecoverable!"); else { /* attempt recovery */ uint32_t parity; target_read_u32(target, info->ecc + AT91C_ECCx_PR, &parity); uint32_t word = (parity & 0x0000FFF0) >> 4; uint32_t bit = parity & 0x0F; data[word] ^= (0x1) << bit; LOG_INFO("Data word %d, bit %d corrected.", (unsigned) word, (unsigned) bit); } } if (status & 2) { /* we could write back correct ECC data */ LOG_ERROR("Error in ECC bytes detected"); } } if (!oob) { /* if it wasn't asked for, free it */ free(oob_data); } return retval; } /** * Write a page of data including 1-bit ECC information to a NAND device * attached to an AT91SAM9 controller. If there is OOB data to be written, * this will ignore the computed ECC from the ECC controller. * * @param nand NAND device to write to. * @param page Page to write. * @param data Pointer to data being written. * @param data_size Size of the data being written. * @param oob Pointer to OOB data being written. * @param oob_size Size of the OOB data. * @return Success or failure of the page write. */ static int at91sam9_write_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { struct at91sam9_nand *info = nand->controller_priv; struct target *target = nand->target; int retval; uint8_t *oob_data = oob; uint32_t parity, nparity; retval = at91sam9_ecc_init(target, info); if (ERROR_OK != retval) return retval; retval = nand_page_command(nand, page, NAND_CMD_SEQIN, !data); if (ERROR_OK != retval) return retval; if (data) { retval = nand_write_data_page(nand, data, data_size); if (ERROR_OK != retval) { LOG_ERROR("Unable to write data to NAND device"); return retval; } } oob_data = at91sam9_oob_init(nand, oob, &oob_size); if (!oob) { /* no OOB given, so read in the ECC parity from the ECC controller */ target_read_u32(target, info->ecc + AT91C_ECCx_PR, &parity); target_read_u32(target, info->ecc + AT91C_ECCx_NPR, &nparity); oob_data[0] = (uint8_t) parity; oob_data[1] = (uint8_t) (parity >> 8); oob_data[2] = (uint8_t) nparity; oob_data[3] = (uint8_t) (nparity >> 8); } retval = nand_write_data_page(nand, oob_data, oob_size); if (!oob) free(oob_data); if (ERROR_OK != retval) { LOG_ERROR("Unable to write OOB data to NAND"); return retval; } retval = nand_write_finish(nand); return retval; } /** * Handle the initial NAND device command for AT91SAM9 controllers. This * initializes much of the controller information struct to be ready for future * reads and writes. */ NAND_DEVICE_COMMAND_HANDLER(at91sam9_nand_device_command) { unsigned long chip = 0, ecc = 0; struct at91sam9_nand *info = NULL; LOG_DEBUG("AT91SAM9 NAND Device Command"); if (CMD_ARGC < 3 || CMD_ARGC > 4) { LOG_ERROR("parameters: %s target chip_addr", CMD_ARGV[0]); return ERROR_NAND_OPERATION_FAILED; } COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], chip); if (chip == 0) { LOG_ERROR("invalid NAND chip address: %s", CMD_ARGV[2]); return ERROR_NAND_OPERATION_FAILED; } if (CMD_ARGC == 4) { COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[3], ecc); if (ecc == 0) { LOG_ERROR("invalid ECC controller address: %s", CMD_ARGV[3]); return ERROR_NAND_OPERATION_FAILED; } } info = calloc(1, sizeof(*info)); if (!info) { LOG_ERROR("unable to allocate space for controller private data"); return ERROR_NAND_OPERATION_FAILED; } info->data = chip; info->cmd = chip | (1 << 22); info->addr = chip | (1 << 21); info->ecc = ecc; nand->controller_priv = info; info->io.target = nand->target; info->io.data = info->data; info->io.op = ARM_NAND_NONE; return ERROR_OK; } /** * Handle the AT91SAM9 CLE command for specifying the address line to use for * writing commands to a NAND device. */ COMMAND_HANDLER(handle_at91sam9_cle_command) { struct nand_device *nand = NULL; struct at91sam9_nand *info = NULL; unsigned num, address_line; if (CMD_ARGC != 2) { command_print(CMD_CTX, "incorrect number of arguments for 'at91sam9 cle' command"); return ERROR_OK; } COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num); nand = get_nand_device_by_num(num); if (!nand) { command_print(CMD_CTX, "invalid nand device number: %s", CMD_ARGV[0]); return ERROR_OK; } info = nand->controller_priv; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], address_line); info->cmd = info->data | (1 << address_line); return ERROR_OK; } /** * Handle the AT91SAM9 ALE command for specifying the address line to use for * writing addresses to the NAND device. */ COMMAND_HANDLER(handle_at91sam9_ale_command) { struct nand_device *nand = NULL; struct at91sam9_nand *info = NULL; unsigned num, address_line; if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num); nand = get_nand_device_by_num(num); if (!nand) { command_print(CMD_CTX, "invalid nand device number: %s", CMD_ARGV[0]); return ERROR_COMMAND_ARGUMENT_INVALID; } info = nand->controller_priv; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], address_line); info->addr = info->data | (1 << address_line); return ERROR_OK; } /** * Handle the AT91SAM9 RDY/~BUSY command for specifying the pin that watches the * RDY/~BUSY line from the NAND device. */ COMMAND_HANDLER(handle_at91sam9_rdy_busy_command) { struct nand_device *nand = NULL; struct at91sam9_nand *info = NULL; unsigned num, base_pioc, pin_num; if (CMD_ARGC != 3) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num); nand = get_nand_device_by_num(num); if (!nand) { command_print(CMD_CTX, "invalid nand device number: %s", CMD_ARGV[0]); return ERROR_COMMAND_ARGUMENT_INVALID; } info = nand->controller_priv; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], base_pioc); info->busy.pioc = base_pioc; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[2], pin_num); info->busy.num = pin_num; return ERROR_OK; } /** * Handle the AT91SAM9 CE command for specifying the pin that is used to enable * or disable the NAND device. */ COMMAND_HANDLER(handle_at91sam9_ce_command) { struct nand_device *nand = NULL; struct at91sam9_nand *info = NULL; unsigned num, base_pioc, pin_num; if (CMD_ARGC != 3) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num); nand = get_nand_device_by_num(num); if (!nand) { command_print(CMD_CTX, "invalid nand device number: %s", CMD_ARGV[0]); return ERROR_COMMAND_ARGUMENT_INVALID; } info = nand->controller_priv; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], base_pioc); info->ce.pioc = base_pioc; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[2], pin_num); info->ce.num = pin_num; return ERROR_OK; } static const struct command_registration at91sam9_sub_command_handlers[] = { { .name = "cle", .handler = handle_at91sam9_cle_command, .mode = COMMAND_CONFIG, .help = "set command latch enable address line (default is 22)", .usage = "bank_id address_line", }, { .name = "ale", .handler = handle_at91sam9_ale_command, .mode = COMMAND_CONFIG, .help = "set address latch enable address line (default is 21)", .usage = "bank_id address_line", }, { .name = "rdy_busy", .handler = handle_at91sam9_rdy_busy_command, .mode = COMMAND_CONFIG, .help = "set the GPIO input pin connected to " "the RDY/~BUSY signal (no default)", .usage = "bank_id pio_base_addr pin_num", }, { .name = "ce", .handler = handle_at91sam9_ce_command, .mode = COMMAND_CONFIG, .help = "set the GPIO output pin connected to " "the chip enable signal (no default)", .usage = "bank_id pio_base_addr pin_num", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration at91sam9_command_handler[] = { { .name = "at91sam9", .mode = COMMAND_ANY, .help = "AT91SAM9 NAND flash controller commands", .usage = "", .chain = at91sam9_sub_command_handlers, }, COMMAND_REGISTRATION_DONE }; /** * Structure representing the AT91SAM9 NAND controller. */ struct nand_flash_controller at91sam9_nand_controller = { .name = "at91sam9", .nand_device_command = at91sam9_nand_device_command, .commands = at91sam9_command_handler, .init = at91sam9_init, .command = at91sam9_command, .reset = at91sam9_reset, .address = at91sam9_address, .read_data = at91sam9_read_data, .write_data = at91sam9_write_data, .nand_ready = at91sam9_nand_ready, .read_block_data = at91sam9_read_block_data, .write_block_data = at91sam9_write_block_data, .read_page = at91sam9_read_page, .write_page = at91sam9_write_page, }; openocd-0.7.0/src/flash/nand/davinci.c0000644000175000001440000005415212134336410014453 00000000000000/*************************************************************************** * Copyright (C) 2009 by David Brownell * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /* * DaVinci family NAND controller support for OpenOCD. * * This driver uses hardware ECC (1-bit or 4-bit) unless * the chip is accessed in "raw" mode. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "arm_io.h" #include enum ecc { HWECC1, /* all controllers support 1-bit ECC */ HWECC4, /* newer chips also have 4-bit ECC hardware */ HWECC4_INFIX, /* avoid this layout, except maybe for boot code */ }; struct davinci_nand { uint8_t chipsel; /* chipselect 0..3 == CS2..CS5 */ uint8_t eccmode; /* Async EMIF controller base */ uint32_t aemif; /* NAND chip addresses */ uint32_t data; /* without CLE or ALE */ uint32_t cmd; /* with CLE */ uint32_t addr; /* with ALE */ /* write acceleration */ struct arm_nand_data io; /* page i/o for the relevant flavor of hardware ECC */ int (*read_page)(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size); int (*write_page)(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size); }; #define NANDFCR 0x60 /* flash control register */ #define NANDFSR 0x64 /* flash status register */ #define NANDFECC 0x70 /* 1-bit ECC data, CS0, 1st of 4 */ #define NAND4BITECCLOAD 0xbc /* 4-bit ECC, load saved values */ #define NAND4BITECC 0xc0 /* 4-bit ECC data, 1st of 4 */ #define NANDERRADDR 0xd0 /* 4-bit ECC err addr, 1st of 2 */ #define NANDERRVAL 0xd8 /* 4-bit ECC err value, 1st of 2 */ static int halted(struct target *target, const char *label) { if (target->state == TARGET_HALTED) return true; LOG_ERROR("Target must be halted to use NAND controller (%s)", label); return false; } static int davinci_init(struct nand_device *nand) { struct davinci_nand *info = nand->controller_priv; struct target *target = nand->target; uint32_t nandfcr; if (!halted(target, "init")) return ERROR_NAND_OPERATION_FAILED; /* We require something else to have configured AEMIF to talk * to NAND chip in this range (including timings and width). */ target_read_u32(target, info->aemif + NANDFCR, &nandfcr); if (!(nandfcr & (1 << info->chipsel))) { LOG_ERROR("chip address %08" PRIx32 " not NAND-enabled?", info->data); return ERROR_NAND_OPERATION_FAILED; } /* REVISIT verify: AxCR must be in 8-bit mode, since that's all we * tested. 16 bit support should work too; but not with 4-bit ECC. */ return ERROR_OK; } static int davinci_reset(struct nand_device *nand) { return ERROR_OK; } static int davinci_nand_ready(struct nand_device *nand, int timeout) { struct davinci_nand *info = nand->controller_priv; struct target *target = nand->target; uint32_t nandfsr; /* NOTE: return code is zero/error, else success; not ERROR_* */ if (!halted(target, "ready")) return 0; do { target_read_u32(target, info->aemif + NANDFSR, &nandfsr); if (nandfsr & 0x01) return 1; alive_sleep(1); } while (timeout-- > 0); return 0; } static int davinci_command(struct nand_device *nand, uint8_t command) { struct davinci_nand *info = nand->controller_priv; struct target *target = nand->target; if (!halted(target, "command")) return ERROR_NAND_OPERATION_FAILED; target_write_u8(target, info->cmd, command); return ERROR_OK; } static int davinci_address(struct nand_device *nand, uint8_t address) { struct davinci_nand *info = nand->controller_priv; struct target *target = nand->target; if (!halted(target, "address")) return ERROR_NAND_OPERATION_FAILED; target_write_u8(target, info->addr, address); return ERROR_OK; } static int davinci_write_data(struct nand_device *nand, uint16_t data) { struct davinci_nand *info = nand->controller_priv; struct target *target = nand->target; if (!halted(target, "write_data")) return ERROR_NAND_OPERATION_FAILED; target_write_u8(target, info->data, data); return ERROR_OK; } static int davinci_read_data(struct nand_device *nand, void *data) { struct davinci_nand *info = nand->controller_priv; struct target *target = nand->target; if (!halted(target, "read_data")) return ERROR_NAND_OPERATION_FAILED; target_read_u8(target, info->data, data); return ERROR_OK; } /* REVISIT a bit of native code should let block reads be MUCH faster */ static int davinci_read_block_data(struct nand_device *nand, uint8_t *data, int data_size) { struct davinci_nand *info = nand->controller_priv; struct target *target = nand->target; uint32_t nfdata = info->data; uint32_t tmp; if (!halted(target, "read_block")) return ERROR_NAND_OPERATION_FAILED; while (data_size >= 4) { target_read_u32(target, nfdata, &tmp); data[0] = tmp; data[1] = tmp >> 8; data[2] = tmp >> 16; data[3] = tmp >> 24; data_size -= 4; data += 4; } while (data_size > 0) { target_read_u8(target, nfdata, data); data_size -= 1; data += 1; } return ERROR_OK; } static int davinci_write_block_data(struct nand_device *nand, uint8_t *data, int data_size) { struct davinci_nand *info = nand->controller_priv; struct target *target = nand->target; uint32_t nfdata = info->data; uint32_t tmp; int status; if (!halted(target, "write_block")) return ERROR_NAND_OPERATION_FAILED; /* try the fast way first */ status = arm_nandwrite(&info->io, data, data_size); if (status != ERROR_NAND_NO_BUFFER) return status; /* else do it slowly */ while (data_size >= 4) { tmp = le_to_h_u32(data); target_write_u32(target, nfdata, tmp); data_size -= 4; data += 4; } while (data_size > 0) { target_write_u8(target, nfdata, *data); data_size -= 1; data += 1; } return ERROR_OK; } static int davinci_write_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { struct davinci_nand *info = nand->controller_priv; uint8_t *ooballoc = NULL; int status; if (!nand->device) return ERROR_NAND_DEVICE_NOT_PROBED; if (!halted(nand->target, "write_page")) return ERROR_NAND_OPERATION_FAILED; /* Always write both data and OOB ... we are not "raw" I/O! */ if (!data) { LOG_ERROR("Missing NAND data; try 'nand raw_access enable'"); return ERROR_NAND_OPERATION_FAILED; } /* If we're not given OOB, write 0xff where we don't write ECC codes. */ switch (nand->page_size) { case 512: oob_size = 16; break; case 2048: oob_size = 64; break; case 4096: oob_size = 128; break; default: return ERROR_NAND_OPERATION_FAILED; } if (!oob) { ooballoc = malloc(oob_size); if (!ooballoc) return ERROR_NAND_OPERATION_FAILED; oob = ooballoc; memset(oob, 0x0ff, oob_size); } /* REVISIT avoid wasting SRAM: unless nand->use_raw is set, * use 512 byte chunks. Read side support will often want * to include oob_size ... */ info->io.chunk_size = nand->page_size; status = info->write_page(nand, page, data, data_size, oob, oob_size); free(ooballoc); return status; } static int davinci_read_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { struct davinci_nand *info = nand->controller_priv; if (!nand->device) return ERROR_NAND_DEVICE_NOT_PROBED; if (!halted(nand->target, "read_page")) return ERROR_NAND_OPERATION_FAILED; return info->read_page(nand, page, data, data_size, oob, oob_size); } static void davinci_write_pagecmd(struct nand_device *nand, uint8_t cmd, uint32_t page) { struct davinci_nand *info = nand->controller_priv; struct target *target = nand->target; int page3 = nand->address_cycles - (nand->page_size == 512); /* write command ({page,otp}x{read,program} */ target_write_u8(target, info->cmd, cmd); /* column address (beginning-of-page) */ target_write_u8(target, info->addr, 0); if (nand->page_size > 512) target_write_u8(target, info->addr, 0); /* page address */ target_write_u8(target, info->addr, page); target_write_u8(target, info->addr, page >> 8); if (page3) target_write_u8(target, info->addr, page >> 16); if (page3 == 2) target_write_u8(target, info->addr, page >> 24); } static int davinci_seek_column(struct nand_device *nand, uint16_t column) { struct davinci_nand *info = nand->controller_priv; struct target *target = nand->target; /* Random read, we must have issued a page read already */ target_write_u8(target, info->cmd, NAND_CMD_RNDOUT); target_write_u8(target, info->addr, column); if (nand->page_size > 512) { target_write_u8(target, info->addr, column >> 8); target_write_u8(target, info->cmd, NAND_CMD_RNDOUTSTART); } if (!davinci_nand_ready(nand, 100)) return ERROR_NAND_OPERATION_TIMEOUT; return ERROR_OK; } static int davinci_writepage_tail(struct nand_device *nand, uint8_t *oob, uint32_t oob_size) { struct davinci_nand *info = nand->controller_priv; struct target *target = nand->target; uint8_t status; if (oob_size) davinci_write_block_data(nand, oob, oob_size); /* non-cachemode page program */ target_write_u8(target, info->cmd, NAND_CMD_PAGEPROG); if (!davinci_nand_ready(nand, 100)) return ERROR_NAND_OPERATION_TIMEOUT; if (nand_read_status(nand, &status) != ERROR_OK) { LOG_ERROR("couldn't read status"); return ERROR_NAND_OPERATION_FAILED; } if (status & NAND_STATUS_FAIL) { LOG_ERROR("write operation failed, status: 0x%02x", status); return ERROR_NAND_OPERATION_FAILED; } return ERROR_OK; } /* * All DaVinci family chips support 1-bit ECC on a per-chipselect basis. */ static int davinci_write_page_ecc1(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { unsigned oob_offset; struct davinci_nand *info = nand->controller_priv; struct target *target = nand->target; const uint32_t fcr_addr = info->aemif + NANDFCR; const uint32_t ecc1_addr = info->aemif + NANDFECC + (4 * info->chipsel); uint32_t fcr, ecc1; /* Write contiguous ECC bytes starting at specified offset. * NOTE: Linux reserves twice as many bytes as we need; and * for 16-bit OOB, those extra bytes are discontiguous. */ switch (nand->page_size) { case 512: oob_offset = 0; break; case 2048: oob_offset = 40; break; default: oob_offset = 80; break; } davinci_write_pagecmd(nand, NAND_CMD_SEQIN, page); /* scrub any old ECC state */ target_read_u32(target, ecc1_addr, &ecc1); target_read_u32(target, fcr_addr, &fcr); fcr |= 1 << (8 + info->chipsel); do { /* set "start csX 1bit ecc" bit */ target_write_u32(target, fcr_addr, fcr); /* write 512 bytes */ davinci_write_block_data(nand, data, 512); data += 512; data_size -= 512; /* read the ecc, pack to 3 bytes, and invert so the ecc * in an erased block is correct */ target_read_u32(target, ecc1_addr, &ecc1); ecc1 = (ecc1 & 0x0fff) | ((ecc1 & 0x0fff0000) >> 4); ecc1 = ~ecc1; /* save correct ECC code into oob data */ oob[oob_offset++] = (uint8_t)(ecc1); oob[oob_offset++] = (uint8_t)(ecc1 >> 8); oob[oob_offset++] = (uint8_t)(ecc1 >> 16); } while (data_size); /* write OOB into spare area */ return davinci_writepage_tail(nand, oob, oob_size); } /* * Preferred "new style" ECC layout for use with 4-bit ECC. This somewhat * slows down large page reads done with error correction (since the OOB * is read first, so its ECC data can be used incrementally), but the * manufacturer bad block markers are safe. Contrast: old "infix" style. */ static int davinci_write_page_ecc4(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { static const uint8_t ecc512[] = { 0, 1, 2, 3, 4, /* 5== mfr badblock */ 6, 7, /* 8..12 for BBT or JFFS2 */ 13, 14, 15, }; static const uint8_t ecc2048[] = { 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, }; static const uint8_t ecc4096[] = { 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, }; struct davinci_nand *info = nand->controller_priv; const uint8_t *l; struct target *target = nand->target; const uint32_t fcr_addr = info->aemif + NANDFCR; const uint32_t ecc4_addr = info->aemif + NAND4BITECC; uint32_t fcr, ecc4; /* Use the same ECC layout Linux uses. For small page chips * it's a bit cramped. * * NOTE: at this writing, 4KB pages have issues in Linux * because they need more than 64 bytes of ECC data, which * the standard ECC logic can't handle. */ switch (nand->page_size) { case 512: l = ecc512; break; case 2048: l = ecc2048; break; default: l = ecc4096; break; } davinci_write_pagecmd(nand, NAND_CMD_SEQIN, page); /* scrub any old ECC state */ target_read_u32(target, info->aemif + NANDERRVAL, &ecc4); target_read_u32(target, fcr_addr, &fcr); fcr &= ~(0x03 << 4); fcr |= (1 << 12) | (info->chipsel << 4); do { uint32_t raw_ecc[4], *p; int i; /* start 4bit ecc on csX */ target_write_u32(target, fcr_addr, fcr); /* write 512 bytes */ davinci_write_block_data(nand, data, 512); data += 512; data_size -= 512; /* read the ecc, then save it into 10 bytes in the oob */ for (i = 0; i < 4; i++) { target_read_u32(target, ecc4_addr + 4 * i, &raw_ecc[i]); raw_ecc[i] &= 0x03ff03ff; } for (i = 0, p = raw_ecc; i < 2; i++, p += 2) { oob[*l++] = p[0] & 0xff; oob[*l++] = ((p[0] >> 8) & 0x03) | ((p[0] >> 14) & 0xfc); oob[*l++] = ((p[0] >> 22) & 0x0f) | ((p[1] << 4) & 0xf0); oob[*l++] = ((p[1] >> 4) & 0x3f) | ((p[1] >> 10) & 0xc0); oob[*l++] = (p[1] >> 18) & 0xff; } } while (data_size); /* write OOB into spare area */ return davinci_writepage_tail(nand, oob, oob_size); } /* * "Infix" OOB ... like Linux ECC_HW_SYNDROME. Avoided because it trashes * manufacturer bad block markers, except on small page chips. Once you * write to a page using this scheme, you need specialized code to update * it (code which ignores now-invalid bad block markers). * * This is needed *only* to support older firmware. Older ROM Boot Loaders * need it to read their second stage loader (UBL) into SRAM, but from then * on the whole system can use the cleaner non-infix layouts. Systems with * older second stage loaders (ABL/U-Boot, etc) or other system software * (MVL 4.x/5.x kernels, filesystems, etc) may need it more generally. */ static int davinci_write_page_ecc4infix(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { struct davinci_nand *info = nand->controller_priv; struct target *target = nand->target; const uint32_t fcr_addr = info->aemif + NANDFCR; const uint32_t ecc4_addr = info->aemif + NAND4BITECC; uint32_t fcr, ecc4; davinci_write_pagecmd(nand, NAND_CMD_SEQIN, page); /* scrub any old ECC state */ target_read_u32(target, info->aemif + NANDERRVAL, &ecc4); target_read_u32(target, fcr_addr, &fcr); fcr &= ~(0x03 << 4); fcr |= (1 << 12) | (info->chipsel << 4); do { uint32_t raw_ecc[4], *p; uint8_t *l; int i; /* start 4bit ecc on csX */ target_write_u32(target, fcr_addr, fcr); /* write 512 bytes */ davinci_write_block_data(nand, data, 512); data += 512; data_size -= 512; /* read the ecc */ for (i = 0; i < 4; i++) { target_read_u32(target, ecc4_addr + 4 * i, &raw_ecc[i]); raw_ecc[i] &= 0x03ff03ff; } /* skip 6 bytes of prepad, then pack 10 packed ecc bytes */ for (i = 0, l = oob + 6, p = raw_ecc; i < 2; i++, p += 2) { *l++ = p[0] & 0xff; *l++ = ((p[0] >> 8) & 0x03) | ((p[0] >> 14) & 0xfc); *l++ = ((p[0] >> 22) & 0x0f) | ((p[1] << 4) & 0xf0); *l++ = ((p[1] >> 4) & 0x3f) | ((p[1] >> 10) & 0xc0); *l++ = (p[1] >> 18) & 0xff; } /* write this "out-of-band" data -- infix */ davinci_write_block_data(nand, oob, 16); oob += 16; oob_size -= 16; } while (data_size); /* the last data and OOB writes included the spare area */ return davinci_writepage_tail(nand, NULL, 0); } static int davinci_read_page_ecc4infix(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { int read_size; int want_col, at_col; int ret; davinci_write_pagecmd(nand, NAND_CMD_READ0, page); /* large page devices need a start command */ if (nand->page_size > 512) davinci_command(nand, NAND_CMD_READSTART); if (!davinci_nand_ready(nand, 100)) return ERROR_NAND_OPERATION_TIMEOUT; /* NOTE: not bothering to compute and use ECC data for now */ want_col = 0; at_col = 0; while ((data && data_size) || (oob && oob_size)) { if (data && data_size) { if (want_col != at_col) { /* Reads are slow, so seek past them when we can */ ret = davinci_seek_column(nand, want_col); if (ret != ERROR_OK) return ret; at_col = want_col; } /* read 512 bytes or data_size, whichever is smaller*/ read_size = data_size > 512 ? 512 : data_size; davinci_read_block_data(nand, data, read_size); data += read_size; data_size -= read_size; at_col += read_size; } want_col += 512; if (oob && oob_size) { if (want_col != at_col) { ret = davinci_seek_column(nand, want_col); if (ret != ERROR_OK) return ret; at_col = want_col; } /* read this "out-of-band" data -- infix */ read_size = oob_size > 16 ? 16 : oob_size; davinci_read_block_data(nand, oob, read_size); oob += read_size; oob_size -= read_size; at_col += read_size; } want_col += 16; } return ERROR_OK; } NAND_DEVICE_COMMAND_HANDLER(davinci_nand_device_command) { struct davinci_nand *info; unsigned long chip, aemif; enum ecc eccmode; int chipsel; /* arguments: * - "davinci" * - target * - nand chip address * - ecc mode * - aemif address * Plus someday, optionally, ALE and CLE masks. */ if (CMD_ARGC < 5) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], chip); if (chip == 0) { LOG_ERROR("Invalid NAND chip address %s", CMD_ARGV[2]); goto fail; } if (strcmp(CMD_ARGV[3], "hwecc1") == 0) eccmode = HWECC1; else if (strcmp(CMD_ARGV[3], "hwecc4") == 0) eccmode = HWECC4; else if (strcmp(CMD_ARGV[3], "hwecc4_infix") == 0) eccmode = HWECC4_INFIX; else { LOG_ERROR("Invalid ecc mode %s", CMD_ARGV[3]); goto fail; } COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[4], aemif); if (aemif == 0) { LOG_ERROR("Invalid AEMIF controller address %s", CMD_ARGV[4]); goto fail; } /* REVISIT what we'd *like* to do is look up valid ranges using * target-specific declarations, and not even need to pass the * AEMIF controller address. */ if (aemif == 0x01e00000 /* dm6446, dm357 */ || aemif == 0x01e10000 /* dm335, dm355 */ || aemif == 0x01d10000 /* dm365 */ ) { if (chip < 0x02000000 || chip >= 0x0a000000) { LOG_ERROR("NAND address %08lx out of range?", chip); goto fail; } chipsel = (chip - 0x02000000) >> 25; } else { LOG_ERROR("unrecognized AEMIF controller address %08lx", aemif); goto fail; } info = calloc(1, sizeof *info); if (info == NULL) goto fail; info->eccmode = eccmode; info->chipsel = chipsel; info->aemif = aemif; info->data = chip; info->cmd = chip | 0x10; info->addr = chip | 0x08; nand->controller_priv = info; info->io.target = nand->target; info->io.data = info->data; info->io.op = ARM_NAND_NONE; /* NOTE: for now we don't do any error correction on read. * Nothing else in OpenOCD currently corrects read errors, * and in any case it's *writing* that we care most about. */ info->read_page = nand_read_page_raw; switch (eccmode) { case HWECC1: /* ECC_HW, 1-bit corrections, 3 bytes ECC per 512 data bytes */ info->write_page = davinci_write_page_ecc1; break; case HWECC4: /* ECC_HW, 4-bit corrections, 10 bytes ECC per 512 data bytes */ info->write_page = davinci_write_page_ecc4; break; case HWECC4_INFIX: /* Same 4-bit ECC HW, with problematic page/ecc layout */ info->read_page = davinci_read_page_ecc4infix; info->write_page = davinci_write_page_ecc4infix; break; } return ERROR_OK; fail: return ERROR_NAND_OPERATION_FAILED; } struct nand_flash_controller davinci_nand_controller = { .name = "davinci", .usage = "chip_addr hwecc_mode aemif_addr", .nand_device_command = davinci_nand_device_command, .init = davinci_init, .reset = davinci_reset, .command = davinci_command, .address = davinci_address, .write_data = davinci_write_data, .read_data = davinci_read_data, .write_page = davinci_write_page, .read_page = davinci_read_page, .write_block_data = davinci_write_block_data, .read_block_data = davinci_read_block_data, .nand_ready = davinci_nand_ready, }; openocd-0.7.0/src/flash/nand/orion.c0000644000175000001440000001107212134336410014156 00000000000000/*************************************************************************** * Copyright (C) 2009 by Marvell Semiconductors, Inc. * * Written by Nicolas Pitre * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /* * NAND controller interface for Marvell Orion/Kirkwood SoCs. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "arm_io.h" #include struct orion_nand_controller { struct arm_nand_data io; uint32_t cmd; uint32_t addr; uint32_t data; }; #define CHECK_HALTED \ do { \ if (target->state != TARGET_HALTED) { \ LOG_ERROR("NAND flash access requires halted target"); \ return ERROR_NAND_OPERATION_FAILED; \ } \ } while (0) static int orion_nand_command(struct nand_device *nand, uint8_t command) { struct orion_nand_controller *hw = nand->controller_priv; struct target *target = nand->target; CHECK_HALTED; target_write_u8(target, hw->cmd, command); return ERROR_OK; } static int orion_nand_address(struct nand_device *nand, uint8_t address) { struct orion_nand_controller *hw = nand->controller_priv; struct target *target = nand->target; CHECK_HALTED; target_write_u8(target, hw->addr, address); return ERROR_OK; } static int orion_nand_read(struct nand_device *nand, void *data) { struct orion_nand_controller *hw = nand->controller_priv; struct target *target = nand->target; CHECK_HALTED; target_read_u8(target, hw->data, data); return ERROR_OK; } static int orion_nand_write(struct nand_device *nand, uint16_t data) { struct orion_nand_controller *hw = nand->controller_priv; struct target *target = nand->target; CHECK_HALTED; target_write_u8(target, hw->data, data); return ERROR_OK; } static int orion_nand_slow_block_write(struct nand_device *nand, uint8_t *data, int size) { while (size--) orion_nand_write(nand, *data++); return ERROR_OK; } static int orion_nand_fast_block_write(struct nand_device *nand, uint8_t *data, int size) { struct orion_nand_controller *hw = nand->controller_priv; int retval; hw->io.chunk_size = nand->page_size; retval = arm_nandwrite(&hw->io, data, size); if (retval == ERROR_NAND_NO_BUFFER) retval = orion_nand_slow_block_write(nand, data, size); return retval; } static int orion_nand_reset(struct nand_device *nand) { return orion_nand_command(nand, NAND_CMD_RESET); } NAND_DEVICE_COMMAND_HANDLER(orion_nand_device_command) { struct orion_nand_controller *hw; uint32_t base; uint8_t ale, cle; if (CMD_ARGC != 3) return ERROR_COMMAND_SYNTAX_ERROR; hw = calloc(1, sizeof(*hw)); if (!hw) { LOG_ERROR("no memory for nand controller"); return ERROR_NAND_DEVICE_INVALID; } nand->controller_priv = hw; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], base); cle = 0; ale = 1; hw->data = base; hw->cmd = base + (1 << cle); hw->addr = base + (1 << ale); hw->io.target = nand->target; hw->io.data = hw->data; hw->io.op = ARM_NAND_NONE; return ERROR_OK; } static int orion_nand_init(struct nand_device *nand) { return ERROR_OK; } struct nand_flash_controller orion_nand_controller = { .name = "orion", .usage = " ", .command = orion_nand_command, .address = orion_nand_address, .read_data = orion_nand_read, .write_data = orion_nand_write, .write_block_data = orion_nand_fast_block_write, .reset = orion_nand_reset, .nand_device_command = orion_nand_device_command, .init = orion_nand_init, }; openocd-0.7.0/src/flash/nand/driver.c0000644000175000001440000000713612134336410014331 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Copyright (C) 2007,2008 Øyvind Harboe * * Copyright (C) 2008 by Spencer Oliver * * Copyright (C) 2009 Zachary T Welch * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include "core.h" #include "driver.h" /* NAND flash controller */ extern struct nand_flash_controller nonce_nand_controller; extern struct nand_flash_controller davinci_nand_controller; extern struct nand_flash_controller lpc3180_nand_controller; extern struct nand_flash_controller lpc32xx_nand_controller; extern struct nand_flash_controller orion_nand_controller; extern struct nand_flash_controller s3c2410_nand_controller; extern struct nand_flash_controller s3c2412_nand_controller; extern struct nand_flash_controller s3c2440_nand_controller; extern struct nand_flash_controller s3c2443_nand_controller; extern struct nand_flash_controller s3c6400_nand_controller; extern struct nand_flash_controller mxc_nand_flash_controller; extern struct nand_flash_controller imx31_nand_flash_controller; extern struct nand_flash_controller at91sam9_nand_controller; extern struct nand_flash_controller nuc910_nand_controller; /* extern struct nand_flash_controller boundary_scan_nand_controller; */ static struct nand_flash_controller *nand_flash_controllers[] = { &nonce_nand_controller, &davinci_nand_controller, &lpc3180_nand_controller, &lpc32xx_nand_controller, &orion_nand_controller, &s3c2410_nand_controller, &s3c2412_nand_controller, &s3c2440_nand_controller, &s3c2443_nand_controller, &s3c6400_nand_controller, &mxc_nand_flash_controller, &imx31_nand_flash_controller, &at91sam9_nand_controller, &nuc910_nand_controller, /* &boundary_scan_nand_controller, */ NULL }; struct nand_flash_controller *nand_driver_find_by_name(const char *name) { for (unsigned i = 0; nand_flash_controllers[i]; i++) { struct nand_flash_controller *controller = nand_flash_controllers[i]; if (strcmp(name, controller->name) == 0) return controller; } return NULL; } int nand_driver_walk(nand_driver_walker_t f, void *x) { for (unsigned i = 0; nand_flash_controllers[i]; i++) { int retval = (*f)(nand_flash_controllers[i], x); if (ERROR_OK != retval) return retval; } return ERROR_OK; } openocd-0.7.0/src/flash/nand/core.c0000644000175000001440000006400612134336410013765 00000000000000/*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Copyright (C) 2002 Thomas Gleixner * * Copyright (C) 2009 Zachary T Welch * * * * Partially based on drivers/mtd/nand_ids.c from Linux. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" /* configured NAND devices and NAND Flash command handler */ struct nand_device *nand_devices; void nand_device_add(struct nand_device *c) { if (nand_devices) { struct nand_device *p = nand_devices; while (p && p->next) p = p->next; p->next = c; } else nand_devices = c; } /* Chip ID list * * Manufacturer, ID code, pagesize, chipsize in MegaByte, eraseblock size, * options, name * * Pagesize; 0, 256, 512 * 0 get this information from the extended chip ID * 256 256 Byte page size * 512 512 Byte page size */ static struct nand_info nand_flash_ids[] = { /* Vendor Specific Entries */ { NAND_MFR_SAMSUNG, 0xD5, 8192, 2048, 0x100000, LP_OPTIONS, "K9GAG08 2GB NAND 3.3V x8 MLC 2b/cell"}, { NAND_MFR_SAMSUNG, 0xD7, 8192, 4096, 0x100000, LP_OPTIONS, "K9LBG08 4GB NAND 3.3V x8 MLC 2b/cell"}, /* start "museum" IDs */ { 0x0, 0x6e, 256, 1, 0x1000, 0, "NAND 1MiB 5V 8-bit"}, { 0x0, 0x64, 256, 2, 0x1000, 0, "NAND 2MiB 5V 8-bit"}, { 0x0, 0x6b, 512, 4, 0x2000, 0, "NAND 4MiB 5V 8-bit"}, { 0x0, 0xe8, 256, 1, 0x1000, 0, "NAND 1MiB 3.3V 8-bit"}, { 0x0, 0xec, 256, 1, 0x1000, 0, "NAND 1MiB 3.3V 8-bit"}, { 0x0, 0xea, 256, 2, 0x1000, 0, "NAND 2MiB 3.3V 8-bit"}, { 0x0, 0xd5, 512, 4, 0x2000, 0, "NAND 4MiB 3.3V 8-bit"}, { 0x0, 0xe3, 512, 4, 0x2000, 0, "NAND 4MiB 3.3V 8-bit"}, { 0x0, 0xe5, 512, 4, 0x2000, 0, "NAND 4MiB 3.3V 8-bit"}, { 0x0, 0xd6, 512, 8, 0x2000, 0, "NAND 8MiB 3.3V 8-bit"}, { 0x0, 0x39, 512, 8, 0x2000, 0, "NAND 8MiB 1.8V 8-bit"}, { 0x0, 0xe6, 512, 8, 0x2000, 0, "NAND 8MiB 3.3V 8-bit"}, { 0x0, 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16, "NAND 8MiB 1.8V 16-bit"}, { 0x0, 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16, "NAND 8MiB 3.3V 16-bit"}, /* end "museum" IDs */ { 0x0, 0x33, 512, 16, 0x4000, 0, "NAND 16MiB 1.8V 8-bit"}, { 0x0, 0x73, 512, 16, 0x4000, 0, "NAND 16MiB 3.3V 8-bit"}, { 0x0, 0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16, "NAND 16MiB 1.8V 16-bit"}, { 0x0, 0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16, "NAND 16MiB 3.3V 16-bit"}, { 0x0, 0x35, 512, 32, 0x4000, 0, "NAND 32MiB 1.8V 8-bit"}, { 0x0, 0x75, 512, 32, 0x4000, 0, "NAND 32MiB 3.3V 8-bit"}, { 0x0, 0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16, "NAND 32MiB 1.8V 16-bit"}, { 0x0, 0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16, "NAND 32MiB 3.3V 16-bit"}, { 0x0, 0x36, 512, 64, 0x4000, 0, "NAND 64MiB 1.8V 8-bit"}, { 0x0, 0x76, 512, 64, 0x4000, 0, "NAND 64MiB 3.3V 8-bit"}, { 0x0, 0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16, "NAND 64MiB 1.8V 16-bit"}, { 0x0, 0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16, "NAND 64MiB 3.3V 16-bit"}, { 0x0, 0x78, 512, 128, 0x4000, 0, "NAND 128MiB 1.8V 8-bit"}, { 0x0, 0x39, 512, 128, 0x4000, 0, "NAND 128MiB 1.8V 8-bit"}, { 0x0, 0x79, 512, 128, 0x4000, 0, "NAND 128MiB 3.3V 8-bit"}, { 0x0, 0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16, "NAND 128MiB 1.8V 16-bit"}, { 0x0, 0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16, "NAND 128MiB 1.8V 16-bit"}, { 0x0, 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16, "NAND 128MiB 3.3V 16-bit"}, { 0x0, 0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16, "NAND 128MiB 3.3V 16-bit"}, { 0x0, 0x71, 512, 256, 0x4000, 0, "NAND 256MiB 3.3V 8-bit"}, { 0x0, 0xA2, 0, 64, 0, LP_OPTIONS, "NAND 64MiB 1.8V 8-bit"}, { 0x0, 0xF2, 0, 64, 0, LP_OPTIONS, "NAND 64MiB 3.3V 8-bit"}, { 0x0, 0xB2, 0, 64, 0, LP_OPTIONS16, "NAND 64MiB 1.8V 16-bit"}, { 0x0, 0xC2, 0, 64, 0, LP_OPTIONS16, "NAND 64MiB 3.3V 16-bit"}, { 0x0, 0xA1, 0, 128, 0, LP_OPTIONS, "NAND 128MiB 1.8V 8-bit"}, { 0x0, 0xF1, 0, 128, 0, LP_OPTIONS, "NAND 128MiB 3.3V 8-bit"}, { 0x0, 0xB1, 0, 128, 0, LP_OPTIONS16, "NAND 128MiB 1.8V 16-bit"}, { 0x0, 0xC1, 0, 128, 0, LP_OPTIONS16, "NAND 128MiB 3.3V 16-bit"}, { 0x0, 0xAA, 0, 256, 0, LP_OPTIONS, "NAND 256MiB 1.8V 8-bit"}, { 0x0, 0xDA, 0, 256, 0, LP_OPTIONS, "NAND 256MiB 3.3V 8-bit"}, { 0x0, 0xBA, 0, 256, 0, LP_OPTIONS16, "NAND 256MiB 1.8V 16-bit"}, { 0x0, 0xCA, 0, 256, 0, LP_OPTIONS16, "NAND 256MiB 3.3V 16-bit"}, { 0x0, 0xAC, 0, 512, 0, LP_OPTIONS, "NAND 512MiB 1.8V 8-bit"}, { 0x0, 0xDC, 0, 512, 0, LP_OPTIONS, "NAND 512MiB 3.3V 8-bit"}, { 0x0, 0xBC, 0, 512, 0, LP_OPTIONS16, "NAND 512MiB 1.8V 16-bit"}, { 0x0, 0xCC, 0, 512, 0, LP_OPTIONS16, "NAND 512MiB 3.3V 16-bit"}, { 0x0, 0xA3, 0, 1024, 0, LP_OPTIONS, "NAND 1GiB 1.8V 8-bit"}, { 0x0, 0xD3, 0, 1024, 0, LP_OPTIONS, "NAND 1GiB 3.3V 8-bit"}, { 0x0, 0xB3, 0, 1024, 0, LP_OPTIONS16, "NAND 1GiB 1.8V 16-bit"}, { 0x0, 0xC3, 0, 1024, 0, LP_OPTIONS16, "NAND 1GiB 3.3V 16-bit"}, { 0x0, 0xA5, 0, 2048, 0, LP_OPTIONS, "NAND 2GiB 1.8V 8-bit"}, { 0x0, 0xD5, 0, 8192, 0, LP_OPTIONS, "NAND 2GiB 3.3V 8-bit"}, { 0x0, 0xB5, 0, 2048, 0, LP_OPTIONS16, "NAND 2GiB 1.8V 16-bit"}, { 0x0, 0xC5, 0, 2048, 0, LP_OPTIONS16, "NAND 2GiB 3.3V 16-bit"}, { 0x0, 0x48, 0, 2048, 0, LP_OPTIONS, "NAND 2GiB 3.3V 8-bit"}, {0, 0, 0, 0, 0, 0, NULL} }; /* Manufacturer ID list */ static struct nand_manufacturer nand_manuf_ids[] = { {0x0, "unknown"}, {NAND_MFR_TOSHIBA, "Toshiba"}, {NAND_MFR_SAMSUNG, "Samsung"}, {NAND_MFR_FUJITSU, "Fujitsu"}, {NAND_MFR_NATIONAL, "National"}, {NAND_MFR_RENESAS, "Renesas"}, {NAND_MFR_STMICRO, "ST Micro"}, {NAND_MFR_HYNIX, "Hynix"}, {NAND_MFR_MICRON, "Micron"}, {0x0, NULL}, }; /* * Define default oob placement schemes for large and small page devices */ #if 0 static struct nand_ecclayout nand_oob_8 = { .eccbytes = 3, .eccpos = {0, 1, 2}, .oobfree = { {.offset = 3, .length = 2}, {.offset = 6, .length = 2} } }; #endif /** * Returns the flash bank specified by @a name, which matches the * driver name and a suffix (option) specify the driver-specific * bank number. The suffix consists of the '.' and the driver-specific * bank number: when two davinci banks are defined, then 'davinci.1' refers * to the second (e.g. DM355EVM). */ static struct nand_device *get_nand_device_by_name(const char *name) { unsigned requested = get_flash_name_index(name); unsigned found = 0; struct nand_device *nand; for (nand = nand_devices; NULL != nand; nand = nand->next) { if (strcmp(nand->name, name) == 0) return nand; if (!flash_driver_name_matches(nand->controller->name, name)) continue; if (++found < requested) continue; return nand; } return NULL; } struct nand_device *get_nand_device_by_num(int num) { struct nand_device *p; int i = 0; for (p = nand_devices; p; p = p->next) { if (i++ == num) return p; } return NULL; } COMMAND_HELPER(nand_command_get_device, unsigned name_index, struct nand_device **nand) { const char *str = CMD_ARGV[name_index]; *nand = get_nand_device_by_name(str); if (*nand) return ERROR_OK; unsigned num; COMMAND_PARSE_NUMBER(uint, str, num); *nand = get_nand_device_by_num(num); if (!*nand) { command_print(CMD_CTX, "NAND flash device '%s' not found", str); return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; } int nand_build_bbt(struct nand_device *nand, int first, int last) { uint32_t page; int i; int pages_per_block = (nand->erase_size / nand->page_size); uint8_t oob[6]; int ret; if ((first < 0) || (first >= nand->num_blocks)) first = 0; if ((last >= nand->num_blocks) || (last == -1)) last = nand->num_blocks - 1; page = first * pages_per_block; for (i = first; i <= last; i++) { ret = nand_read_page(nand, page, NULL, 0, oob, 6); if (ret != ERROR_OK) return ret; if (((nand->device->options & NAND_BUSWIDTH_16) && ((oob[0] & oob[1]) != 0xff)) || (((nand->page_size == 512) && (oob[5] != 0xff)) || ((nand->page_size == 2048) && (oob[0] != 0xff)))) { LOG_WARNING("bad block: %i", i); nand->blocks[i].is_bad = 1; } else nand->blocks[i].is_bad = 0; page += pages_per_block; } return ERROR_OK; } int nand_read_status(struct nand_device *nand, uint8_t *status) { if (!nand->device) return ERROR_NAND_DEVICE_NOT_PROBED; /* Send read status command */ nand->controller->command(nand, NAND_CMD_STATUS); alive_sleep(1); /* read status */ if (nand->device->options & NAND_BUSWIDTH_16) { uint16_t data; nand->controller->read_data(nand, &data); *status = data & 0xff; } else nand->controller->read_data(nand, status); return ERROR_OK; } static int nand_poll_ready(struct nand_device *nand, int timeout) { uint8_t status; nand->controller->command(nand, NAND_CMD_STATUS); do { if (nand->device->options & NAND_BUSWIDTH_16) { uint16_t data; nand->controller->read_data(nand, &data); status = data & 0xff; } else nand->controller->read_data(nand, &status); if (status & NAND_STATUS_READY) break; alive_sleep(1); } while (timeout--); return (status & NAND_STATUS_READY) != 0; } int nand_probe(struct nand_device *nand) { uint8_t manufacturer_id, device_id; uint8_t id_buff[6]; int retval; int i; /* clear device data */ nand->device = NULL; nand->manufacturer = NULL; /* clear device parameters */ nand->bus_width = 0; nand->address_cycles = 0; nand->page_size = 0; nand->erase_size = 0; /* initialize controller (device parameters are zero, use controller default) */ retval = nand->controller->init(nand); if (retval != ERROR_OK) { switch (retval) { case ERROR_NAND_OPERATION_FAILED: LOG_DEBUG("controller initialization failed"); return ERROR_NAND_OPERATION_FAILED; case ERROR_NAND_OPERATION_NOT_SUPPORTED: LOG_ERROR( "BUG: controller reported that it doesn't support default parameters"); return ERROR_NAND_OPERATION_FAILED; default: LOG_ERROR("BUG: unknown controller initialization failure"); return ERROR_NAND_OPERATION_FAILED; } } nand->controller->command(nand, NAND_CMD_RESET); nand->controller->reset(nand); nand->controller->command(nand, NAND_CMD_READID); nand->controller->address(nand, 0x0); if (nand->bus_width == 8) { nand->controller->read_data(nand, &manufacturer_id); nand->controller->read_data(nand, &device_id); } else { uint16_t data_buf; nand->controller->read_data(nand, &data_buf); manufacturer_id = data_buf & 0xff; nand->controller->read_data(nand, &data_buf); device_id = data_buf & 0xff; } for (i = 0; nand_flash_ids[i].name; i++) { if (nand_flash_ids[i].id == device_id && (nand_flash_ids[i].mfr_id == manufacturer_id || nand_flash_ids[i].mfr_id == 0)) { nand->device = &nand_flash_ids[i]; break; } } for (i = 0; nand_manuf_ids[i].name; i++) { if (nand_manuf_ids[i].id == manufacturer_id) { nand->manufacturer = &nand_manuf_ids[i]; break; } } if (!nand->manufacturer) { nand->manufacturer = &nand_manuf_ids[0]; nand->manufacturer->id = manufacturer_id; } if (!nand->device) { LOG_ERROR( "unknown NAND flash device found, manufacturer id: 0x%2.2x device id: 0x%2.2x", manufacturer_id, device_id); return ERROR_NAND_OPERATION_FAILED; } LOG_DEBUG("found %s (%s)", nand->device->name, nand->manufacturer->name); /* initialize device parameters */ /* bus width */ if (nand->device->options & NAND_BUSWIDTH_16) nand->bus_width = 16; else nand->bus_width = 8; /* Do we need extended device probe information? */ if (nand->device->page_size == 0 || nand->device->erase_size == 0) { if (nand->bus_width == 8) { nand->controller->read_data(nand, id_buff + 3); nand->controller->read_data(nand, id_buff + 4); nand->controller->read_data(nand, id_buff + 5); } else { uint16_t data_buf; nand->controller->read_data(nand, &data_buf); id_buff[3] = data_buf; nand->controller->read_data(nand, &data_buf); id_buff[4] = data_buf; nand->controller->read_data(nand, &data_buf); id_buff[5] = data_buf >> 8; } } /* page size */ if (nand->device->page_size == 0) nand->page_size = 1 << (10 + (id_buff[4] & 3)); else if (nand->device->page_size == 256) { LOG_ERROR("NAND flashes with 256 byte pagesize are not supported"); return ERROR_NAND_OPERATION_FAILED; } else nand->page_size = nand->device->page_size; /* number of address cycles */ if (nand->page_size <= 512) { /* small page devices */ if (nand->device->chip_size <= 32) nand->address_cycles = 3; else if (nand->device->chip_size <= 8*1024) nand->address_cycles = 4; else { LOG_ERROR("BUG: small page NAND device with more than 8 GiB encountered"); nand->address_cycles = 5; } } else { /* large page devices */ if (nand->device->chip_size <= 128) nand->address_cycles = 4; else if (nand->device->chip_size <= 32*1024) nand->address_cycles = 5; else { LOG_ERROR("BUG: large page NAND device with more than 32 GiB encountered"); nand->address_cycles = 6; } } /* erase size */ if (nand->device->erase_size == 0) { switch ((id_buff[4] >> 4) & 3) { case 0: nand->erase_size = 64 << 10; break; case 1: nand->erase_size = 128 << 10; break; case 2: nand->erase_size = 256 << 10; break; case 3: nand->erase_size = 512 << 10; break; } } else nand->erase_size = nand->device->erase_size; /* initialize controller, but leave parameters at the controllers default */ retval = nand->controller->init(nand); if (retval != ERROR_OK) { switch (retval) { case ERROR_NAND_OPERATION_FAILED: LOG_DEBUG("controller initialization failed"); return ERROR_NAND_OPERATION_FAILED; case ERROR_NAND_OPERATION_NOT_SUPPORTED: LOG_ERROR( "controller doesn't support requested parameters (buswidth: %i, address cycles: %i, page size: %i)", nand->bus_width, nand->address_cycles, nand->page_size); return ERROR_NAND_OPERATION_FAILED; default: LOG_ERROR("BUG: unknown controller initialization failure"); return ERROR_NAND_OPERATION_FAILED; } } nand->num_blocks = (nand->device->chip_size * 1024) / (nand->erase_size / 1024); nand->blocks = malloc(sizeof(struct nand_block) * nand->num_blocks); for (i = 0; i < nand->num_blocks; i++) { nand->blocks[i].size = nand->erase_size; nand->blocks[i].offset = i * nand->erase_size; nand->blocks[i].is_erased = -1; nand->blocks[i].is_bad = -1; } return ERROR_OK; } int nand_erase(struct nand_device *nand, int first_block, int last_block) { int i; uint32_t page; uint8_t status; int retval; if (!nand->device) return ERROR_NAND_DEVICE_NOT_PROBED; if ((first_block < 0) || (last_block >= nand->num_blocks)) return ERROR_COMMAND_SYNTAX_ERROR; /* make sure we know if a block is bad before erasing it */ for (i = first_block; i <= last_block; i++) { if (nand->blocks[i].is_bad == -1) { nand_build_bbt(nand, i, last_block); break; } } for (i = first_block; i <= last_block; i++) { /* Send erase setup command */ nand->controller->command(nand, NAND_CMD_ERASE1); page = i * (nand->erase_size / nand->page_size); /* Send page address */ if (nand->page_size <= 512) { /* row */ nand->controller->address(nand, page & 0xff); nand->controller->address(nand, (page >> 8) & 0xff); /* 3rd cycle only on devices with more than 32 MiB */ if (nand->address_cycles >= 4) nand->controller->address(nand, (page >> 16) & 0xff); /* 4th cycle only on devices with more than 8 GiB */ if (nand->address_cycles >= 5) nand->controller->address(nand, (page >> 24) & 0xff); } else { /* row */ nand->controller->address(nand, page & 0xff); nand->controller->address(nand, (page >> 8) & 0xff); /* 3rd cycle only on devices with more than 128 MiB */ if (nand->address_cycles >= 5) nand->controller->address(nand, (page >> 16) & 0xff); } /* Send erase confirm command */ nand->controller->command(nand, NAND_CMD_ERASE2); retval = nand->controller->nand_ready ? nand->controller->nand_ready(nand, 1000) : nand_poll_ready(nand, 1000); if (!retval) { LOG_ERROR("timeout waiting for NAND flash block erase to complete"); return ERROR_NAND_OPERATION_TIMEOUT; } retval = nand_read_status(nand, &status); if (retval != ERROR_OK) { LOG_ERROR("couldn't read status"); return ERROR_NAND_OPERATION_FAILED; } if (status & 0x1) { LOG_ERROR("didn't erase %sblock %d; status: 0x%2.2x", (nand->blocks[i].is_bad == 1) ? "bad " : "", i, status); /* continue; other blocks might still be erasable */ } nand->blocks[i].is_erased = 1; } return ERROR_OK; } #if 0 static int nand_read_plain(struct nand_device *nand, uint32_t address, uint8_t *data, uint32_t data_size) { uint8_t *page; if (!nand->device) return ERROR_NAND_DEVICE_NOT_PROBED; if (address % nand->page_size) { LOG_ERROR("reads need to be page aligned"); return ERROR_NAND_OPERATION_FAILED; } page = malloc(nand->page_size); while (data_size > 0) { uint32_t thisrun_size = (data_size > nand->page_size) ? nand->page_size : data_size; uint32_t page_address; page_address = address / nand->page_size; nand_read_page(nand, page_address, page, nand->page_size, NULL, 0); memcpy(data, page, thisrun_size); address += thisrun_size; data += thisrun_size; data_size -= thisrun_size; } free(page); return ERROR_OK; } static int nand_write_plain(struct nand_device *nand, uint32_t address, uint8_t *data, uint32_t data_size) { uint8_t *page; if (!nand->device) return ERROR_NAND_DEVICE_NOT_PROBED; if (address % nand->page_size) { LOG_ERROR("writes need to be page aligned"); return ERROR_NAND_OPERATION_FAILED; } page = malloc(nand->page_size); while (data_size > 0) { uint32_t thisrun_size = (data_size > nand->page_size) ? nand->page_size : data_size; uint32_t page_address; memset(page, 0xff, nand->page_size); memcpy(page, data, thisrun_size); page_address = address / nand->page_size; nand_write_page(nand, page_address, page, nand->page_size, NULL, 0); address += thisrun_size; data += thisrun_size; data_size -= thisrun_size; } free(page); return ERROR_OK; } #endif int nand_write_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { uint32_t block; if (!nand->device) return ERROR_NAND_DEVICE_NOT_PROBED; block = page / (nand->erase_size / nand->page_size); if (nand->blocks[block].is_erased == 1) nand->blocks[block].is_erased = 0; if (nand->use_raw || nand->controller->write_page == NULL) return nand_write_page_raw(nand, page, data, data_size, oob, oob_size); else return nand->controller->write_page(nand, page, data, data_size, oob, oob_size); } int nand_read_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { if (!nand->device) return ERROR_NAND_DEVICE_NOT_PROBED; if (nand->use_raw || nand->controller->read_page == NULL) return nand_read_page_raw(nand, page, data, data_size, oob, oob_size); else return nand->controller->read_page(nand, page, data, data_size, oob, oob_size); } int nand_page_command(struct nand_device *nand, uint32_t page, uint8_t cmd, bool oob_only) { if (!nand->device) return ERROR_NAND_DEVICE_NOT_PROBED; if (oob_only && NAND_CMD_READ0 == cmd && nand->page_size <= 512) cmd = NAND_CMD_READOOB; nand->controller->command(nand, cmd); if (nand->page_size <= 512) { /* small page device */ /* column (always 0, we start at the beginning of a page/OOB area) */ nand->controller->address(nand, 0x0); /* row */ nand->controller->address(nand, page & 0xff); nand->controller->address(nand, (page >> 8) & 0xff); /* 4th cycle only on devices with more than 32 MiB */ if (nand->address_cycles >= 4) nand->controller->address(nand, (page >> 16) & 0xff); /* 5th cycle only on devices with more than 8 GiB */ if (nand->address_cycles >= 5) nand->controller->address(nand, (page >> 24) & 0xff); } else { /* large page device */ /* column (0 when we start at the beginning of a page, * or 2048 for the beginning of OOB area) */ nand->controller->address(nand, 0x0); if (oob_only) nand->controller->address(nand, 0x8); else nand->controller->address(nand, 0x0); /* row */ nand->controller->address(nand, page & 0xff); nand->controller->address(nand, (page >> 8) & 0xff); /* 5th cycle only on devices with more than 128 MiB */ if (nand->address_cycles >= 5) nand->controller->address(nand, (page >> 16) & 0xff); /* large page devices need a start command if reading */ if (NAND_CMD_READ0 == cmd) nand->controller->command(nand, NAND_CMD_READSTART); } if (nand->controller->nand_ready) { if (!nand->controller->nand_ready(nand, 100)) return ERROR_NAND_OPERATION_TIMEOUT; } else { /* nand_poll_read() cannot be used during nand read */ alive_sleep(1); } return ERROR_OK; } int nand_read_data_page(struct nand_device *nand, uint8_t *data, uint32_t size) { int retval = ERROR_NAND_NO_BUFFER; if (nand->controller->read_block_data != NULL) retval = (nand->controller->read_block_data)(nand, data, size); if (ERROR_NAND_NO_BUFFER == retval) { uint32_t i; int incr = (nand->device->options & NAND_BUSWIDTH_16) ? 2 : 1; retval = ERROR_OK; for (i = 0; retval == ERROR_OK && i < size; i += incr) { retval = nand->controller->read_data(nand, data); data += incr; } } return retval; } int nand_read_page_raw(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { int retval; retval = nand_page_command(nand, page, NAND_CMD_READ0, !data); if (ERROR_OK != retval) return retval; if (data) nand_read_data_page(nand, data, data_size); if (oob) nand_read_data_page(nand, oob, oob_size); return ERROR_OK; } int nand_write_data_page(struct nand_device *nand, uint8_t *data, uint32_t size) { int retval = ERROR_NAND_NO_BUFFER; if (nand->controller->write_block_data != NULL) retval = (nand->controller->write_block_data)(nand, data, size); if (ERROR_NAND_NO_BUFFER == retval) { bool is16bit = nand->device->options & NAND_BUSWIDTH_16; uint32_t incr = is16bit ? 2 : 1; uint16_t write_data; uint32_t i; for (i = 0; i < size; i += incr) { if (is16bit) write_data = le_to_h_u16(data); else write_data = *data; retval = nand->controller->write_data(nand, write_data); if (ERROR_OK != retval) break; data += incr; } } return retval; } int nand_write_finish(struct nand_device *nand) { int retval; uint8_t status; nand->controller->command(nand, NAND_CMD_PAGEPROG); retval = nand->controller->nand_ready ? nand->controller->nand_ready(nand, 100) : nand_poll_ready(nand, 100); if (!retval) return ERROR_NAND_OPERATION_TIMEOUT; retval = nand_read_status(nand, &status); if (ERROR_OK != retval) { LOG_ERROR("couldn't read status"); return ERROR_NAND_OPERATION_FAILED; } if (status & NAND_STATUS_FAIL) { LOG_ERROR("write operation didn't pass, status: 0x%2.2x", status); return ERROR_NAND_OPERATION_FAILED; } return ERROR_OK; } int nand_write_page_raw(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { int retval; retval = nand_page_command(nand, page, NAND_CMD_SEQIN, !data); if (ERROR_OK != retval) return retval; if (data) { retval = nand_write_data_page(nand, data, data_size); if (ERROR_OK != retval) { LOG_ERROR("Unable to write data to NAND device"); return retval; } } if (oob) { retval = nand_write_data_page(nand, oob, oob_size); if (ERROR_OK != retval) { LOG_ERROR("Unable to write OOB data to NAND device"); return retval; } } return nand_write_finish(nand); } openocd-0.7.0/src/flash/nand/s3c2410.c0000644000175000001440000000733312134336410014034 00000000000000/*************************************************************************** * Copyright (C) 2007, 2008 by Ben Dooks * * ben@fluff.org * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /* * S3C2410 OpenOCD NAND Flash controller support. * * Many thanks to Simtec Electronics for sponsoring this work. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "s3c24xx.h" NAND_DEVICE_COMMAND_HANDLER(s3c2410_nand_device_command) { struct s3c24xx_nand_controller *info; CALL_S3C24XX_DEVICE_COMMAND(nand, &info); /* fill in the address fields for the core device */ info->cmd = S3C2410_NFCMD; info->addr = S3C2410_NFADDR; info->data = S3C2410_NFDATA; info->nfstat = S3C2410_NFSTAT; return ERROR_OK; } static int s3c2410_init(struct nand_device *nand) { struct target *target = nand->target; target_write_u32(target, S3C2410_NFCONF, S3C2410_NFCONF_EN | S3C2410_NFCONF_TACLS(3) | S3C2410_NFCONF_TWRPH0(5) | S3C2410_NFCONF_TWRPH1(3)); return ERROR_OK; } static int s3c2410_write_data(struct nand_device *nand, uint16_t data) { struct target *target = nand->target; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } target_write_u32(target, S3C2410_NFDATA, data); return ERROR_OK; } static int s3c2410_read_data(struct nand_device *nand, void *data) { struct target *target = nand->target; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } target_read_u8(target, S3C2410_NFDATA, data); return ERROR_OK; } static int s3c2410_nand_ready(struct nand_device *nand, int timeout) { struct target *target = nand->target; uint8_t status; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } do { target_read_u8(target, S3C2410_NFSTAT, &status); if (status & S3C2410_NFSTAT_BUSY) return 1; alive_sleep(1); } while (timeout-- > 0); return 0; } struct nand_flash_controller s3c2410_nand_controller = { .name = "s3c2410", .nand_device_command = &s3c2410_nand_device_command, .init = &s3c2410_init, .reset = &s3c24xx_reset, .command = &s3c24xx_command, .address = &s3c24xx_address, .write_data = &s3c2410_write_data, .read_data = &s3c2410_read_data, .write_page = s3c24xx_write_page, .read_page = s3c24xx_read_page, .nand_ready = &s3c2410_nand_ready, }; openocd-0.7.0/src/flash/nand/ecc.c0000644000175000001440000001436712134336410013574 00000000000000/* * This file contains an ECC algorithm from Toshiba that allows for detection * and correction of 1-bit errors in a 256 byte block of data. * * [ Extracted from the initial code found in some early Linux versions. * The current Linux code is bigger while being faster, but this is of * no real benefit when the bottleneck largely remains the JTAG link. ] * * Copyright (C) 2000-2004 Steven J. Hill (sjhill at realitydiluted.com) * Toshiba America Electronics Components, Inc. * * Copyright (C) 2006 Thomas Gleixner * * 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 or (at your option) any * later version. * * This file 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 file; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * * As a special exception, if other files instantiate templates or use * macros or inline functions from these files, or you compile these * files and link them with other works to produce a work based on these * files, these files do not by themselves cause the resulting work to be * covered by the GNU General Public License. However the source code for * these files must still be made available in accordance with section (3) * of the GNU General Public License. * * This exception does not invalidate any other reasons why a work based on * this file might be covered by the GNU General Public License. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "core.h" /* * Pre-calculated 256-way 1 byte column parity */ static const uint8_t nand_ecc_precalc_table[] = { 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00, 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00 }; /* * nand_calculate_ecc - Calculate 3-byte ECC for 256-byte block */ int nand_calculate_ecc(struct nand_device *nand, const uint8_t *dat, uint8_t *ecc_code) { uint8_t idx, reg1, reg2, reg3, tmp1, tmp2; int i; /* Initialize variables */ reg1 = reg2 = reg3 = 0; /* Build up column parity */ for (i = 0; i < 256; i++) { /* Get CP0 - CP5 from table */ idx = nand_ecc_precalc_table[*dat++]; reg1 ^= (idx & 0x3f); /* All bit XOR = 1 ? */ if (idx & 0x40) { reg3 ^= (uint8_t) i; reg2 ^= ~((uint8_t) i); } } /* Create non-inverted ECC code from line parity */ tmp1 = (reg3 & 0x80) >> 0; /* B7 -> B7 */ tmp1 |= (reg2 & 0x80) >> 1; /* B7 -> B6 */ tmp1 |= (reg3 & 0x40) >> 1; /* B6 -> B5 */ tmp1 |= (reg2 & 0x40) >> 2; /* B6 -> B4 */ tmp1 |= (reg3 & 0x20) >> 2; /* B5 -> B3 */ tmp1 |= (reg2 & 0x20) >> 3; /* B5 -> B2 */ tmp1 |= (reg3 & 0x10) >> 3; /* B4 -> B1 */ tmp1 |= (reg2 & 0x10) >> 4; /* B4 -> B0 */ tmp2 = (reg3 & 0x08) << 4; /* B3 -> B7 */ tmp2 |= (reg2 & 0x08) << 3; /* B3 -> B6 */ tmp2 |= (reg3 & 0x04) << 3; /* B2 -> B5 */ tmp2 |= (reg2 & 0x04) << 2; /* B2 -> B4 */ tmp2 |= (reg3 & 0x02) << 2; /* B1 -> B3 */ tmp2 |= (reg2 & 0x02) << 1; /* B1 -> B2 */ tmp2 |= (reg3 & 0x01) << 1; /* B0 -> B1 */ tmp2 |= (reg2 & 0x01) << 0; /* B7 -> B0 */ /* Calculate final ECC code */ #ifdef NAND_ECC_SMC ecc_code[0] = ~tmp2; ecc_code[1] = ~tmp1; #else ecc_code[0] = ~tmp1; ecc_code[1] = ~tmp2; #endif ecc_code[2] = ((~reg1) << 2) | 0x03; return 0; } static inline int countbits(uint32_t b) { int res = 0; for (; b; b >>= 1) res += b & 0x01; return res; } /** * nand_correct_data - Detect and correct a 1 bit error for 256 byte block */ int nand_correct_data(struct nand_device *nand, u_char *dat, u_char *read_ecc, u_char *calc_ecc) { uint8_t s0, s1, s2; #ifdef NAND_ECC_SMC s0 = calc_ecc[0] ^ read_ecc[0]; s1 = calc_ecc[1] ^ read_ecc[1]; s2 = calc_ecc[2] ^ read_ecc[2]; #else s1 = calc_ecc[0] ^ read_ecc[0]; s0 = calc_ecc[1] ^ read_ecc[1]; s2 = calc_ecc[2] ^ read_ecc[2]; #endif if ((s0 | s1 | s2) == 0) return 0; /* Check for a single bit error */ if (((s0 ^ (s0 >> 1)) & 0x55) == 0x55 && ((s1 ^ (s1 >> 1)) & 0x55) == 0x55 && ((s2 ^ (s2 >> 1)) & 0x54) == 0x54) { uint32_t byteoffs, bitnum; byteoffs = (s1 << 0) & 0x80; byteoffs |= (s1 << 1) & 0x40; byteoffs |= (s1 << 2) & 0x20; byteoffs |= (s1 << 3) & 0x10; byteoffs |= (s0 >> 4) & 0x08; byteoffs |= (s0 >> 3) & 0x04; byteoffs |= (s0 >> 2) & 0x02; byteoffs |= (s0 >> 1) & 0x01; bitnum = (s2 >> 5) & 0x04; bitnum |= (s2 >> 4) & 0x02; bitnum |= (s2 >> 3) & 0x01; dat[byteoffs] ^= (1 << bitnum); return 1; } if (countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 << 16)) == 1) return 1; return -1; } openocd-0.7.0/src/flash/nand/s3c24xx.h0000644000175000001440000000574212134336410014262 00000000000000/*************************************************************************** * Copyright (C) 2007, 2008 by Ben Dooks * * ben@fluff.org * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef S3C24xx_NAND_H #define S3C24xx_NAND_H /* * S3C24XX Series OpenOCD NAND Flash controller support. * * Many thanks to Simtec Electronics for sponsoring this work. */ #include "imp.h" #include "s3c24xx_regs.h" #include struct s3c24xx_nand_controller { /* register addresses */ uint32_t cmd; uint32_t addr; uint32_t data; uint32_t nfstat; }; /* Default to using the un-translated NAND register based address */ #undef S3C2410_NFREG #define S3C2410_NFREG(x) ((x) + 0x4e000000) #define S3C24XX_DEVICE_COMMAND() \ COMMAND_HELPER(s3c24xx_nand_device_command, \ struct nand_device *nand, \ struct s3c24xx_nand_controller **info) S3C24XX_DEVICE_COMMAND(); #define CALL_S3C24XX_DEVICE_COMMAND(d, i) \ do { \ int retval = CALL_COMMAND_HANDLER(s3c24xx_nand_device_command, d, i); \ if (ERROR_OK != retval) \ return retval; \ } while (0) int s3c24xx_reset(struct nand_device *nand); int s3c24xx_command(struct nand_device *nand, uint8_t command); int s3c24xx_address(struct nand_device *nand, uint8_t address); int s3c24xx_write_data(struct nand_device *nand, uint16_t data); int s3c24xx_read_data(struct nand_device *nand, void *data); #define s3c24xx_write_page NULL #define s3c24xx_read_page NULL /* code shared between different controllers */ int s3c2440_nand_ready(struct nand_device *nand, int timeout); int s3c2440_read_block_data(struct nand_device *nand, uint8_t *data, int data_size); int s3c2440_write_block_data(struct nand_device *nand, uint8_t *data, int data_size); #endif /* S3C24xx_NAND_H */ openocd-0.7.0/src/flash/nand/mxc.h0000644000175000001440000001613212134336410013626 00000000000000 /*************************************************************************** * Copyright (C) 2009 by Alexei Babich * * Rezonans plc., Chelyabinsk, Russia * * impatt@mail.ru * * * * Copyright (C) 2011 by Erik Ahlen * * Avalon Innovation, Sweden * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /* * Freescale iMX OpenOCD NAND Flash controller support. * based on Freescale iMX2* and iMX3* OpenOCD NAND Flash controller support. * * Many thanks to Ben Dooks for writing s3c24xx driver. */ #define MXC_NF_BUFSIZ (mxc_nf_info->mxc_regs_addr + 0x00) #define MXC_NF_BUFADDR (mxc_nf_info->mxc_regs_addr + 0x04) #define MXC_NF_FADDR (mxc_nf_info->mxc_regs_addr + 0x06) #define MXC_NF_FCMD (mxc_nf_info->mxc_regs_addr + 0x08) #define MXC_NF_BUFCFG (mxc_nf_info->mxc_regs_addr + 0x0a) #define MXC_NF_ECCSTATUS (mxc_nf_info->mxc_regs_addr + 0x0c) #define MXC_NF_ECCMAINPOS (mxc_nf_info->mxc_regs_addr + 0x0e) #define MXC_NF_V1_ECCSPAREPOS (mxc_nf_info->mxc_regs_addr + 0x10) #define MXC_NF_V2_SPAS (mxc_nf_info->mxc_regs_addr + 0x10) #define MXC_NF_FWP (mxc_nf_info->mxc_regs_addr + 0x12) #define MXC_NF_V1_UNLOCKSTART (mxc_nf_info->mxc_regs_addr + 0x14) #define MXC_NF_V1_UNLOCKEND (mxc_nf_info->mxc_regs_addr + 0x16) #define MXC_NF_V2_UNLOCKSTART0 (mxc_nf_info->mxc_regs_addr + 0x20) #define MXC_NF_V2_UNLOCKSTART1 (mxc_nf_info->mxc_regs_addr + 0x24) #define MXC_NF_V2_UNLOCKSTART2 (mxc_nf_info->mxc_regs_addr + 0x28) #define MXC_NF_V2_UNLOCKSTART3 (mxc_nf_info->mxc_regs_addr + 0x2c) #define MXC_NF_V2_UNLOCKEND0 (mxc_nf_info->mxc_regs_addr + 0x22) #define MXC_NF_V2_UNLOCKEND1 (mxc_nf_info->mxc_regs_addr + 0x26) #define MXC_NF_V2_UNLOCKEND2 (mxc_nf_info->mxc_regs_addr + 0x2a) #define MXC_NF_V2_UNLOCKEND3 (mxc_nf_info->mxc_regs_addr + 0x2e) #define MXC_NF_FWPSTATUS (mxc_nf_info->mxc_regs_addr + 0x18) /* * all bits not marked as self-clearing bit */ #define MXC_NF_CFG1 (mxc_nf_info->mxc_regs_addr + 0x1a) #define MXC_NF_CFG2 (mxc_nf_info->mxc_regs_addr + 0x1c) #define MXC_NF_MAIN_BUFFER0 (mxc_nf_info->mxc_base_addr + 0x0000) #define MXC_NF_MAIN_BUFFER1 (mxc_nf_info->mxc_base_addr + 0x0200) #define MXC_NF_MAIN_BUFFER2 (mxc_nf_info->mxc_base_addr + 0x0400) #define MXC_NF_MAIN_BUFFER3 (mxc_nf_info->mxc_base_addr + 0x0600) #define MXC_NF_V1_SPARE_BUFFER0 (mxc_nf_info->mxc_base_addr + 0x0800) #define MXC_NF_V1_SPARE_BUFFER1 (mxc_nf_info->mxc_base_addr + 0x0810) #define MXC_NF_V1_SPARE_BUFFER2 (mxc_nf_info->mxc_base_addr + 0x0820) #define MXC_NF_V1_SPARE_BUFFER3 (mxc_nf_info->mxc_base_addr + 0x0830) #define MXC_NF_V2_MAIN_BUFFER4 (mxc_nf_info->mxc_base_addr + 0x0800) #define MXC_NF_V2_MAIN_BUFFER5 (mxc_nf_info->mxc_base_addr + 0x0a00) #define MXC_NF_V2_MAIN_BUFFER6 (mxc_nf_info->mxc_base_addr + 0x0c00) #define MXC_NF_V2_MAIN_BUFFER7 (mxc_nf_info->mxc_base_addr + 0x0e00) #define MXC_NF_V2_SPARE_BUFFER0 (mxc_nf_info->mxc_base_addr + 0x1000) #define MXC_NF_V2_SPARE_BUFFER1 (mxc_nf_info->mxc_base_addr + 0x1040) #define MXC_NF_V2_SPARE_BUFFER2 (mxc_nf_info->mxc_base_addr + 0x1080) #define MXC_NF_V2_SPARE_BUFFER3 (mxc_nf_info->mxc_base_addr + 0x10c0) #define MXC_NF_V2_SPARE_BUFFER4 (mxc_nf_info->mxc_base_addr + 0x1100) #define MXC_NF_V2_SPARE_BUFFER5 (mxc_nf_info->mxc_base_addr + 0x1140) #define MXC_NF_V2_SPARE_BUFFER6 (mxc_nf_info->mxc_base_addr + 0x1180) #define MXC_NF_V2_SPARE_BUFFER7 (mxc_nf_info->mxc_base_addr + 0x11c0) #define MXC_NF_MAIN_BUFFER_LEN 512 #define MXC_NF_SPARE_BUFFER_LEN 16 #define MXC_NF_SPARE_BUFFER_MAX 64 #define MXC_NF_V1_LAST_BUFFADDR ((MXC_NF_V1_SPARE_BUFFER3) + \ MXC_NF_SPARE_BUFFER_LEN - 2) #define MXC_NF_V2_LAST_BUFFADDR ((MXC_NF_V2_SPARE_BUFFER7) + \ MXC_NF_SPARE_BUFFER_LEN - 2) /* bits in MXC_NF_CFG1 register */ #define MXC_NF_BIT_ECC_4BIT (1<<0) #define MXC_NF_BIT_SPARE_ONLY_EN (1<<2) #define MXC_NF_BIT_ECC_EN (1<<3) #define MXC_NF_BIT_INT_DIS (1<<4) #define MXC_NF_BIT_BE_EN (1<<5) #define MXC_NF_BIT_RESET_EN (1<<6) #define MXC_NF_BIT_FORCE_CE (1<<7) #define MXC_NF_V2_CFG1_PPB(x) (((x) & 0x3) << 9) /* bits in MXC_NF_CFG2 register */ /*Flash Command Input*/ #define MXC_NF_BIT_OP_FCI (1<<0) /* * Flash Address Input */ #define MXC_NF_BIT_OP_FAI (1<<1) /* * Flash Data Input */ #define MXC_NF_BIT_OP_FDI (1<<2) /* see "enum mx_dataout_type" below */ #define MXC_NF_BIT_DATAOUT_TYPE(x) ((x)<<3) #define MXC_NF_BIT_OP_DONE (1<<15) #define MXC_CCM_CGR2 0x53f80028 #define MXC_GPR 0x43fac008 #define MX2_FMCR 0x10027814 #define MX2_FMCR_NF_16BIT_SEL (1<<4) #define MX2_FMCR_NF_FMS (1<<5) #define MX25_RCSR 0x53f80018 #define MX25_RCSR_NF_16BIT_SEL (1<<14) #define MX25_RCSR_NF_FMS (1<<8) #define MX25_RCSR_NF_4K (1<<9) #define MX3_PCSR 0x53f8000c #define MX3_PCSR_NF_16BIT_SEL (1<<31) #define MX3_PCSR_NF_FMS (1<<30) #define MX35_RCSR 0x53f80018 #define MX35_RCSR_NF_16BIT_SEL (1<<14) #define MX35_RCSR_NF_FMS (1<<8) #define MX35_RCSR_NF_4K (1<<9) enum mxc_version { MXC_VERSION_UKWN = 0, MXC_VERSION_MX25 = 1, MXC_VERSION_MX27 = 2, MXC_VERSION_MX31 = 3, MXC_VERSION_MX35 = 4 }; enum mxc_dataout_type { MXC_NF_DATAOUT_PAGE = 1, MXC_NF_DATAOUT_NANDID = 2, MXC_NF_DATAOUT_NANDSTATUS = 4, }; enum mxc_nf_finalize_action { MXC_NF_FIN_NONE, MXC_NF_FIN_DATAOUT, }; struct mxc_nf_flags { unsigned host_little_endian:1; unsigned target_little_endian:1; unsigned nand_readonly:1; unsigned one_kb_sram:1; unsigned hw_ecc_enabled:1; unsigned biswap_enabled:1; }; struct mxc_nf_controller { enum mxc_version mxc_version; uint32_t mxc_base_addr; uint32_t mxc_regs_addr; enum mxc_dataout_type optype; enum mxc_nf_finalize_action fin; struct mxc_nf_flags flags; }; openocd-0.7.0/src/flash/nand/arm_io.c0000644000175000001440000002215312137151330014277 00000000000000/* * Copyright (C) 2009 by Marvell Semiconductors, Inc. * Written by Nicolas Pitre * * Copyright (C) 2009 by David Brownell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 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. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "core.h" #include "arm_io.h" #include #include #include #include /** * Copies code to a working area. This will allocate room for the code plus the * additional amount requested if the working area pointer is null. * * @param target Pointer to the target to copy code to * @param code Pointer to the code area to be copied * @param code_size Size of the code being copied * @param additional Size of the additional area to be allocated in addition to * code * @param area Pointer to a pointer to a working area to copy code to * @return Success or failure of the operation */ static int arm_code_to_working_area(struct target *target, const uint32_t *code, unsigned code_size, unsigned additional, struct working_area **area) { uint8_t code_buf[code_size]; unsigned i; int retval; unsigned size = code_size + additional; /* REVISIT this assumes size doesn't ever change. * That's usually correct; but there are boards with * both large and small page chips, where it won't be... */ /* make sure we have a working area */ if (NULL == *area) { retval = target_alloc_working_area(target, size, area); if (retval != ERROR_OK) { LOG_DEBUG("%s: no %d byte buffer", __func__, (int) size); return ERROR_NAND_NO_BUFFER; } } /* buffer code in target endianness */ for (i = 0; i < code_size / 4; i++) target_buffer_set_u32(target, code_buf + i * 4, code[i]); /* copy code to work area */ retval = target_write_memory(target, (*area)->address, 4, code_size / 4, code_buf); return retval; } /** * ARM-specific bulk write from buffer to address of 8-bit wide NAND. * For now this supports ARMv4,ARMv5 and ARMv7-M cores. * * Enhancements to target_run_algorithm() could enable: * - ARMv6 and ARMv7 cores in ARM mode * * Different code fragments could handle: * - 16-bit wide data (needs different setup) * * @param nand Pointer to the arm_nand_data struct that defines the I/O * @param data Pointer to the data to be copied to flash * @param size Size of the data being copied * @return Success or failure of the operation */ int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size) { struct target *target = nand->target; struct arm_algorithm armv4_5_algo; struct armv7m_algorithm armv7m_algo; void *arm_algo; struct arm *arm = target->arch_info; struct reg_param reg_params[3]; uint32_t target_buf; uint32_t exit_var = 0; int retval; /* Inputs: * r0 NAND data address (byte wide) * r1 buffer address * r2 buffer length */ static const uint32_t code_armv4_5[] = { 0xe4d13001, /* s: ldrb r3, [r1], #1 */ 0xe5c03000, /* strb r3, [r0] */ 0xe2522001, /* subs r2, r2, #1 */ 0x1afffffb, /* bne s */ /* exit: ARMv4 needs hardware breakpoint */ 0xe1200070, /* e: bkpt #0 */ }; /* Inputs: * r0 NAND data address (byte wide) * r1 buffer address * r2 buffer length * * see contrib/loaders/flash/armv7m_io.s for src */ static const uint32_t code_armv7m[] = { 0x3b01f811, 0x3a017003, 0xaffaf47f, 0xbf00be00, }; int target_code_size = 0; const uint32_t *target_code_src = NULL; /* set up algorithm */ if (is_armv7m(target_to_armv7m(target))) { /* armv7m target */ armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC; armv7m_algo.core_mode = ARM_MODE_THREAD; arm_algo = &armv7m_algo; target_code_size = sizeof(code_armv7m); target_code_src = code_armv7m; } else { armv4_5_algo.common_magic = ARM_COMMON_MAGIC; armv4_5_algo.core_mode = ARM_MODE_SVC; armv4_5_algo.core_state = ARM_STATE_ARM; arm_algo = &armv4_5_algo; target_code_size = sizeof(code_armv4_5); target_code_src = code_armv4_5; } if (nand->op != ARM_NAND_WRITE || !nand->copy_area) { retval = arm_code_to_working_area(target, target_code_src, target_code_size, nand->chunk_size, &nand->copy_area); if (retval != ERROR_OK) return retval; } nand->op = ARM_NAND_WRITE; /* copy data to work area */ target_buf = nand->copy_area->address + target_code_size; retval = target_write_buffer(target, target_buf, size, data); if (retval != ERROR_OK) return retval; /* set up parameters */ init_reg_param(®_params[0], "r0", 32, PARAM_IN); init_reg_param(®_params[1], "r1", 32, PARAM_IN); init_reg_param(®_params[2], "r2", 32, PARAM_IN); buf_set_u32(reg_params[0].value, 0, 32, nand->data); buf_set_u32(reg_params[1].value, 0, 32, target_buf); buf_set_u32(reg_params[2].value, 0, 32, size); /* armv4 must exit using a hardware breakpoint */ if (arm->is_armv4) exit_var = nand->copy_area->address + target_code_size - 4; /* use alg to write data from work area to NAND chip */ retval = target_run_algorithm(target, 0, NULL, 3, reg_params, nand->copy_area->address, exit_var, 1000, arm_algo); if (retval != ERROR_OK) LOG_ERROR("error executing hosted NAND write"); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); return retval; } /** * Uses an on-chip algorithm for an ARM device to read from a NAND device and * store the data into the host machine's memory. * * @param nand Pointer to the arm_nand_data struct that defines the I/O * @param data Pointer to the data buffer to store the read data * @param size Amount of data to be stored to the buffer. * @return Success or failure of the operation */ int arm_nandread(struct arm_nand_data *nand, uint8_t *data, uint32_t size) { struct target *target = nand->target; struct arm_algorithm armv4_5_algo; struct armv7m_algorithm armv7m_algo; void *arm_algo; struct arm *arm = target->arch_info; struct reg_param reg_params[3]; uint32_t target_buf; uint32_t exit_var = 0; int retval; /* Inputs: * r0 buffer address * r1 NAND data address (byte wide) * r2 buffer length */ static const uint32_t code_armv4_5[] = { 0xe5d13000, /* s: ldrb r3, [r1] */ 0xe4c03001, /* strb r3, [r0], #1 */ 0xe2522001, /* subs r2, r2, #1 */ 0x1afffffb, /* bne s */ /* exit: ARMv4 needs hardware breakpoint */ 0xe1200070, /* e: bkpt #0 */ }; /* Inputs: * r0 buffer address * r1 NAND data address (byte wide) * r2 buffer length * * see contrib/loaders/flash/armv7m_io.s for src */ static const uint32_t code_armv7m[] = { 0xf800780b, 0x3a013b01, 0xaffaf47f, 0xbf00be00, }; int target_code_size = 0; const uint32_t *target_code_src = NULL; /* set up algorithm */ if (is_armv7m(target_to_armv7m(target))) { /* armv7m target */ armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC; armv7m_algo.core_mode = ARM_MODE_THREAD; arm_algo = &armv7m_algo; target_code_size = sizeof(code_armv7m); target_code_src = code_armv7m; } else { armv4_5_algo.common_magic = ARM_COMMON_MAGIC; armv4_5_algo.core_mode = ARM_MODE_SVC; armv4_5_algo.core_state = ARM_STATE_ARM; arm_algo = &armv4_5_algo; target_code_size = sizeof(code_armv4_5); target_code_src = code_armv4_5; } /* create the copy area if not yet available */ if (nand->op != ARM_NAND_READ || !nand->copy_area) { retval = arm_code_to_working_area(target, target_code_src, target_code_size, nand->chunk_size, &nand->copy_area); if (retval != ERROR_OK) return retval; } nand->op = ARM_NAND_READ; target_buf = nand->copy_area->address + target_code_size; /* set up parameters */ init_reg_param(®_params[0], "r0", 32, PARAM_IN); init_reg_param(®_params[1], "r1", 32, PARAM_IN); init_reg_param(®_params[2], "r2", 32, PARAM_IN); buf_set_u32(reg_params[0].value, 0, 32, target_buf); buf_set_u32(reg_params[1].value, 0, 32, nand->data); buf_set_u32(reg_params[2].value, 0, 32, size); /* armv4 must exit using a hardware breakpoint */ if (arm->is_armv4) exit_var = nand->copy_area->address + target_code_size - 4; /* use alg to write data from NAND chip to work area */ retval = target_run_algorithm(target, 0, NULL, 3, reg_params, nand->copy_area->address, exit_var, 1000, arm_algo); if (retval != ERROR_OK) LOG_ERROR("error executing hosted NAND read"); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); /* read from work area to the host's memory */ retval = target_read_buffer(target, target_buf, size, data); return retval; } openocd-0.7.0/src/flash/nand/s3c2440.c0000644000175000001440000001146012134336410014033 00000000000000/*************************************************************************** * Copyright (C) 2007, 2008 by Ben Dooks * * ben@fluff.org * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /* * S3C2440 OpenOCD NAND Flash controller support. * * Many thanks to Simtec Electronics for sponsoring this work. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "s3c24xx.h" NAND_DEVICE_COMMAND_HANDLER(s3c2440_nand_device_command) { struct s3c24xx_nand_controller *info; CALL_S3C24XX_DEVICE_COMMAND(nand, &info); /* fill in the address fields for the core device */ info->cmd = S3C2440_NFCMD; info->addr = S3C2440_NFADDR; info->data = S3C2440_NFDATA; info->nfstat = S3C2440_NFSTAT; return ERROR_OK; } static int s3c2440_init(struct nand_device *nand) { struct target *target = nand->target; target_write_u32(target, S3C2410_NFCONF, S3C2440_NFCONF_TACLS(3) | S3C2440_NFCONF_TWRPH0(7) | S3C2440_NFCONF_TWRPH1(7)); target_write_u32(target, S3C2440_NFCONT, S3C2440_NFCONT_INITECC | S3C2440_NFCONT_ENABLE); return ERROR_OK; } int s3c2440_nand_ready(struct nand_device *nand, int timeout) { struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; struct target *target = nand->target; uint8_t status; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } do { target_read_u8(target, s3c24xx_info->nfstat, &status); if (status & S3C2440_NFSTAT_READY) return 1; alive_sleep(1); } while (timeout-- > 0); return 0; } /* use the fact we can read/write 4 bytes in one go via a single 32bit op */ int s3c2440_read_block_data(struct nand_device *nand, uint8_t *data, int data_size) { struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; struct target *target = nand->target; uint32_t nfdata = s3c24xx_info->data; uint32_t tmp; LOG_INFO("%s: reading data: %p, %p, %d", __func__, nand, data, data_size); if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } while (data_size >= 4) { target_read_u32(target, nfdata, &tmp); data[0] = tmp; data[1] = tmp >> 8; data[2] = tmp >> 16; data[3] = tmp >> 24; data_size -= 4; data += 4; } while (data_size > 0) { target_read_u8(target, nfdata, data); data_size -= 1; data += 1; } return ERROR_OK; } int s3c2440_write_block_data(struct nand_device *nand, uint8_t *data, int data_size) { struct s3c24xx_nand_controller *s3c24xx_info = nand->controller_priv; struct target *target = nand->target; uint32_t nfdata = s3c24xx_info->data; uint32_t tmp; if (target->state != TARGET_HALTED) { LOG_ERROR("target must be halted to use S3C24XX NAND flash controller"); return ERROR_NAND_OPERATION_FAILED; } while (data_size >= 4) { tmp = le_to_h_u32(data); target_write_u32(target, nfdata, tmp); data_size -= 4; data += 4; } while (data_size > 0) { target_write_u8(target, nfdata, *data); data_size -= 1; data += 1; } return ERROR_OK; } struct nand_flash_controller s3c2440_nand_controller = { .name = "s3c2440", .nand_device_command = &s3c2440_nand_device_command, .init = &s3c2440_init, .reset = &s3c24xx_reset, .command = &s3c24xx_command, .address = &s3c24xx_address, .write_data = &s3c24xx_write_data, .read_data = &s3c24xx_read_data, .write_page = s3c24xx_write_page, .read_page = s3c24xx_read_page, .write_block_data = &s3c2440_write_block_data, .read_block_data = &s3c2440_read_block_data, .nand_ready = &s3c2440_nand_ready, }; openocd-0.7.0/src/flash/nand/s3c2443.c0000644000175000001440000000546012134336410014041 00000000000000/*************************************************************************** * Copyright (C) 2007, 2008 by Ben Dooks * * ben@fluff.org * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /* * S3C2443 OpenOCD NAND Flash controller support. * * Many thanks to Simtec Electronics for sponsoring this work. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "s3c24xx.h" NAND_DEVICE_COMMAND_HANDLER(s3c2443_nand_device_command) { struct s3c24xx_nand_controller *info; CALL_S3C24XX_DEVICE_COMMAND(nand, &info); /* fill in the address fields for the core device */ info->cmd = S3C2440_NFCMD; info->addr = S3C2440_NFADDR; info->data = S3C2440_NFDATA; info->nfstat = S3C2412_NFSTAT; return ERROR_OK; } static int s3c2443_init(struct nand_device *nand) { struct target *target = nand->target; target_write_u32(target, S3C2410_NFCONF, S3C2440_NFCONF_TACLS(3) | S3C2440_NFCONF_TWRPH0(7) | S3C2440_NFCONF_TWRPH1(7)); target_write_u32(target, S3C2440_NFCONT, S3C2412_NFCONT_INIT_MAIN_ECC | S3C2440_NFCONT_ENABLE); return ERROR_OK; } struct nand_flash_controller s3c2443_nand_controller = { .name = "s3c2443", .nand_device_command = &s3c2443_nand_device_command, .init = &s3c2443_init, .reset = &s3c24xx_reset, .command = &s3c24xx_command, .address = &s3c24xx_address, .write_data = &s3c24xx_write_data, .read_data = &s3c24xx_read_data, .write_page = s3c24xx_write_page, .read_page = s3c24xx_read_page, .write_block_data = &s3c2440_write_block_data, .read_block_data = &s3c2440_read_block_data, .nand_ready = &s3c2440_nand_ready, }; openocd-0.7.0/src/flash/nand/tcl.c0000644000175000001440000004050212134336410013612 00000000000000/*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Copyright (C) 2002 Thomas Gleixner * * Copyright (C) 2009 Zachary T Welch * * * * Partially based on drivers/mtd/nand_ids.c from Linux. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "core.h" #include "imp.h" #include "fileio.h" #include /* to be removed */ extern struct nand_device *nand_devices; COMMAND_HANDLER(handle_nand_list_command) { struct nand_device *p; int i; if (!nand_devices) { command_print(CMD_CTX, "no NAND flash devices configured"); return ERROR_OK; } for (p = nand_devices, i = 0; p; p = p->next, i++) { if (p->device) command_print(CMD_CTX, "#%i: %s (%s) " "pagesize: %i, buswidth: %i,\n\t" "blocksize: %i, blocks: %i", i, p->device->name, p->manufacturer->name, p->page_size, p->bus_width, p->erase_size, p->num_blocks); else command_print(CMD_CTX, "#%i: not probed", i); } return ERROR_OK; } COMMAND_HANDLER(handle_nand_info_command) { int i = 0; int j = 0; int first = -1; int last = -1; switch (CMD_ARGC) { default: return ERROR_COMMAND_SYNTAX_ERROR; case 1: first = 0; last = INT32_MAX; break; case 2: COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], i); first = last = i; i = 0; break; case 3: COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], first); COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], last); break; } struct nand_device *p; int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p); if (ERROR_OK != retval) return retval; if (NULL == p->device) { command_print(CMD_CTX, "#%s: not probed", CMD_ARGV[0]); return ERROR_OK; } if (first >= p->num_blocks) first = p->num_blocks - 1; if (last >= p->num_blocks) last = p->num_blocks - 1; command_print(CMD_CTX, "#%i: %s (%s) pagesize: %i, buswidth: %i, erasesize: %i", i++, p->device->name, p->manufacturer->name, p->page_size, p->bus_width, p->erase_size); for (j = first; j <= last; j++) { char *erase_state, *bad_state; if (p->blocks[j].is_erased == 0) erase_state = "not erased"; else if (p->blocks[j].is_erased == 1) erase_state = "erased"; else erase_state = "erase state unknown"; if (p->blocks[j].is_bad == 0) bad_state = ""; else if (p->blocks[j].is_bad == 1) bad_state = " (marked bad)"; else bad_state = " (block condition unknown)"; command_print(CMD_CTX, "\t#%i: 0x%8.8" PRIx32 " (%" PRId32 "kB) %s%s", j, p->blocks[j].offset, p->blocks[j].size / 1024, erase_state, bad_state); } return ERROR_OK; } COMMAND_HANDLER(handle_nand_probe_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; struct nand_device *p; int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p); if (ERROR_OK != retval) return retval; retval = nand_probe(p); if (retval == ERROR_OK) { command_print(CMD_CTX, "NAND flash device '%s (%s)' found", p->device->name, p->manufacturer->name); } return retval; } COMMAND_HANDLER(handle_nand_erase_command) { if (CMD_ARGC != 1 && CMD_ARGC != 3) return ERROR_COMMAND_SYNTAX_ERROR; struct nand_device *p; int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p); if (ERROR_OK != retval) return retval; unsigned long offset; unsigned long length; /* erase specified part of the chip; or else everything */ if (CMD_ARGC == 3) { unsigned long size = p->erase_size * p->num_blocks; COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[1], offset); if ((offset % p->erase_size) != 0 || offset >= size) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], length); if ((length == 0) || (length % p->erase_size) != 0 || (length + offset) > size) return ERROR_COMMAND_SYNTAX_ERROR; offset /= p->erase_size; length /= p->erase_size; } else { offset = 0; length = p->num_blocks; } retval = nand_erase(p, offset, offset + length - 1); if (retval == ERROR_OK) { command_print(CMD_CTX, "erased blocks %lu to %lu " "on NAND flash device #%s '%s'", offset, offset + length - 1, CMD_ARGV[0], p->device->name); } return retval; } COMMAND_HANDLER(handle_nand_check_bad_blocks_command) { int first = -1; int last = -1; if ((CMD_ARGC < 1) || (CMD_ARGC > 3) || (CMD_ARGC == 2)) return ERROR_COMMAND_SYNTAX_ERROR; struct nand_device *p; int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p); if (ERROR_OK != retval) return retval; if (CMD_ARGC == 3) { unsigned long offset; unsigned long length; COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[1], offset); if (offset % p->erase_size) return ERROR_COMMAND_SYNTAX_ERROR; offset /= p->erase_size; COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], length); if (length % p->erase_size) return ERROR_COMMAND_SYNTAX_ERROR; length -= 1; length /= p->erase_size; first = offset; last = offset + length; } retval = nand_build_bbt(p, first, last); if (retval == ERROR_OK) { command_print(CMD_CTX, "checked NAND flash device for bad blocks, " "use \"nand info\" command to list blocks"); } return retval; } COMMAND_HANDLER(handle_nand_write_command) { struct nand_device *nand = NULL; struct nand_fileio_state s; int retval = CALL_COMMAND_HANDLER(nand_fileio_parse_args, &s, &nand, FILEIO_READ, false, true); if (ERROR_OK != retval) return retval; uint32_t total_bytes = s.size; while (s.size > 0) { int bytes_read = nand_fileio_read(nand, &s); if (bytes_read <= 0) { command_print(CMD_CTX, "error while reading file"); return nand_fileio_cleanup(&s); } s.size -= bytes_read; retval = nand_write_page(nand, s.address / nand->page_size, s.page, s.page_size, s.oob, s.oob_size); if (ERROR_OK != retval) { command_print(CMD_CTX, "failed writing file %s " "to NAND flash %s at offset 0x%8.8" PRIx32, CMD_ARGV[1], CMD_ARGV[0], s.address); return nand_fileio_cleanup(&s); } s.address += s.page_size; } if (nand_fileio_finish(&s) == ERROR_OK) { command_print(CMD_CTX, "wrote file %s to NAND flash %s up to " "offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)", CMD_ARGV[1], CMD_ARGV[0], s.address, duration_elapsed(&s.bench), duration_kbps(&s.bench, total_bytes)); } return ERROR_OK; } COMMAND_HANDLER(handle_nand_verify_command) { struct nand_device *nand = NULL; struct nand_fileio_state file; int retval = CALL_COMMAND_HANDLER(nand_fileio_parse_args, &file, &nand, FILEIO_READ, false, true); if (ERROR_OK != retval) return retval; struct nand_fileio_state dev; nand_fileio_init(&dev); dev.address = file.address; dev.size = file.size; dev.oob_format = file.oob_format; retval = nand_fileio_start(CMD_CTX, nand, NULL, FILEIO_NONE, &dev); if (ERROR_OK != retval) return retval; while (file.size > 0) { retval = nand_read_page(nand, dev.address / dev.page_size, dev.page, dev.page_size, dev.oob, dev.oob_size); if (ERROR_OK != retval) { command_print(CMD_CTX, "reading NAND flash page failed"); nand_fileio_cleanup(&dev); nand_fileio_cleanup(&file); return retval; } int bytes_read = nand_fileio_read(nand, &file); if (bytes_read <= 0) { command_print(CMD_CTX, "error while reading file"); nand_fileio_cleanup(&dev); nand_fileio_cleanup(&file); return ERROR_FAIL; } if ((dev.page && memcmp(dev.page, file.page, dev.page_size)) || (dev.oob && memcmp(dev.oob, file.oob, dev.oob_size))) { command_print(CMD_CTX, "NAND flash contents differ " "at 0x%8.8" PRIx32, dev.address); nand_fileio_cleanup(&dev); nand_fileio_cleanup(&file); return ERROR_FAIL; } file.size -= bytes_read; dev.address += nand->page_size; } if (nand_fileio_finish(&file) == ERROR_OK) { command_print(CMD_CTX, "verified file %s in NAND flash %s " "up to offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)", CMD_ARGV[1], CMD_ARGV[0], dev.address, duration_elapsed(&file.bench), duration_kbps(&file.bench, dev.size)); } return nand_fileio_cleanup(&dev); } COMMAND_HANDLER(handle_nand_dump_command) { int filesize; struct nand_device *nand = NULL; struct nand_fileio_state s; int retval = CALL_COMMAND_HANDLER(nand_fileio_parse_args, &s, &nand, FILEIO_WRITE, true, false); if (ERROR_OK != retval) return retval; while (s.size > 0) { size_t size_written; retval = nand_read_page(nand, s.address / nand->page_size, s.page, s.page_size, s.oob, s.oob_size); if (ERROR_OK != retval) { command_print(CMD_CTX, "reading NAND flash page failed"); nand_fileio_cleanup(&s); return retval; } if (NULL != s.page) fileio_write(&s.fileio, s.page_size, s.page, &size_written); if (NULL != s.oob) fileio_write(&s.fileio, s.oob_size, s.oob, &size_written); s.size -= nand->page_size; s.address += nand->page_size; } retval = fileio_size(&s.fileio, &filesize); if (retval != ERROR_OK) return retval; if (nand_fileio_finish(&s) == ERROR_OK) { command_print(CMD_CTX, "dumped %ld bytes in %fs (%0.3f KiB/s)", (long)filesize, duration_elapsed(&s.bench), duration_kbps(&s.bench, filesize)); } return ERROR_OK; } COMMAND_HANDLER(handle_nand_raw_access_command) { if ((CMD_ARGC < 1) || (CMD_ARGC > 2)) return ERROR_COMMAND_SYNTAX_ERROR; struct nand_device *p; int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &p); if (ERROR_OK != retval) return retval; if (NULL == p->device) { command_print(CMD_CTX, "#%s: not probed", CMD_ARGV[0]); return ERROR_OK; } if (CMD_ARGC == 2) COMMAND_PARSE_ENABLE(CMD_ARGV[1], p->use_raw); const char *msg = p->use_raw ? "enabled" : "disabled"; command_print(CMD_CTX, "raw access is %s", msg); return ERROR_OK; } static const struct command_registration nand_exec_command_handlers[] = { { .name = "list", .handler = handle_nand_list_command, .mode = COMMAND_EXEC, .help = "list configured NAND flash devices", }, { .name = "info", .handler = handle_nand_info_command, .mode = COMMAND_EXEC, .usage = "[banknum | first_bank_num last_bank_num]", .help = "print info about one or more NAND flash devices", }, { .name = "probe", .handler = handle_nand_probe_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "identify NAND flash device", }, { .name = "check_bad_blocks", .handler = handle_nand_check_bad_blocks_command, .mode = COMMAND_EXEC, .usage = "bank_id [offset length]", .help = "check all or part of NAND flash device for bad blocks", }, { .name = "erase", .handler = handle_nand_erase_command, .mode = COMMAND_EXEC, .usage = "bank_id [offset length]", .help = "erase all or subset of blocks on NAND flash device", }, { .name = "dump", .handler = handle_nand_dump_command, .mode = COMMAND_EXEC, .usage = "bank_id filename offset length " "['oob_raw'|'oob_only']", .help = "dump from NAND flash device", }, { .name = "verify", .handler = handle_nand_verify_command, .mode = COMMAND_EXEC, .usage = "bank_id filename offset " "['oob_raw'|'oob_only'|'oob_softecc'|'oob_softecc_kw']", .help = "verify NAND flash device", }, { .name = "write", .handler = handle_nand_write_command, .mode = COMMAND_EXEC, .usage = "bank_id filename offset " "['oob_raw'|'oob_only'|'oob_softecc'|'oob_softecc_kw']", .help = "write to NAND flash device", }, { .name = "raw_access", .handler = handle_nand_raw_access_command, .mode = COMMAND_EXEC, .usage = "bank_id ['enable'|'disable']", .help = "raw access to NAND flash device", }, COMMAND_REGISTRATION_DONE }; static int nand_init(struct command_context *cmd_ctx) { if (!nand_devices) return ERROR_OK; struct command *parent = command_find_in_context(cmd_ctx, "nand"); return register_commands(cmd_ctx, parent, nand_exec_command_handlers); } COMMAND_HANDLER(handle_nand_init_command) { if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; static bool nand_initialized; if (nand_initialized) { LOG_INFO("'nand init' has already been called"); return ERROR_OK; } nand_initialized = true; LOG_DEBUG("Initializing NAND devices..."); return nand_init(CMD_CTX); } static int nand_list_walker(struct nand_flash_controller *c, void *x) { struct command_context *cmd_ctx = (struct command_context *)x; command_print(cmd_ctx, " %s", c->name); return ERROR_OK; } COMMAND_HANDLER(handle_nand_list_drivers) { command_print(CMD_CTX, "Available NAND flash controller drivers:"); return nand_driver_walk(&nand_list_walker, CMD_CTX); } static COMMAND_HELPER(create_nand_device, const char *bank_name, struct nand_flash_controller *controller) { struct nand_device *c; struct target *target; int retval; if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; target = get_target(CMD_ARGV[1]); if (!target) { LOG_ERROR("invalid target %s", CMD_ARGV[1]); return ERROR_COMMAND_ARGUMENT_INVALID; } if (NULL != controller->commands) { retval = register_commands(CMD_CTX, NULL, controller->commands); if (ERROR_OK != retval) return retval; } c = malloc(sizeof(struct nand_device)); if (c == NULL) { LOG_ERROR("End of memory"); return ERROR_FAIL; } c->name = strdup(bank_name); c->target = target; c->controller = controller; c->controller_priv = NULL; c->manufacturer = NULL; c->device = NULL; c->bus_width = 0; c->address_cycles = 0; c->page_size = 0; c->use_raw = 0; c->next = NULL; retval = CALL_COMMAND_HANDLER(controller->nand_device_command, c); if (ERROR_OK != retval) { LOG_ERROR("'%s' driver rejected nand flash. Usage: %s", controller->name, controller->usage); free(c); return retval; } if (controller->usage == NULL) LOG_DEBUG("'%s' driver usage field missing", controller->name); nand_device_add(c); return ERROR_OK; } COMMAND_HANDLER(handle_nand_device_command) { if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; /* save name and increment (for compatibility) with drivers */ const char *bank_name = *CMD_ARGV++; CMD_ARGC--; const char *driver_name = CMD_ARGV[0]; struct nand_flash_controller *controller; controller = nand_driver_find_by_name(CMD_ARGV[0]); if (NULL == controller) { LOG_ERROR("No valid NAND flash driver found (%s)", driver_name); return CALL_COMMAND_HANDLER(handle_nand_list_drivers); } return CALL_COMMAND_HANDLER(create_nand_device, bank_name, controller); } static const struct command_registration nand_config_command_handlers[] = { { .name = "device", .handler = &handle_nand_device_command, .mode = COMMAND_CONFIG, .help = "defines a new NAND bank", .usage = "bank_id driver target [driver_options ...]", }, { .name = "drivers", .handler = &handle_nand_list_drivers, .mode = COMMAND_ANY, .help = "lists available NAND drivers", .usage = "" }, { .name = "init", .mode = COMMAND_CONFIG, .handler = &handle_nand_init_command, .help = "initialize NAND devices", .usage = "" }, COMMAND_REGISTRATION_DONE }; static const struct command_registration nand_command_handlers[] = { { .name = "nand", .mode = COMMAND_ANY, .help = "NAND flash command group", .usage = "", .chain = nand_config_command_handlers, }, COMMAND_REGISTRATION_DONE }; int nand_register_commands(struct command_context *cmd_ctx) { return register_commands(cmd_ctx, NULL, nand_command_handlers); } openocd-0.7.0/src/flash/nand/mxc.c0000644000175000001440000007163612134336410013633 00000000000000/*************************************************************************** * Copyright (C) 2009 by Alexei Babich * * Rezonans plc., Chelyabinsk, Russia * * impatt@mail.ru * * * * Copyright (C) 2010 by Gaetan CARLIER * * Trump s.a., Belgium * * * * Copyright (C) 2011 by Erik Ahlen * * Avalon Innovation, Sweden * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /* * Freescale iMX OpenOCD NAND Flash controller support. * based on Freescale iMX2* and iMX3* OpenOCD NAND Flash controller support. */ /* * driver tested with Samsung K9F2G08UXA and Numonyx/ST NAND02G-B2D @mxc * tested "nand probe #", "nand erase # 0 #", "nand dump # file 0 #", * "nand write # file 0", "nand verify" * * get_next_halfword_from_sram_buffer() not tested * !! all function only tested with 2k page nand device; mxc_write_page * writes the 4 MAIN_BUFFER's and is not compatible with < 2k page * !! oob must be be used due to NFS bug * !! oob must be 64 bytes per 2KiB page */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "mxc.h" #include #define OOB_SIZE 64 #define nfc_is_v1() (mxc_nf_info->mxc_version == MXC_VERSION_MX27 || \ mxc_nf_info->mxc_version == MXC_VERSION_MX31) #define nfc_is_v2() (mxc_nf_info->mxc_version == MXC_VERSION_MX25 || \ mxc_nf_info->mxc_version == MXC_VERSION_MX35) /* This permits to print (in LOG_INFO) how much bytes * has been written after a page read or write. * This is useful when OpenOCD is used with a graphical * front-end to estimate progression of the global read/write */ #undef _MXC_PRINT_STAT /* #define _MXC_PRINT_STAT */ static const char target_not_halted_err_msg[] = "target must be halted to use mxc NAND flash controller"; static const char data_block_size_err_msg[] = "minimal granularity is one half-word, %" PRId32 " is incorrect"; static const char sram_buffer_bounds_err_msg[] = "trying to access out of SRAM buffer bound (addr=0x%" PRIx32 ")"; static const char get_status_register_err_msg[] = "can't get NAND status"; static uint32_t in_sram_address; static unsigned char sign_of_sequental_byte_read; static uint32_t align_address_v2(struct nand_device *nand, uint32_t addr); static int initialize_nf_controller(struct nand_device *nand); static int get_next_byte_from_sram_buffer(struct nand_device *nand, uint8_t *value); static int get_next_halfword_from_sram_buffer(struct nand_device *nand, uint16_t *value); static int poll_for_complete_op(struct nand_device *nand, const char *text); static int validate_target_state(struct nand_device *nand); static int do_data_output(struct nand_device *nand); static int mxc_command(struct nand_device *nand, uint8_t command); static int mxc_address(struct nand_device *nand, uint8_t address); NAND_DEVICE_COMMAND_HANDLER(mxc_nand_device_command) { struct mxc_nf_controller *mxc_nf_info; int hwecc_needed; int x; mxc_nf_info = malloc(sizeof(struct mxc_nf_controller)); if (mxc_nf_info == NULL) { LOG_ERROR("no memory for nand controller"); return ERROR_FAIL; } nand->controller_priv = mxc_nf_info; if (CMD_ARGC < 4) { LOG_ERROR("use \"nand device mxc target mx25|mx27|mx31|mx35 noecc|hwecc [biswap]\""); return ERROR_FAIL; } /* * check board type */ if (strcmp(CMD_ARGV[2], "mx25") == 0) { mxc_nf_info->mxc_version = MXC_VERSION_MX25; mxc_nf_info->mxc_base_addr = 0xBB000000; mxc_nf_info->mxc_regs_addr = mxc_nf_info->mxc_base_addr + 0x1E00; } else if (strcmp(CMD_ARGV[2], "mx27") == 0) { mxc_nf_info->mxc_version = MXC_VERSION_MX27; mxc_nf_info->mxc_base_addr = 0xD8000000; mxc_nf_info->mxc_regs_addr = mxc_nf_info->mxc_base_addr + 0x0E00; } else if (strcmp(CMD_ARGV[2], "mx31") == 0) { mxc_nf_info->mxc_version = MXC_VERSION_MX31; mxc_nf_info->mxc_base_addr = 0xB8000000; mxc_nf_info->mxc_regs_addr = mxc_nf_info->mxc_base_addr + 0x0E00; } else if (strcmp(CMD_ARGV[2], "mx35") == 0) { mxc_nf_info->mxc_version = MXC_VERSION_MX35; mxc_nf_info->mxc_base_addr = 0xBB000000; mxc_nf_info->mxc_regs_addr = mxc_nf_info->mxc_base_addr + 0x1E00; } /* * check hwecc requirements */ hwecc_needed = strcmp(CMD_ARGV[3], "hwecc"); if (hwecc_needed == 0) mxc_nf_info->flags.hw_ecc_enabled = 1; else mxc_nf_info->flags.hw_ecc_enabled = 0; mxc_nf_info->optype = MXC_NF_DATAOUT_PAGE; mxc_nf_info->fin = MXC_NF_FIN_NONE; mxc_nf_info->flags.target_little_endian = (nand->target->endianness == TARGET_LITTLE_ENDIAN); /* * should factory bad block indicator be swaped * as a workaround for how the nfc handles pages. */ if (CMD_ARGC > 4 && strcmp(CMD_ARGV[4], "biswap") == 0) { LOG_DEBUG("BI-swap enabled"); mxc_nf_info->flags.biswap_enabled = 1; } /* * testing host endianness */ x = 1; if (*(char *) &x == 1) mxc_nf_info->flags.host_little_endian = 1; else mxc_nf_info->flags.host_little_endian = 0; return ERROR_OK; } COMMAND_HANDLER(handle_mxc_biswap_command) { struct nand_device *nand = NULL; struct mxc_nf_controller *mxc_nf_info = NULL; if (CMD_ARGC < 1 || CMD_ARGC > 2) return ERROR_COMMAND_SYNTAX_ERROR; int retval = CALL_COMMAND_HANDLER(nand_command_get_device, 0, &nand); if (retval != ERROR_OK) { command_print(CMD_CTX, "invalid nand device number or name: %s", CMD_ARGV[0]); return ERROR_COMMAND_ARGUMENT_INVALID; } mxc_nf_info = nand->controller_priv; if (CMD_ARGC == 2) { if (strcmp(CMD_ARGV[1], "enable") == 0) mxc_nf_info->flags.biswap_enabled = true; else mxc_nf_info->flags.biswap_enabled = false; } if (mxc_nf_info->flags.biswap_enabled) command_print(CMD_CTX, "BI-swapping enabled on %s", nand->name); else command_print(CMD_CTX, "BI-swapping disabled on %s", nand->name); return ERROR_OK; } static const struct command_registration mxc_sub_command_handlers[] = { { .name = "biswap", .handler = handle_mxc_biswap_command, .help = "Turns on/off bad block information swaping from main area, " "without parameter query status.", .usage = "bank_id ['enable'|'disable']", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration mxc_nand_command_handler[] = { { .name = "mxc", .mode = COMMAND_ANY, .help = "MXC NAND flash controller commands", .chain = mxc_sub_command_handlers }, COMMAND_REGISTRATION_DONE }; static int mxc_init(struct nand_device *nand) { struct mxc_nf_controller *mxc_nf_info = nand->controller_priv; struct target *target = nand->target; int validate_target_result; uint16_t buffsize_register_content; uint32_t sreg_content; uint32_t SREG = MX2_FMCR; uint32_t SEL_16BIT = MX2_FMCR_NF_16BIT_SEL; uint32_t SEL_FMS = MX2_FMCR_NF_FMS; int retval; uint16_t nand_status_content; /* * validate target state */ validate_target_result = validate_target_state(nand); if (validate_target_result != ERROR_OK) return validate_target_result; if (nfc_is_v1()) { target_read_u16(target, MXC_NF_BUFSIZ, &buffsize_register_content); mxc_nf_info->flags.one_kb_sram = !(buffsize_register_content & 0x000f); } else mxc_nf_info->flags.one_kb_sram = 0; if (mxc_nf_info->mxc_version == MXC_VERSION_MX31) { SREG = MX3_PCSR; SEL_16BIT = MX3_PCSR_NF_16BIT_SEL; SEL_FMS = MX3_PCSR_NF_FMS; } else if (mxc_nf_info->mxc_version == MXC_VERSION_MX25) { SREG = MX25_RCSR; SEL_16BIT = MX25_RCSR_NF_16BIT_SEL; SEL_FMS = MX25_RCSR_NF_FMS; } else if (mxc_nf_info->mxc_version == MXC_VERSION_MX35) { SREG = MX35_RCSR; SEL_16BIT = MX35_RCSR_NF_16BIT_SEL; SEL_FMS = MX35_RCSR_NF_FMS; } target_read_u32(target, SREG, &sreg_content); if (!nand->bus_width) { /* bus_width not yet defined. Read it from MXC_FMCR */ nand->bus_width = (sreg_content & SEL_16BIT) ? 16 : 8; } else { /* bus_width forced in soft. Sync it to MXC_FMCR */ sreg_content |= ((nand->bus_width == 16) ? SEL_16BIT : 0x00000000); target_write_u32(target, SREG, sreg_content); } if (nand->bus_width == 16) LOG_DEBUG("MXC_NF : bus is 16-bit width"); else LOG_DEBUG("MXC_NF : bus is 8-bit width"); if (!nand->page_size) nand->page_size = (sreg_content & SEL_FMS) ? 2048 : 512; else { sreg_content |= ((nand->page_size == 2048) ? SEL_FMS : 0x00000000); target_write_u32(target, SREG, sreg_content); } if (mxc_nf_info->flags.one_kb_sram && (nand->page_size == 2048)) { LOG_ERROR("NAND controller have only 1 kb SRAM, so " "pagesize 2048 is incompatible with it"); } else LOG_DEBUG("MXC_NF : NAND controller can handle pagesize of 2048"); if (nfc_is_v2() && sreg_content & MX35_RCSR_NF_4K) LOG_ERROR("MXC driver does not have support for 4k pagesize."); initialize_nf_controller(nand); retval = ERROR_OK; retval |= mxc_command(nand, NAND_CMD_STATUS); retval |= mxc_address(nand, 0x00); retval |= do_data_output(nand); if (retval != ERROR_OK) { LOG_ERROR(get_status_register_err_msg); return ERROR_FAIL; } target_read_u16(target, MXC_NF_MAIN_BUFFER0, &nand_status_content); if (!(nand_status_content & 0x0080)) { LOG_INFO("NAND read-only"); mxc_nf_info->flags.nand_readonly = 1; } else mxc_nf_info->flags.nand_readonly = 0; return ERROR_OK; } static int mxc_read_data(struct nand_device *nand, void *data) { int validate_target_result; int try_data_output_from_nand_chip; /* * validate target state */ validate_target_result = validate_target_state(nand); if (validate_target_result != ERROR_OK) return validate_target_result; /* * get data from nand chip */ try_data_output_from_nand_chip = do_data_output(nand); if (try_data_output_from_nand_chip != ERROR_OK) { LOG_ERROR("mxc_read_data : read data failed : '%x'", try_data_output_from_nand_chip); return try_data_output_from_nand_chip; } if (nand->bus_width == 16) get_next_halfword_from_sram_buffer(nand, data); else get_next_byte_from_sram_buffer(nand, data); return ERROR_OK; } static int mxc_write_data(struct nand_device *nand, uint16_t data) { LOG_ERROR("write_data() not implemented"); return ERROR_NAND_OPERATION_FAILED; } static int mxc_reset(struct nand_device *nand) { /* * validate target state */ int validate_target_result; validate_target_result = validate_target_state(nand); if (validate_target_result != ERROR_OK) return validate_target_result; initialize_nf_controller(nand); return ERROR_OK; } static int mxc_command(struct nand_device *nand, uint8_t command) { struct mxc_nf_controller *mxc_nf_info = nand->controller_priv; struct target *target = nand->target; int validate_target_result; int poll_result; /* * validate target state */ validate_target_result = validate_target_state(nand); if (validate_target_result != ERROR_OK) return validate_target_result; switch (command) { case NAND_CMD_READOOB: command = NAND_CMD_READ0; /* set read point for data_read() and read_block_data() to * spare area in SRAM buffer */ if (nfc_is_v1()) in_sram_address = MXC_NF_V1_SPARE_BUFFER0; else in_sram_address = MXC_NF_V2_SPARE_BUFFER0; break; case NAND_CMD_READ1: command = NAND_CMD_READ0; /* * offset == one half of page size */ in_sram_address = MXC_NF_MAIN_BUFFER0 + (nand->page_size >> 1); break; default: in_sram_address = MXC_NF_MAIN_BUFFER0; break; } target_write_u16(target, MXC_NF_FCMD, command); /* * start command input operation (set MXC_NF_BIT_OP_DONE==0) */ target_write_u16(target, MXC_NF_CFG2, MXC_NF_BIT_OP_FCI); poll_result = poll_for_complete_op(nand, "command"); if (poll_result != ERROR_OK) return poll_result; /* * reset cursor to begin of the buffer */ sign_of_sequental_byte_read = 0; /* Handle special read command and adjust NF_CFG2(FDO) */ switch (command) { case NAND_CMD_READID: mxc_nf_info->optype = MXC_NF_DATAOUT_NANDID; mxc_nf_info->fin = MXC_NF_FIN_DATAOUT; break; case NAND_CMD_STATUS: mxc_nf_info->optype = MXC_NF_DATAOUT_NANDSTATUS; mxc_nf_info->fin = MXC_NF_FIN_DATAOUT; target_write_u16 (target, MXC_NF_BUFADDR, 0); in_sram_address = 0; break; case NAND_CMD_READ0: mxc_nf_info->fin = MXC_NF_FIN_DATAOUT; mxc_nf_info->optype = MXC_NF_DATAOUT_PAGE; break; default: /* Ohter command use the default 'One page data out' FDO */ mxc_nf_info->optype = MXC_NF_DATAOUT_PAGE; break; } return ERROR_OK; } static int mxc_address(struct nand_device *nand, uint8_t address) { struct mxc_nf_controller *mxc_nf_info = nand->controller_priv; struct target *target = nand->target; int validate_target_result; int poll_result; /* * validate target state */ validate_target_result = validate_target_state(nand); if (validate_target_result != ERROR_OK) return validate_target_result; target_write_u16(target, MXC_NF_FADDR, address); /* * start address input operation (set MXC_NF_BIT_OP_DONE==0) */ target_write_u16(target, MXC_NF_CFG2, MXC_NF_BIT_OP_FAI); poll_result = poll_for_complete_op(nand, "address"); if (poll_result != ERROR_OK) return poll_result; return ERROR_OK; } static int mxc_nand_ready(struct nand_device *nand, int tout) { struct mxc_nf_controller *mxc_nf_info = nand->controller_priv; struct target *target = nand->target; uint16_t poll_complete_status; int validate_target_result; /* * validate target state */ validate_target_result = validate_target_state(nand); if (validate_target_result != ERROR_OK) return validate_target_result; do { target_read_u16(target, MXC_NF_CFG2, &poll_complete_status); if (poll_complete_status & MXC_NF_BIT_OP_DONE) return tout; alive_sleep(1); } while (tout-- > 0); return tout; } static int mxc_write_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { struct mxc_nf_controller *mxc_nf_info = nand->controller_priv; struct target *target = nand->target; int retval; uint16_t nand_status_content; uint16_t swap1, swap2, new_swap1; uint8_t bufs; int poll_result; if (data_size % 2) { LOG_ERROR(data_block_size_err_msg, data_size); return ERROR_NAND_OPERATION_FAILED; } if (oob_size % 2) { LOG_ERROR(data_block_size_err_msg, oob_size); return ERROR_NAND_OPERATION_FAILED; } if (!data) { LOG_ERROR("nothing to program"); return ERROR_NAND_OPERATION_FAILED; } /* * validate target state */ retval = validate_target_state(nand); if (retval != ERROR_OK) return retval; in_sram_address = MXC_NF_MAIN_BUFFER0; sign_of_sequental_byte_read = 0; retval = ERROR_OK; retval |= mxc_command(nand, NAND_CMD_SEQIN); retval |= mxc_address(nand, 0); /* col */ retval |= mxc_address(nand, 0); /* col */ retval |= mxc_address(nand, page & 0xff); /* page address */ retval |= mxc_address(nand, (page >> 8) & 0xff);/* page address */ retval |= mxc_address(nand, (page >> 16) & 0xff); /* page address */ target_write_buffer(target, MXC_NF_MAIN_BUFFER0, data_size, data); if (oob) { if (mxc_nf_info->flags.hw_ecc_enabled) { /* * part of spare block will be overrided by hardware * ECC generator */ LOG_DEBUG("part of spare block will be overrided " "by hardware ECC generator"); } if (nfc_is_v1()) target_write_buffer(target, MXC_NF_V1_SPARE_BUFFER0, oob_size, oob); else { uint32_t addr = MXC_NF_V2_SPARE_BUFFER0; while (oob_size > 0) { uint8_t len = MIN(oob_size, MXC_NF_SPARE_BUFFER_LEN); target_write_buffer(target, addr, len, oob); addr = align_address_v2(nand, addr + len); oob += len; oob_size -= len; } } } if (nand->page_size > 512 && mxc_nf_info->flags.biswap_enabled) { /* BI-swap - work-around of i.MX NFC for NAND device with page == 2kb*/ target_read_u16(target, MXC_NF_MAIN_BUFFER3 + 464, &swap1); if (oob) { LOG_ERROR("Due to NFC Bug, oob is not correctly implemented in mxc driver"); return ERROR_NAND_OPERATION_FAILED; } swap2 = 0xffff; /* Spare buffer unused forced to 0xffff */ new_swap1 = (swap1 & 0xFF00) | (swap2 >> 8); swap2 = (swap1 << 8) | (swap2 & 0xFF); target_write_u16(target, MXC_NF_MAIN_BUFFER3 + 464, new_swap1); if (nfc_is_v1()) target_write_u16(target, MXC_NF_V1_SPARE_BUFFER3, swap2); else target_write_u16(target, MXC_NF_V2_SPARE_BUFFER3, swap2); } /* * start data input operation (set MXC_NF_BIT_OP_DONE==0) */ if (nfc_is_v1() && nand->page_size > 512) bufs = 4; else bufs = 1; for (uint8_t i = 0; i < bufs; ++i) { target_write_u16(target, MXC_NF_BUFADDR, i); target_write_u16(target, MXC_NF_CFG2, MXC_NF_BIT_OP_FDI); poll_result = poll_for_complete_op(nand, "data input"); if (poll_result != ERROR_OK) return poll_result; } retval |= mxc_command(nand, NAND_CMD_PAGEPROG); if (retval != ERROR_OK) return retval; /* * check status register */ retval = ERROR_OK; retval |= mxc_command(nand, NAND_CMD_STATUS); target_write_u16 (target, MXC_NF_BUFADDR, 0); mxc_nf_info->optype = MXC_NF_DATAOUT_NANDSTATUS; mxc_nf_info->fin = MXC_NF_FIN_DATAOUT; retval |= do_data_output(nand); if (retval != ERROR_OK) { LOG_ERROR(get_status_register_err_msg); return retval; } target_read_u16(target, MXC_NF_MAIN_BUFFER0, &nand_status_content); if (nand_status_content & 0x0001) { /* * page not correctly written */ return ERROR_NAND_OPERATION_FAILED; } #ifdef _MXC_PRINT_STAT LOG_INFO("%d bytes newly written", data_size); #endif return ERROR_OK; } static int mxc_read_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { struct mxc_nf_controller *mxc_nf_info = nand->controller_priv; struct target *target = nand->target; int retval; uint8_t bufs; uint16_t swap1, swap2, new_swap1; if (data_size % 2) { LOG_ERROR(data_block_size_err_msg, data_size); return ERROR_NAND_OPERATION_FAILED; } if (oob_size % 2) { LOG_ERROR(data_block_size_err_msg, oob_size); return ERROR_NAND_OPERATION_FAILED; } /* * validate target state */ retval = validate_target_state(nand); if (retval != ERROR_OK) return retval; /* Reset address_cycles before mxc_command ?? */ retval = mxc_command(nand, NAND_CMD_READ0); if (retval != ERROR_OK) return retval; retval = mxc_address(nand, 0); /* col */ if (retval != ERROR_OK) return retval; retval = mxc_address(nand, 0); /* col */ if (retval != ERROR_OK) return retval; retval = mxc_address(nand, page & 0xff);/* page address */ if (retval != ERROR_OK) return retval; retval = mxc_address(nand, (page >> 8) & 0xff); /* page address */ if (retval != ERROR_OK) return retval; retval = mxc_address(nand, (page >> 16) & 0xff);/* page address */ if (retval != ERROR_OK) return retval; retval = mxc_command(nand, NAND_CMD_READSTART); if (retval != ERROR_OK) return retval; if (nfc_is_v1() && nand->page_size > 512) bufs = 4; else bufs = 1; for (uint8_t i = 0; i < bufs; ++i) { target_write_u16(target, MXC_NF_BUFADDR, i); mxc_nf_info->fin = MXC_NF_FIN_DATAOUT; retval = do_data_output(nand); if (retval != ERROR_OK) { LOG_ERROR("MXC_NF : Error reading page %d", i); return retval; } } if (nand->page_size > 512 && mxc_nf_info->flags.biswap_enabled) { uint32_t SPARE_BUFFER3; /* BI-swap - work-around of mxc NFC for NAND device with page == 2k */ target_read_u16(target, MXC_NF_MAIN_BUFFER3 + 464, &swap1); if (nfc_is_v1()) SPARE_BUFFER3 = MXC_NF_V1_SPARE_BUFFER3; else SPARE_BUFFER3 = MXC_NF_V2_SPARE_BUFFER3; target_read_u16(target, SPARE_BUFFER3, &swap2); new_swap1 = (swap1 & 0xFF00) | (swap2 >> 8); swap2 = (swap1 << 8) | (swap2 & 0xFF); target_write_u16(target, MXC_NF_MAIN_BUFFER3 + 464, new_swap1); target_write_u16(target, SPARE_BUFFER3, swap2); } if (data) target_read_buffer(target, MXC_NF_MAIN_BUFFER0, data_size, data); if (oob) { if (nfc_is_v1()) target_read_buffer(target, MXC_NF_V1_SPARE_BUFFER0, oob_size, oob); else { uint32_t addr = MXC_NF_V2_SPARE_BUFFER0; while (oob_size > 0) { uint8_t len = MIN(oob_size, MXC_NF_SPARE_BUFFER_LEN); target_read_buffer(target, addr, len, oob); addr = align_address_v2(nand, addr + len); oob += len; oob_size -= len; } } } #ifdef _MXC_PRINT_STAT if (data_size > 0) { /* When Operation Status is read (when page is erased), * this function is used but data_size is null. */ LOG_INFO("%d bytes newly read", data_size); } #endif return ERROR_OK; } static uint32_t align_address_v2(struct nand_device *nand, uint32_t addr) { struct mxc_nf_controller *mxc_nf_info = nand->controller_priv; uint32_t ret = addr; if (addr > MXC_NF_V2_SPARE_BUFFER0 && (addr & 0x1F) == MXC_NF_SPARE_BUFFER_LEN) ret += MXC_NF_SPARE_BUFFER_MAX - MXC_NF_SPARE_BUFFER_LEN; else if (addr >= (mxc_nf_info->mxc_base_addr + (uint32_t)nand->page_size)) ret = MXC_NF_V2_SPARE_BUFFER0; return ret; } static int initialize_nf_controller(struct nand_device *nand) { struct mxc_nf_controller *mxc_nf_info = nand->controller_priv; struct target *target = nand->target; uint16_t work_mode = 0; uint16_t temp; /* * resets NAND flash controller in zero time ? I dont know. */ target_write_u16(target, MXC_NF_CFG1, MXC_NF_BIT_RESET_EN); if (mxc_nf_info->mxc_version == MXC_VERSION_MX27) work_mode = MXC_NF_BIT_INT_DIS; /* disable interrupt */ if (target->endianness == TARGET_BIG_ENDIAN) { LOG_DEBUG("MXC_NF : work in Big Endian mode"); work_mode |= MXC_NF_BIT_BE_EN; } else LOG_DEBUG("MXC_NF : work in Little Endian mode"); if (mxc_nf_info->flags.hw_ecc_enabled) { LOG_DEBUG("MXC_NF : work with ECC mode"); work_mode |= MXC_NF_BIT_ECC_EN; } else LOG_DEBUG("MXC_NF : work without ECC mode"); if (nfc_is_v2()) { target_write_u16(target, MXC_NF_V2_SPAS, OOB_SIZE / 2); if (nand->page_size) { uint16_t pages_per_block = nand->erase_size / nand->page_size; work_mode |= MXC_NF_V2_CFG1_PPB(ffs(pages_per_block) - 6); } work_mode |= MXC_NF_BIT_ECC_4BIT; } target_write_u16(target, MXC_NF_CFG1, work_mode); /* * unlock SRAM buffer for write; 2 mean "Unlock", other values means "Lock" */ target_write_u16(target, MXC_NF_BUFCFG, 2); target_read_u16(target, MXC_NF_FWP, &temp); if ((temp & 0x0007) == 1) { LOG_ERROR("NAND flash is tight-locked, reset needed"); return ERROR_FAIL; } /* * unlock NAND flash for write */ if (nfc_is_v1()) { target_write_u16(target, MXC_NF_V1_UNLOCKSTART, 0x0000); target_write_u16(target, MXC_NF_V1_UNLOCKEND, 0xFFFF); } else { target_write_u16(target, MXC_NF_V2_UNLOCKSTART0, 0x0000); target_write_u16(target, MXC_NF_V2_UNLOCKSTART1, 0x0000); target_write_u16(target, MXC_NF_V2_UNLOCKSTART2, 0x0000); target_write_u16(target, MXC_NF_V2_UNLOCKSTART3, 0x0000); target_write_u16(target, MXC_NF_V2_UNLOCKEND0, 0xFFFF); target_write_u16(target, MXC_NF_V2_UNLOCKEND1, 0xFFFF); target_write_u16(target, MXC_NF_V2_UNLOCKEND2, 0xFFFF); target_write_u16(target, MXC_NF_V2_UNLOCKEND3, 0xFFFF); } target_write_u16(target, MXC_NF_FWP, 4); /* * 0x0000 means that first SRAM buffer @base_addr will be used */ target_write_u16(target, MXC_NF_BUFADDR, 0x0000); /* * address of SRAM buffer */ in_sram_address = MXC_NF_MAIN_BUFFER0; sign_of_sequental_byte_read = 0; return ERROR_OK; } static int get_next_byte_from_sram_buffer(struct nand_device *nand, uint8_t *value) { struct mxc_nf_controller *mxc_nf_info = nand->controller_priv; struct target *target = nand->target; static uint8_t even_byte; uint16_t temp; /* * host-big_endian ?? */ if (sign_of_sequental_byte_read == 0) even_byte = 0; if (in_sram_address > (nfc_is_v1() ? MXC_NF_V1_LAST_BUFFADDR : MXC_NF_V2_LAST_BUFFADDR)) { LOG_ERROR(sram_buffer_bounds_err_msg, in_sram_address); *value = 0; sign_of_sequental_byte_read = 0; even_byte = 0; return ERROR_NAND_OPERATION_FAILED; } else { if (nfc_is_v2()) in_sram_address = align_address_v2(nand, in_sram_address); target_read_u16(target, in_sram_address, &temp); if (even_byte) { *value = temp >> 8; even_byte = 0; in_sram_address += 2; } else { *value = temp & 0xff; even_byte = 1; } } sign_of_sequental_byte_read = 1; return ERROR_OK; } static int get_next_halfword_from_sram_buffer(struct nand_device *nand, uint16_t *value) { struct mxc_nf_controller *mxc_nf_info = nand->controller_priv; struct target *target = nand->target; if (in_sram_address > (nfc_is_v1() ? MXC_NF_V1_LAST_BUFFADDR : MXC_NF_V2_LAST_BUFFADDR)) { LOG_ERROR(sram_buffer_bounds_err_msg, in_sram_address); *value = 0; return ERROR_NAND_OPERATION_FAILED; } else { if (nfc_is_v2()) in_sram_address = align_address_v2(nand, in_sram_address); target_read_u16(target, in_sram_address, value); in_sram_address += 2; } return ERROR_OK; } static int poll_for_complete_op(struct nand_device *nand, const char *text) { if (mxc_nand_ready(nand, 1000) == -1) { LOG_ERROR("%s sending timeout", text); return ERROR_NAND_OPERATION_FAILED; } return ERROR_OK; } static int validate_target_state(struct nand_device *nand) { struct mxc_nf_controller *mxc_nf_info = nand->controller_priv; struct target *target = nand->target; if (target->state != TARGET_HALTED) { LOG_ERROR(target_not_halted_err_msg); return ERROR_NAND_OPERATION_FAILED; } if (mxc_nf_info->flags.target_little_endian != (target->endianness == TARGET_LITTLE_ENDIAN)) { /* * endianness changed after NAND controller probed */ return ERROR_NAND_OPERATION_FAILED; } return ERROR_OK; } int ecc_status_v1(struct nand_device *nand) { struct mxc_nf_controller *mxc_nf_info = nand->controller_priv; struct target *target = nand->target; uint16_t ecc_status; target_read_u16(target, MXC_NF_ECCSTATUS, &ecc_status); switch (ecc_status & 0x000c) { case 1 << 2: LOG_INFO("main area read with 1 (correctable) error"); break; case 2 << 2: LOG_INFO("main area read with more than 1 (incorrectable) error"); return ERROR_NAND_OPERATION_FAILED; break; } switch (ecc_status & 0x0003) { case 1: LOG_INFO("spare area read with 1 (correctable) error"); break; case 2: LOG_INFO("main area read with more than 1 (incorrectable) error"); return ERROR_NAND_OPERATION_FAILED; break; } return ERROR_OK; } int ecc_status_v2(struct nand_device *nand) { struct mxc_nf_controller *mxc_nf_info = nand->controller_priv; struct target *target = nand->target; uint16_t ecc_status; uint8_t no_subpages; uint8_t err; no_subpages = nand->page_size >> 9; target_read_u16(target, MXC_NF_ECCSTATUS, &ecc_status); do { err = ecc_status & 0xF; if (err > 4) { LOG_INFO("UnCorrectable RS-ECC Error"); return ERROR_NAND_OPERATION_FAILED; } else if (err > 0) LOG_INFO("%d Symbol Correctable RS-ECC Error", err); ecc_status >>= 4; } while (--no_subpages); return ERROR_OK; } static int do_data_output(struct nand_device *nand) { struct mxc_nf_controller *mxc_nf_info = nand->controller_priv; struct target *target = nand->target; int poll_result; switch (mxc_nf_info->fin) { case MXC_NF_FIN_DATAOUT: /* * start data output operation (set MXC_NF_BIT_OP_DONE==0) */ target_write_u16(target, MXC_NF_CFG2, MXC_NF_BIT_DATAOUT_TYPE(mxc_nf_info->optype)); poll_result = poll_for_complete_op(nand, "data output"); if (poll_result != ERROR_OK) return poll_result; mxc_nf_info->fin = MXC_NF_FIN_NONE; /* * ECC stuff */ if (mxc_nf_info->optype == MXC_NF_DATAOUT_PAGE && mxc_nf_info->flags.hw_ecc_enabled) { int ecc_status; if (nfc_is_v1()) ecc_status = ecc_status_v1(nand); else ecc_status = ecc_status_v2(nand); if (ecc_status != ERROR_OK) return ecc_status; } break; case MXC_NF_FIN_NONE: break; } return ERROR_OK; } struct nand_flash_controller mxc_nand_flash_controller = { .name = "mxc", .nand_device_command = &mxc_nand_device_command, .commands = mxc_nand_command_handler, .init = &mxc_init, .reset = &mxc_reset, .command = &mxc_command, .address = &mxc_address, .write_data = &mxc_write_data, .read_data = &mxc_read_data, .write_page = &mxc_write_page, .read_page = &mxc_read_page, .nand_ready = &mxc_nand_ready, }; openocd-0.7.0/src/flash/nand/s3c6400.c0000644000175000001440000000550312134336410014034 00000000000000/*************************************************************************** * Copyright (C) 2010 by Peter Korsgaard * * Heavily based on s3c2412.c by Ben Dooks * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "s3c24xx.h" /* s3c64xx uses another base address for the nand controller than 24xx */ #undef S3C2410_NFREG #define S3C2410_NFREG(x) ((x) + 0x70200000) NAND_DEVICE_COMMAND_HANDLER(s3c6400_nand_device_command) { struct s3c24xx_nand_controller *info; CALL_S3C24XX_DEVICE_COMMAND(nand, &info); /* fill in the address fields for the core device */ info->cmd = S3C2440_NFCMD; info->addr = S3C2440_NFADDR; info->data = S3C2440_NFDATA; info->nfstat = S3C2412_NFSTAT; return ERROR_OK; } static int s3c6400_init(struct nand_device *nand) { struct target *target = nand->target; target_write_u32(target, S3C2410_NFCONF, S3C2440_NFCONF_TACLS(3) | S3C2440_NFCONF_TWRPH0(7) | S3C2440_NFCONF_TWRPH1(7) | 4); target_write_u32(target, S3C2440_NFCONT, S3C2412_NFCONT_INIT_MAIN_ECC | S3C2440_NFCONT_ENABLE); return ERROR_OK; } struct nand_flash_controller s3c6400_nand_controller = { .name = "s3c6400", .nand_device_command = &s3c6400_nand_device_command, .init = &s3c6400_init, .reset = &s3c24xx_reset, .command = &s3c24xx_command, .address = &s3c24xx_address, .write_data = &s3c24xx_write_data, .read_data = &s3c24xx_read_data, .write_page = s3c24xx_write_page, .read_page = s3c24xx_read_page, .write_block_data = &s3c2440_write_block_data, .read_block_data = &s3c2440_read_block_data, .nand_ready = &s3c2440_nand_ready, }; openocd-0.7.0/src/flash/nand/driver.h0000644000175000001440000001106312134336410014330 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Copyright (C) 2007,2008 Øyvind Harboe * * Copyright (C) 2008 by Spencer Oliver * * Copyright (C) 2009 Zachary T Welch * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef FLASH_NAND_DRIVER_H #define FLASH_NAND_DRIVER_H struct nand_device; #define __NAND_DEVICE_COMMAND(name) \ COMMAND_HELPER(name, struct nand_device *nand) /** * Interface for NAND flash controllers. Not all of these functions are * required for full functionality of the NAND driver, but better performance * can be achieved by implementing each function. */ struct nand_flash_controller { /** Driver name that is used to select it from configuration files. */ const char *name; /** Usage of flash command registration. */ const char *usage; const struct command_registration *commands; /** NAND device command called when driver is instantiated during configuration. */ __NAND_DEVICE_COMMAND((*nand_device_command)); /** Initialize the NAND device. */ int (*init)(struct nand_device *nand); /** Reset the NAND device. */ int (*reset)(struct nand_device *nand); /** Issue a command to the NAND device. */ int (*command)(struct nand_device *nand, uint8_t command); /** Write an address to the NAND device. */ int (*address)(struct nand_device *nand, uint8_t address); /** Write word of data to the NAND device. */ int (*write_data)(struct nand_device *nand, uint16_t data); /** Read word of data from the NAND device. */ int (*read_data)(struct nand_device *nand, void *data); /** Write a block of data to the NAND device. */ int (*write_block_data)(struct nand_device *nand, uint8_t *data, int size); /** Read a block of data from the NAND device. */ int (*read_block_data)(struct nand_device *nand, uint8_t *data, int size); /** Write a page to the NAND device. */ int (*write_page)(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size); /** Read a page from the NAND device. */ int (*read_page)(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size); /** Check if the NAND device is ready for more instructions with timeout. */ int (*nand_ready)(struct nand_device *nand, int timeout); }; #define NAND_DEVICE_COMMAND_HANDLER(name) static __NAND_DEVICE_COMMAND(name) /** * Find a NAND flash controller by name. * @param name Identifies the NAND controller to find. * @returns The nand_flash_controller named @c name, or NULL if not found. */ struct nand_flash_controller *nand_driver_find_by_name(const char *name); /** Signature for callback functions passed to nand_driver_walk */ typedef int (*nand_driver_walker_t)(struct nand_flash_controller *c, void *); /** * Walk the list of drivers, encapsulating the data structure type. * Application state/context can be passed through the @c x pointer. * @param f The callback function to invoke for each function. * @param x For use as private data storate, passed directly to @c f. * @returns ERROR_OK if successful, or the non-zero return value of @c f. * This allows a walker to terminate the loop early. */ int nand_driver_walk(nand_driver_walker_t f, void *x); #endif /* FLASH_NAND_DRIVER_H */ openocd-0.7.0/src/flash/nand/lpc32xx.h0000644000175000001440000000352412134336410014343 00000000000000/*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef LPC32xx_NAND_CONTROLLER_H #define LPC32xx_NAND_CONTROLLER_H enum lpc32xx_selected_controller { LPC32xx_NO_CONTROLLER, LPC32xx_MLC_CONTROLLER, LPC32xx_SLC_CONTROLLER, }; struct lpc32xx_nand_controller { int osc_freq; enum lpc32xx_selected_controller selected_controller; int sw_write_protection; uint32_t sw_wp_lower_bound; uint32_t sw_wp_upper_bound; }; #endif /*LPC32xx_NAND_CONTROLLER_H */ openocd-0.7.0/src/flash/nand/Makefile.am0000644000175000001440000000113312134336410014715 00000000000000include $(top_srcdir)/common.mk noinst_LTLIBRARIES = libocdflashnand.la libocdflashnand_la_SOURCES = \ ecc.c \ ecc_kw.c \ core.c \ fileio.c \ tcl.c \ arm_io.c \ $(NAND_DRIVERS) \ driver.c NAND_DRIVERS = \ nonce.c \ davinci.c \ lpc3180.c \ lpc32xx.c \ mxc.c \ mx3.c \ orion.c \ s3c24xx.c \ s3c2410.c \ s3c2412.c \ s3c2440.c \ s3c2443.c \ s3c6400.c \ at91sam9.c \ nuc910.c noinst_HEADERS = \ arm_io.h \ core.h \ driver.h \ fileio.h \ imp.h \ lpc3180.h \ lpc32xx.h \ mxc.h \ mx3.h \ s3c24xx.h \ s3c24xx_regs.h \ nuc910.h MAINTAINERCLEANFILES = $(srcdir)/Makefile.in openocd-0.7.0/src/flash/nor/0000755000175000001440000000000012141414412012616 500000000000000openocd-0.7.0/src/flash/nor/stellaris.c0000644000175000001440000012045012137151331014711 00000000000000/*************************************************************************** * Copyright (C) 2006 by Magnus Lundin * * lundin@mlu.mine.nu * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /*************************************************************************** * STELLARIS flash is tested on LM3S811, LM3S6965, LM3s3748, more. ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "jtag/interface.h" #include "imp.h" #include #include #define DID0_VER(did0) ((did0 >> 28)&0x07) /* STELLARIS control registers */ #define SCB_BASE 0x400FE000 #define DID0 0x000 #define DID1 0x004 #define DC0 0x008 #define DC1 0x010 #define DC2 0x014 #define DC3 0x018 #define DC4 0x01C #define RIS 0x050 #define RCC 0x060 #define PLLCFG 0x064 #define RCC2 0x070 #define NVMSTAT 0x1a0 /* "legacy" flash memory protection registers (64KB max) */ #define FMPRE 0x130 #define FMPPE 0x134 /* new flash memory protection registers (for more than 64KB) */ #define FMPRE0 0x200 /* PRE1 = PRE0 + 4, etc */ #define FMPPE0 0x400 /* PPE1 = PPE0 + 4, etc */ #define USECRL 0x140 #define FLASH_CONTROL_BASE 0x400FD000 #define FLASH_FMA (FLASH_CONTROL_BASE | 0x000) #define FLASH_FMD (FLASH_CONTROL_BASE | 0x004) #define FLASH_FMC (FLASH_CONTROL_BASE | 0x008) #define FLASH_CRIS (FLASH_CONTROL_BASE | 0x00C) #define FLASH_CIM (FLASH_CONTROL_BASE | 0x010) #define FLASH_MISC (FLASH_CONTROL_BASE | 0x014) #define AMISC 1 #define PMISC 2 #define AMASK 1 #define PMASK 2 /* Flash Controller Command bits */ #define FMC_WRKEY (0xA442 << 16) #define FMC_COMT (1 << 3) #define FMC_MERASE (1 << 2) #define FMC_ERASE (1 << 1) #define FMC_WRITE (1 << 0) /* STELLARIS constants */ /* values to write in FMA to commit write-"once" values */ #define FLASH_FMA_PRE(x) (2 * (x)) /* for FMPPREx */ #define FLASH_FMA_PPE(x) (2 * (x) + 1) /* for FMPPPEx */ static void stellaris_read_clock_info(struct flash_bank *bank); static int stellaris_mass_erase(struct flash_bank *bank); struct stellaris_flash_bank { /* chip id register */ uint32_t did0; uint32_t did1; uint32_t dc0; uint32_t dc1; const char *target_name; uint8_t target_class; uint32_t sramsiz; uint32_t flshsz; /* flash geometry */ uint32_t num_pages; uint32_t pagesize; uint32_t pages_in_lockregion; /* nv memory bits */ uint16_t num_lockbits; /* main clock status */ uint32_t rcc; uint32_t rcc2; uint8_t mck_valid; uint8_t xtal_mask; uint32_t iosc_freq; uint32_t mck_freq; const char *iosc_desc; const char *mck_desc; }; /* Autogenerated by contrib/gen-stellaris-part-header.pl */ /* From Stellaris Firmware Development Package revision 9453 */ static struct { uint8_t class; uint8_t partno; const char *partname; } StellarisParts[] = { {0x00, 0x01, "LM3S101"}, {0x00, 0x02, "LM3S102"}, {0x01, 0xBF, "LM3S1110"}, {0x01, 0xC3, "LM3S1133"}, {0x01, 0xC5, "LM3S1138"}, {0x01, 0xC1, "LM3S1150"}, {0x01, 0xC4, "LM3S1162"}, {0x01, 0xC2, "LM3S1165"}, {0x01, 0xEC, "LM3S1166"}, {0x01, 0xC6, "LM3S1332"}, {0x01, 0xBC, "LM3S1435"}, {0x01, 0xBA, "LM3S1439"}, {0x01, 0xBB, "LM3S1512"}, {0x01, 0xC7, "LM3S1538"}, {0x01, 0xDB, "LM3S1601"}, {0x03, 0x06, "LM3S1607"}, {0x01, 0xDA, "LM3S1608"}, {0x01, 0xC0, "LM3S1620"}, {0x04, 0xCD, "LM3S1621"}, {0x03, 0x03, "LM3S1625"}, {0x03, 0x04, "LM3S1626"}, {0x03, 0x05, "LM3S1627"}, {0x01, 0xB3, "LM3S1635"}, {0x01, 0xEB, "LM3S1636"}, {0x01, 0xBD, "LM3S1637"}, {0x04, 0xB1, "LM3S1651"}, {0x01, 0xB9, "LM3S1751"}, {0x03, 0x10, "LM3S1776"}, {0x04, 0x16, "LM3S1811"}, {0x04, 0x3D, "LM3S1816"}, {0x01, 0xB4, "LM3S1850"}, {0x01, 0xDD, "LM3S1911"}, {0x01, 0xDC, "LM3S1918"}, {0x01, 0xB7, "LM3S1937"}, {0x01, 0xBE, "LM3S1958"}, {0x01, 0xB5, "LM3S1960"}, {0x01, 0xB8, "LM3S1968"}, {0x01, 0xEA, "LM3S1969"}, {0x04, 0xCE, "LM3S1B21"}, {0x06, 0xCA, "LM3S1C21"}, {0x06, 0xCB, "LM3S1C26"}, {0x06, 0x98, "LM3S1C58"}, {0x06, 0xB0, "LM3S1D21"}, {0x06, 0xCC, "LM3S1D26"}, {0x06, 0x1D, "LM3S1F11"}, {0x06, 0x1B, "LM3S1F16"}, {0x06, 0xAF, "LM3S1G21"}, {0x06, 0x95, "LM3S1G58"}, {0x06, 0x1E, "LM3S1H11"}, {0x06, 0x1C, "LM3S1H16"}, {0x04, 0x0F, "LM3S1J11"}, {0x04, 0x3C, "LM3S1J16"}, {0x04, 0x0E, "LM3S1N11"}, {0x04, 0x3B, "LM3S1N16"}, {0x04, 0xB2, "LM3S1P51"}, {0x04, 0x9E, "LM3S1R21"}, {0x04, 0xC9, "LM3S1R26"}, {0x04, 0x30, "LM3S1W16"}, {0x04, 0x2F, "LM3S1Z16"}, {0x01, 0x51, "LM3S2110"}, {0x01, 0x84, "LM3S2139"}, {0x03, 0x39, "LM3S2276"}, {0x01, 0xA2, "LM3S2410"}, {0x01, 0x59, "LM3S2412"}, {0x01, 0x56, "LM3S2432"}, {0x01, 0x5A, "LM3S2533"}, {0x01, 0xE1, "LM3S2601"}, {0x01, 0xE0, "LM3S2608"}, {0x03, 0x33, "LM3S2616"}, {0x01, 0x57, "LM3S2620"}, {0x01, 0x85, "LM3S2637"}, {0x01, 0x53, "LM3S2651"}, {0x03, 0x80, "LM3S2671"}, {0x03, 0x50, "LM3S2678"}, {0x01, 0xA4, "LM3S2730"}, {0x01, 0x52, "LM3S2739"}, {0x03, 0x3A, "LM3S2776"}, {0x04, 0x6D, "LM3S2793"}, {0x01, 0xE3, "LM3S2911"}, {0x01, 0xE2, "LM3S2918"}, {0x01, 0xED, "LM3S2919"}, {0x01, 0x54, "LM3S2939"}, {0x01, 0x8F, "LM3S2948"}, {0x01, 0x58, "LM3S2950"}, {0x01, 0x55, "LM3S2965"}, {0x04, 0x6C, "LM3S2B93"}, {0x06, 0x94, "LM3S2D93"}, {0x06, 0x93, "LM3S2U93"}, {0x00, 0x19, "LM3S300"}, {0x00, 0x11, "LM3S301"}, {0x00, 0x1A, "LM3S308"}, {0x00, 0x12, "LM3S310"}, {0x00, 0x13, "LM3S315"}, {0x00, 0x14, "LM3S316"}, {0x00, 0x17, "LM3S317"}, {0x00, 0x15, "LM3S328"}, {0x03, 0x08, "LM3S3634"}, {0x03, 0x43, "LM3S3651"}, {0x04, 0xC8, "LM3S3654"}, {0x03, 0x44, "LM3S3739"}, {0x03, 0x49, "LM3S3748"}, {0x03, 0x45, "LM3S3749"}, {0x04, 0x42, "LM3S3826"}, {0x04, 0x41, "LM3S3J26"}, {0x04, 0x40, "LM3S3N26"}, {0x04, 0x3F, "LM3S3W26"}, {0x04, 0x3E, "LM3S3Z26"}, {0x03, 0x81, "LM3S5632"}, {0x04, 0x0C, "LM3S5651"}, {0x03, 0x8A, "LM3S5652"}, {0x04, 0x4D, "LM3S5656"}, {0x03, 0x91, "LM3S5662"}, {0x03, 0x96, "LM3S5732"}, {0x03, 0x97, "LM3S5737"}, {0x03, 0xA0, "LM3S5739"}, {0x03, 0x99, "LM3S5747"}, {0x03, 0xA7, "LM3S5749"}, {0x03, 0x9A, "LM3S5752"}, {0x03, 0x9C, "LM3S5762"}, {0x04, 0x69, "LM3S5791"}, {0x04, 0x0B, "LM3S5951"}, {0x04, 0x4E, "LM3S5956"}, {0x04, 0x68, "LM3S5B91"}, {0x06, 0x2E, "LM3S5C31"}, {0x06, 0x2C, "LM3S5C36"}, {0x06, 0x5E, "LM3S5C51"}, {0x06, 0x5B, "LM3S5C56"}, {0x06, 0x5F, "LM3S5D51"}, {0x06, 0x5C, "LM3S5D56"}, {0x06, 0x87, "LM3S5D91"}, {0x06, 0x2D, "LM3S5G31"}, {0x06, 0x1F, "LM3S5G36"}, {0x06, 0x5D, "LM3S5G51"}, {0x06, 0x4F, "LM3S5G56"}, {0x04, 0x09, "LM3S5K31"}, {0x04, 0x4A, "LM3S5K36"}, {0x04, 0x0A, "LM3S5P31"}, {0x04, 0x48, "LM3S5P36"}, {0x04, 0xB6, "LM3S5P3B"}, {0x04, 0x0D, "LM3S5P51"}, {0x04, 0x4C, "LM3S5P56"}, {0x04, 0x07, "LM3S5R31"}, {0x04, 0x4B, "LM3S5R36"}, {0x04, 0x47, "LM3S5T36"}, {0x06, 0x7F, "LM3S5U91"}, {0x04, 0x46, "LM3S5Y36"}, {0x00, 0x2A, "LM3S600"}, {0x00, 0x21, "LM3S601"}, {0x00, 0x2B, "LM3S608"}, {0x00, 0x22, "LM3S610"}, {0x01, 0xA1, "LM3S6100"}, {0x00, 0x23, "LM3S611"}, {0x01, 0x74, "LM3S6110"}, {0x00, 0x24, "LM3S612"}, {0x00, 0x25, "LM3S613"}, {0x00, 0x26, "LM3S615"}, {0x00, 0x28, "LM3S617"}, {0x00, 0x29, "LM3S618"}, {0x00, 0x27, "LM3S628"}, {0x01, 0xA5, "LM3S6420"}, {0x01, 0x82, "LM3S6422"}, {0x01, 0x75, "LM3S6432"}, {0x01, 0x76, "LM3S6537"}, {0x01, 0x71, "LM3S6610"}, {0x01, 0xE7, "LM3S6611"}, {0x01, 0xE6, "LM3S6618"}, {0x01, 0x83, "LM3S6633"}, {0x01, 0x8B, "LM3S6637"}, {0x01, 0xA3, "LM3S6730"}, {0x01, 0x77, "LM3S6753"}, {0x01, 0xE9, "LM3S6911"}, {0x01, 0xE8, "LM3S6918"}, {0x01, 0x89, "LM3S6938"}, {0x01, 0x72, "LM3S6950"}, {0x01, 0x78, "LM3S6952"}, {0x01, 0x73, "LM3S6965"}, {0x06, 0xAA, "LM3S6C11"}, {0x06, 0xAC, "LM3S6C65"}, {0x06, 0x9F, "LM3S6G11"}, {0x06, 0xAB, "LM3S6G65"}, {0x00, 0x38, "LM3S800"}, {0x00, 0x31, "LM3S801"}, {0x00, 0x39, "LM3S808"}, {0x00, 0x32, "LM3S811"}, {0x00, 0x33, "LM3S812"}, {0x00, 0x34, "LM3S815"}, {0x00, 0x36, "LM3S817"}, {0x00, 0x37, "LM3S818"}, {0x00, 0x35, "LM3S828"}, {0x01, 0x64, "LM3S8530"}, {0x01, 0x8E, "LM3S8538"}, {0x01, 0x61, "LM3S8630"}, {0x01, 0x63, "LM3S8730"}, {0x01, 0x8D, "LM3S8733"}, {0x01, 0x86, "LM3S8738"}, {0x01, 0x65, "LM3S8930"}, {0x01, 0x8C, "LM3S8933"}, {0x01, 0x88, "LM3S8938"}, {0x01, 0xA6, "LM3S8962"}, {0x01, 0x62, "LM3S8970"}, {0x01, 0xD7, "LM3S8971"}, {0x06, 0xAE, "LM3S8C62"}, {0x06, 0xAD, "LM3S8G62"}, {0x04, 0xCF, "LM3S9781"}, {0x04, 0x67, "LM3S9790"}, {0x04, 0x6B, "LM3S9792"}, {0x04, 0x2D, "LM3S9971"}, {0x04, 0x20, "LM3S9997"}, {0x04, 0xD0, "LM3S9B81"}, {0x04, 0x66, "LM3S9B90"}, {0x04, 0x6A, "LM3S9B92"}, {0x04, 0x6E, "LM3S9B95"}, {0x04, 0x6F, "LM3S9B96"}, {0x04, 0x1D, "LM3S9BN2"}, {0x04, 0x1E, "LM3S9BN5"}, {0x04, 0x1F, "LM3S9BN6"}, {0x06, 0x70, "LM3S9C97"}, {0x06, 0xA9, "LM3S9D81"}, {0x06, 0x7E, "LM3S9D90"}, {0x06, 0x92, "LM3S9D92"}, {0x06, 0x9D, "LM3S9D96"}, {0x06, 0x7B, "LM3S9DN5"}, {0x06, 0x7C, "LM3S9DN6"}, {0x06, 0x60, "LM3S9G97"}, {0x06, 0x79, "LM3S9GN5"}, {0x04, 0x1B, "LM3S9L71"}, {0x04, 0x18, "LM3S9L97"}, {0x06, 0xA8, "LM3S9U81"}, {0x06, 0x7D, "LM3S9U90"}, {0x06, 0x90, "LM3S9U92"}, {0x06, 0x9B, "LM3S9U96"}, {0x05, 0x18, "LM4F110B2QR"}, {0x05, 0x19, "LM4F110C4QR"}, {0x05, 0x10, "LM4F110E5QR"}, {0x05, 0x11, "LM4F110H5QR"}, {0x05, 0x22, "LM4F111B2QR"}, {0x05, 0x23, "LM4F111C4QR"}, {0x05, 0x20, "LM4F111E5QR"}, {0x05, 0x21, "LM4F111H5QR"}, {0x05, 0x36, "LM4F112C4QC"}, {0x05, 0x30, "LM4F112E5QC"}, {0x05, 0x31, "LM4F112H5QC"}, {0x05, 0x35, "LM4F112H5QD"}, {0x05, 0x01, "LM4F120B2QR"}, {0x05, 0x02, "LM4F120C4QR"}, {0x05, 0x03, "LM4F120E5QR"}, {0x05, 0x04, "LM4F120H5QR"}, {0x05, 0x08, "LM4F121B2QR"}, {0x05, 0x09, "LM4F121C4QR"}, {0x05, 0x0A, "LM4F121E5QR"}, {0x05, 0x0B, "LM4F121H5QR"}, {0x05, 0xD0, "LM4F122C4QC"}, {0x05, 0xD1, "LM4F122E5QC"}, {0x05, 0xD2, "LM4F122H5QC"}, {0x05, 0xD6, "LM4F122H5QD"}, {0x05, 0x48, "LM4F130C4QR"}, {0x05, 0x40, "LM4F130E5QR"}, {0x05, 0x41, "LM4F130H5QR"}, {0x05, 0x52, "LM4F131C4QR"}, {0x05, 0x50, "LM4F131E5QR"}, {0x05, 0x51, "LM4F131H5QR"}, {0x05, 0x66, "LM4F132C4QC"}, {0x05, 0x60, "LM4F132E5QC"}, {0x05, 0x61, "LM4F132H5QC"}, {0x05, 0x65, "LM4F132H5QD"}, {0x05, 0x70, "LM4F210E5QR"}, {0x05, 0x73, "LM4F210H5QR"}, {0x05, 0x80, "LM4F211E5QR"}, {0x05, 0x83, "LM4F211H5QR"}, {0x05, 0xE9, "LM4F212H5BB"}, {0x05, 0xC4, "LM4F212H5QC"}, {0x05, 0xC6, "LM4F212H5QD"}, {0x05, 0xA0, "LM4F230E5QR"}, {0x05, 0xA1, "LM4F230H5QR"}, {0x05, 0xB0, "LM4F231E5QR"}, {0x05, 0xB1, "LM4F231H5QR"}, {0x05, 0xC0, "LM4F232E5QC"}, {0x05, 0xE3, "LM4F232H5BB"}, {0x05, 0xC1, "LM4F232H5QC"}, {0x05, 0xC5, "LM4F232H5QD"}, {0x05, 0xE5, "LM4FS1AH5BB"}, {0x05, 0xEA, "LM4FS1GH5BB"}, {0x05, 0xE4, "LM4FS99H5BB"}, {0x05, 0xE1, "LM4FSXLH5BB"}, {0xFF, 0x00, "Unknown Part"} }; static char *StellarisClassname[7] = { "Sandstorm", "Fury", "Unknown", "DustDevil", "Tempest", "Blizzard", "Firestorm" }; /*************************************************************************** * openocd command interface * ***************************************************************************/ /* flash_bank stellaris 0 0 */ FLASH_BANK_COMMAND_HANDLER(stellaris_flash_bank_command) { struct stellaris_flash_bank *stellaris_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; stellaris_info = calloc(sizeof(struct stellaris_flash_bank), 1); bank->base = 0x0; bank->driver_priv = stellaris_info; stellaris_info->target_name = "Unknown target"; /* part wasn't probed for info yet */ stellaris_info->did1 = 0; /* TODO Specify the main crystal speed in kHz using an optional * argument; ditto, the speed of an external oscillator used * instead of a crystal. Avoid programming flash using IOSC. */ return ERROR_OK; } static int get_stellaris_info(struct flash_bank *bank, char *buf, int buf_size) { int printed; struct stellaris_flash_bank *stellaris_info = bank->driver_priv; if (stellaris_info->did1 == 0) return ERROR_FLASH_BANK_NOT_PROBED; /* Read main and master clock freqency register */ stellaris_read_clock_info(bank); printed = snprintf(buf, buf_size, "\nTI/LMI Stellaris information: Chip is " "class %i (%s) %s rev %c%i\n", stellaris_info->target_class, StellarisClassname[stellaris_info->target_class], stellaris_info->target_name, (int)('A' + ((stellaris_info->did0 >> 8) & 0xFF)), (int)((stellaris_info->did0) & 0xFF)); buf += printed; buf_size -= printed; printed = snprintf(buf, buf_size, "did1: 0x%8.8" PRIx32 ", arch: 0x%4.4" PRIx32 ", eproc: %s, ramsize: %ik, flashsize: %ik\n", stellaris_info->did1, stellaris_info->did1, "ARMv7M", (int)((1 + ((stellaris_info->dc0 >> 16) & 0xFFFF))/4), (int)((1 + (stellaris_info->dc0 & 0xFFFF))*2)); buf += printed; buf_size -= printed; printed = snprintf(buf, buf_size, "master clock: %ikHz%s, " "rcc is 0x%" PRIx32 ", rcc2 is 0x%" PRIx32 "\n", (int)(stellaris_info->mck_freq / 1000), stellaris_info->mck_desc, stellaris_info->rcc, stellaris_info->rcc2); buf += printed; buf_size -= printed; if (stellaris_info->num_lockbits > 0) { snprintf(buf, buf_size, "pagesize: %" PRIi32 ", pages: %d, " "lockbits: %i, pages per lockbit: %i\n", stellaris_info->pagesize, (unsigned) stellaris_info->num_pages, stellaris_info->num_lockbits, (unsigned) stellaris_info->pages_in_lockregion); } return ERROR_OK; } /*************************************************************************** * chip identification and status * ***************************************************************************/ /* Set the flash timimg register to match current clocking */ static void stellaris_set_flash_timing(struct flash_bank *bank) { struct stellaris_flash_bank *stellaris_info = bank->driver_priv; struct target *target = bank->target; uint32_t usecrl = (stellaris_info->mck_freq/1000000ul-1); /* only valid for Sandstorm and Fury class devices */ if (stellaris_info->target_class > 1) return; LOG_DEBUG("usecrl = %i", (int)(usecrl)); target_write_u32(target, SCB_BASE | USECRL, usecrl); } static const unsigned rcc_xtal[32] = { [0x00] = 1000000, /* no pll */ [0x01] = 1843200, /* no pll */ [0x02] = 2000000, /* no pll */ [0x03] = 2457600, /* no pll */ [0x04] = 3579545, [0x05] = 3686400, [0x06] = 4000000, /* usb */ [0x07] = 4096000, [0x08] = 4915200, [0x09] = 5000000, /* usb */ [0x0a] = 5120000, [0x0b] = 6000000, /* (reset) usb */ [0x0c] = 6144000, [0x0d] = 7372800, [0x0e] = 8000000, /* usb */ [0x0f] = 8192000, /* parts before DustDevil use just 4 bits for xtal spec */ [0x10] = 10000000, /* usb */ [0x11] = 12000000, /* usb */ [0x12] = 12288000, [0x13] = 13560000, [0x14] = 14318180, [0x15] = 16000000, /* usb */ [0x16] = 16384000, }; /** Read clock configuration and set stellaris_info->usec_clocks. */ static void stellaris_read_clock_info(struct flash_bank *bank) { struct stellaris_flash_bank *stellaris_info = bank->driver_priv; struct target *target = bank->target; uint32_t rcc, rcc2, pllcfg, sysdiv, usesysdiv, bypass, oscsrc; unsigned xtal; unsigned long mainfreq; target_read_u32(target, SCB_BASE | RCC, &rcc); LOG_DEBUG("Stellaris RCC %" PRIx32 "", rcc); target_read_u32(target, SCB_BASE | RCC2, &rcc2); LOG_DEBUG("Stellaris RCC2 %" PRIx32 "", rcc); target_read_u32(target, SCB_BASE | PLLCFG, &pllcfg); LOG_DEBUG("Stellaris PLLCFG %" PRIx32 "", pllcfg); stellaris_info->rcc = rcc; stellaris_info->rcc = rcc2; sysdiv = (rcc >> 23) & 0xF; usesysdiv = (rcc >> 22) & 0x1; bypass = (rcc >> 11) & 0x1; oscsrc = (rcc >> 4) & 0x3; xtal = (rcc >> 6) & stellaris_info->xtal_mask; /* NOTE: post-Sandstorm parts have RCC2 which may override * parts of RCC ... with more sysdiv options, option for * 32768 Hz mainfreq, PLL controls. On Sandstorm it reads * as zero, so the "use RCC2" flag is always clear. */ if (rcc2 & (1 << 31)) { sysdiv = (rcc2 >> 23) & 0x3F; bypass = (rcc2 >> 11) & 0x1; oscsrc = (rcc2 >> 4) & 0x7; /* FIXME Tempest parts have an additional lsb for * fractional sysdiv (200 MHz / 2.5 == 80 MHz) */ } stellaris_info->mck_desc = ""; switch (oscsrc) { case 0: /* MOSC */ mainfreq = rcc_xtal[xtal]; break; case 1: /* IOSC */ mainfreq = stellaris_info->iosc_freq; stellaris_info->mck_desc = stellaris_info->iosc_desc; break; case 2: /* IOSC/4 */ mainfreq = stellaris_info->iosc_freq / 4; stellaris_info->mck_desc = stellaris_info->iosc_desc; break; case 3: /* lowspeed */ /* Sandstorm doesn't have this 30K +/- 30% osc */ mainfreq = 30000; stellaris_info->mck_desc = " (±30%)"; break; case 8: /* hibernation osc */ /* not all parts support hibernation */ mainfreq = 32768; break; default: /* NOTREACHED */ mainfreq = 0; break; } /* PLL is used if it's not bypassed; its output is 200 MHz * even when it runs at 400 MHz (adds divide-by-two stage). */ if (!bypass) mainfreq = 200000000; if (usesysdiv) stellaris_info->mck_freq = mainfreq/(1 + sysdiv); else stellaris_info->mck_freq = mainfreq; } /* Read device id register, main clock frequency register and fill in driver info structure */ static int stellaris_read_part_info(struct flash_bank *bank) { struct stellaris_flash_bank *stellaris_info = bank->driver_priv; struct target *target = bank->target; uint32_t did0, did1, ver, fam; int i; /* Read and parse chip identification register */ target_read_u32(target, SCB_BASE | DID0, &did0); target_read_u32(target, SCB_BASE | DID1, &did1); target_read_u32(target, SCB_BASE | DC0, &stellaris_info->dc0); target_read_u32(target, SCB_BASE | DC1, &stellaris_info->dc1); LOG_DEBUG("did0 0x%" PRIx32 ", did1 0x%" PRIx32 ", dc0 0x%" PRIx32 ", dc1 0x%" PRIx32 "", did0, did1, stellaris_info->dc0, stellaris_info->dc1); ver = did0 >> 28; if ((ver != 0) && (ver != 1)) { LOG_WARNING("Unknown did0 version, cannot identify target"); return ERROR_FLASH_OPERATION_FAILED; } if (did1 == 0) { LOG_WARNING("Cannot identify target as a Stellaris"); return ERROR_FLASH_OPERATION_FAILED; } ver = did1 >> 28; fam = (did1 >> 24) & 0xF; if (((ver != 0) && (ver != 1)) || (fam != 0)) { LOG_WARNING("Unknown did1 version/family."); return ERROR_FLASH_OPERATION_FAILED; } /* For Sandstorm, Fury, DustDevil: current data sheets say IOSC * is 12 MHz, but some older parts have 15 MHz. A few data sheets * even give _both_ numbers! We'll use current numbers; IOSC is * always approximate. * * For Tempest: IOSC is calibrated, 16 MHz * For Blizzard: IOSC is calibrated, 16 MHz * For Firestorm: IOSC is calibrated, 16 MHz */ stellaris_info->iosc_freq = 12000000; stellaris_info->iosc_desc = " (±30%)"; stellaris_info->xtal_mask = 0x0f; /* get device class */ if (DID0_VER(did0) > 0) { stellaris_info->target_class = (did0 >> 16) & 0xFF; } else { /* Sandstorm class */ stellaris_info->target_class = 0; } switch (stellaris_info->target_class) { case 0: /* Sandstorm */ /* * Current (2009-August) parts seem to be rev C2 and use 12 MHz. * Parts before rev C0 used 15 MHz; some C0 parts use 15 MHz * (LM3S618), but some other C0 parts are 12 MHz (LM3S811). */ if (((did0 >> 8) & 0xff) < 2) { stellaris_info->iosc_freq = 15000000; stellaris_info->iosc_desc = " (±50%)"; } break; case 1: /* Fury */ break; case 4: /* Tempest */ case 5: /* Blizzard */ case 6: /* Firestorm */ stellaris_info->iosc_freq = 16000000; /* +/- 1% */ stellaris_info->iosc_desc = " (±1%)"; /* FALL THROUGH */ case 3: /* DustDevil */ stellaris_info->xtal_mask = 0x1f; break; default: LOG_WARNING("Unknown did0 class"); } for (i = 0; StellarisParts[i].partno; i++) { if ((StellarisParts[i].partno == ((did1 >> 16) & 0xFF)) && (StellarisParts[i].class == stellaris_info->target_class)) break; } stellaris_info->target_name = StellarisParts[i].partname; stellaris_info->did0 = did0; stellaris_info->did1 = did1; stellaris_info->num_lockbits = 1 + (stellaris_info->dc0 & 0xFFFF); stellaris_info->num_pages = 2 * (1 + (stellaris_info->dc0 & 0xFFFF)); stellaris_info->pagesize = 1024; stellaris_info->pages_in_lockregion = 2; /* REVISIT for at least Tempest parts, read NVMSTAT.FWB too. * That exposes a 32-word Flash Write Buffer ... enabling * writes of more than one word at a time. */ return ERROR_OK; } /*************************************************************************** * flash operations * ***************************************************************************/ static int stellaris_protect_check(struct flash_bank *bank) { struct stellaris_flash_bank *stellaris = bank->driver_priv; int status = ERROR_OK; unsigned i; unsigned page; if (stellaris->did1 == 0) return ERROR_FLASH_BANK_NOT_PROBED; for (i = 0; i < (unsigned) bank->num_sectors; i++) bank->sectors[i].is_protected = -1; /* Read each Flash Memory Protection Program Enable (FMPPE) register * to report any pages that we can't write. Ignore the Read Enable * register (FMPRE). */ for (i = 0, page = 0; i < DIV_ROUND_UP(stellaris->num_lockbits, 32u); i++) { uint32_t lockbits; status = target_read_u32(bank->target, SCB_BASE + (i ? (FMPPE0 + 4 * i) : FMPPE), &lockbits); LOG_DEBUG("FMPPE%d = %#8.8x (status %d)", i, (unsigned) lockbits, status); if (status != ERROR_OK) goto done; for (unsigned j = 0; j < 32; j++) { unsigned k; for (k = 0; k < stellaris->pages_in_lockregion; k++) { if (page >= (unsigned) bank->num_sectors) goto done; bank->sectors[page++].is_protected = !(lockbits & (1 << j)); } } } done: return status; } static int stellaris_erase(struct flash_bank *bank, int first, int last) { int banknr; uint32_t flash_fmc, flash_cris; struct stellaris_flash_bank *stellaris_info = bank->driver_priv; struct target *target = bank->target; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (stellaris_info->did1 == 0) return ERROR_FLASH_BANK_NOT_PROBED; if ((first < 0) || (last < first) || (last >= (int)stellaris_info->num_pages)) return ERROR_FLASH_SECTOR_INVALID; if ((first == 0) && (last == ((int)stellaris_info->num_pages-1))) return stellaris_mass_erase(bank); /* Refresh flash controller timing */ stellaris_read_clock_info(bank); stellaris_set_flash_timing(bank); /* Clear and disable flash programming interrupts */ target_write_u32(target, FLASH_CIM, 0); target_write_u32(target, FLASH_MISC, PMISC | AMISC); /* REVISIT this clobbers state set by any halted firmware ... * it might want to process those IRQs. */ for (banknr = first; banknr <= last; banknr++) { /* Address is first word in page */ target_write_u32(target, FLASH_FMA, banknr * stellaris_info->pagesize); /* Write erase command */ target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_ERASE); /* Wait until erase complete */ do { target_read_u32(target, FLASH_FMC, &flash_fmc); } while (flash_fmc & FMC_ERASE); /* Check acess violations */ target_read_u32(target, FLASH_CRIS, &flash_cris); if (flash_cris & (AMASK)) { LOG_WARNING("Error erasing flash page %i, flash_cris 0x%" PRIx32 "", banknr, flash_cris); target_write_u32(target, FLASH_CRIS, 0); return ERROR_FLASH_OPERATION_FAILED; } bank->sectors[banknr].is_erased = 1; } return ERROR_OK; } static int stellaris_protect(struct flash_bank *bank, int set, int first, int last) { uint32_t fmppe, flash_fmc, flash_cris; int lockregion; struct stellaris_flash_bank *stellaris_info = bank->driver_priv; struct target *target = bank->target; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!set) { LOG_ERROR("Hardware doesn't support page-level unprotect. " "Try the 'recover' command."); return ERROR_COMMAND_SYNTAX_ERROR; } if (stellaris_info->did1 == 0) return ERROR_FLASH_BANK_NOT_PROBED; /* lockregions are 2 pages ... must protect [even..odd] */ if ((first < 0) || (first & 1) || (last < first) || !(last & 1) || (last >= 2 * stellaris_info->num_lockbits)) { LOG_ERROR("Can't protect unaligned or out-of-range pages."); return ERROR_FLASH_SECTOR_INVALID; } /* Refresh flash controller timing */ stellaris_read_clock_info(bank); stellaris_set_flash_timing(bank); /* convert from pages to lockregions */ first /= 2; last /= 2; /* FIXME this assumes single FMPPE, for a max of 64K of flash!! * Current parts can be much bigger. */ if (last >= 32) { LOG_ERROR("No support yet for protection > 64K"); return ERROR_FLASH_OPERATION_FAILED; } target_read_u32(target, SCB_BASE | FMPPE, &fmppe); for (lockregion = first; lockregion <= last; lockregion++) fmppe &= ~(1 << lockregion); /* Clear and disable flash programming interrupts */ target_write_u32(target, FLASH_CIM, 0); target_write_u32(target, FLASH_MISC, PMISC | AMISC); /* REVISIT this clobbers state set by any halted firmware ... * it might want to process those IRQs. */ LOG_DEBUG("fmppe 0x%" PRIx32 "", fmppe); target_write_u32(target, SCB_BASE | FMPPE, fmppe); /* Commit FMPPE */ target_write_u32(target, FLASH_FMA, 1); /* Write commit command */ /* REVISIT safety check, since this cannot be undone * except by the "Recover a locked device" procedure. * REVISIT DustDevil-A0 parts have an erratum making FMPPE commits * inadvisable ... it makes future mass erase operations fail. */ LOG_WARNING("Flash protection cannot be removed once committed, commit is NOT executed !"); /* target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_COMT); */ /* Wait until erase complete */ do { target_read_u32(target, FLASH_FMC, &flash_fmc); } while (flash_fmc & FMC_COMT); /* Check acess violations */ target_read_u32(target, FLASH_CRIS, &flash_cris); if (flash_cris & (AMASK)) { LOG_WARNING("Error setting flash page protection, flash_cris 0x%" PRIx32 "", flash_cris); target_write_u32(target, FLASH_CRIS, 0); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } /* see contib/loaders/flash/stellaris.s for src */ static const uint8_t stellaris_write_code[] = { /* write: */ 0xDF, 0xF8, 0x40, 0x40, /* ldr r4, pFLASH_CTRL_BASE */ 0xDF, 0xF8, 0x40, 0x50, /* ldr r5, FLASHWRITECMD */ /* wait_fifo: */ 0xD0, 0xF8, 0x00, 0x80, /* ldr r8, [r0, #0] */ 0xB8, 0xF1, 0x00, 0x0F, /* cmp r8, #0 */ 0x17, 0xD0, /* beq exit */ 0x47, 0x68, /* ldr r7, [r0, #4] */ 0x47, 0x45, /* cmp r7, r8 */ 0xF7, 0xD0, /* beq wait_fifo */ /* mainloop: */ 0x22, 0x60, /* str r2, [r4, #0] */ 0x02, 0xF1, 0x04, 0x02, /* add r2, r2, #4 */ 0x57, 0xF8, 0x04, 0x8B, /* ldr r8, [r7], #4 */ 0xC4, 0xF8, 0x04, 0x80, /* str r8, [r4, #4] */ 0xA5, 0x60, /* str r5, [r4, #8] */ /* busy: */ 0xD4, 0xF8, 0x08, 0x80, /* ldr r8, [r4, #8] */ 0x18, 0xF0, 0x01, 0x0F, /* tst r8, #1 */ 0xFA, 0xD1, /* bne busy */ 0x8F, 0x42, /* cmp r7, r1 */ 0x28, 0xBF, /* it cs */ 0x00, 0xF1, 0x08, 0x07, /* addcs r7, r0, #8 */ 0x47, 0x60, /* str r7, [r0, #4] */ 0x01, 0x3B, /* subs r3, r3, #1 */ 0x03, 0xB1, /* cbz r3, exit */ 0xE2, 0xE7, /* b wait_fifo */ /* exit: */ 0x00, 0xBE, /* bkpt #0 */ /* pFLASH_CTRL_BASE: */ 0x00, 0xD0, 0x0F, 0x40, /* .word 0x400FD000 */ /* FLASHWRITECMD: */ 0x01, 0x00, 0x42, 0xA4 /* .word 0xA4420001 */ }; static int stellaris_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t wcount) { struct target *target = bank->target; uint32_t buffer_size = 16384; struct working_area *source; struct working_area *write_algorithm; uint32_t address = bank->base + offset; struct reg_param reg_params[4]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; /* power of two, and multiple of word size */ static const unsigned buf_min = 128; /* for small buffers it's faster not to download an algorithm */ if (wcount * 4 < buf_min) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; LOG_DEBUG("(bank=%p buffer=%p offset=%08" PRIx32 " wcount=%08" PRIx32 "", bank, buffer, offset, wcount); /* flash write code */ if (target_alloc_working_area(target, sizeof(stellaris_write_code), &write_algorithm) != ERROR_OK) { LOG_DEBUG("no working area for block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; }; /* plus a buffer big enough for this data */ if (wcount * 4 < buffer_size) buffer_size = wcount * 4; /* memory buffer */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; if (buffer_size <= buf_min) { target_free_working_area(target, write_algorithm); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } LOG_DEBUG("retry target_alloc_working_area(%s, size=%u)", target_name(target), (unsigned) buffer_size); }; target_write_buffer(target, write_algorithm->address, sizeof(stellaris_write_code), (uint8_t *) stellaris_write_code); armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size); buf_set_u32(reg_params[2].value, 0, 32, address); buf_set_u32(reg_params[3].value, 0, 32, wcount); retval = target_run_flash_async_algorithm(target, buffer, wcount, 4, 0, NULL, 4, reg_params, source->address, source->size, write_algorithm->address, 0, &armv7m_info); if (retval == ERROR_FLASH_OPERATION_FAILED) LOG_ERROR("error %d executing stellaris flash write algorithm", retval); target_free_working_area(target, write_algorithm); target_free_working_area(target, source); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); return retval; } static int stellaris_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct stellaris_flash_bank *stellaris_info = bank->driver_priv; struct target *target = bank->target; uint32_t address = offset; uint32_t flash_cris, flash_fmc; uint32_t words_remaining = (count / 4); uint32_t bytes_remaining = (count & 0x00000003); uint32_t bytes_written = 0; int retval; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } LOG_DEBUG("(bank=%p buffer=%p offset=%08" PRIx32 " count=%08" PRIx32 "", bank, buffer, offset, count); if (stellaris_info->did1 == 0) return ERROR_FLASH_BANK_NOT_PROBED; if (offset & 0x3) { LOG_WARNING("offset size must be word aligned"); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } if (offset + count > bank->size) return ERROR_FLASH_DST_OUT_OF_BANK; /* Refresh flash controller timing */ stellaris_read_clock_info(bank); stellaris_set_flash_timing(bank); /* Clear and disable flash programming interrupts */ target_write_u32(target, FLASH_CIM, 0); target_write_u32(target, FLASH_MISC, PMISC | AMISC); /* REVISIT this clobbers state set by any halted firmware ... * it might want to process those IRQs. */ /* multiple words to be programmed? */ if (words_remaining > 0) { /* try using a block write */ retval = stellaris_write_block(bank, buffer, offset, words_remaining); if (retval != ERROR_OK) { if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { LOG_DEBUG("writing flash word-at-a-time"); } else if (retval == ERROR_FLASH_OPERATION_FAILED) { /* if an error occured, we examine the reason, and quit */ target_read_u32(target, FLASH_CRIS, &flash_cris); LOG_ERROR("flash writing failed with CRIS: 0x%" PRIx32 "", flash_cris); return ERROR_FLASH_OPERATION_FAILED; } } else { buffer += words_remaining * 4; address += words_remaining * 4; words_remaining = 0; } } while (words_remaining > 0) { if (!(address & 0xff)) LOG_DEBUG("0x%" PRIx32 "", address); /* Program one word */ target_write_u32(target, FLASH_FMA, address); target_write_buffer(target, FLASH_FMD, 4, buffer); target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_WRITE); /* LOG_DEBUG("0x%x 0x%x 0x%x",address,buf_get_u32(buffer, 0, 32),FMC_WRKEY | FMC_WRITE); */ /* Wait until write complete */ do { target_read_u32(target, FLASH_FMC, &flash_fmc); } while (flash_fmc & FMC_WRITE); buffer += 4; address += 4; words_remaining--; } if (bytes_remaining) { uint8_t last_word[4] = {0xff, 0xff, 0xff, 0xff}; /* copy the last remaining bytes into the write buffer */ memcpy(last_word, buffer+bytes_written, bytes_remaining); if (!(address & 0xff)) LOG_DEBUG("0x%" PRIx32 "", address); /* Program one word */ target_write_u32(target, FLASH_FMA, address); target_write_buffer(target, FLASH_FMD, 4, last_word); target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_WRITE); /* LOG_DEBUG("0x%x 0x%x 0x%x",address,buf_get_u32(buffer, 0, 32),FMC_WRKEY | FMC_WRITE); */ /* Wait until write complete */ do { target_read_u32(target, FLASH_FMC, &flash_fmc); } while (flash_fmc & FMC_WRITE); } /* Check access violations */ target_read_u32(target, FLASH_CRIS, &flash_cris); if (flash_cris & (AMASK)) { LOG_DEBUG("flash_cris 0x%" PRIx32 "", flash_cris); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } static int stellaris_probe(struct flash_bank *bank) { struct stellaris_flash_bank *stellaris_info = bank->driver_priv; int retval; /* If this is a stellaris chip, it has flash; probe() is just * to figure out how much is present. Only do it once. */ if (stellaris_info->did1 != 0) return ERROR_OK; /* stellaris_read_part_info() already handled error checking and * reporting. Note that it doesn't write, so we don't care about * whether the target is halted or not. */ retval = stellaris_read_part_info(bank); if (retval != ERROR_OK) return retval; if (bank->sectors) { free(bank->sectors); bank->sectors = NULL; } /* provide this for the benefit of the NOR flash framework */ bank->size = 1024 * stellaris_info->num_pages; bank->num_sectors = stellaris_info->num_pages; bank->sectors = calloc(bank->num_sectors, sizeof(struct flash_sector)); for (int i = 0; i < bank->num_sectors; i++) { bank->sectors[i].offset = i * stellaris_info->pagesize; bank->sectors[i].size = stellaris_info->pagesize; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = -1; } return retval; } static int stellaris_mass_erase(struct flash_bank *bank) { struct target *target = NULL; struct stellaris_flash_bank *stellaris_info = NULL; uint32_t flash_fmc; stellaris_info = bank->driver_priv; target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (stellaris_info->did1 == 0) return ERROR_FLASH_BANK_NOT_PROBED; /* Refresh flash controller timing */ stellaris_read_clock_info(bank); stellaris_set_flash_timing(bank); /* Clear and disable flash programming interrupts */ target_write_u32(target, FLASH_CIM, 0); target_write_u32(target, FLASH_MISC, PMISC | AMISC); /* REVISIT this clobbers state set by any halted firmware ... * it might want to process those IRQs. */ target_write_u32(target, FLASH_FMA, 0); target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_MERASE); /* Wait until erase complete */ do { target_read_u32(target, FLASH_FMC, &flash_fmc); } while (flash_fmc & FMC_MERASE); /* if device has > 128k, then second erase cycle is needed * this is only valid for older devices, but will not hurt */ if (stellaris_info->num_pages * stellaris_info->pagesize > 0x20000) { target_write_u32(target, FLASH_FMA, 0x20000); target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_MERASE); /* Wait until erase complete */ do { target_read_u32(target, FLASH_FMC, &flash_fmc); } while (flash_fmc & FMC_MERASE); } return ERROR_OK; } COMMAND_HANDLER(stellaris_handle_mass_erase_command) { int i; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; if (stellaris_mass_erase(bank) == ERROR_OK) { /* set all sectors as erased */ for (i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_erased = 1; command_print(CMD_CTX, "stellaris mass erase complete"); } else command_print(CMD_CTX, "stellaris mass erase failed"); return ERROR_OK; } /** * Perform the Stellaris "Recovering a 'Locked' Device procedure. * This performs a mass erase and then restores all nonvolatile registers * (including USER_* registers and flash lock bits) to their defaults. * Accordingly, flash can be reprogrammed, and JTAG can be used. * * NOTE that DustDevil parts (at least rev A0 silicon) have errata which * can affect this operation if flash protection has been enabled. */ COMMAND_HANDLER(stellaris_handle_recover_command) { struct flash_bank *bank; int retval; retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (retval != ERROR_OK) return retval; /* REVISIT ... it may be worth sanity checking that the AP is * inactive before we start. ARM documents that switching a DP's * mode while it's active can cause fault modes that need a power * cycle to recover. */ /* assert SRST */ if (!(jtag_get_reset_config() & RESET_HAS_SRST)) { LOG_ERROR("Can't recover Stellaris flash without SRST"); return ERROR_FAIL; } adapter_assert_reset(); for (int i = 0; i < 5; i++) { retval = dap_to_swd(bank->target); if (retval != ERROR_OK) goto done; retval = dap_to_jtag(bank->target); if (retval != ERROR_OK) goto done; } /* de-assert SRST */ adapter_deassert_reset(); retval = jtag_execute_queue(); /* wait 400+ msec ... OK, "1+ second" is simpler */ usleep(1000); /* USER INTERVENTION required for the power cycle * Restarting OpenOCD is likely needed because of mode switching. */ LOG_INFO("USER ACTION: " "power cycle Stellaris chip, then restart OpenOCD."); done: return retval; } static const struct command_registration stellaris_exec_command_handlers[] = { { .name = "mass_erase", .usage = "", .handler = stellaris_handle_mass_erase_command, .mode = COMMAND_EXEC, .help = "erase entire device", }, { .name = "recover", .handler = stellaris_handle_recover_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "recover (and erase) locked device", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration stellaris_command_handlers[] = { { .name = "stellaris", .mode = COMMAND_EXEC, .help = "Stellaris flash command group", .usage = "", .chain = stellaris_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct flash_driver stellaris_flash = { .name = "stellaris", .commands = stellaris_command_handlers, .flash_bank_command = stellaris_flash_bank_command, .erase = stellaris_erase, .protect = stellaris_protect, .write = stellaris_write, .read = default_flash_read, .probe = stellaris_probe, .auto_probe = stellaris_probe, .erase_check = default_flash_blank_check, .protect_check = stellaris_protect_check, .info = get_stellaris_info, }; openocd-0.7.0/src/flash/nor/cfi.c0000644000175000001440000027427712137151330013470 00000000000000/*************************************************************************** * Copyright (C) 2005, 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * Copyright (C) 2009 Michael Schwingen * * michael@schwingen.org * * Copyright (C) 2010 Øyvind Harboe * * Copyright (C) 2010 by Antonio Borneo * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "cfi.h" #include "non_cfi.h" #include #include #include #include #include #include #define CFI_MAX_BUS_WIDTH 4 #define CFI_MAX_CHIP_WIDTH 4 /* defines internal maximum size for code fragment in cfi_intel_write_block() */ #define CFI_MAX_INTEL_CODESIZE 256 /* some id-types with specific handling */ #define AT49BV6416 0x00d6 #define AT49BV6416T 0x00d2 static struct cfi_unlock_addresses cfi_unlock_addresses[] = { [CFI_UNLOCK_555_2AA] = { .unlock1 = 0x555, .unlock2 = 0x2aa }, [CFI_UNLOCK_5555_2AAA] = { .unlock1 = 0x5555, .unlock2 = 0x2aaa }, }; /* CFI fixups forward declarations */ static void cfi_fixup_0002_erase_regions(struct flash_bank *bank, void *param); static void cfi_fixup_0002_unlock_addresses(struct flash_bank *bank, void *param); static void cfi_fixup_reversed_erase_regions(struct flash_bank *bank, void *param); static void cfi_fixup_0002_write_buffer(struct flash_bank *bank, void *param); /* fixup after reading cmdset 0002 primary query table */ static const struct cfi_fixup cfi_0002_fixups[] = { {CFI_MFR_SST, 0x00D4, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]}, {CFI_MFR_SST, 0x00D5, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]}, {CFI_MFR_SST, 0x00D6, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]}, {CFI_MFR_SST, 0x00D7, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]}, {CFI_MFR_SST, 0x2780, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]}, {CFI_MFR_SST, 0x274b, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]}, {CFI_MFR_SST, 0x236d, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_555_2AA]}, {CFI_MFR_ATMEL, 0x00C8, cfi_fixup_reversed_erase_regions, NULL}, {CFI_MFR_ST, 0x22C4, cfi_fixup_reversed_erase_regions, NULL}, /* M29W160ET */ {CFI_MFR_FUJITSU, 0x22ea, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_555_2AA]}, {CFI_MFR_FUJITSU, 0x226b, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_5555_2AAA]}, {CFI_MFR_AMIC, 0xb31a, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_555_2AA]}, {CFI_MFR_MX, 0x225b, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_555_2AA]}, {CFI_MFR_EON, 0x225b, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_555_2AA]}, {CFI_MFR_AMD, 0x225b, cfi_fixup_0002_unlock_addresses, &cfi_unlock_addresses[CFI_UNLOCK_555_2AA]}, {CFI_MFR_ANY, CFI_ID_ANY, cfi_fixup_0002_erase_regions, NULL}, {CFI_MFR_ST, 0x227E, cfi_fixup_0002_write_buffer, NULL},/* M29W128G */ {0, 0, NULL, NULL} }; /* fixup after reading cmdset 0001 primary query table */ static const struct cfi_fixup cfi_0001_fixups[] = { {0, 0, NULL, NULL} }; static void cfi_fixup(struct flash_bank *bank, const struct cfi_fixup *fixups) { struct cfi_flash_bank *cfi_info = bank->driver_priv; const struct cfi_fixup *f; for (f = fixups; f->fixup; f++) { if (((f->mfr == CFI_MFR_ANY) || (f->mfr == cfi_info->manufacturer)) && ((f->id == CFI_ID_ANY) || (f->id == cfi_info->device_id))) f->fixup(bank, f->param); } } static inline uint32_t flash_address(struct flash_bank *bank, int sector, uint32_t offset) { struct cfi_flash_bank *cfi_info = bank->driver_priv; if (cfi_info->x16_as_x8) offset *= 2; /* while the sector list isn't built, only accesses to sector 0 work */ if (sector == 0) return bank->base + offset * bank->bus_width; else { if (!bank->sectors) { LOG_ERROR("BUG: sector list not yet built"); exit(-1); } return bank->base + bank->sectors[sector].offset + offset * bank->bus_width; } } static void cfi_command(struct flash_bank *bank, uint8_t cmd, uint8_t *cmd_buf) { int i; /* clear whole buffer, to ensure bits that exceed the bus_width * are set to zero */ for (i = 0; i < CFI_MAX_BUS_WIDTH; i++) cmd_buf[i] = 0; if (bank->target->endianness == TARGET_LITTLE_ENDIAN) { for (i = bank->bus_width; i > 0; i--) *cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd; } else { for (i = 1; i <= bank->bus_width; i++) *cmd_buf++ = (i & (bank->chip_width - 1)) ? 0x0 : cmd; } } static int cfi_send_command(struct flash_bank *bank, uint8_t cmd, uint32_t address) { uint8_t command[CFI_MAX_BUS_WIDTH]; cfi_command(bank, cmd, command); return target_write_memory(bank->target, address, bank->bus_width, 1, command); } /* read unsigned 8-bit value from the bank * flash banks are expected to be made of similar chips * the query result should be the same for all */ static int cfi_query_u8(struct flash_bank *bank, int sector, uint32_t offset, uint8_t *val) { struct target *target = bank->target; uint8_t data[CFI_MAX_BUS_WIDTH]; int retval; retval = target_read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 1, data); if (retval != ERROR_OK) return retval; if (bank->target->endianness == TARGET_LITTLE_ENDIAN) *val = data[0]; else *val = data[bank->bus_width - 1]; return ERROR_OK; } /* read unsigned 8-bit value from the bank * in case of a bank made of multiple chips, * the individual values are ORed */ static int cfi_get_u8(struct flash_bank *bank, int sector, uint32_t offset, uint8_t *val) { struct target *target = bank->target; uint8_t data[CFI_MAX_BUS_WIDTH]; int i; int retval; retval = target_read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 1, data); if (retval != ERROR_OK) return retval; if (bank->target->endianness == TARGET_LITTLE_ENDIAN) { for (i = 0; i < bank->bus_width / bank->chip_width; i++) data[0] |= data[i]; *val = data[0]; } else { uint8_t value = 0; for (i = 0; i < bank->bus_width / bank->chip_width; i++) value |= data[bank->bus_width - 1 - i]; *val = value; } return ERROR_OK; } static int cfi_query_u16(struct flash_bank *bank, int sector, uint32_t offset, uint16_t *val) { struct target *target = bank->target; struct cfi_flash_bank *cfi_info = bank->driver_priv; uint8_t data[CFI_MAX_BUS_WIDTH * 2]; int retval; if (cfi_info->x16_as_x8) { uint8_t i; for (i = 0; i < 2; i++) { retval = target_read_memory(target, flash_address(bank, sector, offset + i), bank->bus_width, 1, &data[i * bank->bus_width]); if (retval != ERROR_OK) return retval; } } else { retval = target_read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 2, data); if (retval != ERROR_OK) return retval; } if (bank->target->endianness == TARGET_LITTLE_ENDIAN) *val = data[0] | data[bank->bus_width] << 8; else *val = data[bank->bus_width - 1] | data[(2 * bank->bus_width) - 1] << 8; return ERROR_OK; } static int cfi_query_u32(struct flash_bank *bank, int sector, uint32_t offset, uint32_t *val) { struct target *target = bank->target; struct cfi_flash_bank *cfi_info = bank->driver_priv; uint8_t data[CFI_MAX_BUS_WIDTH * 4]; int retval; if (cfi_info->x16_as_x8) { uint8_t i; for (i = 0; i < 4; i++) { retval = target_read_memory(target, flash_address(bank, sector, offset + i), bank->bus_width, 1, &data[i * bank->bus_width]); if (retval != ERROR_OK) return retval; } } else { retval = target_read_memory(target, flash_address(bank, sector, offset), bank->bus_width, 4, data); if (retval != ERROR_OK) return retval; } if (bank->target->endianness == TARGET_LITTLE_ENDIAN) *val = data[0] | data[bank->bus_width] << 8 | data[bank->bus_width * 2] << 16 | data[bank->bus_width * 3] << 24; else *val = data[bank->bus_width - 1] | data[(2 * bank->bus_width) - 1] << 8 | data[(3 * bank->bus_width) - 1] << 16 | data[(4 * bank->bus_width) - 1] << 24; return ERROR_OK; } static int cfi_reset(struct flash_bank *bank) { struct cfi_flash_bank *cfi_info = bank->driver_priv; int retval = ERROR_OK; retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; if (cfi_info->manufacturer == 0x20 && (cfi_info->device_id == 0x227E || cfi_info->device_id == 0x7E)) { /* Numonix M29W128G is cmd 0xFF intolerant - causes internal undefined state * so we send an extra 0xF0 reset to fix the bug */ retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x00)); if (retval != ERROR_OK) return retval; } return retval; } static void cfi_intel_clear_status_register(struct flash_bank *bank) { cfi_send_command(bank, 0x50, flash_address(bank, 0, 0x0)); } static int cfi_intel_wait_status_busy(struct flash_bank *bank, int timeout, uint8_t *val) { uint8_t status; int retval = ERROR_OK; for (;; ) { if (timeout-- < 0) { LOG_ERROR("timeout while waiting for WSM to become ready"); return ERROR_FAIL; } retval = cfi_get_u8(bank, 0, 0x0, &status); if (retval != ERROR_OK) return retval; if (status & 0x80) break; alive_sleep(1); } /* mask out bit 0 (reserved) */ status = status & 0xfe; LOG_DEBUG("status: 0x%x", status); if (status != 0x80) { LOG_ERROR("status register: 0x%x", status); if (status & 0x2) LOG_ERROR("Block Lock-Bit Detected, Operation Abort"); if (status & 0x4) LOG_ERROR("Program suspended"); if (status & 0x8) LOG_ERROR("Low Programming Voltage Detected, Operation Aborted"); if (status & 0x10) LOG_ERROR("Program Error / Error in Setting Lock-Bit"); if (status & 0x20) LOG_ERROR("Error in Block Erasure or Clear Lock-Bits"); if (status & 0x40) LOG_ERROR("Block Erase Suspended"); cfi_intel_clear_status_register(bank); retval = ERROR_FAIL; } *val = status; return retval; } static int cfi_spansion_wait_status_busy(struct flash_bank *bank, int timeout) { uint8_t status, oldstatus; struct cfi_flash_bank *cfi_info = bank->driver_priv; int retval; retval = cfi_get_u8(bank, 0, 0x0, &oldstatus); if (retval != ERROR_OK) return retval; do { retval = cfi_get_u8(bank, 0, 0x0, &status); if (retval != ERROR_OK) return retval; if ((status ^ oldstatus) & 0x40) { if (status & cfi_info->status_poll_mask & 0x20) { retval = cfi_get_u8(bank, 0, 0x0, &oldstatus); if (retval != ERROR_OK) return retval; retval = cfi_get_u8(bank, 0, 0x0, &status); if (retval != ERROR_OK) return retval; if ((status ^ oldstatus) & 0x40) { LOG_ERROR("dq5 timeout, status: 0x%x", status); return ERROR_FLASH_OPERATION_FAILED; } else { LOG_DEBUG("status: 0x%x", status); return ERROR_OK; } } } else {/* no toggle: finished, OK */ LOG_DEBUG("status: 0x%x", status); return ERROR_OK; } oldstatus = status; alive_sleep(1); } while (timeout-- > 0); LOG_ERROR("timeout, status: 0x%x", status); return ERROR_FLASH_BUSY; } static int cfi_read_intel_pri_ext(struct flash_bank *bank) { int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_intel_pri_ext *pri_ext; if (cfi_info->pri_ext) free(cfi_info->pri_ext); pri_ext = malloc(sizeof(struct cfi_intel_pri_ext)); if (pri_ext == NULL) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } cfi_info->pri_ext = pri_ext; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0, &pri_ext->pri[0]); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 1, &pri_ext->pri[1]); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 2, &pri_ext->pri[2]); if (retval != ERROR_OK) return retval; if ((pri_ext->pri[0] != 'P') || (pri_ext->pri[1] != 'R') || (pri_ext->pri[2] != 'I')) { retval = cfi_reset(bank); if (retval != ERROR_OK) return retval; LOG_ERROR("Could not read bank flash bank information"); return ERROR_FLASH_BANK_INVALID; } retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 3, &pri_ext->major_version); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 4, &pri_ext->minor_version); if (retval != ERROR_OK) return retval; LOG_DEBUG("pri: '%c%c%c', version: %c.%c", pri_ext->pri[0], pri_ext->pri[1], pri_ext->pri[2], pri_ext->major_version, pri_ext->minor_version); retval = cfi_query_u32(bank, 0, cfi_info->pri_addr + 5, &pri_ext->feature_support); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 9, &pri_ext->suspend_cmd_support); if (retval != ERROR_OK) return retval; retval = cfi_query_u16(bank, 0, cfi_info->pri_addr + 0xa, &pri_ext->blk_status_reg_mask); if (retval != ERROR_OK) return retval; LOG_DEBUG("feature_support: 0x%" PRIx32 ", suspend_cmd_support: " "0x%x, blk_status_reg_mask: 0x%x", pri_ext->feature_support, pri_ext->suspend_cmd_support, pri_ext->blk_status_reg_mask); retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0xc, &pri_ext->vcc_optimal); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0xd, &pri_ext->vpp_optimal); if (retval != ERROR_OK) return retval; LOG_DEBUG("Vcc opt: %x.%x, Vpp opt: %u.%x", (pri_ext->vcc_optimal & 0xf0) >> 4, pri_ext->vcc_optimal & 0x0f, (pri_ext->vpp_optimal & 0xf0) >> 4, pri_ext->vpp_optimal & 0x0f); retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0xe, &pri_ext->num_protection_fields); if (retval != ERROR_OK) return retval; if (pri_ext->num_protection_fields != 1) { LOG_WARNING("expected one protection register field, but found %i", pri_ext->num_protection_fields); } retval = cfi_query_u16(bank, 0, cfi_info->pri_addr + 0xf, &pri_ext->prot_reg_addr); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0x11, &pri_ext->fact_prot_reg_size); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0x12, &pri_ext->user_prot_reg_size); if (retval != ERROR_OK) return retval; LOG_DEBUG("protection_fields: %i, prot_reg_addr: 0x%x, " "factory pre-programmed: %i, user programmable: %i", pri_ext->num_protection_fields, pri_ext->prot_reg_addr, 1 << pri_ext->fact_prot_reg_size, 1 << pri_ext->user_prot_reg_size); return ERROR_OK; } static int cfi_read_spansion_pri_ext(struct flash_bank *bank) { int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_spansion_pri_ext *pri_ext; if (cfi_info->pri_ext) free(cfi_info->pri_ext); pri_ext = malloc(sizeof(struct cfi_spansion_pri_ext)); if (pri_ext == NULL) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } cfi_info->pri_ext = pri_ext; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0, &pri_ext->pri[0]); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 1, &pri_ext->pri[1]); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 2, &pri_ext->pri[2]); if (retval != ERROR_OK) return retval; if ((pri_ext->pri[0] != 'P') || (pri_ext->pri[1] != 'R') || (pri_ext->pri[2] != 'I')) { retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; LOG_ERROR("Could not read spansion bank information"); return ERROR_FLASH_BANK_INVALID; } retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 3, &pri_ext->major_version); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 4, &pri_ext->minor_version); if (retval != ERROR_OK) return retval; LOG_DEBUG("pri: '%c%c%c', version: %c.%c", pri_ext->pri[0], pri_ext->pri[1], pri_ext->pri[2], pri_ext->major_version, pri_ext->minor_version); retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 5, &pri_ext->SiliconRevision); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 6, &pri_ext->EraseSuspend); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 7, &pri_ext->BlkProt); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 8, &pri_ext->TmpBlkUnprotect); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 9, &pri_ext->BlkProtUnprot); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 10, &pri_ext->SimultaneousOps); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 11, &pri_ext->BurstMode); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 12, &pri_ext->PageMode); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 13, &pri_ext->VppMin); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 14, &pri_ext->VppMax); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 15, &pri_ext->TopBottom); if (retval != ERROR_OK) return retval; LOG_DEBUG("Silicon Revision: 0x%x, Erase Suspend: 0x%x, Block protect: 0x%x", pri_ext->SiliconRevision, pri_ext->EraseSuspend, pri_ext->BlkProt); LOG_DEBUG("Temporary Unprotect: 0x%x, Block Protect Scheme: 0x%x, " "Simultaneous Ops: 0x%x", pri_ext->TmpBlkUnprotect, pri_ext->BlkProtUnprot, pri_ext->SimultaneousOps); LOG_DEBUG("Burst Mode: 0x%x, Page Mode: 0x%x, ", pri_ext->BurstMode, pri_ext->PageMode); LOG_DEBUG("Vpp min: %u.%x, Vpp max: %u.%x", (pri_ext->VppMin & 0xf0) >> 4, pri_ext->VppMin & 0x0f, (pri_ext->VppMax & 0xf0) >> 4, pri_ext->VppMax & 0x0f); LOG_DEBUG("WP# protection 0x%x", pri_ext->TopBottom); /* default values for implementation specific workarounds */ pri_ext->_unlock1 = cfi_unlock_addresses[CFI_UNLOCK_555_2AA].unlock1; pri_ext->_unlock2 = cfi_unlock_addresses[CFI_UNLOCK_555_2AA].unlock2; pri_ext->_reversed_geometry = 0; return ERROR_OK; } static int cfi_read_atmel_pri_ext(struct flash_bank *bank) { int retval; struct cfi_atmel_pri_ext atmel_pri_ext; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_spansion_pri_ext *pri_ext; if (cfi_info->pri_ext) free(cfi_info->pri_ext); pri_ext = malloc(sizeof(struct cfi_spansion_pri_ext)); if (pri_ext == NULL) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } /* ATMEL devices use the same CFI primary command set (0x2) as AMD/Spansion, * but a different primary extended query table. * We read the atmel table, and prepare a valid AMD/Spansion query table. */ memset(pri_ext, 0, sizeof(struct cfi_spansion_pri_ext)); cfi_info->pri_ext = pri_ext; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 0, &atmel_pri_ext.pri[0]); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 1, &atmel_pri_ext.pri[1]); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 2, &atmel_pri_ext.pri[2]); if (retval != ERROR_OK) return retval; if ((atmel_pri_ext.pri[0] != 'P') || (atmel_pri_ext.pri[1] != 'R') || (atmel_pri_ext.pri[2] != 'I')) { retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; LOG_ERROR("Could not read atmel bank information"); return ERROR_FLASH_BANK_INVALID; } pri_ext->pri[0] = atmel_pri_ext.pri[0]; pri_ext->pri[1] = atmel_pri_ext.pri[1]; pri_ext->pri[2] = atmel_pri_ext.pri[2]; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 3, &atmel_pri_ext.major_version); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 4, &atmel_pri_ext.minor_version); if (retval != ERROR_OK) return retval; LOG_DEBUG("pri: '%c%c%c', version: %c.%c", atmel_pri_ext.pri[0], atmel_pri_ext.pri[1], atmel_pri_ext.pri[2], atmel_pri_ext.major_version, atmel_pri_ext.minor_version); pri_ext->major_version = atmel_pri_ext.major_version; pri_ext->minor_version = atmel_pri_ext.minor_version; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 5, &atmel_pri_ext.features); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 6, &atmel_pri_ext.bottom_boot); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 7, &atmel_pri_ext.burst_mode); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, cfi_info->pri_addr + 8, &atmel_pri_ext.page_mode); if (retval != ERROR_OK) return retval; LOG_DEBUG( "features: 0x%2.2x, bottom_boot: 0x%2.2x, burst_mode: 0x%2.2x, page_mode: 0x%2.2x", atmel_pri_ext.features, atmel_pri_ext.bottom_boot, atmel_pri_ext.burst_mode, atmel_pri_ext.page_mode); if (atmel_pri_ext.features & 0x02) pri_ext->EraseSuspend = 2; /* some chips got it backwards... */ if (cfi_info->device_id == AT49BV6416 || cfi_info->device_id == AT49BV6416T) { if (atmel_pri_ext.bottom_boot) pri_ext->TopBottom = 3; else pri_ext->TopBottom = 2; } else { if (atmel_pri_ext.bottom_boot) pri_ext->TopBottom = 2; else pri_ext->TopBottom = 3; } pri_ext->_unlock1 = cfi_unlock_addresses[CFI_UNLOCK_555_2AA].unlock1; pri_ext->_unlock2 = cfi_unlock_addresses[CFI_UNLOCK_555_2AA].unlock2; return ERROR_OK; } static int cfi_read_0002_pri_ext(struct flash_bank *bank) { struct cfi_flash_bank *cfi_info = bank->driver_priv; if (cfi_info->manufacturer == CFI_MFR_ATMEL) return cfi_read_atmel_pri_ext(bank); else return cfi_read_spansion_pri_ext(bank); } static int cfi_spansion_info(struct flash_bank *bank, char *buf, int buf_size) { int printed; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; printed = snprintf(buf, buf_size, "\nSpansion primary algorithm extend information:\n"); buf += printed; buf_size -= printed; printed = snprintf(buf, buf_size, "pri: '%c%c%c', version: %c.%c\n", pri_ext->pri[0], pri_ext->pri[1], pri_ext->pri[2], pri_ext->major_version, pri_ext->minor_version); buf += printed; buf_size -= printed; printed = snprintf(buf, buf_size, "Silicon Rev.: 0x%x, Address Sensitive unlock: 0x%x\n", (pri_ext->SiliconRevision) >> 2, (pri_ext->SiliconRevision) & 0x03); buf += printed; buf_size -= printed; printed = snprintf(buf, buf_size, "Erase Suspend: 0x%x, Sector Protect: 0x%x\n", pri_ext->EraseSuspend, pri_ext->BlkProt); buf += printed; buf_size -= printed; snprintf(buf, buf_size, "VppMin: %u.%x, VppMax: %u.%x\n", (pri_ext->VppMin & 0xf0) >> 4, pri_ext->VppMin & 0x0f, (pri_ext->VppMax & 0xf0) >> 4, pri_ext->VppMax & 0x0f); return ERROR_OK; } static int cfi_intel_info(struct flash_bank *bank, char *buf, int buf_size) { int printed; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_intel_pri_ext *pri_ext = cfi_info->pri_ext; printed = snprintf(buf, buf_size, "\nintel primary algorithm extend information:\n"); buf += printed; buf_size -= printed; printed = snprintf(buf, buf_size, "pri: '%c%c%c', version: %c.%c\n", pri_ext->pri[0], pri_ext->pri[1], pri_ext->pri[2], pri_ext->major_version, pri_ext->minor_version); buf += printed; buf_size -= printed; printed = snprintf(buf, buf_size, "feature_support: 0x%" PRIx32 ", " "suspend_cmd_support: 0x%x, blk_status_reg_mask: 0x%x\n", pri_ext->feature_support, pri_ext->suspend_cmd_support, pri_ext->blk_status_reg_mask); buf += printed; buf_size -= printed; printed = snprintf(buf, buf_size, "Vcc opt: %x.%x, Vpp opt: %u.%x\n", (pri_ext->vcc_optimal & 0xf0) >> 4, pri_ext->vcc_optimal & 0x0f, (pri_ext->vpp_optimal & 0xf0) >> 4, pri_ext->vpp_optimal & 0x0f); buf += printed; buf_size -= printed; snprintf(buf, buf_size, "protection_fields: %i, prot_reg_addr: 0x%x, " "factory pre-programmed: %i, user programmable: %i\n", pri_ext->num_protection_fields, pri_ext->prot_reg_addr, 1 << pri_ext->fact_prot_reg_size, 1 << pri_ext->user_prot_reg_size); return ERROR_OK; } /* flash_bank cfi [options] */ FLASH_BANK_COMMAND_HANDLER(cfi_flash_bank_command) { struct cfi_flash_bank *cfi_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; /* both widths must: * - not exceed max value; * - not be null; * - be equal to a power of 2. * bus must be wide enough to hold one chip */ if ((bank->chip_width > CFI_MAX_CHIP_WIDTH) || (bank->bus_width > CFI_MAX_BUS_WIDTH) || (bank->chip_width == 0) || (bank->bus_width == 0) || (bank->chip_width & (bank->chip_width - 1)) || (bank->bus_width & (bank->bus_width - 1)) || (bank->chip_width > bank->bus_width)) { LOG_ERROR("chip and bus width have to specified in bytes"); return ERROR_FLASH_BANK_INVALID; } cfi_info = malloc(sizeof(struct cfi_flash_bank)); cfi_info->probed = 0; cfi_info->erase_region_info = NULL; cfi_info->pri_ext = NULL; bank->driver_priv = cfi_info; cfi_info->x16_as_x8 = 0; cfi_info->jedec_probe = 0; cfi_info->not_cfi = 0; for (unsigned i = 6; i < CMD_ARGC; i++) { if (strcmp(CMD_ARGV[i], "x16_as_x8") == 0) cfi_info->x16_as_x8 = 1; else if (strcmp(CMD_ARGV[i], "jedec_probe") == 0) cfi_info->jedec_probe = 1; } /* bank wasn't probed yet */ cfi_info->qry[0] = 0xff; return ERROR_OK; } static int cfi_intel_erase(struct flash_bank *bank, int first, int last) { int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; int i; cfi_intel_clear_status_register(bank); for (i = first; i <= last; i++) { retval = cfi_send_command(bank, 0x20, flash_address(bank, i, 0x0)); if (retval != ERROR_OK) return retval; retval = cfi_send_command(bank, 0xd0, flash_address(bank, i, 0x0)); if (retval != ERROR_OK) return retval; uint8_t status; retval = cfi_intel_wait_status_busy(bank, cfi_info->block_erase_timeout, &status); if (retval != ERROR_OK) return retval; if (status == 0x80) bank->sectors[i].is_erased = 1; else { retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; LOG_ERROR("couldn't erase block %i of flash bank at base 0x%" PRIx32, i, bank->base); return ERROR_FLASH_OPERATION_FAILED; } } return cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0)); } static int cfi_spansion_erase(struct flash_bank *bank, int first, int last) { int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; int i; for (i = first; i <= last; i++) { retval = cfi_send_command(bank, 0xaa, flash_address(bank, 0, pri_ext->_unlock1)); if (retval != ERROR_OK) return retval; retval = cfi_send_command(bank, 0x55, flash_address(bank, 0, pri_ext->_unlock2)); if (retval != ERROR_OK) return retval; retval = cfi_send_command(bank, 0x80, flash_address(bank, 0, pri_ext->_unlock1)); if (retval != ERROR_OK) return retval; retval = cfi_send_command(bank, 0xaa, flash_address(bank, 0, pri_ext->_unlock1)); if (retval != ERROR_OK) return retval; retval = cfi_send_command(bank, 0x55, flash_address(bank, 0, pri_ext->_unlock2)); if (retval != ERROR_OK) return retval; retval = cfi_send_command(bank, 0x30, flash_address(bank, i, 0x0)); if (retval != ERROR_OK) return retval; if (cfi_spansion_wait_status_busy(bank, cfi_info->block_erase_timeout) == ERROR_OK) bank->sectors[i].is_erased = 1; else { retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; LOG_ERROR("couldn't erase block %i of flash bank at base 0x%" PRIx32, i, bank->base); return ERROR_FLASH_OPERATION_FAILED; } } return cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0)); } static int cfi_erase(struct flash_bank *bank, int first, int last) { struct cfi_flash_bank *cfi_info = bank->driver_priv; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if ((first < 0) || (last < first) || (last >= bank->num_sectors)) return ERROR_FLASH_SECTOR_INVALID; if (cfi_info->qry[0] != 'Q') return ERROR_FLASH_BANK_NOT_PROBED; switch (cfi_info->pri_id) { case 1: case 3: return cfi_intel_erase(bank, first, last); break; case 2: return cfi_spansion_erase(bank, first, last); break; default: LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); break; } return ERROR_OK; } static int cfi_intel_protect(struct flash_bank *bank, int set, int first, int last) { int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_intel_pri_ext *pri_ext = cfi_info->pri_ext; int retry = 0; int i; /* if the device supports neither legacy lock/unlock (bit 3) nor * instant individual block locking (bit 5). */ if (!(pri_ext->feature_support & 0x28)) { LOG_ERROR("lock/unlock not supported on flash"); return ERROR_FLASH_OPERATION_FAILED; } cfi_intel_clear_status_register(bank); for (i = first; i <= last; i++) { retval = cfi_send_command(bank, 0x60, flash_address(bank, i, 0x0)); if (retval != ERROR_OK) return retval; if (set) { retval = cfi_send_command(bank, 0x01, flash_address(bank, i, 0x0)); if (retval != ERROR_OK) return retval; bank->sectors[i].is_protected = 1; } else { retval = cfi_send_command(bank, 0xd0, flash_address(bank, i, 0x0)); if (retval != ERROR_OK) return retval; bank->sectors[i].is_protected = 0; } /* instant individual block locking doesn't require reading of the status register **/ if (!(pri_ext->feature_support & 0x20)) { /* Clear lock bits operation may take up to 1.4s */ uint8_t status; retval = cfi_intel_wait_status_busy(bank, 1400, &status); if (retval != ERROR_OK) return retval; } else { uint8_t block_status; /* read block lock bit, to verify status */ retval = cfi_send_command(bank, 0x90, flash_address(bank, 0, 0x55)); if (retval != ERROR_OK) return retval; retval = cfi_get_u8(bank, i, 0x2, &block_status); if (retval != ERROR_OK) return retval; if ((block_status & 0x1) != set) { LOG_ERROR( "couldn't change block lock status (set = %i, block_status = 0x%2.2x)", set, block_status); retval = cfi_send_command(bank, 0x70, flash_address(bank, 0, 0x55)); if (retval != ERROR_OK) return retval; uint8_t status; retval = cfi_intel_wait_status_busy(bank, 10, &status); if (retval != ERROR_OK) return retval; if (retry > 10) return ERROR_FLASH_OPERATION_FAILED; else { i--; retry++; } } } } /* if the device doesn't support individual block lock bits set/clear, * all blocks have been unlocked in parallel, so we set those that should be protected */ if ((!set) && (!(pri_ext->feature_support & 0x20))) { /* FIX!!! this code path is broken!!! * * The correct approach is: * * 1. read out current protection status * * 2. override read out protection status w/unprotected. * * 3. re-protect what should be protected. * */ for (i = 0; i < bank->num_sectors; i++) { if (bank->sectors[i].is_protected == 1) { cfi_intel_clear_status_register(bank); retval = cfi_send_command(bank, 0x60, flash_address(bank, i, 0x0)); if (retval != ERROR_OK) return retval; retval = cfi_send_command(bank, 0x01, flash_address(bank, i, 0x0)); if (retval != ERROR_OK) return retval; uint8_t status; retval = cfi_intel_wait_status_busy(bank, 100, &status); if (retval != ERROR_OK) return retval; } } } return cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0)); } static int cfi_protect(struct flash_bank *bank, int set, int first, int last) { struct cfi_flash_bank *cfi_info = bank->driver_priv; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if ((first < 0) || (last < first) || (last >= bank->num_sectors)) { LOG_ERROR("Invalid sector range"); return ERROR_FLASH_SECTOR_INVALID; } if (cfi_info->qry[0] != 'Q') return ERROR_FLASH_BANK_NOT_PROBED; switch (cfi_info->pri_id) { case 1: case 3: return cfi_intel_protect(bank, set, first, last); break; default: LOG_WARNING("protect: cfi primary command set %i unsupported", cfi_info->pri_id); return ERROR_OK; } } /* Convert code image to target endian * FIXME create general block conversion fcts in target.c?) */ static void cfi_fix_code_endian(struct target *target, uint8_t *dest, const uint32_t *src, uint32_t count) { uint32_t i; for (i = 0; i < count; i++) { target_buffer_set_u32(target, dest, *src); dest += 4; src++; } } static uint32_t cfi_command_val(struct flash_bank *bank, uint8_t cmd) { struct target *target = bank->target; uint8_t buf[CFI_MAX_BUS_WIDTH]; cfi_command(bank, cmd, buf); switch (bank->bus_width) { case 1: return buf[0]; break; case 2: return target_buffer_get_u16(target, buf); break; case 4: return target_buffer_get_u32(target, buf); break; default: LOG_ERROR("Unsupported bank buswidth %d, can't do block memory writes", bank->bus_width); return 0; } } static int cfi_intel_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t address, uint32_t count) { struct target *target = bank->target; struct reg_param reg_params[7]; struct arm_algorithm arm_algo; struct working_area *write_algorithm; struct working_area *source = NULL; uint32_t buffer_size = 32768; uint32_t write_command_val, busy_pattern_val, error_pattern_val; /* algorithm register usage: * r0: source address (in RAM) * r1: target address (in Flash) * r2: count * r3: flash write command * r4: status byte (returned to host) * r5: busy test pattern * r6: error test pattern */ /* see contib/loaders/flash/armv4_5_cfi_intel_32.s for src */ static const uint32_t word_32_code[] = { 0xe4904004, /* loop: ldr r4, [r0], #4 */ 0xe5813000, /* str r3, [r1] */ 0xe5814000, /* str r4, [r1] */ 0xe5914000, /* busy: ldr r4, [r1] */ 0xe0047005, /* and r7, r4, r5 */ 0xe1570005, /* cmp r7, r5 */ 0x1afffffb, /* bne busy */ 0xe1140006, /* tst r4, r6 */ 0x1a000003, /* bne done */ 0xe2522001, /* subs r2, r2, #1 */ 0x0a000001, /* beq done */ 0xe2811004, /* add r1, r1 #4 */ 0xeafffff2, /* b loop */ 0xeafffffe /* done: b -2 */ }; /* see contib/loaders/flash/armv4_5_cfi_intel_16.s for src */ static const uint32_t word_16_code[] = { 0xe0d040b2, /* loop: ldrh r4, [r0], #2 */ 0xe1c130b0, /* strh r3, [r1] */ 0xe1c140b0, /* strh r4, [r1] */ 0xe1d140b0, /* busy ldrh r4, [r1] */ 0xe0047005, /* and r7, r4, r5 */ 0xe1570005, /* cmp r7, r5 */ 0x1afffffb, /* bne busy */ 0xe1140006, /* tst r4, r6 */ 0x1a000003, /* bne done */ 0xe2522001, /* subs r2, r2, #1 */ 0x0a000001, /* beq done */ 0xe2811002, /* add r1, r1 #2 */ 0xeafffff2, /* b loop */ 0xeafffffe /* done: b -2 */ }; /* see contib/loaders/flash/armv4_5_cfi_intel_8.s for src */ static const uint32_t word_8_code[] = { 0xe4d04001, /* loop: ldrb r4, [r0], #1 */ 0xe5c13000, /* strb r3, [r1] */ 0xe5c14000, /* strb r4, [r1] */ 0xe5d14000, /* busy ldrb r4, [r1] */ 0xe0047005, /* and r7, r4, r5 */ 0xe1570005, /* cmp r7, r5 */ 0x1afffffb, /* bne busy */ 0xe1140006, /* tst r4, r6 */ 0x1a000003, /* bne done */ 0xe2522001, /* subs r2, r2, #1 */ 0x0a000001, /* beq done */ 0xe2811001, /* add r1, r1 #1 */ 0xeafffff2, /* b loop */ 0xeafffffe /* done: b -2 */ }; uint8_t target_code[4*CFI_MAX_INTEL_CODESIZE]; const uint32_t *target_code_src; uint32_t target_code_size; int retval = ERROR_OK; /* check we have a supported arch */ if (is_arm(target_to_arm(target))) { /* All other ARM CPUs have 32 bit instructions */ arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; } else { LOG_ERROR("Unknown architecture"); return ERROR_FAIL; } cfi_intel_clear_status_register(bank); /* If we are setting up the write_algorith, we need target_code_src * if not we only need target_code_size. */ /* However, we don't want to create multiple code paths, so we * do the unnecessary evaluation of target_code_src, which the * compiler will probably nicely optimize away if not needed */ /* prepare algorithm code for target endian */ switch (bank->bus_width) { case 1: target_code_src = word_8_code; target_code_size = sizeof(word_8_code); break; case 2: target_code_src = word_16_code; target_code_size = sizeof(word_16_code); break; case 4: target_code_src = word_32_code; target_code_size = sizeof(word_32_code); break; default: LOG_ERROR("Unsupported bank buswidth %d, can't do block memory writes", bank->bus_width); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* flash write code */ if (target_code_size > sizeof(target_code)) { LOG_WARNING("Internal error - target code buffer to small. " "Increase CFI_MAX_INTEL_CODESIZE and recompile."); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } cfi_fix_code_endian(target, target_code, target_code_src, target_code_size / 4); /* Get memory for block write handler */ retval = target_alloc_working_area(target, target_code_size, &write_algorithm); if (retval != ERROR_OK) { LOG_WARNING("No working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } ; /* write algorithm code to working area */ retval = target_write_buffer(target, write_algorithm->address, target_code_size, target_code); if (retval != ERROR_OK) { LOG_ERROR("Unable to write block write code to target"); goto cleanup; } /* Get a workspace buffer for the data to flash starting with 32k size. * Half size until buffer would be smaller 256 Bytes then fail back */ /* FIXME Why 256 bytes, why not 32 bytes (smallest flash write page */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; if (buffer_size <= 256) { LOG_WARNING( "no large enough working area available, can't do block memory writes"); retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; goto cleanup; } } ; /* setup algo registers */ init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_OUT); init_reg_param(®_params[4], "r4", 32, PARAM_IN); init_reg_param(®_params[5], "r5", 32, PARAM_OUT); init_reg_param(®_params[6], "r6", 32, PARAM_OUT); /* prepare command and status register patterns */ write_command_val = cfi_command_val(bank, 0x40); busy_pattern_val = cfi_command_val(bank, 0x80); error_pattern_val = cfi_command_val(bank, 0x7e); LOG_DEBUG("Using target buffer at 0x%08" PRIx32 " and of size 0x%04" PRIx32, source->address, buffer_size); /* Programming main loop */ while (count > 0) { uint32_t thisrun_count = (count > buffer_size) ? buffer_size : count; uint32_t wsm_error; retval = target_write_buffer(target, source->address, thisrun_count, buffer); if (retval != ERROR_OK) goto cleanup; buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, address); buf_set_u32(reg_params[2].value, 0, 32, thisrun_count / bank->bus_width); buf_set_u32(reg_params[3].value, 0, 32, write_command_val); buf_set_u32(reg_params[5].value, 0, 32, busy_pattern_val); buf_set_u32(reg_params[6].value, 0, 32, error_pattern_val); LOG_DEBUG("Write 0x%04" PRIx32 " bytes to flash at 0x%08" PRIx32, thisrun_count, address); /* Execute algorithm, assume breakpoint for last instruction */ retval = target_run_algorithm(target, 0, NULL, 7, reg_params, write_algorithm->address, write_algorithm->address + target_code_size - sizeof(uint32_t), 10000, /* 10s should be enough for max. 32k of data */ &arm_algo); /* On failure try a fall back to direct word writes */ if (retval != ERROR_OK) { cfi_intel_clear_status_register(bank); LOG_ERROR( "Execution of flash algorythm failed. Can't fall back. Please report."); retval = ERROR_FLASH_OPERATION_FAILED; /* retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; */ /* FIXME To allow fall back or recovery, we must save the actual status * somewhere, so that a higher level code can start recovery. */ goto cleanup; } /* Check return value from algo code */ wsm_error = buf_get_u32(reg_params[4].value, 0, 32) & error_pattern_val; if (wsm_error) { /* read status register (outputs debug information) */ uint8_t status; cfi_intel_wait_status_busy(bank, 100, &status); cfi_intel_clear_status_register(bank); retval = ERROR_FLASH_OPERATION_FAILED; goto cleanup; } buffer += thisrun_count; address += thisrun_count; count -= thisrun_count; keep_alive(); } /* free up resources */ cleanup: if (source) target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); destroy_reg_param(®_params[5]); destroy_reg_param(®_params[6]); return retval; } static int cfi_spansion_write_block_mips(struct flash_bank *bank, uint8_t *buffer, uint32_t address, uint32_t count) { struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; struct target *target = bank->target; struct reg_param reg_params[10]; struct mips32_algorithm mips32_info; struct working_area *write_algorithm; struct working_area *source; uint32_t buffer_size = 32768; uint32_t status; int retval = ERROR_OK; /* input parameters - * 4 A0 = source address * 5 A1 = destination address * 6 A2 = number of writes * 7 A3 = flash write command * 8 T0 = constant to mask DQ7 bits (also used for Dq5 with shift) * output parameters - * 9 T1 = 0x80 ok 0x00 bad * temp registers - * 10 T2 = value read from flash to test status * 11 T3 = holding register * unlock registers - * 12 T4 = unlock1_addr * 13 T5 = unlock1_cmd * 14 T6 = unlock2_addr * 15 T7 = unlock2_cmd */ static const uint32_t mips_word_16_code[] = { /* start: */ MIPS32_LHU(9, 0, 4), /* lhu $t1, ($a0) ; out = &saddr */ MIPS32_ADDI(4, 4, 2), /* addi $a0, $a0, 2 ; saddr += 2 */ MIPS32_SH(13, 0, 12), /* sh $t5, ($t4) ; *fl_unl_addr1 = fl_unl_cmd1 */ MIPS32_SH(15, 0, 14), /* sh $t7, ($t6) ; *fl_unl_addr2 = fl_unl_cmd2 */ MIPS32_SH(7, 0, 12), /* sh $a3, ($t4) ; *fl_unl_addr1 = fl_write_cmd */ MIPS32_SH(9, 0, 5), /* sh $t1, ($a1) ; *daddr = out */ MIPS32_NOP, /* nop */ /* busy: */ MIPS32_LHU(10, 0, 5), /* lhu $t2, ($a1) ; temp1 = *daddr */ MIPS32_XOR(11, 9, 10), /* xor $t3, $a0, $t2 ; temp2 = out ^ temp1; */ MIPS32_AND(11, 8, 11), /* and $t3, $t0, $t3 ; temp2 = temp2 & DQ7mask */ MIPS32_BNE(11, 8, 13), /* bne $t3, $t0, cont ; if (temp2 != DQ7mask) goto cont */ MIPS32_NOP, /* nop */ MIPS32_SRL(10, 8, 2), /* srl $t2,$t0,2 ; temp1 = DQ7mask >> 2 */ MIPS32_AND(11, 10, 11), /* and $t3, $t2, $t3 ; temp2 = temp2 & temp1 */ MIPS32_BNE(11, 10, NEG16(8)), /* bne $t3, $t2, busy ; if (temp2 != temp1) goto busy */ MIPS32_NOP, /* nop */ MIPS32_LHU(10, 0, 5), /* lhu $t2, ($a1) ; temp1 = *daddr */ MIPS32_XOR(11, 9, 10), /* xor $t3, $a0, $t2 ; temp2 = out ^ temp1; */ MIPS32_AND(11, 8, 11), /* and $t3, $t0, $t3 ; temp2 = temp2 & DQ7mask */ MIPS32_BNE(11, 8, 4), /* bne $t3, $t0, cont ; if (temp2 != DQ7mask) goto cont */ MIPS32_NOP, /* nop */ MIPS32_XOR(9, 9, 9), /* xor $t1, $t1, $t1 ; out = 0 */ MIPS32_BEQ(9, 0, 11), /* beq $t1, $zero, done ; if (out == 0) goto done */ MIPS32_NOP, /* nop */ /* cont: */ MIPS32_ADDI(6, 6, NEG16(1)), /* addi, $a2, $a2, -1 ; numwrites-- */ MIPS32_BNE(6, 0, 5), /* bne $a2, $zero, cont2 ; if (numwrite != 0) goto cont2 */ MIPS32_NOP, /* nop */ MIPS32_LUI(9, 0), /* lui $t1, 0 */ MIPS32_ORI(9, 9, 0x80), /* ori $t1, $t1, 0x80 ; out = 0x80 */ MIPS32_B(4), /* b done ; goto done */ MIPS32_NOP, /* nop */ /* cont2: */ MIPS32_ADDI(5, 5, 2), /* addi $a0, $a0, 2 ; daddr += 2 */ MIPS32_B(NEG16(33)), /* b start ; goto start */ MIPS32_NOP, /* nop */ /* done: */ MIPS32_SDBBP, /* sdbbp ; break(); */ }; mips32_info.common_magic = MIPS32_COMMON_MAGIC; mips32_info.isa_mode = MIPS32_ISA_MIPS32; int target_code_size = 0; const uint32_t *target_code_src = NULL; switch (bank->bus_width) { case 2: /* Check for DQ5 support */ if (cfi_info->status_poll_mask & (1 << 5)) { target_code_src = mips_word_16_code; target_code_size = sizeof(mips_word_16_code); } else { LOG_ERROR("Need DQ5 support"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; /* target_code_src = mips_word_16_code_dq7only; */ /* target_code_size = sizeof(mips_word_16_code_dq7only); */ } break; default: LOG_ERROR("Unsupported bank buswidth %d, can't do block memory writes", bank->bus_width); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* flash write code */ uint8_t *target_code; /* convert bus-width dependent algorithm code to correct endianness */ target_code = malloc(target_code_size); if (target_code == NULL) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } cfi_fix_code_endian(target, target_code, target_code_src, target_code_size / 4); /* allocate working area */ retval = target_alloc_working_area(target, target_code_size, &write_algorithm); if (retval != ERROR_OK) { free(target_code); return retval; } /* write algorithm code to working area */ retval = target_write_buffer(target, write_algorithm->address, target_code_size, target_code); if (retval != ERROR_OK) { free(target_code); return retval; } free(target_code); /* the following code still assumes target code is fixed 24*4 bytes */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; if (buffer_size <= 256) { /* we already allocated the writing code, but failed to get a * buffer, free the algorithm */ target_free_working_area(target, write_algorithm); LOG_WARNING( "not enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } ; init_reg_param(®_params[0], "a0", 32, PARAM_OUT); init_reg_param(®_params[1], "a1", 32, PARAM_OUT); init_reg_param(®_params[2], "a2", 32, PARAM_OUT); init_reg_param(®_params[3], "a3", 32, PARAM_OUT); init_reg_param(®_params[4], "t0", 32, PARAM_OUT); init_reg_param(®_params[5], "t1", 32, PARAM_IN); init_reg_param(®_params[6], "t4", 32, PARAM_OUT); init_reg_param(®_params[7], "t5", 32, PARAM_OUT); init_reg_param(®_params[8], "t6", 32, PARAM_OUT); init_reg_param(®_params[9], "t7", 32, PARAM_OUT); while (count > 0) { uint32_t thisrun_count = (count > buffer_size) ? buffer_size : count; retval = target_write_buffer(target, source->address, thisrun_count, buffer); if (retval != ERROR_OK) break; buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, address); buf_set_u32(reg_params[2].value, 0, 32, thisrun_count / bank->bus_width); buf_set_u32(reg_params[3].value, 0, 32, cfi_command_val(bank, 0xA0)); buf_set_u32(reg_params[4].value, 0, 32, cfi_command_val(bank, 0x80)); buf_set_u32(reg_params[6].value, 0, 32, flash_address(bank, 0, pri_ext->_unlock1)); buf_set_u32(reg_params[7].value, 0, 32, 0xaaaaaaaa); buf_set_u32(reg_params[8].value, 0, 32, flash_address(bank, 0, pri_ext->_unlock2)); buf_set_u32(reg_params[9].value, 0, 32, 0x55555555); retval = target_run_algorithm(target, 0, NULL, 10, reg_params, write_algorithm->address, write_algorithm->address + ((target_code_size) - 4), 10000, &mips32_info); if (retval != ERROR_OK) break; status = buf_get_u32(reg_params[5].value, 0, 32); if (status != 0x80) { LOG_ERROR("flash write block failed status: 0x%" PRIx32, status); retval = ERROR_FLASH_OPERATION_FAILED; break; } buffer += thisrun_count; address += thisrun_count; count -= thisrun_count; } target_free_all_working_areas(target); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); destroy_reg_param(®_params[5]); destroy_reg_param(®_params[6]); destroy_reg_param(®_params[7]); destroy_reg_param(®_params[8]); destroy_reg_param(®_params[9]); return retval; } static int cfi_spansion_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t address, uint32_t count) { struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; struct target *target = bank->target; struct reg_param reg_params[10]; void *arm_algo; struct arm_algorithm armv4_5_algo; struct armv7m_algorithm armv7m_algo; struct working_area *write_algorithm; struct working_area *source; uint32_t buffer_size = 32768; uint32_t status; int retval = ERROR_OK; /* input parameters - * R0 = source address * R1 = destination address * R2 = number of writes * R3 = flash write command * R4 = constant to mask DQ7 bits (also used for Dq5 with shift) * output parameters - * R5 = 0x80 ok 0x00 bad * temp registers - * R6 = value read from flash to test status * R7 = holding register * unlock registers - * R8 = unlock1_addr * R9 = unlock1_cmd * R10 = unlock2_addr * R11 = unlock2_cmd */ /* see contib/loaders/flash/armv4_5_cfi_span_32.s for src */ static const uint32_t armv4_5_word_32_code[] = { /* 00008100 : */ 0xe4905004, /* ldr r5, [r0], #4 */ 0xe5889000, /* str r9, [r8] */ 0xe58ab000, /* str r11, [r10] */ 0xe5883000, /* str r3, [r8] */ 0xe5815000, /* str r5, [r1] */ 0xe1a00000, /* nop */ /* 00008110 : */ 0xe5916000, /* ldr r6, [r1] */ 0xe0257006, /* eor r7, r5, r6 */ 0xe0147007, /* ands r7, r4, r7 */ 0x0a000007, /* beq 8140 ; b if DQ7 == Data7 */ 0xe0166124, /* ands r6, r6, r4, lsr #2 */ 0x0afffff9, /* beq 8110 ; b if DQ5 low */ 0xe5916000, /* ldr r6, [r1] */ 0xe0257006, /* eor r7, r5, r6 */ 0xe0147007, /* ands r7, r4, r7 */ 0x0a000001, /* beq 8140 ; b if DQ7 == Data7 */ 0xe3a05000, /* mov r5, #0 ; 0x0 - return 0x00, error */ 0x1a000004, /* bne 8154 */ /* 00008140 : */ 0xe2522001, /* subs r2, r2, #1 ; 0x1 */ 0x03a05080, /* moveq r5, #128 ; 0x80 */ 0x0a000001, /* beq 8154 */ 0xe2811004, /* add r1, r1, #4 ; 0x4 */ 0xeaffffe8, /* b 8100 */ /* 00008154 : */ 0xeafffffe /* b 8154 */ }; /* see contib/loaders/flash/armv4_5_cfi_span_16.s for src */ static const uint32_t armv4_5_word_16_code[] = { /* 00008158 : */ 0xe0d050b2, /* ldrh r5, [r0], #2 */ 0xe1c890b0, /* strh r9, [r8] */ 0xe1cab0b0, /* strh r11, [r10] */ 0xe1c830b0, /* strh r3, [r8] */ 0xe1c150b0, /* strh r5, [r1] */ 0xe1a00000, /* nop (mov r0,r0) */ /* 00008168 : */ 0xe1d160b0, /* ldrh r6, [r1] */ 0xe0257006, /* eor r7, r5, r6 */ 0xe0147007, /* ands r7, r4, r7 */ 0x0a000007, /* beq 8198 */ 0xe0166124, /* ands r6, r6, r4, lsr #2 */ 0x0afffff9, /* beq 8168 */ 0xe1d160b0, /* ldrh r6, [r1] */ 0xe0257006, /* eor r7, r5, r6 */ 0xe0147007, /* ands r7, r4, r7 */ 0x0a000001, /* beq 8198 */ 0xe3a05000, /* mov r5, #0 ; 0x0 */ 0x1a000004, /* bne 81ac */ /* 00008198 : */ 0xe2522001, /* subs r2, r2, #1 ; 0x1 */ 0x03a05080, /* moveq r5, #128 ; 0x80 */ 0x0a000001, /* beq 81ac */ 0xe2811002, /* add r1, r1, #2 ; 0x2 */ 0xeaffffe8, /* b 8158 */ /* 000081ac : */ 0xeafffffe /* b 81ac */ }; /* see contib/loaders/flash/armv7m_cfi_span_16.s for src */ static const uint32_t armv7m_word_16_code[] = { 0x5B02F830, 0x9000F8A8, 0xB000F8AA, 0x3000F8A8, 0xBF00800D, 0xEA85880E, 0x40270706, 0xEA16D00A, 0xD0F70694, 0xEA85880E, 0x40270706, 0xF04FD002, 0xD1070500, 0xD0023A01, 0x0102F101, 0xF04FE7E0, 0xE7FF0580, 0x0000BE00 }; /* see contib/loaders/flash/armv4_5_cfi_span_16_dq7.s for src */ static const uint32_t armv4_5_word_16_code_dq7only[] = { /* : */ 0xe0d050b2, /* ldrh r5, [r0], #2 */ 0xe1c890b0, /* strh r9, [r8] */ 0xe1cab0b0, /* strh r11, [r10] */ 0xe1c830b0, /* strh r3, [r8] */ 0xe1c150b0, /* strh r5, [r1] */ 0xe1a00000, /* nop (mov r0,r0) */ /* : */ 0xe1d160b0, /* ldrh r6, [r1] */ 0xe0257006, /* eor r7, r5, r6 */ 0xe2177080, /* ands r7, #0x80 */ 0x1afffffb, /* bne 8168 */ /* */ 0xe2522001, /* subs r2, r2, #1 ; 0x1 */ 0x03a05080, /* moveq r5, #128 ; 0x80 */ 0x0a000001, /* beq 81ac */ 0xe2811002, /* add r1, r1, #2 ; 0x2 */ 0xeafffff0, /* b 8158 */ /* 000081ac : */ 0xeafffffe /* b 81ac */ }; /* see contib/loaders/flash/armv4_5_cfi_span_8.s for src */ static const uint32_t armv4_5_word_8_code[] = { /* 000081b0 : */ 0xe4d05001, /* ldrb r5, [r0], #1 */ 0xe5c89000, /* strb r9, [r8] */ 0xe5cab000, /* strb r11, [r10] */ 0xe5c83000, /* strb r3, [r8] */ 0xe5c15000, /* strb r5, [r1] */ 0xe1a00000, /* nop (mov r0,r0) */ /* 000081c0 : */ 0xe5d16000, /* ldrb r6, [r1] */ 0xe0257006, /* eor r7, r5, r6 */ 0xe0147007, /* ands r7, r4, r7 */ 0x0a000007, /* beq 81f0 */ 0xe0166124, /* ands r6, r6, r4, lsr #2 */ 0x0afffff9, /* beq 81c0 */ 0xe5d16000, /* ldrb r6, [r1] */ 0xe0257006, /* eor r7, r5, r6 */ 0xe0147007, /* ands r7, r4, r7 */ 0x0a000001, /* beq 81f0 */ 0xe3a05000, /* mov r5, #0 ; 0x0 */ 0x1a000004, /* bne 8204 */ /* 000081f0 : */ 0xe2522001, /* subs r2, r2, #1 ; 0x1 */ 0x03a05080, /* moveq r5, #128 ; 0x80 */ 0x0a000001, /* beq 8204 */ 0xe2811001, /* add r1, r1, #1 ; 0x1 */ 0xeaffffe8, /* b 81b0 */ /* 00008204 : */ 0xeafffffe /* b 8204 */ }; if (strncmp(target_type_name(target), "mips_m4k", 8) == 0) return cfi_spansion_write_block_mips(bank, buffer, address, count); if (is_armv7m(target_to_armv7m(target))) { /* armv7m target */ armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC; armv7m_algo.core_mode = ARM_MODE_THREAD; arm_algo = &armv7m_algo; } else if (is_arm(target_to_arm(target))) { /* All other ARM CPUs have 32 bit instructions */ armv4_5_algo.common_magic = ARM_COMMON_MAGIC; armv4_5_algo.core_mode = ARM_MODE_SVC; armv4_5_algo.core_state = ARM_STATE_ARM; arm_algo = &armv4_5_algo; } else { LOG_ERROR("Unknown architecture"); return ERROR_FAIL; } int target_code_size = 0; const uint32_t *target_code_src = NULL; switch (bank->bus_width) { case 1: if (is_armv7m(target_to_armv7m(target))) { LOG_ERROR("Unknown ARM architecture"); return ERROR_FAIL; } target_code_src = armv4_5_word_8_code; target_code_size = sizeof(armv4_5_word_8_code); break; case 2: /* Check for DQ5 support */ if (cfi_info->status_poll_mask & (1 << 5)) { if (is_armv7m(target_to_armv7m(target))) { /* armv7m target */ target_code_src = armv7m_word_16_code; target_code_size = sizeof(armv7m_word_16_code); } else { /* armv4_5 target */ target_code_src = armv4_5_word_16_code; target_code_size = sizeof(armv4_5_word_16_code); } } else { /* No DQ5 support. Use DQ7 DATA# polling only. */ if (is_armv7m(target_to_armv7m(target))) { LOG_ERROR("Unknown ARM architecture"); return ERROR_FAIL; } target_code_src = armv4_5_word_16_code_dq7only; target_code_size = sizeof(armv4_5_word_16_code_dq7only); } break; case 4: if (is_armv7m(target_to_armv7m(target))) { LOG_ERROR("Unknown ARM architecture"); return ERROR_FAIL; } target_code_src = armv4_5_word_32_code; target_code_size = sizeof(armv4_5_word_32_code); break; default: LOG_ERROR("Unsupported bank buswidth %d, can't do block memory writes", bank->bus_width); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* flash write code */ uint8_t *target_code; /* convert bus-width dependent algorithm code to correct endianness */ target_code = malloc(target_code_size); if (target_code == NULL) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } cfi_fix_code_endian(target, target_code, target_code_src, target_code_size / 4); /* allocate working area */ retval = target_alloc_working_area(target, target_code_size, &write_algorithm); if (retval != ERROR_OK) { free(target_code); return retval; } /* write algorithm code to working area */ retval = target_write_buffer(target, write_algorithm->address, target_code_size, target_code); if (retval != ERROR_OK) { free(target_code); return retval; } free(target_code); /* the following code still assumes target code is fixed 24*4 bytes */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; if (buffer_size <= 256) { /* we already allocated the writing code, but failed to get a * buffer, free the algorithm */ target_free_working_area(target, write_algorithm); LOG_WARNING( "not enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } ; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_OUT); init_reg_param(®_params[4], "r4", 32, PARAM_OUT); init_reg_param(®_params[5], "r5", 32, PARAM_IN); init_reg_param(®_params[6], "r8", 32, PARAM_OUT); init_reg_param(®_params[7], "r9", 32, PARAM_OUT); init_reg_param(®_params[8], "r10", 32, PARAM_OUT); init_reg_param(®_params[9], "r11", 32, PARAM_OUT); while (count > 0) { uint32_t thisrun_count = (count > buffer_size) ? buffer_size : count; retval = target_write_buffer(target, source->address, thisrun_count, buffer); if (retval != ERROR_OK) break; buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, address); buf_set_u32(reg_params[2].value, 0, 32, thisrun_count / bank->bus_width); buf_set_u32(reg_params[3].value, 0, 32, cfi_command_val(bank, 0xA0)); buf_set_u32(reg_params[4].value, 0, 32, cfi_command_val(bank, 0x80)); buf_set_u32(reg_params[6].value, 0, 32, flash_address(bank, 0, pri_ext->_unlock1)); buf_set_u32(reg_params[7].value, 0, 32, 0xaaaaaaaa); buf_set_u32(reg_params[8].value, 0, 32, flash_address(bank, 0, pri_ext->_unlock2)); buf_set_u32(reg_params[9].value, 0, 32, 0x55555555); retval = target_run_algorithm(target, 0, NULL, 10, reg_params, write_algorithm->address, write_algorithm->address + ((target_code_size) - 4), 10000, arm_algo); if (retval != ERROR_OK) break; status = buf_get_u32(reg_params[5].value, 0, 32); if (status != 0x80) { LOG_ERROR("flash write block failed status: 0x%" PRIx32, status); retval = ERROR_FLASH_OPERATION_FAILED; break; } buffer += thisrun_count; address += thisrun_count; count -= thisrun_count; } target_free_all_working_areas(target); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); destroy_reg_param(®_params[5]); destroy_reg_param(®_params[6]); destroy_reg_param(®_params[7]); destroy_reg_param(®_params[8]); destroy_reg_param(®_params[9]); return retval; } static int cfi_intel_write_word(struct flash_bank *bank, uint8_t *word, uint32_t address) { int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct target *target = bank->target; cfi_intel_clear_status_register(bank); retval = cfi_send_command(bank, 0x40, address); if (retval != ERROR_OK) return retval; retval = target_write_memory(target, address, bank->bus_width, 1, word); if (retval != ERROR_OK) return retval; uint8_t status; retval = cfi_intel_wait_status_busy(bank, cfi_info->word_write_timeout, &status); if (retval != 0x80) { retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; LOG_ERROR("couldn't write word at base 0x%" PRIx32 ", address 0x%" PRIx32, bank->base, address); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } static int cfi_intel_write_words(struct flash_bank *bank, uint8_t *word, uint32_t wordcount, uint32_t address) { int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct target *target = bank->target; /* Calculate buffer size and boundary mask * buffersize is (buffer size per chip) * (number of chips) * bufferwsize is buffersize in words */ uint32_t buffersize = (1UL << cfi_info->max_buf_write_size) * (bank->bus_width / bank->chip_width); uint32_t buffermask = buffersize-1; uint32_t bufferwsize = buffersize / bank->bus_width; /* Check for valid range */ if (address & buffermask) { LOG_ERROR("Write address at base 0x%" PRIx32 ", address 0x%" PRIx32 " not aligned to 2^%d boundary", bank->base, address, cfi_info->max_buf_write_size); return ERROR_FLASH_OPERATION_FAILED; } /* Check for valid size */ if (wordcount > bufferwsize) { LOG_ERROR("Number of data words %" PRId32 " exceeds available buffersize %" PRId32, wordcount, buffersize); return ERROR_FLASH_OPERATION_FAILED; } /* Write to flash buffer */ cfi_intel_clear_status_register(bank); /* Initiate buffer operation _*/ retval = cfi_send_command(bank, 0xe8, address); if (retval != ERROR_OK) return retval; uint8_t status; retval = cfi_intel_wait_status_busy(bank, cfi_info->buf_write_timeout, &status); if (retval != ERROR_OK) return retval; if (status != 0x80) { retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; LOG_ERROR( "couldn't start buffer write operation at base 0x%" PRIx32 ", address 0x%" PRIx32, bank->base, address); return ERROR_FLASH_OPERATION_FAILED; } /* Write buffer wordcount-1 and data words */ retval = cfi_send_command(bank, bufferwsize-1, address); if (retval != ERROR_OK) return retval; retval = target_write_memory(target, address, bank->bus_width, bufferwsize, word); if (retval != ERROR_OK) return retval; /* Commit write operation */ retval = cfi_send_command(bank, 0xd0, address); if (retval != ERROR_OK) return retval; retval = cfi_intel_wait_status_busy(bank, cfi_info->buf_write_timeout, &status); if (retval != ERROR_OK) return retval; if (status != 0x80) { retval = cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; LOG_ERROR("Buffer write at base 0x%" PRIx32 ", address 0x%" PRIx32 " failed.", bank->base, address); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } static int cfi_spansion_write_word(struct flash_bank *bank, uint8_t *word, uint32_t address) { int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; struct target *target = bank->target; retval = cfi_send_command(bank, 0xaa, flash_address(bank, 0, pri_ext->_unlock1)); if (retval != ERROR_OK) return retval; retval = cfi_send_command(bank, 0x55, flash_address(bank, 0, pri_ext->_unlock2)); if (retval != ERROR_OK) return retval; retval = cfi_send_command(bank, 0xa0, flash_address(bank, 0, pri_ext->_unlock1)); if (retval != ERROR_OK) return retval; retval = target_write_memory(target, address, bank->bus_width, 1, word); if (retval != ERROR_OK) return retval; if (cfi_spansion_wait_status_busy(bank, cfi_info->word_write_timeout) != ERROR_OK) { retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; LOG_ERROR("couldn't write word at base 0x%" PRIx32 ", address 0x%" PRIx32, bank->base, address); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } static int cfi_spansion_write_words(struct flash_bank *bank, uint8_t *word, uint32_t wordcount, uint32_t address) { int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct target *target = bank->target; struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; /* Calculate buffer size and boundary mask * buffersize is (buffer size per chip) * (number of chips) * bufferwsize is buffersize in words */ uint32_t buffersize = (1UL << cfi_info->max_buf_write_size) * (bank->bus_width / bank->chip_width); uint32_t buffermask = buffersize-1; uint32_t bufferwsize = buffersize / bank->bus_width; /* Check for valid range */ if (address & buffermask) { LOG_ERROR("Write address at base 0x%" PRIx32 ", address 0x%" PRIx32 " not aligned to 2^%d boundary", bank->base, address, cfi_info->max_buf_write_size); return ERROR_FLASH_OPERATION_FAILED; } /* Check for valid size */ if (wordcount > bufferwsize) { LOG_ERROR("Number of data words %" PRId32 " exceeds available buffersize %" PRId32, wordcount, buffersize); return ERROR_FLASH_OPERATION_FAILED; } /* Unlock */ retval = cfi_send_command(bank, 0xaa, flash_address(bank, 0, pri_ext->_unlock1)); if (retval != ERROR_OK) return retval; retval = cfi_send_command(bank, 0x55, flash_address(bank, 0, pri_ext->_unlock2)); if (retval != ERROR_OK) return retval; /* Buffer load command */ retval = cfi_send_command(bank, 0x25, address); if (retval != ERROR_OK) return retval; /* Write buffer wordcount-1 and data words */ retval = cfi_send_command(bank, bufferwsize-1, address); if (retval != ERROR_OK) return retval; retval = target_write_memory(target, address, bank->bus_width, bufferwsize, word); if (retval != ERROR_OK) return retval; /* Commit write operation */ retval = cfi_send_command(bank, 0x29, address); if (retval != ERROR_OK) return retval; if (cfi_spansion_wait_status_busy(bank, cfi_info->buf_write_timeout) != ERROR_OK) { retval = cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0)); if (retval != ERROR_OK) return retval; LOG_ERROR("couldn't write block at base 0x%" PRIx32 ", address 0x%" PRIx32 ", size 0x%" PRIx32, bank->base, address, bufferwsize); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } static int cfi_write_word(struct flash_bank *bank, uint8_t *word, uint32_t address) { struct cfi_flash_bank *cfi_info = bank->driver_priv; switch (cfi_info->pri_id) { case 1: case 3: return cfi_intel_write_word(bank, word, address); break; case 2: return cfi_spansion_write_word(bank, word, address); break; default: LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); break; } return ERROR_FLASH_OPERATION_FAILED; } static int cfi_write_words(struct flash_bank *bank, uint8_t *word, uint32_t wordcount, uint32_t address) { struct cfi_flash_bank *cfi_info = bank->driver_priv; if (cfi_info->buf_write_timeout_typ == 0) { /* buffer writes are not supported */ LOG_DEBUG("Buffer Writes Not Supported"); return ERROR_FLASH_OPER_UNSUPPORTED; } switch (cfi_info->pri_id) { case 1: case 3: return cfi_intel_write_words(bank, word, wordcount, address); break; case 2: return cfi_spansion_write_words(bank, word, wordcount, address); break; default: LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); break; } return ERROR_FLASH_OPERATION_FAILED; } static int cfi_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct cfi_flash_bank *cfi_info = bank->driver_priv; struct target *target = bank->target; uint32_t address = bank->base + offset; uint32_t read_p; int align; /* number of unaligned bytes */ uint8_t current_word[CFI_MAX_BUS_WIDTH]; int i; int retval; LOG_DEBUG("reading buffer of %i byte at 0x%8.8x", (int)count, (unsigned)offset); if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset + count > bank->size) return ERROR_FLASH_DST_OUT_OF_BANK; if (cfi_info->qry[0] != 'Q') return ERROR_FLASH_BANK_NOT_PROBED; /* start at the first byte of the first word (bus_width size) */ read_p = address & ~(bank->bus_width - 1); align = address - read_p; if (align != 0) { LOG_INFO("Fixup %d unaligned read head bytes", align); /* read a complete word from flash */ retval = target_read_memory(target, read_p, bank->bus_width, 1, current_word); if (retval != ERROR_OK) return retval; /* take only bytes we need */ for (i = align; (i < bank->bus_width) && (count > 0); i++, count--) *buffer++ = current_word[i]; read_p += bank->bus_width; } align = count / bank->bus_width; if (align) { retval = target_read_memory(target, read_p, bank->bus_width, align, buffer); if (retval != ERROR_OK) return retval; read_p += align * bank->bus_width; buffer += align * bank->bus_width; count -= align * bank->bus_width; } if (count) { LOG_INFO("Fixup %d unaligned read tail bytes", count); /* read a complete word from flash */ retval = target_read_memory(target, read_p, bank->bus_width, 1, current_word); if (retval != ERROR_OK) return retval; /* take only bytes we need */ for (i = 0; (i < bank->bus_width) && (count > 0); i++, count--) *buffer++ = current_word[i]; } return ERROR_OK; } static int cfi_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct cfi_flash_bank *cfi_info = bank->driver_priv; struct target *target = bank->target; uint32_t address = bank->base + offset; /* address of first byte to be programmed */ uint32_t write_p; int align; /* number of unaligned bytes */ int blk_count; /* number of bus_width bytes for block copy */ uint8_t current_word[CFI_MAX_BUS_WIDTH * 4]; /* word (bus_width size) currently being *programmed */ int i; int retval; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset + count > bank->size) return ERROR_FLASH_DST_OUT_OF_BANK; if (cfi_info->qry[0] != 'Q') return ERROR_FLASH_BANK_NOT_PROBED; /* start at the first byte of the first word (bus_width size) */ write_p = address & ~(bank->bus_width - 1); align = address - write_p; if (align != 0) { LOG_INFO("Fixup %d unaligned head bytes", align); /* read a complete word from flash */ retval = target_read_memory(target, write_p, bank->bus_width, 1, current_word); if (retval != ERROR_OK) return retval; /* replace only bytes that must be written */ for (i = align; (i < bank->bus_width) && (count > 0); i++, count--) current_word[i] = *buffer++; retval = cfi_write_word(bank, current_word, write_p); if (retval != ERROR_OK) return retval; write_p += bank->bus_width; } /* handle blocks of bus_size aligned bytes */ blk_count = count & ~(bank->bus_width - 1); /* round down, leave tail bytes */ switch (cfi_info->pri_id) { /* try block writes (fails without working area) */ case 1: case 3: retval = cfi_intel_write_block(bank, buffer, write_p, blk_count); break; case 2: retval = cfi_spansion_write_block(bank, buffer, write_p, blk_count); break; default: LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); retval = ERROR_FLASH_OPERATION_FAILED; break; } if (retval == ERROR_OK) { /* Increment pointers and decrease count on succesful block write */ buffer += blk_count; write_p += blk_count; count -= blk_count; } else { if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* Calculate buffer size and boundary mask * buffersize is (buffer size per chip) * (number of chips) * bufferwsize is buffersize in words */ uint32_t buffersize = (1UL << cfi_info->max_buf_write_size) * (bank->bus_width / bank->chip_width); uint32_t buffermask = buffersize-1; uint32_t bufferwsize = buffersize / bank->bus_width; /* fall back to memory writes */ while (count >= (uint32_t)bank->bus_width) { int fallback; if ((write_p & 0xff) == 0) { LOG_INFO("Programming at 0x%08" PRIx32 ", count 0x%08" PRIx32 " bytes remaining", write_p, count); } fallback = 1; if ((bufferwsize > 0) && (count >= buffersize) && !(write_p & buffermask)) { retval = cfi_write_words(bank, buffer, bufferwsize, write_p); if (retval == ERROR_OK) { buffer += buffersize; write_p += buffersize; count -= buffersize; fallback = 0; } else if (retval != ERROR_FLASH_OPER_UNSUPPORTED) return retval; } /* try the slow way? */ if (fallback) { for (i = 0; i < bank->bus_width; i++) current_word[i] = *buffer++; retval = cfi_write_word(bank, current_word, write_p); if (retval != ERROR_OK) return retval; write_p += bank->bus_width; count -= bank->bus_width; } } } else return retval; } /* return to read array mode, so we can read from flash again for padding */ retval = cfi_reset(bank); if (retval != ERROR_OK) return retval; /* handle unaligned tail bytes */ if (count > 0) { LOG_INFO("Fixup %" PRId32 " unaligned tail bytes", count); /* read a complete word from flash */ retval = target_read_memory(target, write_p, bank->bus_width, 1, current_word); if (retval != ERROR_OK) return retval; /* replace only bytes that must be written */ for (i = 0; (i < bank->bus_width) && (count > 0); i++, count--) current_word[i] = *buffer++; retval = cfi_write_word(bank, current_word, write_p); if (retval != ERROR_OK) return retval; } /* return to read array mode */ return cfi_reset(bank); } static void cfi_fixup_reversed_erase_regions(struct flash_bank *bank, void *param) { (void) param; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; pri_ext->_reversed_geometry = 1; } static void cfi_fixup_0002_erase_regions(struct flash_bank *bank, void *param) { int i; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; (void) param; if ((pri_ext->_reversed_geometry) || (pri_ext->TopBottom == 3)) { LOG_DEBUG("swapping reversed erase region information on cmdset 0002 device"); for (i = 0; i < cfi_info->num_erase_regions / 2; i++) { int j = (cfi_info->num_erase_regions - 1) - i; uint32_t swap; swap = cfi_info->erase_region_info[i]; cfi_info->erase_region_info[i] = cfi_info->erase_region_info[j]; cfi_info->erase_region_info[j] = swap; } } } static void cfi_fixup_0002_unlock_addresses(struct flash_bank *bank, void *param) { struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; struct cfi_unlock_addresses *unlock_addresses = param; pri_ext->_unlock1 = unlock_addresses->unlock1; pri_ext->_unlock2 = unlock_addresses->unlock2; } static int cfi_query_string(struct flash_bank *bank, int address) { struct cfi_flash_bank *cfi_info = bank->driver_priv; int retval; retval = cfi_send_command(bank, 0x98, flash_address(bank, 0, address)); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, 0x10, &cfi_info->qry[0]); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, 0x11, &cfi_info->qry[1]); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, 0x12, &cfi_info->qry[2]); if (retval != ERROR_OK) return retval; LOG_DEBUG("CFI qry returned: 0x%2.2x 0x%2.2x 0x%2.2x", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2]); if ((cfi_info->qry[0] != 'Q') || (cfi_info->qry[1] != 'R') || (cfi_info->qry[2] != 'Y')) { retval = cfi_reset(bank); if (retval != ERROR_OK) return retval; LOG_ERROR("Could not probe bank: no QRY"); return ERROR_FLASH_BANK_INVALID; } return ERROR_OK; } static int cfi_probe(struct flash_bank *bank) { struct cfi_flash_bank *cfi_info = bank->driver_priv; struct target *target = bank->target; int num_sectors = 0; int i; int sector = 0; uint32_t unlock1 = 0x555; uint32_t unlock2 = 0x2aa; int retval; uint8_t value_buf0[CFI_MAX_BUS_WIDTH], value_buf1[CFI_MAX_BUS_WIDTH]; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } cfi_info->probed = 0; cfi_info->num_erase_regions = 0; if (bank->sectors) { free(bank->sectors); bank->sectors = NULL; } if (cfi_info->erase_region_info) { free(cfi_info->erase_region_info); cfi_info->erase_region_info = NULL; } /* JEDEC standard JESD21C uses 0x5555 and 0x2aaa as unlock addresses, * while CFI compatible AMD/Spansion flashes use 0x555 and 0x2aa */ if (cfi_info->jedec_probe) { unlock1 = 0x5555; unlock2 = 0x2aaa; } /* switch to read identifier codes mode ("AUTOSELECT") */ retval = cfi_send_command(bank, 0xaa, flash_address(bank, 0, unlock1)); if (retval != ERROR_OK) return retval; retval = cfi_send_command(bank, 0x55, flash_address(bank, 0, unlock2)); if (retval != ERROR_OK) return retval; retval = cfi_send_command(bank, 0x90, flash_address(bank, 0, unlock1)); if (retval != ERROR_OK) return retval; retval = target_read_memory(target, flash_address(bank, 0, 0x00), bank->bus_width, 1, value_buf0); if (retval != ERROR_OK) return retval; retval = target_read_memory(target, flash_address(bank, 0, 0x01), bank->bus_width, 1, value_buf1); if (retval != ERROR_OK) return retval; switch (bank->chip_width) { case 1: cfi_info->manufacturer = *value_buf0; cfi_info->device_id = *value_buf1; break; case 2: cfi_info->manufacturer = target_buffer_get_u16(target, value_buf0); cfi_info->device_id = target_buffer_get_u16(target, value_buf1); break; case 4: cfi_info->manufacturer = target_buffer_get_u32(target, value_buf0); cfi_info->device_id = target_buffer_get_u32(target, value_buf1); break; default: LOG_ERROR("Unsupported bank chipwidth %d, can't probe memory", bank->chip_width); return ERROR_FLASH_OPERATION_FAILED; } LOG_INFO("Flash Manufacturer/Device: 0x%04x 0x%04x", cfi_info->manufacturer, cfi_info->device_id); /* switch back to read array mode */ retval = cfi_reset(bank); if (retval != ERROR_OK) return retval; /* check device/manufacturer ID for known non-CFI flashes. */ cfi_fixup_non_cfi(bank); /* query only if this is a CFI compatible flash, * otherwise the relevant info has already been filled in */ if (cfi_info->not_cfi == 0) { /* enter CFI query mode * according to JEDEC Standard No. 68.01, * a single bus sequence with address = 0x55, data = 0x98 should put * the device into CFI query mode. * * SST flashes clearly violate this, and we will consider them incompatible for now */ retval = cfi_query_string(bank, 0x55); if (retval != ERROR_OK) { /* * Spansion S29WS-N CFI query fix is to try 0x555 if 0x55 fails. Should * be harmless enough: * * http://www.infradead.org/pipermail/linux-mtd/2005-September/013618.html */ LOG_USER("Try workaround w/0x555 instead of 0x55 to get QRY."); retval = cfi_query_string(bank, 0x555); } if (retval != ERROR_OK) return retval; retval = cfi_query_u16(bank, 0, 0x13, &cfi_info->pri_id); if (retval != ERROR_OK) return retval; retval = cfi_query_u16(bank, 0, 0x15, &cfi_info->pri_addr); if (retval != ERROR_OK) return retval; retval = cfi_query_u16(bank, 0, 0x17, &cfi_info->alt_id); if (retval != ERROR_OK) return retval; retval = cfi_query_u16(bank, 0, 0x19, &cfi_info->alt_addr); if (retval != ERROR_OK) return retval; LOG_DEBUG("qry: '%c%c%c', pri_id: 0x%4.4x, pri_addr: 0x%4.4x, alt_id: " "0x%4.4x, alt_addr: 0x%4.4x", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2], cfi_info->pri_id, cfi_info->pri_addr, cfi_info->alt_id, cfi_info->alt_addr); retval = cfi_query_u8(bank, 0, 0x1b, &cfi_info->vcc_min); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, 0x1c, &cfi_info->vcc_max); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, 0x1d, &cfi_info->vpp_min); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, 0x1e, &cfi_info->vpp_max); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, 0x1f, &cfi_info->word_write_timeout_typ); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, 0x20, &cfi_info->buf_write_timeout_typ); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, 0x21, &cfi_info->block_erase_timeout_typ); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, 0x22, &cfi_info->chip_erase_timeout_typ); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, 0x23, &cfi_info->word_write_timeout_max); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, 0x24, &cfi_info->buf_write_timeout_max); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, 0x25, &cfi_info->block_erase_timeout_max); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, 0x26, &cfi_info->chip_erase_timeout_max); if (retval != ERROR_OK) return retval; uint8_t data; retval = cfi_query_u8(bank, 0, 0x27, &data); if (retval != ERROR_OK) return retval; cfi_info->dev_size = 1 << data; retval = cfi_query_u16(bank, 0, 0x28, &cfi_info->interface_desc); if (retval != ERROR_OK) return retval; retval = cfi_query_u16(bank, 0, 0x2a, &cfi_info->max_buf_write_size); if (retval != ERROR_OK) return retval; retval = cfi_query_u8(bank, 0, 0x2c, &cfi_info->num_erase_regions); if (retval != ERROR_OK) return retval; LOG_DEBUG("size: 0x%" PRIx32 ", interface desc: %i, max buffer write size: 0x%x", cfi_info->dev_size, cfi_info->interface_desc, (1 << cfi_info->max_buf_write_size)); if (cfi_info->num_erase_regions) { cfi_info->erase_region_info = malloc(sizeof(*cfi_info->erase_region_info) * cfi_info->num_erase_regions); for (i = 0; i < cfi_info->num_erase_regions; i++) { retval = cfi_query_u32(bank, 0, 0x2d + (4 * i), &cfi_info->erase_region_info[i]); if (retval != ERROR_OK) return retval; LOG_DEBUG( "erase region[%i]: %" PRIu32 " blocks of size 0x%" PRIx32 "", i, (cfi_info->erase_region_info[i] & 0xffff) + 1, (cfi_info->erase_region_info[i] >> 16) * 256); } } else cfi_info->erase_region_info = NULL; /* We need to read the primary algorithm extended query table before calculating * the sector layout to be able to apply fixups */ switch (cfi_info->pri_id) { /* Intel command set (standard and extended) */ case 0x0001: case 0x0003: cfi_read_intel_pri_ext(bank); break; /* AMD/Spansion, Atmel, ... command set */ case 0x0002: cfi_info->status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7; /* *default *for *all *CFI *flashs **/ cfi_read_0002_pri_ext(bank); break; default: LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); break; } /* return to read array mode * we use both reset commands, as some Intel flashes fail to recognize the 0xF0 command */ retval = cfi_reset(bank); if (retval != ERROR_OK) return retval; } /* end CFI case */ LOG_DEBUG("Vcc min: %x.%x, Vcc max: %x.%x, Vpp min: %u.%x, Vpp max: %u.%x", (cfi_info->vcc_min & 0xf0) >> 4, cfi_info->vcc_min & 0x0f, (cfi_info->vcc_max & 0xf0) >> 4, cfi_info->vcc_max & 0x0f, (cfi_info->vpp_min & 0xf0) >> 4, cfi_info->vpp_min & 0x0f, (cfi_info->vpp_max & 0xf0) >> 4, cfi_info->vpp_max & 0x0f); LOG_DEBUG("typ. word write timeout: %u us, typ. buf write timeout: %u us, " "typ. block erase timeout: %u ms, typ. chip erase timeout: %u ms", 1 << cfi_info->word_write_timeout_typ, 1 << cfi_info->buf_write_timeout_typ, 1 << cfi_info->block_erase_timeout_typ, 1 << cfi_info->chip_erase_timeout_typ); LOG_DEBUG("max. word write timeout: %u us, max. buf write timeout: %u us, " "max. block erase timeout: %u ms, max. chip erase timeout: %u ms", (1 << cfi_info->word_write_timeout_max) * (1 << cfi_info->word_write_timeout_typ), (1 << cfi_info->buf_write_timeout_max) * (1 << cfi_info->buf_write_timeout_typ), (1 << cfi_info->block_erase_timeout_max) * (1 << cfi_info->block_erase_timeout_typ), (1 << cfi_info->chip_erase_timeout_max) * (1 << cfi_info->chip_erase_timeout_typ)); /* convert timeouts to real values in ms */ cfi_info->word_write_timeout = DIV_ROUND_UP((1L << cfi_info->word_write_timeout_typ) * (1L << cfi_info->word_write_timeout_max), 1000); cfi_info->buf_write_timeout = DIV_ROUND_UP((1L << cfi_info->buf_write_timeout_typ) * (1L << cfi_info->buf_write_timeout_max), 1000); cfi_info->block_erase_timeout = (1L << cfi_info->block_erase_timeout_typ) * (1L << cfi_info->block_erase_timeout_max); cfi_info->chip_erase_timeout = (1L << cfi_info->chip_erase_timeout_typ) * (1L << cfi_info->chip_erase_timeout_max); LOG_DEBUG("calculated word write timeout: %u ms, buf write timeout: %u ms, " "block erase timeout: %u ms, chip erase timeout: %u ms", cfi_info->word_write_timeout, cfi_info->buf_write_timeout, cfi_info->block_erase_timeout, cfi_info->chip_erase_timeout); /* apply fixups depending on the primary command set */ switch (cfi_info->pri_id) { /* Intel command set (standard and extended) */ case 0x0001: case 0x0003: cfi_fixup(bank, cfi_0001_fixups); break; /* AMD/Spansion, Atmel, ... command set */ case 0x0002: cfi_fixup(bank, cfi_0002_fixups); break; default: LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); break; } if ((cfi_info->dev_size * bank->bus_width / bank->chip_width) != bank->size) { LOG_WARNING("configuration specifies 0x%" PRIx32 " size, but a 0x%" PRIx32 " size flash was found", bank->size, cfi_info->dev_size); } if (cfi_info->num_erase_regions == 0) { /* a device might have only one erase block, spanning the whole device */ bank->num_sectors = 1; bank->sectors = malloc(sizeof(struct flash_sector)); bank->sectors[sector].offset = 0x0; bank->sectors[sector].size = bank->size; bank->sectors[sector].is_erased = -1; bank->sectors[sector].is_protected = -1; } else { uint32_t offset = 0; for (i = 0; i < cfi_info->num_erase_regions; i++) num_sectors += (cfi_info->erase_region_info[i] & 0xffff) + 1; bank->num_sectors = num_sectors; bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors); for (i = 0; i < cfi_info->num_erase_regions; i++) { uint32_t j; for (j = 0; j < (cfi_info->erase_region_info[i] & 0xffff) + 1; j++) { bank->sectors[sector].offset = offset; bank->sectors[sector].size = ((cfi_info->erase_region_info[i] >> 16) * 256) * bank->bus_width / bank->chip_width; offset += bank->sectors[sector].size; bank->sectors[sector].is_erased = -1; bank->sectors[sector].is_protected = -1; sector++; } } if (offset != (cfi_info->dev_size * bank->bus_width / bank->chip_width)) { LOG_WARNING( "CFI size is 0x%" PRIx32 ", but total sector size is 0x%" PRIx32 "", \ (cfi_info->dev_size * bank->bus_width / bank->chip_width), offset); } } cfi_info->probed = 1; return ERROR_OK; } static int cfi_auto_probe(struct flash_bank *bank) { struct cfi_flash_bank *cfi_info = bank->driver_priv; if (cfi_info->probed) return ERROR_OK; return cfi_probe(bank); } static int cfi_intel_protect_check(struct flash_bank *bank) { int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_intel_pri_ext *pri_ext = cfi_info->pri_ext; int i; /* check if block lock bits are supported on this device */ if (!(pri_ext->blk_status_reg_mask & 0x1)) return ERROR_FLASH_OPERATION_FAILED; retval = cfi_send_command(bank, 0x90, flash_address(bank, 0, 0x55)); if (retval != ERROR_OK) return retval; for (i = 0; i < bank->num_sectors; i++) { uint8_t block_status; retval = cfi_get_u8(bank, i, 0x2, &block_status); if (retval != ERROR_OK) return retval; if (block_status & 1) bank->sectors[i].is_protected = 1; else bank->sectors[i].is_protected = 0; } return cfi_send_command(bank, 0xff, flash_address(bank, 0, 0x0)); } static int cfi_spansion_protect_check(struct flash_bank *bank) { int retval; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct cfi_spansion_pri_ext *pri_ext = cfi_info->pri_ext; int i; retval = cfi_send_command(bank, 0xaa, flash_address(bank, 0, pri_ext->_unlock1)); if (retval != ERROR_OK) return retval; retval = cfi_send_command(bank, 0x55, flash_address(bank, 0, pri_ext->_unlock2)); if (retval != ERROR_OK) return retval; retval = cfi_send_command(bank, 0x90, flash_address(bank, 0, pri_ext->_unlock1)); if (retval != ERROR_OK) return retval; for (i = 0; i < bank->num_sectors; i++) { uint8_t block_status; retval = cfi_get_u8(bank, i, 0x2, &block_status); if (retval != ERROR_OK) return retval; if (block_status & 1) bank->sectors[i].is_protected = 1; else bank->sectors[i].is_protected = 0; } return cfi_send_command(bank, 0xf0, flash_address(bank, 0, 0x0)); } static int cfi_protect_check(struct flash_bank *bank) { struct cfi_flash_bank *cfi_info = bank->driver_priv; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (cfi_info->qry[0] != 'Q') return ERROR_FLASH_BANK_NOT_PROBED; switch (cfi_info->pri_id) { case 1: case 3: return cfi_intel_protect_check(bank); break; case 2: return cfi_spansion_protect_check(bank); break; default: LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); break; } return ERROR_OK; } static int get_cfi_info(struct flash_bank *bank, char *buf, int buf_size) { int printed; struct cfi_flash_bank *cfi_info = bank->driver_priv; if (cfi_info->qry[0] == 0xff) { snprintf(buf, buf_size, "\ncfi flash bank not probed yet\n"); return ERROR_OK; } if (cfi_info->not_cfi == 0) printed = snprintf(buf, buf_size, "\nCFI flash: "); else printed = snprintf(buf, buf_size, "\nnon-CFI flash: "); buf += printed; buf_size -= printed; printed = snprintf(buf, buf_size, "mfr: 0x%4.4x, id:0x%4.4x\n\n", cfi_info->manufacturer, cfi_info->device_id); buf += printed; buf_size -= printed; printed = snprintf(buf, buf_size, "qry: '%c%c%c', pri_id: 0x%4.4x, pri_addr: " "0x%4.4x, alt_id: 0x%4.4x, alt_addr: 0x%4.4x\n", cfi_info->qry[0], cfi_info->qry[1], cfi_info->qry[2], cfi_info->pri_id, cfi_info->pri_addr, cfi_info->alt_id, cfi_info->alt_addr); buf += printed; buf_size -= printed; printed = snprintf(buf, buf_size, "Vcc min: %x.%x, Vcc max: %x.%x, " "Vpp min: %u.%x, Vpp max: %u.%x\n", (cfi_info->vcc_min & 0xf0) >> 4, cfi_info->vcc_min & 0x0f, (cfi_info->vcc_max & 0xf0) >> 4, cfi_info->vcc_max & 0x0f, (cfi_info->vpp_min & 0xf0) >> 4, cfi_info->vpp_min & 0x0f, (cfi_info->vpp_max & 0xf0) >> 4, cfi_info->vpp_max & 0x0f); buf += printed; buf_size -= printed; printed = snprintf(buf, buf_size, "typ. word write timeout: %u us, " "typ. buf write timeout: %u us, " "typ. block erase timeout: %u ms, " "typ. chip erase timeout: %u ms\n", 1 << cfi_info->word_write_timeout_typ, 1 << cfi_info->buf_write_timeout_typ, 1 << cfi_info->block_erase_timeout_typ, 1 << cfi_info->chip_erase_timeout_typ); buf += printed; buf_size -= printed; printed = snprintf(buf, buf_size, "max. word write timeout: %u us, " "max. buf write timeout: %u us, max. " "block erase timeout: %u ms, max. chip erase timeout: %u ms\n", (1 << cfi_info->word_write_timeout_max) * (1 << cfi_info->word_write_timeout_typ), (1 << cfi_info->buf_write_timeout_max) * (1 << cfi_info->buf_write_timeout_typ), (1 << cfi_info->block_erase_timeout_max) * (1 << cfi_info->block_erase_timeout_typ), (1 << cfi_info->chip_erase_timeout_max) * (1 << cfi_info->chip_erase_timeout_typ)); buf += printed; buf_size -= printed; printed = snprintf(buf, buf_size, "size: 0x%" PRIx32 ", interface desc: %i, " "max buffer write size: 0x%x\n", cfi_info->dev_size, cfi_info->interface_desc, 1 << cfi_info->max_buf_write_size); buf += printed; buf_size -= printed; switch (cfi_info->pri_id) { case 1: case 3: cfi_intel_info(bank, buf, buf_size); break; case 2: cfi_spansion_info(bank, buf, buf_size); break; default: LOG_ERROR("cfi primary command set %i unsupported", cfi_info->pri_id); break; } return ERROR_OK; } static void cfi_fixup_0002_write_buffer(struct flash_bank *bank, void *param) { struct cfi_flash_bank *cfi_info = bank->driver_priv; /* disable write buffer for M29W128G */ cfi_info->buf_write_timeout_typ = 0; } struct flash_driver cfi_flash = { .name = "cfi", .flash_bank_command = cfi_flash_bank_command, .erase = cfi_erase, .protect = cfi_protect, .write = cfi_write, .read = cfi_read, .probe = cfi_probe, .auto_probe = cfi_auto_probe, /* FIXME: access flash at bus_width size */ .erase_check = default_flash_blank_check, .protect_check = cfi_protect_check, .info = get_cfi_info, }; openocd-0.7.0/src/flash/nor/at91sam4.c0000644000175000001440000017334312137151330014262 00000000000000/*************************************************************************** * Copyright (C) 2009 by Duane Ellis * * openocd@duaneellis.com * * * * Copyright (C) 2010 by Olaf Lüke (at91sam3s* support) * * olaf@uni-paderborn.de * * * * Copyright (C) 2011 by Olivier Schonken, Jim Norris * * (at91sam3x* & at91sam4 support)* * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General public License as published by * * the Free Software Foundation; either version 2 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. * ****************************************************************************/ /* Some of the the lower level code was based on code supplied by * ATMEL under this copyright. */ /* BEGIN ATMEL COPYRIGHT */ /* ---------------------------------------------------------------------------- * ATMEL Microcontroller Software Support * ---------------------------------------------------------------------------- * Copyright (c) 2009, Atmel Corporation * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the disclaimer below. * * Atmel's name may not be used to endorse or promote products derived from * this software without specific prior written permission. * * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ---------------------------------------------------------------------------- */ /* END ATMEL COPYRIGHT */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include #define REG_NAME_WIDTH (12) /* at91sam4s series (has always one flash bank)*/ #define FLASH_BANK_BASE_S 0x00400000 /* at91sam4sd series (two one flash banks), first bank address */ #define FLASH_BANK0_BASE_SD FLASH_BANK_BASE_S /* at91sam4sd16x, second bank address */ #define FLASH_BANK1_BASE_1024K_SD (FLASH_BANK0_BASE_SD+(1024*1024/2)) /* at91sam4sd32x, second bank address */ #define FLASH_BANK1_BASE_2048K_SD (FLASH_BANK0_BASE_SD+(2048*1024/2)) #define AT91C_EFC_FCMD_GETD (0x0) /* (EFC) Get Flash Descriptor */ #define AT91C_EFC_FCMD_WP (0x1) /* (EFC) Write Page */ #define AT91C_EFC_FCMD_WPL (0x2) /* (EFC) Write Page and Lock */ #define AT91C_EFC_FCMD_EWP (0x3) /* (EFC) Erase Page and Write Page */ #define AT91C_EFC_FCMD_EWPL (0x4) /* (EFC) Erase Page and Write Page then Lock */ #define AT91C_EFC_FCMD_EA (0x5) /* (EFC) Erase All */ /* cmd6 is not present in the at91sam4u4/2/1 data sheet table 19-2 */ /* #define AT91C_EFC_FCMD_EPL (0x6) // (EFC) Erase plane? */ #define AT91C_EFC_FCMD_EPA (0x7) /* (EFC) Erase pages */ #define AT91C_EFC_FCMD_SLB (0x8) /* (EFC) Set Lock Bit */ #define AT91C_EFC_FCMD_CLB (0x9) /* (EFC) Clear Lock Bit */ #define AT91C_EFC_FCMD_GLB (0xA) /* (EFC) Get Lock Bit */ #define AT91C_EFC_FCMD_SFB (0xB) /* (EFC) Set Fuse Bit */ #define AT91C_EFC_FCMD_CFB (0xC) /* (EFC) Clear Fuse Bit */ #define AT91C_EFC_FCMD_GFB (0xD) /* (EFC) Get Fuse Bit */ #define AT91C_EFC_FCMD_STUI (0xE) /* (EFC) Start Read Unique ID */ #define AT91C_EFC_FCMD_SPUI (0xF) /* (EFC) Stop Read Unique ID */ #define offset_EFC_FMR 0 #define offset_EFC_FCR 4 #define offset_EFC_FSR 8 #define offset_EFC_FRR 12 extern struct flash_driver at91sam4_flash; static float _tomhz(uint32_t freq_hz) { float f; f = ((float)(freq_hz)) / 1000000.0; return f; } /* How the chip is configured. */ struct sam4_cfg { uint32_t unique_id[4]; uint32_t slow_freq; uint32_t rc_freq; uint32_t mainosc_freq; uint32_t plla_freq; uint32_t mclk_freq; uint32_t cpu_freq; uint32_t fclk_freq; uint32_t pclk0_freq; uint32_t pclk1_freq; uint32_t pclk2_freq; #define SAM4_CHIPID_CIDR (0x400E0740) uint32_t CHIPID_CIDR; #define SAM4_CHIPID_EXID (0x400E0744) uint32_t CHIPID_EXID; #define SAM4_PMC_BASE (0x400E0400) #define SAM4_PMC_SCSR (SAM4_PMC_BASE + 0x0008) uint32_t PMC_SCSR; #define SAM4_PMC_PCSR (SAM4_PMC_BASE + 0x0018) uint32_t PMC_PCSR; #define SAM4_CKGR_UCKR (SAM4_PMC_BASE + 0x001c) uint32_t CKGR_UCKR; #define SAM4_CKGR_MOR (SAM4_PMC_BASE + 0x0020) uint32_t CKGR_MOR; #define SAM4_CKGR_MCFR (SAM4_PMC_BASE + 0x0024) uint32_t CKGR_MCFR; #define SAM4_CKGR_PLLAR (SAM4_PMC_BASE + 0x0028) uint32_t CKGR_PLLAR; #define SAM4_PMC_MCKR (SAM4_PMC_BASE + 0x0030) uint32_t PMC_MCKR; #define SAM4_PMC_PCK0 (SAM4_PMC_BASE + 0x0040) uint32_t PMC_PCK0; #define SAM4_PMC_PCK1 (SAM4_PMC_BASE + 0x0044) uint32_t PMC_PCK1; #define SAM4_PMC_PCK2 (SAM4_PMC_BASE + 0x0048) uint32_t PMC_PCK2; #define SAM4_PMC_SR (SAM4_PMC_BASE + 0x0068) uint32_t PMC_SR; #define SAM4_PMC_IMR (SAM4_PMC_BASE + 0x006c) uint32_t PMC_IMR; #define SAM4_PMC_FSMR (SAM4_PMC_BASE + 0x0070) uint32_t PMC_FSMR; #define SAM4_PMC_FSPR (SAM4_PMC_BASE + 0x0074) uint32_t PMC_FSPR; }; struct sam4_bank_private { int probed; /* DANGER: THERE ARE DRAGONS HERE.. */ /* NOTE: If you add more 'ghost' pointers */ /* be aware that you must *manually* update */ /* these pointers in the function sam4_GetDetails() */ /* See the comment "Here there be dragons" */ /* so we can find the chip we belong to */ struct sam4_chip *pChip; /* so we can find the original bank pointer */ struct flash_bank *pBank; unsigned bank_number; uint32_t controller_address; uint32_t base_address; uint32_t flash_wait_states; bool present; unsigned size_bytes; unsigned nsectors; unsigned sector_size; unsigned page_size; }; struct sam4_chip_details { /* THERE ARE DRAGONS HERE.. */ /* note: If you add pointers here */ /* be careful about them as they */ /* may need to be updated inside */ /* the function: "sam4_GetDetails() */ /* which copy/overwrites the */ /* 'runtime' copy of this structure */ uint32_t chipid_cidr; const char *name; unsigned n_gpnvms; #define SAM4_N_NVM_BITS 3 unsigned gpnvm[SAM4_N_NVM_BITS]; unsigned total_flash_size; unsigned total_sram_size; unsigned n_banks; #define SAM4_MAX_FLASH_BANKS 2 /* these are "initialized" from the global const data */ struct sam4_bank_private bank[SAM4_MAX_FLASH_BANKS]; }; struct sam4_chip { struct sam4_chip *next; int probed; /* this is "initialized" from the global const structure */ struct sam4_chip_details details; struct target *target; struct sam4_cfg cfg; }; struct sam4_reg_list { uint32_t address; size_t struct_offset; const char *name; void (*explain_func)(struct sam4_chip *pInfo); }; static struct sam4_chip *all_sam4_chips; static struct sam4_chip *get_current_sam4(struct command_context *cmd_ctx) { struct target *t; static struct sam4_chip *p; t = get_current_target(cmd_ctx); if (!t) { command_print(cmd_ctx, "No current target?"); return NULL; } p = all_sam4_chips; if (!p) { /* this should not happen */ /* the command is not registered until the chip is created? */ command_print(cmd_ctx, "No SAM4 chips exist?"); return NULL; } while (p) { if (p->target == t) return p; p = p->next; } command_print(cmd_ctx, "Cannot find SAM4 chip?"); return NULL; } /*The actual sector size of the SAM4S flash memory is 65536 bytes. 16 sectors for a 1024KB device*/ /*The lockregions are 8KB per lock region, with a 1024KB device having 128 lock regions. */ /*For the best results, nsectors are thus set to the amount of lock regions, and the sector_size*/ /*set to the lock region size. Page erases are used to erase 8KB sections when programming*/ /* these are used to *initialize* the "pChip->details" structure. */ static const struct sam4_chip_details all_sam4_details[] = { /* Start at91sam4s* series */ /*atsam4s16c - LQFP100/BGA100*/ { .chipid_cidr = 0x28AC0CE0, .name = "at91sam4s16c", .total_flash_size = 1024 * 1024, .total_sram_size = 128 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = {*/ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 1024 * 1024, .nsectors = 128, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = {*/ { .present = 0, .probed = 0, .bank_number = 1, }, }, }, /*atsam4s16b - LQFP64/QFN64*/ { .chipid_cidr = 0x289C0CE0, .name = "at91sam4s16b", .total_flash_size = 1024 * 1024, .total_sram_size = 128 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = {*/ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 1024 * 1024, .nsectors = 128, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = {*/ { .present = 0, .probed = 0, .bank_number = 1, }, }, }, /*atsam4s16a - LQFP48/QFN48*/ { .chipid_cidr = 0x288C0CE0, .name = "at91sam4s16a", .total_flash_size = 1024 * 1024, .total_sram_size = 128 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = {*/ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 1024 * 1024, .nsectors = 128, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = {*/ { .present = 0, .probed = 0, .bank_number = 1, }, }, }, /*atsam4s8c - LQFP100/BGA100*/ { .chipid_cidr = 0x28AC0AE0, .name = "at91sam4s8c", .total_flash_size = 512 * 1024, .total_sram_size = 128 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = {*/ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 512 * 1024, .nsectors = 64, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = {*/ { .present = 0, .probed = 0, .bank_number = 1, }, }, }, /*atsam4s8b - LQFP64/BGA64*/ { .chipid_cidr = 0x289C0AE0, .name = "at91sam4s8b", .total_flash_size = 512 * 1024, .total_sram_size = 128 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = {*/ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 512 * 1024, .nsectors = 64, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = {*/ { .present = 0, .probed = 0, .bank_number = 1, }, }, }, /*atsam4s8a - LQFP48/BGA48*/ { .chipid_cidr = 0x288C0AE0, .name = "at91sam4s8a", .total_flash_size = 512 * 1024, .total_sram_size = 128 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = {*/ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 512 * 1024, .nsectors = 64, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = {*/ { .present = 0, .probed = 0, .bank_number = 1, }, }, }, /*at91sam4sd32c*/ { .chipid_cidr = 0x29a70ee0, .name = "at91sam4sd32c", .total_flash_size = 2048 * 1024, .total_sram_size = 160 * 1024, .n_gpnvms = 3, .n_banks = 2, /* .bank[0] = { */ { { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_SD, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 1024 * 1024, .nsectors = 128, .sector_size = 8192, .page_size = 512, }, /* .bank[1] = { */ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_2048K_SD, .controller_address = 0x400e0c00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 1024 * 1024, .nsectors = 128, .sector_size = 8192, .page_size = 512, }, }, }, /* terminate */ { .chipid_cidr = 0, .name = NULL, } }; /* Globals above */ /*********************************************************************** ********************************************************************** ********************************************************************** ********************************************************************** ********************************************************************** **********************************************************************/ /* *ATMEL* style code - from the SAM4 driver code */ /** * Get the current status of the EEFC and * the value of some status bits (LOCKE, PROGE). * @param pPrivate - info about the bank * @param v - result goes here */ static int EFC_GetStatus(struct sam4_bank_private *pPrivate, uint32_t *v) { int r; r = target_read_u32(pPrivate->pChip->target, pPrivate->controller_address + offset_EFC_FSR, v); LOG_DEBUG("Status: 0x%08x (lockerror: %d, cmderror: %d, ready: %d)", (unsigned int)(*v), ((unsigned int)((*v >> 2) & 1)), ((unsigned int)((*v >> 1) & 1)), ((unsigned int)((*v >> 0) & 1))); return r; } /** * Get the result of the last executed command. * @param pPrivate - info about the bank * @param v - result goes here */ static int EFC_GetResult(struct sam4_bank_private *pPrivate, uint32_t *v) { int r; uint32_t rv; r = target_read_u32(pPrivate->pChip->target, pPrivate->controller_address + offset_EFC_FRR, &rv); if (v) *v = rv; LOG_DEBUG("Result: 0x%08x", ((unsigned int)(rv))); return r; } static int EFC_StartCommand(struct sam4_bank_private *pPrivate, unsigned command, unsigned argument) { uint32_t n, v; int r; int retry; retry = 0; do_retry: /* Check command & argument */ switch (command) { case AT91C_EFC_FCMD_WP: case AT91C_EFC_FCMD_WPL: case AT91C_EFC_FCMD_EWP: case AT91C_EFC_FCMD_EWPL: /* case AT91C_EFC_FCMD_EPL: */ case AT91C_EFC_FCMD_EPA: case AT91C_EFC_FCMD_SLB: case AT91C_EFC_FCMD_CLB: n = (pPrivate->size_bytes / pPrivate->page_size); if (argument >= n) LOG_ERROR("*BUG*: Embedded flash has only %u pages", (unsigned)(n)); break; case AT91C_EFC_FCMD_SFB: case AT91C_EFC_FCMD_CFB: if (argument >= pPrivate->pChip->details.n_gpnvms) { LOG_ERROR("*BUG*: Embedded flash has only %d GPNVMs", pPrivate->pChip->details.n_gpnvms); } break; case AT91C_EFC_FCMD_GETD: case AT91C_EFC_FCMD_EA: case AT91C_EFC_FCMD_GLB: case AT91C_EFC_FCMD_GFB: case AT91C_EFC_FCMD_STUI: case AT91C_EFC_FCMD_SPUI: if (argument != 0) LOG_ERROR("Argument is meaningless for cmd: %d", command); break; default: LOG_ERROR("Unknown command %d", command); break; } if (command == AT91C_EFC_FCMD_SPUI) { /* this is a very special situation. */ /* Situation (1) - error/retry - see below */ /* And we are being called recursively */ /* Situation (2) - normal, finished reading unique id */ } else { /* it should be "ready" */ EFC_GetStatus(pPrivate, &v); if (v & 1) { /* then it is ready */ /* we go on */ } else { if (retry) { /* we have done this before */ /* the controller is not responding. */ LOG_ERROR("flash controller(%d) is not ready! Error", pPrivate->bank_number); return ERROR_FAIL; } else { retry++; LOG_ERROR("Flash controller(%d) is not ready, attempting reset", pPrivate->bank_number); /* we do that by issuing the *STOP* command */ EFC_StartCommand(pPrivate, AT91C_EFC_FCMD_SPUI, 0); /* above is recursive, and further recursion is blocked by */ /* if (command == AT91C_EFC_FCMD_SPUI) above */ goto do_retry; } } } v = (0x5A << 24) | (argument << 8) | command; LOG_DEBUG("Command: 0x%08x", ((unsigned int)(v))); r = target_write_u32(pPrivate->pBank->target, pPrivate->controller_address + offset_EFC_FCR, v); if (r != ERROR_OK) LOG_DEBUG("Error Write failed"); return r; } /** * Performs the given command and wait until its completion (or an error). * @param pPrivate - info about the bank * @param command - Command to perform. * @param argument - Optional command argument. * @param status - put command status bits here */ static int EFC_PerformCommand(struct sam4_bank_private *pPrivate, unsigned command, unsigned argument, uint32_t *status) { int r; uint32_t v; long long ms_now, ms_end; /* default */ if (status) *status = 0; r = EFC_StartCommand(pPrivate, command, argument); if (r != ERROR_OK) return r; ms_end = 10000 + timeval_ms(); do { r = EFC_GetStatus(pPrivate, &v); if (r != ERROR_OK) return r; ms_now = timeval_ms(); if (ms_now > ms_end) { /* error */ LOG_ERROR("Command timeout"); return ERROR_FAIL; } } while ((v & 1) == 0); /* error bits.. */ if (status) *status = (v & 0x6); return ERROR_OK; } /** * Read the unique ID. * @param pPrivate - info about the bank * The unique ID is stored in the 'pPrivate' structure. */ static int FLASHD_ReadUniqueID(struct sam4_bank_private *pPrivate) { int r; uint32_t v; int x; /* assume 0 */ pPrivate->pChip->cfg.unique_id[0] = 0; pPrivate->pChip->cfg.unique_id[1] = 0; pPrivate->pChip->cfg.unique_id[2] = 0; pPrivate->pChip->cfg.unique_id[3] = 0; LOG_DEBUG("Begin"); r = EFC_StartCommand(pPrivate, AT91C_EFC_FCMD_STUI, 0); if (r < 0) return r; for (x = 0; x < 4; x++) { r = target_read_u32(pPrivate->pChip->target, pPrivate->pBank->base + (x * 4), &v); if (r < 0) return r; pPrivate->pChip->cfg.unique_id[x] = v; } r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_SPUI, 0, NULL); LOG_DEBUG("End: R=%d, id = 0x%08x, 0x%08x, 0x%08x, 0x%08x", r, (unsigned int)(pPrivate->pChip->cfg.unique_id[0]), (unsigned int)(pPrivate->pChip->cfg.unique_id[1]), (unsigned int)(pPrivate->pChip->cfg.unique_id[2]), (unsigned int)(pPrivate->pChip->cfg.unique_id[3])); return r; } /** * Erases the entire flash. * @param pPrivate - the info about the bank. */ static int FLASHD_EraseEntireBank(struct sam4_bank_private *pPrivate) { LOG_DEBUG("Here"); return EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_EA, 0, NULL); } /** * Erases the entire flash. * @param pPrivate - the info about the bank. */ static int FLASHD_ErasePages(struct sam4_bank_private *pPrivate, int firstPage, int numPages, uint32_t *status) { LOG_DEBUG("Here"); uint8_t erasePages; switch (numPages) { case 4: erasePages = 0x00; break; case 8: erasePages = 0x01; break; case 16: erasePages = 0x02; break; case 32: erasePages = 0x03; break; default: erasePages = 0x00; break; } /* AT91C_EFC_FCMD_EPA * According to the datasheet FARG[15:2] defines the page from which * the erase will start.This page must be modulo 4, 8, 16 or 32 * according to the number of pages to erase. FARG[1:0] defines the * number of pages to be erased. Previously (firstpage << 2) was used * to conform to this, seems it should not be shifted... */ return EFC_PerformCommand(pPrivate, /* send Erase Page */ AT91C_EFC_FCMD_EPA, (firstPage) | erasePages, status); } /** * Gets current GPNVM state. * @param pPrivate - info about the bank. * @param gpnvm - GPNVM bit index. * @param puthere - result stored here. */ /* ------------------------------------------------------------------------------ */ static int FLASHD_GetGPNVM(struct sam4_bank_private *pPrivate, unsigned gpnvm, unsigned *puthere) { uint32_t v; int r; LOG_DEBUG("Here"); if (pPrivate->bank_number != 0) { LOG_ERROR("GPNVM only works with Bank0"); return ERROR_FAIL; } if (gpnvm >= pPrivate->pChip->details.n_gpnvms) { LOG_ERROR("Invalid GPNVM %d, max: %d, ignored", gpnvm, pPrivate->pChip->details.n_gpnvms); return ERROR_FAIL; } /* Get GPNVMs status */ r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_GFB, 0, NULL); if (r != ERROR_OK) { LOG_ERROR("Failed"); return r; } r = EFC_GetResult(pPrivate, &v); if (puthere) { /* Check if GPNVM is set */ /* get the bit and make it a 0/1 */ *puthere = (v >> gpnvm) & 1; } return r; } /** * Clears the selected GPNVM bit. * @param pPrivate info about the bank * @param gpnvm GPNVM index. * @returns 0 if successful; otherwise returns an error code. */ static int FLASHD_ClrGPNVM(struct sam4_bank_private *pPrivate, unsigned gpnvm) { int r; unsigned v; LOG_DEBUG("Here"); if (pPrivate->bank_number != 0) { LOG_ERROR("GPNVM only works with Bank0"); return ERROR_FAIL; } if (gpnvm >= pPrivate->pChip->details.n_gpnvms) { LOG_ERROR("Invalid GPNVM %d, max: %d, ignored", gpnvm, pPrivate->pChip->details.n_gpnvms); return ERROR_FAIL; } r = FLASHD_GetGPNVM(pPrivate, gpnvm, &v); if (r != ERROR_OK) { LOG_DEBUG("Failed: %d", r); return r; } r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_CFB, gpnvm, NULL); LOG_DEBUG("End: %d", r); return r; } /** * Sets the selected GPNVM bit. * @param pPrivate info about the bank * @param gpnvm GPNVM index. */ static int FLASHD_SetGPNVM(struct sam4_bank_private *pPrivate, unsigned gpnvm) { int r; unsigned v; if (pPrivate->bank_number != 0) { LOG_ERROR("GPNVM only works with Bank0"); return ERROR_FAIL; } if (gpnvm >= pPrivate->pChip->details.n_gpnvms) { LOG_ERROR("Invalid GPNVM %d, max: %d, ignored", gpnvm, pPrivate->pChip->details.n_gpnvms); return ERROR_FAIL; } r = FLASHD_GetGPNVM(pPrivate, gpnvm, &v); if (r != ERROR_OK) return r; if (v) { /* already set */ r = ERROR_OK; } else { /* set it */ r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_SFB, gpnvm, NULL); } return r; } /** * Returns a bit field (at most 64) of locked regions within a page. * @param pPrivate info about the bank * @param v where to store locked bits */ static int FLASHD_GetLockBits(struct sam4_bank_private *pPrivate, uint32_t *v) { int r; LOG_DEBUG("Here"); r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_GLB, 0, NULL); if (r == ERROR_OK) { EFC_GetResult(pPrivate, v); EFC_GetResult(pPrivate, v); EFC_GetResult(pPrivate, v); r = EFC_GetResult(pPrivate, v); } LOG_DEBUG("End: %d", r); return r; } /** * Unlocks all the regions in the given address range. * @param pPrivate info about the bank * @param start_sector first sector to unlock * @param end_sector last (inclusive) to unlock */ static int FLASHD_Unlock(struct sam4_bank_private *pPrivate, unsigned start_sector, unsigned end_sector) { int r; uint32_t status; uint32_t pg; uint32_t pages_per_sector; pages_per_sector = pPrivate->sector_size / pPrivate->page_size; /* Unlock all pages */ while (start_sector <= end_sector) { pg = start_sector * pages_per_sector; r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_CLB, pg, &status); if (r != ERROR_OK) return r; start_sector++; } return ERROR_OK; } /** * Locks regions * @param pPrivate - info about the bank * @param start_sector - first sector to lock * @param end_sector - last sector (inclusive) to lock */ static int FLASHD_Lock(struct sam4_bank_private *pPrivate, unsigned start_sector, unsigned end_sector) { uint32_t status; uint32_t pg; uint32_t pages_per_sector; int r; pages_per_sector = pPrivate->sector_size / pPrivate->page_size; /* Lock all pages */ while (start_sector <= end_sector) { pg = start_sector * pages_per_sector; r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_SLB, pg, &status); if (r != ERROR_OK) return r; start_sector++; } return ERROR_OK; } /****** END SAM4 CODE ********/ /* begin helpful debug code */ /* print the fieldname, the field value, in dec & hex, and return field value */ static uint32_t sam4_reg_fieldname(struct sam4_chip *pChip, const char *regname, uint32_t value, unsigned shift, unsigned width) { uint32_t v; int hwidth, dwidth; /* extract the field */ v = value >> shift; v = v & ((1 << width)-1); if (width <= 16) { hwidth = 4; dwidth = 5; } else { hwidth = 8; dwidth = 12; } /* show the basics */ LOG_USER_N("\t%*s: %*d [0x%0*x] ", REG_NAME_WIDTH, regname, dwidth, v, hwidth, v); return v; } static const char _unknown[] = "unknown"; static const char *const eproc_names[] = { _unknown, /* 0 */ "arm946es", /* 1 */ "arm7tdmi", /* 2 */ "cortex-m3", /* 3 */ "arm920t", /* 4 */ "arm926ejs", /* 5 */ "cortex-a5", /* 6 */ "cortex-m4", /* 7 */ _unknown, /* 8 */ _unknown, /* 9 */ _unknown, /* 10 */ _unknown, /* 11 */ _unknown, /* 12 */ _unknown, /* 13 */ _unknown, /* 14 */ _unknown, /* 15 */ }; #define nvpsize2 nvpsize /* these two tables are identical */ static const char *const nvpsize[] = { "none", /* 0 */ "8K bytes", /* 1 */ "16K bytes", /* 2 */ "32K bytes", /* 3 */ _unknown, /* 4 */ "64K bytes", /* 5 */ _unknown, /* 6 */ "128K bytes", /* 7 */ _unknown, /* 8 */ "256K bytes", /* 9 */ "512K bytes", /* 10 */ _unknown, /* 11 */ "1024K bytes", /* 12 */ _unknown, /* 13 */ "2048K bytes", /* 14 */ _unknown, /* 15 */ }; static const char *const sramsize[] = { "48K Bytes", /* 0 */ "1K Bytes", /* 1 */ "2K Bytes", /* 2 */ "6K Bytes", /* 3 */ "112K Bytes", /* 4 */ "4K Bytes", /* 5 */ "80K Bytes", /* 6 */ "160K Bytes", /* 7 */ "8K Bytes", /* 8 */ "16K Bytes", /* 9 */ "32K Bytes", /* 10 */ "64K Bytes", /* 11 */ "128K Bytes", /* 12 */ "256K Bytes", /* 13 */ "96K Bytes", /* 14 */ "512K Bytes", /* 15 */ }; static const struct archnames { unsigned value; const char *name; } archnames[] = { { 0x19, "AT91SAM9xx Series" }, { 0x29, "AT91SAM9XExx Series" }, { 0x34, "AT91x34 Series" }, { 0x37, "CAP7 Series" }, { 0x39, "CAP9 Series" }, { 0x3B, "CAP11 Series" }, { 0x40, "AT91x40 Series" }, { 0x42, "AT91x42 Series" }, { 0x55, "AT91x55 Series" }, { 0x60, "AT91SAM7Axx Series" }, { 0x61, "AT91SAM7AQxx Series" }, { 0x63, "AT91x63 Series" }, { 0x70, "AT91SAM7Sxx Series" }, { 0x71, "AT91SAM7XCxx Series" }, { 0x72, "AT91SAM7SExx Series" }, { 0x73, "AT91SAM7Lxx Series" }, { 0x75, "AT91SAM7Xxx Series" }, { 0x76, "AT91SAM7SLxx Series" }, { 0x80, "ATSAM3UxC Series (100-pin version)" }, { 0x81, "ATSAM3UxE Series (144-pin version)" }, { 0x83, "ATSAM3A/SAM4A xC Series (100-pin version)"}, { 0x84, "ATSAM3X/SAM4X xC Series (100-pin version)"}, { 0x85, "ATSAM3X/SAM4X xE Series (144-pin version)"}, { 0x86, "ATSAM3X/SAM4X xG Series (208/217-pin version)" }, { 0x88, "ATSAM3S/SAM4S xA Series (48-pin version)" }, { 0x89, "ATSAM3S/SAM4S xB Series (64-pin version)" }, { 0x8A, "ATSAM3S/SAM4S xC Series (100-pin version)"}, { 0x92, "AT91x92 Series" }, { 0x93, "ATSAM3NxA Series (48-pin version)" }, { 0x94, "ATSAM3NxB Series (64-pin version)" }, { 0x95, "ATSAM3NxC Series (100-pin version)" }, { 0x98, "ATSAM3SDxA Series (48-pin version)" }, { 0x99, "ATSAM3SDxB Series (64-pin version)" }, { 0x9A, "ATSAM3SDxC Series (100-pin version)" }, { 0xA5, "ATSAM5A" }, { 0xF0, "AT75Cxx Series" }, { -1, NULL }, }; static const char *const nvptype[] = { "rom", /* 0 */ "romless or onchip flash", /* 1 */ "embedded flash memory",/* 2 */ "rom(nvpsiz) + embedded flash (nvpsiz2)", /* 3 */ "sram emulating flash", /* 4 */ _unknown, /* 5 */ _unknown, /* 6 */ _unknown, /* 7 */ }; static const char *_yes_or_no(uint32_t v) { if (v) return "YES"; else return "NO"; } static const char *const _rc_freq[] = { "4 MHz", "8 MHz", "12 MHz", "reserved" }; static void sam4_explain_ckgr_mor(struct sam4_chip *pChip) { uint32_t v; uint32_t rcen; v = sam4_reg_fieldname(pChip, "MOSCXTEN", pChip->cfg.CKGR_MOR, 0, 1); LOG_USER("(main xtal enabled: %s)", _yes_or_no(v)); v = sam4_reg_fieldname(pChip, "MOSCXTBY", pChip->cfg.CKGR_MOR, 1, 1); LOG_USER("(main osc bypass: %s)", _yes_or_no(v)); rcen = sam4_reg_fieldname(pChip, "MOSCRCEN", pChip->cfg.CKGR_MOR, 3, 1); LOG_USER("(onchip RC-OSC enabled: %s)", _yes_or_no(rcen)); v = sam4_reg_fieldname(pChip, "MOSCRCF", pChip->cfg.CKGR_MOR, 4, 3); LOG_USER("(onchip RC-OSC freq: %s)", _rc_freq[v]); pChip->cfg.rc_freq = 0; if (rcen) { switch (v) { default: pChip->cfg.rc_freq = 0; break; case 0: pChip->cfg.rc_freq = 4 * 1000 * 1000; break; case 1: pChip->cfg.rc_freq = 8 * 1000 * 1000; break; case 2: pChip->cfg.rc_freq = 12 * 1000 * 1000; break; } } v = sam4_reg_fieldname(pChip, "MOSCXTST", pChip->cfg.CKGR_MOR, 8, 8); LOG_USER("(startup clks, time= %f uSecs)", ((float)(v * 1000000)) / ((float)(pChip->cfg.slow_freq))); v = sam4_reg_fieldname(pChip, "MOSCSEL", pChip->cfg.CKGR_MOR, 24, 1); LOG_USER("(mainosc source: %s)", v ? "external xtal" : "internal RC"); v = sam4_reg_fieldname(pChip, "CFDEN", pChip->cfg.CKGR_MOR, 25, 1); LOG_USER("(clock failure enabled: %s)", _yes_or_no(v)); } static void sam4_explain_chipid_cidr(struct sam4_chip *pChip) { int x; uint32_t v; const char *cp; sam4_reg_fieldname(pChip, "Version", pChip->cfg.CHIPID_CIDR, 0, 5); LOG_USER_N("\n"); v = sam4_reg_fieldname(pChip, "EPROC", pChip->cfg.CHIPID_CIDR, 5, 3); LOG_USER("%s", eproc_names[v]); v = sam4_reg_fieldname(pChip, "NVPSIZE", pChip->cfg.CHIPID_CIDR, 8, 4); LOG_USER("%s", nvpsize[v]); v = sam4_reg_fieldname(pChip, "NVPSIZE2", pChip->cfg.CHIPID_CIDR, 12, 4); LOG_USER("%s", nvpsize2[v]); v = sam4_reg_fieldname(pChip, "SRAMSIZE", pChip->cfg.CHIPID_CIDR, 16, 4); LOG_USER("%s", sramsize[v]); v = sam4_reg_fieldname(pChip, "ARCH", pChip->cfg.CHIPID_CIDR, 20, 8); cp = _unknown; for (x = 0; archnames[x].name; x++) { if (v == archnames[x].value) { cp = archnames[x].name; break; } } LOG_USER("%s", cp); v = sam4_reg_fieldname(pChip, "NVPTYP", pChip->cfg.CHIPID_CIDR, 28, 3); LOG_USER("%s", nvptype[v]); v = sam4_reg_fieldname(pChip, "EXTID", pChip->cfg.CHIPID_CIDR, 31, 1); LOG_USER("(exists: %s)", _yes_or_no(v)); } static void sam4_explain_ckgr_mcfr(struct sam4_chip *pChip) { uint32_t v; v = sam4_reg_fieldname(pChip, "MAINFRDY", pChip->cfg.CKGR_MCFR, 16, 1); LOG_USER("(main ready: %s)", _yes_or_no(v)); v = sam4_reg_fieldname(pChip, "MAINF", pChip->cfg.CKGR_MCFR, 0, 16); v = (v * pChip->cfg.slow_freq) / 16; pChip->cfg.mainosc_freq = v; LOG_USER("(%3.03f Mhz (%d.%03dkhz slowclk)", _tomhz(v), pChip->cfg.slow_freq / 1000, pChip->cfg.slow_freq % 1000); } static void sam4_explain_ckgr_plla(struct sam4_chip *pChip) { uint32_t mula, diva; diva = sam4_reg_fieldname(pChip, "DIVA", pChip->cfg.CKGR_PLLAR, 0, 8); LOG_USER_N("\n"); mula = sam4_reg_fieldname(pChip, "MULA", pChip->cfg.CKGR_PLLAR, 16, 11); LOG_USER_N("\n"); pChip->cfg.plla_freq = 0; if (mula == 0) LOG_USER("\tPLLA Freq: (Disabled,mula = 0)"); else if (diva == 0) LOG_USER("\tPLLA Freq: (Disabled,diva = 0)"); else if (diva == 1) { pChip->cfg.plla_freq = (pChip->cfg.mainosc_freq * (mula + 1)); LOG_USER("\tPLLA Freq: %3.03f MHz", _tomhz(pChip->cfg.plla_freq)); } } static void sam4_explain_mckr(struct sam4_chip *pChip) { uint32_t css, pres, fin = 0; int pdiv = 0; const char *cp = NULL; css = sam4_reg_fieldname(pChip, "CSS", pChip->cfg.PMC_MCKR, 0, 2); switch (css & 3) { case 0: fin = pChip->cfg.slow_freq; cp = "slowclk"; break; case 1: fin = pChip->cfg.mainosc_freq; cp = "mainosc"; break; case 2: fin = pChip->cfg.plla_freq; cp = "plla"; break; case 3: if (pChip->cfg.CKGR_UCKR & (1 << 16)) { fin = 480 * 1000 * 1000; cp = "upll"; } else { fin = 0; cp = "upll (*ERROR* UPLL is disabled)"; } break; default: assert(0); break; } LOG_USER("%s (%3.03f Mhz)", cp, _tomhz(fin)); pres = sam4_reg_fieldname(pChip, "PRES", pChip->cfg.PMC_MCKR, 4, 3); switch (pres & 0x07) { case 0: pdiv = 1; cp = "selected clock"; break; case 1: pdiv = 2; cp = "clock/2"; break; case 2: pdiv = 4; cp = "clock/4"; break; case 3: pdiv = 8; cp = "clock/8"; break; case 4: pdiv = 16; cp = "clock/16"; break; case 5: pdiv = 32; cp = "clock/32"; break; case 6: pdiv = 64; cp = "clock/64"; break; case 7: pdiv = 6; cp = "clock/6"; break; default: assert(0); break; } LOG_USER("(%s)", cp); fin = fin / pdiv; /* sam4 has a *SINGLE* clock - */ /* other at91 series parts have divisors for these. */ pChip->cfg.cpu_freq = fin; pChip->cfg.mclk_freq = fin; pChip->cfg.fclk_freq = fin; LOG_USER("\t\tResult CPU Freq: %3.03f", _tomhz(fin)); } #if 0 static struct sam4_chip *target2sam4(struct target *pTarget) { struct sam4_chip *pChip; if (pTarget == NULL) return NULL; pChip = all_sam4_chips; while (pChip) { if (pChip->target == pTarget) break; /* return below */ else pChip = pChip->next; } return pChip; } #endif static uint32_t *sam4_get_reg_ptr(struct sam4_cfg *pCfg, const struct sam4_reg_list *pList) { /* this function exists to help */ /* keep funky offsetof() errors */ /* and casting from causing bugs */ /* By using prototypes - we can detect what would */ /* be casting errors. */ return (uint32_t *)(void *)(((char *)(pCfg)) + pList->struct_offset); } #define SAM4_ENTRY(NAME, FUNC) { .address = SAM4_ ## NAME, .struct_offset = offsetof( \ struct sam4_cfg, \ NAME), # NAME, FUNC } static const struct sam4_reg_list sam4_all_regs[] = { SAM4_ENTRY(CKGR_MOR, sam4_explain_ckgr_mor), SAM4_ENTRY(CKGR_MCFR, sam4_explain_ckgr_mcfr), SAM4_ENTRY(CKGR_PLLAR, sam4_explain_ckgr_plla), SAM4_ENTRY(CKGR_UCKR, NULL), SAM4_ENTRY(PMC_FSMR, NULL), SAM4_ENTRY(PMC_FSPR, NULL), SAM4_ENTRY(PMC_IMR, NULL), SAM4_ENTRY(PMC_MCKR, sam4_explain_mckr), SAM4_ENTRY(PMC_PCK0, NULL), SAM4_ENTRY(PMC_PCK1, NULL), SAM4_ENTRY(PMC_PCK2, NULL), SAM4_ENTRY(PMC_PCSR, NULL), SAM4_ENTRY(PMC_SCSR, NULL), SAM4_ENTRY(PMC_SR, NULL), SAM4_ENTRY(CHIPID_CIDR, sam4_explain_chipid_cidr), SAM4_ENTRY(CHIPID_EXID, NULL), /* TERMINATE THE LIST */ { .name = NULL } }; #undef SAM4_ENTRY static struct sam4_bank_private *get_sam4_bank_private(struct flash_bank *bank) { return (struct sam4_bank_private *)(bank->driver_priv); } /** * Given a pointer to where it goes in the structure, * determine the register name, address from the all registers table. */ static const struct sam4_reg_list *sam4_GetReg(struct sam4_chip *pChip, uint32_t *goes_here) { const struct sam4_reg_list *pReg; pReg = &(sam4_all_regs[0]); while (pReg->name) { uint32_t *pPossible; /* calculate where this one go.. */ /* it is "possibly" this register. */ pPossible = ((uint32_t *)(void *)(((char *)(&(pChip->cfg))) + pReg->struct_offset)); /* well? Is it this register */ if (pPossible == goes_here) { /* Jump for joy! */ return pReg; } /* next... */ pReg++; } /* This is *TOTAL*PANIC* - we are totally screwed. */ LOG_ERROR("INVALID SAM4 REGISTER"); return NULL; } static int sam4_ReadThisReg(struct sam4_chip *pChip, uint32_t *goes_here) { const struct sam4_reg_list *pReg; int r; pReg = sam4_GetReg(pChip, goes_here); if (!pReg) return ERROR_FAIL; r = target_read_u32(pChip->target, pReg->address, goes_here); if (r != ERROR_OK) { LOG_ERROR("Cannot read SAM4 register: %s @ 0x%08x, Err: %d", pReg->name, (unsigned)(pReg->address), r); } return r; } static int sam4_ReadAllRegs(struct sam4_chip *pChip) { int r; const struct sam4_reg_list *pReg; pReg = &(sam4_all_regs[0]); while (pReg->name) { r = sam4_ReadThisReg(pChip, sam4_get_reg_ptr(&(pChip->cfg), pReg)); if (r != ERROR_OK) { LOG_ERROR("Cannot read SAM4 register: %s @ 0x%08x, Error: %d", pReg->name, ((unsigned)(pReg->address)), r); return r; } pReg++; } return ERROR_OK; } static int sam4_GetInfo(struct sam4_chip *pChip) { const struct sam4_reg_list *pReg; uint32_t regval; pReg = &(sam4_all_regs[0]); while (pReg->name) { /* display all regs */ LOG_DEBUG("Start: %s", pReg->name); regval = *sam4_get_reg_ptr(&(pChip->cfg), pReg); LOG_USER("%*s: [0x%08x] -> 0x%08x", REG_NAME_WIDTH, pReg->name, pReg->address, regval); if (pReg->explain_func) (*(pReg->explain_func))(pChip); LOG_DEBUG("End: %s", pReg->name); pReg++; } LOG_USER(" rc-osc: %3.03f MHz", _tomhz(pChip->cfg.rc_freq)); LOG_USER(" mainosc: %3.03f MHz", _tomhz(pChip->cfg.mainosc_freq)); LOG_USER(" plla: %3.03f MHz", _tomhz(pChip->cfg.plla_freq)); LOG_USER(" cpu-freq: %3.03f MHz", _tomhz(pChip->cfg.cpu_freq)); LOG_USER("mclk-freq: %3.03f MHz", _tomhz(pChip->cfg.mclk_freq)); LOG_USER(" UniqueId: 0x%08x 0x%08x 0x%08x 0x%08x", pChip->cfg.unique_id[0], pChip->cfg.unique_id[1], pChip->cfg.unique_id[2], pChip->cfg.unique_id[3]); return ERROR_OK; } static int sam4_protect_check(struct flash_bank *bank) { int r; uint32_t v[4] = {0}; unsigned x; struct sam4_bank_private *pPrivate; LOG_DEBUG("Begin"); if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } pPrivate = get_sam4_bank_private(bank); if (!pPrivate) { LOG_ERROR("no private for this bank?"); return ERROR_FAIL; } if (!(pPrivate->probed)) return ERROR_FLASH_BANK_NOT_PROBED; r = FLASHD_GetLockBits(pPrivate, v); if (r != ERROR_OK) { LOG_DEBUG("Failed: %d", r); return r; } for (x = 0; x < pPrivate->nsectors; x++) bank->sectors[x].is_protected = (!!(v[x >> 5] & (1 << (x % 32)))); LOG_DEBUG("Done"); return ERROR_OK; } FLASH_BANK_COMMAND_HANDLER(sam4_flash_bank_command) { struct sam4_chip *pChip; pChip = all_sam4_chips; /* is this an existing chip? */ while (pChip) { if (pChip->target == bank->target) break; pChip = pChip->next; } if (!pChip) { /* this is a *NEW* chip */ pChip = calloc(1, sizeof(struct sam4_chip)); if (!pChip) { LOG_ERROR("NO RAM!"); return ERROR_FAIL; } pChip->target = bank->target; /* insert at head */ pChip->next = all_sam4_chips; all_sam4_chips = pChip; pChip->target = bank->target; /* assumption is this runs at 32khz */ pChip->cfg.slow_freq = 32768; pChip->probed = 0; } switch (bank->base) { default: LOG_ERROR("Address 0x%08x invalid bank address (try 0x%08x" "[at91sam4s series] )", ((unsigned int)(bank->base)), ((unsigned int)(FLASH_BANK_BASE_S))); return ERROR_FAIL; break; /* at91sam4s series only has bank 0*/ /* at91sam4sd series has the same address for bank 0 (FLASH_BANK0_BASE_SD)*/ case FLASH_BANK_BASE_S: bank->driver_priv = &(pChip->details.bank[0]); bank->bank_number = 0; pChip->details.bank[0].pChip = pChip; pChip->details.bank[0].pBank = bank; break; /* Bank 1 of at91sam4sd series */ case FLASH_BANK1_BASE_1024K_SD: case FLASH_BANK1_BASE_2048K_SD: bank->driver_priv = &(pChip->details.bank[1]); bank->bank_number = 1; pChip->details.bank[1].pChip = pChip; pChip->details.bank[1].pBank = bank; break; } /* we initialize after probing. */ return ERROR_OK; } static int sam4_GetDetails(struct sam4_bank_private *pPrivate) { const struct sam4_chip_details *pDetails; struct sam4_chip *pChip; struct flash_bank *saved_banks[SAM4_MAX_FLASH_BANKS]; unsigned x; LOG_DEBUG("Begin"); pDetails = all_sam4_details; while (pDetails->name) { /* Compare cidr without version bits */ if (pDetails->chipid_cidr == (pPrivate->pChip->cfg.CHIPID_CIDR & 0xFFFFFFE0)) break; else pDetails++; } if (pDetails->name == NULL) { LOG_ERROR("SAM4 ChipID 0x%08x not found in table (perhaps you can ID this chip?)", (unsigned int)(pPrivate->pChip->cfg.CHIPID_CIDR)); /* Help the victim, print details about the chip */ LOG_INFO("SAM4 CHIPID_CIDR: 0x%08x decodes as follows", pPrivate->pChip->cfg.CHIPID_CIDR); sam4_explain_chipid_cidr(pPrivate->pChip); return ERROR_FAIL; } /* DANGER: THERE ARE DRAGONS HERE */ /* get our pChip - it is going */ /* to be over-written shortly */ pChip = pPrivate->pChip; /* Note that, in reality: */ /* */ /* pPrivate = &(pChip->details.bank[0]) */ /* or pPrivate = &(pChip->details.bank[1]) */ /* */ /* save the "bank" pointers */ for (x = 0; x < SAM4_MAX_FLASH_BANKS; x++) saved_banks[x] = pChip->details.bank[x].pBank; /* Overwrite the "details" structure. */ memcpy(&(pPrivate->pChip->details), pDetails, sizeof(pPrivate->pChip->details)); /* now fix the ghosted pointers */ for (x = 0; x < SAM4_MAX_FLASH_BANKS; x++) { pChip->details.bank[x].pChip = pChip; pChip->details.bank[x].pBank = saved_banks[x]; } /* update the *BANK*SIZE* */ LOG_DEBUG("End"); return ERROR_OK; } static int _sam4_probe(struct flash_bank *bank, int noise) { unsigned x; int r; struct sam4_bank_private *pPrivate; LOG_DEBUG("Begin: Bank: %d, Noise: %d", bank->bank_number, noise); if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } pPrivate = get_sam4_bank_private(bank); if (!pPrivate) { LOG_ERROR("Invalid/unknown bank number"); return ERROR_FAIL; } r = sam4_ReadAllRegs(pPrivate->pChip); if (r != ERROR_OK) return r; LOG_DEBUG("Here"); if (pPrivate->pChip->probed) r = sam4_GetInfo(pPrivate->pChip); else r = sam4_GetDetails(pPrivate); if (r != ERROR_OK) return r; /* update the flash bank size */ for (x = 0; x < SAM4_MAX_FLASH_BANKS; x++) { if (bank->base == pPrivate->pChip->details.bank[x].base_address) { bank->size = pPrivate->pChip->details.bank[x].size_bytes; break; } } if (bank->sectors == NULL) { bank->sectors = calloc(pPrivate->nsectors, (sizeof((bank->sectors)[0]))); if (bank->sectors == NULL) { LOG_ERROR("No memory!"); return ERROR_FAIL; } bank->num_sectors = pPrivate->nsectors; for (x = 0; ((int)(x)) < bank->num_sectors; x++) { bank->sectors[x].size = pPrivate->sector_size; bank->sectors[x].offset = x * (pPrivate->sector_size); /* mark as unknown */ bank->sectors[x].is_erased = -1; bank->sectors[x].is_protected = -1; } } pPrivate->probed = 1; r = sam4_protect_check(bank); if (r != ERROR_OK) return r; LOG_DEBUG("Bank = %d, nbanks = %d", pPrivate->bank_number, pPrivate->pChip->details.n_banks); if ((pPrivate->bank_number + 1) == pPrivate->pChip->details.n_banks) { /* read unique id, */ /* it appears to be associated with the *last* flash bank. */ FLASHD_ReadUniqueID(pPrivate); } return r; } static int sam4_probe(struct flash_bank *bank) { return _sam4_probe(bank, 1); } static int sam4_auto_probe(struct flash_bank *bank) { return _sam4_probe(bank, 0); } static int sam4_erase(struct flash_bank *bank, int first, int last) { struct sam4_bank_private *pPrivate; int r; int i; int pageCount; /*16 pages equals 8KB - Same size as a lock region*/ pageCount = 16; uint32_t status; LOG_DEBUG("Here"); if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } r = sam4_auto_probe(bank); if (r != ERROR_OK) { LOG_DEBUG("Here,r=%d", r); return r; } pPrivate = get_sam4_bank_private(bank); if (!(pPrivate->probed)) return ERROR_FLASH_BANK_NOT_PROBED; if ((first == 0) && ((last + 1) == ((int)(pPrivate->nsectors)))) { /* whole chip */ LOG_DEBUG("Here"); return FLASHD_EraseEntireBank(pPrivate); } LOG_INFO("sam4 does not auto-erase while programming (Erasing relevant sectors)"); LOG_INFO("sam4 First: 0x%08x Last: 0x%08x", (unsigned int)(first), (unsigned int)(last)); for (i = first; i <= last; i++) { /*16 pages equals 8KB - Same size as a lock region*/ r = FLASHD_ErasePages(pPrivate, (i * pageCount), pageCount, &status); LOG_INFO("Erasing sector: 0x%08x", (unsigned int)(i)); if (r != ERROR_OK) LOG_ERROR("SAM4: Error performing Erase page @ lock region number %d", (unsigned int)(i)); if (status & (1 << 2)) { LOG_ERROR("SAM4: Lock Region %d is locked", (unsigned int)(i)); return ERROR_FAIL; } if (status & (1 << 1)) { LOG_ERROR("SAM4: Flash Command error @lock region %d", (unsigned int)(i)); return ERROR_FAIL; } } return ERROR_OK; } static int sam4_protect(struct flash_bank *bank, int set, int first, int last) { struct sam4_bank_private *pPrivate; int r; LOG_DEBUG("Here"); if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } pPrivate = get_sam4_bank_private(bank); if (!(pPrivate->probed)) return ERROR_FLASH_BANK_NOT_PROBED; if (set) r = FLASHD_Lock(pPrivate, (unsigned)(first), (unsigned)(last)); else r = FLASHD_Unlock(pPrivate, (unsigned)(first), (unsigned)(last)); LOG_DEBUG("End: r=%d", r); return r; } static int sam4_info(struct flash_bank *bank, char *buf, int buf_size) { if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } buf[0] = 0; return ERROR_OK; } static int sam4_page_read(struct sam4_bank_private *pPrivate, unsigned pagenum, uint8_t *buf) { uint32_t adr; int r; adr = pagenum * pPrivate->page_size; adr = adr + pPrivate->base_address; r = target_read_memory(pPrivate->pChip->target, adr, 4, /* THIS*MUST*BE* in 32bit values */ pPrivate->page_size / 4, buf); if (r != ERROR_OK) LOG_ERROR("SAM4: Flash program failed to read page phys address: 0x%08x", (unsigned int)(adr)); return r; } /* The code below is basically this: */ /* compiled with */ /* arm-none-eabi-gcc -mthumb -mcpu = cortex-m3 -O9 -S ./foobar.c -o foobar.s */ /* */ /* Only the *CPU* can write to the flash buffer. */ /* the DAP cannot... so - we download this 28byte thing */ /* Run the algorithm - (below) */ /* to program the device */ /* */ /* ======================================== */ /* #include */ /* */ /* struct foo { */ /* uint32_t *dst; */ /* const uint32_t *src; */ /* int n; */ /* volatile uint32_t *base; */ /* uint32_t cmd; */ /* }; */ /* */ /* */ /* uint32_t sam4_function(struct foo *p) */ /* { */ /* volatile uint32_t *v; */ /* uint32_t *d; */ /* const uint32_t *s; */ /* int n; */ /* uint32_t r; */ /* */ /* d = p->dst; */ /* s = p->src; */ /* n = p->n; */ /* */ /* do { */ /* *d++ = *s++; */ /* } while (--n) */ /* ; */ /* */ /* v = p->base; */ /* */ /* v[ 1 ] = p->cmd; */ /* do { */ /* r = v[8/4]; */ /* } while (!(r&1)) */ /* ; */ /* return r; */ /* } */ /* ======================================== */ static const uint8_t sam4_page_write_opcodes[] = { /* 24 0000 0446 mov r4, r0 */ 0x04, 0x46, /* 25 0002 6168 ldr r1, [r4, #4] */ 0x61, 0x68, /* 26 0004 0068 ldr r0, [r0, #0] */ 0x00, 0x68, /* 27 0006 A268 ldr r2, [r4, #8] */ 0xa2, 0x68, /* 28 @ lr needed for prologue */ /* 29 .L2: */ /* 30 0008 51F8043B ldr r3, [r1], #4 */ 0x51, 0xf8, 0x04, 0x3b, /* 31 000c 12F1FF32 adds r2, r2, #-1 */ 0x12, 0xf1, 0xff, 0x32, /* 32 0010 40F8043B str r3, [r0], #4 */ 0x40, 0xf8, 0x04, 0x3b, /* 33 0014 F8D1 bne .L2 */ 0xf8, 0xd1, /* 34 0016 E268 ldr r2, [r4, #12] */ 0xe2, 0x68, /* 35 0018 2369 ldr r3, [r4, #16] */ 0x23, 0x69, /* 36 001a 5360 str r3, [r2, #4] */ 0x53, 0x60, /* 37 001c 0832 adds r2, r2, #8 */ 0x08, 0x32, /* 38 .L4: */ /* 39 001e 1068 ldr r0, [r2, #0] */ 0x10, 0x68, /* 40 0020 10F0010F tst r0, #1 */ 0x10, 0xf0, 0x01, 0x0f, /* 41 0024 FBD0 beq .L4 */ 0xfb, 0xd0, 0x00, 0xBE /* bkpt #0 */ }; static int sam4_page_write(struct sam4_bank_private *pPrivate, unsigned pagenum, uint8_t *buf) { uint32_t adr; uint32_t status; uint32_t fmr; /* EEFC Flash Mode Register */ int r; adr = pagenum * pPrivate->page_size; adr = (adr + pPrivate->base_address); /* Get flash mode register value */ r = target_read_u32(pPrivate->pChip->target, pPrivate->controller_address, &fmr); if (r != ERROR_OK) LOG_DEBUG("Error Read failed: read flash mode register"); /* Clear flash wait state field */ fmr &= 0xfffff0ff; /* set FWS (flash wait states) field in the FMR (flash mode register) */ fmr |= (pPrivate->flash_wait_states << 8); LOG_DEBUG("Flash Mode: 0x%08x", ((unsigned int)(fmr))); r = target_write_u32(pPrivate->pBank->target, pPrivate->controller_address, fmr); if (r != ERROR_OK) LOG_DEBUG("Error Write failed: set flash mode register"); /* 1st sector 8kBytes - page 0 - 15*/ /* 2nd sector 8kBytes - page 16 - 30*/ /* 3rd sector 48kBytes - page 31 - 127*/ LOG_DEBUG("Wr Page %u @ phys address: 0x%08x", pagenum, (unsigned int)(adr)); r = target_write_memory(pPrivate->pChip->target, adr, 4, /* THIS*MUST*BE* in 32bit values */ pPrivate->page_size / 4, buf); if (r != ERROR_OK) { LOG_ERROR("SAM4: Failed to write (buffer) page at phys address 0x%08x", (unsigned int)(adr)); return r; } r = EFC_PerformCommand(pPrivate, /* send Erase & Write Page */ AT91C_EFC_FCMD_WP, /*AT91C_EFC_FCMD_EWP only works on first two 8kb sectors*/ pagenum, &status); if (r != ERROR_OK) LOG_ERROR("SAM4: Error performing Write page @ phys address 0x%08x", (unsigned int)(adr)); if (status & (1 << 2)) { LOG_ERROR("SAM4: Page @ Phys address 0x%08x is locked", (unsigned int)(adr)); return ERROR_FAIL; } if (status & (1 << 1)) { LOG_ERROR("SAM4: Flash Command error @phys address 0x%08x", (unsigned int)(adr)); return ERROR_FAIL; } return ERROR_OK; } static int sam4_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { int n; unsigned page_cur; unsigned page_end; int r; unsigned page_offset; struct sam4_bank_private *pPrivate; uint8_t *pagebuffer; /* incase we bail further below, set this to null */ pagebuffer = NULL; /* ignore dumb requests */ if (count == 0) { r = ERROR_OK; goto done; } if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); r = ERROR_TARGET_NOT_HALTED; goto done; } pPrivate = get_sam4_bank_private(bank); if (!(pPrivate->probed)) { r = ERROR_FLASH_BANK_NOT_PROBED; goto done; } if ((offset + count) > pPrivate->size_bytes) { LOG_ERROR("Flash write error - past end of bank"); LOG_ERROR(" offset: 0x%08x, count 0x%08x, BankEnd: 0x%08x", (unsigned int)(offset), (unsigned int)(count), (unsigned int)(pPrivate->size_bytes)); r = ERROR_FAIL; goto done; } pagebuffer = malloc(pPrivate->page_size); if (!pagebuffer) { LOG_ERROR("No memory for %d Byte page buffer", (int)(pPrivate->page_size)); r = ERROR_FAIL; goto done; } /* what page do we start & end in? */ page_cur = offset / pPrivate->page_size; page_end = (offset + count - 1) / pPrivate->page_size; LOG_DEBUG("Offset: 0x%08x, Count: 0x%08x", (unsigned int)(offset), (unsigned int)(count)); LOG_DEBUG("Page start: %d, Page End: %d", (int)(page_cur), (int)(page_end)); /* Special case: all one page */ /* */ /* Otherwise: */ /* (1) non-aligned start */ /* (2) body pages */ /* (3) non-aligned end. */ /* Handle special case - all one page. */ if (page_cur == page_end) { LOG_DEBUG("Special case, all in one page"); r = sam4_page_read(pPrivate, page_cur, pagebuffer); if (r != ERROR_OK) goto done; page_offset = (offset & (pPrivate->page_size-1)); memcpy(pagebuffer + page_offset, buffer, count); r = sam4_page_write(pPrivate, page_cur, pagebuffer); if (r != ERROR_OK) goto done; r = ERROR_OK; goto done; } /* non-aligned start */ page_offset = offset & (pPrivate->page_size - 1); if (page_offset) { LOG_DEBUG("Not-Aligned start"); /* read the partial */ r = sam4_page_read(pPrivate, page_cur, pagebuffer); if (r != ERROR_OK) goto done; /* over-write with new data */ n = (pPrivate->page_size - page_offset); memcpy(pagebuffer + page_offset, buffer, n); r = sam4_page_write(pPrivate, page_cur, pagebuffer); if (r != ERROR_OK) goto done; count -= n; offset += n; buffer += n; page_cur++; } /* By checking that offset is correct here, we also fix a clang warning */ assert(offset % pPrivate->page_size == 0); /* intermediate large pages */ /* also - the final *terminal* */ /* if that terminal page is a full page */ LOG_DEBUG("Full Page Loop: cur=%d, end=%d, count = 0x%08x", (int)page_cur, (int)page_end, (unsigned int)(count)); while ((page_cur < page_end) && (count >= pPrivate->page_size)) { r = sam4_page_write(pPrivate, page_cur, buffer); if (r != ERROR_OK) goto done; count -= pPrivate->page_size; buffer += pPrivate->page_size; page_cur += 1; } /* terminal partial page? */ if (count) { LOG_DEBUG("Terminal partial page, count = 0x%08x", (unsigned int)(count)); /* we have a partial page */ r = sam4_page_read(pPrivate, page_cur, pagebuffer); if (r != ERROR_OK) goto done; /* data goes at start */ memcpy(pagebuffer, buffer, count); r = sam4_page_write(pPrivate, page_cur, pagebuffer); if (r != ERROR_OK) goto done; } LOG_DEBUG("Done!"); r = ERROR_OK; done: if (pagebuffer) free(pagebuffer); return r; } COMMAND_HANDLER(sam4_handle_info_command) { struct sam4_chip *pChip; pChip = get_current_sam4(CMD_CTX); if (!pChip) return ERROR_OK; unsigned x; int r; /* bank0 must exist before we can do anything */ if (pChip->details.bank[0].pBank == NULL) { x = 0; need_define: command_print(CMD_CTX, "Please define bank %d via command: flash bank %s ... ", x, at91sam4_flash.name); return ERROR_FAIL; } /* if bank 0 is not probed, then probe it */ if (!(pChip->details.bank[0].probed)) { r = sam4_auto_probe(pChip->details.bank[0].pBank); if (r != ERROR_OK) return ERROR_FAIL; } /* above guarantees the "chip details" structure is valid */ /* and thus, bank private areas are valid */ /* and we have a SAM4 chip, what a concept! */ /* auto-probe other banks, 0 done above */ for (x = 1; x < SAM4_MAX_FLASH_BANKS; x++) { /* skip banks not present */ if (!(pChip->details.bank[x].present)) continue; if (pChip->details.bank[x].pBank == NULL) goto need_define; if (pChip->details.bank[x].probed) continue; r = sam4_auto_probe(pChip->details.bank[x].pBank); if (r != ERROR_OK) return r; } r = sam4_GetInfo(pChip); if (r != ERROR_OK) { LOG_DEBUG("Sam4Info, Failed %d", r); return r; } return ERROR_OK; } COMMAND_HANDLER(sam4_handle_gpnvm_command) { unsigned x, v; int r, who; struct sam4_chip *pChip; pChip = get_current_sam4(CMD_CTX); if (!pChip) return ERROR_OK; if (pChip->target->state != TARGET_HALTED) { LOG_ERROR("sam4 - target not halted"); return ERROR_TARGET_NOT_HALTED; } if (pChip->details.bank[0].pBank == NULL) { command_print(CMD_CTX, "Bank0 must be defined first via: flash bank %s ...", at91sam4_flash.name); return ERROR_FAIL; } if (!pChip->details.bank[0].probed) { r = sam4_auto_probe(pChip->details.bank[0].pBank); if (r != ERROR_OK) return r; } switch (CMD_ARGC) { default: return ERROR_COMMAND_SYNTAX_ERROR; break; case 0: goto showall; break; case 1: who = -1; break; case 2: if ((0 == strcmp(CMD_ARGV[0], "show")) && (0 == strcmp(CMD_ARGV[1], "all"))) who = -1; else { uint32_t v32; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], v32); who = v32; } break; } if (0 == strcmp("show", CMD_ARGV[0])) { if (who == -1) { showall: r = ERROR_OK; for (x = 0; x < pChip->details.n_gpnvms; x++) { r = FLASHD_GetGPNVM(&(pChip->details.bank[0]), x, &v); if (r != ERROR_OK) break; command_print(CMD_CTX, "sam4-gpnvm%u: %u", x, v); } return r; } if ((who >= 0) && (((unsigned)(who)) < pChip->details.n_gpnvms)) { r = FLASHD_GetGPNVM(&(pChip->details.bank[0]), who, &v); command_print(CMD_CTX, "sam4-gpnvm%u: %u", who, v); return r; } else { command_print(CMD_CTX, "sam4-gpnvm invalid GPNVM: %u", who); return ERROR_COMMAND_SYNTAX_ERROR; } } if (who == -1) { command_print(CMD_CTX, "Missing GPNVM number"); return ERROR_COMMAND_SYNTAX_ERROR; } if (0 == strcmp("set", CMD_ARGV[0])) r = FLASHD_SetGPNVM(&(pChip->details.bank[0]), who); else if ((0 == strcmp("clr", CMD_ARGV[0])) || (0 == strcmp("clear", CMD_ARGV[0]))) /* quietly accept both */ r = FLASHD_ClrGPNVM(&(pChip->details.bank[0]), who); else { command_print(CMD_CTX, "Unknown command: %s", CMD_ARGV[0]); r = ERROR_COMMAND_SYNTAX_ERROR; } return r; } COMMAND_HANDLER(sam4_handle_slowclk_command) { struct sam4_chip *pChip; pChip = get_current_sam4(CMD_CTX); if (!pChip) return ERROR_OK; switch (CMD_ARGC) { case 0: /* show */ break; case 1: { /* set */ uint32_t v; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], v); if (v > 200000) { /* absurd slow clock of 200Khz? */ command_print(CMD_CTX, "Absurd/illegal slow clock freq: %d\n", (int)(v)); return ERROR_COMMAND_SYNTAX_ERROR; } pChip->cfg.slow_freq = v; break; } default: /* error */ command_print(CMD_CTX, "Too many parameters"); return ERROR_COMMAND_SYNTAX_ERROR; break; } command_print(CMD_CTX, "Slowclk freq: %d.%03dkhz", (int)(pChip->cfg.slow_freq / 1000), (int)(pChip->cfg.slow_freq % 1000)); return ERROR_OK; } static const struct command_registration at91sam4_exec_command_handlers[] = { { .name = "gpnvm", .handler = sam4_handle_gpnvm_command, .mode = COMMAND_EXEC, .usage = "[('clr'|'set'|'show') bitnum]", .help = "Without arguments, shows all bits in the gpnvm " "register. Otherwise, clears, sets, or shows one " "General Purpose Non-Volatile Memory (gpnvm) bit.", }, { .name = "info", .handler = sam4_handle_info_command, .mode = COMMAND_EXEC, .help = "Print information about the current at91sam4 chip" "and its flash configuration.", }, { .name = "slowclk", .handler = sam4_handle_slowclk_command, .mode = COMMAND_EXEC, .usage = "[clock_hz]", .help = "Display or set the slowclock frequency " "(default 32768 Hz).", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration at91sam4_command_handlers[] = { { .name = "at91sam4", .mode = COMMAND_ANY, .help = "at91sam4 flash command group", .usage = "", .chain = at91sam4_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct flash_driver at91sam4_flash = { .name = "at91sam4", .commands = at91sam4_command_handlers, .flash_bank_command = sam4_flash_bank_command, .erase = sam4_erase, .protect = sam4_protect, .write = sam4_write, .read = default_flash_read, .probe = sam4_probe, .auto_probe = sam4_auto_probe, .erase_check = default_flash_blank_check, .protect_check = sam4_protect_check, .info = sam4_info, }; openocd-0.7.0/src/flash/nor/at91sam7.c0000644000175000001440000010302612134336410014255 00000000000000/*************************************************************************** * Copyright (C) 2006 by Magnus Lundin * * lundin@mlu.mine.nu * * * * Copyright (C) 2008 by Gheorghe Guran (atlas) * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General public License as published by * * the Free Software Foundation; either version 2 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. * ****************************************************************************/ /*************************************************************************** * * New flash setup command: * * flash bank * [ * * * ] * * - MUST be used if clock is from external source, * CAN be used if main oscillator frequency is known (recommended) * Examples: * ==== RECOMMENDED (covers clock speed) ============ * flash bank at91sam7 0x00100000 0 0 4 $_TARGETNAME AT91SAM7XC256 1 16 64 256 3 25000 * (if auto-detect fails; provides clock spec) * flash bank at91sam7 0 0 0 0 $_TARGETNAME 0 0 0 0 0 0 25000 * (auto-detect everything except the clock) * ==== NOT RECOMMENDED !!! (clock speed is not configured) ==== * flash bank at91sam7 0x00100000 0 0 4 $_TARGETNAME AT91SAM7XC256 1 16 64 256 3 0 * (if auto-detect fails) * flash bank at91sam7 0 0 0 0 $_TARGETNAME * (old style, auto-detect everything) ****************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include /* AT91SAM7 control registers */ #define DBGU_CIDR 0xFFFFF240 #define CKGR_MCFR 0xFFFFFC24 #define CKGR_MOR 0xFFFFFC20 #define CKGR_MCFR_MAINRDY 0x10000 #define CKGR_PLLR 0xFFFFFC2c #define CKGR_PLLR_DIV 0xff #define CKGR_PLLR_MUL 0x07ff0000 #define PMC_MCKR 0xFFFFFC30 #define PMC_MCKR_CSS 0x03 #define PMC_MCKR_PRES 0x1c /* Flash Controller Commands */ #define WP 0x01 #define SLB 0x02 #define WPL 0x03 #define CLB 0x04 #define EA 0x08 #define SGPB 0x0B #define CGPB 0x0D #define SSB 0x0F /* MC_FSR bit definitions */ #define MC_FSR_FRDY 1 #define MC_FSR_EOL 2 /* AT91SAM7 constants */ #define RC_FREQ 32000 /* Flash timing modes */ #define FMR_TIMING_NONE 0 #define FMR_TIMING_NVBITS 1 #define FMR_TIMING_FLASH 2 /* Flash size constants */ #define FLASH_SIZE_8KB 1 #define FLASH_SIZE_16KB 2 #define FLASH_SIZE_32KB 3 #define FLASH_SIZE_64KB 5 #define FLASH_SIZE_128KB 7 #define FLASH_SIZE_256KB 9 #define FLASH_SIZE_512KB 10 #define FLASH_SIZE_1024KB 12 #define FLASH_SIZE_2048KB 14 static int at91sam7_protect_check(struct flash_bank *bank); static int at91sam7_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count); static uint32_t at91sam7_get_flash_status(struct target *target, int bank_number); static void at91sam7_set_flash_mode(struct flash_bank *bank, int mode); static uint32_t at91sam7_wait_status_busy(struct flash_bank *bank, uint32_t waitbits, int timeout); static int at91sam7_flash_command(struct flash_bank *bank, uint8_t cmd, uint16_t pagen); static uint32_t MC_FMR[4] = { 0xFFFFFF60, 0xFFFFFF70, 0xFFFFFF80, 0xFFFFFF90 }; static uint32_t MC_FCR[4] = { 0xFFFFFF64, 0xFFFFFF74, 0xFFFFFF84, 0xFFFFFF94 }; static uint32_t MC_FSR[4] = { 0xFFFFFF68, 0xFFFFFF78, 0xFFFFFF88, 0xFFFFFF98 }; static char *EPROC[8] = { "Unknown", "ARM946-E", "ARM7TDMI", "Unknown", "ARM920T", "ARM926EJ-S", "Unknown", "Unknown" }; struct at91sam7_flash_bank { /* chip id register */ uint32_t cidr; uint16_t cidr_ext; uint16_t cidr_nvptyp; uint16_t cidr_arch; uint16_t cidr_sramsiz; uint16_t cidr_nvpsiz; uint16_t cidr_nvpsiz2; uint16_t cidr_eproc; uint16_t cidr_version; const char *target_name; /* flash auto-detection */ uint8_t flash_autodetection; /* flash geometry */ uint16_t pages_per_sector; uint16_t pagesize; uint16_t pages_in_lockregion; /* nv memory bits */ uint16_t num_lockbits_on; uint16_t lockbits; uint16_t num_nvmbits; uint16_t num_nvmbits_on; uint16_t nvmbits; uint8_t securitybit; /* 0: not init * 1: fmcn for nvbits (1uS) * 2: fmcn for flash (1.5uS) */ uint8_t flashmode; /* main clock status */ uint8_t mck_valid; uint32_t mck_freq; /* external clock frequency */ uint32_t ext_freq; }; #if 0 static long SRAMSIZ[16] = { -1, 0x0400, /* 1K */ 0x0800, /* 2K */ -1, 0x1c000, /* 112K */ 0x1000, /* 4K */ 0x14000, /* 80K */ 0x28000, /* 160K */ 0x2000, /* 8K */ 0x4000, /* 16K */ 0x8000, /* 32K */ 0x10000, /* 64K */ 0x20000, /* 128K */ 0x40000, /* 256K */ 0x18000, /* 96K */ 0x80000, /* 512K */ }; #endif static uint32_t at91sam7_get_flash_status(struct target *target, int bank_number) { uint32_t fsr; target_read_u32(target, MC_FSR[bank_number], &fsr); return fsr; } /* Read clock configuration and set at91sam7_info->mck_freq */ static void at91sam7_read_clock_info(struct flash_bank *bank) { struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv; struct target *target = bank->target; uint32_t mckr, mcfr, pllr, mor; unsigned long tmp = 0, mainfreq; /* Read Clock Generator Main Oscillator Register */ target_read_u32(target, CKGR_MOR, &mor); /* Read Clock Generator Main Clock Frequency Register */ target_read_u32(target, CKGR_MCFR, &mcfr); /* Read Master Clock Register*/ target_read_u32(target, PMC_MCKR, &mckr); /* Read Clock Generator PLL Register */ target_read_u32(target, CKGR_PLLR, &pllr); at91sam7_info->mck_valid = 0; at91sam7_info->mck_freq = 0; switch (mckr & PMC_MCKR_CSS) { case 0: /* Slow Clock */ at91sam7_info->mck_valid = 1; tmp = RC_FREQ; break; case 1: /* Main Clock */ if ((mcfr & CKGR_MCFR_MAINRDY) && (at91sam7_info->ext_freq == 0)) { at91sam7_info->mck_valid = 1; tmp = RC_FREQ / 16ul * (mcfr & 0xffff); } else if (at91sam7_info->ext_freq != 0) { at91sam7_info->mck_valid = 1; tmp = at91sam7_info->ext_freq; } break; case 2: /* Reserved */ break; case 3: /* PLL Clock */ if ((mcfr & CKGR_MCFR_MAINRDY) && (at91sam7_info->ext_freq == 0)) { target_read_u32(target, CKGR_PLLR, &pllr); if (!(pllr & CKGR_PLLR_DIV)) break; /* 0 Hz */ at91sam7_info->mck_valid = 1; mainfreq = RC_FREQ / 16ul * (mcfr & 0xffff); /* Integer arithmetic should have sufficient precision * as long as PLL is properly configured. */ tmp = mainfreq / (pllr & CKGR_PLLR_DIV)* (((pllr & CKGR_PLLR_MUL) >> 16) + 1); } else if ((at91sam7_info->ext_freq != 0) && ((pllr&CKGR_PLLR_DIV) != 0)) { at91sam7_info->mck_valid = 1; tmp = at91sam7_info->ext_freq / (pllr&CKGR_PLLR_DIV)* (((pllr & CKGR_PLLR_MUL) >> 16) + 1); } break; } /* Prescaler adjust */ if ((((mckr & PMC_MCKR_PRES) >> 2) == 7) || (tmp == 0)) { at91sam7_info->mck_valid = 0; at91sam7_info->mck_freq = 0; } else if (((mckr & PMC_MCKR_PRES) >> 2) != 0) at91sam7_info->mck_freq = tmp >> ((mckr & PMC_MCKR_PRES) >> 2); else at91sam7_info->mck_freq = tmp; } /* Setup the timimg registers for nvbits or normal flash */ static void at91sam7_set_flash_mode(struct flash_bank *bank, int mode) { uint32_t fmr, fmcn = 0, fws = 0; struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv; struct target *target = bank->target; if (mode && (mode != at91sam7_info->flashmode)) { /* Always round up (ceil) */ if (mode == FMR_TIMING_NVBITS) { if (at91sam7_info->cidr_arch == 0x60) { /* AT91SAM7A3 uses master clocks in 100 ns */ fmcn = (at91sam7_info->mck_freq/10000000ul) + 1; } else { /* master clocks in 1uS for ARCH 0x7 types */ fmcn = (at91sam7_info->mck_freq/1000000ul) + 1; } } else if (mode == FMR_TIMING_FLASH) { /* main clocks in 1.5uS */ fmcn = (at91sam7_info->mck_freq/1000000ul)+ (at91sam7_info->mck_freq/2000000ul) + 1; } /* hard overclocking */ if (fmcn > 0xFF) fmcn = 0xFF; /* Only allow fmcn = 0 if clock period is > 30 us = 33kHz. */ if (at91sam7_info->mck_freq <= 33333ul) fmcn = 0; /* Only allow fws = 0 if clock frequency is < 30 MHz. */ if (at91sam7_info->mck_freq > 30000000ul) fws = 1; LOG_DEBUG("fmcn[%i]: %i", bank->bank_number, (int)(fmcn)); fmr = fmcn << 16 | fws << 8; target_write_u32(target, MC_FMR[bank->bank_number], fmr); } at91sam7_info->flashmode = mode; } static uint32_t at91sam7_wait_status_busy(struct flash_bank *bank, uint32_t waitbits, int timeout) { uint32_t status; while ((!((status = at91sam7_get_flash_status(bank->target, bank->bank_number)) & waitbits)) && (timeout-- > 0)) { LOG_DEBUG("status[%i]: 0x%" PRIx32 "", (int)bank->bank_number, status); alive_sleep(1); } LOG_DEBUG("status[%i]: 0x%" PRIx32 "", bank->bank_number, status); if (status & 0x0C) { LOG_ERROR("status register: 0x%" PRIx32 "", status); if (status & 0x4) LOG_ERROR("Lock Error Bit Detected, Operation Abort"); if (status & 0x8) LOG_ERROR("Invalid command and/or bad keyword, Operation Abort"); if (status & 0x10) LOG_ERROR("Security Bit Set, Operation Abort"); } return status; } /* Send one command to the AT91SAM flash controller */ static int at91sam7_flash_command(struct flash_bank *bank, uint8_t cmd, uint16_t pagen) { uint32_t fcr; struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv; struct target *target = bank->target; fcr = (0x5A << 24) | ((pagen&0x3FF) << 8) | cmd; target_write_u32(target, MC_FCR[bank->bank_number], fcr); LOG_DEBUG("Flash command: 0x%" PRIx32 ", flash bank: %i, page number: %u", fcr, bank->bank_number + 1, pagen); if ((at91sam7_info->cidr_arch == 0x60) && ((cmd == SLB) | (cmd == CLB))) { /* Lock bit manipulation on AT91SAM7A3 waits for FC_FSR bit 1, EOL */ if (at91sam7_wait_status_busy(bank, MC_FSR_EOL, 10)&0x0C) return ERROR_FLASH_OPERATION_FAILED; return ERROR_OK; } if (at91sam7_wait_status_busy(bank, MC_FSR_FRDY, 10)&0x0C) return ERROR_FLASH_OPERATION_FAILED; return ERROR_OK; } /* Read device id register, main clock frequency register and fill in driver info structure */ static int at91sam7_read_part_info(struct flash_bank *bank) { struct at91sam7_flash_bank *at91sam7_info; struct target *target = bank->target; uint16_t bnk, sec; uint16_t arch; uint32_t cidr; uint8_t banks_num = 0; uint16_t num_nvmbits = 0; uint16_t sectors_num = 0; uint16_t pages_per_sector = 0; uint16_t page_size = 0; uint32_t ext_freq; uint32_t bank_size; uint32_t base_address = 0; char *target_name_t = "Unknown"; at91sam7_info = bank->driver_priv; if (at91sam7_info->cidr != 0) { /* flash already configured, update clock and check for protected sectors */ struct flash_bank *fb = bank; struct flash_bank *t_bank = bank; while (t_bank) { /* re-calculate master clock frequency */ at91sam7_read_clock_info(t_bank); /* no timming */ at91sam7_set_flash_mode(t_bank, FMR_TIMING_NONE); /* check protect state */ at91sam7_protect_check(t_bank); t_bank = fb->next; fb = t_bank; } return ERROR_OK; } /* Read and parse chip identification register */ target_read_u32(target, DBGU_CIDR, &cidr); if (cidr == 0) { LOG_WARNING("Cannot identify target as an AT91SAM"); return ERROR_FLASH_OPERATION_FAILED; } if (at91sam7_info->flash_autodetection == 0) { /* banks and sectors are already created, based on data from input file */ struct flash_bank *fb = bank; struct flash_bank *t_bank = bank; while (t_bank) { at91sam7_info = t_bank->driver_priv; at91sam7_info->cidr = cidr; at91sam7_info->cidr_ext = (cidr >> 31)&0x0001; at91sam7_info->cidr_nvptyp = (cidr >> 28)&0x0007; at91sam7_info->cidr_arch = (cidr >> 20)&0x00FF; at91sam7_info->cidr_sramsiz = (cidr >> 16)&0x000F; at91sam7_info->cidr_nvpsiz2 = (cidr >> 12)&0x000F; at91sam7_info->cidr_nvpsiz = (cidr >> 8)&0x000F; at91sam7_info->cidr_eproc = (cidr >> 5)&0x0007; at91sam7_info->cidr_version = cidr&0x001F; /* calculate master clock frequency */ at91sam7_read_clock_info(t_bank); /* no timming */ at91sam7_set_flash_mode(t_bank, FMR_TIMING_NONE); /* check protect state */ at91sam7_protect_check(t_bank); t_bank = fb->next; fb = t_bank; } return ERROR_OK; } arch = (cidr >> 20)&0x00FF; /* check flash size */ switch ((cidr >> 8)&0x000F) { case FLASH_SIZE_8KB: break; case FLASH_SIZE_16KB: banks_num = 1; sectors_num = 8; pages_per_sector = 32; page_size = 64; base_address = 0x00100000; if (arch == 0x70) { num_nvmbits = 2; target_name_t = "AT91SAM7S161/16"; } break; case FLASH_SIZE_32KB: banks_num = 1; sectors_num = 8; pages_per_sector = 32; page_size = 128; base_address = 0x00100000; if (arch == 0x70) { num_nvmbits = 2; target_name_t = "AT91SAM7S321/32"; } if (arch == 0x72) { num_nvmbits = 3; target_name_t = "AT91SAM7SE32"; } break; case FLASH_SIZE_64KB: banks_num = 1; sectors_num = 16; pages_per_sector = 32; page_size = 128; base_address = 0x00100000; if (arch == 0x70) { num_nvmbits = 2; target_name_t = "AT91SAM7S64"; } break; case FLASH_SIZE_128KB: banks_num = 1; sectors_num = 8; pages_per_sector = 64; page_size = 256; base_address = 0x00100000; if (arch == 0x70) { num_nvmbits = 2; target_name_t = "AT91SAM7S128"; } if (arch == 0x71) { num_nvmbits = 3; target_name_t = "AT91SAM7XC128"; } if (arch == 0x72) { num_nvmbits = 3; target_name_t = "AT91SAM7SE128"; } if (arch == 0x75) { num_nvmbits = 3; target_name_t = "AT91SAM7X128"; } break; case FLASH_SIZE_256KB: banks_num = 1; sectors_num = 16; pages_per_sector = 64; page_size = 256; base_address = 0x00100000; if (arch == 0x60) { num_nvmbits = 3; target_name_t = "AT91SAM7A3"; } if (arch == 0x70) { num_nvmbits = 2; target_name_t = "AT91SAM7S256"; } if (arch == 0x71) { num_nvmbits = 3; target_name_t = "AT91SAM7XC256"; } if (arch == 0x72) { num_nvmbits = 3; target_name_t = "AT91SAM7SE256"; } if (arch == 0x75) { num_nvmbits = 3; target_name_t = "AT91SAM7X256"; } break; case FLASH_SIZE_512KB: banks_num = 2; sectors_num = 16; pages_per_sector = 64; page_size = 256; base_address = 0x00100000; if (arch == 0x70) { num_nvmbits = 2; target_name_t = "AT91SAM7S512"; } if (arch == 0x71) { num_nvmbits = 3; target_name_t = "AT91SAM7XC512"; } if (arch == 0x72) { num_nvmbits = 3; target_name_t = "AT91SAM7SE512"; } if (arch == 0x75) { num_nvmbits = 3; target_name_t = "AT91SAM7X512"; } break; case FLASH_SIZE_1024KB: break; case FLASH_SIZE_2048KB: break; } if (strcmp(target_name_t, "Unknown") == 0) { LOG_ERROR( "Target autodetection failed! Please specify target parameters in configuration file"); return ERROR_FLASH_OPERATION_FAILED; } ext_freq = at91sam7_info->ext_freq; /* calculate bank size */ bank_size = sectors_num * pages_per_sector * page_size; for (bnk = 0; bnk < banks_num; bnk++) { struct flash_bank *t_bank = bank; if (bnk > 0) { if (!t_bank->next) { /* create a new flash bank element */ struct flash_bank *fb = malloc(sizeof(struct flash_bank)); fb->target = target; fb->driver = bank->driver; fb->driver_priv = malloc(sizeof(struct at91sam7_flash_bank)); fb->name = "sam7_probed"; fb->next = NULL; /* link created bank in 'flash_banks' list */ t_bank->next = fb; } t_bank = t_bank->next; } t_bank->bank_number = bnk; t_bank->base = base_address + bnk * bank_size; t_bank->size = bank_size; t_bank->chip_width = 0; t_bank->bus_width = 4; t_bank->num_sectors = sectors_num; /* allocate sectors */ t_bank->sectors = malloc(sectors_num * sizeof(struct flash_sector)); for (sec = 0; sec < sectors_num; sec++) { t_bank->sectors[sec].offset = sec * pages_per_sector * page_size; t_bank->sectors[sec].size = pages_per_sector * page_size; t_bank->sectors[sec].is_erased = -1; t_bank->sectors[sec].is_protected = -1; } at91sam7_info = t_bank->driver_priv; at91sam7_info->cidr = cidr; at91sam7_info->cidr_ext = (cidr >> 31)&0x0001; at91sam7_info->cidr_nvptyp = (cidr >> 28)&0x0007; at91sam7_info->cidr_arch = (cidr >> 20)&0x00FF; at91sam7_info->cidr_sramsiz = (cidr >> 16)&0x000F; at91sam7_info->cidr_nvpsiz2 = (cidr >> 12)&0x000F; at91sam7_info->cidr_nvpsiz = (cidr >> 8)&0x000F; at91sam7_info->cidr_eproc = (cidr >> 5)&0x0007; at91sam7_info->cidr_version = cidr&0x001F; at91sam7_info->target_name = target_name_t; at91sam7_info->flashmode = 0; at91sam7_info->ext_freq = ext_freq; at91sam7_info->num_nvmbits = num_nvmbits; at91sam7_info->num_nvmbits_on = 0; at91sam7_info->pagesize = page_size; at91sam7_info->pages_per_sector = pages_per_sector; /* calculate master clock frequency */ at91sam7_read_clock_info(t_bank); /* no timming */ at91sam7_set_flash_mode(t_bank, FMR_TIMING_NONE); /* check protect state */ at91sam7_protect_check(t_bank); } LOG_DEBUG("nvptyp: 0x%3.3x, arch: 0x%4.4x", at91sam7_info->cidr_nvptyp, at91sam7_info->cidr_arch); return ERROR_OK; } static int at91sam7_erase_check(struct flash_bank *bank) { struct target *target = bank->target; uint16_t retval; uint32_t blank; uint16_t fast_check; uint8_t *buffer; uint16_t nSector; uint16_t nByte; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Configure the flash controller timing */ at91sam7_read_clock_info(bank); at91sam7_set_flash_mode(bank, FMR_TIMING_FLASH); fast_check = 1; for (nSector = 0; nSector < bank->num_sectors; nSector++) { retval = target_blank_check_memory(target, bank->base + bank->sectors[nSector].offset, bank->sectors[nSector].size, &blank); if (retval != ERROR_OK) { fast_check = 0; break; } if (blank == 0xFF) bank->sectors[nSector].is_erased = 1; else bank->sectors[nSector].is_erased = 0; } if (fast_check) return ERROR_OK; LOG_USER("Running slow fallback erase check - add working memory"); buffer = malloc(bank->sectors[0].size); for (nSector = 0; nSector < bank->num_sectors; nSector++) { bank->sectors[nSector].is_erased = 1; retval = target_read_memory(target, bank->base + bank->sectors[nSector].offset, 4, bank->sectors[nSector].size/4, buffer); if (retval != ERROR_OK) return retval; for (nByte = 0; nByte < bank->sectors[nSector].size; nByte++) { if (buffer[nByte] != 0xFF) { bank->sectors[nSector].is_erased = 0; break; } } } free(buffer); return ERROR_OK; } static int at91sam7_protect_check(struct flash_bank *bank) { uint8_t lock_pos, gpnvm_pos; uint32_t status; struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv; if (at91sam7_info->cidr == 0) return ERROR_FLASH_BANK_NOT_PROBED; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } status = at91sam7_get_flash_status(bank->target, bank->bank_number); at91sam7_info->lockbits = (status >> 16); at91sam7_info->num_lockbits_on = 0; for (lock_pos = 0; lock_pos < bank->num_sectors; lock_pos++) { if (((status >> (16 + lock_pos))&(0x0001)) == 1) { at91sam7_info->num_lockbits_on++; bank->sectors[lock_pos].is_protected = 1; } else bank->sectors[lock_pos].is_protected = 0; } /* GPNVM and SECURITY bits apply only for MC_FSR of EFC0 */ status = at91sam7_get_flash_status(bank->target, 0); at91sam7_info->securitybit = (status >> 4)&0x01; at91sam7_info->nvmbits = (status >> 8)&0xFF; at91sam7_info->num_nvmbits_on = 0; for (gpnvm_pos = 0; gpnvm_pos < at91sam7_info->num_nvmbits; gpnvm_pos++) { if (((status >> (8 + gpnvm_pos))&(0x01)) == 1) at91sam7_info->num_nvmbits_on++; } return ERROR_OK; } FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command) { struct flash_bank *t_bank = bank; struct at91sam7_flash_bank *at91sam7_info; struct target *target = t_bank->target; uint32_t base_address; uint32_t bank_size; uint32_t ext_freq = 0; int chip_width; int bus_width; int banks_num; int num_sectors; uint16_t pages_per_sector; uint16_t page_size; uint16_t num_nvmbits; char *target_name_t; int bnk, sec; at91sam7_info = malloc(sizeof(struct at91sam7_flash_bank)); t_bank->driver_priv = at91sam7_info; /* part wasn't probed for info yet */ at91sam7_info->cidr = 0; at91sam7_info->flashmode = 0; at91sam7_info->ext_freq = 0; at91sam7_info->flash_autodetection = 0; if (CMD_ARGC < 13) { at91sam7_info->flash_autodetection = 1; return ERROR_OK; } COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], base_address); COMMAND_PARSE_NUMBER(int, CMD_ARGV[3], chip_width); COMMAND_PARSE_NUMBER(int, CMD_ARGV[4], bus_width); COMMAND_PARSE_NUMBER(int, CMD_ARGV[8], banks_num); COMMAND_PARSE_NUMBER(int, CMD_ARGV[9], num_sectors); COMMAND_PARSE_NUMBER(u16, CMD_ARGV[10], pages_per_sector); COMMAND_PARSE_NUMBER(u16, CMD_ARGV[11], page_size); COMMAND_PARSE_NUMBER(u16, CMD_ARGV[12], num_nvmbits); if (CMD_ARGC == 14) { unsigned long freq; COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[13], freq); ext_freq = freq * 1000; at91sam7_info->ext_freq = ext_freq; } if ((bus_width == 0) || (banks_num == 0) || (num_sectors == 0) || (pages_per_sector == 0) || (page_size == 0) || (num_nvmbits == 0)) { at91sam7_info->flash_autodetection = 1; return ERROR_OK; } target_name_t = calloc(strlen(CMD_ARGV[7]) + 1, sizeof(char)); strcpy(target_name_t, CMD_ARGV[7]); /* calculate bank size */ bank_size = num_sectors * pages_per_sector * page_size; for (bnk = 0; bnk < banks_num; bnk++) { if (bnk > 0) { if (!t_bank->next) { /* create a new bank element */ struct flash_bank *fb = malloc(sizeof(struct flash_bank)); fb->target = target; fb->driver = bank->driver; fb->driver_priv = malloc(sizeof(struct at91sam7_flash_bank)); fb->name = "sam7_probed"; fb->next = NULL; /* link created bank in 'flash_banks' list */ t_bank->next = fb; } t_bank = t_bank->next; } t_bank->bank_number = bnk; t_bank->base = base_address + bnk * bank_size; t_bank->size = bank_size; t_bank->chip_width = chip_width; t_bank->bus_width = bus_width; t_bank->num_sectors = num_sectors; /* allocate sectors */ t_bank->sectors = malloc(num_sectors * sizeof(struct flash_sector)); for (sec = 0; sec < num_sectors; sec++) { t_bank->sectors[sec].offset = sec * pages_per_sector * page_size; t_bank->sectors[sec].size = pages_per_sector * page_size; t_bank->sectors[sec].is_erased = -1; t_bank->sectors[sec].is_protected = -1; } at91sam7_info = t_bank->driver_priv; at91sam7_info->target_name = target_name_t; at91sam7_info->flashmode = 0; at91sam7_info->ext_freq = ext_freq; at91sam7_info->num_nvmbits = num_nvmbits; at91sam7_info->num_nvmbits_on = 0; at91sam7_info->pagesize = page_size; at91sam7_info->pages_per_sector = pages_per_sector; } return ERROR_OK; } static int at91sam7_erase(struct flash_bank *bank, int first, int last) { struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv; int sec; uint32_t nbytes, pos; uint8_t *buffer; uint8_t erase_all; if (at91sam7_info->cidr == 0) return ERROR_FLASH_BANK_NOT_PROBED; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if ((first < 0) || (last < first) || (last >= bank->num_sectors)) return ERROR_FLASH_SECTOR_INVALID; erase_all = 0; if ((first == 0) && (last == (bank->num_sectors-1))) erase_all = 1; /* Configure the flash controller timing */ at91sam7_read_clock_info(bank); at91sam7_set_flash_mode(bank, FMR_TIMING_FLASH); if (erase_all) { if (at91sam7_flash_command(bank, EA, 0) != ERROR_OK) return ERROR_FLASH_OPERATION_FAILED; } else { /* allocate and clean buffer */ nbytes = (last - first + 1) * bank->sectors[first].size; buffer = malloc(nbytes * sizeof(uint8_t)); for (pos = 0; pos < nbytes; pos++) buffer[pos] = 0xFF; if (at91sam7_write(bank, buffer, bank->sectors[first].offset, nbytes) != ERROR_OK) { free(buffer); return ERROR_FLASH_OPERATION_FAILED; } free(buffer); } /* mark erased sectors */ for (sec = first; sec <= last; sec++) bank->sectors[sec].is_erased = 1; return ERROR_OK; } static int at91sam7_protect(struct flash_bank *bank, int set, int first, int last) { uint32_t cmd; int sector; uint32_t pagen; struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv; if (at91sam7_info->cidr == 0) return ERROR_FLASH_BANK_NOT_PROBED; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if ((first < 0) || (last < first) || (last >= bank->num_sectors)) return ERROR_FLASH_SECTOR_INVALID; /* Configure the flash controller timing */ at91sam7_read_clock_info(bank); at91sam7_set_flash_mode(bank, FMR_TIMING_NVBITS); for (sector = first; sector <= last; sector++) { if (set) cmd = SLB; else cmd = CLB; /* if we lock a page from one sector then entire sector will be locked, also, * if we unlock a page from a locked sector, entire sector will be unlocked */ pagen = sector * at91sam7_info->pages_per_sector; if (at91sam7_flash_command(bank, cmd, pagen) != ERROR_OK) return ERROR_FLASH_OPERATION_FAILED; } at91sam7_protect_check(bank); return ERROR_OK; } static int at91sam7_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { int retval; struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv; struct target *target = bank->target; uint32_t dst_min_alignment, wcount, bytes_remaining = count; uint32_t first_page, last_page, pagen, buffer_pos; if (at91sam7_info->cidr == 0) return ERROR_FLASH_BANK_NOT_PROBED; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset + count > bank->size) return ERROR_FLASH_DST_OUT_OF_BANK; dst_min_alignment = at91sam7_info->pagesize; if (offset % dst_min_alignment) { LOG_WARNING("offset 0x%" PRIx32 " breaks required alignment 0x%" PRIx32 "", offset, dst_min_alignment); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } if (at91sam7_info->cidr_arch == 0) return ERROR_FLASH_BANK_NOT_PROBED; first_page = offset/dst_min_alignment; last_page = DIV_ROUND_UP(offset + count, dst_min_alignment); LOG_DEBUG("first_page: %i, last_page: %i, count %i", (int)first_page, (int)last_page, (int)count); /* Configure the flash controller timing */ at91sam7_read_clock_info(bank); at91sam7_set_flash_mode(bank, FMR_TIMING_FLASH); for (pagen = first_page; pagen < last_page; pagen++) { if (bytes_remaining < dst_min_alignment) count = bytes_remaining; else count = dst_min_alignment; bytes_remaining -= count; /* Write one block to the PageWriteBuffer */ buffer_pos = (pagen-first_page)*dst_min_alignment; wcount = DIV_ROUND_UP(count, 4); retval = target_write_memory(target, bank->base + pagen*dst_min_alignment, 4, wcount, buffer + buffer_pos); if (retval != ERROR_OK) return retval; /* Send Write Page command to Flash Controller */ if (at91sam7_flash_command(bank, WP, pagen) != ERROR_OK) return ERROR_FLASH_OPERATION_FAILED; LOG_DEBUG("Write flash bank:%i page number:%" PRIi32 "", bank->bank_number, pagen); } return ERROR_OK; } static int at91sam7_probe(struct flash_bank *bank) { /* we can't probe on an at91sam7 * if this is an at91sam7, it has the configured flash */ int retval; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } retval = at91sam7_read_part_info(bank); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int get_at91sam7_info(struct flash_bank *bank, char *buf, int buf_size) { int printed; struct at91sam7_flash_bank *at91sam7_info = bank->driver_priv; if (at91sam7_info->cidr == 0) return ERROR_FLASH_BANK_NOT_PROBED; printed = snprintf(buf, buf_size, "\n at91sam7 driver information: Chip is %s\n", at91sam7_info->target_name); buf += printed; buf_size -= printed; printed = snprintf(buf, buf_size, " Cidr: 0x%8.8" PRIx32 " | Arch: 0x%4.4x | Eproc: %s | Version: 0x%3.3x | " "Flashsize: 0x%8.8" PRIx32 "\n", at91sam7_info->cidr, at91sam7_info->cidr_arch, EPROC[at91sam7_info->cidr_eproc], at91sam7_info->cidr_version, bank->size); buf += printed; buf_size -= printed; printed = snprintf(buf, buf_size, " Master clock (estimated): %u KHz | External clock: %u KHz\n", (unsigned)(at91sam7_info->mck_freq / 1000), (unsigned)(at91sam7_info->ext_freq / 1000)); buf += printed; buf_size -= printed; printed = snprintf(buf, buf_size, " Pagesize: %i bytes | Lockbits(%i): %i 0x%4.4x | Pages in lock region: %i\n", at91sam7_info->pagesize, bank->num_sectors, at91sam7_info->num_lockbits_on, at91sam7_info->lockbits, at91sam7_info->pages_per_sector*at91sam7_info->num_lockbits_on); buf += printed; buf_size -= printed; snprintf(buf, buf_size, " Securitybit: %i | Nvmbits(%i): %i 0x%1.1x\n", at91sam7_info->securitybit, at91sam7_info->num_nvmbits, at91sam7_info->num_nvmbits_on, at91sam7_info->nvmbits); return ERROR_OK; } /* * On AT91SAM7S: When the gpnvm bits are set with * > at91sam7 gpnvm bitnr set * the changes are not visible in the flash controller status register MC_FSR * until the processor has been reset. * On the Olimex board this requires a power cycle. * Note that the AT91SAM7S has the following errata (doc6175.pdf sec 14.1.3): * The maximum number of write/erase cycles for Non volatile Memory bits is 100. this includes * Lock Bits (LOCKx), General Purpose NVM bits (GPNVMx) and the Security Bit. */ COMMAND_HANDLER(at91sam7_handle_gpnvm_command) { struct flash_bank *bank; int bit; uint8_t flashcmd; uint32_t status; struct at91sam7_flash_bank *at91sam7_info; int retval; if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; bank = get_flash_bank_by_num_noprobe(0); if (bank == NULL) return ERROR_FLASH_BANK_INVALID; if (strcmp(bank->driver->name, "at91sam7")) { command_print(CMD_CTX, "not an at91sam7 flash bank '%s'", CMD_ARGV[0]); return ERROR_FLASH_BANK_INVALID; } if (bank->target->state != TARGET_HALTED) { LOG_ERROR("target has to be halted to perform flash operation"); return ERROR_TARGET_NOT_HALTED; } if (strcmp(CMD_ARGV[1], "set") == 0) flashcmd = SGPB; else if (strcmp(CMD_ARGV[1], "clear") == 0) flashcmd = CGPB; else return ERROR_COMMAND_SYNTAX_ERROR; at91sam7_info = bank->driver_priv; if (at91sam7_info->cidr == 0) { retval = at91sam7_read_part_info(bank); if (retval != ERROR_OK) return retval; } COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], bit); if ((bit < 0) || (bit >= at91sam7_info->num_nvmbits)) { command_print(CMD_CTX, "gpnvm bit '#%s' is out of bounds for target %s", CMD_ARGV[0], at91sam7_info->target_name); return ERROR_OK; } /* Configure the flash controller timing */ at91sam7_read_clock_info(bank); at91sam7_set_flash_mode(bank, FMR_TIMING_NVBITS); if (at91sam7_flash_command(bank, flashcmd, bit) != ERROR_OK) return ERROR_FLASH_OPERATION_FAILED; /* GPNVM and SECURITY bits apply only for MC_FSR of EFC0 */ status = at91sam7_get_flash_status(bank->target, 0); LOG_DEBUG("at91sam7_handle_gpnvm_command: cmd 0x%x, value %d, status 0x%" PRIx32, flashcmd, bit, status); /* check protect state */ at91sam7_protect_check(bank); return ERROR_OK; } static const struct command_registration at91sam7_exec_command_handlers[] = { { .name = "gpnvm", .handler = at91sam7_handle_gpnvm_command, .mode = COMMAND_EXEC, .help = "set or clear one General Purpose Non-Volatile Memory " "(gpnvm) bit", .usage = "bitnum ('set'|'clear')", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration at91sam7_command_handlers[] = { { .name = "at91sam7", .mode = COMMAND_ANY, .help = "at91sam7 flash command group", .usage = "", .chain = at91sam7_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct flash_driver at91sam7_flash = { .name = "at91sam7", .usage = "gpnvm ", .commands = at91sam7_command_handlers, .flash_bank_command = at91sam7_flash_bank_command, .erase = at91sam7_erase, .protect = at91sam7_protect, .write = at91sam7_write, .read = default_flash_read, .probe = at91sam7_probe, .auto_probe = at91sam7_probe, .erase_check = at91sam7_erase_check, .protect_check = at91sam7_protect_check, .info = get_at91sam7_info, }; openocd-0.7.0/src/flash/nor/non_cfi.h0000644000175000001440000000341712134336410014332 00000000000000/*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef NON_CFI_H #define NON_CFI_H struct non_cfi { uint16_t mfr; uint16_t id; uint16_t pri_id; uint32_t dev_size; uint16_t interface_desc; uint16_t max_buf_write_size; uint8_t num_erase_regions; uint32_t erase_region_info[6]; uint8_t status_poll_mask; }; void cfi_fixup_non_cfi(struct flash_bank *bank); #endif /* NON_CFI_H */ openocd-0.7.0/src/flash/nor/pic32mx.c0000644000175000001440000006505412134336410014204 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2008 by John McCarthy * * jgmcc@magma.ca * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "imp.h" #include #include #include #define PIC32MX_MANUF_ID 0x029 /* pic32mx memory locations */ #define PIC32MX_PHYS_RAM 0x00000000 #define PIC32MX_PHYS_PGM_FLASH 0x1D000000 #define PIC32MX_PHYS_PERIPHERALS 0x1F800000 #define PIC32MX_PHYS_BOOT_FLASH 0x1FC00000 /* * Translate Virtual and Physical addresses. * Note: These macros only work for KSEG0/KSEG1 addresses. */ #define Virt2Phys(v) ((v) & 0x1FFFFFFF) /* pic32mx configuration register locations */ #define PIC32MX_DEVCFG0_1_2 0xBFC00BFC #define PIC32MX_DEVCFG0 0xBFC02FFC #define PIC32MX_DEVCFG1 0xBFC02FF8 #define PIC32MX_DEVCFG2 0xBFC02FF4 #define PIC32MX_DEVCFG3 0xBFC02FF0 #define PIC32MX_DEVID 0xBF80F220 #define PIC32MX_BMXPFMSZ 0xBF882060 #define PIC32MX_BMXBOOTSZ 0xBF882070 #define PIC32MX_BMXDRMSZ 0xBF882040 /* pic32mx flash controller register locations */ #define PIC32MX_NVMCON 0xBF80F400 #define PIC32MX_NVMCONCLR 0xBF80F404 #define PIC32MX_NVMCONSET 0xBF80F408 #define PIC32MX_NVMCONINV 0xBF80F40C #define NVMCON_NVMWR (1 << 15) #define NVMCON_NVMWREN (1 << 14) #define NVMCON_NVMERR (1 << 13) #define NVMCON_LVDERR (1 << 12) #define NVMCON_LVDSTAT (1 << 11) #define NVMCON_OP_PFM_ERASE 0x5 #define NVMCON_OP_PAGE_ERASE 0x4 #define NVMCON_OP_ROW_PROG 0x3 #define NVMCON_OP_WORD_PROG 0x1 #define NVMCON_OP_NOP 0x0 #define PIC32MX_NVMKEY 0xBF80F410 #define PIC32MX_NVMADDR 0xBF80F420 #define PIC32MX_NVMADDRCLR 0xBF80F424 #define PIC32MX_NVMADDRSET 0xBF80F428 #define PIC32MX_NVMADDRINV 0xBF80F42C #define PIC32MX_NVMDATA 0xBF80F430 #define PIC32MX_NVMSRCADDR 0xBF80F440 /* flash unlock keys */ #define NVMKEY1 0xAA996655 #define NVMKEY2 0x556699AA #define MX_1_2 1 /* PIC32mx1xx/2xx */ struct pic32mx_flash_bank { int probed; int dev_type; /* Default 0. 1 for Pic32MX1XX/2XX variant */ }; /* * DEVID values as per PIC32MX Flash Programming Specification Rev J */ static const struct pic32mx_devs_s { uint32_t devid; const char *name; } pic32mx_devs[] = { {0x04A07053, "110F016B"}, {0x04A09053, "110F016C"}, {0x04A0B053, "110F016D"}, {0x04A06053, "120F032B"}, {0x04A08053, "120F032C"}, {0x04A0A053, "120F032D"}, {0x04D07053, "130F064B"}, {0x04D09053, "130F064C"}, {0x04D0B053, "130F064D"}, {0x04D06053, "150F128B"}, {0x04D08053, "150F128C"}, {0x04D0A053, "150F128D"}, {0x04A01053, "210F016B"}, {0x04A03053, "210F016C"}, {0x04A05053, "210F016D"}, {0x04A00053, "220F032B"}, {0x04A02053, "220F032C"}, {0x04A04053, "220F032D"}, {0x04D01053, "230F064B"}, {0x04D03053, "230F064C"}, {0x04D05053, "230F064D"}, {0x04D00053, "250F128B"}, {0x04D02053, "250F128C"}, {0x04D04053, "250F128D"}, {0x00938053, "360F512L"}, {0x00934053, "360F256L"}, {0x0092D053, "340F128L"}, {0x0092A053, "320F128L"}, {0x00916053, "340F512H"}, {0x00912053, "340F256H"}, {0x0090D053, "340F128H"}, {0x0090A053, "320F128H"}, {0x00906053, "320F064H"}, {0x00902053, "320F032H"}, {0x00978053, "460F512L"}, {0x00974053, "460F256L"}, {0x0096D053, "440F128L"}, {0x00952053, "440F256H"}, {0x00956053, "440F512H"}, {0x0094D053, "440F128H"}, {0x00942053, "420F032H"}, {0x04307053, "795F512L"}, {0x0430E053, "795F512H"}, {0x04306053, "775F512L"}, {0x0430D053, "775F512H"}, {0x04312053, "775F256L"}, {0x04303053, "775F256H"}, {0x04417053, "764F128L"}, {0x0440B053, "764F128H"}, {0x04341053, "695F512L"}, {0x04325053, "695F512H"}, {0x04311053, "675F512L"}, {0x0430C053, "675F512H"}, {0x04305053, "675F256L"}, {0x0430B053, "675F256H"}, {0x04413053, "664F128L"}, {0x04407053, "664F128H"}, {0x04411053, "664F064L"}, {0x04405053, "664F064H"}, {0x0430F053, "575F512L"}, {0x04309053, "575F512H"}, {0x04333053, "575F256L"}, {0x04317053, "575F256H"}, {0x0440F053, "564F128L"}, {0x04403053, "564F128H"}, {0x0440D053, "564F064L"}, {0x04401053, "564F064H"}, {0x04400053, "534F064H"}, {0x0440C053, "534F064L"}, {0x00000000, NULL} }; /* flash bank pic32mx 0 0 */ FLASH_BANK_COMMAND_HANDLER(pic32mx_flash_bank_command) { struct pic32mx_flash_bank *pic32mx_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; pic32mx_info = malloc(sizeof(struct pic32mx_flash_bank)); bank->driver_priv = pic32mx_info; pic32mx_info->probed = 0; pic32mx_info->dev_type = 0; return ERROR_OK; } static uint32_t pic32mx_get_flash_status(struct flash_bank *bank) { struct target *target = bank->target; uint32_t status; target_read_u32(target, PIC32MX_NVMCON, &status); return status; } static uint32_t pic32mx_wait_status_busy(struct flash_bank *bank, int timeout) { uint32_t status; /* wait for busy to clear */ while (((status = pic32mx_get_flash_status(bank)) & NVMCON_NVMWR) && (timeout-- > 0)) { LOG_DEBUG("status: 0x%" PRIx32, status); alive_sleep(1); } if (timeout <= 0) LOG_DEBUG("timeout: status: 0x%" PRIx32, status); return status; } static int pic32mx_nvm_exec(struct flash_bank *bank, uint32_t op, uint32_t timeout) { struct target *target = bank->target; uint32_t status; target_write_u32(target, PIC32MX_NVMCON, NVMCON_NVMWREN | op); /* unlock flash registers */ target_write_u32(target, PIC32MX_NVMKEY, NVMKEY1); target_write_u32(target, PIC32MX_NVMKEY, NVMKEY2); /* start operation */ target_write_u32(target, PIC32MX_NVMCONSET, NVMCON_NVMWR); status = pic32mx_wait_status_busy(bank, timeout); /* lock flash registers */ target_write_u32(target, PIC32MX_NVMCONCLR, NVMCON_NVMWREN); return status; } static int pic32mx_protect_check(struct flash_bank *bank) { struct target *target = bank->target; struct pic32mx_flash_bank *pic32mx_info = bank->driver_priv; uint32_t config0_address; uint32_t devcfg0; int s; int num_pages; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (pic32mx_info->dev_type == MX_1_2) config0_address = PIC32MX_DEVCFG0_1_2; else config0_address = PIC32MX_DEVCFG0; target_read_u32(target, config0_address, &devcfg0); if ((devcfg0 & (1 << 28)) == 0) /* code protect bit */ num_pages = 0xffff; /* All pages protected */ else if (Virt2Phys(bank->base) == PIC32MX_PHYS_BOOT_FLASH) { if (devcfg0 & (1 << 24)) num_pages = 0; /* All pages unprotected */ else num_pages = 0xffff; /* All pages protected */ } else { /* pgm flash */ if (pic32mx_info->dev_type == MX_1_2) num_pages = (~devcfg0 >> 10) & 0x3f; else num_pages = (~devcfg0 >> 12) & 0xff; } for (s = 0; s < bank->num_sectors && s < num_pages; s++) bank->sectors[s].is_protected = 1; for (; s < bank->num_sectors; s++) bank->sectors[s].is_protected = 0; return ERROR_OK; } static int pic32mx_erase(struct flash_bank *bank, int first, int last) { struct target *target = bank->target; int i; uint32_t status; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if ((first == 0) && (last == (bank->num_sectors - 1)) && (Virt2Phys(bank->base) == PIC32MX_PHYS_PGM_FLASH)) { /* this will only erase the Program Flash (PFM), not the Boot Flash (BFM) * we need to use the MTAP to perform a full erase */ LOG_DEBUG("Erasing entire program flash"); status = pic32mx_nvm_exec(bank, NVMCON_OP_PFM_ERASE, 50); if (status & NVMCON_NVMERR) return ERROR_FLASH_OPERATION_FAILED; if (status & NVMCON_LVDERR) return ERROR_FLASH_OPERATION_FAILED; return ERROR_OK; } for (i = first; i <= last; i++) { target_write_u32(target, PIC32MX_NVMADDR, Virt2Phys(bank->base + bank->sectors[i].offset)); status = pic32mx_nvm_exec(bank, NVMCON_OP_PAGE_ERASE, 10); if (status & NVMCON_NVMERR) return ERROR_FLASH_OPERATION_FAILED; if (status & NVMCON_LVDERR) return ERROR_FLASH_OPERATION_FAILED; bank->sectors[i].is_erased = 1; } return ERROR_OK; } static int pic32mx_protect(struct flash_bank *bank, int set, int first, int last) { struct target *target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } return ERROR_OK; } /* see contib/loaders/flash/pic32mx.s for src */ static uint32_t pic32mx_flash_write_code[] = { /* write: */ 0x3C08AA99, /* lui $t0, 0xaa99 */ 0x35086655, /* ori $t0, 0x6655 */ 0x3C095566, /* lui $t1, 0x5566 */ 0x352999AA, /* ori $t1, 0x99aa */ 0x3C0ABF80, /* lui $t2, 0xbf80 */ 0x354AF400, /* ori $t2, 0xf400 */ 0x340B4003, /* ori $t3, $zero, 0x4003 */ 0x340C8000, /* ori $t4, $zero, 0x8000 */ /* write_row: */ 0x2CD30080, /* sltiu $s3, $a2, 128 */ 0x16600008, /* bne $s3, $zero, write_word */ 0x340D4000, /* ori $t5, $zero, 0x4000 */ 0xAD450020, /* sw $a1, 32($t2) */ 0xAD440040, /* sw $a0, 64($t2) */ 0x04110016, /* bal progflash */ 0x24840200, /* addiu $a0, $a0, 512 */ 0x24A50200, /* addiu $a1, $a1, 512 */ 0x1000FFF7, /* beq $zero, $zero, write_row */ 0x24C6FF80, /* addiu $a2, $a2, -128 */ /* write_word: */ 0x3C15A000, /* lui $s5, 0xa000 */ 0x36B50000, /* ori $s5, $s5, 0x0 */ 0x00952025, /* or $a0, $a0, $s5 */ 0x10000008, /* beq $zero, $zero, next_word */ 0x340B4001, /* ori $t3, $zero, 0x4001 */ /* prog_word: */ 0x8C940000, /* lw $s4, 0($a0) */ 0xAD540030, /* sw $s4, 48($t2) */ 0xAD450020, /* sw $a1, 32($t2) */ 0x04110009, /* bal progflash */ 0x24840004, /* addiu $a0, $a0, 4 */ 0x24A50004, /* addiu $a1, $a1, 4 */ 0x24C6FFFF, /* addiu $a2, $a2, -1 */ /* next_word: */ 0x14C0FFF8, /* bne $a2, $zero, prog_word */ 0x00000000, /* nop */ /* done: */ 0x10000002, /* beq $zero, $zero, exit */ 0x24040000, /* addiu $a0, $zero, 0 */ /* error: */ 0x26240000, /* addiu $a0, $s1, 0 */ /* exit: */ 0x7000003F, /* sdbbp */ /* progflash: */ 0xAD4B0000, /* sw $t3, 0($t2) */ 0xAD480010, /* sw $t0, 16($t2) */ 0xAD490010, /* sw $t1, 16($t2) */ 0xAD4C0008, /* sw $t4, 8($t2) */ /* waitflash: */ 0x8D500000, /* lw $s0, 0($t2) */ 0x020C8024, /* and $s0, $s0, $t4 */ 0x1600FFFD, /* bne $s0, $zero, waitflash */ 0x00000000, /* nop */ 0x00000000, /* nop */ 0x00000000, /* nop */ 0x00000000, /* nop */ 0x00000000, /* nop */ 0x8D510000, /* lw $s1, 0($t2) */ 0x30113000, /* andi $s1, $zero, 0x3000 */ 0x1620FFEF, /* bne $s1, $zero, error */ 0xAD4D0004, /* sw $t5, 4($t2) */ 0x03E00008, /* jr $ra */ 0x00000000 /* nop */ }; static int pic32mx_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t buffer_size = 16384; struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[3]; uint32_t row_size; int retval = ERROR_OK; struct pic32mx_flash_bank *pic32mx_info = bank->driver_priv; struct mips32_algorithm mips32_info; /* flash write code */ if (target_alloc_working_area(target, sizeof(pic32mx_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; }; /* Change values for counters and row size, depending on variant */ if (pic32mx_info->dev_type == MX_1_2) { /* 128 byte row */ pic32mx_flash_write_code[8] = 0x2CD30020; pic32mx_flash_write_code[14] = 0x24840080; pic32mx_flash_write_code[15] = 0x24A50080; pic32mx_flash_write_code[17] = 0x24C6FFE0; row_size = 128; } else { /* 512 byte row */ pic32mx_flash_write_code[8] = 0x2CD30080; pic32mx_flash_write_code[14] = 0x24840200; pic32mx_flash_write_code[15] = 0x24A50200; pic32mx_flash_write_code[17] = 0x24C6FF80; row_size = 512; } retval = target_write_buffer(target, write_algorithm->address, sizeof(pic32mx_flash_write_code), (uint8_t *)pic32mx_flash_write_code); if (retval != ERROR_OK) return retval; /* memory buffer */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; if (buffer_size <= 256) { /* we already allocated the writing code, but failed to get a * buffer, free the algorithm */ target_free_working_area(target, write_algorithm); LOG_WARNING("no large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } mips32_info.common_magic = MIPS32_COMMON_MAGIC; mips32_info.isa_mode = MIPS32_ISA_MIPS32; init_reg_param(®_params[0], "a0", 32, PARAM_IN_OUT); init_reg_param(®_params[1], "a1", 32, PARAM_OUT); init_reg_param(®_params[2], "a2", 32, PARAM_OUT); int row_offset = offset % row_size; uint8_t *new_buffer = NULL; if (row_offset && (count >= (row_size / 4))) { new_buffer = malloc(buffer_size); if (new_buffer == NULL) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } memset(new_buffer, 0xff, row_offset); address -= row_offset; } else row_offset = 0; while (count > 0) { uint32_t status; uint32_t thisrun_count; if (row_offset) { thisrun_count = (count > ((buffer_size - row_offset) / 4)) ? ((buffer_size - row_offset) / 4) : count; memcpy(new_buffer + row_offset, buffer, thisrun_count * 4); retval = target_write_buffer(target, source->address, row_offset + thisrun_count * 4, new_buffer); if (retval != ERROR_OK) break; } else { thisrun_count = (count > (buffer_size / 4)) ? (buffer_size / 4) : count; retval = target_write_buffer(target, source->address, thisrun_count * 4, buffer); if (retval != ERROR_OK) break; } buf_set_u32(reg_params[0].value, 0, 32, Virt2Phys(source->address)); buf_set_u32(reg_params[1].value, 0, 32, Virt2Phys(address)); buf_set_u32(reg_params[2].value, 0, 32, thisrun_count + row_offset / 4); retval = target_run_algorithm(target, 0, NULL, 3, reg_params, write_algorithm->address, 0, 10000, &mips32_info); if (retval != ERROR_OK) { LOG_ERROR("error executing pic32mx flash write algorithm"); retval = ERROR_FLASH_OPERATION_FAILED; break; } status = buf_get_u32(reg_params[0].value, 0, 32); if (status & NVMCON_NVMERR) { LOG_ERROR("Flash write error NVMERR (status = 0x%08" PRIx32 ")", status); retval = ERROR_FLASH_OPERATION_FAILED; break; } if (status & NVMCON_LVDERR) { LOG_ERROR("Flash write error LVDERR (status = 0x%08" PRIx32 ")", status); retval = ERROR_FLASH_OPERATION_FAILED; break; } buffer += thisrun_count * 4; address += thisrun_count * 4; count -= thisrun_count; if (row_offset) { address += row_offset; row_offset = 0; } } target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); if (new_buffer != NULL) free(new_buffer); return retval; } static int pic32mx_write_word(struct flash_bank *bank, uint32_t address, uint32_t word) { struct target *target = bank->target; target_write_u32(target, PIC32MX_NVMADDR, Virt2Phys(address)); target_write_u32(target, PIC32MX_NVMDATA, word); return pic32mx_nvm_exec(bank, NVMCON_OP_WORD_PROG, 5); } static int pic32mx_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { uint32_t words_remaining = (count / 4); uint32_t bytes_remaining = (count & 0x00000003); uint32_t address = bank->base + offset; uint32_t bytes_written = 0; uint32_t status; int retval; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } LOG_DEBUG("writing to flash at address 0x%08" PRIx32 " at offset 0x%8.8" PRIx32 " count: 0x%8.8" PRIx32 "", bank->base, offset, count); if (offset & 0x3) { LOG_WARNING("offset 0x%" PRIx32 "breaks required 4-byte alignment", offset); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } /* multiple words (4-byte) to be programmed? */ if (words_remaining > 0) { /* try using a block write */ retval = pic32mx_write_block(bank, buffer, offset, words_remaining); if (retval != ERROR_OK) { if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* if block write failed (no sufficient working area), * we use normal (slow) single dword accesses */ LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); } else if (retval == ERROR_FLASH_OPERATION_FAILED) { LOG_ERROR("flash writing failed"); return retval; } } else { buffer += words_remaining * 4; address += words_remaining * 4; words_remaining = 0; } } while (words_remaining > 0) { uint32_t value; memcpy(&value, buffer + bytes_written, sizeof(uint32_t)); status = pic32mx_write_word(bank, address, value); if (status & NVMCON_NVMERR) { LOG_ERROR("Flash write error NVMERR (status = 0x%08" PRIx32 ")", status); return ERROR_FLASH_OPERATION_FAILED; } if (status & NVMCON_LVDERR) { LOG_ERROR("Flash write error LVDERR (status = 0x%08" PRIx32 ")", status); return ERROR_FLASH_OPERATION_FAILED; } bytes_written += 4; words_remaining--; address += 4; } if (bytes_remaining) { uint32_t value = 0xffffffff; memcpy(&value, buffer + bytes_written, bytes_remaining); status = pic32mx_write_word(bank, address, value); if (status & NVMCON_NVMERR) { LOG_ERROR("Flash write error NVMERR (status = 0x%08" PRIx32 ")", status); return ERROR_FLASH_OPERATION_FAILED; } if (status & NVMCON_LVDERR) { LOG_ERROR("Flash write error LVDERR (status = 0x%08" PRIx32 ")", status); return ERROR_FLASH_OPERATION_FAILED; } } return ERROR_OK; } static int pic32mx_probe(struct flash_bank *bank) { struct target *target = bank->target; struct pic32mx_flash_bank *pic32mx_info = bank->driver_priv; struct mips32_common *mips32 = target->arch_info; struct mips_ejtag *ejtag_info = &mips32->ejtag_info; int i; uint32_t num_pages = 0; uint32_t device_id; int page_size; pic32mx_info->probed = 0; device_id = ejtag_info->idcode; LOG_INFO("device id = 0x%08" PRIx32 " (manuf 0x%03x dev 0x%04x, ver 0x%02x)", device_id, (unsigned)((device_id >> 1) & 0x7ff), (unsigned)((device_id >> 12) & 0xffff), (unsigned)((device_id >> 28) & 0xf)); if (((device_id >> 1) & 0x7ff) != PIC32MX_MANUF_ID) { LOG_WARNING("Cannot identify target as a PIC32MX family."); return ERROR_FLASH_OPERATION_FAILED; } /* Check for PIC32mx1xx/2xx */ for (i = 0; pic32mx_devs[i].name != NULL; i++) { if (pic32mx_devs[i].devid == (device_id & 0x0fffffff)) { if ((*(pic32mx_devs[i].name) == '1') || (*(pic32mx_devs[i].name) == '2')) pic32mx_info->dev_type = MX_1_2; break; } } if (pic32mx_info->dev_type == MX_1_2) page_size = 1024; else page_size = 4096; if (Virt2Phys(bank->base) == PIC32MX_PHYS_BOOT_FLASH) { /* 0x1FC00000: Boot flash size */ #if 0 /* for some reason this register returns 8k for the boot bank size * this does not match the docs, so for now set the boot bank at a * fixed 12k */ if (target_read_u32(target, PIC32MX_BMXBOOTSZ, &num_pages) != ERROR_OK) { LOG_WARNING("PIC32MX flash size failed, probe inaccurate - assuming 12k flash"); num_pages = (12 * 1024); } #else /* fixed 12k boot bank - see comments above */ if (pic32mx_info->dev_type == MX_1_2) num_pages = (3 * 1024); else num_pages = (12 * 1024); #endif } else { /* read the flash size from the device */ if (target_read_u32(target, PIC32MX_BMXPFMSZ, &num_pages) != ERROR_OK) { if (pic32mx_info->dev_type == MX_1_2) { LOG_WARNING("PIC32MX flash size failed, probe inaccurate - assuming 32k flash"); num_pages = (32 * 1024); } else { LOG_WARNING("PIC32MX flash size failed, probe inaccurate - assuming 512k flash"); num_pages = (512 * 1024); } } } LOG_INFO("flash size = %" PRId32 "kbytes", num_pages / 1024); if (bank->sectors) { free(bank->sectors); bank->sectors = NULL; } /* calculate numbers of pages */ num_pages /= page_size; bank->size = (num_pages * page_size); bank->num_sectors = num_pages; bank->sectors = malloc(sizeof(struct flash_sector) * num_pages); for (i = 0; i < (int)num_pages; i++) { bank->sectors[i].offset = i * page_size; bank->sectors[i].size = page_size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } pic32mx_info->probed = 1; return ERROR_OK; } static int pic32mx_auto_probe(struct flash_bank *bank) { struct pic32mx_flash_bank *pic32mx_info = bank->driver_priv; if (pic32mx_info->probed) return ERROR_OK; return pic32mx_probe(bank); } static int pic32mx_info(struct flash_bank *bank, char *buf, int buf_size) { struct target *target = bank->target; struct mips32_common *mips32 = target->arch_info; struct mips_ejtag *ejtag_info = &mips32->ejtag_info; uint32_t device_id; int printed = 0, i; device_id = ejtag_info->idcode; if (((device_id >> 1) & 0x7ff) != PIC32MX_MANUF_ID) { snprintf(buf, buf_size, "Cannot identify target as a PIC32MX family (manufacturer 0x%03d != 0x%03d)\n", (unsigned)((device_id >> 1) & 0x7ff), PIC32MX_MANUF_ID); return ERROR_FLASH_OPERATION_FAILED; } for (i = 0; pic32mx_devs[i].name != NULL; i++) { if (pic32mx_devs[i].devid == (device_id & 0x0fffffff)) { printed = snprintf(buf, buf_size, "PIC32MX%s", pic32mx_devs[i].name); break; } } if (pic32mx_devs[i].name == NULL) printed = snprintf(buf, buf_size, "Unknown"); buf += printed; buf_size -= printed; snprintf(buf, buf_size, " Ver: 0x%02x", (unsigned)((device_id >> 28) & 0xf)); return ERROR_OK; } COMMAND_HANDLER(pic32mx_handle_pgm_word_command) { uint32_t address, value; int status, res; if (CMD_ARGC != 3) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 2, &bank); if (ERROR_OK != retval) return retval; if (address < bank->base || address >= (bank->base + bank->size)) { command_print(CMD_CTX, "flash address '%s' is out of bounds", CMD_ARGV[0]); return ERROR_OK; } res = ERROR_OK; status = pic32mx_write_word(bank, address, value); if (status & NVMCON_NVMERR) res = ERROR_FLASH_OPERATION_FAILED; if (status & NVMCON_LVDERR) res = ERROR_FLASH_OPERATION_FAILED; if (res == ERROR_OK) command_print(CMD_CTX, "pic32mx pgm word complete"); else command_print(CMD_CTX, "pic32mx pgm word failed (status = 0x%x)", status); return ERROR_OK; } COMMAND_HANDLER(pic32mx_handle_unlock_command) { uint32_t mchip_cmd; struct target *target = NULL; struct mips_m4k_common *mips_m4k; struct mips_ejtag *ejtag_info; int timeout = 10; if (CMD_ARGC < 1) { command_print(CMD_CTX, "pic32mx unlock "); return ERROR_COMMAND_SYNTAX_ERROR; } struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; target = bank->target; mips_m4k = target_to_m4k(target); ejtag_info = &mips_m4k->mips32.ejtag_info; /* we have to use the MTAP to perform a full erase */ mips_ejtag_set_instr(ejtag_info, MTAP_SW_MTAP); mips_ejtag_set_instr(ejtag_info, MTAP_COMMAND); /* first check status of device */ mchip_cmd = MCHP_STATUS; mips_ejtag_drscan_8(ejtag_info, &mchip_cmd); if (mchip_cmd & (1 << 7)) { /* device is not locked */ command_print(CMD_CTX, "pic32mx is already unlocked, erasing anyway"); } /* unlock/erase device */ mips_ejtag_drscan_8_out(ejtag_info, MCHP_ASERT_RST); jtag_add_sleep(200); mips_ejtag_drscan_8_out(ejtag_info, MCHP_ERASE); do { mchip_cmd = MCHP_STATUS; mips_ejtag_drscan_8(ejtag_info, &mchip_cmd); if (timeout-- == 0) { LOG_DEBUG("timeout waiting for unlock: 0x%" PRIx32 "", mchip_cmd); break; } alive_sleep(1); } while ((mchip_cmd & (1 << 2)) || (!(mchip_cmd & (1 << 3)))); mips_ejtag_drscan_8_out(ejtag_info, MCHP_DE_ASSERT_RST); /* select ejtag tap */ mips_ejtag_set_instr(ejtag_info, MTAP_SW_ETAP); command_print(CMD_CTX, "pic32mx unlocked.\n" "INFO: a reset or power cycle is required " "for the new settings to take effect."); return ERROR_OK; } static const struct command_registration pic32mx_exec_command_handlers[] = { { .name = "pgm_word", .usage = " ", .handler = pic32mx_handle_pgm_word_command, .mode = COMMAND_EXEC, .help = "program a word", }, { .name = "unlock", .handler = pic32mx_handle_unlock_command, .mode = COMMAND_EXEC, .usage = "[bank_id]", .help = "Unlock/Erase entire device.", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration pic32mx_command_handlers[] = { { .name = "pic32mx", .mode = COMMAND_ANY, .help = "pic32mx flash command group", .usage = "", .chain = pic32mx_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct flash_driver pic32mx_flash = { .name = "pic32mx", .commands = pic32mx_command_handlers, .flash_bank_command = pic32mx_flash_bank_command, .erase = pic32mx_erase, .protect = pic32mx_protect, .write = pic32mx_write, .read = default_flash_read, .probe = pic32mx_probe, .auto_probe = pic32mx_auto_probe, .erase_check = default_flash_blank_check, .protect_check = pic32mx_protect_check, .info = pic32mx_info, }; openocd-0.7.0/src/flash/nor/at91sam3.c0000644000175000001440000026043412137151330014257 00000000000000/*************************************************************************** * Copyright (C) 2009 by Duane Ellis * * openocd@duaneellis.com * * * * Copyright (C) 2010 by Olaf Lüke (at91sam3s* support) * * olaf@uni-paderborn.de * * * * Copyright (C) 2011 by Olivier Schonken (at91sam3x* support) * * * and Jim Norris * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General public License as published by * * the Free Software Foundation; either version 2 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. * ****************************************************************************/ /* Some of the the lower level code was based on code supplied by * ATMEL under this copyright. */ /* BEGIN ATMEL COPYRIGHT */ /* ---------------------------------------------------------------------------- * ATMEL Microcontroller Software Support * ---------------------------------------------------------------------------- * Copyright (c) 2009, Atmel Corporation * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the disclaimer below. * * Atmel's name may not be used to endorse or promote products derived from * this software without specific prior written permission. * * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ---------------------------------------------------------------------------- */ /* END ATMEL COPYRIGHT */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include #define REG_NAME_WIDTH (12) /* at91sam3u series (has one or two flash banks) */ #define FLASH_BANK0_BASE_U 0x00080000 #define FLASH_BANK1_BASE_U 0x00100000 /* at91sam3s series (has always one flash bank) */ #define FLASH_BANK_BASE_S 0x00400000 /* at91sam3n series (has always one flash bank) */ #define FLASH_BANK_BASE_N 0x00400000 /* at91sam3a/x series has two flash banks*/ #define FLASH_BANK0_BASE_AX 0x00080000 /*Bank 1 of the at91sam3a/x series starts at 0x00080000 + half flash size*/ #define FLASH_BANK1_BASE_256K_AX 0x000A0000 #define FLASH_BANK1_BASE_512K_AX 0x000C0000 #define FLASH_BANK0_BASE_SD FLASH_BANK_BASE_S #define FLASH_BANK1_BASE_512K_SD (FLASH_BANK0_BASE_SD+(512*1024/2)) #define AT91C_EFC_FCMD_GETD (0x0) /* (EFC) Get Flash Descriptor */ #define AT91C_EFC_FCMD_WP (0x1) /* (EFC) Write Page */ #define AT91C_EFC_FCMD_WPL (0x2) /* (EFC) Write Page and Lock */ #define AT91C_EFC_FCMD_EWP (0x3) /* (EFC) Erase Page and Write Page */ #define AT91C_EFC_FCMD_EWPL (0x4) /* (EFC) Erase Page and Write Page then Lock */ #define AT91C_EFC_FCMD_EA (0x5) /* (EFC) Erase All */ /* cmd6 is not present in the at91sam3u4/2/1 data sheet table 17-2 */ /* #define AT91C_EFC_FCMD_EPL (0x6) // (EFC) Erase plane? */ /* cmd7 is not present in the at91sam3u4/2/1 data sheet table 17-2 */ /* #define AT91C_EFC_FCMD_EPA (0x7) // (EFC) Erase pages? */ #define AT91C_EFC_FCMD_SLB (0x8) /* (EFC) Set Lock Bit */ #define AT91C_EFC_FCMD_CLB (0x9) /* (EFC) Clear Lock Bit */ #define AT91C_EFC_FCMD_GLB (0xA) /* (EFC) Get Lock Bit */ #define AT91C_EFC_FCMD_SFB (0xB) /* (EFC) Set Fuse Bit */ #define AT91C_EFC_FCMD_CFB (0xC) /* (EFC) Clear Fuse Bit */ #define AT91C_EFC_FCMD_GFB (0xD) /* (EFC) Get Fuse Bit */ #define AT91C_EFC_FCMD_STUI (0xE) /* (EFC) Start Read Unique ID */ #define AT91C_EFC_FCMD_SPUI (0xF) /* (EFC) Stop Read Unique ID */ #define offset_EFC_FMR 0 #define offset_EFC_FCR 4 #define offset_EFC_FSR 8 #define offset_EFC_FRR 12 extern struct flash_driver at91sam3_flash; static float _tomhz(uint32_t freq_hz) { float f; f = ((float)(freq_hz)) / 1000000.0; return f; } /* How the chip is configured. */ struct sam3_cfg { uint32_t unique_id[4]; uint32_t slow_freq; uint32_t rc_freq; uint32_t mainosc_freq; uint32_t plla_freq; uint32_t mclk_freq; uint32_t cpu_freq; uint32_t fclk_freq; uint32_t pclk0_freq; uint32_t pclk1_freq; uint32_t pclk2_freq; #define SAM3_CHIPID_CIDR (0x400E0740) uint32_t CHIPID_CIDR; #define SAM3_CHIPID_CIDR2 (0x400E0940) /*SAM3X and SAM3A cidr at this address*/ uint32_t CHIPID_CIDR2; #define SAM3_CHIPID_EXID (0x400E0744) uint32_t CHIPID_EXID; #define SAM3_CHIPID_EXID2 (0x400E0944) /*SAM3X and SAM3A cidr at this address*/ uint32_t CHIPID_EXID2; #define SAM3_PMC_BASE (0x400E0400) #define SAM3_PMC_SCSR (SAM3_PMC_BASE + 0x0008) uint32_t PMC_SCSR; #define SAM3_PMC_PCSR (SAM3_PMC_BASE + 0x0018) uint32_t PMC_PCSR; #define SAM3_CKGR_UCKR (SAM3_PMC_BASE + 0x001c) uint32_t CKGR_UCKR; #define SAM3_CKGR_MOR (SAM3_PMC_BASE + 0x0020) uint32_t CKGR_MOR; #define SAM3_CKGR_MCFR (SAM3_PMC_BASE + 0x0024) uint32_t CKGR_MCFR; #define SAM3_CKGR_PLLAR (SAM3_PMC_BASE + 0x0028) uint32_t CKGR_PLLAR; #define SAM3_PMC_MCKR (SAM3_PMC_BASE + 0x0030) uint32_t PMC_MCKR; #define SAM3_PMC_PCK0 (SAM3_PMC_BASE + 0x0040) uint32_t PMC_PCK0; #define SAM3_PMC_PCK1 (SAM3_PMC_BASE + 0x0044) uint32_t PMC_PCK1; #define SAM3_PMC_PCK2 (SAM3_PMC_BASE + 0x0048) uint32_t PMC_PCK2; #define SAM3_PMC_SR (SAM3_PMC_BASE + 0x0068) uint32_t PMC_SR; #define SAM3_PMC_IMR (SAM3_PMC_BASE + 0x006c) uint32_t PMC_IMR; #define SAM3_PMC_FSMR (SAM3_PMC_BASE + 0x0070) uint32_t PMC_FSMR; #define SAM3_PMC_FSPR (SAM3_PMC_BASE + 0x0074) uint32_t PMC_FSPR; }; /* * The AT91SAM3N data sheet 04-Oct-2010, AT91SAM3U data sheet 22-Aug-2011 * and AT91SAM3S data sheet 09-Feb-2011 state that for flash writes * the flash wait state (FWS) should be set to 6. It seems like that the * cause of the problem is not the flash itself, but the flash write * buffer. Ie the wait states have to be set before writing into the * buffer. * Tested and confirmed with SAM3N and SAM3U */ struct sam3_bank_private { int probed; /* DANGER: THERE ARE DRAGONS HERE.. */ /* NOTE: If you add more 'ghost' pointers */ /* be aware that you must *manually* update */ /* these pointers in the function sam3_GetDetails() */ /* See the comment "Here there be dragons" */ /* so we can find the chip we belong to */ struct sam3_chip *pChip; /* so we can find the original bank pointer */ struct flash_bank *pBank; unsigned bank_number; uint32_t controller_address; uint32_t base_address; uint32_t flash_wait_states; bool present; unsigned size_bytes; unsigned nsectors; unsigned sector_size; unsigned page_size; }; struct sam3_chip_details { /* THERE ARE DRAGONS HERE.. */ /* note: If you add pointers here */ /* be careful about them as they */ /* may need to be updated inside */ /* the function: "sam3_GetDetails() */ /* which copy/overwrites the */ /* 'runtime' copy of this structure */ uint32_t chipid_cidr; const char *name; unsigned n_gpnvms; #define SAM3_N_NVM_BITS 3 unsigned gpnvm[SAM3_N_NVM_BITS]; unsigned total_flash_size; unsigned total_sram_size; unsigned n_banks; #define SAM3_MAX_FLASH_BANKS 2 /* these are "initialized" from the global const data */ struct sam3_bank_private bank[SAM3_MAX_FLASH_BANKS]; }; struct sam3_chip { struct sam3_chip *next; int probed; /* this is "initialized" from the global const structure */ struct sam3_chip_details details; struct target *target; struct sam3_cfg cfg; }; struct sam3_reg_list { uint32_t address; size_t struct_offset; const char *name; void (*explain_func)(struct sam3_chip *pInfo); }; static struct sam3_chip *all_sam3_chips; static struct sam3_chip *get_current_sam3(struct command_context *cmd_ctx) { struct target *t; static struct sam3_chip *p; t = get_current_target(cmd_ctx); if (!t) { command_print(cmd_ctx, "No current target?"); return NULL; } p = all_sam3_chips; if (!p) { /* this should not happen */ /* the command is not registered until the chip is created? */ command_print(cmd_ctx, "No SAM3 chips exist?"); return NULL; } while (p) { if (p->target == t) return p; p = p->next; } command_print(cmd_ctx, "Cannot find SAM3 chip?"); return NULL; } /* these are used to *initialize* the "pChip->details" structure. */ static const struct sam3_chip_details all_sam3_details[] = { /* Start at91sam3u* series */ { .chipid_cidr = 0x28100960, .name = "at91sam3u4e", .total_flash_size = 256 * 1024, .total_sram_size = 52 * 1024, .n_gpnvms = 3, .n_banks = 2, /* System boots at address 0x0 */ /* gpnvm[1] = selects boot code */ /* if gpnvm[1] == 0 */ /* boot is via "SAMBA" (rom) */ /* else */ /* boot is via FLASH */ /* Selection is via gpnvm[2] */ /* endif */ /* */ /* NOTE: banks 0 & 1 switch places */ /* if gpnvm[2] == 0 */ /* Bank0 is the boot rom */ /* else */ /* Bank1 is the boot rom */ /* endif */ /* .bank[0] = { */ { { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_U, .controller_address = 0x400e0800, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 128 * 1024, .nsectors = 16, .sector_size = 8192, .page_size = 256, }, /* .bank[1] = { */ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_U, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 128 * 1024, .nsectors = 16, .sector_size = 8192, .page_size = 256, }, }, }, { .chipid_cidr = 0x281a0760, .name = "at91sam3u2e", .total_flash_size = 128 * 1024, .total_sram_size = 36 * 1024, .n_gpnvms = 2, .n_banks = 1, /* System boots at address 0x0 */ /* gpnvm[1] = selects boot code */ /* if gpnvm[1] == 0 */ /* boot is via "SAMBA" (rom) */ /* else */ /* boot is via FLASH */ /* Selection is via gpnvm[2] */ /* endif */ /* .bank[0] = { */ { { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_U, .controller_address = 0x400e0800, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 128 * 1024, .nsectors = 16, .sector_size = 8192, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = 0, .bank_number = 1, }, }, }, { .chipid_cidr = 0x28190560, .name = "at91sam3u1e", .total_flash_size = 64 * 1024, .total_sram_size = 20 * 1024, .n_gpnvms = 2, .n_banks = 1, /* System boots at address 0x0 */ /* gpnvm[1] = selects boot code */ /* if gpnvm[1] == 0 */ /* boot is via "SAMBA" (rom) */ /* else */ /* boot is via FLASH */ /* Selection is via gpnvm[2] */ /* endif */ /* */ /* .bank[0] = { */ { { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_U, .controller_address = 0x400e0800, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 64 * 1024, .nsectors = 8, .sector_size = 8192, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = 0, .bank_number = 1, }, }, }, { .chipid_cidr = 0x28000960, .name = "at91sam3u4c", .total_flash_size = 256 * 1024, .total_sram_size = 52 * 1024, .n_gpnvms = 3, .n_banks = 2, /* System boots at address 0x0 */ /* gpnvm[1] = selects boot code */ /* if gpnvm[1] == 0 */ /* boot is via "SAMBA" (rom) */ /* else */ /* boot is via FLASH */ /* Selection is via gpnvm[2] */ /* endif */ /* */ /* NOTE: banks 0 & 1 switch places */ /* if gpnvm[2] == 0 */ /* Bank0 is the boot rom */ /* else */ /* Bank1 is the boot rom */ /* endif */ { { /* .bank[0] = { */ .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_U, .controller_address = 0x400e0800, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 128 * 1024, .nsectors = 16, .sector_size = 8192, .page_size = 256, }, /* .bank[1] = { */ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_U, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 128 * 1024, .nsectors = 16, .sector_size = 8192, .page_size = 256, }, }, }, { .chipid_cidr = 0x280a0760, .name = "at91sam3u2c", .total_flash_size = 128 * 1024, .total_sram_size = 36 * 1024, .n_gpnvms = 2, .n_banks = 1, /* System boots at address 0x0 */ /* gpnvm[1] = selects boot code */ /* if gpnvm[1] == 0 */ /* boot is via "SAMBA" (rom) */ /* else */ /* boot is via FLASH */ /* Selection is via gpnvm[2] */ /* endif */ { /* .bank[0] = { */ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_U, .controller_address = 0x400e0800, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 128 * 1024, .nsectors = 16, .sector_size = 8192, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = 0, .bank_number = 1, }, }, }, { .chipid_cidr = 0x28090560, .name = "at91sam3u1c", .total_flash_size = 64 * 1024, .total_sram_size = 20 * 1024, .n_gpnvms = 2, .n_banks = 1, /* System boots at address 0x0 */ /* gpnvm[1] = selects boot code */ /* if gpnvm[1] == 0 */ /* boot is via "SAMBA" (rom) */ /* else */ /* boot is via FLASH */ /* Selection is via gpnvm[2] */ /* endif */ /* */ { /* .bank[0] = { */ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_U, .controller_address = 0x400e0800, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 64 * 1024, .nsectors = 8, .sector_size = 8192, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = 0, .bank_number = 1, }, }, }, /* Start at91sam3s* series */ /* Note: The preliminary at91sam3s datasheet says on page 302 */ /* that the flash controller is at address 0x400E0800. */ /* This is _not_ the case, the controller resides at address 0x400e0a0. */ { .chipid_cidr = 0x28A00960, .name = "at91sam3s4c", .total_flash_size = 256 * 1024, .total_sram_size = 48 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = { */ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = 0, .bank_number = 1, }, }, }, { .chipid_cidr = 0x28900960, .name = "at91sam3s4b", .total_flash_size = 256 * 1024, .total_sram_size = 48 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = { */ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = 0, .bank_number = 1, }, }, }, { .chipid_cidr = 0x28800960, .name = "at91sam3s4a", .total_flash_size = 256 * 1024, .total_sram_size = 48 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = { */ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = 0, .bank_number = 1, }, }, }, { .chipid_cidr = 0x28AA0760, .name = "at91sam3s2c", .total_flash_size = 128 * 1024, .total_sram_size = 32 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = { */ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 128 * 1024, .nsectors = 8, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = 0, .bank_number = 1, }, }, }, { .chipid_cidr = 0x289A0760, .name = "at91sam3s2b", .total_flash_size = 128 * 1024, .total_sram_size = 32 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = { */ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 128 * 1024, .nsectors = 8, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = 0, .bank_number = 1, }, }, }, { .chipid_cidr = 0x29ab0a60, .name = "at91sam3sd8c", .total_flash_size = 512 * 1024, .total_sram_size = 64 * 1024, .n_gpnvms = 3, .n_banks = 2, { /* .bank[0] = { */ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_SD, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_512K_SD, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 16384, .page_size = 256, }, }, }, { .chipid_cidr = 0x288A0760, .name = "at91sam3s2a", .total_flash_size = 128 * 1024, .total_sram_size = 32 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = { */ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 128 * 1024, .nsectors = 8, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = 0, .bank_number = 1, }, }, }, { .chipid_cidr = 0x28A90560, .name = "at91sam3s1c", .total_flash_size = 64 * 1024, .total_sram_size = 16 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = { */ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 64 * 1024, .nsectors = 4, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = 0, .bank_number = 1, }, }, }, { .chipid_cidr = 0x28990560, .name = "at91sam3s1b", .total_flash_size = 64 * 1024, .total_sram_size = 16 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = { */ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 64 * 1024, .nsectors = 4, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = 0, .bank_number = 1, }, }, }, { .chipid_cidr = 0x28890560, .name = "at91sam3s1a", .total_flash_size = 64 * 1024, .total_sram_size = 16 * 1024, .n_gpnvms = 2, .n_banks = 1, { /* .bank[0] = { */ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_S, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 64 * 1024, .nsectors = 4, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = 0, .bank_number = 1, }, }, }, /* Start at91sam3n* series */ { .chipid_cidr = 0x29540960, .name = "at91sam3n4c", .total_flash_size = 256 * 1024, .total_sram_size = 24 * 1024, .n_gpnvms = 3, .n_banks = 1, /* System boots at address 0x0 */ /* gpnvm[1] = selects boot code */ /* if gpnvm[1] == 0 */ /* boot is via "SAMBA" (rom) */ /* else */ /* boot is via FLASH */ /* Selection is via gpnvm[2] */ /* endif */ /* */ /* NOTE: banks 0 & 1 switch places */ /* if gpnvm[2] == 0 */ /* Bank0 is the boot rom */ /* else */ /* Bank1 is the boot rom */ /* endif */ /* .bank[0] = { */ { { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_N, .controller_address = 0x400e0A00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = 0, .bank_number = 1, }, }, }, { .chipid_cidr = 0x29440960, .name = "at91sam3n4b", .total_flash_size = 256 * 1024, .total_sram_size = 24 * 1024, .n_gpnvms = 3, .n_banks = 1, /* System boots at address 0x0 */ /* gpnvm[1] = selects boot code */ /* if gpnvm[1] == 0 */ /* boot is via "SAMBA" (rom) */ /* else */ /* boot is via FLASH */ /* Selection is via gpnvm[2] */ /* endif */ /* */ /* NOTE: banks 0 & 1 switch places */ /* if gpnvm[2] == 0 */ /* Bank0 is the boot rom */ /* else */ /* Bank1 is the boot rom */ /* endif */ /* .bank[0] = { */ { { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_N, .controller_address = 0x400e0A00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = 0, .bank_number = 1, }, }, }, { .chipid_cidr = 0x29340960, .name = "at91sam3n4a", .total_flash_size = 256 * 1024, .total_sram_size = 24 * 1024, .n_gpnvms = 3, .n_banks = 1, /* System boots at address 0x0 */ /* gpnvm[1] = selects boot code */ /* if gpnvm[1] == 0 */ /* boot is via "SAMBA" (rom) */ /* else */ /* boot is via FLASH */ /* Selection is via gpnvm[2] */ /* endif */ /* */ /* NOTE: banks 0 & 1 switch places */ /* if gpnvm[2] == 0 */ /* Bank0 is the boot rom */ /* else */ /* Bank1 is the boot rom */ /* endif */ /* .bank[0] = { */ { { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_N, .controller_address = 0x400e0A00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = 0, .bank_number = 1, }, }, }, { .chipid_cidr = 0x29590760, .name = "at91sam3n2c", .total_flash_size = 128 * 1024, .total_sram_size = 16 * 1024, .n_gpnvms = 3, .n_banks = 1, /* System boots at address 0x0 */ /* gpnvm[1] = selects boot code */ /* if gpnvm[1] == 0 */ /* boot is via "SAMBA" (rom) */ /* else */ /* boot is via FLASH */ /* Selection is via gpnvm[2] */ /* endif */ /* */ /* NOTE: banks 0 & 1 switch places */ /* if gpnvm[2] == 0 */ /* Bank0 is the boot rom */ /* else */ /* Bank1 is the boot rom */ /* endif */ /* .bank[0] = { */ { { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_N, .controller_address = 0x400e0A00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 128 * 1024, .nsectors = 8, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = 0, .bank_number = 1, }, }, }, { .chipid_cidr = 0x29490760, .name = "at91sam3n2b", .total_flash_size = 128 * 1024, .total_sram_size = 16 * 1024, .n_gpnvms = 3, .n_banks = 1, /* System boots at address 0x0 */ /* gpnvm[1] = selects boot code */ /* if gpnvm[1] == 0 */ /* boot is via "SAMBA" (rom) */ /* else */ /* boot is via FLASH */ /* Selection is via gpnvm[2] */ /* endif */ /* */ /* NOTE: banks 0 & 1 switch places */ /* if gpnvm[2] == 0 */ /* Bank0 is the boot rom */ /* else */ /* Bank1 is the boot rom */ /* endif */ /* .bank[0] = { */ { { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_N, .controller_address = 0x400e0A00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 128 * 1024, .nsectors = 8, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = 0, .bank_number = 1, }, }, }, { .chipid_cidr = 0x29390760, .name = "at91sam3n2a", .total_flash_size = 128 * 1024, .total_sram_size = 16 * 1024, .n_gpnvms = 3, .n_banks = 1, /* System boots at address 0x0 */ /* gpnvm[1] = selects boot code */ /* if gpnvm[1] == 0 */ /* boot is via "SAMBA" (rom) */ /* else */ /* boot is via FLASH */ /* Selection is via gpnvm[2] */ /* endif */ /* */ /* NOTE: banks 0 & 1 switch places */ /* if gpnvm[2] == 0 */ /* Bank0 is the boot rom */ /* else */ /* Bank1 is the boot rom */ /* endif */ /* .bank[0] = { */ { { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_N, .controller_address = 0x400e0A00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 128 * 1024, .nsectors = 8, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = 0, .bank_number = 1, }, }, }, { .chipid_cidr = 0x29580560, .name = "at91sam3n1c", .total_flash_size = 64 * 1024, .total_sram_size = 8 * 1024, .n_gpnvms = 3, .n_banks = 1, /* System boots at address 0x0 */ /* gpnvm[1] = selects boot code */ /* if gpnvm[1] == 0 */ /* boot is via "SAMBA" (rom) */ /* else */ /* boot is via FLASH */ /* Selection is via gpnvm[2] */ /* endif */ /* */ /* NOTE: banks 0 & 1 switch places */ /* if gpnvm[2] == 0 */ /* Bank0 is the boot rom */ /* else */ /* Bank1 is the boot rom */ /* endif */ /* .bank[0] = { */ { { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_N, .controller_address = 0x400e0A00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 64 * 1024, .nsectors = 4, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = 0, .bank_number = 1, }, }, }, { .chipid_cidr = 0x29480560, .name = "at91sam3n1b", .total_flash_size = 64 * 1024, .total_sram_size = 8 * 1024, .n_gpnvms = 3, .n_banks = 1, /* System boots at address 0x0 */ /* gpnvm[1] = selects boot code */ /* if gpnvm[1] == 0 */ /* boot is via "SAMBA" (rom) */ /* else */ /* boot is via FLASH */ /* Selection is via gpnvm[2] */ /* endif */ /* */ /* NOTE: banks 0 & 1 switch places */ /* if gpnvm[2] == 0 */ /* Bank0 is the boot rom */ /* else */ /* Bank1 is the boot rom */ /* endif */ /* .bank[0] = { */ { { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_N, .controller_address = 0x400e0A00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 64 * 1024, .nsectors = 4, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = 0, .bank_number = 1, }, }, }, { .chipid_cidr = 0x29380560, .name = "at91sam3n1a", .total_flash_size = 64 * 1024, .total_sram_size = 8 * 1024, .n_gpnvms = 3, .n_banks = 1, /* System boots at address 0x0 */ /* gpnvm[1] = selects boot code */ /* if gpnvm[1] == 0 */ /* boot is via "SAMBA" (rom) */ /* else */ /* boot is via FLASH */ /* Selection is via gpnvm[2] */ /* endif */ /* */ /* NOTE: banks 0 & 1 switch places */ /* if gpnvm[2] == 0 */ /* Bank0 is the boot rom */ /* else */ /* Bank1 is the boot rom */ /* endif */ /* .bank[0] = { */ { { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK_BASE_N, .controller_address = 0x400e0A00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 64 * 1024, .nsectors = 4, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .present = 0, .probed = 0, .bank_number = 1, }, }, }, /* Start at91sam3a series*/ /* System boots at address 0x0 */ /* gpnvm[1] = selects boot code */ /* if gpnvm[1] == 0 */ /* boot is via "SAMBA" (rom) */ /* else */ /* boot is via FLASH */ /* Selection is via gpnvm[2] */ /* endif */ /* */ /* NOTE: banks 0 & 1 switch places */ /* if gpnvm[2] == 0 */ /* Bank0 is the boot rom */ /* else */ /* Bank1 is the boot rom */ /* endif */ { .chipid_cidr = 0x283E0A60, .name = "at91sam3a8c", .total_flash_size = 512 * 1024, .total_sram_size = 96 * 1024, .n_gpnvms = 3, .n_banks = 2, { /* .bank[0] = { */ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_AX, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_512K_AX, .controller_address = 0x400e0c00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 16384, .page_size = 256, }, }, }, { .chipid_cidr = 0x283B0960, .name = "at91sam3a4c", .total_flash_size = 256 * 1024, .total_sram_size = 64 * 1024, .n_gpnvms = 3, .n_banks = 2, { /* .bank[0] = { */ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_AX, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 128 * 1024, .nsectors = 8, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_256K_AX, .controller_address = 0x400e0c00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 128 * 1024, .nsectors = 8, .sector_size = 16384, .page_size = 256, }, }, }, /* Start at91sam3x* series */ /* System boots at address 0x0 */ /* gpnvm[1] = selects boot code */ /* if gpnvm[1] == 0 */ /* boot is via "SAMBA" (rom) */ /* else */ /* boot is via FLASH */ /* Selection is via gpnvm[2] */ /* endif */ /* */ /* NOTE: banks 0 & 1 switch places */ /* if gpnvm[2] == 0 */ /* Bank0 is the boot rom */ /* else */ /* Bank1 is the boot rom */ /* endif */ /*at91sam3x8h - ES has an incorrect CIDR of 0x286E0A20*/ { .chipid_cidr = 0x286E0A20, .name = "at91sam3x8h - ES", .total_flash_size = 512 * 1024, .total_sram_size = 96 * 1024, .n_gpnvms = 3, .n_banks = 2, { /* .bank[0] = { */ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_AX, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_512K_AX, .controller_address = 0x400e0c00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 16384, .page_size = 256, }, }, }, /*at91sam3x8h - ES2 and up uses the correct CIDR of 0x286E0A60*/ { .chipid_cidr = 0x286E0A60, .name = "at91sam3x8h", .total_flash_size = 512 * 1024, .total_sram_size = 96 * 1024, .n_gpnvms = 3, .n_banks = 2, { /* .bank[0] = { */ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_AX, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_512K_AX, .controller_address = 0x400e0c00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 16384, .page_size = 256, }, }, }, { .chipid_cidr = 0x285E0A60, .name = "at91sam3x8e", .total_flash_size = 512 * 1024, .total_sram_size = 96 * 1024, .n_gpnvms = 3, .n_banks = 2, { /* .bank[0] = { */ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_AX, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_512K_AX, .controller_address = 0x400e0c00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 16384, .page_size = 256, }, }, }, { .chipid_cidr = 0x284E0A60, .name = "at91sam3x8c", .total_flash_size = 512 * 1024, .total_sram_size = 96 * 1024, .n_gpnvms = 3, .n_banks = 2, { /* .bank[0] = { */ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_AX, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_512K_AX , .controller_address = 0x400e0c00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 256 * 1024, .nsectors = 16, .sector_size = 16384, .page_size = 256, }, }, }, { .chipid_cidr = 0x285B0960, .name = "at91sam3x4e", .total_flash_size = 256 * 1024, .total_sram_size = 64 * 1024, .n_gpnvms = 3, .n_banks = 2, { /* .bank[0] = { */ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_AX, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 128 * 1024, .nsectors = 8, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_256K_AX, .controller_address = 0x400e0c00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 128 * 1024, .nsectors = 8, .sector_size = 16384, .page_size = 256, }, }, }, { .chipid_cidr = 0x284B0960, .name = "at91sam3x4c", .total_flash_size = 256 * 1024, .total_sram_size = 64 * 1024, .n_gpnvms = 3, .n_banks = 2, { /* .bank[0] = { */ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 0, .base_address = FLASH_BANK0_BASE_AX, .controller_address = 0x400e0a00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 128 * 1024, .nsectors = 8, .sector_size = 16384, .page_size = 256, }, /* .bank[1] = { */ { .probed = 0, .pChip = NULL, .pBank = NULL, .bank_number = 1, .base_address = FLASH_BANK1_BASE_256K_AX, .controller_address = 0x400e0c00, .flash_wait_states = 6, /* workaround silicon bug */ .present = 1, .size_bytes = 128 * 1024, .nsectors = 8, .sector_size = 16384, .page_size = 256, }, }, }, /* terminate */ { .chipid_cidr = 0, .name = NULL, } }; /* Globals above */ /*********************************************************************** ********************************************************************** ********************************************************************** ********************************************************************** ********************************************************************** **********************************************************************/ /* *ATMEL* style code - from the SAM3 driver code */ /** * Get the current status of the EEFC and * the value of some status bits (LOCKE, PROGE). * @param pPrivate - info about the bank * @param v - result goes here */ static int EFC_GetStatus(struct sam3_bank_private *pPrivate, uint32_t *v) { int r; r = target_read_u32(pPrivate->pChip->target, pPrivate->controller_address + offset_EFC_FSR, v); LOG_DEBUG("Status: 0x%08x (lockerror: %d, cmderror: %d, ready: %d)", (unsigned int)(*v), ((unsigned int)((*v >> 2) & 1)), ((unsigned int)((*v >> 1) & 1)), ((unsigned int)((*v >> 0) & 1))); return r; } /** * Get the result of the last executed command. * @param pPrivate - info about the bank * @param v - result goes here */ static int EFC_GetResult(struct sam3_bank_private *pPrivate, uint32_t *v) { int r; uint32_t rv; r = target_read_u32(pPrivate->pChip->target, pPrivate->controller_address + offset_EFC_FRR, &rv); if (v) *v = rv; LOG_DEBUG("Result: 0x%08x", ((unsigned int)(rv))); return r; } static int EFC_StartCommand(struct sam3_bank_private *pPrivate, unsigned command, unsigned argument) { uint32_t n, v; int r; int retry; retry = 0; do_retry: /* Check command & argument */ switch (command) { case AT91C_EFC_FCMD_WP: case AT91C_EFC_FCMD_WPL: case AT91C_EFC_FCMD_EWP: case AT91C_EFC_FCMD_EWPL: /* case AT91C_EFC_FCMD_EPL: */ /* case AT91C_EFC_FCMD_EPA: */ case AT91C_EFC_FCMD_SLB: case AT91C_EFC_FCMD_CLB: n = (pPrivate->size_bytes / pPrivate->page_size); if (argument >= n) LOG_ERROR("*BUG*: Embedded flash has only %u pages", (unsigned)(n)); break; case AT91C_EFC_FCMD_SFB: case AT91C_EFC_FCMD_CFB: if (argument >= pPrivate->pChip->details.n_gpnvms) { LOG_ERROR("*BUG*: Embedded flash has only %d GPNVMs", pPrivate->pChip->details.n_gpnvms); } break; case AT91C_EFC_FCMD_GETD: case AT91C_EFC_FCMD_EA: case AT91C_EFC_FCMD_GLB: case AT91C_EFC_FCMD_GFB: case AT91C_EFC_FCMD_STUI: case AT91C_EFC_FCMD_SPUI: if (argument != 0) LOG_ERROR("Argument is meaningless for cmd: %d", command); break; default: LOG_ERROR("Unknown command %d", command); break; } if (command == AT91C_EFC_FCMD_SPUI) { /* this is a very special situation. */ /* Situation (1) - error/retry - see below */ /* And we are being called recursively */ /* Situation (2) - normal, finished reading unique id */ } else { /* it should be "ready" */ EFC_GetStatus(pPrivate, &v); if (v & 1) { /* then it is ready */ /* we go on */ } else { if (retry) { /* we have done this before */ /* the controller is not responding. */ LOG_ERROR("flash controller(%d) is not ready! Error", pPrivate->bank_number); return ERROR_FAIL; } else { retry++; LOG_ERROR("Flash controller(%d) is not ready, attempting reset", pPrivate->bank_number); /* we do that by issuing the *STOP* command */ EFC_StartCommand(pPrivate, AT91C_EFC_FCMD_SPUI, 0); /* above is recursive, and further recursion is blocked by */ /* if (command == AT91C_EFC_FCMD_SPUI) above */ goto do_retry; } } } v = (0x5A << 24) | (argument << 8) | command; LOG_DEBUG("Command: 0x%08x", ((unsigned int)(v))); r = target_write_u32(pPrivate->pBank->target, pPrivate->controller_address + offset_EFC_FCR, v); if (r != ERROR_OK) LOG_DEBUG("Error Write failed"); return r; } /** * Performs the given command and wait until its completion (or an error). * @param pPrivate - info about the bank * @param command - Command to perform. * @param argument - Optional command argument. * @param status - put command status bits here */ static int EFC_PerformCommand(struct sam3_bank_private *pPrivate, unsigned command, unsigned argument, uint32_t *status) { int r; uint32_t v; long long ms_now, ms_end; /* default */ if (status) *status = 0; r = EFC_StartCommand(pPrivate, command, argument); if (r != ERROR_OK) return r; ms_end = 500 + timeval_ms(); do { r = EFC_GetStatus(pPrivate, &v); if (r != ERROR_OK) return r; ms_now = timeval_ms(); if (ms_now > ms_end) { /* error */ LOG_ERROR("Command timeout"); return ERROR_FAIL; } } while ((v & 1) == 0); /* error bits.. */ if (status) *status = (v & 0x6); return ERROR_OK; } /** * Read the unique ID. * @param pPrivate - info about the bank * The unique ID is stored in the 'pPrivate' structure. */ static int FLASHD_ReadUniqueID(struct sam3_bank_private *pPrivate) { int r; uint32_t v; int x; /* assume 0 */ pPrivate->pChip->cfg.unique_id[0] = 0; pPrivate->pChip->cfg.unique_id[1] = 0; pPrivate->pChip->cfg.unique_id[2] = 0; pPrivate->pChip->cfg.unique_id[3] = 0; LOG_DEBUG("Begin"); r = EFC_StartCommand(pPrivate, AT91C_EFC_FCMD_STUI, 0); if (r < 0) return r; for (x = 0; x < 4; x++) { r = target_read_u32(pPrivate->pChip->target, pPrivate->pBank->base + (x * 4), &v); if (r < 0) return r; pPrivate->pChip->cfg.unique_id[x] = v; } r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_SPUI, 0, NULL); LOG_DEBUG("End: R=%d, id = 0x%08x, 0x%08x, 0x%08x, 0x%08x", r, (unsigned int)(pPrivate->pChip->cfg.unique_id[0]), (unsigned int)(pPrivate->pChip->cfg.unique_id[1]), (unsigned int)(pPrivate->pChip->cfg.unique_id[2]), (unsigned int)(pPrivate->pChip->cfg.unique_id[3])); return r; } /** * Erases the entire flash. * @param pPrivate - the info about the bank. */ static int FLASHD_EraseEntireBank(struct sam3_bank_private *pPrivate) { LOG_DEBUG("Here"); return EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_EA, 0, NULL); } /** * Gets current GPNVM state. * @param pPrivate - info about the bank. * @param gpnvm - GPNVM bit index. * @param puthere - result stored here. */ /* ------------------------------------------------------------------------------ */ static int FLASHD_GetGPNVM(struct sam3_bank_private *pPrivate, unsigned gpnvm, unsigned *puthere) { uint32_t v; int r; LOG_DEBUG("Here"); if (pPrivate->bank_number != 0) { LOG_ERROR("GPNVM only works with Bank0"); return ERROR_FAIL; } if (gpnvm >= pPrivate->pChip->details.n_gpnvms) { LOG_ERROR("Invalid GPNVM %d, max: %d, ignored", gpnvm, pPrivate->pChip->details.n_gpnvms); return ERROR_FAIL; } /* Get GPNVMs status */ r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_GFB, 0, NULL); if (r != ERROR_OK) { LOG_ERROR("Failed"); return r; } r = EFC_GetResult(pPrivate, &v); if (puthere) { /* Check if GPNVM is set */ /* get the bit and make it a 0/1 */ *puthere = (v >> gpnvm) & 1; } return r; } /** * Clears the selected GPNVM bit. * @param pPrivate info about the bank * @param gpnvm GPNVM index. * @returns 0 if successful; otherwise returns an error code. */ static int FLASHD_ClrGPNVM(struct sam3_bank_private *pPrivate, unsigned gpnvm) { int r; unsigned v; LOG_DEBUG("Here"); if (pPrivate->bank_number != 0) { LOG_ERROR("GPNVM only works with Bank0"); return ERROR_FAIL; } if (gpnvm >= pPrivate->pChip->details.n_gpnvms) { LOG_ERROR("Invalid GPNVM %d, max: %d, ignored", gpnvm, pPrivate->pChip->details.n_gpnvms); return ERROR_FAIL; } r = FLASHD_GetGPNVM(pPrivate, gpnvm, &v); if (r != ERROR_OK) { LOG_DEBUG("Failed: %d", r); return r; } r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_CFB, gpnvm, NULL); LOG_DEBUG("End: %d", r); return r; } /** * Sets the selected GPNVM bit. * @param pPrivate info about the bank * @param gpnvm GPNVM index. */ static int FLASHD_SetGPNVM(struct sam3_bank_private *pPrivate, unsigned gpnvm) { int r; unsigned v; if (pPrivate->bank_number != 0) { LOG_ERROR("GPNVM only works with Bank0"); return ERROR_FAIL; } if (gpnvm >= pPrivate->pChip->details.n_gpnvms) { LOG_ERROR("Invalid GPNVM %d, max: %d, ignored", gpnvm, pPrivate->pChip->details.n_gpnvms); return ERROR_FAIL; } r = FLASHD_GetGPNVM(pPrivate, gpnvm, &v); if (r != ERROR_OK) return r; if (v) { /* already set */ r = ERROR_OK; } else { /* set it */ r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_SFB, gpnvm, NULL); } return r; } /** * Returns a bit field (at most 64) of locked regions within a page. * @param pPrivate info about the bank * @param v where to store locked bits */ static int FLASHD_GetLockBits(struct sam3_bank_private *pPrivate, uint32_t *v) { int r; LOG_DEBUG("Here"); r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_GLB, 0, NULL); if (r == ERROR_OK) r = EFC_GetResult(pPrivate, v); LOG_DEBUG("End: %d", r); return r; } /** * Unlocks all the regions in the given address range. * @param pPrivate info about the bank * @param start_sector first sector to unlock * @param end_sector last (inclusive) to unlock */ static int FLASHD_Unlock(struct sam3_bank_private *pPrivate, unsigned start_sector, unsigned end_sector) { int r; uint32_t status; uint32_t pg; uint32_t pages_per_sector; pages_per_sector = pPrivate->sector_size / pPrivate->page_size; /* Unlock all pages */ while (start_sector <= end_sector) { pg = start_sector * pages_per_sector; r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_CLB, pg, &status); if (r != ERROR_OK) return r; start_sector++; } return ERROR_OK; } /** * Locks regions * @param pPrivate - info about the bank * @param start_sector - first sector to lock * @param end_sector - last sector (inclusive) to lock */ static int FLASHD_Lock(struct sam3_bank_private *pPrivate, unsigned start_sector, unsigned end_sector) { uint32_t status; uint32_t pg; uint32_t pages_per_sector; int r; pages_per_sector = pPrivate->sector_size / pPrivate->page_size; /* Lock all pages */ while (start_sector <= end_sector) { pg = start_sector * pages_per_sector; r = EFC_PerformCommand(pPrivate, AT91C_EFC_FCMD_SLB, pg, &status); if (r != ERROR_OK) return r; start_sector++; } return ERROR_OK; } /****** END SAM3 CODE ********/ /* begin helpful debug code */ /* print the fieldname, the field value, in dec & hex, and return field value */ static uint32_t sam3_reg_fieldname(struct sam3_chip *pChip, const char *regname, uint32_t value, unsigned shift, unsigned width) { uint32_t v; int hwidth, dwidth; /* extract the field */ v = value >> shift; v = v & ((1 << width)-1); if (width <= 16) { hwidth = 4; dwidth = 5; } else { hwidth = 8; dwidth = 12; } /* show the basics */ LOG_USER_N("\t%*s: %*d [0x%0*x] ", REG_NAME_WIDTH, regname, dwidth, v, hwidth, v); return v; } static const char _unknown[] = "unknown"; static const char *const eproc_names[] = { _unknown, /* 0 */ "arm946es", /* 1 */ "arm7tdmi", /* 2 */ "cortex-m3", /* 3 */ "arm920t", /* 4 */ "arm926ejs", /* 5 */ _unknown, /* 6 */ _unknown, /* 7 */ _unknown, /* 8 */ _unknown, /* 9 */ _unknown, /* 10 */ _unknown, /* 11 */ _unknown, /* 12 */ _unknown, /* 13 */ _unknown, /* 14 */ _unknown, /* 15 */ }; #define nvpsize2 nvpsize /* these two tables are identical */ static const char *const nvpsize[] = { "none", /* 0 */ "8K bytes", /* 1 */ "16K bytes", /* 2 */ "32K bytes", /* 3 */ _unknown, /* 4 */ "64K bytes", /* 5 */ _unknown, /* 6 */ "128K bytes", /* 7 */ _unknown, /* 8 */ "256K bytes", /* 9 */ "512K bytes", /* 10 */ _unknown, /* 11 */ "1024K bytes", /* 12 */ _unknown, /* 13 */ "2048K bytes", /* 14 */ _unknown, /* 15 */ }; static const char *const sramsize[] = { "48K Bytes", /* 0 */ "1K Bytes", /* 1 */ "2K Bytes", /* 2 */ "6K Bytes", /* 3 */ "112K Bytes", /* 4 */ "4K Bytes", /* 5 */ "80K Bytes", /* 6 */ "160K Bytes", /* 7 */ "8K Bytes", /* 8 */ "16K Bytes", /* 9 */ "32K Bytes", /* 10 */ "64K Bytes", /* 11 */ "128K Bytes", /* 12 */ "256K Bytes", /* 13 */ "96K Bytes", /* 14 */ "512K Bytes", /* 15 */ }; static const struct archnames { unsigned value; const char *name; } archnames[] = { { 0x19, "AT91SAM9xx Series" }, { 0x29, "AT91SAM9XExx Series" }, { 0x34, "AT91x34 Series" }, { 0x37, "CAP7 Series" }, { 0x39, "CAP9 Series" }, { 0x3B, "CAP11 Series" }, { 0x40, "AT91x40 Series" }, { 0x42, "AT91x42 Series" }, { 0x55, "AT91x55 Series" }, { 0x60, "AT91SAM7Axx Series" }, { 0x61, "AT91SAM7AQxx Series" }, { 0x63, "AT91x63 Series" }, { 0x70, "AT91SAM7Sxx Series" }, { 0x71, "AT91SAM7XCxx Series" }, { 0x72, "AT91SAM7SExx Series" }, { 0x73, "AT91SAM7Lxx Series" }, { 0x75, "AT91SAM7Xxx Series" }, { 0x76, "AT91SAM7SLxx Series" }, { 0x80, "ATSAM3UxC Series (100-pin version)" }, { 0x81, "ATSAM3UxE Series (144-pin version)" }, { 0x83, "ATSAM3AxC Series (100-pin version)" }, { 0x84, "ATSAM3XxC Series (100-pin version)" }, { 0x85, "ATSAM3XxE Series (144-pin version)" }, { 0x86, "ATSAM3XxG Series (208/217-pin version)" }, { 0x88, "ATSAM3SxA Series (48-pin version)" }, { 0x89, "ATSAM3SxB Series (64-pin version)" }, { 0x8A, "ATSAM3SxC Series (100-pin version)" }, { 0x92, "AT91x92 Series" }, { 0x93, "ATSAM3NxA Series (48-pin version)" }, { 0x94, "ATSAM3NxB Series (64-pin version)" }, { 0x95, "ATSAM3NxC Series (100-pin version)" }, { 0x98, "ATSAM3SDxA Series (48-pin version)" }, { 0x99, "ATSAM3SDxB Series (64-pin version)" }, { 0x9A, "ATSAM3SDxC Series (100-pin version)" }, { 0xA5, "ATSAM5A" }, { 0xF0, "AT75Cxx Series" }, { -1, NULL }, }; static const char *const nvptype[] = { "rom", /* 0 */ "romless or onchip flash", /* 1 */ "embedded flash memory",/* 2 */ "rom(nvpsiz) + embedded flash (nvpsiz2)", /* 3 */ "sram emulating flash", /* 4 */ _unknown, /* 5 */ _unknown, /* 6 */ _unknown, /* 7 */ }; static const char *_yes_or_no(uint32_t v) { if (v) return "YES"; else return "NO"; } static const char *const _rc_freq[] = { "4 MHz", "8 MHz", "12 MHz", "reserved" }; static void sam3_explain_ckgr_mor(struct sam3_chip *pChip) { uint32_t v; uint32_t rcen; v = sam3_reg_fieldname(pChip, "MOSCXTEN", pChip->cfg.CKGR_MOR, 0, 1); LOG_USER("(main xtal enabled: %s)", _yes_or_no(v)); v = sam3_reg_fieldname(pChip, "MOSCXTBY", pChip->cfg.CKGR_MOR, 1, 1); LOG_USER("(main osc bypass: %s)", _yes_or_no(v)); rcen = sam3_reg_fieldname(pChip, "MOSCRCEN", pChip->cfg.CKGR_MOR, 3, 1); LOG_USER("(onchip RC-OSC enabled: %s)", _yes_or_no(rcen)); v = sam3_reg_fieldname(pChip, "MOSCRCF", pChip->cfg.CKGR_MOR, 4, 3); LOG_USER("(onchip RC-OSC freq: %s)", _rc_freq[v]); pChip->cfg.rc_freq = 0; if (rcen) { switch (v) { default: pChip->cfg.rc_freq = 0; break; case 0: pChip->cfg.rc_freq = 4 * 1000 * 1000; break; case 1: pChip->cfg.rc_freq = 8 * 1000 * 1000; break; case 2: pChip->cfg.rc_freq = 12 * 1000 * 1000; break; } } v = sam3_reg_fieldname(pChip, "MOSCXTST", pChip->cfg.CKGR_MOR, 8, 8); LOG_USER("(startup clks, time= %f uSecs)", ((float)(v * 1000000)) / ((float)(pChip->cfg.slow_freq))); v = sam3_reg_fieldname(pChip, "MOSCSEL", pChip->cfg.CKGR_MOR, 24, 1); LOG_USER("(mainosc source: %s)", v ? "external xtal" : "internal RC"); v = sam3_reg_fieldname(pChip, "CFDEN", pChip->cfg.CKGR_MOR, 25, 1); LOG_USER("(clock failure enabled: %s)", _yes_or_no(v)); } static void sam3_explain_chipid_cidr(struct sam3_chip *pChip) { int x; uint32_t v; const char *cp; sam3_reg_fieldname(pChip, "Version", pChip->cfg.CHIPID_CIDR, 0, 5); LOG_USER_N("\n"); v = sam3_reg_fieldname(pChip, "EPROC", pChip->cfg.CHIPID_CIDR, 5, 3); LOG_USER("%s", eproc_names[v]); v = sam3_reg_fieldname(pChip, "NVPSIZE", pChip->cfg.CHIPID_CIDR, 8, 4); LOG_USER("%s", nvpsize[v]); v = sam3_reg_fieldname(pChip, "NVPSIZE2", pChip->cfg.CHIPID_CIDR, 12, 4); LOG_USER("%s", nvpsize2[v]); v = sam3_reg_fieldname(pChip, "SRAMSIZE", pChip->cfg.CHIPID_CIDR, 16, 4); LOG_USER("%s", sramsize[v]); v = sam3_reg_fieldname(pChip, "ARCH", pChip->cfg.CHIPID_CIDR, 20, 8); cp = _unknown; for (x = 0; archnames[x].name; x++) { if (v == archnames[x].value) { cp = archnames[x].name; break; } } LOG_USER("%s", cp); v = sam3_reg_fieldname(pChip, "NVPTYP", pChip->cfg.CHIPID_CIDR, 28, 3); LOG_USER("%s", nvptype[v]); v = sam3_reg_fieldname(pChip, "EXTID", pChip->cfg.CHIPID_CIDR, 31, 1); LOG_USER("(exists: %s)", _yes_or_no(v)); } static void sam3_explain_ckgr_mcfr(struct sam3_chip *pChip) { uint32_t v; v = sam3_reg_fieldname(pChip, "MAINFRDY", pChip->cfg.CKGR_MCFR, 16, 1); LOG_USER("(main ready: %s)", _yes_or_no(v)); v = sam3_reg_fieldname(pChip, "MAINF", pChip->cfg.CKGR_MCFR, 0, 16); v = (v * pChip->cfg.slow_freq) / 16; pChip->cfg.mainosc_freq = v; LOG_USER("(%3.03f Mhz (%d.%03dkhz slowclk)", _tomhz(v), pChip->cfg.slow_freq / 1000, pChip->cfg.slow_freq % 1000); } static void sam3_explain_ckgr_plla(struct sam3_chip *pChip) { uint32_t mula, diva; diva = sam3_reg_fieldname(pChip, "DIVA", pChip->cfg.CKGR_PLLAR, 0, 8); LOG_USER_N("\n"); mula = sam3_reg_fieldname(pChip, "MULA", pChip->cfg.CKGR_PLLAR, 16, 11); LOG_USER_N("\n"); pChip->cfg.plla_freq = 0; if (mula == 0) LOG_USER("\tPLLA Freq: (Disabled,mula = 0)"); else if (diva == 0) LOG_USER("\tPLLA Freq: (Disabled,diva = 0)"); else if (diva >= 1) { pChip->cfg.plla_freq = (pChip->cfg.mainosc_freq * (mula + 1) / diva); LOG_USER("\tPLLA Freq: %3.03f MHz", _tomhz(pChip->cfg.plla_freq)); } } static void sam3_explain_mckr(struct sam3_chip *pChip) { uint32_t css, pres, fin = 0; int pdiv = 0; const char *cp = NULL; css = sam3_reg_fieldname(pChip, "CSS", pChip->cfg.PMC_MCKR, 0, 2); switch (css & 3) { case 0: fin = pChip->cfg.slow_freq; cp = "slowclk"; break; case 1: fin = pChip->cfg.mainosc_freq; cp = "mainosc"; break; case 2: fin = pChip->cfg.plla_freq; cp = "plla"; break; case 3: if (pChip->cfg.CKGR_UCKR & (1 << 16)) { fin = 480 * 1000 * 1000; cp = "upll"; } else { fin = 0; cp = "upll (*ERROR* UPLL is disabled)"; } break; default: assert(0); break; } LOG_USER("%s (%3.03f Mhz)", cp, _tomhz(fin)); pres = sam3_reg_fieldname(pChip, "PRES", pChip->cfg.PMC_MCKR, 4, 3); switch (pres & 0x07) { case 0: pdiv = 1; cp = "selected clock"; break; case 1: pdiv = 2; cp = "clock/2"; break; case 2: pdiv = 4; cp = "clock/4"; break; case 3: pdiv = 8; cp = "clock/8"; break; case 4: pdiv = 16; cp = "clock/16"; break; case 5: pdiv = 32; cp = "clock/32"; break; case 6: pdiv = 64; cp = "clock/64"; break; case 7: pdiv = 6; cp = "clock/6"; break; default: assert(0); break; } LOG_USER("(%s)", cp); fin = fin / pdiv; /* sam3 has a *SINGLE* clock - */ /* other at91 series parts have divisors for these. */ pChip->cfg.cpu_freq = fin; pChip->cfg.mclk_freq = fin; pChip->cfg.fclk_freq = fin; LOG_USER("\t\tResult CPU Freq: %3.03f", _tomhz(fin)); } #if 0 static struct sam3_chip *target2sam3(struct target *pTarget) { struct sam3_chip *pChip; if (pTarget == NULL) return NULL; pChip = all_sam3_chips; while (pChip) { if (pChip->target == pTarget) break; /* return below */ else pChip = pChip->next; } return pChip; } #endif static uint32_t *sam3_get_reg_ptr(struct sam3_cfg *pCfg, const struct sam3_reg_list *pList) { /* this function exists to help */ /* keep funky offsetof() errors */ /* and casting from causing bugs */ /* By using prototypes - we can detect what would */ /* be casting errors. */ return (uint32_t *)(void *)(((char *)(pCfg)) + pList->struct_offset); } #define SAM3_ENTRY(NAME, FUNC) { .address = SAM3_ ## NAME, .struct_offset = offsetof( \ struct sam3_cfg, \ NAME), # NAME, FUNC } static const struct sam3_reg_list sam3_all_regs[] = { SAM3_ENTRY(CKGR_MOR, sam3_explain_ckgr_mor), SAM3_ENTRY(CKGR_MCFR, sam3_explain_ckgr_mcfr), SAM3_ENTRY(CKGR_PLLAR, sam3_explain_ckgr_plla), SAM3_ENTRY(CKGR_UCKR, NULL), SAM3_ENTRY(PMC_FSMR, NULL), SAM3_ENTRY(PMC_FSPR, NULL), SAM3_ENTRY(PMC_IMR, NULL), SAM3_ENTRY(PMC_MCKR, sam3_explain_mckr), SAM3_ENTRY(PMC_PCK0, NULL), SAM3_ENTRY(PMC_PCK1, NULL), SAM3_ENTRY(PMC_PCK2, NULL), SAM3_ENTRY(PMC_PCSR, NULL), SAM3_ENTRY(PMC_SCSR, NULL), SAM3_ENTRY(PMC_SR, NULL), SAM3_ENTRY(CHIPID_CIDR, sam3_explain_chipid_cidr), SAM3_ENTRY(CHIPID_CIDR2, sam3_explain_chipid_cidr), SAM3_ENTRY(CHIPID_EXID, NULL), SAM3_ENTRY(CHIPID_EXID2, NULL), /* TERMINATE THE LIST */ { .name = NULL } }; #undef SAM3_ENTRY static struct sam3_bank_private *get_sam3_bank_private(struct flash_bank *bank) { return (struct sam3_bank_private *)(bank->driver_priv); } /** * Given a pointer to where it goes in the structure, * determine the register name, address from the all registers table. */ static const struct sam3_reg_list *sam3_GetReg(struct sam3_chip *pChip, uint32_t *goes_here) { const struct sam3_reg_list *pReg; pReg = &(sam3_all_regs[0]); while (pReg->name) { uint32_t *pPossible; /* calculate where this one go.. */ /* it is "possibly" this register. */ pPossible = ((uint32_t *)(void *)(((char *)(&(pChip->cfg))) + pReg->struct_offset)); /* well? Is it this register */ if (pPossible == goes_here) { /* Jump for joy! */ return pReg; } /* next... */ pReg++; } /* This is *TOTAL*PANIC* - we are totally screwed. */ LOG_ERROR("INVALID SAM3 REGISTER"); return NULL; } static int sam3_ReadThisReg(struct sam3_chip *pChip, uint32_t *goes_here) { const struct sam3_reg_list *pReg; int r; pReg = sam3_GetReg(pChip, goes_here); if (!pReg) return ERROR_FAIL; r = target_read_u32(pChip->target, pReg->address, goes_here); if (r != ERROR_OK) { LOG_ERROR("Cannot read SAM3 register: %s @ 0x%08x, Err: %d", pReg->name, (unsigned)(pReg->address), r); } return r; } static int sam3_ReadAllRegs(struct sam3_chip *pChip) { int r; const struct sam3_reg_list *pReg; pReg = &(sam3_all_regs[0]); while (pReg->name) { r = sam3_ReadThisReg(pChip, sam3_get_reg_ptr(&(pChip->cfg), pReg)); if (r != ERROR_OK) { LOG_ERROR("Cannot read SAM3 register: %s @ 0x%08x, Error: %d", pReg->name, ((unsigned)(pReg->address)), r); return r; } pReg++; } /* Chip identification register * * Unfortunately, the chip identification register is not at * a constant address across all of the SAM3 series'. As a * consequence, a simple heuristic is used to find where it's * at... * * If the contents at the first address is zero, then we know * that the second address is where the chip id register is. * We can deduce this because for those SAM's that have the * chip id @ 0x400e0940, the first address, 0x400e0740, is * located in the memory map of the Power Management Controller * (PMC). Furthermore, the address is not used by the PMC. * So when read, the memory controller returns zero.*/ if (pChip->cfg.CHIPID_CIDR == 0) { /*Put the correct CIDR and EXID values in the pChip structure */ pChip->cfg.CHIPID_CIDR = pChip->cfg.CHIPID_CIDR2; pChip->cfg.CHIPID_EXID = pChip->cfg.CHIPID_EXID2; } return ERROR_OK; } static int sam3_GetInfo(struct sam3_chip *pChip) { const struct sam3_reg_list *pReg; uint32_t regval; pReg = &(sam3_all_regs[0]); while (pReg->name) { /* display all regs */ LOG_DEBUG("Start: %s", pReg->name); regval = *sam3_get_reg_ptr(&(pChip->cfg), pReg); LOG_USER("%*s: [0x%08x] -> 0x%08x", REG_NAME_WIDTH, pReg->name, pReg->address, regval); if (pReg->explain_func) (*(pReg->explain_func))(pChip); LOG_DEBUG("End: %s", pReg->name); pReg++; } LOG_USER(" rc-osc: %3.03f MHz", _tomhz(pChip->cfg.rc_freq)); LOG_USER(" mainosc: %3.03f MHz", _tomhz(pChip->cfg.mainosc_freq)); LOG_USER(" plla: %3.03f MHz", _tomhz(pChip->cfg.plla_freq)); LOG_USER(" cpu-freq: %3.03f MHz", _tomhz(pChip->cfg.cpu_freq)); LOG_USER("mclk-freq: %3.03f MHz", _tomhz(pChip->cfg.mclk_freq)); LOG_USER(" UniqueId: 0x%08x 0x%08x 0x%08x 0x%08x", pChip->cfg.unique_id[0], pChip->cfg.unique_id[1], pChip->cfg.unique_id[2], pChip->cfg.unique_id[3]); return ERROR_OK; } static int sam3_erase_check(struct flash_bank *bank) { int x; LOG_DEBUG("Here"); if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (0 == bank->num_sectors) { LOG_ERROR("Target: not supported/not probed"); return ERROR_FAIL; } LOG_INFO("sam3 - supports auto-erase, erase_check ignored"); for (x = 0; x < bank->num_sectors; x++) bank->sectors[x].is_erased = 1; LOG_DEBUG("Done"); return ERROR_OK; } static int sam3_protect_check(struct flash_bank *bank) { int r; uint32_t v = 0; unsigned x; struct sam3_bank_private *pPrivate; LOG_DEBUG("Begin"); if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } pPrivate = get_sam3_bank_private(bank); if (!pPrivate) { LOG_ERROR("no private for this bank?"); return ERROR_FAIL; } if (!(pPrivate->probed)) return ERROR_FLASH_BANK_NOT_PROBED; r = FLASHD_GetLockBits(pPrivate, &v); if (r != ERROR_OK) { LOG_DEBUG("Failed: %d", r); return r; } for (x = 0; x < pPrivate->nsectors; x++) bank->sectors[x].is_protected = (!!(v & (1 << x))); LOG_DEBUG("Done"); return ERROR_OK; } FLASH_BANK_COMMAND_HANDLER(sam3_flash_bank_command) { struct sam3_chip *pChip; pChip = all_sam3_chips; /* is this an existing chip? */ while (pChip) { if (pChip->target == bank->target) break; pChip = pChip->next; } if (!pChip) { /* this is a *NEW* chip */ pChip = calloc(1, sizeof(struct sam3_chip)); if (!pChip) { LOG_ERROR("NO RAM!"); return ERROR_FAIL; } pChip->target = bank->target; /* insert at head */ pChip->next = all_sam3_chips; all_sam3_chips = pChip; pChip->target = bank->target; /* assumption is this runs at 32khz */ pChip->cfg.slow_freq = 32768; pChip->probed = 0; } switch (bank->base) { default: LOG_ERROR("Address 0x%08x invalid bank address (try 0x%08x or 0x%08x " "[at91sam3u series] or 0x%08x [at91sam3s series] or " "0x%08x [at91sam3n series] or 0x%08x or 0x%08x or 0x%08x[at91sam3ax series] )", ((unsigned int)(bank->base)), ((unsigned int)(FLASH_BANK0_BASE_U)), ((unsigned int)(FLASH_BANK1_BASE_U)), ((unsigned int)(FLASH_BANK_BASE_S)), ((unsigned int)(FLASH_BANK_BASE_N)), ((unsigned int)(FLASH_BANK0_BASE_AX)), ((unsigned int)(FLASH_BANK1_BASE_256K_AX)), ((unsigned int)(FLASH_BANK1_BASE_512K_AX))); return ERROR_FAIL; break; /* at91sam3s and at91sam3n series only has bank 0*/ /* at91sam3u and at91sam3ax series has the same address for bank 0*/ case FLASH_BANK_BASE_S: case FLASH_BANK0_BASE_U: bank->driver_priv = &(pChip->details.bank[0]); bank->bank_number = 0; pChip->details.bank[0].pChip = pChip; pChip->details.bank[0].pBank = bank; break; /* Bank 1 of at91sam3u or at91sam3ax series */ case FLASH_BANK1_BASE_U: case FLASH_BANK1_BASE_256K_AX: case FLASH_BANK1_BASE_512K_AX: bank->driver_priv = &(pChip->details.bank[1]); bank->bank_number = 1; pChip->details.bank[1].pChip = pChip; pChip->details.bank[1].pBank = bank; break; } /* we initialize after probing. */ return ERROR_OK; } static int sam3_GetDetails(struct sam3_bank_private *pPrivate) { const struct sam3_chip_details *pDetails; struct sam3_chip *pChip; struct flash_bank *saved_banks[SAM3_MAX_FLASH_BANKS]; unsigned x; LOG_DEBUG("Begin"); pDetails = all_sam3_details; while (pDetails->name) { /* Compare cidr without version bits */ if (pDetails->chipid_cidr == (pPrivate->pChip->cfg.CHIPID_CIDR & 0xFFFFFFE0)) break; else pDetails++; } if (pDetails->name == NULL) { LOG_ERROR("SAM3 ChipID 0x%08x not found in table (perhaps you can ID this chip?)", (unsigned int)(pPrivate->pChip->cfg.CHIPID_CIDR)); /* Help the victim, print details about the chip */ LOG_INFO("SAM3 CHIPID_CIDR: 0x%08x decodes as follows", pPrivate->pChip->cfg.CHIPID_CIDR); sam3_explain_chipid_cidr(pPrivate->pChip); return ERROR_FAIL; } /* DANGER: THERE ARE DRAGONS HERE */ /* get our pChip - it is going */ /* to be over-written shortly */ pChip = pPrivate->pChip; /* Note that, in reality: */ /* */ /* pPrivate = &(pChip->details.bank[0]) */ /* or pPrivate = &(pChip->details.bank[1]) */ /* */ /* save the "bank" pointers */ for (x = 0; x < SAM3_MAX_FLASH_BANKS; x++) saved_banks[x] = pChip->details.bank[x].pBank; /* Overwrite the "details" structure. */ memcpy(&(pPrivate->pChip->details), pDetails, sizeof(pPrivate->pChip->details)); /* now fix the ghosted pointers */ for (x = 0; x < SAM3_MAX_FLASH_BANKS; x++) { pChip->details.bank[x].pChip = pChip; pChip->details.bank[x].pBank = saved_banks[x]; } /* update the *BANK*SIZE* */ LOG_DEBUG("End"); return ERROR_OK; } static int _sam3_probe(struct flash_bank *bank, int noise) { unsigned x; int r; struct sam3_bank_private *pPrivate; LOG_DEBUG("Begin: Bank: %d, Noise: %d", bank->bank_number, noise); if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } pPrivate = get_sam3_bank_private(bank); if (!pPrivate) { LOG_ERROR("Invalid/unknown bank number"); return ERROR_FAIL; } r = sam3_ReadAllRegs(pPrivate->pChip); if (r != ERROR_OK) return r; LOG_DEBUG("Here"); if (pPrivate->pChip->probed) r = sam3_GetInfo(pPrivate->pChip); else r = sam3_GetDetails(pPrivate); if (r != ERROR_OK) return r; /* update the flash bank size */ for (x = 0; x < SAM3_MAX_FLASH_BANKS; x++) { if (bank->base == pPrivate->pChip->details.bank[x].base_address) { bank->size = pPrivate->pChip->details.bank[x].size_bytes; break; } } if (bank->sectors == NULL) { bank->sectors = calloc(pPrivate->nsectors, (sizeof((bank->sectors)[0]))); if (bank->sectors == NULL) { LOG_ERROR("No memory!"); return ERROR_FAIL; } bank->num_sectors = pPrivate->nsectors; for (x = 0; ((int)(x)) < bank->num_sectors; x++) { bank->sectors[x].size = pPrivate->sector_size; bank->sectors[x].offset = x * (pPrivate->sector_size); /* mark as unknown */ bank->sectors[x].is_erased = -1; bank->sectors[x].is_protected = -1; } } pPrivate->probed = 1; r = sam3_protect_check(bank); if (r != ERROR_OK) return r; LOG_DEBUG("Bank = %d, nbanks = %d", pPrivate->bank_number, pPrivate->pChip->details.n_banks); if ((pPrivate->bank_number + 1) == pPrivate->pChip->details.n_banks) { /* read unique id, */ /* it appears to be associated with the *last* flash bank. */ FLASHD_ReadUniqueID(pPrivate); } return r; } static int sam3_probe(struct flash_bank *bank) { return _sam3_probe(bank, 1); } static int sam3_auto_probe(struct flash_bank *bank) { return _sam3_probe(bank, 0); } static int sam3_erase(struct flash_bank *bank, int first, int last) { struct sam3_bank_private *pPrivate; int r; LOG_DEBUG("Here"); if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } r = sam3_auto_probe(bank); if (r != ERROR_OK) { LOG_DEBUG("Here,r=%d", r); return r; } pPrivate = get_sam3_bank_private(bank); if (!(pPrivate->probed)) return ERROR_FLASH_BANK_NOT_PROBED; if ((first == 0) && ((last + 1) == ((int)(pPrivate->nsectors)))) { /* whole chip */ LOG_DEBUG("Here"); return FLASHD_EraseEntireBank(pPrivate); } LOG_INFO("sam3 auto-erases while programming (request ignored)"); return ERROR_OK; } static int sam3_protect(struct flash_bank *bank, int set, int first, int last) { struct sam3_bank_private *pPrivate; int r; LOG_DEBUG("Here"); if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } pPrivate = get_sam3_bank_private(bank); if (!(pPrivate->probed)) return ERROR_FLASH_BANK_NOT_PROBED; if (set) r = FLASHD_Lock(pPrivate, (unsigned)(first), (unsigned)(last)); else r = FLASHD_Unlock(pPrivate, (unsigned)(first), (unsigned)(last)); LOG_DEBUG("End: r=%d", r); return r; } static int sam3_info(struct flash_bank *bank, char *buf, int buf_size) { if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } buf[0] = 0; return ERROR_OK; } static int sam3_page_read(struct sam3_bank_private *pPrivate, unsigned pagenum, uint8_t *buf) { uint32_t adr; int r; adr = pagenum * pPrivate->page_size; adr += pPrivate->base_address; r = target_read_memory(pPrivate->pChip->target, adr, 4, /* THIS*MUST*BE* in 32bit values */ pPrivate->page_size / 4, buf); if (r != ERROR_OK) LOG_ERROR("SAM3: Flash program failed to read page phys address: 0x%08x", (unsigned int)(adr)); return r; } /* The code below is basically this: */ /* compiled with */ /* arm-none-eabi-gcc -mthumb -mcpu = cortex-m3 -O9 -S ./foobar.c -o foobar.s */ /* */ /* Only the *CPU* can write to the flash buffer. */ /* the DAP cannot... so - we download this 28byte thing */ /* Run the algorithm - (below) */ /* to program the device */ /* */ /* ======================================== */ /* #include */ /* */ /* struct foo { */ /* uint32_t *dst; */ /* const uint32_t *src; */ /* int n; */ /* volatile uint32_t *base; */ /* uint32_t cmd; */ /* }; */ /* */ /* */ /* uint32_t sam3_function(struct foo *p) */ /* { */ /* volatile uint32_t *v; */ /* uint32_t *d; */ /* const uint32_t *s; */ /* int n; */ /* uint32_t r; */ /* */ /* d = p->dst; */ /* s = p->src; */ /* n = p->n; */ /* */ /* do { */ /* *d++ = *s++; */ /* } while (--n) */ /* ; */ /* */ /* v = p->base; */ /* */ /* v[ 1 ] = p->cmd; */ /* do { */ /* r = v[8/4]; */ /* } while (!(r&1)) */ /* ; */ /* return r; */ /* } */ /* ======================================== */ static const uint8_t sam3_page_write_opcodes[] = { /* 24 0000 0446 mov r4, r0 */ 0x04, 0x46, /* 25 0002 6168 ldr r1, [r4, #4] */ 0x61, 0x68, /* 26 0004 0068 ldr r0, [r0, #0] */ 0x00, 0x68, /* 27 0006 A268 ldr r2, [r4, #8] */ 0xa2, 0x68, /* 28 @ lr needed for prologue */ /* 29 .L2: */ /* 30 0008 51F8043B ldr r3, [r1], #4 */ 0x51, 0xf8, 0x04, 0x3b, /* 31 000c 12F1FF32 adds r2, r2, #-1 */ 0x12, 0xf1, 0xff, 0x32, /* 32 0010 40F8043B str r3, [r0], #4 */ 0x40, 0xf8, 0x04, 0x3b, /* 33 0014 F8D1 bne .L2 */ 0xf8, 0xd1, /* 34 0016 E268 ldr r2, [r4, #12] */ 0xe2, 0x68, /* 35 0018 2369 ldr r3, [r4, #16] */ 0x23, 0x69, /* 36 001a 5360 str r3, [r2, #4] */ 0x53, 0x60, /* 37 001c 0832 adds r2, r2, #8 */ 0x08, 0x32, /* 38 .L4: */ /* 39 001e 1068 ldr r0, [r2, #0] */ 0x10, 0x68, /* 40 0020 10F0010F tst r0, #1 */ 0x10, 0xf0, 0x01, 0x0f, /* 41 0024 FBD0 beq .L4 */ 0xfb, 0xd0, 0x00, 0xBE /* bkpt #0 */ }; static int sam3_page_write(struct sam3_bank_private *pPrivate, unsigned pagenum, uint8_t *buf) { uint32_t adr; uint32_t status; uint32_t fmr; /* EEFC Flash Mode Register */ int r; adr = pagenum * pPrivate->page_size; adr += pPrivate->base_address; /* Get flash mode register value */ r = target_read_u32(pPrivate->pChip->target, pPrivate->controller_address, &fmr); if (r != ERROR_OK) LOG_DEBUG("Error Read failed: read flash mode register"); /* Clear flash wait state field */ fmr &= 0xfffff0ff; /* set FWS (flash wait states) field in the FMR (flash mode register) */ fmr |= (pPrivate->flash_wait_states << 8); LOG_DEBUG("Flash Mode: 0x%08x", ((unsigned int)(fmr))); r = target_write_u32(pPrivate->pBank->target, pPrivate->controller_address, fmr); if (r != ERROR_OK) LOG_DEBUG("Error Write failed: set flash mode register"); LOG_DEBUG("Wr Page %u @ phys address: 0x%08x", pagenum, (unsigned int)(adr)); r = target_write_memory(pPrivate->pChip->target, adr, 4, /* THIS*MUST*BE* in 32bit values */ pPrivate->page_size / 4, buf); if (r != ERROR_OK) { LOG_ERROR("SAM3: Failed to write (buffer) page at phys address 0x%08x", (unsigned int)(adr)); return r; } r = EFC_PerformCommand(pPrivate, /* send Erase & Write Page */ AT91C_EFC_FCMD_EWP, pagenum, &status); if (r != ERROR_OK) LOG_ERROR("SAM3: Error performing Erase & Write page @ phys address 0x%08x", (unsigned int)(adr)); if (status & (1 << 2)) { LOG_ERROR("SAM3: Page @ Phys address 0x%08x is locked", (unsigned int)(adr)); return ERROR_FAIL; } if (status & (1 << 1)) { LOG_ERROR("SAM3: Flash Command error @phys address 0x%08x", (unsigned int)(adr)); return ERROR_FAIL; } return ERROR_OK; } static int sam3_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { int n; unsigned page_cur; unsigned page_end; int r; unsigned page_offset; struct sam3_bank_private *pPrivate; uint8_t *pagebuffer; /* incase we bail further below, set this to null */ pagebuffer = NULL; /* ignore dumb requests */ if (count == 0) { r = ERROR_OK; goto done; } if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); r = ERROR_TARGET_NOT_HALTED; goto done; } pPrivate = get_sam3_bank_private(bank); if (!(pPrivate->probed)) { r = ERROR_FLASH_BANK_NOT_PROBED; goto done; } if ((offset + count) > pPrivate->size_bytes) { LOG_ERROR("Flash write error - past end of bank"); LOG_ERROR(" offset: 0x%08x, count 0x%08x, BankEnd: 0x%08x", (unsigned int)(offset), (unsigned int)(count), (unsigned int)(pPrivate->size_bytes)); r = ERROR_FAIL; goto done; } pagebuffer = malloc(pPrivate->page_size); if (!pagebuffer) { LOG_ERROR("No memory for %d Byte page buffer", (int)(pPrivate->page_size)); r = ERROR_FAIL; goto done; } /* what page do we start & end in? */ page_cur = offset / pPrivate->page_size; page_end = (offset + count - 1) / pPrivate->page_size; LOG_DEBUG("Offset: 0x%08x, Count: 0x%08x", (unsigned int)(offset), (unsigned int)(count)); LOG_DEBUG("Page start: %d, Page End: %d", (int)(page_cur), (int)(page_end)); /* Special case: all one page */ /* */ /* Otherwise: */ /* (1) non-aligned start */ /* (2) body pages */ /* (3) non-aligned end. */ /* Handle special case - all one page. */ if (page_cur == page_end) { LOG_DEBUG("Special case, all in one page"); r = sam3_page_read(pPrivate, page_cur, pagebuffer); if (r != ERROR_OK) goto done; page_offset = (offset & (pPrivate->page_size-1)); memcpy(pagebuffer + page_offset, buffer, count); r = sam3_page_write(pPrivate, page_cur, pagebuffer); if (r != ERROR_OK) goto done; r = ERROR_OK; goto done; } /* non-aligned start */ page_offset = offset & (pPrivate->page_size - 1); if (page_offset) { LOG_DEBUG("Not-Aligned start"); /* read the partial */ r = sam3_page_read(pPrivate, page_cur, pagebuffer); if (r != ERROR_OK) goto done; /* over-write with new data */ n = (pPrivate->page_size - page_offset); memcpy(pagebuffer + page_offset, buffer, n); r = sam3_page_write(pPrivate, page_cur, pagebuffer); if (r != ERROR_OK) goto done; count -= n; offset += n; buffer += n; page_cur++; } /* By checking that offset is correct here, we also fix a clang warning */ assert(offset % pPrivate->page_size == 0); /* intermediate large pages */ /* also - the final *terminal* */ /* if that terminal page is a full page */ LOG_DEBUG("Full Page Loop: cur=%d, end=%d, count = 0x%08x", (int)page_cur, (int)page_end, (unsigned int)(count)); while ((page_cur < page_end) && (count >= pPrivate->page_size)) { r = sam3_page_write(pPrivate, page_cur, buffer); if (r != ERROR_OK) goto done; count -= pPrivate->page_size; buffer += pPrivate->page_size; page_cur += 1; } /* terminal partial page? */ if (count) { LOG_DEBUG("Terminal partial page, count = 0x%08x", (unsigned int)(count)); /* we have a partial page */ r = sam3_page_read(pPrivate, page_cur, pagebuffer); if (r != ERROR_OK) goto done; /* data goes at start */ memcpy(pagebuffer, buffer, count); r = sam3_page_write(pPrivate, page_cur, pagebuffer); if (r != ERROR_OK) goto done; } LOG_DEBUG("Done!"); r = ERROR_OK; done: if (pagebuffer) free(pagebuffer); return r; } COMMAND_HANDLER(sam3_handle_info_command) { struct sam3_chip *pChip; pChip = get_current_sam3(CMD_CTX); if (!pChip) return ERROR_OK; unsigned x; int r; /* bank0 must exist before we can do anything */ if (pChip->details.bank[0].pBank == NULL) { x = 0; need_define: command_print(CMD_CTX, "Please define bank %d via command: flash bank %s ... ", x, at91sam3_flash.name); return ERROR_FAIL; } /* if bank 0 is not probed, then probe it */ if (!(pChip->details.bank[0].probed)) { r = sam3_auto_probe(pChip->details.bank[0].pBank); if (r != ERROR_OK) return ERROR_FAIL; } /* above guarantees the "chip details" structure is valid */ /* and thus, bank private areas are valid */ /* and we have a SAM3 chip, what a concept! */ /* auto-probe other banks, 0 done above */ for (x = 1; x < SAM3_MAX_FLASH_BANKS; x++) { /* skip banks not present */ if (!(pChip->details.bank[x].present)) continue; if (pChip->details.bank[x].pBank == NULL) goto need_define; if (pChip->details.bank[x].probed) continue; r = sam3_auto_probe(pChip->details.bank[x].pBank); if (r != ERROR_OK) return r; } r = sam3_GetInfo(pChip); if (r != ERROR_OK) { LOG_DEBUG("Sam3Info, Failed %d", r); return r; } return ERROR_OK; } COMMAND_HANDLER(sam3_handle_gpnvm_command) { unsigned x, v; int r, who; struct sam3_chip *pChip; pChip = get_current_sam3(CMD_CTX); if (!pChip) return ERROR_OK; if (pChip->target->state != TARGET_HALTED) { LOG_ERROR("sam3 - target not halted"); return ERROR_TARGET_NOT_HALTED; } if (pChip->details.bank[0].pBank == NULL) { command_print(CMD_CTX, "Bank0 must be defined first via: flash bank %s ...", at91sam3_flash.name); return ERROR_FAIL; } if (!pChip->details.bank[0].probed) { r = sam3_auto_probe(pChip->details.bank[0].pBank); if (r != ERROR_OK) return r; } switch (CMD_ARGC) { default: return ERROR_COMMAND_SYNTAX_ERROR; break; case 0: goto showall; break; case 1: who = -1; break; case 2: if ((0 == strcmp(CMD_ARGV[0], "show")) && (0 == strcmp(CMD_ARGV[1], "all"))) who = -1; else { uint32_t v32; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], v32); who = v32; } break; } if (0 == strcmp("show", CMD_ARGV[0])) { if (who == -1) { showall: r = ERROR_OK; for (x = 0; x < pChip->details.n_gpnvms; x++) { r = FLASHD_GetGPNVM(&(pChip->details.bank[0]), x, &v); if (r != ERROR_OK) break; command_print(CMD_CTX, "sam3-gpnvm%u: %u", x, v); } return r; } if ((who >= 0) && (((unsigned)(who)) < pChip->details.n_gpnvms)) { r = FLASHD_GetGPNVM(&(pChip->details.bank[0]), who, &v); command_print(CMD_CTX, "sam3-gpnvm%u: %u", who, v); return r; } else { command_print(CMD_CTX, "sam3-gpnvm invalid GPNVM: %u", who); return ERROR_COMMAND_SYNTAX_ERROR; } } if (who == -1) { command_print(CMD_CTX, "Missing GPNVM number"); return ERROR_COMMAND_SYNTAX_ERROR; } if (0 == strcmp("set", CMD_ARGV[0])) r = FLASHD_SetGPNVM(&(pChip->details.bank[0]), who); else if ((0 == strcmp("clr", CMD_ARGV[0])) || (0 == strcmp("clear", CMD_ARGV[0]))) /* quietly accept both */ r = FLASHD_ClrGPNVM(&(pChip->details.bank[0]), who); else { command_print(CMD_CTX, "Unknown command: %s", CMD_ARGV[0]); r = ERROR_COMMAND_SYNTAX_ERROR; } return r; } COMMAND_HANDLER(sam3_handle_slowclk_command) { struct sam3_chip *pChip; pChip = get_current_sam3(CMD_CTX); if (!pChip) return ERROR_OK; switch (CMD_ARGC) { case 0: /* show */ break; case 1: { /* set */ uint32_t v; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], v); if (v > 200000) { /* absurd slow clock of 200Khz? */ command_print(CMD_CTX, "Absurd/illegal slow clock freq: %d\n", (int)(v)); return ERROR_COMMAND_SYNTAX_ERROR; } pChip->cfg.slow_freq = v; break; } default: /* error */ command_print(CMD_CTX, "Too many parameters"); return ERROR_COMMAND_SYNTAX_ERROR; break; } command_print(CMD_CTX, "Slowclk freq: %d.%03dkhz", (int)(pChip->cfg.slow_freq / 1000), (int)(pChip->cfg.slow_freq % 1000)); return ERROR_OK; } static const struct command_registration at91sam3_exec_command_handlers[] = { { .name = "gpnvm", .handler = sam3_handle_gpnvm_command, .mode = COMMAND_EXEC, .usage = "[('clr'|'set'|'show') bitnum]", .help = "Without arguments, shows all bits in the gpnvm " "register. Otherwise, clears, sets, or shows one " "General Purpose Non-Volatile Memory (gpnvm) bit.", }, { .name = "info", .handler = sam3_handle_info_command, .mode = COMMAND_EXEC, .help = "Print information about the current at91sam3 chip" "and its flash configuration.", }, { .name = "slowclk", .handler = sam3_handle_slowclk_command, .mode = COMMAND_EXEC, .usage = "[clock_hz]", .help = "Display or set the slowclock frequency " "(default 32768 Hz).", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration at91sam3_command_handlers[] = { { .name = "at91sam3", .mode = COMMAND_ANY, .help = "at91sam3 flash command group", .usage = "", .chain = at91sam3_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct flash_driver at91sam3_flash = { .name = "at91sam3", .commands = at91sam3_command_handlers, .flash_bank_command = sam3_flash_bank_command, .erase = sam3_erase, .protect = sam3_protect, .write = sam3_write, .read = default_flash_read, .probe = sam3_probe, .auto_probe = sam3_auto_probe, .erase_check = sam3_erase_check, .protect_check = sam3_protect_check, .info = sam3_info, }; openocd-0.7.0/src/flash/nor/ocl.h0000644000175000001440000000356712134336410013502 00000000000000/*************************************************************************** * Copyright (C) 2007 by Pavel Chromy * * chromy@asix.cz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef OCL_H #define OCL_H /* command/response mask */ #define OCL_CMD_MASK 0xFFFF0000L /* commads */ #define OCL_FLASH_BLOCK 0x0CFB0000L #define OCL_ERASE_BLOCK 0x0CEB0000L #define OCL_ERASE_ALL 0x0CEA0000L #define OCL_PROBE 0x0CBE0000L /* responses */ #define OCL_CMD_DONE 0x0ACD0000L #define OCL_CMD_ERR 0x0ACE0000L #define OCL_CHKS_FAIL 0x0ACF0000L #define OCL_BUFF_OVER 0x0AB00000L #define OCL_CHKS_INIT 0xC100CD0CL #endif /* OCL_H */ openocd-0.7.0/src/flash/nor/kinetis.c0000644000175000001440000006037612137151330014366 00000000000000/*************************************************************************** * Copyright (C) 2011 by Mathias Kuester * * kesmtp@freenet.de * * * * Copyright (C) 2011 sleep(5) ltd * * tomas@sleepfive.com * * * * Copyright (C) 2012 by Christopher D. Kilgour * * techie at whiterocker.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "helper/binarybuffer.h" /* * Implementation Notes * * The persistent memories in the Kinetis chip families K10 through * K70 are all manipulated with the Flash Memory Module. Some * variants call this module the FTFE, others call it the FTFL. To * indicate that both are considered here, we use FTFX. * * Within the module, according to the chip variant, the persistent * memory is divided into what Freescale terms Program Flash, FlexNVM, * and FlexRAM. All chip variants have Program Flash. Some chip * variants also have FlexNVM and FlexRAM, which always appear * together. * * A given Kinetis chip may have 2 or 4 blocks of flash. Here we map * each block to a separate bank. Each block size varies by chip and * may be determined by the read-only SIM_FCFG1 register. The sector * size within each bank/block varies by the chip granularity as * described below. * * Kinetis offers four different of flash granularities applicable * across the chip families. The granularity is apparently reflected * by at least the reference manual suffix. For example, for chip * MK60FN1M0VLQ12, reference manual K60P144M150SF3RM ends in "SF3RM", * where the "3" indicates there are four flash blocks with 4kiB * sectors. All possible granularities are indicated below. * * The first half of the flash (1 or 2 blocks, depending on the * granularity) is always Program Flash and always starts at address * 0x00000000. The "PFLSH" flag, bit 23 of the read-only SIM_FCFG2 * register, determines whether the second half of the flash is also * Program Flash or FlexNVM+FlexRAM. When PFLSH is set, the second * half of flash is Program Flash and is contiguous in the memory map * from the first half. When PFLSH is clear, the second half of flash * is FlexNVM and always starts at address 0x10000000. FlexRAM, which * is also present when PFLSH is clear, always starts at address * 0x14000000. * * The Flash Memory Module provides a register set where flash * commands are loaded to perform flash operations like erase and * program. Different commands are available depending on whether * Program Flash or FlexNVM/FlexRAM is being manipulated. Although * the commands used are quite consistent between flash blocks, the * parameters they accept differ according to the flash granularity. * Some Kinetis chips have different granularity between Program Flash * and FlexNVM/FlexRAM, so flash command arguments may differ between * blocks in the same chip. * * Although not documented as such by Freescale, it appears that bits * 8:7 of the read-only SIM_SDID register reflect the granularity * settings 0..3, so sector sizes and block counts are applicable * according to the following table. */ const struct { unsigned pflash_sector_size_bytes; unsigned nvm_sector_size_bytes; unsigned num_blocks; } kinetis_flash_params[4] = { { 1<<10, 1<<10, 2 }, { 2<<10, 1<<10, 2 }, { 2<<10, 2<<10, 2 }, { 4<<10, 4<<10, 4 } }; /* Addressess */ #define FLEXRAM 0x14000000 #define FTFx_FSTAT 0x40020000 #define FTFx_FCNFG 0x40020001 #define FTFx_FCCOB3 0x40020004 #define FTFx_FPROT3 0x40020010 #define SIM_SDID 0x40048024 #define SIM_FCFG1 0x4004804c #define SIM_FCFG2 0x40048050 /* Commands */ #define FTFx_CMD_BLOCKSTAT 0x00 #define FTFx_CMD_SECTSTAT 0x01 #define FTFx_CMD_LWORDPROG 0x06 #define FTFx_CMD_SECTERASE 0x09 #define FTFx_CMD_SECTWRITE 0x0b #define FTFx_CMD_SETFLEXRAM 0x81 struct kinetis_flash_bank { unsigned granularity; unsigned bank_ordinal; uint32_t sector_size; uint32_t protection_size; uint32_t sim_sdid; uint32_t sim_fcfg1; uint32_t sim_fcfg2; enum { FC_AUTO = 0, FC_PFLASH, FC_FLEX_NVM, FC_FLEX_RAM, } flash_class; }; FLASH_BANK_COMMAND_HANDLER(kinetis_flash_bank_command) { struct kinetis_flash_bank *bank_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; LOG_INFO("add flash_bank kinetis %s", bank->name); bank_info = malloc(sizeof(struct kinetis_flash_bank)); memset(bank_info, 0, sizeof(struct kinetis_flash_bank)); bank->driver_priv = bank_info; return ERROR_OK; } static int kinetis_protect(struct flash_bank *bank, int set, int first, int last) { LOG_WARNING("kinetis_protect not supported yet"); /* FIXME: TODO */ if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } return ERROR_FLASH_BANK_INVALID; } static int kinetis_protect_check(struct flash_bank *bank) { struct kinetis_flash_bank *kinfo = bank->driver_priv; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (kinfo->flash_class == FC_PFLASH) { int result; uint8_t buffer[4]; uint32_t fprot, psec; int i, b; /* read protection register */ result = target_read_memory(bank->target, FTFx_FPROT3, 1, 4, buffer); if (result != ERROR_OK) return result; fprot = target_buffer_get_u32(bank->target, buffer); /* * Every bit protects 1/32 of the full flash (not necessarily * just this bank), but we enforce the bank ordinals for * PFlash to start at zero. */ b = kinfo->bank_ordinal * (bank->size / kinfo->protection_size); for (psec = 0, i = 0; i < bank->num_sectors; i++) { if ((fprot >> b) & 1) bank->sectors[i].is_protected = 0; else bank->sectors[i].is_protected = 1; psec += bank->sectors[i].size; if (psec >= kinfo->protection_size) { psec = 0; b++; } } } else { LOG_ERROR("Protection checks for FlexNVM not yet supported"); return ERROR_FLASH_BANK_INVALID; } return ERROR_OK; } static int kinetis_ftfx_command(struct flash_bank *bank, uint8_t fcmd, uint32_t faddr, uint8_t fccob4, uint8_t fccob5, uint8_t fccob6, uint8_t fccob7, uint8_t fccob8, uint8_t fccob9, uint8_t fccoba, uint8_t fccobb, uint8_t *ftfx_fstat) { uint8_t command[12] = {faddr & 0xff, (faddr >> 8) & 0xff, (faddr >> 16) & 0xff, fcmd, fccob7, fccob6, fccob5, fccob4, fccobb, fccoba, fccob9, fccob8}; int result, i; uint8_t buffer; /* wait for done */ for (i = 0; i < 50; i++) { result = target_read_memory(bank->target, FTFx_FSTAT, 1, 1, &buffer); if (result != ERROR_OK) return result; if (buffer & 0x80) break; buffer = 0x00; } if (buffer != 0x80) { /* reset error flags */ buffer = 0x30; result = target_write_memory(bank->target, FTFx_FSTAT, 1, 1, &buffer); if (result != ERROR_OK) return result; } result = target_write_memory(bank->target, FTFx_FCCOB3, 4, 3, command); if (result != ERROR_OK) return result; /* start command */ buffer = 0x80; result = target_write_memory(bank->target, FTFx_FSTAT, 1, 1, &buffer); if (result != ERROR_OK) return result; /* wait for done */ for (i = 0; i < 50; i++) { result = target_read_memory(bank->target, FTFx_FSTAT, 1, 1, ftfx_fstat); if (result != ERROR_OK) return result; if (*ftfx_fstat & 0x80) break; } if ((*ftfx_fstat & 0xf0) != 0x80) { LOG_ERROR ("ftfx command failed FSTAT: %02X FCCOB: %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X", *ftfx_fstat, command[3], command[2], command[1], command[0], command[7], command[6], command[5], command[4], command[11], command[10], command[9], command[8]); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } static int kinetis_erase(struct flash_bank *bank, int first, int last) { int result, i; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if ((first > bank->num_sectors) || (last > bank->num_sectors)) return ERROR_FLASH_OPERATION_FAILED; /* * FIXME: TODO: use the 'Erase Flash Block' command if the * requested erase is PFlash or NVM and encompasses the entire * block. Should be quicker. */ for (i = first; i <= last; i++) { uint8_t ftfx_fstat; /* set command and sector address */ result = kinetis_ftfx_command(bank, FTFx_CMD_SECTERASE, bank->base + bank->sectors[i].offset, 0, 0, 0, 0, 0, 0, 0, 0, &ftfx_fstat); if (result != ERROR_OK) { LOG_WARNING("erase sector %d failed", i); return ERROR_FLASH_OPERATION_FAILED; } bank->sectors[i].is_erased = 1; } if (first == 0) { LOG_WARNING ("flash configuration field erased, please reset the device"); } return ERROR_OK; } static int kinetis_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { unsigned int i, result, fallback = 0; uint8_t buf[8]; uint32_t wc; struct kinetis_flash_bank *kinfo = bank->driver_priv; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (kinfo->flash_class == FC_FLEX_NVM) { uint8_t ftfx_fstat; LOG_DEBUG("flash write into FlexNVM @%08X", offset); /* make flex ram available */ result = kinetis_ftfx_command(bank, FTFx_CMD_SETFLEXRAM, 0x00ff0000, 0, 0, 0, 0, 0, 0, 0, 0, &ftfx_fstat); if (result != ERROR_OK) return ERROR_FLASH_OPERATION_FAILED; /* check if ram ready */ result = target_read_memory(bank->target, FTFx_FCNFG, 1, 1, buf); if (result != ERROR_OK) return result; if (!(buf[0] & (1 << 1))) { /* fallback to longword write */ fallback = 1; LOG_WARNING("ram not ready, fallback to slow longword write (FCNFG: %02X)", buf[0]); } } else { LOG_DEBUG("flash write into PFLASH @08%X", offset); } /* program section command */ if (fallback == 0) { /* * Kinetis uses different terms for the granularity of * sector writes, e.g. "phrase" or "128 bits". We use * the generic term "chunk". The largest possible * Kinetis "chunk" is 16 bytes (128 bits). */ unsigned prog_section_chunk_bytes = kinfo->sector_size >> 8; /* assume the NVM sector size is half the FlexRAM size */ unsigned prog_size_bytes = MIN(kinfo->sector_size, kinetis_flash_params[kinfo->granularity].nvm_sector_size_bytes); for (i = 0; i < count; i += prog_size_bytes) { uint8_t residual_buffer[16]; uint8_t ftfx_fstat; uint32_t section_count = prog_size_bytes / prog_section_chunk_bytes; uint32_t residual_wc = 0; /* * Assume the word count covers an entire * sector. */ wc = prog_size_bytes / 4; /* * If bytes to be programmed are less than the * full sector, then determine the number of * full-words to program, and put together the * residual buffer so that a full "section" * may always be programmed. */ if ((count - i) < prog_size_bytes) { /* number of bytes to program beyond full section */ unsigned residual_bc = (count-i) % prog_section_chunk_bytes; /* number of complete words to copy directly from buffer */ wc = (count - i) / 4; /* number of total sections to write, including residual */ section_count = DIV_ROUND_UP((count-i), prog_section_chunk_bytes); /* any residual bytes delivers a whole residual section */ residual_wc = (residual_bc ? prog_section_chunk_bytes : 0)/4; /* clear residual buffer then populate residual bytes */ (void) memset(residual_buffer, 0xff, prog_section_chunk_bytes); (void) memcpy(residual_buffer, &buffer[i+4*wc], residual_bc); } LOG_DEBUG("write section @ %08X with length %d bytes", offset + i, wc*4); /* write data to flexram as whole-words */ result = target_write_memory(bank->target, FLEXRAM, 4, wc, buffer + i); if (result != ERROR_OK) { LOG_ERROR("target_write_memory failed"); return result; } /* write the residual words to the flexram */ if (residual_wc) { result = target_write_memory(bank->target, FLEXRAM+4*wc, 4, residual_wc, residual_buffer); if (result != ERROR_OK) { LOG_ERROR("target_write_memory failed"); return result; } } /* execute section-write command */ result = kinetis_ftfx_command(bank, FTFx_CMD_SECTWRITE, bank->base + offset + i, section_count>>8, section_count, 0, 0, 0, 0, 0, 0, &ftfx_fstat); if (result != ERROR_OK) return ERROR_FLASH_OPERATION_FAILED; } } /* program longword command, not supported in "SF3" devices */ else if (kinfo->granularity != 3) { for (i = 0; i < count; i += 4) { uint8_t ftfx_fstat; LOG_DEBUG("write longword @ %08X", offset + i); uint8_t padding[4] = {0xff, 0xff, 0xff, 0xff}; memcpy(padding, buffer + i, MIN(4, count-i)); result = kinetis_ftfx_command(bank, FTFx_CMD_LWORDPROG, bank->base + offset + i, padding[3], padding[2], padding[1], padding[0], 0, 0, 0, 0, &ftfx_fstat); if (result != ERROR_OK) return ERROR_FLASH_OPERATION_FAILED; } } else { LOG_ERROR("Flash write strategy not implemented"); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } static int kinetis_read_part_info(struct flash_bank *bank) { int result, i; uint8_t buf[4]; uint32_t offset = 0; uint8_t fcfg1_nvmsize, fcfg1_pfsize, fcfg1_eesize, fcfg2_pflsh; uint32_t nvm_size = 0, pf_size = 0, ee_size = 0; unsigned granularity, num_blocks = 0, num_pflash_blocks = 0, num_nvm_blocks = 0, first_nvm_bank = 0, reassign = 0; struct kinetis_flash_bank *kinfo = bank->driver_priv; result = target_read_memory(bank->target, SIM_SDID, 1, 4, buf); if (result != ERROR_OK) return result; kinfo->sim_sdid = target_buffer_get_u32(bank->target, buf); granularity = (kinfo->sim_sdid >> 7) & 0x03; result = target_read_memory(bank->target, SIM_FCFG1, 1, 4, buf); if (result != ERROR_OK) return result; kinfo->sim_fcfg1 = target_buffer_get_u32(bank->target, buf); result = target_read_memory(bank->target, SIM_FCFG2, 1, 4, buf); if (result != ERROR_OK) return result; kinfo->sim_fcfg2 = target_buffer_get_u32(bank->target, buf); fcfg2_pflsh = (kinfo->sim_fcfg2 >> 23) & 0x01; LOG_DEBUG("SDID: %08X FCFG1: %08X FCFG2: %08X", kinfo->sim_sdid, kinfo->sim_fcfg1, kinfo->sim_fcfg2); fcfg1_nvmsize = (uint8_t)((kinfo->sim_fcfg1 >> 28) & 0x0f); fcfg1_pfsize = (uint8_t)((kinfo->sim_fcfg1 >> 24) & 0x0f); fcfg1_eesize = (uint8_t)((kinfo->sim_fcfg1 >> 16) & 0x0f); /* when the PFLSH bit is set, there is no FlexNVM/FlexRAM */ if (!fcfg2_pflsh) { switch (fcfg1_nvmsize) { case 0x03: case 0x07: case 0x09: case 0x0b: nvm_size = 1 << (14 + (fcfg1_nvmsize >> 1)); break; case 0x0f: if (granularity == 3) nvm_size = 512<<10; else nvm_size = 256<<10; break; default: nvm_size = 0; break; } switch (fcfg1_eesize) { case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08: case 0x09: ee_size = (16 << (10 - fcfg1_eesize)); break; default: ee_size = 0; break; } } switch (fcfg1_pfsize) { case 0x03: case 0x05: case 0x07: case 0x09: case 0x0b: case 0x0d: pf_size = 1 << (14 + (fcfg1_pfsize >> 1)); break; case 0x0f: if (granularity == 3) pf_size = 1024<<10; else if (fcfg2_pflsh) pf_size = 512<<10; else pf_size = 256<<10; break; default: pf_size = 0; break; } LOG_DEBUG("FlexNVM: %d PFlash: %d FlexRAM: %d PFLSH: %d", nvm_size, pf_size, ee_size, fcfg2_pflsh); num_blocks = kinetis_flash_params[granularity].num_blocks; num_pflash_blocks = num_blocks / (2 - fcfg2_pflsh); first_nvm_bank = num_pflash_blocks; num_nvm_blocks = num_blocks - num_pflash_blocks; LOG_DEBUG("%d blocks total: %d PFlash, %d FlexNVM", num_blocks, num_pflash_blocks, num_nvm_blocks); /* * If the flash class is already assigned, verify the * parameters. */ if (kinfo->flash_class != FC_AUTO) { if (kinfo->bank_ordinal != (unsigned) bank->bank_number) { LOG_WARNING("Flash ordinal/bank number mismatch"); reassign = 1; } else if (kinfo->granularity != granularity) { LOG_WARNING("Flash granularity mismatch"); reassign = 1; } else { switch (kinfo->flash_class) { case FC_PFLASH: if (kinfo->bank_ordinal >= first_nvm_bank) { LOG_WARNING("Class mismatch, bank %d is not PFlash", bank->bank_number); reassign = 1; } else if (bank->size != (pf_size / num_pflash_blocks)) { LOG_WARNING("PFlash size mismatch"); reassign = 1; } else if (bank->base != (0x00000000 + bank->size * kinfo->bank_ordinal)) { LOG_WARNING("PFlash address range mismatch"); reassign = 1; } else if (kinfo->sector_size != kinetis_flash_params[granularity].pflash_sector_size_bytes) { LOG_WARNING("PFlash sector size mismatch"); reassign = 1; } else { LOG_DEBUG("PFlash bank %d already configured okay", kinfo->bank_ordinal); } break; case FC_FLEX_NVM: if ((kinfo->bank_ordinal >= num_blocks) || (kinfo->bank_ordinal < first_nvm_bank)) { LOG_WARNING("Class mismatch, bank %d is not FlexNVM", bank->bank_number); reassign = 1; } else if (bank->size != (nvm_size / num_nvm_blocks)) { LOG_WARNING("FlexNVM size mismatch"); reassign = 1; } else if (bank->base != (0x10000000 + bank->size * kinfo->bank_ordinal)) { LOG_WARNING("FlexNVM address range mismatch"); reassign = 1; } else if (kinfo->sector_size != kinetis_flash_params[granularity].nvm_sector_size_bytes) { LOG_WARNING("FlexNVM sector size mismatch"); reassign = 1; } else { LOG_DEBUG("FlexNVM bank %d already configured okay", kinfo->bank_ordinal); } break; case FC_FLEX_RAM: if (kinfo->bank_ordinal != num_blocks) { LOG_WARNING("Class mismatch, bank %d is not FlexRAM", bank->bank_number); reassign = 1; } else if (bank->size != ee_size) { LOG_WARNING("FlexRAM size mismatch"); reassign = 1; } else if (bank->base != FLEXRAM) { LOG_WARNING("FlexRAM address mismatch"); reassign = 1; } else if (kinfo->sector_size != kinetis_flash_params[granularity].nvm_sector_size_bytes) { LOG_WARNING("FlexRAM sector size mismatch"); reassign = 1; } else { LOG_DEBUG("FlexRAM bank %d already configured okay", kinfo->bank_ordinal); } break; default: LOG_WARNING("Unknown or inconsistent flash class"); reassign = 1; break; } } } else { LOG_INFO("Probing flash info for bank %d", bank->bank_number); reassign = 1; } if (!reassign) return ERROR_OK; kinfo->granularity = granularity; if ((unsigned)bank->bank_number < num_pflash_blocks) { /* pflash, banks start at address zero */ kinfo->flash_class = FC_PFLASH; bank->size = (pf_size / num_pflash_blocks); bank->base = 0x00000000 + bank->size * bank->bank_number; kinfo->sector_size = kinetis_flash_params[granularity].pflash_sector_size_bytes; kinfo->protection_size = pf_size / 32; } else if ((unsigned)bank->bank_number < num_blocks) { /* nvm, banks start at address 0x10000000 */ kinfo->flash_class = FC_FLEX_NVM; bank->size = (nvm_size / num_nvm_blocks); bank->base = 0x10000000 + bank->size * (bank->bank_number - first_nvm_bank); kinfo->sector_size = kinetis_flash_params[granularity].nvm_sector_size_bytes; kinfo->protection_size = 0; /* FIXME: TODO: depends on DEPART bits, chip */ } else if ((unsigned)bank->bank_number == num_blocks) { LOG_ERROR("FlexRAM support not yet implemented"); return ERROR_FLASH_OPER_UNSUPPORTED; } else { LOG_ERROR("Cannot determine parameters for bank %d, only %d banks on device", bank->bank_number, num_blocks); return ERROR_FLASH_BANK_INVALID; } if (bank->sectors) { free(bank->sectors); bank->sectors = NULL; } bank->num_sectors = bank->size / kinfo->sector_size; assert(bank->num_sectors > 0); bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); for (i = 0; i < bank->num_sectors; i++) { bank->sectors[i].offset = offset; bank->sectors[i].size = kinfo->sector_size; offset += kinfo->sector_size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } return ERROR_OK; } static int kinetis_probe(struct flash_bank *bank) { if (bank->target->state != TARGET_HALTED) { LOG_WARNING("Cannot communicate... target not halted."); return ERROR_TARGET_NOT_HALTED; } return kinetis_read_part_info(bank); } static int kinetis_auto_probe(struct flash_bank *bank) { struct kinetis_flash_bank *kinfo = bank->driver_priv; if (kinfo->sim_sdid) return ERROR_OK; return kinetis_probe(bank); } static int kinetis_info(struct flash_bank *bank, char *buf, int buf_size) { const char *bank_class_names[] = { "(ANY)", "PFlash", "FlexNVM", "FlexRAM" }; struct kinetis_flash_bank *kinfo = bank->driver_priv; (void) snprintf(buf, buf_size, "%s driver for %s flash bank %s at 0x%8.8" PRIx32 "", bank->driver->name, bank_class_names[kinfo->flash_class], bank->name, bank->base); return ERROR_OK; } static int kinetis_blank_check(struct flash_bank *bank) { struct kinetis_flash_bank *kinfo = bank->driver_priv; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (kinfo->flash_class == FC_PFLASH) { int result; uint8_t ftfx_fstat; /* check if whole bank is blank */ result = kinetis_ftfx_command(bank, FTFx_CMD_BLOCKSTAT, bank->base, 0, 0, 0, 0, 0, 0, 0, 0, &ftfx_fstat); if (result != ERROR_OK) return result; if (ftfx_fstat & 0x01) { /* the whole bank is not erased, check sector-by-sector */ int i; for (i = 0; i < bank->num_sectors; i++) { /* normal margin */ result = kinetis_ftfx_command(bank, FTFx_CMD_SECTSTAT, bank->base + bank->sectors[i].offset, 1, 0, 0, 0, 0, 0, 0, 0, &ftfx_fstat); if (result == ERROR_OK) { bank->sectors[i].is_erased = !(ftfx_fstat & 0x01); } else { LOG_DEBUG("Ignoring errored PFlash sector blank-check"); bank->sectors[i].is_erased = -1; } } } else { /* the whole bank is erased, update all sectors */ int i; for (i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_erased = 1; } } else { LOG_WARNING("kinetis_blank_check not supported yet for FlexNVM"); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } static int kinetis_flash_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { LOG_WARNING("kinetis_flash_read not supported yet"); if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } return ERROR_FLASH_OPERATION_FAILED; } struct flash_driver kinetis_flash = { .name = "kinetis", .flash_bank_command = kinetis_flash_bank_command, .erase = kinetis_erase, .protect = kinetis_protect, .write = kinetis_write, .read = kinetis_flash_read, .probe = kinetis_probe, .auto_probe = kinetis_auto_probe, .erase_check = kinetis_blank_check, .protect_check = kinetis_protect_check, .info = kinetis_info, }; openocd-0.7.0/src/flash/nor/core.h0000644000175000001440000002065512134336410013652 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Copyright (C) 2007,2008 Øyvind Harboe * * Copyright (C) 2008 by Spencer Oliver * * Copyright (C) 2009 Zachary T Welch * * Copyright (C) 2010 by Antonio Borneo * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef FLASH_NOR_CORE_H #define FLASH_NOR_CORE_H #include /** * @file * Upper level NOR flash interfaces. */ struct image; #define FLASH_MAX_ERROR_STR (128) /** * Describes the geometry and status of a single flash sector * within a flash bank. A single bank typically consists of multiple * sectors, each of which can be erased and protected independently. */ struct flash_sector { /** Bus offset from start of the flash chip (in bytes). */ uint32_t offset; /** Number of bytes in this flash sector. */ uint32_t size; /** * Indication of erasure status: 0 = not erased, 1 = erased, * other = unknown. Set by @c flash_driver_s::erase_check. */ int is_erased; /** * Indication of protection status: 0 = unprotected/unlocked, * 1 = protected/locked, other = unknown. Set by * @c flash_driver_s::protect_check. * * This information must be considered stale immediately. * A million things could make it stale: power cycle, * reset of target, code running on target, etc. */ int is_protected; }; /** * Provides details of a flash bank, available either on-chip or through * a major interface. * * This structure will be passed as a parameter to the callbacks in the * flash_driver_s structure, some of which may modify the contents of * this structure of the area of flash that it defines. Driver writers * may use the @c driver_priv member to store additional data on a * per-bank basis, if required. */ struct flash_bank { const char *name; struct target *target; /**< Target to which this bank belongs. */ struct flash_driver *driver; /**< Driver for this bank. */ void *driver_priv; /**< Private driver storage pointer */ int bank_number; /**< The 'bank' (or chip number) of this instance. */ uint32_t base; /**< The base address of this bank */ uint32_t size; /**< The size of this chip bank, in bytes */ int chip_width; /**< Width of the chip in bytes (1,2,4 bytes) */ int bus_width; /**< Maximum bus width, in bytes (1,2,4 bytes) */ /** * The number of sectors on this chip. This value will * be set intially to 0, and the flash driver must set this to * some non-zero value during "probe()" or "auto_probe()". */ int num_sectors; /** Array of sectors, allocated and initilized by the flash driver */ struct flash_sector *sectors; struct flash_bank *next; /**< The next flash bank on this chip */ }; /** Registers the 'flash' subsystem commands */ int flash_register_commands(struct command_context *cmd_ctx); /** * Erases @a length bytes in the @a target flash, starting at @a addr. * The range @a addr to @a addr + @a length - 1 must be strictly * sector aligned, unless @a pad is true. Setting @a pad true extends * the range, at beginning and/or end, if needed for sector alignment. * @returns ERROR_OK if successful; otherwise, an error code. */ int flash_erase_address_range(struct target *target, bool pad, uint32_t addr, uint32_t length); int flash_unlock_address_range(struct target *target, uint32_t addr, uint32_t length); /** * Writes @a image into the @a target flash. The @a written parameter * will contain the * @param target The target with the flash to be programmed. * @param image The image that will be programmed to flash. * @param written On return, contains the number of bytes written. * @param erase If non-zero, indicates the flash driver should first * erase the corresponding banks or sectors before programming. * @returns ERROR_OK if successful; otherwise, an error code. */ int flash_write(struct target *target, struct image *image, uint32_t *written, int erase); /** * Forces targets to re-examine their erase/protection state. * This routine must be called when the system may modify the status. */ void flash_set_dirty(void); /** @returns The number of flash banks currently defined. */ int flash_get_bank_count(void); /** * Provides default read implementation for flash memory. * @param bank The bank to read. * @param buffer The data bytes read. * @param offset The offset into the chip to read. * @param count The number of bytes to read. * @returns ERROR_OK if successful; otherwise, an error code. */ int default_flash_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count); /** * Provides default erased-bank check handling. Checks to see if * the flash driver knows they are erased; if things look uncertain, * this routine will call default_flash_mem_blank_check() to confirm. * @returns ERROR_OK if successful; otherwise, an error code. */ int default_flash_blank_check(struct flash_bank *bank); /** * Returns the flash bank specified by @a name, which matches the * driver name and a suffix (option) specify the driver-specific * bank number. The suffix consists of the '.' and the driver-specific * bank number: when two str9x banks are defined, then 'str9x.1' refers * to the second. */ int get_flash_bank_by_name(const char *name, struct flash_bank **bank_result); /** * Returns the flash bank specified by @a name, which matches the * driver name and a suffix (option) specify the driver-specific * bank number. The suffix consists of the '.' and the driver-specific * bank number: when two str9x banks are defined, then 'str9x.1' refers * to the second. */ struct flash_bank *get_flash_bank_by_name_noprobe(const char *name); /** * Returns the flash bank like get_flash_bank_by_name(), without probing. * @param num The flash bank number. * @param bank returned bank if fn returns ERROR_OK * @returns ERROR_OK if successful */ int get_flash_bank_by_num(int num, struct flash_bank **bank); /** * Retreives @a bank from a command argument, reporting errors parsing * the bank identifier or retreiving the specified bank. The bank * may be identified by its bank number or by @c name.instance, where * @a instance is driver-specific. * @param name_index The index to the string in args containing the * bank identifier. * @param bank On output, contians a pointer to the bank or NULL. * @returns ERROR_OK on success, or an error indicating the problem. */ COMMAND_HELPER(flash_command_get_bank, unsigned name_index, struct flash_bank **bank); /** * Returns the flash bank like get_flash_bank_by_num(), without probing. * @param num The flash bank number. * @returns A struct flash_bank for flash bank @a num, or NULL. */ struct flash_bank *get_flash_bank_by_num_noprobe(int num); /** * Returns the flash bank located at a specified address. * @param target The target, presumed to contain one or more banks. * @param addr An address that is within the range of the bank. * @param check return ERROR_OK and result_bank NULL if the bank does not exist * @returns The struct flash_bank located at @a addr, or NULL. */ int get_flash_bank_by_addr(struct target *target, uint32_t addr, bool check, struct flash_bank **result_bank); #endif /* FLASH_NOR_CORE_H */ openocd-0.7.0/src/flash/nor/imp.h0000644000175000001440000000454212134336410013504 00000000000000/*************************************************************************** * Copyright (C) 2009 Zachary T Welch * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef FLASH_NOR_IMP_H #define FLASH_NOR_IMP_H /* this is an internal header */ #include "core.h" #include "driver.h" /* almost all drivers will need this file */ #include /** * Adds a new NOR bank to the global list of banks. * @param bank The bank that should be added. */ void flash_bank_add(struct flash_bank *bank); /** * @return The first bank in the global list. */ struct flash_bank *flash_bank_list(void); int flash_driver_erase(struct flash_bank *bank, int first, int last); int flash_driver_protect(struct flash_bank *bank, int set, int first, int last); int flash_driver_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count); int flash_driver_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count); /* write (optional verify) an image to flash memory of the given target */ int flash_write_unlock(struct target *target, struct image *image, uint32_t *written, int erase, bool unlock); #endif /* FLASH_NOR_IMP_H */ openocd-0.7.0/src/flash/nor/str9xpec.c0000644000175000001440000007367612134336410014511 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include /* ISC commands */ #define ISC_IDCODE 0xFE #define ISC_MFG_READ 0x4C #define ISC_CONFIGURATION 0x07 #define ISC_ENABLE 0x0C #define ISC_DISABLE 0x0F #define ISC_NOOP 0x10 #define ISC_ADDRESS_SHIFT 0x11 #define ISC_CLR_STATUS 0x13 #define ISC_PROGRAM 0x20 #define ISC_PROGRAM_SECURITY 0x22 #define ISC_PROGRAM_UC 0x23 #define ISC_ERASE 0x30 #define ISC_READ 0x50 #define ISC_BLANK_CHECK 0x60 /* ISC_DEFAULT bit definitions */ #define ISC_STATUS_SECURITY 0x40 #define ISC_STATUS_INT_ERROR 0x30 #define ISC_STATUS_MODE 0x08 #define ISC_STATUS_BUSY 0x04 #define ISC_STATUS_ERROR 0x03 /* Option bytes definitions */ #define STR9XPEC_OPT_CSMAPBIT 48 #define STR9XPEC_OPT_LVDTHRESBIT 49 #define STR9XPEC_OPT_LVDSELBIT 50 #define STR9XPEC_OPT_LVDWARNBIT 51 #define STR9XPEC_OPT_OTPBIT 63 enum str9xpec_status_codes { STR9XPEC_INVALID_COMMAND = 1, STR9XPEC_ISC_SUCCESS = 2, STR9XPEC_ISC_DISABLED = 3, STR9XPEC_ISC_INTFAIL = 32, }; struct str9xpec_flash_controller { struct jtag_tap *tap; uint32_t *sector_bits; int chain_pos; int isc_enable; uint8_t options[8]; }; static int str9xpec_erase_area(struct flash_bank *bank, int first, int last); static int str9xpec_set_address(struct flash_bank *bank, uint8_t sector); static int str9xpec_write_options(struct flash_bank *bank); static int str9xpec_set_instr(struct jtag_tap *tap, uint32_t new_instr, tap_state_t end_state) { if (tap == NULL) return ERROR_TARGET_INVALID; if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != new_instr) { struct scan_field field; field.num_bits = tap->ir_length; void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1); field.out_value = t; buf_set_u32(t, 0, field.num_bits, new_instr); field.in_value = NULL; jtag_add_ir_scan(tap, &field, end_state); free(t); } return ERROR_OK; } static uint8_t str9xpec_isc_status(struct jtag_tap *tap) { struct scan_field field; uint8_t status; if (str9xpec_set_instr(tap, ISC_NOOP, TAP_IRPAUSE) != ERROR_OK) return ISC_STATUS_ERROR; field.num_bits = 8; field.out_value = NULL; field.in_value = &status; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); jtag_execute_queue(); LOG_DEBUG("status: 0x%2.2x", status); if (status & ISC_STATUS_SECURITY) LOG_INFO("Device Security Bit Set"); return status; } static int str9xpec_isc_enable(struct flash_bank *bank) { uint8_t status; struct jtag_tap *tap; struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv; tap = str9xpec_info->tap; if (str9xpec_info->isc_enable) return ERROR_OK; /* enter isc mode */ if (str9xpec_set_instr(tap, ISC_ENABLE, TAP_IDLE) != ERROR_OK) return ERROR_TARGET_INVALID; /* check ISC status */ status = str9xpec_isc_status(tap); if (status & ISC_STATUS_MODE) { /* we have entered isc mode */ str9xpec_info->isc_enable = 1; LOG_DEBUG("ISC_MODE Enabled"); } return ERROR_OK; } static int str9xpec_isc_disable(struct flash_bank *bank) { uint8_t status; struct jtag_tap *tap; struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv; tap = str9xpec_info->tap; if (!str9xpec_info->isc_enable) return ERROR_OK; if (str9xpec_set_instr(tap, ISC_DISABLE, TAP_IDLE) != ERROR_OK) return ERROR_TARGET_INVALID; /* delay to handle aborts */ jtag_add_sleep(50); /* check ISC status */ status = str9xpec_isc_status(tap); if (!(status & ISC_STATUS_MODE)) { /* we have left isc mode */ str9xpec_info->isc_enable = 0; LOG_DEBUG("ISC_MODE Disabled"); } return ERROR_OK; } static int str9xpec_read_config(struct flash_bank *bank) { struct scan_field field; uint8_t status; struct jtag_tap *tap; struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv; tap = str9xpec_info->tap; LOG_DEBUG("ISC_CONFIGURATION"); /* execute ISC_CONFIGURATION command */ str9xpec_set_instr(tap, ISC_CONFIGURATION, TAP_IRPAUSE); field.num_bits = 64; field.out_value = NULL; field.in_value = str9xpec_info->options; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); jtag_execute_queue(); status = str9xpec_isc_status(tap); return status; } static int str9xpec_build_block_list(struct flash_bank *bank) { struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv; int i; int num_sectors; int b0_sectors = 0, b1_sectors = 0; uint32_t offset = 0; int b1_size = 0x2000; switch (bank->size) { case (256 * 1024): b0_sectors = 4; break; case (512 * 1024): b0_sectors = 8; break; case (1024 * 1024): b0_sectors = 16; break; case (2048 * 1024): b0_sectors = 32; break; case (128 * 1024): b1_size = 0x4000; b1_sectors = 8; break; case (32 * 1024): b1_sectors = 4; break; default: LOG_ERROR("BUG: unknown bank->size encountered"); exit(-1); } num_sectors = b0_sectors + b1_sectors; bank->num_sectors = num_sectors; bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors); str9xpec_info->sector_bits = malloc(sizeof(uint32_t) * num_sectors); num_sectors = 0; for (i = 0; i < b0_sectors; i++) { bank->sectors[num_sectors].offset = offset; bank->sectors[num_sectors].size = 0x10000; offset += bank->sectors[i].size; bank->sectors[num_sectors].is_erased = -1; bank->sectors[num_sectors].is_protected = 1; str9xpec_info->sector_bits[num_sectors++] = i; } for (i = 0; i < b1_sectors; i++) { bank->sectors[num_sectors].offset = offset; bank->sectors[num_sectors].size = b1_size; offset += bank->sectors[i].size; bank->sectors[num_sectors].is_erased = -1; bank->sectors[num_sectors].is_protected = 1; str9xpec_info->sector_bits[num_sectors++] = i + 32; } return ERROR_OK; } /* flash bank str9x 0 0 */ FLASH_BANK_COMMAND_HANDLER(str9xpec_flash_bank_command) { struct str9xpec_flash_controller *str9xpec_info; struct arm *arm = NULL; struct arm7_9_common *arm7_9 = NULL; struct arm_jtag *jtag_info = NULL; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; str9xpec_info = malloc(sizeof(struct str9xpec_flash_controller)); bank->driver_priv = str9xpec_info; /* REVISIT verify that the jtag position of flash controller is * right after *THIS* core, which must be a STR9xx core ... */ arm = bank->target->arch_info; arm7_9 = arm->arch_info; jtag_info = &arm7_9->jtag_info; /* The core is the next tap after the flash controller in the chain */ str9xpec_info->tap = jtag_tap_by_position(jtag_info->tap->abs_chain_position - 1); str9xpec_info->isc_enable = 0; str9xpec_build_block_list(bank); /* clear option byte register */ buf_set_u32(str9xpec_info->options, 0, 64, 0); return ERROR_OK; } static int str9xpec_blank_check(struct flash_bank *bank, int first, int last) { struct scan_field field; uint8_t status; struct jtag_tap *tap; int i; uint8_t *buffer = NULL; struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv; tap = str9xpec_info->tap; if (!str9xpec_info->isc_enable) str9xpec_isc_enable(bank); if (!str9xpec_info->isc_enable) return ERROR_FLASH_OPERATION_FAILED; buffer = calloc(DIV_ROUND_UP(64, 8), 1); LOG_DEBUG("blank check: first_bank: %i, last_bank: %i", first, last); for (i = first; i <= last; i++) buf_set_u32(buffer, str9xpec_info->sector_bits[i], 1, 1); /* execute ISC_BLANK_CHECK command */ str9xpec_set_instr(tap, ISC_BLANK_CHECK, TAP_IRPAUSE); field.num_bits = 64; field.out_value = buffer; field.in_value = NULL; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); jtag_add_sleep(40000); /* read blank check result */ field.num_bits = 64; field.out_value = NULL; field.in_value = buffer; jtag_add_dr_scan(tap, 1, &field, TAP_IRPAUSE); jtag_execute_queue(); status = str9xpec_isc_status(tap); for (i = first; i <= last; i++) { if (buf_get_u32(buffer, str9xpec_info->sector_bits[i], 1)) bank->sectors[i].is_erased = 0; else bank->sectors[i].is_erased = 1; } free(buffer); str9xpec_isc_disable(bank); if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) return ERROR_FLASH_OPERATION_FAILED; return ERROR_OK; } static int str9xpec_protect_check(struct flash_bank *bank) { uint8_t status; int i; struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv; status = str9xpec_read_config(bank); for (i = 0; i < bank->num_sectors; i++) { if (buf_get_u32(str9xpec_info->options, str9xpec_info->sector_bits[i], 1)) bank->sectors[i].is_protected = 1; else bank->sectors[i].is_protected = 0; } if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) return ERROR_FLASH_OPERATION_FAILED; return ERROR_OK; } static int str9xpec_erase_area(struct flash_bank *bank, int first, int last) { struct scan_field field; uint8_t status; struct jtag_tap *tap; int i; uint8_t *buffer = NULL; struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv; tap = str9xpec_info->tap; if (!str9xpec_info->isc_enable) str9xpec_isc_enable(bank); if (!str9xpec_info->isc_enable) return ISC_STATUS_ERROR; buffer = calloc(DIV_ROUND_UP(64, 8), 1); LOG_DEBUG("erase: first_bank: %i, last_bank: %i", first, last); /* last bank: 0xFF signals a full erase (unlock complete device) */ /* last bank: 0xFE signals a option byte erase */ if (last == 0xFF) { for (i = 0; i < 64; i++) buf_set_u32(buffer, i, 1, 1); } else if (last == 0xFE) buf_set_u32(buffer, 49, 1, 1); else { for (i = first; i <= last; i++) buf_set_u32(buffer, str9xpec_info->sector_bits[i], 1, 1); } LOG_DEBUG("ISC_ERASE"); /* execute ISC_ERASE command */ str9xpec_set_instr(tap, ISC_ERASE, TAP_IRPAUSE); field.num_bits = 64; field.out_value = buffer; field.in_value = NULL; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); jtag_execute_queue(); jtag_add_sleep(10); /* wait for erase completion */ while (!((status = str9xpec_isc_status(tap)) & ISC_STATUS_BUSY)) alive_sleep(1); free(buffer); str9xpec_isc_disable(bank); return status; } static int str9xpec_erase(struct flash_bank *bank, int first, int last) { int status; status = str9xpec_erase_area(bank, first, last); if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) return ERROR_FLASH_OPERATION_FAILED; return ERROR_OK; } static int str9xpec_lock_device(struct flash_bank *bank) { struct scan_field field; uint8_t status; struct jtag_tap *tap; struct str9xpec_flash_controller *str9xpec_info = NULL; str9xpec_info = bank->driver_priv; tap = str9xpec_info->tap; if (!str9xpec_info->isc_enable) str9xpec_isc_enable(bank); if (!str9xpec_info->isc_enable) return ISC_STATUS_ERROR; /* set security address */ str9xpec_set_address(bank, 0x80); /* execute ISC_PROGRAM command */ str9xpec_set_instr(tap, ISC_PROGRAM_SECURITY, TAP_IDLE); str9xpec_set_instr(tap, ISC_NOOP, TAP_IRPAUSE); do { field.num_bits = 8; field.out_value = NULL; field.in_value = &status; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); jtag_execute_queue(); } while (!(status & ISC_STATUS_BUSY)); str9xpec_isc_disable(bank); return status; } static int str9xpec_unlock_device(struct flash_bank *bank) { uint8_t status; status = str9xpec_erase_area(bank, 0, 255); return status; } static int str9xpec_protect(struct flash_bank *bank, int set, int first, int last) { uint8_t status; int i; struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv; status = str9xpec_read_config(bank); if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) return ERROR_FLASH_OPERATION_FAILED; LOG_DEBUG("protect: first_bank: %i, last_bank: %i", first, last); /* last bank: 0xFF signals a full device protect */ if (last == 0xFF) { if (set) status = str9xpec_lock_device(bank); else { /* perform full erase to unlock device */ status = str9xpec_unlock_device(bank); } } else { for (i = first; i <= last; i++) { if (set) buf_set_u32(str9xpec_info->options, str9xpec_info->sector_bits[i], 1, 1); else buf_set_u32(str9xpec_info->options, str9xpec_info->sector_bits[i], 1, 0); } status = str9xpec_write_options(bank); } if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) return ERROR_FLASH_OPERATION_FAILED; return ERROR_OK; } static int str9xpec_set_address(struct flash_bank *bank, uint8_t sector) { struct jtag_tap *tap; struct scan_field field; struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv; tap = str9xpec_info->tap; /* set flash controller address */ str9xpec_set_instr(tap, ISC_ADDRESS_SHIFT, TAP_IRPAUSE); field.num_bits = 8; field.out_value = §or; field.in_value = NULL; jtag_add_dr_scan(tap, 1, &field, TAP_IRPAUSE); return ERROR_OK; } static int str9xpec_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct str9xpec_flash_controller *str9xpec_info = bank->driver_priv; uint32_t dwords_remaining = (count / 8); uint32_t bytes_remaining = (count & 0x00000007); uint32_t bytes_written = 0; uint8_t status; uint32_t check_address = offset; struct jtag_tap *tap; struct scan_field field; uint8_t *scanbuf; int i; int first_sector = 0; int last_sector = 0; tap = str9xpec_info->tap; if (!str9xpec_info->isc_enable) str9xpec_isc_enable(bank); if (!str9xpec_info->isc_enable) return ERROR_FLASH_OPERATION_FAILED; if (offset & 0x7) { LOG_WARNING("offset 0x%" PRIx32 " breaks required 8-byte alignment", offset); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } for (i = 0; i < bank->num_sectors; i++) { uint32_t sec_start = bank->sectors[i].offset; uint32_t sec_end = sec_start + bank->sectors[i].size; /* check if destination falls within the current sector */ if ((check_address >= sec_start) && (check_address < sec_end)) { /* check if destination ends in the current sector */ if (offset + count < sec_end) check_address = offset + count; else check_address = sec_end; } if ((offset >= sec_start) && (offset < sec_end)) first_sector = i; if ((offset + count >= sec_start) && (offset + count < sec_end)) last_sector = i; } if (check_address != offset + count) return ERROR_FLASH_DST_OUT_OF_BANK; LOG_DEBUG("first_sector: %i, last_sector: %i", first_sector, last_sector); scanbuf = calloc(DIV_ROUND_UP(64, 8), 1); LOG_DEBUG("ISC_PROGRAM"); for (i = first_sector; i <= last_sector; i++) { str9xpec_set_address(bank, str9xpec_info->sector_bits[i]); dwords_remaining = dwords_remaining < (bank->sectors[i].size/8) ? dwords_remaining : (bank->sectors[i].size/8); while (dwords_remaining > 0) { str9xpec_set_instr(tap, ISC_PROGRAM, TAP_IRPAUSE); field.num_bits = 64; field.out_value = (buffer + bytes_written); field.in_value = NULL; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); /* small delay before polling */ jtag_add_sleep(50); str9xpec_set_instr(tap, ISC_NOOP, TAP_IRPAUSE); do { field.num_bits = 8; field.out_value = NULL; field.in_value = scanbuf; jtag_add_dr_scan(tap, 1, &field, TAP_IRPAUSE); jtag_execute_queue(); status = buf_get_u32(scanbuf, 0, 8); } while (!(status & ISC_STATUS_BUSY)); if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) return ERROR_FLASH_OPERATION_FAILED; /* if ((status & ISC_STATUS_INT_ERROR) != STR9XPEC_ISC_INTFAIL) return ERROR_FLASH_OPERATION_FAILED; */ dwords_remaining--; bytes_written += 8; } } if (bytes_remaining) { uint8_t last_dword[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; /* copy the last remaining bytes into the write buffer */ memcpy(last_dword, buffer+bytes_written, bytes_remaining); str9xpec_set_instr(tap, ISC_PROGRAM, TAP_IRPAUSE); field.num_bits = 64; field.out_value = last_dword; field.in_value = NULL; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); /* small delay before polling */ jtag_add_sleep(50); str9xpec_set_instr(tap, ISC_NOOP, TAP_IRPAUSE); do { field.num_bits = 8; field.out_value = NULL; field.in_value = scanbuf; jtag_add_dr_scan(tap, 1, &field, TAP_IRPAUSE); jtag_execute_queue(); status = buf_get_u32(scanbuf, 0, 8); } while (!(status & ISC_STATUS_BUSY)); if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) return ERROR_FLASH_OPERATION_FAILED; /* if ((status & ISC_STATUS_INT_ERROR) != STR9XPEC_ISC_INTFAIL) return ERROR_FLASH_OPERATION_FAILED; */ } free(scanbuf); str9xpec_isc_disable(bank); return ERROR_OK; } static int str9xpec_probe(struct flash_bank *bank) { return ERROR_OK; } COMMAND_HANDLER(str9xpec_handle_part_id_command) { struct scan_field field; uint8_t *buffer = NULL; struct jtag_tap *tap; uint32_t idcode; struct str9xpec_flash_controller *str9xpec_info = NULL; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; str9xpec_info = bank->driver_priv; tap = str9xpec_info->tap; buffer = calloc(DIV_ROUND_UP(32, 8), 1); str9xpec_set_instr(tap, ISC_IDCODE, TAP_IRPAUSE); field.num_bits = 32; field.out_value = NULL; field.in_value = buffer; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); jtag_execute_queue(); idcode = buf_get_u32(buffer, 0, 32); command_print(CMD_CTX, "str9xpec part id: 0x%8.8" PRIx32 "", idcode); free(buffer); return ERROR_OK; } static int str9xpec_erase_check(struct flash_bank *bank) { return str9xpec_blank_check(bank, 0, bank->num_sectors - 1); } static int get_str9xpec_info(struct flash_bank *bank, char *buf, int buf_size) { snprintf(buf, buf_size, "str9xpec flash driver info"); return ERROR_OK; } COMMAND_HANDLER(str9xpec_handle_flash_options_read_command) { uint8_t status; struct str9xpec_flash_controller *str9xpec_info = NULL; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; str9xpec_info = bank->driver_priv; status = str9xpec_read_config(bank); if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) return ERROR_FLASH_OPERATION_FAILED; /* boot bank */ if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_CSMAPBIT, 1)) command_print(CMD_CTX, "CS Map: bank1"); else command_print(CMD_CTX, "CS Map: bank0"); /* OTP lock */ if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_OTPBIT, 1)) command_print(CMD_CTX, "OTP Lock: OTP Locked"); else command_print(CMD_CTX, "OTP Lock: OTP Unlocked"); /* LVD Threshold */ if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_LVDTHRESBIT, 1)) command_print(CMD_CTX, "LVD Threshold: 2.7v"); else command_print(CMD_CTX, "LVD Threshold: 2.4v"); /* LVD reset warning */ if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_LVDWARNBIT, 1)) command_print(CMD_CTX, "LVD Reset Warning: VDD or VDDQ Inputs"); else command_print(CMD_CTX, "LVD Reset Warning: VDD Input Only"); /* LVD reset select */ if (buf_get_u32(str9xpec_info->options, STR9XPEC_OPT_LVDSELBIT, 1)) command_print(CMD_CTX, "LVD Reset Selection: VDD or VDDQ Inputs"); else command_print(CMD_CTX, "LVD Reset Selection: VDD Input Only"); return ERROR_OK; } static int str9xpec_write_options(struct flash_bank *bank) { struct scan_field field; uint8_t status; struct jtag_tap *tap; struct str9xpec_flash_controller *str9xpec_info = NULL; str9xpec_info = bank->driver_priv; tap = str9xpec_info->tap; /* erase config options first */ status = str9xpec_erase_area(bank, 0xFE, 0xFE); if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) return status; if (!str9xpec_info->isc_enable) str9xpec_isc_enable(bank); if (!str9xpec_info->isc_enable) return ISC_STATUS_ERROR; /* according to data 64th bit has to be set */ buf_set_u32(str9xpec_info->options, 63, 1, 1); /* set option byte address */ str9xpec_set_address(bank, 0x50); /* execute ISC_PROGRAM command */ str9xpec_set_instr(tap, ISC_PROGRAM, TAP_IRPAUSE); field.num_bits = 64; field.out_value = str9xpec_info->options; field.in_value = NULL; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); /* small delay before polling */ jtag_add_sleep(50); str9xpec_set_instr(tap, ISC_NOOP, TAP_IRPAUSE); do { field.num_bits = 8; field.out_value = NULL; field.in_value = &status; jtag_add_dr_scan(tap, 1, &field, TAP_IRPAUSE); jtag_execute_queue(); } while (!(status & ISC_STATUS_BUSY)); str9xpec_isc_disable(bank); return status; } COMMAND_HANDLER(str9xpec_handle_flash_options_write_command) { uint8_t status; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; status = str9xpec_write_options(bank); if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) return ERROR_FLASH_OPERATION_FAILED; command_print(CMD_CTX, "str9xpec write options complete.\n" "INFO: a reset or power cycle is required " "for the new settings to take effect."); return ERROR_OK; } COMMAND_HANDLER(str9xpec_handle_flash_options_cmap_command) { struct str9xpec_flash_controller *str9xpec_info = NULL; if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; str9xpec_info = bank->driver_priv; if (strcmp(CMD_ARGV[1], "bank1") == 0) buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_CSMAPBIT, 1, 1); else buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_CSMAPBIT, 1, 0); return ERROR_OK; } COMMAND_HANDLER(str9xpec_handle_flash_options_lvdthd_command) { struct str9xpec_flash_controller *str9xpec_info = NULL; if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; str9xpec_info = bank->driver_priv; if (strcmp(CMD_ARGV[1], "2.7v") == 0) buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDTHRESBIT, 1, 1); else buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDTHRESBIT, 1, 0); return ERROR_OK; } COMMAND_HANDLER(str9xpec_handle_flash_options_lvdsel_command) { struct str9xpec_flash_controller *str9xpec_info = NULL; if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; str9xpec_info = bank->driver_priv; if (strcmp(CMD_ARGV[1], "vdd_vddq") == 0) buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDSELBIT, 1, 1); else buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDSELBIT, 1, 0); return ERROR_OK; } COMMAND_HANDLER(str9xpec_handle_flash_options_lvdwarn_command) { struct str9xpec_flash_controller *str9xpec_info = NULL; if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; str9xpec_info = bank->driver_priv; if (strcmp(CMD_ARGV[1], "vdd_vddq") == 0) buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDWARNBIT, 1, 1); else buf_set_u32(str9xpec_info->options, STR9XPEC_OPT_LVDWARNBIT, 1, 0); return ERROR_OK; } COMMAND_HANDLER(str9xpec_handle_flash_lock_command) { uint8_t status; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; status = str9xpec_lock_device(bank); if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) return ERROR_FLASH_OPERATION_FAILED; return ERROR_OK; } COMMAND_HANDLER(str9xpec_handle_flash_unlock_command) { uint8_t status; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; status = str9xpec_unlock_device(bank); if ((status & ISC_STATUS_ERROR) != STR9XPEC_ISC_SUCCESS) return ERROR_FLASH_OPERATION_FAILED; command_print(CMD_CTX, "str9xpec unlocked.\n" "INFO: a reset or power cycle is required " "for the new settings to take effect."); return ERROR_OK; } COMMAND_HANDLER(str9xpec_handle_flash_enable_turbo_command) { struct jtag_tap *tap0; struct jtag_tap *tap1; struct jtag_tap *tap2; struct str9xpec_flash_controller *str9xpec_info = NULL; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; str9xpec_info = bank->driver_priv; /* remove arm core from chain - enter turbo mode */ tap0 = str9xpec_info->tap; if (tap0 == NULL) { /* things are *WRONG* */ command_print(CMD_CTX, "**STR9FLASH** (tap0) invalid chain?"); return ERROR_FAIL; } tap1 = tap0->next_tap; if (tap1 == NULL) { /* things are *WRONG* */ command_print(CMD_CTX, "**STR9FLASH** (tap1) invalid chain?"); return ERROR_FAIL; } tap2 = tap1->next_tap; if (tap2 == NULL) { /* things are *WRONG* */ command_print(CMD_CTX, "**STR9FLASH** (tap2) invalid chain?"); return ERROR_FAIL; } /* enable turbo mode - TURBO-PROG-ENABLE */ str9xpec_set_instr(tap2, 0xD, TAP_IDLE); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; /* modify scan chain - str9 core has been removed */ tap1->enabled = 0; return ERROR_OK; } COMMAND_HANDLER(str9xpec_handle_flash_disable_turbo_command) { struct jtag_tap *tap; struct str9xpec_flash_controller *str9xpec_info = NULL; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; str9xpec_info = bank->driver_priv; tap = str9xpec_info->tap; if (tap == NULL) return ERROR_FAIL; /* exit turbo mode via RESET */ str9xpec_set_instr(tap, ISC_NOOP, TAP_IDLE); jtag_add_tlr(); jtag_execute_queue(); /* restore previous scan chain */ if (tap->next_tap) tap->next_tap->enabled = 1; return ERROR_OK; } static const struct command_registration str9xpec_config_command_handlers[] = { { .name = "enable_turbo", .usage = "", .handler = str9xpec_handle_flash_enable_turbo_command, .mode = COMMAND_EXEC, .help = "enable str9xpec turbo mode", }, { .name = "disable_turbo", .usage = "", .handler = str9xpec_handle_flash_disable_turbo_command, .mode = COMMAND_EXEC, .help = "disable str9xpec turbo mode", }, { .name = "options_cmap", .usage = " ", .handler = str9xpec_handle_flash_options_cmap_command, .mode = COMMAND_EXEC, .help = "configure str9xpec boot sector", }, { .name = "options_lvdthd", .usage = " <2.4v | 2.7v>", .handler = str9xpec_handle_flash_options_lvdthd_command, .mode = COMMAND_EXEC, .help = "configure str9xpec lvd threshold", }, { .name = "options_lvdsel", .usage = " ", .handler = str9xpec_handle_flash_options_lvdsel_command, .mode = COMMAND_EXEC, .help = "configure str9xpec lvd selection", }, { .name = "options_lvdwarn", .usage = " ", .handler = str9xpec_handle_flash_options_lvdwarn_command, .mode = COMMAND_EXEC, .help = "configure str9xpec lvd warning", }, { .name = "options_read", .usage = "", .handler = str9xpec_handle_flash_options_read_command, .mode = COMMAND_EXEC, .help = "read str9xpec options", }, { .name = "options_write", .usage = "", .handler = str9xpec_handle_flash_options_write_command, .mode = COMMAND_EXEC, .help = "write str9xpec options", }, { .name = "lock", .usage = "", .handler = str9xpec_handle_flash_lock_command, .mode = COMMAND_EXEC, .help = "lock str9xpec device", }, { .name = "unlock", .usage = "", .handler = str9xpec_handle_flash_unlock_command, .mode = COMMAND_EXEC, .help = "unlock str9xpec device", }, { .name = "part_id", .handler = str9xpec_handle_part_id_command, .mode = COMMAND_EXEC, .help = "print part id of str9xpec flash bank ", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration str9xpec_command_handlers[] = { { .name = "str9xpec", .mode = COMMAND_ANY, .help = "str9xpec flash command group", .usage = "", .chain = str9xpec_config_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct flash_driver str9xpec_flash = { .name = "str9xpec", .commands = str9xpec_command_handlers, .flash_bank_command = str9xpec_flash_bank_command, .erase = str9xpec_erase, .protect = str9xpec_protect, .write = str9xpec_write, .read = default_flash_read, .probe = str9xpec_probe, .auto_probe = str9xpec_probe, .erase_check = str9xpec_erase_check, .protect_check = str9xpec_protect_check, .info = get_str9xpec_info, }; openocd-0.7.0/src/flash/nor/lpc2000.c0000644000175000001440000006767412137151331014011 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * LPC1700 support Copyright (C) 2009 by Audrius Urmanavicius * * didele.deze@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include #include #include #include /** * @file * flash programming support for NXP LPC17xx and LPC2xxx devices. * * @todo Provide a way to update CCLK after declaring the flash bank. The value which is correct after chip reset will * rarely still work right after the clocks switch to use the PLL (e.g. 4MHz --> 100 MHz). */ /* * currently supported devices: * variant 1 (lpc2000_v1): * - 2104 | 5 | 6 * - 2114 | 9 * - 2124 | 9 * - 2194 * - 2212 | 4 * - 2292 | 4 * * variant 2 (lpc2000_v2): * - 213x * - 214x * - 2101 | 2 | 3 * - 2364 | 6 | 8 * - 2378 * * lpc1700: * - 175x * - 176x (tested with LPC1768) * * lpc4300 (also available as lpc1800 - alias) * - 43x2 | 3 | 5 | 7 (tested with 4337) * - 18x2 | 3 | 5 | 7 */ typedef enum { lpc2000_v1, lpc2000_v2, lpc1700, lpc4300, } lpc2000_variant; struct lpc2000_flash_bank { lpc2000_variant variant; uint32_t cclk; int cmd51_dst_boundary; int cmd51_can_256b; int cmd51_can_8192b; int calc_checksum; uint32_t cmd51_max_buffer; int checksum_vector; uint32_t iap_max_stack; uint32_t cmd51_src_offset; uint32_t lpc4300_bank; }; enum lpc2000_status_codes { LPC2000_CMD_SUCCESS = 0, LPC2000_INVALID_COMMAND = 1, LPC2000_SRC_ADDR_ERROR = 2, LPC2000_DST_ADDR_ERROR = 3, LPC2000_SRC_ADDR_NOT_MAPPED = 4, LPC2000_DST_ADDR_NOT_MAPPED = 5, LPC2000_COUNT_ERROR = 6, LPC2000_INVALID_SECTOR = 7, LPC2000_SECTOR_NOT_BLANK = 8, LPC2000_SECTOR_NOT_PREPARED = 9, LPC2000_COMPARE_ERROR = 10, LPC2000_BUSY = 11, LPC2000_PARAM_ERROR = 12, LPC2000_ADDR_ERROR = 13, LPC2000_ADDR_NOT_MAPPED = 14, LPC2000_CMD_NOT_LOCKED = 15, LPC2000_INVALID_CODE = 16, LPC2000_INVALID_BAUD_RATE = 17, LPC2000_INVALID_STOP_BIT = 18, LPC2000_CRP_ENABLED = 19, LPC2000_INVALID_FLASH_UNIT = 20, LPC2000_USER_CODE_CHECKSUM = 21, LCP2000_ERROR_SETTING_ACTIVE_PARTITION = 22, }; static int lpc2000_build_sector_list(struct flash_bank *bank) { struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv; uint32_t offset = 0; /* default to a 4096 write buffer */ lpc2000_info->cmd51_max_buffer = 4096; if (lpc2000_info->variant == lpc2000_v1) { /* variant 1 has different layout for 128kb and 256kb flashes */ if (bank->size == 128 * 1024) { bank->num_sectors = 16; bank->sectors = malloc(sizeof(struct flash_sector) * 16); for (int i = 0; i < 16; i++) { bank->sectors[i].offset = offset; bank->sectors[i].size = 8 * 1024; offset += bank->sectors[i].size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } } else if (bank->size == 256 * 1024) { bank->num_sectors = 18; bank->sectors = malloc(sizeof(struct flash_sector) * 18); for (int i = 0; i < 8; i++) { bank->sectors[i].offset = offset; bank->sectors[i].size = 8 * 1024; offset += bank->sectors[i].size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } for (int i = 8; i < 10; i++) { bank->sectors[i].offset = offset; bank->sectors[i].size = 64 * 1024; offset += bank->sectors[i].size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } for (int i = 10; i < 18; i++) { bank->sectors[i].offset = offset; bank->sectors[i].size = 8 * 1024; offset += bank->sectors[i].size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } } else { LOG_ERROR("BUG: unknown bank->size encountered"); exit(-1); } } else if (lpc2000_info->variant == lpc2000_v2) { /* variant 2 has a uniform layout, only number of sectors differs */ switch (bank->size) { case 4 * 1024: lpc2000_info->cmd51_max_buffer = 1024; bank->num_sectors = 1; break; case 8 * 1024: lpc2000_info->cmd51_max_buffer = 1024; bank->num_sectors = 2; break; case 16 * 1024: bank->num_sectors = 4; break; case 32 * 1024: bank->num_sectors = 8; break; case 64 * 1024: bank->num_sectors = 9; break; case 128 * 1024: bank->num_sectors = 11; break; case 256 * 1024: bank->num_sectors = 15; break; case 500 * 1024: bank->num_sectors = 27; break; case 512 * 1024: case 504 * 1024: bank->num_sectors = 28; break; default: LOG_ERROR("BUG: unknown bank->size encountered"); exit(-1); break; } bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); for (int i = 0; i < bank->num_sectors; i++) { if (i < 8) { bank->sectors[i].offset = offset; bank->sectors[i].size = 4 * 1024; offset += bank->sectors[i].size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } else if (i < 22) { bank->sectors[i].offset = offset; bank->sectors[i].size = 32 * 1024; offset += bank->sectors[i].size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } else if (i < 28) { bank->sectors[i].offset = offset; bank->sectors[i].size = 4 * 1024; offset += bank->sectors[i].size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } } } else if (lpc2000_info->variant == lpc1700) { switch (bank->size) { case 32 * 1024: bank->num_sectors = 8; break; case 64 * 1024: bank->num_sectors = 16; break; case 128 * 1024: bank->num_sectors = 18; break; case 256 * 1024: bank->num_sectors = 22; break; case 512 * 1024: bank->num_sectors = 30; break; default: LOG_ERROR("BUG: unknown bank->size encountered"); exit(-1); } bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); for (int i = 0; i < bank->num_sectors; i++) { bank->sectors[i].offset = offset; /* sectors 0-15 are 4kB-sized, 16 and above are 32kB-sized for LPC17xx devices */ bank->sectors[i].size = (i < 16) ? 4 * 1024 : 32 * 1024; offset += bank->sectors[i].size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } } else if (lpc2000_info->variant == lpc4300) { switch (bank->size) { case 256 * 1024: bank->num_sectors = 11; break; case 384 * 1024: bank->num_sectors = 13; break; case 512 * 1024: bank->num_sectors = 15; break; default: LOG_ERROR("BUG: unknown bank->size encountered"); exit(-1); } bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); for (int i = 0; i < bank->num_sectors; i++) { bank->sectors[i].offset = offset; /* sectors 0-7 are 8kB-sized, 8 and above are 64kB-sized for LPC43xx devices */ bank->sectors[i].size = (i < 8) ? 8 * 1024 : 64 * 1024; offset += bank->sectors[i].size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } } else { LOG_ERROR("BUG: unknown lpc2000_info->variant encountered"); exit(-1); } return ERROR_OK; } /* this function allocates and initializes working area used for IAP algorithm * uses 52 + max IAP stack bytes working area * 0x0 to 0x7: jump gate (BX to thumb state, b -2 to wait) * 0x8 to 0x1f: command parameter table (1+5 words) * 0x20 to 0x33: command result table (1+4 words) * 0x34 to 0xb3|0x104: stack (only 128b needed for lpc17xx/2000, 208 for lpc43xx) */ static int lpc2000_iap_working_area_init(struct flash_bank *bank, struct working_area **iap_working_area) { struct target *target = bank->target; struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv; if (target_alloc_working_area(target, 0x34 + lpc2000_info->iap_max_stack, iap_working_area) != ERROR_OK) { LOG_ERROR("no working area specified, can't write LPC2000 internal flash"); return ERROR_FLASH_OPERATION_FAILED; } uint8_t jump_gate[8]; /* write IAP code to working area */ switch (lpc2000_info->variant) { case lpc1700: case lpc4300: target_buffer_set_u32(target, jump_gate, ARMV4_5_T_BX(12)); target_buffer_set_u32(target, jump_gate + 4, ARMV5_T_BKPT(0)); break; case lpc2000_v1: case lpc2000_v2: target_buffer_set_u32(target, jump_gate, ARMV4_5_BX(12)); target_buffer_set_u32(target, jump_gate + 4, ARMV4_5_B(0xfffffe, 0)); break; default: LOG_ERROR("BUG: unknown lpc2000_info->variant encountered"); exit(-1); } int retval = target_write_memory(target, (*iap_working_area)->address, 4, 2, jump_gate); if (retval != ERROR_OK) LOG_ERROR("Write memory at address 0x%8.8" PRIx32 " failed (check work_area definition)", (*iap_working_area)->address); return retval; } /* call LPC1700/LPC2000 IAP function */ static int lpc2000_iap_call(struct flash_bank *bank, struct working_area *iap_working_area, int code, uint32_t param_table[5], uint32_t result_table[4]) { struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv; struct target *target = bank->target; struct arm_algorithm arm_algo; /* for LPC2000 */ struct armv7m_algorithm armv7m_info; /* for LPC1700 */ uint32_t iap_entry_point = 0; /* to make compiler happier */ switch (lpc2000_info->variant) { case lpc1700: armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; iap_entry_point = 0x1fff1ff1; break; case lpc2000_v1: case lpc2000_v2: arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; iap_entry_point = 0x7ffffff1; break; case lpc4300: armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; /* read out IAP entry point from ROM driver table at 0x10400100 */ target_read_u32(target, 0x10400100, &iap_entry_point); break; default: LOG_ERROR("BUG: unknown lpc2000->variant encountered"); exit(-1); } struct mem_param mem_params[2]; /* command parameter table */ init_mem_param(&mem_params[0], iap_working_area->address + 8, 6 * 4, PARAM_OUT); target_buffer_set_u32(target, mem_params[0].value, code); target_buffer_set_u32(target, mem_params[0].value + 0x04, param_table[0]); target_buffer_set_u32(target, mem_params[0].value + 0x08, param_table[1]); target_buffer_set_u32(target, mem_params[0].value + 0x0c, param_table[2]); target_buffer_set_u32(target, mem_params[0].value + 0x10, param_table[3]); target_buffer_set_u32(target, mem_params[0].value + 0x14, param_table[4]); struct reg_param reg_params[5]; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, iap_working_area->address + 0x08); /* command result table */ init_mem_param(&mem_params[1], iap_working_area->address + 0x20, 5 * 4, PARAM_IN); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); buf_set_u32(reg_params[1].value, 0, 32, iap_working_area->address + 0x20); /* IAP entry point */ init_reg_param(®_params[2], "r12", 32, PARAM_OUT); buf_set_u32(reg_params[2].value, 0, 32, iap_entry_point); switch (lpc2000_info->variant) { case lpc1700: case lpc4300: /* IAP stack */ init_reg_param(®_params[3], "sp", 32, PARAM_OUT); buf_set_u32(reg_params[3].value, 0, 32, iap_working_area->address + lpc2000_info->cmd51_src_offset); /* return address */ init_reg_param(®_params[4], "lr", 32, PARAM_OUT); buf_set_u32(reg_params[4].value, 0, 32, (iap_working_area->address + 0x04) | 1); /* bit0 of LR = 1 to return in Thumb mode */ target_run_algorithm(target, 2, mem_params, 5, reg_params, iap_working_area->address, 0, 10000, &armv7m_info); break; case lpc2000_v1: case lpc2000_v2: /* IAP stack */ init_reg_param(®_params[3], "sp_svc", 32, PARAM_OUT); buf_set_u32(reg_params[3].value, 0, 32, iap_working_area->address + lpc2000_info->cmd51_src_offset); /* return address */ init_reg_param(®_params[4], "lr_svc", 32, PARAM_OUT); buf_set_u32(reg_params[4].value, 0, 32, iap_working_area->address + 0x04); target_run_algorithm(target, 2, mem_params, 5, reg_params, iap_working_area->address, iap_working_area->address + 0x4, 10000, &arm_algo); break; default: LOG_ERROR("BUG: unknown lpc2000->variant encountered"); exit(-1); } int status_code = target_buffer_get_u32(target, mem_params[1].value); result_table[0] = target_buffer_get_u32(target, mem_params[1].value + 0x04); result_table[1] = target_buffer_get_u32(target, mem_params[1].value + 0x08); result_table[2] = target_buffer_get_u32(target, mem_params[1].value + 0x0c); result_table[3] = target_buffer_get_u32(target, mem_params[1].value + 0x10); LOG_DEBUG("IAP command = %i (0x%8.8" PRIx32 ", 0x%8.8" PRIx32 ", 0x%8.8" PRIx32 ", 0x%8.8" PRIx32 ", 0x%8.8" PRIx32 ") completed with result = %8.8" PRIx32, code, param_table[0], param_table[1], param_table[2], param_table[3], param_table[4], status_code); destroy_mem_param(&mem_params[0]); destroy_mem_param(&mem_params[1]); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); return status_code; } static int lpc2000_iap_blank_check(struct flash_bank *bank, int first, int last) { if ((first < 0) || (last >= bank->num_sectors)) return ERROR_FLASH_SECTOR_INVALID; uint32_t param_table[5] = {0}; uint32_t result_table[4]; struct working_area *iap_working_area; int retval = lpc2000_iap_working_area_init(bank, &iap_working_area); if (retval != ERROR_OK) return retval; struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv; if (lpc2000_info->variant == lpc4300) param_table[2] = lpc2000_info->lpc4300_bank; for (int i = first; i <= last && retval == ERROR_OK; i++) { /* check single sector */ param_table[0] = param_table[1] = i; int status_code = lpc2000_iap_call(bank, iap_working_area, 53, param_table, result_table); switch (status_code) { case ERROR_FLASH_OPERATION_FAILED: retval = ERROR_FLASH_OPERATION_FAILED; break; case LPC2000_CMD_SUCCESS: bank->sectors[i].is_erased = 1; break; case LPC2000_SECTOR_NOT_BLANK: bank->sectors[i].is_erased = 0; break; case LPC2000_INVALID_SECTOR: bank->sectors[i].is_erased = 0; break; case LPC2000_BUSY: retval = ERROR_FLASH_BUSY; break; default: LOG_ERROR("BUG: unknown LPC2000 status code %i", status_code); exit(-1); } } struct target *target = bank->target; target_free_working_area(target, iap_working_area); return retval; } /* * flash bank lpc2000 0 0 [calc_checksum] */ FLASH_BANK_COMMAND_HANDLER(lpc2000_flash_bank_command) { if (CMD_ARGC < 8) return ERROR_COMMAND_SYNTAX_ERROR; struct lpc2000_flash_bank *lpc2000_info = malloc(sizeof(struct lpc2000_flash_bank)); bank->driver_priv = lpc2000_info; if (strcmp(CMD_ARGV[6], "lpc2000_v1") == 0) { lpc2000_info->variant = lpc2000_v1; lpc2000_info->cmd51_dst_boundary = 512; lpc2000_info->cmd51_can_256b = 0; lpc2000_info->cmd51_can_8192b = 1; lpc2000_info->checksum_vector = 5; lpc2000_info->iap_max_stack = 128; } else if (strcmp(CMD_ARGV[6], "lpc2000_v2") == 0) { lpc2000_info->variant = lpc2000_v2; lpc2000_info->cmd51_dst_boundary = 256; lpc2000_info->cmd51_can_256b = 1; lpc2000_info->cmd51_can_8192b = 0; lpc2000_info->checksum_vector = 5; lpc2000_info->iap_max_stack = 128; } else if (strcmp(CMD_ARGV[6], "lpc1700") == 0) { lpc2000_info->variant = lpc1700; lpc2000_info->cmd51_dst_boundary = 256; lpc2000_info->cmd51_can_256b = 1; lpc2000_info->cmd51_can_8192b = 0; lpc2000_info->checksum_vector = 7; lpc2000_info->iap_max_stack = 128; } else if (strcmp(CMD_ARGV[6], "lpc1800") == 0 || strcmp(CMD_ARGV[6], "lpc4300") == 0) { lpc2000_info->variant = lpc4300; lpc2000_info->cmd51_dst_boundary = 512; lpc2000_info->cmd51_can_256b = 0; lpc2000_info->cmd51_can_8192b = 0; lpc2000_info->checksum_vector = 7; lpc2000_info->iap_max_stack = 208; } else { LOG_ERROR("unknown LPC2000 variant: %s", CMD_ARGV[6]); free(lpc2000_info); return ERROR_FLASH_BANK_INVALID; } /* see lpc2000_iap_working_area_init() for the reason behind the 0x34 value */ lpc2000_info->cmd51_src_offset = 0x34 + lpc2000_info->iap_max_stack; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[7], lpc2000_info->cclk); lpc2000_info->calc_checksum = 0; lpc2000_build_sector_list(bank); uint32_t temp_base = 0; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], temp_base); if (temp_base >= 0x1B000000) lpc2000_info->lpc4300_bank = 1; /* bank B */ else lpc2000_info->lpc4300_bank = 0; /* bank A */ if (CMD_ARGC >= 9) { if (strcmp(CMD_ARGV[8], "calc_checksum") == 0) lpc2000_info->calc_checksum = 1; } return ERROR_OK; } static int lpc2000_erase(struct flash_bank *bank, int first, int last) { if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv; uint32_t param_table[5] = {0}; param_table[0] = first; param_table[1] = last; if (lpc2000_info->variant == lpc4300) param_table[2] = lpc2000_info->lpc4300_bank; else param_table[2] = lpc2000_info->cclk; uint32_t result_table[4]; struct working_area *iap_working_area; int retval = lpc2000_iap_working_area_init(bank, &iap_working_area); if (retval != ERROR_OK) return retval; /* Prepare sectors */ int status_code = lpc2000_iap_call(bank, iap_working_area, 50, param_table, result_table); switch (status_code) { case ERROR_FLASH_OPERATION_FAILED: retval = ERROR_FLASH_OPERATION_FAILED; break; case LPC2000_CMD_SUCCESS: break; case LPC2000_INVALID_SECTOR: retval = ERROR_FLASH_SECTOR_INVALID; break; default: LOG_WARNING("lpc2000 prepare sectors returned %i", status_code); retval = ERROR_FLASH_OPERATION_FAILED; break; } if (retval == ERROR_OK) { /* Erase sectors */ param_table[2] = lpc2000_info->cclk; if (lpc2000_info->variant == lpc4300) param_table[3] = lpc2000_info->lpc4300_bank; status_code = lpc2000_iap_call(bank, iap_working_area, 52, param_table, result_table); switch (status_code) { case ERROR_FLASH_OPERATION_FAILED: retval = ERROR_FLASH_OPERATION_FAILED; break; case LPC2000_CMD_SUCCESS: break; case LPC2000_INVALID_SECTOR: retval = ERROR_FLASH_SECTOR_INVALID; break; default: LOG_WARNING("lpc2000 erase sectors returned %i", status_code); retval = ERROR_FLASH_OPERATION_FAILED; break; } } struct target *target = bank->target; target_free_working_area(target, iap_working_area); return retval; } static int lpc2000_protect(struct flash_bank *bank, int set, int first, int last) { /* can't protect/unprotect on the lpc2000 */ return ERROR_OK; } static int lpc2000_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset + count > bank->size) return ERROR_FLASH_DST_OUT_OF_BANK; struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv; uint32_t dst_min_alignment = lpc2000_info->cmd51_dst_boundary; if (offset % dst_min_alignment) { LOG_WARNING("offset 0x%" PRIx32 " breaks required alignment 0x%" PRIx32, offset, dst_min_alignment); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } int first_sector = 0; int last_sector = 0; for (int i = 0; i < bank->num_sectors; i++) { if (offset >= bank->sectors[i].offset) first_sector = i; if (offset + DIV_ROUND_UP(count, dst_min_alignment) * dst_min_alignment > bank->sectors[i].offset) last_sector = i; } LOG_DEBUG("first_sector: %i, last_sector: %i", first_sector, last_sector); /* check if exception vectors should be flashed */ if ((offset == 0) && (count >= 0x20) && lpc2000_info->calc_checksum) { uint32_t checksum = 0; for (int i = 0; i < 8; i++) { LOG_DEBUG("Vector 0x%2.2x: 0x%8.8" PRIx32, i * 4, buf_get_u32(buffer + (i * 4), 0, 32)); if (i != lpc2000_info->checksum_vector) checksum += buf_get_u32(buffer + (i * 4), 0, 32); } checksum = 0 - checksum; LOG_DEBUG("checksum: 0x%8.8" PRIx32, checksum); uint32_t original_value = buf_get_u32(buffer + (lpc2000_info->checksum_vector * 4), 0, 32); if (original_value != checksum) { LOG_WARNING("Verification will fail since checksum in image (0x%8.8" PRIx32 ") to be written to flash is " "different from calculated vector checksum (0x%8.8" PRIx32 ").", original_value, checksum); LOG_WARNING("To remove this warning modify build tools on developer PC to inject correct LPC vector " "checksum."); } buf_set_u32(buffer + (lpc2000_info->checksum_vector * 4), 0, 32, checksum); } struct working_area *iap_working_area; int retval = lpc2000_iap_working_area_init(bank, &iap_working_area); if (retval != ERROR_OK) return retval; struct working_area *download_area; /* allocate a working area */ if (target_alloc_working_area(target, lpc2000_info->cmd51_max_buffer, &download_area) != ERROR_OK) { LOG_ERROR("no working area specified, can't write LPC2000 internal flash"); target_free_working_area(target, iap_working_area); return ERROR_FLASH_OPERATION_FAILED; } uint32_t bytes_remaining = count; uint32_t bytes_written = 0; uint32_t param_table[5] = {0}; uint32_t result_table[4]; while (bytes_remaining > 0) { uint32_t thisrun_bytes; if (bytes_remaining >= lpc2000_info->cmd51_max_buffer) thisrun_bytes = lpc2000_info->cmd51_max_buffer; else if (bytes_remaining >= 1024) thisrun_bytes = 1024; else if ((bytes_remaining >= 512) || (!lpc2000_info->cmd51_can_256b)) thisrun_bytes = 512; else thisrun_bytes = 256; /* Prepare sectors */ param_table[0] = first_sector; param_table[1] = last_sector; if (lpc2000_info->variant == lpc4300) param_table[2] = lpc2000_info->lpc4300_bank; else param_table[2] = lpc2000_info->cclk; int status_code = lpc2000_iap_call(bank, iap_working_area, 50, param_table, result_table); switch (status_code) { case ERROR_FLASH_OPERATION_FAILED: retval = ERROR_FLASH_OPERATION_FAILED; break; case LPC2000_CMD_SUCCESS: break; case LPC2000_INVALID_SECTOR: retval = ERROR_FLASH_SECTOR_INVALID; break; default: LOG_WARNING("lpc2000 prepare sectors returned %i", status_code); retval = ERROR_FLASH_OPERATION_FAILED; break; } /* Exit if error occured */ if (retval != ERROR_OK) break; if (bytes_remaining >= thisrun_bytes) { retval = target_write_buffer(bank->target, download_area->address, thisrun_bytes, buffer + bytes_written); if (retval != ERROR_OK) { retval = ERROR_FLASH_OPERATION_FAILED; break; } } else { uint8_t *last_buffer = malloc(thisrun_bytes); memcpy(last_buffer, buffer + bytes_written, bytes_remaining); memset(last_buffer + bytes_remaining, 0xff, thisrun_bytes - bytes_remaining); target_write_buffer(bank->target, download_area->address, thisrun_bytes, last_buffer); free(last_buffer); } LOG_DEBUG("writing 0x%" PRIx32 " bytes to address 0x%" PRIx32, thisrun_bytes, bank->base + offset + bytes_written); /* Write data */ param_table[0] = bank->base + offset + bytes_written; param_table[1] = download_area->address; param_table[2] = thisrun_bytes; param_table[3] = lpc2000_info->cclk; status_code = lpc2000_iap_call(bank, iap_working_area, 51, param_table, result_table); switch (status_code) { case ERROR_FLASH_OPERATION_FAILED: retval = ERROR_FLASH_OPERATION_FAILED; break; case LPC2000_CMD_SUCCESS: break; case LPC2000_INVALID_SECTOR: retval = ERROR_FLASH_SECTOR_INVALID; break; default: LOG_WARNING("lpc2000 returned %i", status_code); retval = ERROR_FLASH_OPERATION_FAILED; break; } /* Exit if error occured */ if (retval != ERROR_OK) break; if (bytes_remaining > thisrun_bytes) bytes_remaining -= thisrun_bytes; else bytes_remaining = 0; bytes_written += thisrun_bytes; } target_free_working_area(target, iap_working_area); target_free_working_area(target, download_area); return retval; } static int lpc2000_probe(struct flash_bank *bank) { /* we can't probe on an lpc2000 if this is an lpc2xxx, it has the configured flash */ return ERROR_OK; } static int lpc2000_erase_check(struct flash_bank *bank) { if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } return lpc2000_iap_blank_check(bank, 0, bank->num_sectors - 1); } static int lpc2000_protect_check(struct flash_bank *bank) { /* sectors are always protected */ return ERROR_OK; } static int get_lpc2000_info(struct flash_bank *bank, char *buf, int buf_size) { struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv; snprintf(buf, buf_size, "lpc2000 flash driver variant: %i, clk: %" PRIi32 "kHz", lpc2000_info->variant, lpc2000_info->cclk); return ERROR_OK; } COMMAND_HANDLER(lpc2000_handle_part_id_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } uint32_t param_table[5] = {0}; uint32_t result_table[4]; struct working_area *iap_working_area; retval = lpc2000_iap_working_area_init(bank, &iap_working_area); if (retval != ERROR_OK) return retval; int status_code = lpc2000_iap_call(bank, iap_working_area, 54, param_table, result_table); if (status_code != 0x0) { if (status_code == ERROR_FLASH_OPERATION_FAILED) { command_print(CMD_CTX, "no sufficient working area specified, can't access LPC2000 IAP interface"); } else command_print(CMD_CTX, "lpc2000 IAP returned status code %i", status_code); } else command_print(CMD_CTX, "lpc2000 part id: 0x%8.8" PRIx32, result_table[0]); return retval; } static const struct command_registration lpc2000_exec_command_handlers[] = { { .name = "part_id", .handler = lpc2000_handle_part_id_command, .mode = COMMAND_EXEC, .help = "print part id of lpc2000 flash bank ", .usage = "", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration lpc2000_command_handlers[] = { { .name = "lpc2000", .mode = COMMAND_ANY, .help = "lpc2000 flash command group", .usage = "", .chain = lpc2000_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct flash_driver lpc2000_flash = { .name = "lpc2000", .commands = lpc2000_command_handlers, .flash_bank_command = lpc2000_flash_bank_command, .erase = lpc2000_erase, .protect = lpc2000_protect, .write = lpc2000_write, .read = default_flash_read, .probe = lpc2000_probe, .auto_probe = lpc2000_probe, .erase_check = lpc2000_erase_check, .protect_check = lpc2000_protect_check, .info = get_lpc2000_info, }; openocd-0.7.0/src/flash/nor/tms470.c0000644000175000001440000010574312134336410013755 00000000000000/*************************************************************************** * Copyright (C) 2007,2008 by Christopher Kilgour * * techie |_at_| whiterocker |_dot_| com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" /* ---------------------------------------------------------------------- * Internal Support, Helpers * ---------------------------------------------------------------------- */ struct tms470_flash_bank { unsigned ordinal; /* device identification register */ uint32_t device_ident_reg; uint32_t silicon_version; uint32_t technology_family; uint32_t rom_flash; uint32_t part_number; const char *part_name; }; static const struct flash_sector TMS470R1A256_SECTORS[] = { {0x00000000, 0x00002000, -1, -1}, {0x00002000, 0x00002000, -1, -1}, {0x00004000, 0x00002000, -1, -1}, {0x00006000, 0x00002000, -1, -1}, {0x00008000, 0x00008000, -1, -1}, {0x00010000, 0x00008000, -1, -1}, {0x00018000, 0x00008000, -1, -1}, {0x00020000, 0x00008000, -1, -1}, {0x00028000, 0x00008000, -1, -1}, {0x00030000, 0x00008000, -1, -1}, {0x00038000, 0x00002000, -1, -1}, {0x0003A000, 0x00002000, -1, -1}, {0x0003C000, 0x00002000, -1, -1}, {0x0003E000, 0x00002000, -1, -1}, }; #define TMS470R1A256_NUM_SECTORS \ ARRAY_SIZE(TMS470R1A256_SECTORS) static const struct flash_sector TMS470R1A288_BANK0_SECTORS[] = { {0x00000000, 0x00002000, -1, -1}, {0x00002000, 0x00002000, -1, -1}, {0x00004000, 0x00002000, -1, -1}, {0x00006000, 0x00002000, -1, -1}, }; #define TMS470R1A288_BANK0_NUM_SECTORS \ ARRAY_SIZE(TMS470R1A288_BANK0_SECTORS) static const struct flash_sector TMS470R1A288_BANK1_SECTORS[] = { {0x00040000, 0x00010000, -1, -1}, {0x00050000, 0x00010000, -1, -1}, {0x00060000, 0x00010000, -1, -1}, {0x00070000, 0x00010000, -1, -1}, }; #define TMS470R1A288_BANK1_NUM_SECTORS \ ARRAY_SIZE(TMS470R1A288_BANK1_SECTORS) static const struct flash_sector TMS470R1A384_BANK0_SECTORS[] = { {0x00000000, 0x00002000, -1, -1}, {0x00002000, 0x00002000, -1, -1}, {0x00004000, 0x00004000, -1, -1}, {0x00008000, 0x00004000, -1, -1}, {0x0000C000, 0x00004000, -1, -1}, {0x00010000, 0x00004000, -1, -1}, {0x00014000, 0x00004000, -1, -1}, {0x00018000, 0x00002000, -1, -1}, {0x0001C000, 0x00002000, -1, -1}, {0x0001E000, 0x00002000, -1, -1}, }; #define TMS470R1A384_BANK0_NUM_SECTORS \ ARRAY_SIZE(TMS470R1A384_BANK0_SECTORS) static const struct flash_sector TMS470R1A384_BANK1_SECTORS[] = { {0x00020000, 0x00008000, -1, -1}, {0x00028000, 0x00008000, -1, -1}, {0x00030000, 0x00008000, -1, -1}, {0x00038000, 0x00008000, -1, -1}, }; #define TMS470R1A384_BANK1_NUM_SECTORS \ ARRAY_SIZE(TMS470R1A384_BANK1_SECTORS) static const struct flash_sector TMS470R1A384_BANK2_SECTORS[] = { {0x00040000, 0x00008000, -1, -1}, {0x00048000, 0x00008000, -1, -1}, {0x00050000, 0x00008000, -1, -1}, {0x00058000, 0x00008000, -1, -1}, }; #define TMS470R1A384_BANK2_NUM_SECTORS \ ARRAY_SIZE(TMS470R1A384_BANK2_SECTORS) /* ---------------------------------------------------------------------- */ static int tms470_read_part_info(struct flash_bank *bank) { struct tms470_flash_bank *tms470_info = bank->driver_priv; struct target *target = bank->target; uint32_t device_ident_reg; uint32_t silicon_version; uint32_t technology_family; uint32_t rom_flash; uint32_t part_number; const char *part_name; /* we shall not rely on the caller in this test, this function allocates memory, thus and executing the code more than once may cause memory leak */ if (tms470_info->device_ident_reg) return ERROR_OK; /* read and parse the device identification register */ target_read_u32(target, 0xFFFFFFF0, &device_ident_reg); LOG_INFO("device_ident_reg = 0x%08" PRIx32 "", device_ident_reg); if ((device_ident_reg & 7) == 0) { LOG_WARNING("Cannot identify target as a TMS470 family."); return ERROR_FLASH_OPERATION_FAILED; } silicon_version = (device_ident_reg >> 12) & 0xF; technology_family = (device_ident_reg >> 11) & 1; rom_flash = (device_ident_reg >> 10) & 1; part_number = (device_ident_reg >> 3) & 0x7f; if (bank->sectors) { free(bank->sectors); bank->sectors = NULL; } /* * If the part number is known, determine if the flash bank is valid * based on the base address being within the known flash bank * ranges. Then fixup/complete the remaining fields of the flash * bank structure. */ switch (part_number) { case 0x0a: part_name = "TMS470R1A256"; if (bank->base >= 0x00040000) { LOG_ERROR("No %s flash bank contains base address 0x%08" PRIx32 ".", part_name, bank->base); return ERROR_FLASH_OPERATION_FAILED; } tms470_info->ordinal = 0; bank->base = 0x00000000; bank->size = 256 * 1024; bank->num_sectors = TMS470R1A256_NUM_SECTORS; bank->sectors = malloc(sizeof(TMS470R1A256_SECTORS)); if (!bank->sectors) return ERROR_FLASH_OPERATION_FAILED; (void)memcpy(bank->sectors, TMS470R1A256_SECTORS, sizeof(TMS470R1A256_SECTORS)); break; case 0x2b: part_name = "TMS470R1A288"; if (bank->base < 0x00008000) { tms470_info->ordinal = 0; bank->base = 0x00000000; bank->size = 32 * 1024; bank->num_sectors = TMS470R1A288_BANK0_NUM_SECTORS; bank->sectors = malloc(sizeof(TMS470R1A288_BANK0_SECTORS)); if (!bank->sectors) return ERROR_FLASH_OPERATION_FAILED; (void)memcpy(bank->sectors, TMS470R1A288_BANK0_SECTORS, sizeof(TMS470R1A288_BANK0_SECTORS)); } else if ((bank->base >= 0x00040000) && (bank->base < 0x00080000)) { tms470_info->ordinal = 1; bank->base = 0x00040000; bank->size = 256 * 1024; bank->num_sectors = TMS470R1A288_BANK1_NUM_SECTORS; bank->sectors = malloc(sizeof(TMS470R1A288_BANK1_SECTORS)); if (!bank->sectors) return ERROR_FLASH_OPERATION_FAILED; (void)memcpy(bank->sectors, TMS470R1A288_BANK1_SECTORS, sizeof(TMS470R1A288_BANK1_SECTORS)); } else { LOG_ERROR("No %s flash bank contains base address 0x%08" PRIx32 ".", part_name, bank->base); return ERROR_FLASH_OPERATION_FAILED; } break; case 0x2d: part_name = "TMS470R1A384"; if (bank->base < 0x00020000) { tms470_info->ordinal = 0; bank->base = 0x00000000; bank->size = 128 * 1024; bank->num_sectors = TMS470R1A384_BANK0_NUM_SECTORS; bank->sectors = malloc(sizeof(TMS470R1A384_BANK0_SECTORS)); if (!bank->sectors) return ERROR_FLASH_OPERATION_FAILED; (void)memcpy(bank->sectors, TMS470R1A384_BANK0_SECTORS, sizeof(TMS470R1A384_BANK0_SECTORS)); } else if ((bank->base >= 0x00020000) && (bank->base < 0x00040000)) { tms470_info->ordinal = 1; bank->base = 0x00020000; bank->size = 128 * 1024; bank->num_sectors = TMS470R1A384_BANK1_NUM_SECTORS; bank->sectors = malloc(sizeof(TMS470R1A384_BANK1_SECTORS)); if (!bank->sectors) return ERROR_FLASH_OPERATION_FAILED; (void)memcpy(bank->sectors, TMS470R1A384_BANK1_SECTORS, sizeof(TMS470R1A384_BANK1_SECTORS)); } else if ((bank->base >= 0x00040000) && (bank->base < 0x00060000)) { tms470_info->ordinal = 2; bank->base = 0x00040000; bank->size = 128 * 1024; bank->num_sectors = TMS470R1A384_BANK2_NUM_SECTORS; bank->sectors = malloc(sizeof(TMS470R1A384_BANK2_SECTORS)); if (!bank->sectors) return ERROR_FLASH_OPERATION_FAILED; (void)memcpy(bank->sectors, TMS470R1A384_BANK2_SECTORS, sizeof(TMS470R1A384_BANK2_SECTORS)); } else { LOG_ERROR("No %s flash bank contains base address 0x%08" PRIx32 ".", part_name, bank->base); return ERROR_FLASH_OPERATION_FAILED; } break; default: LOG_WARNING("Could not identify part 0x%02x as a member of the TMS470 family.", (unsigned)part_number); return ERROR_FLASH_OPERATION_FAILED; } /* turn off memory selects */ target_write_u32(target, 0xFFFFFFE4, 0x00000000); target_write_u32(target, 0xFFFFFFE0, 0x00000000); bank->chip_width = 32; bank->bus_width = 32; LOG_INFO("Identified %s, ver=%d, core=%s, nvmem=%s.", part_name, (int)(silicon_version), (technology_family ? "1.8v" : "3.3v"), (rom_flash ? "rom" : "flash")); tms470_info->device_ident_reg = device_ident_reg; tms470_info->silicon_version = silicon_version; tms470_info->technology_family = technology_family; tms470_info->rom_flash = rom_flash; tms470_info->part_number = part_number; tms470_info->part_name = part_name; /* * Disable reset on address access violation. */ target_write_u32(target, 0xFFFFFFE0, 0x00004007); return ERROR_OK; } /* ---------------------------------------------------------------------- */ static uint32_t keysSet; static uint32_t flashKeys[4]; COMMAND_HANDLER(tms470_handle_flash_keyset_command) { if (CMD_ARGC > 4) return ERROR_COMMAND_SYNTAX_ERROR; else if (CMD_ARGC == 4) { int i; for (i = 0; i < 4; i++) { int start = (0 == strncmp(CMD_ARGV[i], "0x", 2)) ? 2 : 0; if (1 != sscanf(&CMD_ARGV[i][start], "%" SCNx32 "", &flashKeys[i])) { command_print(CMD_CTX, "could not process flash key %s", CMD_ARGV[i]); LOG_ERROR("could not process flash key %s", CMD_ARGV[i]); return ERROR_COMMAND_SYNTAX_ERROR; } } keysSet = 1; } else if (CMD_ARGC != 0) { command_print(CMD_CTX, "tms470 flash_keyset "); return ERROR_COMMAND_SYNTAX_ERROR; } if (keysSet) { command_print(CMD_CTX, "using flash keys 0x%08" PRIx32 ", 0x%08" PRIx32 ", 0x%08" PRIx32 ", 0x%08" PRIx32 "", flashKeys[0], flashKeys[1], flashKeys[2], flashKeys[3]); } else command_print(CMD_CTX, "flash keys not set"); return ERROR_OK; } static const uint32_t FLASH_KEYS_ALL_ONES[] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,}; static const uint32_t FLASH_KEYS_ALL_ZEROS[] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000,}; static const uint32_t FLASH_KEYS_MIX1[] = { 0xf0fff0ff, 0xf0fff0ff, 0xf0fff0ff, 0xf0fff0ff}; static const uint32_t FLASH_KEYS_MIX2[] = { 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff}; /* ---------------------------------------------------------------------- */ static int oscMHz = 12; COMMAND_HANDLER(tms470_handle_osc_megahertz_command) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; else if (CMD_ARGC == 1) sscanf(CMD_ARGV[0], "%d", &oscMHz); if (oscMHz <= 0) { LOG_ERROR("osc_megahertz must be positive and non-zero!"); command_print(CMD_CTX, "osc_megahertz must be positive and non-zero!"); oscMHz = 12; return ERROR_COMMAND_SYNTAX_ERROR; } command_print(CMD_CTX, "osc_megahertz=%d", oscMHz); return ERROR_OK; } /* ---------------------------------------------------------------------- */ static int plldis; COMMAND_HANDLER(tms470_handle_plldis_command) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; else if (CMD_ARGC == 1) { sscanf(CMD_ARGV[0], "%d", &plldis); plldis = plldis ? 1 : 0; } command_print(CMD_CTX, "plldis=%d", plldis); return ERROR_OK; } /* ---------------------------------------------------------------------- */ static int tms470_check_flash_unlocked(struct target *target) { uint32_t fmbbusy; target_read_u32(target, 0xFFE89C08, &fmbbusy); LOG_INFO("tms470 fmbbusy = 0x%08" PRIx32 " -> %s", fmbbusy, fmbbusy & 0x8000 ? "unlocked" : "LOCKED"); return fmbbusy & 0x8000 ? ERROR_OK : ERROR_FLASH_OPERATION_FAILED; } /* ---------------------------------------------------------------------- */ static int tms470_try_flash_keys(struct target *target, const uint32_t *key_set) { uint32_t glbctrl, fmmstat; int retval = ERROR_FLASH_OPERATION_FAILED; /* set GLBCTRL.4 */ target_read_u32(target, 0xFFFFFFDC, &glbctrl); target_write_u32(target, 0xFFFFFFDC, glbctrl | 0x10); /* only perform the key match when 3VSTAT is clear */ target_read_u32(target, 0xFFE8BC0C, &fmmstat); if (!(fmmstat & 0x08)) { unsigned i; uint32_t fmbptr, fmbac2, orig_fmregopt; target_write_u32(target, 0xFFE8BC04, fmmstat & ~0x07); /* wait for pump ready */ do { target_read_u32(target, 0xFFE8A814, &fmbptr); alive_sleep(1); } while (!(fmbptr & 0x0200)); /* force max wait states */ target_read_u32(target, 0xFFE88004, &fmbac2); target_write_u32(target, 0xFFE88004, fmbac2 | 0xff); /* save current access mode, force normal read mode */ target_read_u32(target, 0xFFE89C00, &orig_fmregopt); target_write_u32(target, 0xFFE89C00, 0x00); for (i = 0; i < 4; i++) { uint32_t tmp; /* There is no point displaying the value of tmp, it is * filtered by the chip. The purpose of this read is to * prime the unlocking logic rather than read out the value. */ target_read_u32(target, 0x00001FF0 + 4 * i, &tmp); LOG_INFO("tms470 writing fmpkey = 0x%08" PRIx32 "", key_set[i]); target_write_u32(target, 0xFFE89C0C, key_set[i]); } if (ERROR_OK == tms470_check_flash_unlocked(target)) { /* * There seems to be a side-effect of reading the FMPKEY * register in that it re-enables the protection. So we * re-enable it. */ for (i = 0; i < 4; i++) { uint32_t tmp; target_read_u32(target, 0x00001FF0 + 4 * i, &tmp); target_write_u32(target, 0xFFE89C0C, key_set[i]); } retval = ERROR_OK; } /* restore settings */ target_write_u32(target, 0xFFE89C00, orig_fmregopt); target_write_u32(target, 0xFFE88004, fmbac2); } /* clear config bit */ target_write_u32(target, 0xFFFFFFDC, glbctrl); return retval; } /* ---------------------------------------------------------------------- */ static int tms470_unlock_flash(struct flash_bank *bank) { struct target *target = bank->target; const uint32_t *p_key_sets[5]; unsigned i, key_set_count; if (keysSet) { key_set_count = 5; p_key_sets[0] = flashKeys; p_key_sets[1] = FLASH_KEYS_ALL_ONES; p_key_sets[2] = FLASH_KEYS_ALL_ZEROS; p_key_sets[3] = FLASH_KEYS_MIX1; p_key_sets[4] = FLASH_KEYS_MIX2; } else { key_set_count = 4; p_key_sets[0] = FLASH_KEYS_ALL_ONES; p_key_sets[1] = FLASH_KEYS_ALL_ZEROS; p_key_sets[2] = FLASH_KEYS_MIX1; p_key_sets[3] = FLASH_KEYS_MIX2; } for (i = 0; i < key_set_count; i++) { if (tms470_try_flash_keys(target, p_key_sets[i]) == ERROR_OK) { LOG_INFO("tms470 flash is unlocked"); return ERROR_OK; } } LOG_WARNING("tms470 could not unlock flash memory protection level 2"); return ERROR_FLASH_OPERATION_FAILED; } /* ---------------------------------------------------------------------- */ static int tms470_flash_initialize_internal_state_machine(struct flash_bank *bank) { uint32_t fmmac2, fmmac1, fmmaxep, k, delay, glbctrl, sysclk; struct target *target = bank->target; struct tms470_flash_bank *tms470_info = bank->driver_priv; int result = ERROR_OK; /* * Select the desired bank to be programmed by writing BANK[2:0] of * FMMAC2. */ target_read_u32(target, 0xFFE8BC04, &fmmac2); fmmac2 &= ~0x0007; fmmac2 |= (tms470_info->ordinal & 7); target_write_u32(target, 0xFFE8BC04, fmmac2); LOG_DEBUG("set fmmac2 = 0x%04" PRIx32 "", fmmac2); /* * Disable level 1 sector protection by setting bit 15 of FMMAC1. */ target_read_u32(target, 0xFFE8BC00, &fmmac1); fmmac1 |= 0x8000; target_write_u32(target, 0xFFE8BC00, fmmac1); LOG_DEBUG("set fmmac1 = 0x%04" PRIx32 "", fmmac1); /* * FMTCREG = 0x2fc0; */ target_write_u32(target, 0xFFE8BC10, 0x2fc0); LOG_DEBUG("set fmtcreg = 0x2fc0"); /* * MAXPP = 50 */ target_write_u32(target, 0xFFE8A07C, 50); LOG_DEBUG("set fmmaxpp = 50"); /* * MAXCP = 0xf000 + 2000 */ target_write_u32(target, 0xFFE8A084, 0xf000 + 2000); LOG_DEBUG("set fmmaxcp = 0x%04x", 0xf000 + 2000); /* * configure VHV */ target_read_u32(target, 0xFFE8A080, &fmmaxep); if (fmmaxep == 0xf000) { fmmaxep = 0xf000 + 4095; target_write_u32(target, 0xFFE8A80C, 0x9964); LOG_DEBUG("set fmptr3 = 0x9964"); } else { fmmaxep = 0xa000 + 4095; target_write_u32(target, 0xFFE8A80C, 0x9b64); LOG_DEBUG("set fmptr3 = 0x9b64"); } target_write_u32(target, 0xFFE8A080, fmmaxep); LOG_DEBUG("set fmmaxep = 0x%04" PRIx32 "", fmmaxep); /* * FMPTR4 = 0xa000 */ target_write_u32(target, 0xFFE8A810, 0xa000); LOG_DEBUG("set fmptr4 = 0xa000"); /* * FMPESETUP, delay parameter selected based on clock frequency. * * According to the TI App Note SPNU257 and flashing code, delay is * int((sysclk(MHz) + 1) / 2), with a minimum of 5. The system * clock is usually derived from the ZPLL module, and selected by * the plldis global. */ target_read_u32(target, 0xFFFFFFDC, &glbctrl); sysclk = (plldis ? 1 : (glbctrl & 0x08) ? 4 : 8) * oscMHz / (1 + (glbctrl & 7)); delay = (sysclk > 10) ? (sysclk + 1) / 2 : 5; target_write_u32(target, 0xFFE8A018, (delay << 4) | (delay << 8)); LOG_DEBUG("set fmpsetup = 0x%04" PRIx32 "", (delay << 4) | (delay << 8)); /* * FMPVEVACCESS, based on delay. */ k = delay | (delay << 8); target_write_u32(target, 0xFFE8A05C, k); LOG_DEBUG("set fmpvevaccess = 0x%04" PRIx32 "", k); /* * FMPCHOLD, FMPVEVHOLD, FMPVEVSETUP, based on delay. */ k <<= 1; target_write_u32(target, 0xFFE8A034, k); LOG_DEBUG("set fmpchold = 0x%04" PRIx32 "", k); target_write_u32(target, 0xFFE8A040, k); LOG_DEBUG("set fmpvevhold = 0x%04" PRIx32 "", k); target_write_u32(target, 0xFFE8A024, k); LOG_DEBUG("set fmpvevsetup = 0x%04" PRIx32 "", k); /* * FMCVACCESS, based on delay. */ k = delay * 16; target_write_u32(target, 0xFFE8A060, k); LOG_DEBUG("set fmcvaccess = 0x%04" PRIx32 "", k); /* * FMCSETUP, based on delay. */ k = 0x3000 | delay * 20; target_write_u32(target, 0xFFE8A020, k); LOG_DEBUG("set fmcsetup = 0x%04" PRIx32 "", k); /* * FMEHOLD, based on delay. */ k = (delay * 20) << 2; target_write_u32(target, 0xFFE8A038, k); LOG_DEBUG("set fmehold = 0x%04" PRIx32 "", k); /* * PWIDTH, CWIDTH, EWIDTH, based on delay. */ target_write_u32(target, 0xFFE8A050, delay * 8); LOG_DEBUG("set fmpwidth = 0x%04" PRIx32 "", delay * 8); target_write_u32(target, 0xFFE8A058, delay * 1000); LOG_DEBUG("set fmcwidth = 0x%04" PRIx32 "", delay * 1000); target_write_u32(target, 0xFFE8A054, delay * 5400); LOG_DEBUG("set fmewidth = 0x%04" PRIx32 "", delay * 5400); return result; } /* ---------------------------------------------------------------------- */ static int tms470_flash_status(struct flash_bank *bank) { struct target *target = bank->target; int result = ERROR_OK; uint32_t fmmstat; target_read_u32(target, 0xFFE8BC0C, &fmmstat); LOG_DEBUG("set fmmstat = 0x%04" PRIx32 "", fmmstat); if (fmmstat & 0x0080) { LOG_WARNING("tms470 flash command: erase still active after busy clear."); result = ERROR_FLASH_OPERATION_FAILED; } if (fmmstat & 0x0040) { LOG_WARNING("tms470 flash command: program still active after busy clear."); result = ERROR_FLASH_OPERATION_FAILED; } if (fmmstat & 0x0020) { LOG_WARNING("tms470 flash command: invalid data command."); result = ERROR_FLASH_OPERATION_FAILED; } if (fmmstat & 0x0010) { LOG_WARNING("tms470 flash command: program, erase or validate sector failed."); result = ERROR_FLASH_OPERATION_FAILED; } if (fmmstat & 0x0008) { LOG_WARNING("tms470 flash command: voltage instability detected."); result = ERROR_FLASH_OPERATION_FAILED; } if (fmmstat & 0x0006) { LOG_WARNING("tms470 flash command: command suspend detected."); result = ERROR_FLASH_OPERATION_FAILED; } if (fmmstat & 0x0001) { LOG_WARNING("tms470 flash command: sector was locked."); result = ERROR_FLASH_OPERATION_FAILED; } return result; } /* ---------------------------------------------------------------------- */ static int tms470_erase_sector(struct flash_bank *bank, int sector) { uint32_t glbctrl, orig_fmregopt, fmbsea, fmbseb, fmmstat; struct target *target = bank->target; uint32_t flashAddr = bank->base + bank->sectors[sector].offset; int result = ERROR_OK; /* * Set the bit GLBCTRL4 of the GLBCTRL register (in the System * module) to enable writing to the flash registers }. */ target_read_u32(target, 0xFFFFFFDC, &glbctrl); target_write_u32(target, 0xFFFFFFDC, glbctrl | 0x10); LOG_DEBUG("set glbctrl = 0x%08" PRIx32 "", glbctrl | 0x10); /* Force normal read mode. */ target_read_u32(target, 0xFFE89C00, &orig_fmregopt); target_write_u32(target, 0xFFE89C00, 0); LOG_DEBUG("set fmregopt = 0x%08x", 0); (void)tms470_flash_initialize_internal_state_machine(bank); /* * Select one or more bits in FMBSEA or FMBSEB to disable Level 1 * protection for the particular sector to be erased/written. */ if (sector < 16) { target_read_u32(target, 0xFFE88008, &fmbsea); target_write_u32(target, 0xFFE88008, fmbsea | (1 << sector)); LOG_DEBUG("set fmbsea = 0x%04" PRIx32 "", fmbsea | (1 << sector)); } else { target_read_u32(target, 0xFFE8800C, &fmbseb); target_write_u32(target, 0xFFE8800C, fmbseb | (1 << (sector - 16))); LOG_DEBUG("set fmbseb = 0x%04" PRIx32 "", fmbseb | (1 << (sector - 16))); } bank->sectors[sector].is_protected = 0; /* * clear status regiser, sent erase command, kickoff erase */ target_write_u16(target, flashAddr, 0x0040); LOG_DEBUG("write *(uint16_t *)0x%08" PRIx32 "=0x0040", flashAddr); target_write_u16(target, flashAddr, 0x0020); LOG_DEBUG("write *(uint16_t *)0x%08" PRIx32 "=0x0020", flashAddr); target_write_u16(target, flashAddr, 0xffff); LOG_DEBUG("write *(uint16_t *)0x%08" PRIx32 "=0xffff", flashAddr); /* * Monitor FMMSTAT, busy until clear, then check and other flags for * ultimate result of the operation. */ do { target_read_u32(target, 0xFFE8BC0C, &fmmstat); if (fmmstat & 0x0100) alive_sleep(1); } while (fmmstat & 0x0100); result = tms470_flash_status(bank); if (sector < 16) { target_write_u32(target, 0xFFE88008, fmbsea); LOG_DEBUG("set fmbsea = 0x%04" PRIx32 "", fmbsea); bank->sectors[sector].is_protected = fmbsea & (1 << sector) ? 0 : 1; } else { target_write_u32(target, 0xFFE8800C, fmbseb); LOG_DEBUG("set fmbseb = 0x%04" PRIx32 "", fmbseb); bank->sectors[sector].is_protected = fmbseb & (1 << (sector - 16)) ? 0 : 1; } target_write_u32(target, 0xFFE89C00, orig_fmregopt); LOG_DEBUG("set fmregopt = 0x%08" PRIx32 "", orig_fmregopt); target_write_u32(target, 0xFFFFFFDC, glbctrl); LOG_DEBUG("set glbctrl = 0x%08" PRIx32 "", glbctrl); if (result == ERROR_OK) bank->sectors[sector].is_erased = 1; return result; } /*---------------------------------------------------------------------- * Implementation of Flash Driver Interfaces *---------------------------------------------------------------------- */ static const struct command_registration tms470_any_command_handlers[] = { { .name = "flash_keyset", .usage = " ", .handler = tms470_handle_flash_keyset_command, .mode = COMMAND_ANY, .help = "tms470 flash_keyset ", }, { .name = "osc_megahertz", .usage = "", .handler = tms470_handle_osc_megahertz_command, .mode = COMMAND_ANY, .help = "tms470 osc_megahertz ", }, { .name = "plldis", .usage = "<0 | 1>", .handler = tms470_handle_plldis_command, .mode = COMMAND_ANY, .help = "tms470 plldis <0/1>", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration tms470_command_handlers[] = { { .name = "tms470", .mode = COMMAND_ANY, .help = "TI tms470 flash command group", .usage = "", .chain = tms470_any_command_handlers, }, COMMAND_REGISTRATION_DONE }; /* ---------------------------------------------------------------------- */ static int tms470_erase(struct flash_bank *bank, int first, int last) { struct tms470_flash_bank *tms470_info = bank->driver_priv; int sector, result = ERROR_OK; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } tms470_read_part_info(bank); if ((first < 0) || (first >= bank->num_sectors) || (last < 0) || (last >= bank->num_sectors) || (first > last)) { LOG_ERROR("Sector range %d to %d invalid.", first, last); return ERROR_FLASH_SECTOR_INVALID; } result = tms470_unlock_flash(bank); if (result != ERROR_OK) return result; for (sector = first; sector <= last; sector++) { LOG_INFO("Erasing tms470 bank %d sector %d...", tms470_info->ordinal, sector); result = tms470_erase_sector(bank, sector); if (result != ERROR_OK) { LOG_ERROR("tms470 could not erase flash sector."); break; } else LOG_INFO("sector erased successfully."); } return result; } /* ---------------------------------------------------------------------- */ static int tms470_protect(struct flash_bank *bank, int set, int first, int last) { struct tms470_flash_bank *tms470_info = bank->driver_priv; struct target *target = bank->target; uint32_t fmmac2, fmbsea, fmbseb; int sector; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } tms470_read_part_info(bank); if ((first < 0) || (first >= bank->num_sectors) || (last < 0) || (last >= bank->num_sectors) || (first > last)) { LOG_ERROR("Sector range %d to %d invalid.", first, last); return ERROR_FLASH_SECTOR_INVALID; } /* enable the appropriate bank */ target_read_u32(target, 0xFFE8BC04, &fmmac2); target_write_u32(target, 0xFFE8BC04, (fmmac2 & ~7) | tms470_info->ordinal); /* get the original sector proection flags for this bank */ target_read_u32(target, 0xFFE88008, &fmbsea); target_read_u32(target, 0xFFE8800C, &fmbseb); for (sector = 0; sector < bank->num_sectors; sector++) { if (sector < 16) { fmbsea = set ? fmbsea & ~(1 << sector) : fmbsea | (1 << sector); bank->sectors[sector].is_protected = set ? 1 : 0; } else { fmbseb = set ? fmbseb & ~(1 << (sector - 16)) : fmbseb | (1 << (sector - 16)); bank->sectors[sector].is_protected = set ? 1 : 0; } } /* update the protection bits */ target_write_u32(target, 0xFFE88008, fmbsea); target_write_u32(target, 0xFFE8800C, fmbseb); return ERROR_OK; } /* ---------------------------------------------------------------------- */ static int tms470_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t glbctrl, fmbac2, orig_fmregopt, fmbsea, fmbseb, fmmaxpp, fmmstat; int result = ERROR_OK; uint32_t i; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } tms470_read_part_info(bank); LOG_INFO("Writing %" PRId32 " bytes starting at 0x%08" PRIx32 "", count, bank->base + offset); /* set GLBCTRL.4 */ target_read_u32(target, 0xFFFFFFDC, &glbctrl); target_write_u32(target, 0xFFFFFFDC, glbctrl | 0x10); (void)tms470_flash_initialize_internal_state_machine(bank); /* force max wait states */ target_read_u32(target, 0xFFE88004, &fmbac2); target_write_u32(target, 0xFFE88004, fmbac2 | 0xff); /* save current access mode, force normal read mode */ target_read_u32(target, 0xFFE89C00, &orig_fmregopt); target_write_u32(target, 0xFFE89C00, 0x00); /* * Disable Level 1 protection for all sectors to be erased/written. */ target_read_u32(target, 0xFFE88008, &fmbsea); target_write_u32(target, 0xFFE88008, 0xffff); target_read_u32(target, 0xFFE8800C, &fmbseb); target_write_u32(target, 0xFFE8800C, 0xffff); /* read MAXPP */ target_read_u32(target, 0xFFE8A07C, &fmmaxpp); for (i = 0; i < count; i += 2) { uint32_t addr = bank->base + offset + i; uint16_t word = (((uint16_t) buffer[i]) << 8) | (uint16_t) buffer[i + 1]; if (word != 0xffff) { LOG_INFO("writing 0x%04x at 0x%08" PRIx32 "", word, addr); /* clear status register */ target_write_u16(target, addr, 0x0040); /* program flash command */ target_write_u16(target, addr, 0x0010); /* burn the 16-bit word (big-endian) */ target_write_u16(target, addr, word); /* * Monitor FMMSTAT, busy until clear, then check and other flags * for ultimate result of the operation. */ do { target_read_u32(target, 0xFFE8BC0C, &fmmstat); if (fmmstat & 0x0100) alive_sleep(1); } while (fmmstat & 0x0100); if (fmmstat & 0x3ff) { LOG_ERROR("fmstat = 0x%04" PRIx32 "", fmmstat); LOG_ERROR( "Could not program word 0x%04x at address 0x%08" PRIx32 ".", word, addr); result = ERROR_FLASH_OPERATION_FAILED; break; } } else LOG_INFO("skipping 0xffff at 0x%08" PRIx32 "", addr); } /* restore */ target_write_u32(target, 0xFFE88008, fmbsea); target_write_u32(target, 0xFFE8800C, fmbseb); target_write_u32(target, 0xFFE88004, fmbac2); target_write_u32(target, 0xFFE89C00, orig_fmregopt); target_write_u32(target, 0xFFFFFFDC, glbctrl); return result; } /* ---------------------------------------------------------------------- */ static int tms470_probe(struct flash_bank *bank) { if (bank->target->state != TARGET_HALTED) { LOG_WARNING("Cannot communicate... target not halted."); return ERROR_TARGET_NOT_HALTED; } return tms470_read_part_info(bank); } static int tms470_auto_probe(struct flash_bank *bank) { struct tms470_flash_bank *tms470_info = bank->driver_priv; if (tms470_info->device_ident_reg) return ERROR_OK; return tms470_probe(bank); } /* ---------------------------------------------------------------------- */ static int tms470_erase_check(struct flash_bank *bank) { struct target *target = bank->target; struct tms470_flash_bank *tms470_info = bank->driver_priv; int sector, result = ERROR_OK; uint32_t fmmac2, fmbac2, glbctrl, orig_fmregopt; static uint8_t buffer[64 * 1024]; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!tms470_info->device_ident_reg) tms470_read_part_info(bank); /* set GLBCTRL.4 */ target_read_u32(target, 0xFFFFFFDC, &glbctrl); target_write_u32(target, 0xFFFFFFDC, glbctrl | 0x10); /* save current access mode, force normal read mode */ target_read_u32(target, 0xFFE89C00, &orig_fmregopt); target_write_u32(target, 0xFFE89C00, 0x00); /* enable the appropriate bank */ target_read_u32(target, 0xFFE8BC04, &fmmac2); target_write_u32(target, 0xFFE8BC04, (fmmac2 & ~7) | tms470_info->ordinal); /* TCR = 0 */ target_write_u32(target, 0xFFE8BC10, 0x2fc0); /* clear TEZ in fmbrdy */ target_write_u32(target, 0xFFE88010, 0x0b); /* save current wait states, force max */ target_read_u32(target, 0xFFE88004, &fmbac2); target_write_u32(target, 0xFFE88004, fmbac2 | 0xff); /* * The TI primitives inspect the flash memory by reading one 32-bit * word at a time. Here we read an entire sector and inspect it in * an attempt to reduce the JTAG overhead. */ for (sector = 0; sector < bank->num_sectors; sector++) { if (bank->sectors[sector].is_erased != 1) { uint32_t i, addr = bank->base + bank->sectors[sector].offset; LOG_INFO("checking flash bank %d sector %d", tms470_info->ordinal, sector); target_read_buffer(target, addr, bank->sectors[sector].size, buffer); bank->sectors[sector].is_erased = 1; for (i = 0; i < bank->sectors[sector].size; i++) { if (buffer[i] != 0xff) { LOG_WARNING("tms470 bank %d, sector %d, not erased.", tms470_info->ordinal, sector); LOG_WARNING( "at location 0x%08" PRIx32 ": flash data is 0x%02x.", addr + i, buffer[i]); bank->sectors[sector].is_erased = 0; break; } } } if (bank->sectors[sector].is_erased != 1) { result = ERROR_FLASH_SECTOR_NOT_ERASED; break; } else LOG_INFO("sector erased"); } /* reset TEZ, wait states, read mode, GLBCTRL.4 */ target_write_u32(target, 0xFFE88010, 0x0f); target_write_u32(target, 0xFFE88004, fmbac2); target_write_u32(target, 0xFFE89C00, orig_fmregopt); target_write_u32(target, 0xFFFFFFDC, glbctrl); return result; } /* ---------------------------------------------------------------------- */ static int tms470_protect_check(struct flash_bank *bank) { struct target *target = bank->target; struct tms470_flash_bank *tms470_info = bank->driver_priv; int sector, result = ERROR_OK; uint32_t fmmac2, fmbsea, fmbseb; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!tms470_info->device_ident_reg) tms470_read_part_info(bank); /* enable the appropriate bank */ target_read_u32(target, 0xFFE8BC04, &fmmac2); target_write_u32(target, 0xFFE8BC04, (fmmac2 & ~7) | tms470_info->ordinal); target_read_u32(target, 0xFFE88008, &fmbsea); target_read_u32(target, 0xFFE8800C, &fmbseb); for (sector = 0; sector < bank->num_sectors; sector++) { int protected; if (sector < 16) { protected = fmbsea & (1 << sector) ? 0 : 1; bank->sectors[sector].is_protected = protected; } else { protected = fmbseb & (1 << (sector - 16)) ? 0 : 1; bank->sectors[sector].is_protected = protected; } LOG_DEBUG("bank %d sector %d is %s", tms470_info->ordinal, sector, protected ? "protected" : "not protected"); } return result; } /* ---------------------------------------------------------------------- */ static int get_tms470_info(struct flash_bank *bank, char *buf, int buf_size) { int used = 0; struct tms470_flash_bank *tms470_info = bank->driver_priv; if (!tms470_info->device_ident_reg) tms470_read_part_info(bank); if (!tms470_info->device_ident_reg) { (void)snprintf(buf, buf_size, "Cannot identify target as a TMS470\n"); return ERROR_FLASH_OPERATION_FAILED; } used = snprintf(buf, buf_size, "\ntms470 information: Chip is %s\n", tms470_info->part_name); buf += used; buf_size -= used; snprintf(buf, buf_size, "Flash protection level 2 is %s\n", tms470_check_flash_unlocked(bank->target) == ERROR_OK ? "disabled" : "enabled"); return ERROR_OK; } /* ---------------------------------------------------------------------- */ /* * flash bank tms470 * [options...] */ FLASH_BANK_COMMAND_HANDLER(tms470_flash_bank_command) { bank->driver_priv = malloc(sizeof(struct tms470_flash_bank)); if (!bank->driver_priv) return ERROR_FLASH_OPERATION_FAILED; (void)memset(bank->driver_priv, 0, sizeof(struct tms470_flash_bank)); return ERROR_OK; } struct flash_driver tms470_flash = { .name = "tms470", .commands = tms470_command_handlers, .flash_bank_command = tms470_flash_bank_command, .erase = tms470_erase, .protect = tms470_protect, .write = tms470_write, .read = default_flash_read, .probe = tms470_probe, .auto_probe = tms470_auto_probe, .erase_check = tms470_erase_check, .protect_check = tms470_protect_check, .info = get_tms470_info, }; openocd-0.7.0/src/flash/nor/drivers.c0000644000175000001440000000657612134336410014401 00000000000000/*************************************************************************** * Copyright (C) 2009 Zachary T Welch * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" extern struct flash_driver lpc2000_flash; extern struct flash_driver lpc288x_flash; extern struct flash_driver lpc2900_flash; extern struct flash_driver lpcspifi_flash; extern struct flash_driver cfi_flash; extern struct flash_driver at91sam3_flash; extern struct flash_driver at91sam4_flash; extern struct flash_driver at91sam7_flash; extern struct flash_driver str7x_flash; extern struct flash_driver str9x_flash; extern struct flash_driver aduc702x_flash; extern struct flash_driver stellaris_flash; extern struct flash_driver str9xpec_flash; extern struct flash_driver stm32f1x_flash; extern struct flash_driver stm32f2x_flash; extern struct flash_driver stm32lx_flash; extern struct flash_driver tms470_flash; extern struct flash_driver ocl_flash; extern struct flash_driver pic32mx_flash; extern struct flash_driver avr_flash; extern struct flash_driver faux_flash; extern struct flash_driver virtual_flash; extern struct flash_driver stmsmi_flash; extern struct flash_driver em357_flash; extern struct flash_driver dsp5680xx_flash; extern struct flash_driver fm3_flash; extern struct flash_driver kinetis_flash; extern struct flash_driver efm32_flash; /** * The list of built-in flash drivers. * @todo Make this dynamically extendable with loadable modules. */ static struct flash_driver *flash_drivers[] = { &lpc2000_flash, &lpc288x_flash, &lpc2900_flash, &lpcspifi_flash, &cfi_flash, &at91sam7_flash, &at91sam3_flash, &at91sam4_flash, &str7x_flash, &str9x_flash, &aduc702x_flash, &stellaris_flash, &str9xpec_flash, &stm32f1x_flash, &stm32f2x_flash, &stm32lx_flash, &tms470_flash, &ocl_flash, &pic32mx_flash, &avr_flash, &faux_flash, &virtual_flash, &stmsmi_flash, &em357_flash, &fm3_flash, &dsp5680xx_flash, &kinetis_flash, &efm32_flash, NULL, }; struct flash_driver *flash_driver_find_by_name(const char *name) { for (unsigned i = 0; flash_drivers[i]; i++) { if (strcmp(name, flash_drivers[i]->name) == 0) return flash_drivers[i]; } return NULL; } openocd-0.7.0/src/flash/nor/virtual.c0000644000175000001440000001500612134336410014375 00000000000000/*************************************************************************** * Copyright (C) 2010 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" static struct flash_bank *virtual_get_master_bank(struct flash_bank *bank) { struct flash_bank *master_bank; master_bank = get_flash_bank_by_name_noprobe(bank->driver_priv); if (master_bank == NULL) LOG_ERROR("master flash bank '%s' does not exist", (char *)bank->driver_priv); return master_bank; } static void virtual_update_bank_info(struct flash_bank *bank) { struct flash_bank *master_bank = virtual_get_master_bank(bank); if (master_bank == NULL) return; /* update the info we do not have */ bank->size = master_bank->size; bank->chip_width = master_bank->chip_width; bank->bus_width = master_bank->bus_width; bank->num_sectors = master_bank->num_sectors; bank->sectors = master_bank->sectors; } FLASH_BANK_COMMAND_HANDLER(virtual_flash_bank_command) { if (CMD_ARGC < 7) return ERROR_COMMAND_SYNTAX_ERROR; /* get the master flash bank */ const char *bank_name = CMD_ARGV[6]; struct flash_bank *master_bank = get_flash_bank_by_name_noprobe(bank_name); if (master_bank == NULL) { LOG_ERROR("master flash bank '%s' does not exist", bank_name); return ERROR_FLASH_OPERATION_FAILED; } /* save master bank name - use this to get settings later */ bank->driver_priv = strdup(bank_name); return ERROR_OK; } static int virtual_protect(struct flash_bank *bank, int set, int first, int last) { struct flash_bank *master_bank = virtual_get_master_bank(bank); int retval; if (master_bank == NULL) return ERROR_FLASH_OPERATION_FAILED; /* call master handler */ retval = master_bank->driver->protect(master_bank, set, first, last); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int virtual_protect_check(struct flash_bank *bank) { struct flash_bank *master_bank = virtual_get_master_bank(bank); int retval; if (master_bank == NULL) return ERROR_FLASH_OPERATION_FAILED; /* call master handler */ retval = master_bank->driver->protect_check(master_bank); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int virtual_erase(struct flash_bank *bank, int first, int last) { struct flash_bank *master_bank = virtual_get_master_bank(bank); int retval; if (master_bank == NULL) return ERROR_FLASH_OPERATION_FAILED; /* call master handler */ retval = master_bank->driver->erase(master_bank, first, last); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int virtual_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct flash_bank *master_bank = virtual_get_master_bank(bank); int retval; if (master_bank == NULL) return ERROR_FLASH_OPERATION_FAILED; /* call master handler */ retval = master_bank->driver->write(master_bank, buffer, offset, count); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int virtual_probe(struct flash_bank *bank) { struct flash_bank *master_bank = virtual_get_master_bank(bank); int retval; if (master_bank == NULL) return ERROR_FLASH_OPERATION_FAILED; /* call master handler */ retval = master_bank->driver->probe(master_bank); if (retval != ERROR_OK) return retval; /* update the info we do not have */ virtual_update_bank_info(bank); return ERROR_OK; } static int virtual_auto_probe(struct flash_bank *bank) { struct flash_bank *master_bank = virtual_get_master_bank(bank); int retval; if (master_bank == NULL) return ERROR_FLASH_OPERATION_FAILED; /* call master handler */ retval = master_bank->driver->auto_probe(master_bank); if (retval != ERROR_OK) return retval; /* update the info we do not have */ virtual_update_bank_info(bank); return ERROR_OK; } static int virtual_info(struct flash_bank *bank, char *buf, int buf_size) { struct flash_bank *master_bank = virtual_get_master_bank(bank); if (master_bank == NULL) return ERROR_FLASH_OPERATION_FAILED; snprintf(buf, buf_size, "%s driver for flash bank %s at 0x%8.8" PRIx32 "", bank->driver->name, master_bank->name, master_bank->base); return ERROR_OK; } static int virtual_blank_check(struct flash_bank *bank) { struct flash_bank *master_bank = virtual_get_master_bank(bank); int retval; if (master_bank == NULL) return ERROR_FLASH_OPERATION_FAILED; /* call master handler */ retval = master_bank->driver->erase_check(master_bank); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int virtual_flash_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct flash_bank *master_bank = virtual_get_master_bank(bank); int retval; if (master_bank == NULL) return ERROR_FLASH_OPERATION_FAILED; /* call master handler */ retval = master_bank->driver->read(master_bank, buffer, offset, count); if (retval != ERROR_OK) return retval; return ERROR_OK; } struct flash_driver virtual_flash = { .name = "virtual", .flash_bank_command = virtual_flash_bank_command, .erase = virtual_erase, .protect = virtual_protect, .write = virtual_write, .read = virtual_flash_read, .probe = virtual_probe, .auto_probe = virtual_auto_probe, .erase_check = virtual_blank_check, .protect_check = virtual_protect_check, .info = virtual_info, }; openocd-0.7.0/src/flash/nor/lpc2900.c0000644000175000001440000014130712134336410014004 00000000000000/*************************************************************************** * Copyright (C) 2009 by * * Rolf Meeser * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include #include #include #include /* 1024 bytes */ #define KiB 1024 /* Some flash constants */ #define FLASH_PAGE_SIZE 512 /* bytes */ #define FLASH_ERASE_TIME 100000 /* microseconds */ #define FLASH_PROGRAM_TIME 1000 /* microseconds */ /* Chip ID / Feature Registers */ #define CHIPID 0xE0000000 /* Chip ID */ #define FEAT0 0xE0000100 /* Chip feature 0 */ #define FEAT1 0xE0000104 /* Chip feature 1 */ #define FEAT2 0xE0000108 /* Chip feature 2 (contains flash size indicator) */ #define FEAT3 0xE000010C /* Chip feature 3 */ #define EXPECTED_CHIPID 0x209CE02B /* Chip ID of all LPC2900 devices */ /* Flash/EEPROM Control Registers */ #define FCTR 0x20200000 /* Flash control */ #define FPTR 0x20200008 /* Flash program-time */ #define FTCTR 0x2020000C /* Flash test control */ #define FBWST 0x20200010 /* Flash bridge wait-state */ #define FCRA 0x2020001C /* Flash clock divider */ #define FMSSTART 0x20200020 /* Flash Built-In Selft Test start address */ #define FMSSTOP 0x20200024 /* Flash Built-In Selft Test stop address */ #define FMS16 0x20200028 /* Flash 16-bit signature */ #define FMSW0 0x2020002C /* Flash 128-bit signature Word 0 */ #define FMSW1 0x20200030 /* Flash 128-bit signature Word 1 */ #define FMSW2 0x20200034 /* Flash 128-bit signature Word 2 */ #define FMSW3 0x20200038 /* Flash 128-bit signature Word 3 */ #define EECMD 0x20200080 /* EEPROM command */ #define EEADDR 0x20200084 /* EEPROM address */ #define EEWDATA 0x20200088 /* EEPROM write data */ #define EERDATA 0x2020008C /* EEPROM read data */ #define EEWSTATE 0x20200090 /* EEPROM wait state */ #define EECLKDIV 0x20200094 /* EEPROM clock divider */ #define EEPWRDWN 0x20200098 /* EEPROM power-down/start */ #define EEMSSTART 0x2020009C /* EEPROM BIST start address */ #define EEMSSTOP 0x202000A0 /* EEPROM BIST stop address */ #define EEMSSIG 0x202000A4 /* EEPROM 24-bit BIST signature */ #define INT_CLR_ENABLE 0x20200FD8 /* Flash/EEPROM interrupt clear enable */ #define INT_SET_ENABLE 0x20200FDC /* Flash/EEPROM interrupt set enable */ #define INT_STATUS 0x20200FE0 /* Flash/EEPROM interrupt status */ #define INT_ENABLE 0x20200FE4 /* Flash/EEPROM interrupt enable */ #define INT_CLR_STATUS 0x20200FE8 /* Flash/EEPROM interrupt clear status */ #define INT_SET_STATUS 0x20200FEC /* Flash/EEPROM interrupt set status */ /* Interrupt sources */ #define INTSRC_END_OF_PROG (1 << 28) #define INTSRC_END_OF_BIST (1 << 27) #define INTSRC_END_OF_RDWR (1 << 26) #define INTSRC_END_OF_MISR (1 << 2) #define INTSRC_END_OF_BURN (1 << 1) #define INTSRC_END_OF_ERASE (1 << 0) /* FCTR bits */ #define FCTR_FS_LOADREQ (1 << 15) #define FCTR_FS_CACHECLR (1 << 14) #define FCTR_FS_CACHEBYP (1 << 13) #define FCTR_FS_PROGREQ (1 << 12) #define FCTR_FS_RLS (1 << 11) #define FCTR_FS_PDL (1 << 10) #define FCTR_FS_PD (1 << 9) #define FCTR_FS_WPB (1 << 7) #define FCTR_FS_ISS (1 << 6) #define FCTR_FS_RLD (1 << 5) #define FCTR_FS_DCR (1 << 4) #define FCTR_FS_WEB (1 << 2) #define FCTR_FS_WRE (1 << 1) #define FCTR_FS_CS (1 << 0) /* FPTR bits */ #define FPTR_EN_T (1 << 15) /* FTCTR bits */ #define FTCTR_FS_BYPASS_R (1 << 29) #define FTCTR_FS_BYPASS_W (1 << 28) /* FMSSTOP bits */ #define FMSSTOP_MISR_START (1 << 17) /* EEMSSTOP bits */ #define EEMSSTOP_STRTBIST (1 << 31) /* Index sector */ #define ISS_CUSTOMER_START1 (0x830) #define ISS_CUSTOMER_END1 (0xA00) #define ISS_CUSTOMER_SIZE1 (ISS_CUSTOMER_END1 - ISS_CUSTOMER_START1) #define ISS_CUSTOMER_NWORDS1 (ISS_CUSTOMER_SIZE1 / 4) #define ISS_CUSTOMER_START2 (0xA40) #define ISS_CUSTOMER_END2 (0xC00) #define ISS_CUSTOMER_SIZE2 (ISS_CUSTOMER_END2 - ISS_CUSTOMER_START2) #define ISS_CUSTOMER_NWORDS2 (ISS_CUSTOMER_SIZE2 / 4) #define ISS_CUSTOMER_SIZE (ISS_CUSTOMER_SIZE1 + ISS_CUSTOMER_SIZE2) /** * Private data for \c lpc2900 flash driver. */ struct lpc2900_flash_bank { /** * This flag is set when the device has been successfully probed. */ bool is_probed; /** * Holds the value read from CHIPID register. * The driver will not load if the chipid doesn't match the expected * value of 0x209CE02B of the LPC2900 family. A probe will only be done * if the chipid does not yet contain the expected value. */ uint32_t chipid; /** * String holding device name. * This string is set by the probe function to the type number of the * device. It takes the form "LPC29xx". */ char *target_name; /** * System clock frequency. * Holds the clock frequency in Hz, as passed by the configuration file * to the flash bank command. */ uint32_t clk_sys_fmc; /** * Flag to indicate that dangerous operations are possible. * This flag can be set by passing the correct password to the * lpc2900 password command. If set, other dangerous commands, * which operate on the index sector, can be executed. */ uint32_t risky; /** * Maximum contiguous block of internal SRAM (bytes). * Autodetected by the driver. Not the total amount of SRAM, only the * the largest \em contiguous block! */ uint32_t max_ram_block; }; static uint32_t lpc2900_wait_status(struct flash_bank *bank, uint32_t mask, int timeout); static void lpc2900_setup(struct flash_bank *bank); static uint32_t lpc2900_is_ready(struct flash_bank *bank); static uint32_t lpc2900_read_security_status(struct flash_bank *bank); static uint32_t lpc2900_run_bist128(struct flash_bank *bank, uint32_t addr_from, uint32_t addr_to, uint32_t (*signature)[4]); static uint32_t lpc2900_address2sector(struct flash_bank *bank, uint32_t offset); static uint32_t lpc2900_calc_tr(uint32_t clock_var, uint32_t time_var); /*********************** Helper functions **************************/ /** * Wait for an event in mask to occur in INT_STATUS. * * Return when an event occurs, or after a timeout. * * @param[in] bank Pointer to the flash bank descriptor * @param[in] mask Mask to be used for INT_STATUS * @param[in] timeout Timeout in ms */ static uint32_t lpc2900_wait_status(struct flash_bank *bank, uint32_t mask, int timeout) { uint32_t int_status; struct target *target = bank->target; do { alive_sleep(1); timeout--; target_read_u32(target, INT_STATUS, &int_status); } while (((int_status & mask) == 0) && (timeout != 0)); if (timeout == 0) { LOG_DEBUG("Timeout!"); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } /** * Set up the flash for erase/program operations. * * Enable the flash, and set the correct CRA clock of 66 kHz. * * @param bank Pointer to the flash bank descriptor */ static void lpc2900_setup(struct flash_bank *bank) { uint32_t fcra; struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv; /* Power up the flash block */ target_write_u32(bank->target, FCTR, FCTR_FS_WEB | FCTR_FS_CS); fcra = (lpc2900_info->clk_sys_fmc / (3 * 66000)) - 1; target_write_u32(bank->target, FCRA, fcra); } /** * Check if device is ready. * * Check if device is ready for flash operation: * Must have been successfully probed. * Must be halted. */ static uint32_t lpc2900_is_ready(struct flash_bank *bank) { struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv; if (!lpc2900_info->is_probed) return ERROR_FLASH_BANK_NOT_PROBED; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } return ERROR_OK; } /** * Read the status of sector security from the index sector. * * @param bank Pointer to the flash bank descriptor */ static uint32_t lpc2900_read_security_status(struct flash_bank *bank) { uint32_t status = lpc2900_is_ready(bank); if (status != ERROR_OK) return status; struct target *target = bank->target; /* Enable ISS access */ target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB | FCTR_FS_ISS); /* Read the relevant block of memory from the ISS sector */ uint32_t iss_secured_field[0x230/16][4]; target_read_memory(target, bank->base + 0xC00, 4, 0x230/4, (uint8_t *)iss_secured_field); /* Disable ISS access */ target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB); /* Check status of each sector. Note that the sector numbering in the LPC2900 * is different from the logical sector numbers used in OpenOCD! * Refer to the user manual for details. * * All zeros (16x 0x00) are treated as a secured sector (is_protected = 1) * All ones (16x 0xFF) are treated as a non-secured sector (is_protected = 0) * Anything else is undefined (is_protected = -1). This is treated as * a protected sector! */ int sector; int index_t; for (sector = 0; sector < bank->num_sectors; sector++) { /* Convert logical sector number to physical sector number */ if (sector <= 4) index_t = sector + 11; else if (sector <= 7) index_t = sector + 27; else index_t = sector - 8; bank->sectors[sector].is_protected = -1; if ((iss_secured_field[index_t][0] == 0x00000000) && (iss_secured_field[index_t][1] == 0x00000000) && (iss_secured_field[index_t][2] == 0x00000000) && (iss_secured_field[index_t][3] == 0x00000000)) bank->sectors[sector].is_protected = 1; if ((iss_secured_field[index_t][0] == 0xFFFFFFFF) && (iss_secured_field[index_t][1] == 0xFFFFFFFF) && (iss_secured_field[index_t][2] == 0xFFFFFFFF) && (iss_secured_field[index_t][3] == 0xFFFFFFFF)) bank->sectors[sector].is_protected = 0; } return ERROR_OK; } /** * Use BIST to calculate a 128-bit hash value over a range of flash. * * @param bank Pointer to the flash bank descriptor * @param addr_from * @param addr_to * @param signature */ static uint32_t lpc2900_run_bist128(struct flash_bank *bank, uint32_t addr_from, uint32_t addr_to, uint32_t (*signature)[4]) { struct target *target = bank->target; /* Clear END_OF_MISR interrupt status */ target_write_u32(target, INT_CLR_STATUS, INTSRC_END_OF_MISR); /* Start address */ target_write_u32(target, FMSSTART, addr_from >> 4); /* End address, and issue start command */ target_write_u32(target, FMSSTOP, (addr_to >> 4) | FMSSTOP_MISR_START); /* Poll for end of operation. Calculate a reasonable timeout. */ if (lpc2900_wait_status(bank, INTSRC_END_OF_MISR, 1000) != ERROR_OK) return ERROR_FLASH_OPERATION_FAILED; /* Return the signature */ target_read_memory(target, FMSW0, 4, 4, (uint8_t *)signature); return ERROR_OK; } /** * Return sector number for given address. * * Return the (logical) sector number for a given relative address. * No sanity check is done. It assumed that the address is valid. * * @param bank Pointer to the flash bank descriptor * @param offset Offset address relative to bank start */ static uint32_t lpc2900_address2sector(struct flash_bank *bank, uint32_t offset) { uint32_t address = bank->base + offset; /* Run through all sectors of this bank */ int sector; for (sector = 0; sector < bank->num_sectors; sector++) { /* Return immediately if address is within the current sector */ if (address < (bank->sectors[sector].offset + bank->sectors[sector].size)) return sector; } /* We should never come here. If we do, return an arbitrary sector number. */ return 0; } /** * Write one page to the index sector. * * @param bank Pointer to the flash bank descriptor * @param pagenum Page number (0...7) * @param page Page array (FLASH_PAGE_SIZE bytes) */ static int lpc2900_write_index_page(struct flash_bank *bank, int pagenum, uint8_t (*page)[FLASH_PAGE_SIZE]) { /* Only pages 4...7 are user writable */ if ((pagenum < 4) || (pagenum > 7)) { LOG_ERROR("Refuse to burn index sector page %d", pagenum); return ERROR_COMMAND_ARGUMENT_INVALID; } /* Get target, and check if it's halted */ struct target *target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Private info */ struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv; /* Enable flash block and set the correct CRA clock of 66 kHz */ lpc2900_setup(bank); /* Un-protect the index sector */ target_write_u32(target, bank->base, 0); target_write_u32(target, FCTR, FCTR_FS_LOADREQ | FCTR_FS_WPB | FCTR_FS_ISS | FCTR_FS_WEB | FCTR_FS_WRE | FCTR_FS_CS); /* Set latch load mode */ target_write_u32(target, FCTR, FCTR_FS_ISS | FCTR_FS_WEB | FCTR_FS_WRE | FCTR_FS_CS); /* Write whole page to flash data latches */ if (target_write_memory(target, bank->base + pagenum * FLASH_PAGE_SIZE, 4, FLASH_PAGE_SIZE / 4, (uint8_t *)page) != ERROR_OK) { LOG_ERROR("Index sector write failed @ page %d", pagenum); target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB); return ERROR_FLASH_OPERATION_FAILED; } /* Clear END_OF_BURN interrupt status */ target_write_u32(target, INT_CLR_STATUS, INTSRC_END_OF_BURN); /* Set the program/erase time to FLASH_PROGRAM_TIME */ target_write_u32(target, FPTR, FPTR_EN_T | lpc2900_calc_tr(lpc2900_info->clk_sys_fmc, FLASH_PROGRAM_TIME)); /* Trigger flash write */ target_write_u32(target, FCTR, FCTR_FS_PROGREQ | FCTR_FS_ISS | FCTR_FS_WPB | FCTR_FS_WRE | FCTR_FS_CS); /* Wait for the end of the write operation. If it's not over after one * second, something went dreadfully wrong... :-( */ if (lpc2900_wait_status(bank, INTSRC_END_OF_BURN, 1000) != ERROR_OK) { LOG_ERROR("Index sector write failed @ page %d", pagenum); target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB); return ERROR_FLASH_OPERATION_FAILED; } target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB); return ERROR_OK; } /** * Calculate FPTR.TR register value for desired program/erase time. * * @param clock System clock in Hz * @param time Program/erase time in µs */ static uint32_t lpc2900_calc_tr(uint32_t clock_var, uint32_t time_var) { /* ((time[µs]/1e6) * f[Hz]) + 511 * FPTR.TR = ------------------------------- * 512 */ uint32_t tr_val = (uint32_t)((((time_var / 1e6) * clock_var) + 511.0) / 512.0); return tr_val; } /*********************** Private flash commands **************************/ /** * Command to determine the signature of the whole flash. * * Uses the Built-In-Self-Test (BIST) to generate a 128-bit hash value * of the flash content. */ COMMAND_HANDLER(lpc2900_handle_signature_command) { uint32_t status; uint32_t signature[4]; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Run BIST over whole flash range */ status = lpc2900_run_bist128(bank, bank->base, bank->base + (bank->size - 1), &signature); if (status != ERROR_OK) return status; command_print(CMD_CTX, "signature: 0x%8.8" PRIx32 ":0x%8.8" PRIx32 ":0x%8.8" PRIx32 ":0x%8.8" PRIx32, signature[3], signature[2], signature[1], signature[0]); return ERROR_OK; } /** * Store customer info in file. * * Read customer info from index sector, and store that block of data into * a disk file. The format is binary. */ COMMAND_HANDLER(lpc2900_handle_read_custom_command) { if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv; lpc2900_info->risky = 0; /* Get target, and check if it's halted */ struct target *target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Storage for customer info. Read in two parts */ uint32_t customer[ISS_CUSTOMER_NWORDS1 + ISS_CUSTOMER_NWORDS2]; /* Enable access to index sector */ target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB | FCTR_FS_ISS); /* Read two parts */ target_read_memory(target, bank->base+ISS_CUSTOMER_START1, 4, ISS_CUSTOMER_NWORDS1, (uint8_t *)&customer[0]); target_read_memory(target, bank->base+ISS_CUSTOMER_START2, 4, ISS_CUSTOMER_NWORDS2, (uint8_t *)&customer[ISS_CUSTOMER_NWORDS1]); /* Deactivate access to index sector */ target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB); /* Try and open the file */ struct fileio fileio; const char *filename = CMD_ARGV[1]; int ret = fileio_open(&fileio, filename, FILEIO_WRITE, FILEIO_BINARY); if (ret != ERROR_OK) { LOG_WARNING("Could not open file %s", filename); return ret; } size_t nwritten; ret = fileio_write(&fileio, sizeof(customer), (const uint8_t *)customer, &nwritten); if (ret != ERROR_OK) { LOG_ERROR("Write operation to file %s failed", filename); fileio_close(&fileio); return ret; } fileio_close(&fileio); return ERROR_OK; } /** * Enter password to enable potentially dangerous options. */ COMMAND_HANDLER(lpc2900_handle_password_command) { if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv; #define ISS_PASSWORD "I_know_what_I_am_doing" lpc2900_info->risky = !strcmp(CMD_ARGV[1], ISS_PASSWORD); if (!lpc2900_info->risky) { command_print(CMD_CTX, "Wrong password (use '%s')", ISS_PASSWORD); return ERROR_COMMAND_ARGUMENT_INVALID; } command_print(CMD_CTX, "Potentially dangerous operation allowed in next command!"); return ERROR_OK; } /** * Write customer info from file to the index sector. */ COMMAND_HANDLER(lpc2900_handle_write_custom_command) { if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv; /* Check if command execution is allowed. */ if (!lpc2900_info->risky) { command_print(CMD_CTX, "Command execution not allowed!"); return ERROR_COMMAND_ARGUMENT_INVALID; } lpc2900_info->risky = 0; /* Get target, and check if it's halted */ struct target *target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* The image will always start at offset 0 */ struct image image; image.base_address_set = 1; image.base_address = 0; image.start_address_set = 0; const char *filename = CMD_ARGV[1]; const char *type = (CMD_ARGC >= 3) ? CMD_ARGV[2] : NULL; retval = image_open(&image, filename, type); if (retval != ERROR_OK) return retval; /* Do a sanity check: The image must be exactly the size of the customer programmable area. Any other size is rejected. */ if (image.num_sections != 1) { LOG_ERROR("Only one section allowed in image file."); return ERROR_COMMAND_SYNTAX_ERROR; } if ((image.sections[0].base_address != 0) || (image.sections[0].size != ISS_CUSTOMER_SIZE)) { LOG_ERROR("Incorrect image file size. Expected %d, " "got %" PRIu32, ISS_CUSTOMER_SIZE, image.sections[0].size); return ERROR_COMMAND_SYNTAX_ERROR; } /* Well boys, I reckon this is it... */ /* Customer info is split into two blocks in pages 4 and 5. */ uint8_t page[FLASH_PAGE_SIZE]; /* Page 4 */ uint32_t offset = ISS_CUSTOMER_START1 % FLASH_PAGE_SIZE; memset(page, 0xff, FLASH_PAGE_SIZE); size_t size_read; retval = image_read_section(&image, 0, 0, ISS_CUSTOMER_SIZE1, &page[offset], &size_read); if (retval != ERROR_OK) { LOG_ERROR("couldn't read from file '%s'", filename); image_close(&image); return retval; } retval = lpc2900_write_index_page(bank, 4, &page); if (retval != ERROR_OK) { image_close(&image); return retval; } /* Page 5 */ offset = ISS_CUSTOMER_START2 % FLASH_PAGE_SIZE; memset(page, 0xff, FLASH_PAGE_SIZE); retval = image_read_section(&image, 0, ISS_CUSTOMER_SIZE1, ISS_CUSTOMER_SIZE2, &page[offset], &size_read); if (retval != ERROR_OK) { LOG_ERROR("couldn't read from file '%s'", filename); image_close(&image); return retval; } retval = lpc2900_write_index_page(bank, 5, &page); if (retval != ERROR_OK) { image_close(&image); return retval; } image_close(&image); return ERROR_OK; } /** * Activate 'sector security' for a range of sectors. */ COMMAND_HANDLER(lpc2900_handle_secure_sector_command) { if (CMD_ARGC < 3) return ERROR_COMMAND_SYNTAX_ERROR; /* Get the bank descriptor */ struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv; /* Check if command execution is allowed. */ if (!lpc2900_info->risky) { command_print(CMD_CTX, "Command execution not allowed! " "(use 'password' command first)"); return ERROR_COMMAND_ARGUMENT_INVALID; } lpc2900_info->risky = 0; /* Read sector range, and do a sanity check. */ int first, last; COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], first); COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], last); if ((first >= bank->num_sectors) || (last >= bank->num_sectors) || (first > last)) { command_print(CMD_CTX, "Illegal sector range"); return ERROR_COMMAND_ARGUMENT_INVALID; } uint8_t page[FLASH_PAGE_SIZE]; int sector; /* Sectors in page 6 */ if ((first <= 4) || (last >= 8)) { memset(&page, 0xff, FLASH_PAGE_SIZE); for (sector = first; sector <= last; sector++) { if (sector <= 4) memset(&page[0xB0 + 16*sector], 0, 16); else if (sector >= 8) memset(&page[0x00 + 16*(sector - 8)], 0, 16); } retval = lpc2900_write_index_page(bank, 6, &page); if (retval != ERROR_OK) { LOG_ERROR("failed to update index sector page 6"); return retval; } } /* Sectors in page 7 */ if ((first <= 7) && (last >= 5)) { memset(&page, 0xff, FLASH_PAGE_SIZE); for (sector = first; sector <= last; sector++) { if ((sector >= 5) && (sector <= 7)) memset(&page[0x00 + 16*(sector - 5)], 0, 16); } retval = lpc2900_write_index_page(bank, 7, &page); if (retval != ERROR_OK) { LOG_ERROR("failed to update index sector page 7"); return retval; } } command_print(CMD_CTX, "Sectors security will become effective after next power cycle"); /* Update the sector security status */ if (lpc2900_read_security_status(bank) != ERROR_OK) { LOG_ERROR("Cannot determine sector security status"); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } /** * Activate JTAG protection. */ COMMAND_HANDLER(lpc2900_handle_secure_jtag_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; /* Get the bank descriptor */ struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv; /* Check if command execution is allowed. */ if (!lpc2900_info->risky) { command_print(CMD_CTX, "Command execution not allowed! " "(use 'password' command first)"); return ERROR_COMMAND_ARGUMENT_INVALID; } lpc2900_info->risky = 0; /* Prepare page */ uint8_t page[FLASH_PAGE_SIZE]; memset(&page, 0xff, FLASH_PAGE_SIZE); /* Insert "soft" protection word */ page[0x30 + 15] = 0x7F; page[0x30 + 11] = 0x7F; page[0x30 + 7] = 0x7F; page[0x30 + 3] = 0x7F; /* Write to page 5 */ retval = lpc2900_write_index_page(bank, 5, &page); if (retval != ERROR_OK) { LOG_ERROR("failed to update index sector page 5"); return retval; } LOG_INFO("JTAG security set. Good bye!"); return ERROR_OK; } /*********************** Flash interface functions **************************/ static const struct command_registration lpc2900_exec_command_handlers[] = { { .name = "signature", .usage = "", .handler = lpc2900_handle_signature_command, .mode = COMMAND_EXEC, .help = "Calculate and display signature of flash bank.", }, { .name = "read_custom", .handler = lpc2900_handle_read_custom_command, .mode = COMMAND_EXEC, .usage = "bank_id filename", .help = "Copies 912 bytes of customer information " "from index sector into file.", }, { .name = "password", .handler = lpc2900_handle_password_command, .mode = COMMAND_EXEC, .usage = "bank_id password", .help = "Enter fixed password to enable 'dangerous' options.", }, { .name = "write_custom", .handler = lpc2900_handle_write_custom_command, .mode = COMMAND_EXEC, .usage = "bank_id filename ('bin'|'ihex'|'elf'|'s19')", .help = "Copies 912 bytes of customer info from file " "to index sector.", }, { .name = "secure_sector", .handler = lpc2900_handle_secure_sector_command, .mode = COMMAND_EXEC, .usage = "bank_id first_sector last_sector", .help = "Activate sector security for a range of sectors. " "It will be effective after a power cycle.", }, { .name = "secure_jtag", .handler = lpc2900_handle_secure_jtag_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Disable the JTAG port. " "It will be effective after a power cycle.", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration lpc2900_command_handlers[] = { { .name = "lpc2900", .mode = COMMAND_ANY, .help = "LPC2900 flash command group", .usage = "", .chain = lpc2900_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; /** Evaluate flash bank command. */ FLASH_BANK_COMMAND_HANDLER(lpc2900_flash_bank_command) { struct lpc2900_flash_bank *lpc2900_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; lpc2900_info = malloc(sizeof(struct lpc2900_flash_bank)); bank->driver_priv = lpc2900_info; /* Get flash clock. * Reject it if we can't meet the requirements for program time * (if clock too slow), or for erase time (clock too fast). */ uint32_t clk_sys_fmc; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], clk_sys_fmc); lpc2900_info->clk_sys_fmc = clk_sys_fmc * 1000; uint32_t clock_limit; /* Check program time limit */ clock_limit = 512000000l / FLASH_PROGRAM_TIME; if (lpc2900_info->clk_sys_fmc < clock_limit) { LOG_WARNING("flash clock must be at least %" PRIu32 " kHz", (clock_limit / 1000)); return ERROR_FLASH_BANK_INVALID; } /* Check erase time limit */ clock_limit = (uint32_t)((32767.0 * 512.0 * 1e6) / FLASH_ERASE_TIME); if (lpc2900_info->clk_sys_fmc > clock_limit) { LOG_WARNING("flash clock must be a maximum of %" PRIu32 " kHz", (clock_limit / 1000)); return ERROR_FLASH_BANK_INVALID; } /* Chip ID will be obtained by probing the device later */ lpc2900_info->chipid = 0; lpc2900_info->is_probed = false; return ERROR_OK; } /** * Erase sector(s). * * @param bank Pointer to the flash bank descriptor * @param first First sector to be erased * @param last Last sector (including) to be erased */ static int lpc2900_erase(struct flash_bank *bank, int first, int last) { uint32_t status; int sector; int last_unsecured_sector; struct target *target = bank->target; struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv; status = lpc2900_is_ready(bank); if (status != ERROR_OK) return status; /* Sanity check on sector range */ if ((first < 0) || (last < first) || (last >= bank->num_sectors)) { LOG_INFO("Bad sector range"); return ERROR_FLASH_SECTOR_INVALID; } /* Update the info about secured sectors */ lpc2900_read_security_status(bank); /* The selected sector range might include secured sectors. An attempt * to erase such a sector will cause the erase to fail also for unsecured * sectors. It is necessary to determine the last unsecured sector now, * because we have to treat the last relevant sector in the list in * a special way. */ last_unsecured_sector = -1; for (sector = first; sector <= last; sector++) { if (!bank->sectors[sector].is_protected) last_unsecured_sector = sector; } /* Exit now, in case of the rare constellation where all sectors in range * are secured. This is regarded a success, since erasing/programming of * secured sectors shall be handled transparently. */ if (last_unsecured_sector == -1) return ERROR_OK; /* Enable flash block and set the correct CRA clock of 66 kHz */ lpc2900_setup(bank); /* Clear END_OF_ERASE interrupt status */ target_write_u32(target, INT_CLR_STATUS, INTSRC_END_OF_ERASE); /* Set the program/erase timer to FLASH_ERASE_TIME */ target_write_u32(target, FPTR, FPTR_EN_T | lpc2900_calc_tr(lpc2900_info->clk_sys_fmc, FLASH_ERASE_TIME)); /* Sectors are marked for erasure, then erased all together */ for (sector = first; sector <= last_unsecured_sector; sector++) { /* Only mark sectors that aren't secured. Any attempt to erase a group * of sectors will fail if any single one of them is secured! */ if (!bank->sectors[sector].is_protected) { /* Unprotect the sector */ target_write_u32(target, bank->sectors[sector].offset, 0); target_write_u32(target, FCTR, FCTR_FS_LOADREQ | FCTR_FS_WPB | FCTR_FS_WEB | FCTR_FS_WRE | FCTR_FS_CS); /* Mark the sector for erasure. The last sector in the list triggers the erasure. */ target_write_u32(target, bank->sectors[sector].offset, 0); if (sector == last_unsecured_sector) { target_write_u32(target, FCTR, FCTR_FS_PROGREQ | FCTR_FS_WPB | FCTR_FS_CS); } else { target_write_u32(target, FCTR, FCTR_FS_LOADREQ | FCTR_FS_WPB | FCTR_FS_WEB | FCTR_FS_CS); } } } /* Wait for the end of the erase operation. If it's not over after two seconds, * something went dreadfully wrong... :-( */ if (lpc2900_wait_status(bank, INTSRC_END_OF_ERASE, 2000) != ERROR_OK) return ERROR_FLASH_OPERATION_FAILED; /* Normal flash operating mode */ target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB); return ERROR_OK; } static int lpc2900_protect(struct flash_bank *bank, int set, int first, int last) { /* This command is not supported. * "Protection" in LPC2900 terms is handled transparently. Sectors will * automatically be unprotected as needed. * Instead we use the concept of sector security. A secured sector is shown * as "protected" in OpenOCD. Sector security is a permanent feature, and * cannot be disabled once activated. */ return ERROR_OK; } /** * Write data to flash. * * @param bank Pointer to the flash bank descriptor * @param buffer Buffer with data * @param offset Start address (relative to bank start) * @param count Number of bytes to be programmed */ static int lpc2900_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { uint8_t page[FLASH_PAGE_SIZE]; uint32_t status; uint32_t num_bytes; struct target *target = bank->target; struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv; int sector; int retval; static const uint32_t write_target_code[] = { /* Set auto latch mode: FCTR=CS|WRE|WEB */ 0xe3a0a007, /* loop mov r10, #0x007 */ 0xe583a000, /* str r10,[r3,#0] */ /* Load complete page into latches */ 0xe3a06020, /* mov r6,#(512/16) */ 0xe8b00f00, /* next ldmia r0!,{r8-r11} */ 0xe8a10f00, /* stmia r1!,{r8-r11} */ 0xe2566001, /* subs r6,#1 */ 0x1afffffb, /* bne next */ /* Clear END_OF_BURN interrupt status */ 0xe3a0a002, /* mov r10,#(1 << 1) */ 0xe583afe8, /* str r10,[r3,#0xfe8] */ /* Set the erase time to FLASH_PROGRAM_TIME */ 0xe5834008, /* str r4,[r3,#8] */ /* Trigger flash write * FCTR = CS | WRE | WPB | PROGREQ */ 0xe3a0a083, /* mov r10,#0x83 */ 0xe38aaa01, /* orr r10,#0x1000 */ 0xe583a000, /* str r10,[r3,#0] */ /* Wait for end of burn */ 0xe593afe0, /* wait ldr r10,[r3,#0xfe0] */ 0xe21aa002, /* ands r10,#(1 << 1) */ 0x0afffffc, /* beq wait */ /* End? */ 0xe2522001, /* subs r2,#1 */ 0x1affffed, /* bne loop */ 0xeafffffe /* done b done */ }; status = lpc2900_is_ready(bank); if (status != ERROR_OK) return status; /* Enable flash block and set the correct CRA clock of 66 kHz */ lpc2900_setup(bank); /* Update the info about secured sectors */ lpc2900_read_security_status(bank); /* Unprotect all involved sectors */ for (sector = 0; sector < bank->num_sectors; sector++) { /* Start address in or before this sector? * End address in or behind this sector? */ if (((bank->base + offset) < (bank->sectors[sector].offset + bank->sectors[sector].size)) && ((bank->base + (offset + count - 1)) >= bank->sectors[sector].offset)) { /* This sector is involved and needs to be unprotected. * Don't do it for secured sectors. */ if (!bank->sectors[sector].is_protected) { target_write_u32(target, bank->sectors[sector].offset, 0); target_write_u32(target, FCTR, FCTR_FS_LOADREQ | FCTR_FS_WPB | FCTR_FS_WEB | FCTR_FS_WRE | FCTR_FS_CS); } } } /* Set the program/erase time to FLASH_PROGRAM_TIME */ uint32_t prog_time = FPTR_EN_T | lpc2900_calc_tr(lpc2900_info->clk_sys_fmc, FLASH_PROGRAM_TIME); /* If there is a working area of reasonable size, use it to program via * a target algorithm. If not, fall back to host programming. */ /* We need some room for target code. */ uint32_t target_code_size = sizeof(write_target_code); /* Try working area allocation. Start with a large buffer, and try with * reduced size if that fails. */ struct working_area *warea; uint32_t buffer_size = lpc2900_info->max_ram_block - 1 * KiB; while ((retval = target_alloc_working_area_try(target, buffer_size + target_code_size, &warea)) != ERROR_OK) { /* Try a smaller buffer now, and stop if it's too small. */ buffer_size -= 1 * KiB; if (buffer_size < 2 * KiB) { LOG_INFO("no (large enough) working area, falling back to host mode"); warea = NULL; break; } } ; if (warea) { struct reg_param reg_params[5]; struct arm_algorithm arm_algo; /* We can use target mode. Download the algorithm. */ retval = target_write_buffer(target, (warea->address)+buffer_size, target_code_size, (uint8_t *)write_target_code); if (retval != ERROR_OK) { LOG_ERROR("Unable to write block write code to target"); target_free_all_working_areas(target); return ERROR_FLASH_OPERATION_FAILED; } init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_OUT); init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* Write to flash in large blocks */ while (count != 0) { uint32_t this_npages; uint8_t *this_buffer; int start_sector = lpc2900_address2sector(bank, offset); /* First page / last page / rest */ if (offset % FLASH_PAGE_SIZE) { /* Block doesn't start on page boundary. * Burn first partial page separately. */ memset(&page, 0xff, sizeof(page)); memcpy(&page[offset % FLASH_PAGE_SIZE], buffer, FLASH_PAGE_SIZE - (offset % FLASH_PAGE_SIZE)); this_npages = 1; this_buffer = &page[0]; count = count + (offset % FLASH_PAGE_SIZE); offset = offset - (offset % FLASH_PAGE_SIZE); } else if (count < FLASH_PAGE_SIZE) { /* Download last incomplete page separately. */ memset(&page, 0xff, sizeof(page)); memcpy(&page, buffer, count); this_npages = 1; this_buffer = &page[0]; count = FLASH_PAGE_SIZE; } else { /* Download as many full pages as possible */ this_npages = (count < buffer_size) ? count / FLASH_PAGE_SIZE : buffer_size / FLASH_PAGE_SIZE; this_buffer = buffer; /* Make sure we stop at the next secured sector */ sector = start_sector + 1; while (sector < bank->num_sectors) { /* Secured? */ if (bank->sectors[sector].is_protected) { /* Is that next sector within the current block? */ if ((bank->sectors[sector].offset - bank->base) < (offset + (this_npages * FLASH_PAGE_SIZE))) { /* Yes! Split the block */ this_npages = (bank->sectors[sector].offset - bank->base - offset) / FLASH_PAGE_SIZE; break; } } sector++; } } /* Skip the current sector if it is secured */ if (bank->sectors[start_sector].is_protected) { LOG_DEBUG("Skip secured sector %d", start_sector); /* Stop if this is the last sector */ if (start_sector == bank->num_sectors - 1) break; /* Skip */ uint32_t nskip = bank->sectors[start_sector].size - (offset % bank->sectors[start_sector].size); offset += nskip; buffer += nskip; count = (count >= nskip) ? (count - nskip) : 0; continue; } /* Execute buffer download */ retval = target_write_buffer(target, warea->address, this_npages * FLASH_PAGE_SIZE, this_buffer); if (retval != ERROR_OK) { LOG_ERROR("Unable to write data to target"); target_free_all_working_areas(target); return ERROR_FLASH_OPERATION_FAILED; } /* Prepare registers */ buf_set_u32(reg_params[0].value, 0, 32, warea->address); buf_set_u32(reg_params[1].value, 0, 32, offset); buf_set_u32(reg_params[2].value, 0, 32, this_npages); buf_set_u32(reg_params[3].value, 0, 32, FCTR); buf_set_u32(reg_params[4].value, 0, 32, FPTR_EN_T | prog_time); /* Execute algorithm, assume breakpoint for last instruction */ arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; retval = target_run_algorithm(target, 0, NULL, 5, reg_params, (warea->address) + buffer_size, (warea->address) + buffer_size + target_code_size - 4, 10000, /* 10s should be enough for max. 16 KiB of data */ &arm_algo); if (retval != ERROR_OK) { LOG_ERROR("Execution of flash algorithm failed."); target_free_all_working_areas(target); retval = ERROR_FLASH_OPERATION_FAILED; break; } count -= this_npages * FLASH_PAGE_SIZE; buffer += this_npages * FLASH_PAGE_SIZE; offset += this_npages * FLASH_PAGE_SIZE; } /* Free all resources */ destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); target_free_all_working_areas(target); } else { /* Write to flash memory page-wise */ while (count != 0) { /* How many bytes do we copy this time? */ num_bytes = (count >= FLASH_PAGE_SIZE) ? FLASH_PAGE_SIZE - (offset % FLASH_PAGE_SIZE) : count; /* Don't do anything with it if the page is in a secured sector. */ if (!bank->sectors[lpc2900_address2sector(bank, offset)].is_protected) { /* Set latch load mode */ target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WRE | FCTR_FS_WEB); /* Always clear the buffer (a little overhead, but who cares) */ memset(page, 0xFF, FLASH_PAGE_SIZE); /* Copy them to the buffer */ memcpy(&page[offset % FLASH_PAGE_SIZE], &buffer[offset % FLASH_PAGE_SIZE], num_bytes); /* Write whole page to flash data latches */ if (target_write_memory(target, bank->base + (offset - (offset % FLASH_PAGE_SIZE)), 4, FLASH_PAGE_SIZE / 4, page) != ERROR_OK) { LOG_ERROR("Write failed @ 0x%8.8" PRIx32, offset); target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB); return ERROR_FLASH_OPERATION_FAILED; } /* Clear END_OF_BURN interrupt status */ target_write_u32(target, INT_CLR_STATUS, INTSRC_END_OF_BURN); /* Set the programming time */ target_write_u32(target, FPTR, FPTR_EN_T | prog_time); /* Trigger flash write */ target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WRE | FCTR_FS_WPB | FCTR_FS_PROGREQ); /* Wait for the end of the write operation. If it's not over * after one second, something went dreadfully wrong... :-( */ if (lpc2900_wait_status(bank, INTSRC_END_OF_BURN, 1000) != ERROR_OK) { LOG_ERROR("Write failed @ 0x%8.8" PRIx32, offset); target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB); return ERROR_FLASH_OPERATION_FAILED; } } /* Update pointers and counters */ offset += num_bytes; buffer += num_bytes; count -= num_bytes; } retval = ERROR_OK; } /* Normal flash operating mode */ target_write_u32(target, FCTR, FCTR_FS_CS | FCTR_FS_WEB); return retval; } /** * Try and identify the device. * * Determine type number and its memory layout. * * @param bank Pointer to the flash bank descriptor */ static int lpc2900_probe(struct flash_bank *bank) { struct lpc2900_flash_bank *lpc2900_info = bank->driver_priv; struct target *target = bank->target; int i = 0; uint32_t offset; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* We want to do this only once. */ if (lpc2900_info->is_probed) return ERROR_OK; /* Probing starts with reading the CHIPID register. We will continue only * if this identifies as an LPC2900 device. */ target_read_u32(target, CHIPID, &lpc2900_info->chipid); if (lpc2900_info->chipid != EXPECTED_CHIPID) { LOG_WARNING("Device is not an LPC29xx"); return ERROR_FLASH_OPERATION_FAILED; } /* It's an LPC29xx device. Now read the feature register FEAT0...FEAT3. */ uint32_t feat0, feat1, feat2, feat3; target_read_u32(target, FEAT0, &feat0); target_read_u32(target, FEAT1, &feat1); target_read_u32(target, FEAT2, &feat2); target_read_u32(target, FEAT3, &feat3); /* Base address */ bank->base = 0x20000000; /* Determine flash layout from FEAT2 register */ uint32_t num_64k_sectors = (feat2 >> 16) & 0xFF; uint32_t num_8k_sectors = (feat2 >> 0) & 0xFF; bank->num_sectors = num_64k_sectors + num_8k_sectors; bank->size = KiB * (64 * num_64k_sectors + 8 * num_8k_sectors); /* Determine maximum contiguous RAM block */ lpc2900_info->max_ram_block = 16 * KiB; if ((feat1 & 0x30) == 0x30) { lpc2900_info->max_ram_block = 32 * KiB; if ((feat1 & 0x0C) == 0x0C) lpc2900_info->max_ram_block = 48 * KiB; } /* Determine package code and ITCM size */ uint32_t package_code = feat0 & 0x0F; uint32_t itcm_code = (feat1 >> 16) & 0x1F; /* Determine the exact type number. */ uint32_t found = 1; if ((package_code == 4) && (itcm_code == 5)) { /* Old LPC2917 or LPC2919 (non-/01 devices) */ lpc2900_info->target_name = (bank->size == 768*KiB) ? "LPC2919" : "LPC2917"; } else { if (package_code == 2) { /* 100-pin package */ if (bank->size == 128*KiB) lpc2900_info->target_name = "LPC2921"; else if (bank->size == 256*KiB) lpc2900_info->target_name = "LPC2923"; else if (bank->size == 512*KiB) lpc2900_info->target_name = "LPC2925"; else found = 0; } else if (package_code == 4) { /* 144-pin package */ if ((bank->size == 256*KiB) && (feat3 == 0xFFFFFFE9)) lpc2900_info->target_name = "LPC2926"; else if ((bank->size == 512*KiB) && (feat3 == 0xFFFFFCF0)) lpc2900_info->target_name = "LPC2917/01"; else if ((bank->size == 512*KiB) && (feat3 == 0xFFFFFFF1)) lpc2900_info->target_name = "LPC2927"; else if ((bank->size == 768*KiB) && (feat3 == 0xFFFFFCF8)) lpc2900_info->target_name = "LPC2919/01"; else if ((bank->size == 768*KiB) && (feat3 == 0xFFFFFFF9)) lpc2900_info->target_name = "LPC2929"; else found = 0; } else if (package_code == 5) { /* 208-pin package */ lpc2900_info->target_name = (bank->size == 0) ? "LPC2930" : "LPC2939"; } else found = 0; } if (!found) { LOG_WARNING("Unknown LPC29xx derivative (FEATx=" "%08" PRIx32 ":%08" PRIx32 ":%08" PRIx32 ":%08" PRIx32 ")", feat0, feat1, feat2, feat3); return ERROR_FLASH_OPERATION_FAILED; } /* Show detected device */ LOG_INFO("Flash bank %d: Device %s, %" PRIu32 " KiB in %d sectors", bank->bank_number, lpc2900_info->target_name, bank->size / KiB, bank->num_sectors); /* Flashless devices cannot be handled */ if (bank->num_sectors == 0) { LOG_WARNING("Flashless device cannot be handled"); return ERROR_FLASH_OPERATION_FAILED; } /* Sector layout. * These are logical sector numbers. When doing real flash operations, * the logical flash number are translated into the physical flash numbers * of the device. */ bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); offset = 0; for (i = 0; i < bank->num_sectors; i++) { bank->sectors[i].offset = offset; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = -1; if (i <= 7) bank->sectors[i].size = 8 * KiB; else if (i <= 18) bank->sectors[i].size = 64 * KiB; else { /* We shouldn't come here. But there might be a new part out there * that has more than 19 sectors. Politely ask for a fix then. */ bank->sectors[i].size = 0; LOG_ERROR("Never heard about sector %d", i); } offset += bank->sectors[i].size; } lpc2900_info->is_probed = true; /* Read sector security status */ if (lpc2900_read_security_status(bank) != ERROR_OK) { LOG_ERROR("Cannot determine sector security status"); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } /** * Run a blank check for each sector. * * For speed reasons, the device isn't read word by word. * A hash value is calculated by the hardware ("BIST") for each sector. * This value is then compared against the known hash of an empty sector. * * @param bank Pointer to the flash bank descriptor */ static int lpc2900_erase_check(struct flash_bank *bank) { uint32_t status = lpc2900_is_ready(bank); if (status != ERROR_OK) { LOG_INFO("Processor not halted/not probed"); return status; } /* Use the BIST (Built-In Selft Test) to generate a signature of each flash * sector. Compare against the expected signature of an empty sector. */ int sector; for (sector = 0; sector < bank->num_sectors; sector++) { uint32_t signature[4]; status = lpc2900_run_bist128(bank, bank->sectors[sector].offset, bank->sectors[sector].offset + (bank->sectors[sector].size - 1), &signature); if (status != ERROR_OK) return status; /* The expected signatures for an empty sector are different * for 8 KiB and 64 KiB sectors. */ if (bank->sectors[sector].size == 8*KiB) { bank->sectors[sector].is_erased = (signature[3] == 0x01ABAAAA) && (signature[2] == 0xAAAAAAAA) && (signature[1] == 0xAAAAAAAA) && (signature[0] == 0xAAA00AAA); } if (bank->sectors[sector].size == 64*KiB) { bank->sectors[sector].is_erased = (signature[3] == 0x11801222) && (signature[2] == 0xB88844FF) && (signature[1] == 0x11A22008) && (signature[0] == 0x2B1BFE44); } } return ERROR_OK; } /** * Get protection (sector security) status. * * Determine the status of "sector security" for each sector. * A secured sector is one that can never be erased/programmed again. * * @param bank Pointer to the flash bank descriptor */ static int lpc2900_protect_check(struct flash_bank *bank) { return lpc2900_read_security_status(bank); } /** * Print info about the driver (not the device). * * @param bank Pointer to the flash bank descriptor * @param buf Buffer to take the string * @param buf_size Maximum number of characters that the buffer can take */ static int lpc2900_info(struct flash_bank *bank, char *buf, int buf_size) { snprintf(buf, buf_size, "lpc2900 flash driver"); return ERROR_OK; } struct flash_driver lpc2900_flash = { .name = "lpc2900", .commands = lpc2900_command_handlers, .flash_bank_command = lpc2900_flash_bank_command, .erase = lpc2900_erase, .protect = lpc2900_protect, .write = lpc2900_write, .read = default_flash_read, .probe = lpc2900_probe, .auto_probe = lpc2900_probe, .erase_check = lpc2900_erase_check, .protect_check = lpc2900_protect_check, .info = lpc2900_info }; openocd-0.7.0/src/flash/nor/Makefile.in0000644000175000001440000004724612141414275014627 00000000000000# Makefile.in generated by automake 1.13.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ DIST_COMMON = $(top_srcdir)/common.mk $(srcdir)/Makefile.in \ $(srcdir)/Makefile.am $(top_srcdir)/depcomp $(noinst_HEADERS) @INTERNAL_JIMTCL_TRUE@am__append_1 = -I$(top_srcdir)/jimtcl \ @INTERNAL_JIMTCL_TRUE@ -I$(top_builddir)/jimtcl subdir = src/flash/nor ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/config_subdir.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libocdflashnor_la_LIBADD = am__objects_1 = aduc702x.lo at91sam4.lo at91sam3.lo at91sam7.lo \ avrf.lo cfi.lo efm32.lo em357.lo faux.lo lpc2000.lo lpc288x.lo \ lpc2900.lo lpcspifi.lo non_cfi.lo ocl.lo pic32mx.lo spi.lo \ stmsmi.lo stellaris.lo stm32f1x.lo stm32f2x.lo stm32lx.lo \ str7x.lo str9x.lo str9xpec.lo tms470.lo virtual.lo fm3.lo \ dsp5680xx_flash.lo kinetis.lo am_libocdflashnor_la_OBJECTS = core.lo tcl.lo $(am__objects_1) \ drivers.lo libocdflashnor_la_OBJECTS = $(am_libocdflashnor_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libocdflashnor_la_SOURCES) DIST_SOURCES = $(libocdflashnor_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CC_FOR_BUILD = @CC_FOR_BUILD@ CFLAGS = @CFLAGS@ CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@ FGREP = @FGREP@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ doxygen_as_html = @doxygen_as_html@ doxygen_as_pdf = @doxygen_as_pdf@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ # common flags used in openocd build AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src \ -I$(top_srcdir)/src/helper -DPKGDATADIR=\"$(pkgdatadir)\" \ -DPKGLIBDIR=\"$(pkglibdir)\" $(am__append_1) noinst_LTLIBRARIES = libocdflashnor.la libocdflashnor_la_SOURCES = \ core.c \ tcl.c \ $(NOR_DRIVERS) \ drivers.c NOR_DRIVERS = \ aduc702x.c \ at91sam4.c \ at91sam3.c \ at91sam7.c \ avrf.c \ cfi.c \ efm32.c \ em357.c \ faux.c \ lpc2000.c \ lpc288x.c \ lpc2900.c \ lpcspifi.c \ non_cfi.c \ ocl.c \ pic32mx.c \ spi.c \ stmsmi.c \ stellaris.c \ stm32f1x.c \ stm32f2x.c \ stm32lx.c \ str7x.c \ str9x.c \ str9xpec.c \ tms470.c \ virtual.c \ fm3.c \ dsp5680xx_flash.c \ kinetis.c noinst_HEADERS = \ core.h \ cfi.h \ driver.h \ imp.h \ non_cfi.h \ ocl.h \ spi.h MAINTAINERCLEANFILES = $(srcdir)/Makefile.in all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/common.mk $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/flash/nor/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/flash/nor/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_srcdir)/common.mk: $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libocdflashnor.la: $(libocdflashnor_la_OBJECTS) $(libocdflashnor_la_DEPENDENCIES) $(EXTRA_libocdflashnor_la_DEPENDENCIES) $(AM_V_CCLD)$(LINK) $(libocdflashnor_la_OBJECTS) $(libocdflashnor_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aduc702x.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/at91sam3.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/at91sam4.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/at91sam7.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/avrf.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cfi.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/core.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/drivers.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dsp5680xx_flash.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/efm32.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/em357.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/faux.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fm3.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kinetis.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lpc2000.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lpc288x.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lpc2900.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lpcspifi.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/non_cfi.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ocl.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pic32mx.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spi.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stellaris.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stm32f1x.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stm32f2x.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stm32lx.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stmsmi.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str7x.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str9x.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/str9xpec.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tcl.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tms470.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/virtual.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: openocd-0.7.0/src/flash/nor/stm32f1x.c0000644000175000001440000012652212137151331014304 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2011 by Andreas Fritiofson * * andreas.fritiofson@gmail.com * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include #include #include /* stm32x register locations */ #define FLASH_REG_BASE_B0 0x40022000 #define FLASH_REG_BASE_B1 0x40022040 #define STM32_FLASH_ACR 0x00 #define STM32_FLASH_KEYR 0x04 #define STM32_FLASH_OPTKEYR 0x08 #define STM32_FLASH_SR 0x0C #define STM32_FLASH_CR 0x10 #define STM32_FLASH_AR 0x14 #define STM32_FLASH_OBR 0x1C #define STM32_FLASH_WRPR 0x20 /* TODO: Check if code using these really should be hard coded to bank 0. * There are valid cases, on dual flash devices the protection of the * second bank is done on the bank0 reg's. */ #define STM32_FLASH_ACR_B0 0x40022000 #define STM32_FLASH_KEYR_B0 0x40022004 #define STM32_FLASH_OPTKEYR_B0 0x40022008 #define STM32_FLASH_SR_B0 0x4002200C #define STM32_FLASH_CR_B0 0x40022010 #define STM32_FLASH_AR_B0 0x40022014 #define STM32_FLASH_OBR_B0 0x4002201C #define STM32_FLASH_WRPR_B0 0x40022020 /* option byte location */ #define STM32_OB_RDP 0x1FFFF800 #define STM32_OB_USER 0x1FFFF802 #define STM32_OB_DATA0 0x1FFFF804 #define STM32_OB_DATA1 0x1FFFF806 #define STM32_OB_WRP0 0x1FFFF808 #define STM32_OB_WRP1 0x1FFFF80A #define STM32_OB_WRP2 0x1FFFF80C #define STM32_OB_WRP3 0x1FFFF80E /* FLASH_CR register bits */ #define FLASH_PG (1 << 0) #define FLASH_PER (1 << 1) #define FLASH_MER (1 << 2) #define FLASH_OPTPG (1 << 4) #define FLASH_OPTER (1 << 5) #define FLASH_STRT (1 << 6) #define FLASH_LOCK (1 << 7) #define FLASH_OPTWRE (1 << 9) /* FLASH_SR register bits */ #define FLASH_BSY (1 << 0) #define FLASH_PGERR (1 << 2) #define FLASH_WRPRTERR (1 << 4) #define FLASH_EOP (1 << 5) /* STM32_FLASH_OBR bit definitions (reading) */ #define OPT_ERROR 0 #define OPT_READOUT 1 #define OPT_RDWDGSW 2 #define OPT_RDRSTSTOP 3 #define OPT_RDRSTSTDBY 4 #define OPT_BFB2 5 /* dual flash bank only */ /* register unlock keys */ #define KEY1 0x45670123 #define KEY2 0xCDEF89AB /* timeout values */ #define FLASH_WRITE_TIMEOUT 10 #define FLASH_ERASE_TIMEOUT 100 struct stm32x_options { uint16_t RDP; uint16_t user_options; uint16_t user_data; uint16_t protection[4]; }; struct stm32x_flash_bank { struct stm32x_options option_bytes; int ppage_size; int probed; bool has_dual_banks; /* used to access dual flash bank stm32xl */ uint32_t register_base; uint16_t default_rdp; int user_data_offset; int option_offset; uint32_t user_bank_size; }; static int stm32x_mass_erase(struct flash_bank *bank); static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id); static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count); /* flash bank stm32x 0 0 */ FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command) { struct stm32x_flash_bank *stm32x_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; stm32x_info = malloc(sizeof(struct stm32x_flash_bank)); bank->driver_priv = stm32x_info; stm32x_info->probed = 0; stm32x_info->has_dual_banks = false; stm32x_info->register_base = FLASH_REG_BASE_B0; stm32x_info->user_bank_size = bank->size; return ERROR_OK; } static inline int stm32x_get_flash_reg(struct flash_bank *bank, uint32_t reg) { struct stm32x_flash_bank *stm32x_info = bank->driver_priv; return reg + stm32x_info->register_base; } static inline int stm32x_get_flash_status(struct flash_bank *bank, uint32_t *status) { struct target *target = bank->target; return target_read_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_SR), status); } static int stm32x_wait_status_busy(struct flash_bank *bank, int timeout) { struct target *target = bank->target; uint32_t status; int retval = ERROR_OK; /* wait for busy to clear */ for (;;) { retval = stm32x_get_flash_status(bank, &status); if (retval != ERROR_OK) return retval; LOG_DEBUG("status: 0x%" PRIx32 "", status); if ((status & FLASH_BSY) == 0) break; if (timeout-- <= 0) { LOG_ERROR("timed out waiting for flash"); return ERROR_FAIL; } alive_sleep(1); } if (status & FLASH_WRPRTERR) { LOG_ERROR("stm32x device protected"); retval = ERROR_FAIL; } if (status & FLASH_PGERR) { LOG_ERROR("stm32x device programming failed"); retval = ERROR_FAIL; } /* Clear but report errors */ if (status & (FLASH_WRPRTERR | FLASH_PGERR)) { /* If this operation fails, we ignore it and report the original * retval */ target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_SR), FLASH_WRPRTERR | FLASH_PGERR); } return retval; } static int stm32x_check_operation_supported(struct flash_bank *bank) { struct stm32x_flash_bank *stm32x_info = bank->driver_priv; /* if we have a dual flash bank device then * we need to perform option byte stuff on bank0 only */ if (stm32x_info->register_base != FLASH_REG_BASE_B0) { LOG_ERROR("Option Byte Operation's must use bank0"); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } static int stm32x_read_options(struct flash_bank *bank) { uint32_t optiondata; struct stm32x_flash_bank *stm32x_info = NULL; struct target *target = bank->target; stm32x_info = bank->driver_priv; /* read current option bytes */ int retval = target_read_u32(target, STM32_FLASH_OBR_B0, &optiondata); if (retval != ERROR_OK) return retval; stm32x_info->option_bytes.user_options = (optiondata >> stm32x_info->option_offset >> 2) & 0xffff; stm32x_info->option_bytes.user_data = (optiondata >> stm32x_info->user_data_offset) & 0xffff; stm32x_info->option_bytes.RDP = (optiondata & (1 << OPT_READOUT)) ? 0xFFFF : 0x5AA5; if (optiondata & (1 << OPT_READOUT)) LOG_INFO("Device Security Bit Set"); /* each bit refers to a 4bank protection */ retval = target_read_u32(target, STM32_FLASH_WRPR_B0, &optiondata); if (retval != ERROR_OK) return retval; stm32x_info->option_bytes.protection[0] = (uint16_t)optiondata; stm32x_info->option_bytes.protection[1] = (uint16_t)(optiondata >> 8); stm32x_info->option_bytes.protection[2] = (uint16_t)(optiondata >> 16); stm32x_info->option_bytes.protection[3] = (uint16_t)(optiondata >> 24); return ERROR_OK; } static int stm32x_erase_options(struct flash_bank *bank) { struct stm32x_flash_bank *stm32x_info = NULL; struct target *target = bank->target; stm32x_info = bank->driver_priv; /* read current options */ stm32x_read_options(bank); /* unlock flash registers */ int retval = target_write_u32(target, STM32_FLASH_KEYR_B0, KEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, STM32_FLASH_KEYR_B0, KEY2); if (retval != ERROR_OK) return retval; /* unlock option flash registers */ retval = target_write_u32(target, STM32_FLASH_OPTKEYR_B0, KEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, STM32_FLASH_OPTKEYR_B0, KEY2); if (retval != ERROR_OK) return retval; /* erase option bytes */ retval = target_write_u32(target, STM32_FLASH_CR_B0, FLASH_OPTER | FLASH_OPTWRE); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, STM32_FLASH_CR_B0, FLASH_OPTER | FLASH_STRT | FLASH_OPTWRE); if (retval != ERROR_OK) return retval; retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); if (retval != ERROR_OK) return retval; /* clear readout protection and complementary option bytes * this will also force a device unlock if set */ stm32x_info->option_bytes.RDP = stm32x_info->default_rdp; return ERROR_OK; } static int stm32x_write_options(struct flash_bank *bank) { struct stm32x_flash_bank *stm32x_info = NULL; struct target *target = bank->target; stm32x_info = bank->driver_priv; /* unlock flash registers */ int retval = target_write_u32(target, STM32_FLASH_KEYR_B0, KEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, STM32_FLASH_KEYR_B0, KEY2); if (retval != ERROR_OK) return retval; /* unlock option flash registers */ retval = target_write_u32(target, STM32_FLASH_OPTKEYR_B0, KEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, STM32_FLASH_OPTKEYR_B0, KEY2); if (retval != ERROR_OK) return retval; /* program option bytes */ retval = target_write_u32(target, STM32_FLASH_CR_B0, FLASH_OPTPG | FLASH_OPTWRE); if (retval != ERROR_OK) return retval; uint8_t opt_bytes[16]; target_buffer_set_u16(target, opt_bytes, stm32x_info->option_bytes.RDP); target_buffer_set_u16(target, opt_bytes + 2, stm32x_info->option_bytes.user_options); target_buffer_set_u16(target, opt_bytes + 4, stm32x_info->option_bytes.user_data & 0xff); target_buffer_set_u16(target, opt_bytes + 6, (stm32x_info->option_bytes.user_data >> 8) & 0xff); target_buffer_set_u16(target, opt_bytes + 8, stm32x_info->option_bytes.protection[0]); target_buffer_set_u16(target, opt_bytes + 10, stm32x_info->option_bytes.protection[1]); target_buffer_set_u16(target, opt_bytes + 12, stm32x_info->option_bytes.protection[2]); target_buffer_set_u16(target, opt_bytes + 14, stm32x_info->option_bytes.protection[3]); uint32_t offset = STM32_OB_RDP - bank->base; retval = stm32x_write_block(bank, opt_bytes, offset, sizeof(opt_bytes) / 2); if (retval != ERROR_OK) { if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) LOG_ERROR("working area required to erase options bytes"); return retval; } retval = target_write_u32(target, STM32_FLASH_CR_B0, FLASH_LOCK); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int stm32x_protect_check(struct flash_bank *bank) { struct target *target = bank->target; struct stm32x_flash_bank *stm32x_info = bank->driver_priv; uint32_t protection; int i, s; int num_bits; int set; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } int retval = stm32x_check_operation_supported(bank); if (ERROR_OK != retval) return retval; /* medium density - each bit refers to a 4bank protection * high density - each bit refers to a 2bank protection */ retval = target_read_u32(target, STM32_FLASH_WRPR_B0, &protection); if (retval != ERROR_OK) return retval; /* medium density - each protection bit is for 4 * 1K pages * high density - each protection bit is for 2 * 2K pages */ num_bits = (bank->num_sectors / stm32x_info->ppage_size); if (stm32x_info->ppage_size == 2) { /* high density flash/connectivity line protection */ set = 1; if (protection & (1 << 31)) set = 0; /* bit 31 controls sector 62 - 255 protection for high density * bit 31 controls sector 62 - 127 protection for connectivity line */ for (s = 62; s < bank->num_sectors; s++) bank->sectors[s].is_protected = set; if (bank->num_sectors > 61) num_bits = 31; for (i = 0; i < num_bits; i++) { set = 1; if (protection & (1 << i)) set = 0; for (s = 0; s < stm32x_info->ppage_size; s++) bank->sectors[(i * stm32x_info->ppage_size) + s].is_protected = set; } } else { /* low/medium density flash protection */ for (i = 0; i < num_bits; i++) { set = 1; if (protection & (1 << i)) set = 0; for (s = 0; s < stm32x_info->ppage_size; s++) bank->sectors[(i * stm32x_info->ppage_size) + s].is_protected = set; } } return ERROR_OK; } static int stm32x_erase(struct flash_bank *bank, int first, int last) { struct target *target = bank->target; int i; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if ((first == 0) && (last == (bank->num_sectors - 1))) return stm32x_mass_erase(bank); /* unlock flash registers */ int retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY2); if (retval != ERROR_OK) return retval; for (i = first; i <= last; i++) { retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PER); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_AR), bank->base + bank->sectors[i].offset); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PER | FLASH_STRT); if (retval != ERROR_OK) return retval; retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); if (retval != ERROR_OK) return retval; bank->sectors[i].is_erased = 1; } retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int stm32x_protect(struct flash_bank *bank, int set, int first, int last) { struct stm32x_flash_bank *stm32x_info = NULL; struct target *target = bank->target; uint16_t prot_reg[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}; int i, reg, bit; int status; uint32_t protection; stm32x_info = bank->driver_priv; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } int retval = stm32x_check_operation_supported(bank); if (ERROR_OK != retval) return retval; if ((first % stm32x_info->ppage_size) != 0) { LOG_WARNING("aligned start protect sector to a %d sector boundary", stm32x_info->ppage_size); first = first - (first % stm32x_info->ppage_size); } if (((last + 1) % stm32x_info->ppage_size) != 0) { LOG_WARNING("aligned end protect sector to a %d sector boundary", stm32x_info->ppage_size); last++; last = last - (last % stm32x_info->ppage_size); last--; } /* medium density - each bit refers to a 4bank protection * high density - each bit refers to a 2bank protection */ retval = target_read_u32(target, STM32_FLASH_WRPR_B0, &protection); if (retval != ERROR_OK) return retval; prot_reg[0] = (uint16_t)protection; prot_reg[1] = (uint16_t)(protection >> 8); prot_reg[2] = (uint16_t)(protection >> 16); prot_reg[3] = (uint16_t)(protection >> 24); if (stm32x_info->ppage_size == 2) { /* high density flash */ /* bit 7 controls sector 62 - 255 protection */ if (last > 61) { if (set) prot_reg[3] &= ~(1 << 7); else prot_reg[3] |= (1 << 7); } if (first > 61) first = 62; if (last > 61) last = 61; for (i = first; i <= last; i++) { reg = (i / stm32x_info->ppage_size) / 8; bit = (i / stm32x_info->ppage_size) - (reg * 8); if (set) prot_reg[reg] &= ~(1 << bit); else prot_reg[reg] |= (1 << bit); } } else { /* medium density flash */ for (i = first; i <= last; i++) { reg = (i / stm32x_info->ppage_size) / 8; bit = (i / stm32x_info->ppage_size) - (reg * 8); if (set) prot_reg[reg] &= ~(1 << bit); else prot_reg[reg] |= (1 << bit); } } status = stm32x_erase_options(bank); if (status != ERROR_OK) return status; stm32x_info->option_bytes.protection[0] = prot_reg[0]; stm32x_info->option_bytes.protection[1] = prot_reg[1]; stm32x_info->option_bytes.protection[2] = prot_reg[2]; stm32x_info->option_bytes.protection[3] = prot_reg[3]; return stm32x_write_options(bank); } static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct stm32x_flash_bank *stm32x_info = bank->driver_priv; struct target *target = bank->target; uint32_t buffer_size = 16384; struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[5]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; /* see contrib/loaders/flash/stm32f1x.S for src */ static const uint8_t stm32x_flash_write_code[] = { /* #define STM32_FLASH_SR_OFFSET 0x0C */ /* wait_fifo: */ 0x16, 0x68, /* ldr r6, [r2, #0] */ 0x00, 0x2e, /* cmp r6, #0 */ 0x18, 0xd0, /* beq exit */ 0x55, 0x68, /* ldr r5, [r2, #4] */ 0xb5, 0x42, /* cmp r5, r6 */ 0xf9, 0xd0, /* beq wait_fifo */ 0x2e, 0x88, /* ldrh r6, [r5, #0] */ 0x26, 0x80, /* strh r6, [r4, #0] */ 0x02, 0x35, /* adds r5, #2 */ 0x02, 0x34, /* adds r4, #2 */ /* busy: */ 0xc6, 0x68, /* ldr r6, [r0, #STM32_FLASH_SR_OFFSET] */ 0x01, 0x27, /* movs r7, #1 */ 0x3e, 0x42, /* tst r6, r7 */ 0xfb, 0xd1, /* bne busy */ 0x14, 0x27, /* movs r7, #0x14 */ 0x3e, 0x42, /* tst r6, r7 */ 0x08, 0xd1, /* bne error */ 0x9d, 0x42, /* cmp r5, r3 */ 0x01, 0xd3, /* bcc no_wrap */ 0x15, 0x46, /* mov r5, r2 */ 0x08, 0x35, /* adds r5, #8 */ /* no_wrap: */ 0x55, 0x60, /* str r5, [r2, #4] */ 0x01, 0x39, /* subs r1, r1, #1 */ 0x00, 0x29, /* cmp r1, #0 */ 0x02, 0xd0, /* beq exit */ 0xe5, 0xe7, /* b wait_fifo */ /* error: */ 0x00, 0x20, /* movs r0, #0 */ 0x50, 0x60, /* str r0, [r2, #4] */ /* exit: */ 0x30, 0x46, /* mov r0, r6 */ 0x00, 0xbe, /* bkpt #0 */ }; /* flash write code */ if (target_alloc_working_area(target, sizeof(stm32x_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; }; retval = target_write_buffer(target, write_algorithm->address, sizeof(stm32x_flash_write_code), (uint8_t *)stm32x_flash_write_code); if (retval != ERROR_OK) return retval; /* memory buffer */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; buffer_size &= ~3UL; /* Make sure it's 4 byte aligned */ if (buffer_size <= 256) { /* we already allocated the writing code, but failed to get a * buffer, free the algorithm */ target_free_working_area(target, write_algorithm); LOG_WARNING("no large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } }; init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* flash base (in), status (out) */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* count (halfword-16bit) */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* buffer start */ init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* buffer end */ init_reg_param(®_params[4], "r4", 32, PARAM_IN_OUT); /* target address */ buf_set_u32(reg_params[0].value, 0, 32, stm32x_info->register_base); buf_set_u32(reg_params[1].value, 0, 32, count); buf_set_u32(reg_params[2].value, 0, 32, source->address); buf_set_u32(reg_params[3].value, 0, 32, source->address + source->size); buf_set_u32(reg_params[4].value, 0, 32, address); armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; retval = target_run_flash_async_algorithm(target, buffer, count, 2, 0, NULL, 5, reg_params, source->address, source->size, write_algorithm->address, 0, &armv7m_info); if (retval == ERROR_FLASH_OPERATION_FAILED) { LOG_ERROR("flash write failed at address 0x%"PRIx32, buf_get_u32(reg_params[4].value, 0, 32)); if (buf_get_u32(reg_params[0].value, 0, 32) & FLASH_PGERR) { LOG_ERROR("flash memory not erased before writing"); /* Clear but report errors */ target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_SR), FLASH_PGERR); } if (buf_get_u32(reg_params[0].value, 0, 32) & FLASH_WRPRTERR) { LOG_ERROR("flash memory write protected"); /* Clear but report errors */ target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_SR), FLASH_WRPRTERR); } } target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); return retval; } static int stm32x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint8_t *new_buffer = NULL; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset & 0x1) { LOG_ERROR("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } /* If there's an odd number of bytes, the data has to be padded. Duplicate * the buffer and use the normal code path with a single block write since * it's probably cheaper than to special case the last odd write using * discrete accesses. */ if (count & 1) { new_buffer = malloc(count + 1); if (new_buffer == NULL) { LOG_ERROR("odd number of bytes to write and no memory for padding buffer"); return ERROR_FAIL; } LOG_INFO("odd number of bytes to write, padding with 0xff"); buffer = memcpy(new_buffer, buffer, count); buffer[count++] = 0xff; } uint32_t words_remaining = count / 2; int retval, retval2; /* unlock flash registers */ retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY1); if (retval != ERROR_OK) goto cleanup; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY2); if (retval != ERROR_OK) goto cleanup; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PG); if (retval != ERROR_OK) goto cleanup; /* try using a block write */ retval = stm32x_write_block(bank, buffer, offset, words_remaining); if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* if block write failed (no sufficient working area), * we use normal (slow) single halfword accesses */ LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); while (words_remaining > 0) { uint16_t value; memcpy(&value, buffer, sizeof(uint16_t)); retval = target_write_u16(target, bank->base + offset, value); if (retval != ERROR_OK) goto reset_pg_and_lock; retval = stm32x_wait_status_busy(bank, 5); if (retval != ERROR_OK) goto reset_pg_and_lock; words_remaining--; buffer += 2; offset += 2; } } reset_pg_and_lock: retval2 = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); if (retval == ERROR_OK) retval = retval2; cleanup: if (new_buffer) free(new_buffer); return retval; } static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id) { /* This check the device CPUID core register to detect * the M0 from the M3 devices. */ struct target *target = bank->target; uint32_t cpuid, device_id_register = 0; /* Get the CPUID from the ARM Core * http://infocenter.arm.com/help/topic/com.arm.doc.ddi0432c/DDI0432C_cortex_m0_r0p0_trm.pdf 4.2.1 */ int retval = target_read_u32(target, 0xE000ED00, &cpuid); if (retval != ERROR_OK) return retval; if (((cpuid >> 4) & 0xFFF) == 0xC20) { /* 0xC20 is M0 devices */ device_id_register = 0x40015800; } else if (((cpuid >> 4) & 0xFFF) == 0xC23) { /* 0xC23 is M3 devices */ device_id_register = 0xE0042000; } else if (((cpuid >> 4) & 0xFFF) == 0xC24) { /* 0xC24 is M4 devices */ device_id_register = 0xE0042000; } else { LOG_ERROR("Cannot identify target as a stm32x"); return ERROR_FAIL; } /* read stm32 device id register */ retval = target_read_u32(target, device_id_register, device_id); if (retval != ERROR_OK) return retval; return retval; } static int stm32x_get_flash_size(struct flash_bank *bank, uint16_t *flash_size_in_kb) { struct target *target = bank->target; uint32_t cpuid, flash_size_reg; int retval = target_read_u32(target, 0xE000ED00, &cpuid); if (retval != ERROR_OK) return retval; if (((cpuid >> 4) & 0xFFF) == 0xC20) { /* 0xC20 is M0 devices */ flash_size_reg = 0x1FFFF7CC; } else if (((cpuid >> 4) & 0xFFF) == 0xC23) { /* 0xC23 is M3 devices */ flash_size_reg = 0x1FFFF7E0; } else if (((cpuid >> 4) & 0xFFF) == 0xC24) { /* 0xC24 is M4 devices */ flash_size_reg = 0x1FFFF7CC; } else { LOG_ERROR("Cannot identify target as a stm32x"); return ERROR_FAIL; } retval = target_read_u16(target, flash_size_reg, flash_size_in_kb); if (retval != ERROR_OK) return retval; return retval; } static int stm32x_probe(struct flash_bank *bank) { struct stm32x_flash_bank *stm32x_info = bank->driver_priv; int i; uint16_t flash_size_in_kb; uint16_t max_flash_size_in_kb; uint32_t device_id; int page_size; uint32_t base_address = 0x08000000; stm32x_info->probed = 0; stm32x_info->register_base = FLASH_REG_BASE_B0; stm32x_info->user_data_offset = 10; stm32x_info->option_offset = 0; /* default factory protection level */ stm32x_info->default_rdp = 0x5AA5; /* read stm32 device id register */ int retval = stm32x_get_device_id(bank, &device_id); if (retval != ERROR_OK) return retval; LOG_INFO("device id = 0x%08" PRIx32 "", device_id); /* set page size, protection granularity and max flash size depending on family */ switch (device_id & 0xfff) { case 0x410: /* medium density */ page_size = 1024; stm32x_info->ppage_size = 4; max_flash_size_in_kb = 128; break; case 0x412: /* low density */ page_size = 1024; stm32x_info->ppage_size = 4; max_flash_size_in_kb = 32; break; case 0x414: /* high density */ page_size = 2048; stm32x_info->ppage_size = 2; max_flash_size_in_kb = 512; break; case 0x418: /* connectivity line density */ page_size = 2048; stm32x_info->ppage_size = 2; max_flash_size_in_kb = 256; break; case 0x420: /* value line density */ page_size = 1024; stm32x_info->ppage_size = 4; max_flash_size_in_kb = 128; break; case 0x422: /* stm32f30x */ page_size = 2048; stm32x_info->ppage_size = 2; max_flash_size_in_kb = 256; stm32x_info->user_data_offset = 16; stm32x_info->option_offset = 6; stm32x_info->default_rdp = 0x55AA; break; case 0x428: /* value line High density */ page_size = 2048; stm32x_info->ppage_size = 4; max_flash_size_in_kb = 128; break; case 0x430: /* xl line density (dual flash banks) */ page_size = 2048; stm32x_info->ppage_size = 2; max_flash_size_in_kb = 1024; stm32x_info->has_dual_banks = true; break; case 0x432: /* stm32f37x */ page_size = 2048; stm32x_info->ppage_size = 2; max_flash_size_in_kb = 256; stm32x_info->user_data_offset = 16; stm32x_info->option_offset = 6; stm32x_info->default_rdp = 0x55AA; break; case 0x440: /* stm32f0x */ page_size = 1024; stm32x_info->ppage_size = 4; max_flash_size_in_kb = 64; stm32x_info->user_data_offset = 16; stm32x_info->option_offset = 6; stm32x_info->default_rdp = 0x55AA; break; default: LOG_WARNING("Cannot identify target as a STM32 family."); return ERROR_FAIL; } /* get flash size from target. */ retval = stm32x_get_flash_size(bank, &flash_size_in_kb); /* failed reading flash size or flash size invalid (early silicon), * default to max target family */ if (retval != ERROR_OK || flash_size_in_kb == 0xffff || flash_size_in_kb == 0) { LOG_WARNING("STM32 flash size failed, probe inaccurate - assuming %dk flash", max_flash_size_in_kb); flash_size_in_kb = max_flash_size_in_kb; } if (stm32x_info->has_dual_banks) { /* split reported size into matching bank */ if (bank->base != 0x08080000) { /* bank 0 will be fixed 512k */ flash_size_in_kb = 512; } else { flash_size_in_kb -= 512; /* bank1 also uses a register offset */ stm32x_info->register_base = FLASH_REG_BASE_B1; base_address = 0x08080000; } } /* if the user sets the size manually then ignore the probed value * this allows us to work around devices that have a invalid flash size register value */ if (stm32x_info->user_bank_size) { LOG_INFO("ignoring flash probed value, using configured bank size"); flash_size_in_kb = stm32x_info->user_bank_size / 1024; } LOG_INFO("flash size = %dkbytes", flash_size_in_kb); /* did we assign flash size? */ assert(flash_size_in_kb != 0xffff); /* calculate numbers of pages */ int num_pages = flash_size_in_kb * 1024 / page_size; /* check that calculation result makes sense */ assert(num_pages > 0); if (bank->sectors) { free(bank->sectors); bank->sectors = NULL; } bank->base = base_address; bank->size = (num_pages * page_size); bank->num_sectors = num_pages; bank->sectors = malloc(sizeof(struct flash_sector) * num_pages); for (i = 0; i < num_pages; i++) { bank->sectors[i].offset = i * page_size; bank->sectors[i].size = page_size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } stm32x_info->probed = 1; return ERROR_OK; } static int stm32x_auto_probe(struct flash_bank *bank) { struct stm32x_flash_bank *stm32x_info = bank->driver_priv; if (stm32x_info->probed) return ERROR_OK; return stm32x_probe(bank); } #if 0 COMMAND_HANDLER(stm32x_handle_part_id_command) { return ERROR_OK; } #endif static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size) { uint32_t device_id; int printed; /* read stm32 device id register */ int retval = stm32x_get_device_id(bank, &device_id); if (retval != ERROR_OK) return retval; if ((device_id & 0xfff) == 0x410) { printed = snprintf(buf, buf_size, "stm32x (Medium Density) - Rev: "); buf += printed; buf_size -= printed; switch (device_id >> 16) { case 0x0000: snprintf(buf, buf_size, "A"); break; case 0x2000: snprintf(buf, buf_size, "B"); break; case 0x2001: snprintf(buf, buf_size, "Z"); break; case 0x2003: snprintf(buf, buf_size, "Y"); break; default: snprintf(buf, buf_size, "unknown"); break; } } else if ((device_id & 0xfff) == 0x412) { printed = snprintf(buf, buf_size, "stm32x (Low Density) - Rev: "); buf += printed; buf_size -= printed; switch (device_id >> 16) { case 0x1000: snprintf(buf, buf_size, "A"); break; default: snprintf(buf, buf_size, "unknown"); break; } } else if ((device_id & 0xfff) == 0x414) { printed = snprintf(buf, buf_size, "stm32x (High Density) - Rev: "); buf += printed; buf_size -= printed; switch (device_id >> 16) { case 0x1000: snprintf(buf, buf_size, "A"); break; case 0x1001: snprintf(buf, buf_size, "Z"); break; default: snprintf(buf, buf_size, "unknown"); break; } } else if ((device_id & 0xfff) == 0x418) { printed = snprintf(buf, buf_size, "stm32x (Connectivity) - Rev: "); buf += printed; buf_size -= printed; switch (device_id >> 16) { case 0x1000: snprintf(buf, buf_size, "A"); break; case 0x1001: snprintf(buf, buf_size, "Z"); break; default: snprintf(buf, buf_size, "unknown"); break; } } else if ((device_id & 0xfff) == 0x420) { printed = snprintf(buf, buf_size, "stm32x (Value) - Rev: "); buf += printed; buf_size -= printed; switch (device_id >> 16) { case 0x1000: snprintf(buf, buf_size, "A"); break; case 0x1001: snprintf(buf, buf_size, "Z"); break; default: snprintf(buf, buf_size, "unknown"); break; } } else if ((device_id & 0xfff) == 0x422) { printed = snprintf(buf, buf_size, "stm32f30x - Rev: "); buf += printed; buf_size -= printed; switch (device_id >> 16) { case 0x1000: snprintf(buf, buf_size, "A"); break; case 0x1001: snprintf(buf, buf_size, "Z"); break; case 0x2000: snprintf(buf, buf_size, "B"); break; default: snprintf(buf, buf_size, "unknown"); break; } } else if ((device_id & 0xfff) == 0x428) { printed = snprintf(buf, buf_size, "stm32x (Value HD) - Rev: "); buf += printed; buf_size -= printed; switch (device_id >> 16) { case 0x1000: snprintf(buf, buf_size, "A"); break; case 0x1001: snprintf(buf, buf_size, "Z"); break; default: snprintf(buf, buf_size, "unknown"); break; } } else if ((device_id & 0xfff) == 0x430) { printed = snprintf(buf, buf_size, "stm32x (XL) - Rev: "); buf += printed; buf_size -= printed; switch (device_id >> 16) { case 0x1000: snprintf(buf, buf_size, "A"); break; default: snprintf(buf, buf_size, "unknown"); break; } } else if ((device_id & 0xfff) == 0x432) { printed = snprintf(buf, buf_size, "stm32f37x - Rev: "); buf += printed; buf_size -= printed; switch (device_id >> 16) { case 0x1000: snprintf(buf, buf_size, "A"); break; case 0x2000: snprintf(buf, buf_size, "B"); break; default: snprintf(buf, buf_size, "unknown"); break; } } else if ((device_id & 0xfff) == 0x440) { printed = snprintf(buf, buf_size, "stm32f0x - Rev: "); buf += printed; buf_size -= printed; switch (device_id >> 16) { case 0x1000: snprintf(buf, buf_size, "1.0"); break; case 0x2000: snprintf(buf, buf_size, "2.0"); break; default: snprintf(buf, buf_size, "unknown"); break; } } else { snprintf(buf, buf_size, "Cannot identify target as a stm32x\n"); return ERROR_FAIL; } return ERROR_OK; } COMMAND_HANDLER(stm32x_handle_lock_command) { struct target *target = NULL; struct stm32x_flash_bank *stm32x_info = NULL; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; stm32x_info = bank->driver_priv; target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } retval = stm32x_check_operation_supported(bank); if (ERROR_OK != retval) return retval; if (stm32x_erase_options(bank) != ERROR_OK) { command_print(CMD_CTX, "stm32x failed to erase options"); return ERROR_OK; } /* set readout protection */ stm32x_info->option_bytes.RDP = 0; if (stm32x_write_options(bank) != ERROR_OK) { command_print(CMD_CTX, "stm32x failed to lock device"); return ERROR_OK; } command_print(CMD_CTX, "stm32x locked"); return ERROR_OK; } COMMAND_HANDLER(stm32x_handle_unlock_command) { struct target *target = NULL; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } retval = stm32x_check_operation_supported(bank); if (ERROR_OK != retval) return retval; if (stm32x_erase_options(bank) != ERROR_OK) { command_print(CMD_CTX, "stm32x failed to unlock device"); return ERROR_OK; } if (stm32x_write_options(bank) != ERROR_OK) { command_print(CMD_CTX, "stm32x failed to lock device"); return ERROR_OK; } command_print(CMD_CTX, "stm32x unlocked.\n" "INFO: a reset or power cycle is required " "for the new settings to take effect."); return ERROR_OK; } COMMAND_HANDLER(stm32x_handle_options_read_command) { uint32_t optionbyte; struct target *target = NULL; struct stm32x_flash_bank *stm32x_info = NULL; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; stm32x_info = bank->driver_priv; target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } retval = stm32x_check_operation_supported(bank); if (ERROR_OK != retval) return retval; retval = target_read_u32(target, STM32_FLASH_OBR_B0, &optionbyte); if (retval != ERROR_OK) return retval; command_print(CMD_CTX, "Option Byte: 0x%" PRIx32 "", optionbyte); int user_data = optionbyte; if (buf_get_u32((uint8_t *)&optionbyte, OPT_ERROR, 1)) command_print(CMD_CTX, "Option Byte Complement Error"); if (buf_get_u32((uint8_t *)&optionbyte, OPT_READOUT, 1)) command_print(CMD_CTX, "Readout Protection On"); else command_print(CMD_CTX, "Readout Protection Off"); /* user option bytes are offset depending on variant */ optionbyte >>= stm32x_info->option_offset; if (buf_get_u32((uint8_t *)&optionbyte, OPT_RDWDGSW, 1)) command_print(CMD_CTX, "Software Watchdog"); else command_print(CMD_CTX, "Hardware Watchdog"); if (buf_get_u32((uint8_t *)&optionbyte, OPT_RDRSTSTOP, 1)) command_print(CMD_CTX, "Stop: No reset generated"); else command_print(CMD_CTX, "Stop: Reset generated"); if (buf_get_u32((uint8_t *)&optionbyte, OPT_RDRSTSTDBY, 1)) command_print(CMD_CTX, "Standby: No reset generated"); else command_print(CMD_CTX, "Standby: Reset generated"); if (stm32x_info->has_dual_banks) { if (buf_get_u32((uint8_t *)&optionbyte, OPT_BFB2, 1)) command_print(CMD_CTX, "Boot: Bank 0"); else command_print(CMD_CTX, "Boot: Bank 1"); } command_print(CMD_CTX, "User Option0: 0x%02" PRIx8, (user_data >> stm32x_info->user_data_offset) & 0xff); command_print(CMD_CTX, "User Option1: 0x%02" PRIx8, (user_data >> (stm32x_info->user_data_offset + 8)) & 0xff); return ERROR_OK; } COMMAND_HANDLER(stm32x_handle_options_write_command) { struct target *target = NULL; struct stm32x_flash_bank *stm32x_info = NULL; uint16_t optionbyte; if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; stm32x_info = bank->driver_priv; target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } retval = stm32x_check_operation_supported(bank); if (ERROR_OK != retval) return retval; retval = stm32x_read_options(bank); if (ERROR_OK != retval) return retval; /* start with current options */ optionbyte = stm32x_info->option_bytes.user_options; /* skip over flash bank */ CMD_ARGC--; CMD_ARGV++; while (CMD_ARGC) { if (strcmp("SWWDG", CMD_ARGV[0]) == 0) optionbyte |= (1 << 0); else if (strcmp("HWWDG", CMD_ARGV[0]) == 0) optionbyte &= ~(1 << 0); else if (strcmp("NORSTSTOP", CMD_ARGV[0]) == 0) optionbyte &= ~(1 << 1); else if (strcmp("RSTSTNDBY", CMD_ARGV[0]) == 0) optionbyte &= ~(1 << 1); else if (strcmp("NORSTSTNDBY", CMD_ARGV[0]) == 0) optionbyte &= ~(1 << 2); else if (strcmp("RSTSTOP", CMD_ARGV[0]) == 0) optionbyte &= ~(1 << 2); else if (stm32x_info->has_dual_banks) { if (strcmp("BOOT0", CMD_ARGV[0]) == 0) optionbyte |= (1 << 3); else if (strcmp("BOOT1", CMD_ARGV[0]) == 0) optionbyte &= ~(1 << 3); else return ERROR_COMMAND_SYNTAX_ERROR; } else return ERROR_COMMAND_SYNTAX_ERROR; CMD_ARGC--; CMD_ARGV++; } if (stm32x_erase_options(bank) != ERROR_OK) { command_print(CMD_CTX, "stm32x failed to erase options"); return ERROR_OK; } stm32x_info->option_bytes.user_options = optionbyte; if (stm32x_write_options(bank) != ERROR_OK) { command_print(CMD_CTX, "stm32x failed to write options"); return ERROR_OK; } command_print(CMD_CTX, "stm32x write options complete.\n" "INFO: a reset or power cycle is required " "for the new settings to take effect."); return ERROR_OK; } static int stm32x_mass_erase(struct flash_bank *bank) { struct target *target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* unlock option flash registers */ int retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY2); if (retval != ERROR_OK) return retval; /* mass erase flash memory */ retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_MER); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_MER | FLASH_STRT); if (retval != ERROR_OK) return retval; retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); if (retval != ERROR_OK) return retval; return ERROR_OK; } COMMAND_HANDLER(stm32x_handle_mass_erase_command) { int i; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; retval = stm32x_mass_erase(bank); if (retval == ERROR_OK) { /* set all sectors as erased */ for (i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_erased = 1; command_print(CMD_CTX, "stm32x mass erase complete"); } else command_print(CMD_CTX, "stm32x mass erase failed"); return retval; } static const struct command_registration stm32x_exec_command_handlers[] = { { .name = "lock", .handler = stm32x_handle_lock_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Lock entire flash device.", }, { .name = "unlock", .handler = stm32x_handle_unlock_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Unlock entire protected flash device.", }, { .name = "mass_erase", .handler = stm32x_handle_mass_erase_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Erase entire flash device.", }, { .name = "options_read", .handler = stm32x_handle_options_read_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Read and display device option byte.", }, { .name = "options_write", .handler = stm32x_handle_options_write_command, .mode = COMMAND_EXEC, .usage = "bank_id ('SWWDG'|'HWWDG') " "('RSTSTNDBY'|'NORSTSTNDBY') " "('RSTSTOP'|'NORSTSTOP')", .help = "Replace bits in device option byte.", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration stm32x_command_handlers[] = { { .name = "stm32f1x", .mode = COMMAND_ANY, .help = "stm32f1x flash command group", .usage = "", .chain = stm32x_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct flash_driver stm32f1x_flash = { .name = "stm32f1x", .commands = stm32x_command_handlers, .flash_bank_command = stm32x_flash_bank_command, .erase = stm32x_erase, .protect = stm32x_protect, .write = stm32x_write, .read = default_flash_read, .probe = stm32x_probe, .auto_probe = stm32x_auto_probe, .erase_check = default_flash_blank_check, .protect_check = stm32x_protect_check, .info = get_stm32x_info, }; openocd-0.7.0/src/flash/nor/avrf.c0000644000175000001440000003373112134336410013652 00000000000000/*************************************************************************** * Copyright (C) 2009 by Simon Qian * * SimonQian@SimonQian.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include /* AVR_JTAG_Instructions */ #define AVR_JTAG_INS_LEN 4 /* Public Instructions: */ #define AVR_JTAG_INS_EXTEST 0x00 #define AVR_JTAG_INS_IDCODE 0x01 #define AVR_JTAG_INS_SAMPLE_PRELOAD 0x02 #define AVR_JTAG_INS_BYPASS 0x0F /* AVR Specified Public Instructions: */ #define AVR_JTAG_INS_AVR_RESET 0x0C #define AVR_JTAG_INS_PROG_ENABLE 0x04 #define AVR_JTAG_INS_PROG_COMMANDS 0x05 #define AVR_JTAG_INS_PROG_PAGELOAD 0x06 #define AVR_JTAG_INS_PROG_PAGEREAD 0x07 /* Data Registers: */ #define AVR_JTAG_REG_Bypass_Len 1 #define AVR_JTAG_REG_DeviceID_Len 32 #define AVR_JTAG_REG_Reset_Len 1 #define AVR_JTAG_REG_JTAGID_Len 32 #define AVR_JTAG_REG_ProgrammingEnable_Len 16 #define AVR_JTAG_REG_ProgrammingCommand_Len 15 #define AVR_JTAG_REG_FlashDataByte_Len 16 struct avrf_type { char name[15]; uint16_t chip_id; int flash_page_size; int flash_page_num; int eeprom_page_size; int eeprom_page_num; }; struct avrf_flash_bank { int ppage_size; int probed; }; static struct avrf_type avft_chips_info[] = { /* name, chip_id, flash_page_size, flash_page_num, * eeprom_page_size, eeprom_page_num */ {"atmega128", 0x9702, 256, 512, 8, 512}, {"at90can128", 0x9781, 256, 512, 8, 512}, }; /* avr program functions */ static int avr_jtag_reset(struct avr_common *avr, uint32_t reset) { avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_AVR_RESET); avr_jtag_senddat(avr->jtag_info.tap, NULL, reset, AVR_JTAG_REG_Reset_Len); return ERROR_OK; } static int avr_jtag_read_jtagid(struct avr_common *avr, uint32_t *id) { avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_IDCODE); avr_jtag_senddat(avr->jtag_info.tap, id, 0, AVR_JTAG_REG_JTAGID_Len); return ERROR_OK; } static int avr_jtagprg_enterprogmode(struct avr_common *avr) { avr_jtag_reset(avr, 1); avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_ENABLE); avr_jtag_senddat(avr->jtag_info.tap, NULL, 0xA370, AVR_JTAG_REG_ProgrammingEnable_Len); return ERROR_OK; } static int avr_jtagprg_leaveprogmode(struct avr_common *avr) { avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS); avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x2300, AVR_JTAG_REG_ProgrammingCommand_Len); avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3300, AVR_JTAG_REG_ProgrammingCommand_Len); avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_ENABLE); avr_jtag_senddat(avr->jtag_info.tap, NULL, 0, AVR_JTAG_REG_ProgrammingEnable_Len); avr_jtag_reset(avr, 0); return ERROR_OK; } static int avr_jtagprg_chiperase(struct avr_common *avr) { uint32_t poll_value; avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS); avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x2380, AVR_JTAG_REG_ProgrammingCommand_Len); avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3180, AVR_JTAG_REG_ProgrammingCommand_Len); avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3380, AVR_JTAG_REG_ProgrammingCommand_Len); avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3380, AVR_JTAG_REG_ProgrammingCommand_Len); do { poll_value = 0; avr_jtag_senddat(avr->jtag_info.tap, &poll_value, 0x3380, AVR_JTAG_REG_ProgrammingCommand_Len); if (ERROR_OK != mcu_execute_queue()) return ERROR_FAIL; LOG_DEBUG("poll_value = 0x%04" PRIx32 "", poll_value); } while (!(poll_value & 0x0200)); return ERROR_OK; } static int avr_jtagprg_writeflashpage(struct avr_common *avr, uint8_t *page_buf, uint32_t buf_size, uint32_t addr, uint32_t page_size) { uint32_t i, poll_value; avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS); avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x2310, AVR_JTAG_REG_ProgrammingCommand_Len); /* load addr high byte */ avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x0700 | ((addr >> 9) & 0xFF), AVR_JTAG_REG_ProgrammingCommand_Len); /* load addr low byte */ avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x0300 | ((addr >> 1) & 0xFF), AVR_JTAG_REG_ProgrammingCommand_Len); avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_PAGELOAD); for (i = 0; i < page_size; i++) { if (i < buf_size) avr_jtag_senddat(avr->jtag_info.tap, NULL, page_buf[i], 8); else avr_jtag_senddat(avr->jtag_info.tap, NULL, 0xFF, 8); } avr_jtag_sendinstr(avr->jtag_info.tap, NULL, AVR_JTAG_INS_PROG_COMMANDS); avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3700, AVR_JTAG_REG_ProgrammingCommand_Len); avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3500, AVR_JTAG_REG_ProgrammingCommand_Len); avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3700, AVR_JTAG_REG_ProgrammingCommand_Len); avr_jtag_senddat(avr->jtag_info.tap, NULL, 0x3700, AVR_JTAG_REG_ProgrammingCommand_Len); do { poll_value = 0; avr_jtag_senddat(avr->jtag_info.tap, &poll_value, 0x3700, AVR_JTAG_REG_ProgrammingCommand_Len); if (ERROR_OK != mcu_execute_queue()) return ERROR_FAIL; LOG_DEBUG("poll_value = 0x%04" PRIx32 "", poll_value); } while (!(poll_value & 0x0200)); return ERROR_OK; } FLASH_BANK_COMMAND_HANDLER(avrf_flash_bank_command) { struct avrf_flash_bank *avrf_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; avrf_info = malloc(sizeof(struct avrf_flash_bank)); bank->driver_priv = avrf_info; avrf_info->probed = 0; return ERROR_OK; } static int avrf_erase(struct flash_bank *bank, int first, int last) { struct target *target = bank->target; struct avr_common *avr = target->arch_info; int status; LOG_DEBUG("%s", __func__); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } status = avr_jtagprg_enterprogmode(avr); if (status != ERROR_OK) return status; status = avr_jtagprg_chiperase(avr); if (status != ERROR_OK) return status; return avr_jtagprg_leaveprogmode(avr); } static int avrf_protect(struct flash_bank *bank, int set, int first, int last) { LOG_INFO("%s", __func__); return ERROR_OK; } static int avrf_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; struct avr_common *avr = target->arch_info; uint32_t cur_size, cur_buffer_size, page_size; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } page_size = bank->sectors[0].size; if ((offset % page_size) != 0) { LOG_WARNING("offset 0x%" PRIx32 " breaks required %" PRIu32 "-byte alignment", offset, page_size); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } LOG_DEBUG("offset is 0x%08" PRIx32 "", offset); LOG_DEBUG("count is %" PRId32 "", count); if (ERROR_OK != avr_jtagprg_enterprogmode(avr)) return ERROR_FAIL; cur_size = 0; while (count > 0) { if (count > page_size) cur_buffer_size = page_size; else cur_buffer_size = count; avr_jtagprg_writeflashpage(avr, buffer + cur_size, cur_buffer_size, offset + cur_size, page_size); count -= cur_buffer_size; cur_size += cur_buffer_size; keep_alive(); } return avr_jtagprg_leaveprogmode(avr); } #define EXTRACT_MFG(X) (((X) & 0xffe) >> 1) #define EXTRACT_PART(X) (((X) & 0xffff000) >> 12) #define EXTRACT_VER(X) (((X) & 0xf0000000) >> 28) static int avrf_probe(struct flash_bank *bank) { struct target *target = bank->target; struct avrf_flash_bank *avrf_info = bank->driver_priv; struct avr_common *avr = target->arch_info; struct avrf_type *avr_info = NULL; int i; uint32_t device_id; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } avrf_info->probed = 0; avr_jtag_read_jtagid(avr, &device_id); if (ERROR_OK != mcu_execute_queue()) return ERROR_FAIL; LOG_INFO("device id = 0x%08" PRIx32 "", device_id); if (EXTRACT_MFG(device_id) != 0x1F) LOG_ERROR("0x%" PRIx32 " is invalid Manufacturer for avr, 0x%X is expected", EXTRACT_MFG(device_id), 0x1F); for (i = 0; i < (int)ARRAY_SIZE(avft_chips_info); i++) { if (avft_chips_info[i].chip_id == EXTRACT_PART(device_id)) { avr_info = &avft_chips_info[i]; LOG_INFO("target device is %s", avr_info->name); break; } } if (avr_info != NULL) { if (bank->sectors) { free(bank->sectors); bank->sectors = NULL; } /* chip found */ bank->base = 0x00000000; bank->size = (avr_info->flash_page_size * avr_info->flash_page_num); bank->num_sectors = avr_info->flash_page_num; bank->sectors = malloc(sizeof(struct flash_sector) * avr_info->flash_page_num); for (i = 0; i < avr_info->flash_page_num; i++) { bank->sectors[i].offset = i * avr_info->flash_page_size; bank->sectors[i].size = avr_info->flash_page_size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } avrf_info->probed = 1; return ERROR_OK; } else { /* chip not supported */ LOG_ERROR("0x%" PRIx32 " is not support for avr", EXTRACT_PART(device_id)); avrf_info->probed = 1; return ERROR_FAIL; } } static int avrf_auto_probe(struct flash_bank *bank) { struct avrf_flash_bank *avrf_info = bank->driver_priv; if (avrf_info->probed) return ERROR_OK; return avrf_probe(bank); } static int avrf_protect_check(struct flash_bank *bank) { LOG_INFO("%s", __func__); return ERROR_OK; } static int avrf_info(struct flash_bank *bank, char *buf, int buf_size) { struct target *target = bank->target; struct avr_common *avr = target->arch_info; struct avrf_type *avr_info = NULL; int i; uint32_t device_id; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } avr_jtag_read_jtagid(avr, &device_id); if (ERROR_OK != mcu_execute_queue()) return ERROR_FAIL; LOG_INFO("device id = 0x%08" PRIx32 "", device_id); if (EXTRACT_MFG(device_id) != 0x1F) LOG_ERROR("0x%" PRIx32 " is invalid Manufacturer for avr, 0x%X is expected", EXTRACT_MFG(device_id), 0x1F); for (i = 0; i < (int)ARRAY_SIZE(avft_chips_info); i++) { if (avft_chips_info[i].chip_id == EXTRACT_PART(device_id)) { avr_info = &avft_chips_info[i]; LOG_INFO("target device is %s", avr_info->name); break; } } if (avr_info != NULL) { /* chip found */ snprintf(buf, buf_size, "%s - Rev: 0x%" PRIx32 "", avr_info->name, EXTRACT_VER(device_id)); return ERROR_OK; } else { /* chip not supported */ snprintf(buf, buf_size, "Cannot identify target as a avr\n"); return ERROR_FLASH_OPERATION_FAILED; } } static int avrf_mass_erase(struct flash_bank *bank) { struct target *target = bank->target; struct avr_common *avr = target->arch_info; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if ((ERROR_OK != avr_jtagprg_enterprogmode(avr)) || (ERROR_OK != avr_jtagprg_chiperase(avr)) || (ERROR_OK != avr_jtagprg_leaveprogmode(avr))) return ERROR_FAIL; return ERROR_OK; } COMMAND_HANDLER(avrf_handle_mass_erase_command) { int i; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; if (avrf_mass_erase(bank) == ERROR_OK) { /* set all sectors as erased */ for (i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_erased = 1; command_print(CMD_CTX, "avr mass erase complete"); } else command_print(CMD_CTX, "avr mass erase failed"); LOG_DEBUG("%s", __func__); return ERROR_OK; } static const struct command_registration avrf_exec_command_handlers[] = { { .name = "mass_erase", .usage = "", .handler = avrf_handle_mass_erase_command, .mode = COMMAND_EXEC, .help = "erase entire device", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration avrf_command_handlers[] = { { .name = "avrf", .mode = COMMAND_ANY, .help = "AVR flash command group", .usage = "", .chain = avrf_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct flash_driver avr_flash = { .name = "avr", .commands = avrf_command_handlers, .flash_bank_command = avrf_flash_bank_command, .erase = avrf_erase, .protect = avrf_protect, .write = avrf_write, .read = default_flash_read, .probe = avrf_probe, .auto_probe = avrf_auto_probe, .erase_check = default_flash_blank_check, .protect_check = avrf_protect_check, .info = avrf_info, }; openocd-0.7.0/src/flash/nor/spi.h0000644000175000001440000000536212134336410013513 00000000000000/*************************************************************************** * Copyright (C) 2012 by George Harris * * george@luminairecoffee.com * * * * Copyright (C) 2010 by Antonio Borneo * * borneo.antonio@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /* data structure to maintain flash ids from different vendors */ struct flash_device { char *name; uint8_t erase_cmd; uint8_t chip_erase_cmd; uint32_t device_id; uint32_t pagesize; unsigned long sectorsize; unsigned long size_in_bytes; }; #define FLASH_ID(n, es, ces, id, psize, ssize, size) \ { \ .name = n, \ .erase_cmd = es, \ .chip_erase_cmd = ces, \ .device_id = id, \ .pagesize = psize, \ .sectorsize = ssize, \ .size_in_bytes = size \ } extern struct flash_device flash_devices[]; /* fields in SPI flash status register */ #define SPIFLASH_BSY_BIT 0x00000001 /* WIP Bit of SPI SR on SMI SR */ #define SPIFLASH_WE_BIT 0x00000002 /* WEL Bit of SPI SR on SMI SR */ /* SPI Flash Commands */ #define SPIFLASH_READ_ID 0x9F /* Read Flash Identification */ #define SPIFLASH_READ_STATUS 0x05 /* Read Status Register */ #define SPIFLASH_WRITE_ENABLE 0x06 /* Write Enable */ #define SPIFLASH_PAGE_PROGRAM 0x02 /* Page Program */ #define SPIFLASH_FAST_READ 0x0B /* Fast Read */ #define SPIFLASH_READ 0x03 /* Normal Read */ openocd-0.7.0/src/flash/nor/faux.c0000644000175000001440000001045612134336410013656 00000000000000/*************************************************************************** * Copyright (C) 2009 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include #include "hello.h" struct faux_flash_bank { struct target *target; uint8_t *memory; uint32_t start_address; }; static const int sectorSize = 0x10000; /* flash bank faux */ FLASH_BANK_COMMAND_HANDLER(faux_flash_bank_command) { struct faux_flash_bank *info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; info = malloc(sizeof(struct faux_flash_bank)); if (info == NULL) { LOG_ERROR("no memory for flash bank info"); return ERROR_FAIL; } info->memory = malloc(bank->size); if (info == NULL) { free(info); LOG_ERROR("no memory for flash bank info"); return ERROR_FAIL; } bank->driver_priv = info; /* Use 0x10000 as a fixed sector size. */ int i = 0; uint32_t offset = 0; bank->num_sectors = bank->size/sectorSize; bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); for (i = 0; i < bank->num_sectors; i++) { bank->sectors[i].offset = offset; bank->sectors[i].size = sectorSize; offset += bank->sectors[i].size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 0; } info->target = get_target(CMD_ARGV[5]); if (info->target == NULL) { LOG_ERROR("target '%s' not defined", CMD_ARGV[5]); free(info->memory); free(info); return ERROR_FAIL; } return ERROR_OK; } static int faux_erase(struct flash_bank *bank, int first, int last) { struct faux_flash_bank *info = bank->driver_priv; memset(info->memory + first*sectorSize, 0xff, sectorSize*(last-first + 1)); return ERROR_OK; } static int faux_protect(struct flash_bank *bank, int set, int first, int last) { LOG_USER("set protection sector %d to %d to %s", first, last, set ? "on" : "off"); return ERROR_OK; } static int faux_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct faux_flash_bank *info = bank->driver_priv; memcpy(info->memory + offset, buffer, count); return ERROR_OK; } static int faux_protect_check(struct flash_bank *bank) { return ERROR_OK; } static int faux_info(struct flash_bank *bank, char *buf, int buf_size) { snprintf(buf, buf_size, "faux flash driver"); return ERROR_OK; } static int faux_probe(struct flash_bank *bank) { return ERROR_OK; } static const struct command_registration faux_command_handlers[] = { { .name = "faux", .mode = COMMAND_ANY, .help = "faux flash command group", .chain = hello_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct flash_driver faux_flash = { .name = "faux", .commands = faux_command_handlers, .flash_bank_command = faux_flash_bank_command, .erase = faux_erase, .protect = faux_protect, .write = faux_write, .read = default_flash_read, .probe = faux_probe, .auto_probe = faux_probe, .erase_check = default_flash_blank_check, .protect_check = faux_protect_check, .info = faux_info }; openocd-0.7.0/src/flash/nor/non_cfi.c0000644000175000001440000003625112134336410014327 00000000000000/*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * Copyright (C) 2009 Michael Schwingen * * michael@schwingen.org * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "cfi.h" #include "non_cfi.h" #define KB 1024 #define MB (1024*1024) #define ERASE_REGION(num, size) (((size/256) << 16) | (num-1)) /* non-CFI compatible flashes */ static struct non_cfi non_cfi_flashes[] = { { .mfr = CFI_MFR_SST, .id = 0xd4, .pri_id = 0x02, .dev_size = 64*KB, .interface_desc = 0x0, /* x8 only device */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 1, .erase_region_info = { ERASE_REGION(16, 4*KB) } }, { .mfr = CFI_MFR_SST, .id = 0xd5, .pri_id = 0x02, .dev_size = 128*KB, .interface_desc = 0x0, /* x8 only device */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 1, .erase_region_info = { ERASE_REGION(32, 4*KB) } }, { .mfr = CFI_MFR_SST, .id = 0xd6, .pri_id = 0x02, .dev_size = 256*KB, .interface_desc = 0x0, /* x8 only device */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 1, .erase_region_info = { ERASE_REGION(64, 4*KB) } }, { .mfr = CFI_MFR_SST, .id = 0xd7, .pri_id = 0x02, .dev_size = 512*KB, .interface_desc = 0x0, /* x8 only device */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 1, .erase_region_info = { ERASE_REGION(128, 4*KB) } }, { .mfr = CFI_MFR_AMD, /* Spansion AM29LV040B */ .id = 0x4f, .pri_id = 0x02, .dev_size = 512*KB, .interface_desc = 0x0, /* x8 only device */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 1, .erase_region_info = { ERASE_REGION(8, 64*KB) } }, { .mfr = CFI_MFR_SST, .id = 0x2780, .pri_id = 0x02, .dev_size = 512*KB, .interface_desc = 0x2, /* x8 or x16 device */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 1, .erase_region_info = { ERASE_REGION(128, 4*KB) } }, { .mfr = CFI_MFR_ST, .id = 0xd6, /* ST29F400BB */ .pri_id = 0x02, .dev_size = 512*KB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 4, .erase_region_info = { ERASE_REGION(1, 16*KB), ERASE_REGION(2, 8*KB), ERASE_REGION(1, 32*KB), ERASE_REGION(7, 64*KB) } }, { .mfr = CFI_MFR_ST, .id = 0xd5, /* ST29F400BT */ .pri_id = 0x02, .dev_size = 512*KB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 4, .erase_region_info = { ERASE_REGION(7, 64*KB), ERASE_REGION(1, 32*KB), ERASE_REGION(2, 8*KB), ERASE_REGION(1, 16*KB) } }, /* SST 39VF* do not support DQ5 status polling - this currently is only supported by the host algorithm, not by the target code using the work area. Only true for 8-bit and 32-bit wide memories. 16-bit wide memories without DQ5 status polling are supported by the target code. */ { .mfr = CFI_MFR_SST, .id = 0x2782, /* SST39xF160 */ .pri_id = 0x02, .dev_size = 2*MB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7, .num_erase_regions = 1, .erase_region_info = { ERASE_REGION(512, 4*KB) } }, { .mfr = CFI_MFR_SST, .id = 0x2783, /* SST39VF320 */ .pri_id = 0x02, .dev_size = 4*MB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7, .num_erase_regions = 1, .erase_region_info = { ERASE_REGION(1024, 4*KB) } }, { .mfr = CFI_MFR_SST, .id = 0x234b, /* SST39VF1601 */ .pri_id = 0x02, .dev_size = 2*MB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7, .num_erase_regions = 1, .erase_region_info = { ERASE_REGION(512, 4*KB) } }, { .mfr = CFI_MFR_SST, .id = 0x274b, /* SST39WF1601 */ .pri_id = 0x02, .dev_size = 2*MB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7, .num_erase_regions = 1, .erase_region_info = { ERASE_REGION(512, 4*KB) } }, { .mfr = CFI_MFR_SST, .id = 0x234a, /* SST39VF1602 */ .pri_id = 0x02, .dev_size = 2*MB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7, .num_erase_regions = 1, .erase_region_info = { ERASE_REGION(512, 4*KB) } }, { .mfr = CFI_MFR_SST, .id = 0x235b, /* SST39VF3201 */ .pri_id = 0x02, .dev_size = 4*MB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7, .num_erase_regions = 1, .erase_region_info = { ERASE_REGION(1024, 4*KB) } }, { .mfr = CFI_MFR_SST, .id = 0x235a, /* SST39VF3202 */ .pri_id = 0x02, .dev_size = 4*MB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7, .num_erase_regions = 1, .erase_region_info = { ERASE_REGION(1024, 4*KB) } }, { .mfr = CFI_MFR_SST, .id = 0x236d, /* SST39VF6401B */ .pri_id = 0x02, .dev_size = 8*MB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7, .num_erase_regions = 1, .erase_region_info = { ERASE_REGION(2048, 4*KB) } }, { .mfr = CFI_MFR_AMD, .id = 0x22ab, /* AM29F400BB */ .pri_id = 0x02, .dev_size = 512*KB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 4, .erase_region_info = { ERASE_REGION(1, 16*KB), ERASE_REGION(2, 8*KB), ERASE_REGION(1, 32*KB), ERASE_REGION(7, 64*KB) } }, { .mfr = CFI_MFR_AMD, .id = 0x2223, /* AM29F400BT */ .pri_id = 0x02, .dev_size = 512*KB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 4, .erase_region_info = { ERASE_REGION(7, 64*KB), ERASE_REGION(1, 32*KB), ERASE_REGION(2, 8*KB), ERASE_REGION(1, 16*KB) } }, { .mfr = CFI_MFR_FUJITSU, .id = 0x226b, /* AM29SL800DB */ .pri_id = 0x02, .dev_size = 1*MB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 4, .erase_region_info = { ERASE_REGION(1, 16*KB), ERASE_REGION(2, 8*KB), ERASE_REGION(1, 32*KB), ERASE_REGION(15, 64*KB) } }, { .mfr = CFI_MFR_FUJITSU, .id = 0x22ea, /* MBM29SL800TE */ .pri_id = 0x02, .dev_size = 1*MB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 4, .erase_region_info = { ERASE_REGION(15, 64*KB), ERASE_REGION(1, 32*KB), ERASE_REGION(2, 8*KB), ERASE_REGION(1, 16*KB) } }, { .mfr = CFI_MFR_FUJITSU, .id = 0xba, /* 29LV400BC */ .pri_id = 0x02, .dev_size = 512*KB, .interface_desc = 0x1, /* x8 or x16 device w/ nBYTE */ .max_buf_write_size = 0x00, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 4, .erase_region_info = { ERASE_REGION(1, 16*KB), ERASE_REGION(2, 8*KB), ERASE_REGION(1, 32*KB), ERASE_REGION(7, 64*KB) } }, { .mfr = CFI_MFR_AMIC, .id = 0xb31a, /* A29L800A */ .pri_id = 0x02, .dev_size = 1*MB, .interface_desc = 0x2, .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 4, .erase_region_info = { ERASE_REGION(1, 16*KB), ERASE_REGION(2, 8*KB), ERASE_REGION(1, 32*KB), ERASE_REGION(15, 64*KB) } }, { .mfr = CFI_MFR_MX, .id = 0x225b, /* MX29LV800B */ .pri_id = 0x02, .dev_size = 1*MB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 4, .erase_region_info = { ERASE_REGION(1, 16*KB), ERASE_REGION(2, 8*KB), ERASE_REGION(1, 32*KB), ERASE_REGION(15, 64*KB) } }, { .mfr = CFI_MFR_MX, .id = 0x2249, /* MX29LV160AB: 2MB */ .pri_id = 0x02, .dev_size = 2*MB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 4, .erase_region_info = { ERASE_REGION(1, 16*KB), ERASE_REGION(2, 8*KB), ERASE_REGION(1, 32*KB), ERASE_REGION(31, 64*KB) } }, { .mfr = CFI_MFR_MX, .id = 0x22C4, /* MX29LV160AT: 2MB */ .pri_id = 0x02, .dev_size = 2*MB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 4, .erase_region_info = { ERASE_REGION(31, 64*KB), ERASE_REGION(1, 32*KB), ERASE_REGION(2, 8*KB), ERASE_REGION(1, 16*KB) } }, { .mfr = CFI_MFR_EON, .id = 0x225b, /* EN29LV800BB */ .pri_id = 0x02, .dev_size = 1*MB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 4, .erase_region_info = { ERASE_REGION(1, 16*KB), ERASE_REGION(2, 8*KB), ERASE_REGION(1, 32*KB), ERASE_REGION(15, 64*KB) } }, { .mfr = CFI_MFR_ATMEL, .id = 0x00c0, /* Atmel 49BV1614 */ .pri_id = 0x02, .dev_size = 2*MB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 3, .erase_region_info = { ERASE_REGION(8, 8*KB), ERASE_REGION(2, 32*KB), ERASE_REGION(30, 64*KB) } }, { .mfr = CFI_MFR_ATMEL, .id = 0xC2, /* Atmel 49BV1614T */ .pri_id = 0x02, .dev_size = 2*MB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 3, .erase_region_info = { ERASE_REGION(30, 64*KB), ERASE_REGION(2, 32*KB), ERASE_REGION(8, 8*KB) } }, { .mfr = CFI_MFR_AMD, .id = 0x225b, /* S29AL008D */ .pri_id = 0x02, .dev_size = 1*MB, .interface_desc = 0x2, /* x8 or x16 device with nBYTE */ .max_buf_write_size = 0x0, .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7, .num_erase_regions = 4, .erase_region_info = { ERASE_REGION(1, 16*KB), ERASE_REGION(2, 8*KB), ERASE_REGION(1, 32*KB), ERASE_REGION(15, 64*KB) } }, { .mfr = 0, .id = 0, } }; void cfi_fixup_non_cfi(struct flash_bank *bank) { unsigned int mask; struct cfi_flash_bank *cfi_info = bank->driver_priv; struct non_cfi *non_cfi = non_cfi_flashes; if (cfi_info->x16_as_x8) mask = 0xFF; else mask = 0xFFFF; for (non_cfi = non_cfi_flashes; non_cfi->mfr; non_cfi++) { if ((cfi_info->manufacturer == non_cfi->mfr) && (cfi_info->device_id == (non_cfi->id & mask))) break; } /* only fixup jedec flashs found in table */ if (!non_cfi->mfr) return; cfi_info->not_cfi = 1; /* fill in defaults for non-critical data */ cfi_info->vcc_min = 0x0; cfi_info->vcc_max = 0x0; cfi_info->vpp_min = 0x0; cfi_info->vpp_max = 0x0; /* these are used for timeouts - use vales that should be long enough for normal operation. */ cfi_info->word_write_timeout_typ = 0x0a; cfi_info->buf_write_timeout_typ = 0x0d; cfi_info->block_erase_timeout_typ = 0x0d; cfi_info->chip_erase_timeout_typ = 0x10; cfi_info->word_write_timeout_max = 0x0; cfi_info->buf_write_timeout_max = 0x0; cfi_info->block_erase_timeout_max = 0x0; cfi_info->chip_erase_timeout_max = 0x0; cfi_info->qry[0] = 'Q'; cfi_info->qry[1] = 'R'; cfi_info->qry[2] = 'Y'; cfi_info->pri_id = non_cfi->pri_id; cfi_info->pri_addr = 0x0; cfi_info->alt_id = 0x0; cfi_info->alt_addr = 0x0; cfi_info->alt_ext = NULL; cfi_info->interface_desc = non_cfi->interface_desc; cfi_info->max_buf_write_size = non_cfi->max_buf_write_size; cfi_info->status_poll_mask = non_cfi->status_poll_mask; cfi_info->num_erase_regions = non_cfi->num_erase_regions; size_t erase_region_info_size = sizeof(*cfi_info->erase_region_info) * cfi_info->num_erase_regions; cfi_info->erase_region_info = malloc(erase_region_info_size); memcpy(cfi_info->erase_region_info, non_cfi->erase_region_info, erase_region_info_size); cfi_info->dev_size = non_cfi->dev_size; if (cfi_info->pri_id == 0x2) { struct cfi_spansion_pri_ext *pri_ext = malloc(sizeof(struct cfi_spansion_pri_ext)); pri_ext->pri[0] = 'P'; pri_ext->pri[1] = 'R'; pri_ext->pri[2] = 'I'; pri_ext->major_version = '1'; pri_ext->minor_version = '0'; pri_ext->SiliconRevision = 0x0; pri_ext->EraseSuspend = 0x0; pri_ext->EraseSuspend = 0x0; pri_ext->BlkProt = 0x0; pri_ext->TmpBlkUnprotect = 0x0; pri_ext->BlkProtUnprot = 0x0; pri_ext->SimultaneousOps = 0x0; pri_ext->BurstMode = 0x0; pri_ext->PageMode = 0x0; pri_ext->VppMin = 0x0; pri_ext->VppMax = 0x0; pri_ext->TopBottom = 0x0; pri_ext->_unlock1 = 0x5555; pri_ext->_unlock2 = 0x2AAA; pri_ext->_reversed_geometry = 0; cfi_info->pri_ext = pri_ext; } else if ((cfi_info->pri_id == 0x1) || (cfi_info->pri_id == 0x3)) { LOG_ERROR("BUG: non-CFI flashes using the Intel commandset are not yet supported"); exit(-1); } } openocd-0.7.0/src/flash/nor/cfi.h0000644000175000001440000001073612134336410013462 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef CFI_H #define CFI_H #define CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7 0xE0 /* DQ5..DQ7 */ #define CFI_STATUS_POLL_MASK_DQ6_DQ7 0xC0 /* DQ6..DQ7 */ struct cfi_flash_bank { int x16_as_x8; int jedec_probe; int not_cfi; int probed; uint16_t manufacturer; uint16_t device_id; uint8_t qry[3]; /* identification string */ uint16_t pri_id; uint16_t pri_addr; uint16_t alt_id; uint16_t alt_addr; /* device-system interface */ uint8_t vcc_min; uint8_t vcc_max; uint8_t vpp_min; uint8_t vpp_max; uint8_t word_write_timeout_typ; uint8_t buf_write_timeout_typ; uint8_t block_erase_timeout_typ; uint8_t chip_erase_timeout_typ; uint8_t word_write_timeout_max; uint8_t buf_write_timeout_max; uint8_t block_erase_timeout_max; uint8_t chip_erase_timeout_max; uint8_t status_poll_mask; /* flash geometry */ uint32_t dev_size; uint16_t interface_desc; uint16_t max_buf_write_size; uint8_t num_erase_regions; uint32_t *erase_region_info; void *pri_ext; void *alt_ext; /* calculated timeouts */ unsigned word_write_timeout; unsigned buf_write_timeout; unsigned block_erase_timeout; unsigned chip_erase_timeout; }; /* Intel primary extended query table * as defined for the Advanced+ Boot Block Flash Memory (C3) * and used by the linux kernel cfi driver (as of 2.6.14) */ struct cfi_intel_pri_ext { uint8_t pri[3]; uint8_t major_version; uint8_t minor_version; uint32_t feature_support; uint8_t suspend_cmd_support; uint16_t blk_status_reg_mask; uint8_t vcc_optimal; uint8_t vpp_optimal; uint8_t num_protection_fields; uint16_t prot_reg_addr; uint8_t fact_prot_reg_size; uint8_t user_prot_reg_size; uint8_t extra[0]; }; /* Spansion primary extended query table as defined for and used by * the linux kernel cfi driver (as of 2.6.15) */ struct cfi_spansion_pri_ext { uint8_t pri[3]; uint8_t major_version; uint8_t minor_version; uint8_t SiliconRevision; /* bits 1-0: Address Sensitive Unlock */ uint8_t EraseSuspend; uint8_t BlkProt; uint8_t TmpBlkUnprotect; uint8_t BlkProtUnprot; uint8_t SimultaneousOps; uint8_t BurstMode; uint8_t PageMode; uint8_t VppMin; uint8_t VppMax; uint8_t TopBottom; int _reversed_geometry; uint32_t _unlock1; uint32_t _unlock2; }; /* Atmel primary extended query table as defined for and used by * the linux kernel cfi driver (as of 2.6.20+) */ struct cfi_atmel_pri_ext { uint8_t pri[3]; uint8_t major_version; uint8_t minor_version; uint8_t features; uint8_t bottom_boot; uint8_t burst_mode; uint8_t page_mode; }; enum { CFI_UNLOCK_555_2AA, CFI_UNLOCK_5555_2AAA, }; struct cfi_unlock_addresses { uint32_t unlock1; uint32_t unlock2; }; struct cfi_fixup { uint16_t mfr; uint16_t id; void (*fixup)(struct flash_bank *bank, void *param); void *param; }; #define CFI_MFR_AMD 0x0001 #define CFI_MFR_FUJITSU 0x0004 #define CFI_MFR_ATMEL 0x001F #define CFI_MFR_ST 0x0020 /* STMicroelectronics */ #define CFI_MFR_AMIC 0x0037 #define CFI_MFR_SST 0x00BF #define CFI_MFR_MX 0x00C2 #define CFI_MFR_EON 0x007F #define CFI_MFR_ANY 0xffff #define CFI_ID_ANY 0xffff #endif /* CFI_H */ openocd-0.7.0/src/flash/nor/efm32.c0000644000175000001440000006573612137151330013641 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2011 by Andreas Fritiofson * * andreas.fritiofson@gmail.com * * * * Copyright (C) 2013 by Roman Dmitrienko * * me@iamroman.org * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include #include #include #include /* keep family IDs in decimal */ #define EFM_FAMILY_ID_GECKO 71 #define EFM_FAMILY_ID_GIANT_GECKO 72 #define EFM_FAMILY_ID_TINY_GECKO 73 #define EFM_FAMILY_ID_LEOPARD_GECKO 74 #define EFM32_FLASH_ERASE_TMO 100 #define EFM32_FLASH_WDATAREADY_TMO 100 #define EFM32_FLASH_WRITE_TMO 100 /* size in bytes, not words; must fit all Gecko devices */ #define LOCKBITS_PAGE_SZ 512 #define EFM32_MSC_INFO_BASE 0x0fe00000 #define EFM32_MSC_USER_DATA EFM32_MSC_INFO_BASE #define EFM32_MSC_LOCK_BITS (EFM32_MSC_INFO_BASE+0x4000) #define EFM32_MSC_DEV_INFO (EFM32_MSC_INFO_BASE+0x8000) /* PAGE_SIZE is only present in Leopard and Giant Gecko MCUs */ #define EFM32_MSC_DI_PAGE_SIZE (EFM32_MSC_DEV_INFO+0x1e7) #define EFM32_MSC_DI_FLASH_SZ (EFM32_MSC_DEV_INFO+0x1f8) #define EFM32_MSC_DI_RAM_SZ (EFM32_MSC_DEV_INFO+0x1fa) #define EFM32_MSC_DI_PART_NUM (EFM32_MSC_DEV_INFO+0x1fc) #define EFM32_MSC_DI_PART_FAMILY (EFM32_MSC_DEV_INFO+0x1fe) #define EFM32_MSC_DI_PROD_REV (EFM32_MSC_DEV_INFO+0x1ff) #define EFM32_MSC_REGBASE 0x400c0000 #define EFM32_MSC_WRITECTRL (EFM32_MSC_REGBASE+0x008) #define EFM32_MSC_WRITECTRL_WREN_MASK 0x1 #define EFM32_MSC_WRITECMD (EFM32_MSC_REGBASE+0x00c) #define EFM32_MSC_WRITECMD_LADDRIM_MASK 0x1 #define EFM32_MSC_WRITECMD_ERASEPAGE_MASK 0x2 #define EFM32_MSC_WRITECMD_WRITEONCE_MASK 0x8 #define EFM32_MSC_ADDRB (EFM32_MSC_REGBASE+0x010) #define EFM32_MSC_WDATA (EFM32_MSC_REGBASE+0x018) #define EFM32_MSC_STATUS (EFM32_MSC_REGBASE+0x01c) #define EFM32_MSC_STATUS_BUSY_MASK 0x1 #define EFM32_MSC_STATUS_LOCKED_MASK 0x2 #define EFM32_MSC_STATUS_INVADDR_MASK 0x4 #define EFM32_MSC_STATUS_WDATAREADY_MASK 0x8 #define EFM32_MSC_STATUS_WORDTIMEOUT_MASK 0x10 #define EFM32_MSC_STATUS_ERASEABORTED_MASK 0x20 #define EFM32_MSC_LOCK (EFM32_MSC_REGBASE+0x03c) #define EFM32_MSC_LOCK_LOCKKEY 0x1b71 struct efm32x_flash_bank { int probed; uint8_t lb_page[LOCKBITS_PAGE_SZ]; }; struct efm32_info { uint16_t flash_sz_kib; uint16_t ram_sz_kib; uint16_t part_num; uint8_t part_family; uint8_t prod_rev; uint16_t page_size; }; static int efm32x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count); static int efm32x_get_flash_size(struct flash_bank *bank, uint16_t *flash_sz) { return target_read_u16(bank->target, EFM32_MSC_DI_FLASH_SZ, flash_sz); } static int efm32x_get_ram_size(struct flash_bank *bank, uint16_t *ram_sz) { return target_read_u16(bank->target, EFM32_MSC_DI_RAM_SZ, ram_sz); } static int efm32x_get_part_num(struct flash_bank *bank, uint16_t *pnum) { return target_read_u16(bank->target, EFM32_MSC_DI_PART_NUM, pnum); } static int efm32x_get_part_family(struct flash_bank *bank, uint8_t *pfamily) { return target_read_u8(bank->target, EFM32_MSC_DI_PART_FAMILY, pfamily); } static int efm32x_get_prod_rev(struct flash_bank *bank, uint8_t *prev) { return target_read_u8(bank->target, EFM32_MSC_DI_PROD_REV, prev); } static int efm32x_read_info(struct flash_bank *bank, struct efm32_info *efm32_info) { int ret; uint32_t cpuid = 0; memset(efm32_info, 0, sizeof(struct efm32_info)); ret = target_read_u32(bank->target, CPUID, &cpuid); if (ERROR_OK != ret) return ret; if (((cpuid >> 4) & 0xfff) == 0xc23) { /* Cortex M3 device */ } else { LOG_ERROR("Target is not CortexM3"); return ERROR_FAIL; } ret = efm32x_get_flash_size(bank, &(efm32_info->flash_sz_kib)); if (ERROR_OK != ret) return ret; ret = efm32x_get_ram_size(bank, &(efm32_info->ram_sz_kib)); if (ERROR_OK != ret) return ret; ret = efm32x_get_part_num(bank, &(efm32_info->part_num)); if (ERROR_OK != ret) return ret; ret = efm32x_get_part_family(bank, &(efm32_info->part_family)); if (ERROR_OK != ret) return ret; ret = efm32x_get_prod_rev(bank, &(efm32_info->prod_rev)); if (ERROR_OK != ret) return ret; if (EFM_FAMILY_ID_GECKO == efm32_info->part_family || EFM_FAMILY_ID_TINY_GECKO == efm32_info->part_family) efm32_info->page_size = 512; else if (EFM_FAMILY_ID_GIANT_GECKO == efm32_info->part_family || EFM_FAMILY_ID_LEOPARD_GECKO == efm32_info->part_family) { if (efm32_info->prod_rev >= 18) { uint8_t pg_size = 0; ret = target_read_u8(bank->target, EFM32_MSC_DI_PAGE_SIZE, &pg_size); if (ERROR_OK != ret) return ret; efm32_info->page_size = (1 << ((pg_size+10) & 0xff)); } else { /* EFM32 GG/LG errata: MEM_INFO_PAGE_SIZE is invalid for MCUs with PROD_REV < 18 */ if (efm32_info->flash_sz_kib < 512) efm32_info->page_size = 2048; else efm32_info->page_size = 4096; } if ((2048 != efm32_info->page_size) && (4096 != efm32_info->page_size)) { LOG_ERROR("Invalid page size %u", efm32_info->page_size); return ERROR_FAIL; } } else { LOG_ERROR("Unknown MCU family %d", efm32_info->part_family); return ERROR_FAIL; } return ERROR_OK; } /* flash bank efm32 0 0 */ FLASH_BANK_COMMAND_HANDLER(efm32x_flash_bank_command) { struct efm32x_flash_bank *efm32x_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; efm32x_info = malloc(sizeof(struct efm32x_flash_bank)); bank->driver_priv = efm32x_info; efm32x_info->probed = 0; memset(efm32x_info->lb_page, 0xff, LOCKBITS_PAGE_SZ); return ERROR_OK; } /* set or reset given bits in a register */ static int efm32x_set_reg_bits(struct flash_bank *bank, uint32_t reg, uint32_t bitmask, int set) { int ret = 0; uint32_t reg_val = 0; ret = target_read_u32(bank->target, reg, ®_val); if (ERROR_OK != ret) return ret; if (set) reg_val |= bitmask; else reg_val &= ~bitmask; return target_write_u32(bank->target, reg, reg_val); } static int efm32x_set_wren(struct flash_bank *bank, int write_enable) { return efm32x_set_reg_bits(bank, EFM32_MSC_WRITECTRL, EFM32_MSC_WRITECTRL_WREN_MASK, write_enable); } static int efm32x_msc_lock(struct flash_bank *bank, int lock) { return target_write_u32(bank->target, EFM32_MSC_LOCK, (lock ? 0 : EFM32_MSC_LOCK_LOCKKEY)); } static int efm32x_wait_status(struct flash_bank *bank, int timeout, uint32_t wait_mask, int wait_for_set) { int ret = 0; uint32_t status = 0; while (1) { ret = target_read_u32(bank->target, EFM32_MSC_STATUS, &status); if (ERROR_OK != ret) break; LOG_DEBUG("status: 0x%" PRIx32 "", status); if (((status & wait_mask) == 0) && (0 == wait_for_set)) break; else if (((status & wait_mask) != 0) && wait_for_set) break; if (timeout-- <= 0) { LOG_ERROR("timed out waiting for MSC status"); return ERROR_FAIL; } alive_sleep(1); } if (status & EFM32_MSC_STATUS_ERASEABORTED_MASK) LOG_WARNING("page erase was aborted"); return ret; } static int efm32x_erase_page(struct flash_bank *bank, uint32_t addr) { /* this function DOES NOT set WREN; must be set already */ /* 1. write address to ADDRB 2. write LADDRIM 3. check status (INVADDR, LOCKED) 4. write ERASEPAGE 5. wait until !STATUS_BUSY */ int ret = 0; uint32_t status = 0; LOG_DEBUG("erasing flash page at 0x%08x", addr); ret = target_write_u32(bank->target, EFM32_MSC_ADDRB, addr); if (ERROR_OK != ret) return ret; ret = efm32x_set_reg_bits(bank, EFM32_MSC_WRITECMD, EFM32_MSC_WRITECMD_LADDRIM_MASK, 1); if (ERROR_OK != ret) return ret; ret = target_read_u32(bank->target, EFM32_MSC_STATUS, &status); if (ERROR_OK != ret) return ret; LOG_DEBUG("status 0x%x", status); if (status & EFM32_MSC_STATUS_LOCKED_MASK) { LOG_ERROR("Page is locked"); return ERROR_FAIL; } else if (status & EFM32_MSC_STATUS_INVADDR_MASK) { LOG_ERROR("Invalid address 0x%x", addr); return ERROR_FAIL; } ret = efm32x_set_reg_bits(bank, EFM32_MSC_WRITECMD, EFM32_MSC_WRITECMD_ERASEPAGE_MASK, 1); if (ERROR_OK != ret) return ret; return efm32x_wait_status(bank, EFM32_FLASH_ERASE_TMO, EFM32_MSC_STATUS_BUSY_MASK, 0); } static int efm32x_erase(struct flash_bank *bank, int first, int last) { struct target *target = bank->target; int i = 0; int ret = 0; if (TARGET_HALTED != target->state) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } efm32x_msc_lock(bank, 0); ret = efm32x_set_wren(bank, 1); if (ERROR_OK != ret) { LOG_ERROR("Failed to enable MSC write"); return ret; } for (i = first; i <= last; i++) { ret = efm32x_erase_page(bank, bank->sectors[i].offset); if (ERROR_OK != ret) LOG_ERROR("Failed to erase page %d", i); } ret = efm32x_set_wren(bank, 0); efm32x_msc_lock(bank, 1); return ret; } static int efm32x_read_lock_data(struct flash_bank *bank) { struct efm32x_flash_bank *efm32x_info = bank->driver_priv; struct target *target = bank->target; int i = 0; int data_size = 0; uint32_t *ptr = NULL; int ret = 0; assert(!(bank->num_sectors & 0x1f)); data_size = bank->num_sectors / 8; /* number of data bytes */ data_size /= 4; /* ...and data dwords */ ptr = (uint32_t *)efm32x_info->lb_page; for (i = 0; i < data_size; i++, ptr++) { ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+i*4, ptr); if (ERROR_OK != ret) { LOG_ERROR("Failed to read PLW %d", i); return ret; } } /* also, read ULW, DLW and MLW */ /* ULW, word 126 */ ptr = ((uint32_t *)efm32x_info->lb_page) + 126; ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+126*4, ptr); if (ERROR_OK != ret) { LOG_ERROR("Failed to read ULW"); return ret; } /* DLW, word 127 */ ptr = ((uint32_t *)efm32x_info->lb_page) + 127; ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+127*4, ptr); if (ERROR_OK != ret) { LOG_ERROR("Failed to read DLW"); return ret; } /* MLW, word 125, present in GG and LG */ ptr = ((uint32_t *)efm32x_info->lb_page) + 125; ret = target_read_u32(target, EFM32_MSC_LOCK_BITS+125*4, ptr); if (ERROR_OK != ret) { LOG_ERROR("Failed to read MLW"); return ret; } return ERROR_OK; } static int efm32x_write_lock_data(struct flash_bank *bank) { struct efm32x_flash_bank *efm32x_info = bank->driver_priv; int ret = 0; ret = efm32x_erase_page(bank, EFM32_MSC_LOCK_BITS); if (ERROR_OK != ret) { LOG_ERROR("Failed to erase LB page"); return ret; } return efm32x_write(bank, efm32x_info->lb_page, EFM32_MSC_LOCK_BITS, LOCKBITS_PAGE_SZ); } static int efm32x_get_page_lock(struct flash_bank *bank, size_t page) { struct efm32x_flash_bank *efm32x_info = bank->driver_priv; uint32_t dw = ((uint32_t *)efm32x_info->lb_page)[page >> 5]; uint32_t mask = 0; mask = 1 << (page & 0x1f); return (dw & mask) ? 0 : 1; } static int efm32x_set_page_lock(struct flash_bank *bank, size_t page, int set) { struct efm32x_flash_bank *efm32x_info = bank->driver_priv; uint32_t *dw = &((uint32_t *)efm32x_info->lb_page)[page >> 5]; uint32_t mask = 0; mask = 1 << (page & 0x1f); if (!set) *dw |= mask; else *dw &= ~mask; return ERROR_OK; } static int efm32x_protect(struct flash_bank *bank, int set, int first, int last) { struct target *target = bank->target; int i = 0; int ret = 0; if (!set) { LOG_ERROR("Erase device data to reset page locks"); return ERROR_FAIL; } if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } for (i = first; i <= last; i++) { ret = efm32x_set_page_lock(bank, i, set); if (ERROR_OK != ret) { LOG_ERROR("Failed to set lock on page %d", i); return ret; } } ret = efm32x_write_lock_data(bank); if (ERROR_OK != ret) { LOG_ERROR("Failed to write LB page"); return ret; } return ERROR_OK; } static int efm32x_write_block(struct flash_bank *bank, uint8_t *buf, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t buffer_size = 16384; struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[5]; struct armv7m_algorithm armv7m_info; int ret = ERROR_OK; /* see contrib/loaders/flash/efm32.S for src */ static const uint8_t efm32x_flash_write_code[] = { /* #define EFM32_MSC_WRITECTRL_OFFSET 0x008 */ /* #define EFM32_MSC_WRITECMD_OFFSET 0x00c */ /* #define EFM32_MSC_ADDRB_OFFSET 0x010 */ /* #define EFM32_MSC_WDATA_OFFSET 0x018 */ /* #define EFM32_MSC_STATUS_OFFSET 0x01c */ /* #define EFM32_MSC_LOCK_OFFSET 0x03c */ 0x15, 0x4e, /* ldr r6, =#0x1b71 */ 0xc6, 0x63, /* str r6, [r0, #EFM32_MSC_LOCK_OFFSET] */ 0x01, 0x26, /* movs r6, #1 */ 0x86, 0x60, /* str r6, [r0, #EFM32_MSC_WRITECTRL_OFFSET] */ /* wait_fifo: */ 0x16, 0x68, /* ldr r6, [r2, #0] */ 0x00, 0x2e, /* cmp r6, #0 */ 0x22, 0xd0, /* beq exit */ 0x55, 0x68, /* ldr r5, [r2, #4] */ 0xb5, 0x42, /* cmp r5, r6 */ 0xf9, 0xd0, /* beq wait_fifo */ 0x04, 0x61, /* str r4, [r0, #EFM32_MSC_ADDRB_OFFSET] */ 0x01, 0x26, /* movs r6, #1 */ 0xc6, 0x60, /* str r6, [r0, #EFM32_MSC_WRITECMD_OFFSET] */ 0xc6, 0x69, /* ldr r6, [r0, #EFM32_MSC_STATUS_OFFSET] */ 0x06, 0x27, /* movs r7, #6 */ 0x3e, 0x42, /* tst r6, r7 */ 0x16, 0xd1, /* bne error */ /* wait_wdataready: */ 0xc6, 0x69, /* ldr r6, [r0, #EFM32_MSC_STATUS_OFFSET] */ 0x08, 0x27, /* movs r7, #8 */ 0x3e, 0x42, /* tst r6, r7 */ 0xfb, 0xd0, /* beq wait_wdataready */ 0x2e, 0x68, /* ldr r6, [r5] */ 0x86, 0x61, /* str r6, [r0, #EFM32_MSC_WDATA_OFFSET] */ 0x08, 0x26, /* movs r6, #8 */ 0xc6, 0x60, /* str r6, [r0, #EFM32_MSC_WRITECMD_OFFSET] */ 0x04, 0x35, /* adds r5, #4 */ 0x04, 0x34, /* adds r4, #4 */ /* busy: */ 0xc6, 0x69, /* ldr r6, [r0, #EFM32_MSC_STATUS_OFFSET] */ 0x01, 0x27, /* movs r7, #1 */ 0x3e, 0x42, /* tst r6, r7 */ 0xfb, 0xd1, /* bne busy */ 0x9d, 0x42, /* cmp r5, r3 */ 0x01, 0xd3, /* bcc no_wrap */ 0x15, 0x46, /* mov r5, r2 */ 0x08, 0x35, /* adds r5, #8 */ /* no_wrap: */ 0x55, 0x60, /* str r5, [r2, #4] */ 0x01, 0x39, /* subs r1, r1, #1 */ 0x00, 0x29, /* cmp r1, #0 */ 0x02, 0xd0, /* beq exit */ 0xdb, 0xe7, /* b wait_fifo */ /* error: */ 0x00, 0x20, /* movs r0, #0 */ 0x50, 0x60, /* str r0, [r2, #4] */ /* exit: */ 0x30, 0x46, /* mov r0, r6 */ 0x00, 0xbe, /* bkpt #0 */ /* LOCKKEY */ 0x71, 0x1b, 0x00, 0x00 }; /* flash write code */ if (target_alloc_working_area(target, sizeof(efm32x_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; }; ret = target_write_buffer(target, write_algorithm->address, sizeof(efm32x_flash_write_code), (uint8_t *)efm32x_flash_write_code); if (ret != ERROR_OK) return ret; /* memory buffer */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; buffer_size &= ~3UL; /* Make sure it's 4 byte aligned */ if (buffer_size <= 256) { /* we already allocated the writing code, but failed to get a * buffer, free the algorithm */ target_free_working_area(target, write_algorithm); LOG_WARNING("no large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } }; init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* flash base (in), status (out) */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* count (word-32bit) */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* buffer start */ init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* buffer end */ init_reg_param(®_params[4], "r4", 32, PARAM_IN_OUT); /* target address */ buf_set_u32(reg_params[0].value, 0, 32, EFM32_MSC_REGBASE); buf_set_u32(reg_params[1].value, 0, 32, count); buf_set_u32(reg_params[2].value, 0, 32, source->address); buf_set_u32(reg_params[3].value, 0, 32, source->address + source->size); buf_set_u32(reg_params[4].value, 0, 32, address); armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; ret = target_run_flash_async_algorithm(target, buf, count, 4, 0, NULL, 5, reg_params, source->address, source->size, write_algorithm->address, 0, &armv7m_info); if (ret == ERROR_FLASH_OPERATION_FAILED) { LOG_ERROR("flash write failed at address 0x%"PRIx32, buf_get_u32(reg_params[4].value, 0, 32)); if (buf_get_u32(reg_params[0].value, 0, 32) & EFM32_MSC_STATUS_LOCKED_MASK) { LOG_ERROR("flash memory write protected"); } if (buf_get_u32(reg_params[0].value, 0, 32) & EFM32_MSC_STATUS_INVADDR_MASK) { LOG_ERROR("invalid flash memory write address"); } } target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); return ret; } static int efm32x_write_word(struct flash_bank *bank, uint32_t addr, uint32_t val) { /* this function DOES NOT set WREN; must be set already */ /* 1. write address to ADDRB 2. write LADDRIM 3. check status (INVADDR, LOCKED) 4. wait for WDATAREADY 5. write data to WDATA 6. write WRITECMD_WRITEONCE to WRITECMD 7. wait until !STATUS_BUSY */ /* FIXME: EFM32G ref states (7.3.2) that writes should be * performed twice per dword */ int ret = 0; uint32_t status = 0; /* if not called, GDB errors will be reported during large writes */ keep_alive(); ret = target_write_u32(bank->target, EFM32_MSC_ADDRB, addr); if (ERROR_OK != ret) return ret; ret = efm32x_set_reg_bits(bank, EFM32_MSC_WRITECMD, EFM32_MSC_WRITECMD_LADDRIM_MASK, 1); if (ERROR_OK != ret) return ret; ret = target_read_u32(bank->target, EFM32_MSC_STATUS, &status); if (ERROR_OK != ret) return ret; LOG_DEBUG("status 0x%x", status); if (status & EFM32_MSC_STATUS_LOCKED_MASK) { LOG_ERROR("Page is locked"); return ERROR_FAIL; } else if (status & EFM32_MSC_STATUS_INVADDR_MASK) { LOG_ERROR("Invalid address 0x%x", addr); return ERROR_FAIL; } ret = efm32x_wait_status(bank, EFM32_FLASH_WDATAREADY_TMO, EFM32_MSC_STATUS_WDATAREADY_MASK, 1); if (ERROR_OK != ret) { LOG_ERROR("Wait for WDATAREADY failed"); return ret; } ret = target_write_u32(bank->target, EFM32_MSC_WDATA, val); if (ERROR_OK != ret) { LOG_ERROR("WDATA write failed"); return ret; } ret = target_write_u32(bank->target, EFM32_MSC_WRITECMD, EFM32_MSC_WRITECMD_WRITEONCE_MASK); if (ERROR_OK != ret) { LOG_ERROR("WRITECMD write failed"); return ret; } ret = efm32x_wait_status(bank, EFM32_FLASH_WRITE_TMO, EFM32_MSC_STATUS_BUSY_MASK, 0); if (ERROR_OK != ret) { LOG_ERROR("Wait for BUSY failed"); return ret; } return ERROR_OK; } static int efm32x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint8_t *new_buffer = NULL; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset & 0x3) { LOG_ERROR("offset 0x%" PRIx32 " breaks required 4-byte " "alignment", offset); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } if (count & 0x3) { uint32_t old_count = count; count = (old_count | 3) + 1; new_buffer = malloc(count); if (new_buffer == NULL) { LOG_ERROR("odd number of bytes to write and no memory " "for padding buffer"); return ERROR_FAIL; } LOG_INFO("odd number of bytes to write (%d), extending to %d " "and padding with 0xff", old_count, count); memset(buffer, 0xff, count); buffer = memcpy(new_buffer, buffer, old_count); } uint32_t words_remaining = count / 4; int retval, retval2; /* unlock flash registers */ efm32x_msc_lock(bank, 0); retval = efm32x_set_wren(bank, 1); if (retval != ERROR_OK) goto cleanup; /* try using a block write */ retval = efm32x_write_block(bank, buffer, offset, words_remaining); if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* if block write failed (no sufficient working area), * we use normal (slow) single word accesses */ LOG_WARNING("couldn't use block writes, falling back to single " "memory accesses"); while (words_remaining > 0) { uint32_t value; memcpy(&value, buffer, sizeof(uint32_t)); retval = efm32x_write_word(bank, offset, value); if (retval != ERROR_OK) goto reset_pg_and_lock; words_remaining--; buffer += 4; offset += 4; } } reset_pg_and_lock: retval2 = efm32x_set_wren(bank, 0); efm32x_msc_lock(bank, 1); if (retval == ERROR_OK) retval = retval2; cleanup: if (new_buffer) free(new_buffer); return retval; } static int efm32x_probe(struct flash_bank *bank) { struct efm32x_flash_bank *efm32x_info = bank->driver_priv; struct efm32_info efm32_mcu_info; int ret; int i; uint32_t base_address = 0x00000000; efm32x_info->probed = 0; memset(efm32x_info->lb_page, 0xff, LOCKBITS_PAGE_SZ); ret = efm32x_read_info(bank, &efm32_mcu_info); if (ERROR_OK != ret) return ret; switch (efm32_mcu_info.part_family) { case EFM_FAMILY_ID_GECKO: LOG_INFO("Gecko MCU detected"); break; case EFM_FAMILY_ID_GIANT_GECKO: LOG_INFO("Giant Gecko MCU detected"); break; case EFM_FAMILY_ID_TINY_GECKO: LOG_INFO("Tiny Gecko MCU detected"); break; case EFM_FAMILY_ID_LEOPARD_GECKO: LOG_INFO("Leopard Gecko MCU detected"); break; default: LOG_ERROR("Unsupported MCU family %d", efm32_mcu_info.part_family); return ERROR_FAIL; } LOG_INFO("flash size = %dkbytes", efm32_mcu_info.flash_sz_kib); LOG_INFO("flash page size = %dbytes", efm32_mcu_info.page_size); assert(0 != efm32_mcu_info.page_size); int num_pages = efm32_mcu_info.flash_sz_kib * 1024 / efm32_mcu_info.page_size; assert(num_pages > 0); if (bank->sectors) { free(bank->sectors); bank->sectors = NULL; } bank->base = base_address; bank->size = (num_pages * efm32_mcu_info.page_size); bank->num_sectors = num_pages; ret = efm32x_read_lock_data(bank); if (ERROR_OK != ret) { LOG_ERROR("Failed to read LB data"); return ret; } bank->sectors = malloc(sizeof(struct flash_sector) * num_pages); for (i = 0; i < num_pages; i++) { bank->sectors[i].offset = i * efm32_mcu_info.page_size; bank->sectors[i].size = efm32_mcu_info.page_size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } efm32x_info->probed = 1; return ERROR_OK; } static int efm32x_auto_probe(struct flash_bank *bank) { struct efm32x_flash_bank *efm32x_info = bank->driver_priv; if (efm32x_info->probed) return ERROR_OK; return efm32x_probe(bank); } static int efm32x_protect_check(struct flash_bank *bank) { struct target *target = bank->target; int ret = 0; int i = 0; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } ret = efm32x_read_lock_data(bank); if (ERROR_OK != ret) { LOG_ERROR("Failed to read LB data"); return ret; } assert(NULL != bank->sectors); for (i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_protected = efm32x_get_page_lock(bank, i); return ERROR_OK; } static int get_efm32x_info(struct flash_bank *bank, char *buf, int buf_size) { struct efm32_info info; int ret = 0; int printed = 0; ret = efm32x_read_info(bank, &info); if (ERROR_OK != ret) { LOG_ERROR("Failed to read EFM32 info"); return ret; } printed = snprintf(buf, buf_size, "EFM32 "); buf += printed; buf_size -= printed; if (0 >= buf_size) return ERROR_BUF_TOO_SMALL; switch (info.part_family) { case EFM_FAMILY_ID_GECKO: printed = snprintf(buf, buf_size, "Gecko"); break; case EFM_FAMILY_ID_GIANT_GECKO: printed = snprintf(buf, buf_size, "Giant Gecko"); break; case EFM_FAMILY_ID_TINY_GECKO: printed = snprintf(buf, buf_size, "Tiny Gecko"); break; case EFM_FAMILY_ID_LEOPARD_GECKO: printed = snprintf(buf, buf_size, "Leopard Gecko"); break; } buf += printed; buf_size -= printed; if (0 >= buf_size) return ERROR_BUF_TOO_SMALL; printed = snprintf(buf, buf_size, " - Rev: %d", info.prod_rev); buf += printed; buf_size -= printed; if (0 >= buf_size) return ERROR_BUF_TOO_SMALL; return ERROR_OK; } static const struct command_registration efm32x_exec_command_handlers[] = { COMMAND_REGISTRATION_DONE }; static const struct command_registration efm32x_command_handlers[] = { { .name = "efm32", .mode = COMMAND_ANY, .help = "efm32 flash command group", .usage = "", .chain = efm32x_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct flash_driver efm32_flash = { .name = "efm32", .commands = efm32x_command_handlers, .flash_bank_command = efm32x_flash_bank_command, .erase = efm32x_erase, .protect = efm32x_protect, .write = efm32x_write, .read = default_flash_read, .probe = efm32x_probe, .auto_probe = efm32x_auto_probe, .erase_check = default_flash_blank_check, .protect_check = efm32x_protect_check, .info = get_efm32x_info, }; openocd-0.7.0/src/flash/nor/core.c0000644000175000001440000005011712134336410013641 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Copyright (C) 2007-2010 Øyvind Harboe * * Copyright (C) 2008 by Spencer Oliver * * Copyright (C) 2009 Zachary T Welch * * Copyright (C) 2010 by Antonio Borneo * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include /** * @file * Upper level of NOR flash framework. * The lower level interfaces are to drivers. These upper level ones * primarily support access from Tcl scripts or from GDB. */ static struct flash_bank *flash_banks; int flash_driver_erase(struct flash_bank *bank, int first, int last) { int retval; retval = bank->driver->erase(bank, first, last); if (retval != ERROR_OK) LOG_ERROR("failed erasing sectors %d to %d", first, last); return retval; } int flash_driver_protect(struct flash_bank *bank, int set, int first, int last) { int retval; /* callers may not supply illegal parameters ... */ if (first < 0 || first > last || last >= bank->num_sectors) { LOG_ERROR("illegal sector range"); return ERROR_FAIL; } /* force "set" to 0/1 */ set = !!set; /* DANGER! * * We must not use any cached information about protection state!!!! * * There are a million things that could change the protect state: * * the target could have reset, power cycled, been hot plugged, * the application could have run, etc. * * Drivers only receive valid sector range. */ retval = bank->driver->protect(bank, set, first, last); if (retval != ERROR_OK) LOG_ERROR("failed setting protection for areas %d to %d", first, last); return retval; } int flash_driver_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { int retval; retval = bank->driver->write(bank, buffer, offset, count); if (retval != ERROR_OK) { LOG_ERROR( "error writing to flash at address 0x%08" PRIx32 " at offset 0x%8.8" PRIx32, bank->base, offset); } return retval; } int flash_driver_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { int retval; LOG_DEBUG("call flash_driver_read()"); retval = bank->driver->read(bank, buffer, offset, count); if (retval != ERROR_OK) { LOG_ERROR( "error reading to flash at address 0x%08" PRIx32 " at offset 0x%8.8" PRIx32, bank->base, offset); } return retval; } int default_flash_read(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { return target_read_buffer(bank->target, offset + bank->base, count, buffer); } void flash_bank_add(struct flash_bank *bank) { /* put flash bank in linked list */ unsigned bank_num = 0; if (flash_banks) { /* find last flash bank */ struct flash_bank *p = flash_banks; while (NULL != p->next) { bank_num += 1; p = p->next; } p->next = bank; bank_num += 1; } else flash_banks = bank; bank->bank_number = bank_num; } struct flash_bank *flash_bank_list(void) { return flash_banks; } struct flash_bank *get_flash_bank_by_num_noprobe(int num) { struct flash_bank *p; int i = 0; for (p = flash_banks; p; p = p->next) { if (i++ == num) return p; } LOG_ERROR("flash bank %d does not exist", num); return NULL; } int flash_get_bank_count(void) { struct flash_bank *p; int i = 0; for (p = flash_banks; p; p = p->next) i++; return i; } struct flash_bank *get_flash_bank_by_name_noprobe(const char *name) { unsigned requested = get_flash_name_index(name); unsigned found = 0; struct flash_bank *bank; for (bank = flash_banks; NULL != bank; bank = bank->next) { if (strcmp(bank->name, name) == 0) return bank; if (!flash_driver_name_matches(bank->driver->name, name)) continue; if (++found < requested) continue; return bank; } return NULL; } int get_flash_bank_by_name(const char *name, struct flash_bank **bank_result) { struct flash_bank *bank; int retval; bank = get_flash_bank_by_name_noprobe(name); if (bank != NULL) { retval = bank->driver->auto_probe(bank); if (retval != ERROR_OK) { LOG_ERROR("auto_probe failed"); return retval; } } *bank_result = bank; return ERROR_OK; } int get_flash_bank_by_num(int num, struct flash_bank **bank) { struct flash_bank *p = get_flash_bank_by_num_noprobe(num); int retval; if (p == NULL) return ERROR_FAIL; retval = p->driver->auto_probe(p); if (retval != ERROR_OK) { LOG_ERROR("auto_probe failed"); return retval; } *bank = p; return ERROR_OK; } /* lookup flash bank by address, bank not found is success, but * result_bank is set to NULL. */ int get_flash_bank_by_addr(struct target *target, uint32_t addr, bool check, struct flash_bank **result_bank) { struct flash_bank *c; /* cycle through bank list */ for (c = flash_banks; c; c = c->next) { int retval; retval = c->driver->auto_probe(c); if (retval != ERROR_OK) { LOG_ERROR("auto_probe failed"); return retval; } /* check whether address belongs to this flash bank */ if ((addr >= c->base) && (addr <= c->base + (c->size - 1)) && target == c->target) { *result_bank = c; return ERROR_OK; } } *result_bank = NULL; if (check) { LOG_ERROR("No flash at address 0x%08" PRIx32, addr); return ERROR_FAIL; } return ERROR_OK; } static int default_flash_mem_blank_check(struct flash_bank *bank) { struct target *target = bank->target; const int buffer_size = 1024; int i; uint32_t nBytes; int retval = ERROR_OK; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } uint8_t *buffer = malloc(buffer_size); for (i = 0; i < bank->num_sectors; i++) { uint32_t j; bank->sectors[i].is_erased = 1; for (j = 0; j < bank->sectors[i].size; j += buffer_size) { uint32_t chunk; chunk = buffer_size; if (chunk > (j - bank->sectors[i].size)) chunk = (j - bank->sectors[i].size); retval = target_read_memory(target, bank->base + bank->sectors[i].offset + j, 4, chunk/4, buffer); if (retval != ERROR_OK) goto done; for (nBytes = 0; nBytes < chunk; nBytes++) { if (buffer[nBytes] != 0xFF) { bank->sectors[i].is_erased = 0; break; } } } } done: free(buffer); return retval; } int default_flash_blank_check(struct flash_bank *bank) { struct target *target = bank->target; int i; int retval; int fast_check = 0; uint32_t blank; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } for (i = 0; i < bank->num_sectors; i++) { uint32_t address = bank->base + bank->sectors[i].offset; uint32_t size = bank->sectors[i].size; retval = target_blank_check_memory(target, address, size, &blank); if (retval != ERROR_OK) { fast_check = 0; break; } if (blank == 0xFF) bank->sectors[i].is_erased = 1; else bank->sectors[i].is_erased = 0; fast_check = 1; } if (!fast_check) { LOG_USER("Running slow fallback erase check - add working memory"); return default_flash_mem_blank_check(bank); } return ERROR_OK; } /* Manipulate given flash region, selecting the bank according to target * and address. Maps an address range to a set of sectors, and issues * the callback() on that set ... e.g. to erase or unprotect its members. * * (Note a current bad assumption: that protection operates on the same * size sectors as erase operations use.) * * The "pad_reason" parameter is a kind of boolean: when it's NULL, the * range must fit those sectors exactly. This is clearly safe; it can't * erase data which the caller said to leave alone, for example. If it's * non-NULL, rather than failing, extra data in the first and/or last * sectors will be added to the range, and that reason string is used when * warning about those additions. */ static int flash_iterate_address_range_inner(struct target *target, char *pad_reason, uint32_t addr, uint32_t length, int (*callback)(struct flash_bank *bank, int first, int last)) { struct flash_bank *c; uint32_t last_addr = addr + length; /* first address AFTER end */ int first = -1; int last = -1; int i; int retval = get_flash_bank_by_addr(target, addr, true, &c); if (retval != ERROR_OK) return retval; if (c->size == 0 || c->num_sectors == 0) { LOG_ERROR("Bank is invalid"); return ERROR_FLASH_BANK_INVALID; } if (length == 0) { /* special case, erase whole bank when length is zero */ if (addr != c->base) { LOG_ERROR("Whole bank access must start at beginning of bank."); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } return callback(c, 0, c->num_sectors - 1); } /* check whether it all fits in this bank */ if (addr + length - 1 > c->base + c->size - 1) { LOG_ERROR("Flash access does not fit into bank."); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } /** @todo: handle erasures that cross into adjacent banks */ addr -= c->base; last_addr -= c->base; for (i = 0; i < c->num_sectors; i++) { struct flash_sector *f = c->sectors + i; uint32_t end = f->offset + f->size; /* start only on a sector boundary */ if (first < 0) { /* scanned past the first sector? */ if (addr < f->offset) break; /* is this the first sector? */ if (addr == f->offset) first = i; /* Does this need head-padding? If so, pad and warn; * or else force an error. * * Such padding can make trouble, since *WE* can't * ever know if that data was in use. The warning * should help users sort out messes later. */ else if (addr < end && pad_reason) { /* FIXME say how many bytes (e.g. 80 KB) */ LOG_WARNING("Adding extra %s range, " "%#8.8x to %#8.8x", pad_reason, (unsigned) f->offset, (unsigned) addr - 1); first = i; } else continue; } /* is this (also?) the last sector? */ if (last_addr == end) { last = i; break; } /* Does this need tail-padding? If so, pad and warn; * or else force an error. */ if (last_addr < end && pad_reason) { /* FIXME say how many bytes (e.g. 80 KB) */ LOG_WARNING("Adding extra %s range, " "%#8.8x to %#8.8x", pad_reason, (unsigned) last_addr, (unsigned) end - 1); last = i; break; } /* MUST finish on a sector boundary */ if (last_addr <= f->offset) break; } /* invalid start or end address? */ if (first == -1 || last == -1) { LOG_ERROR("address range 0x%8.8x .. 0x%8.8x " "is not sector-aligned", (unsigned) (c->base + addr), (unsigned) (c->base + last_addr - 1)); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } /* The NOR driver may trim this range down, based on what * sectors are already erased/unprotected. GDB currently * blocks such optimizations. */ return callback(c, first, last); } /* The inner fn only handles a single bank, we could be spanning * multiple chips. */ static int flash_iterate_address_range(struct target *target, char *pad_reason, uint32_t addr, uint32_t length, int (*callback)(struct flash_bank *bank, int first, int last)) { struct flash_bank *c; int retval = ERROR_OK; /* Danger! zero-length iterations means entire bank! */ do { retval = get_flash_bank_by_addr(target, addr, true, &c); if (retval != ERROR_OK) return retval; uint32_t cur_length = length; /* check whether it all fits in this bank */ if (addr + length - 1 > c->base + c->size - 1) { LOG_DEBUG("iterating over more than one flash bank."); cur_length = c->base + c->size - addr; } retval = flash_iterate_address_range_inner(target, pad_reason, addr, cur_length, callback); if (retval != ERROR_OK) break; length -= cur_length; addr += cur_length; } while (length > 0); return retval; } int flash_erase_address_range(struct target *target, bool pad, uint32_t addr, uint32_t length) { return flash_iterate_address_range(target, pad ? "erase" : NULL, addr, length, &flash_driver_erase); } static int flash_driver_unprotect(struct flash_bank *bank, int first, int last) { return flash_driver_protect(bank, 0, first, last); } int flash_unlock_address_range(struct target *target, uint32_t addr, uint32_t length) { /* By default, pad to sector boundaries ... the real issue here * is that our (only) caller *permanently* removes protection, * and doesn't restore it. */ return flash_iterate_address_range(target, "unprotect", addr, length, &flash_driver_unprotect); } static int compare_section(const void *a, const void *b) { struct imagesection *b1, *b2; b1 = *((struct imagesection **)a); b2 = *((struct imagesection **)b); if (b1->base_address == b2->base_address) return 0; else if (b1->base_address > b2->base_address) return 1; else return -1; } int flash_write_unlock(struct target *target, struct image *image, uint32_t *written, int erase, bool unlock) { int retval = ERROR_OK; int section; uint32_t section_offset; struct flash_bank *c; int *padding; section = 0; section_offset = 0; if (written) *written = 0; if (erase) { /* assume all sectors need erasing - stops any problems * when flash_write is called multiple times */ flash_set_dirty(); } /* allocate padding array */ padding = calloc(image->num_sections, sizeof(*padding)); /* This fn requires all sections to be in ascending order of addresses, * whereas an image can have sections out of order. */ struct imagesection **sections = malloc(sizeof(struct imagesection *) * image->num_sections); int i; for (i = 0; i < image->num_sections; i++) sections[i] = &image->sections[i]; qsort(sections, image->num_sections, sizeof(struct imagesection *), compare_section); /* loop until we reach end of the image */ while (section < image->num_sections) { uint32_t buffer_size; uint8_t *buffer; int section_last; uint32_t run_address = sections[section]->base_address + section_offset; uint32_t run_size = sections[section]->size - section_offset; int pad_bytes = 0; if (sections[section]->size == 0) { LOG_WARNING("empty section %d", section); section++; section_offset = 0; continue; } /* find the corresponding flash bank */ retval = get_flash_bank_by_addr(target, run_address, false, &c); if (retval != ERROR_OK) goto done; if (c == NULL) { LOG_WARNING("no flash bank found for address %x", run_address); section++; /* and skip it */ section_offset = 0; continue; } /* collect consecutive sections which fall into the same bank */ section_last = section; padding[section] = 0; while ((run_address + run_size - 1 < c->base + c->size - 1) && (section_last + 1 < image->num_sections)) { /* sections are sorted */ assert(sections[section_last + 1]->base_address >= c->base); if (sections[section_last + 1]->base_address >= (c->base + c->size)) { /* Done with this bank */ break; } /* FIXME This needlessly touches sectors BETWEEN the * sections it's writing. Without auto erase, it just * writes ones. That WILL INVALIDATE data in cases * like Stellaris Tempest chips, corrupting internal * ECC codes; and at least FreeScale suggests issues * with that approach (in HC11 documentation). * * With auto erase enabled, data in those sectors will * be needlessly destroyed; and some of the limited * number of flash erase cycles will be wasted... * * In both cases, the extra writes slow things down. */ /* if we have multiple sections within our image, * flash programming could fail due to alignment issues * attempt to rebuild a consecutive buffer for the flash loader */ pad_bytes = (sections[section_last + 1]->base_address) - (run_address + run_size); padding[section_last] = pad_bytes; run_size += sections[++section_last]->size; run_size += pad_bytes; if (pad_bytes > 0) LOG_INFO("Padding image section %d with %d bytes", section_last-1, pad_bytes); } if (run_address + run_size - 1 > c->base + c->size - 1) { /* If we have more than one flash chip back to back, then we limit * the current write operation to the current chip. */ LOG_DEBUG("Truncate flash run size to the current flash chip."); run_size = c->base + c->size - run_address; assert(run_size > 0); } /* If we're applying any sector automagic, then pad this * (maybe-combined) segment to the end of its last sector. */ if (unlock || erase) { int sector; uint32_t offset_start = run_address - c->base; uint32_t offset_end = offset_start + run_size; uint32_t end = offset_end, delta; for (sector = 0; sector < c->num_sectors; sector++) { end = c->sectors[sector].offset + c->sectors[sector].size; if (offset_end <= end) break; } delta = end - offset_end; padding[section_last] += delta; run_size += delta; } /* allocate buffer */ buffer = malloc(run_size); if (buffer == NULL) { LOG_ERROR("Out of memory for flash bank buffer"); retval = ERROR_FAIL; goto done; } buffer_size = 0; /* read sections to the buffer */ while (buffer_size < run_size) { size_t size_read; size_read = run_size - buffer_size; if (size_read > sections[section]->size - section_offset) size_read = sections[section]->size - section_offset; /* KLUDGE! * * #¤%#"%¤% we have to figure out the section # from the sorted * list of pointers to sections to invoke image_read_section()... */ intptr_t diff = (intptr_t)sections[section] - (intptr_t)image->sections; int t_section_num = diff / sizeof(struct imagesection); LOG_DEBUG("image_read_section: section = %d, t_section_num = %d, " "section_offset = %d, buffer_size = %d, size_read = %d", (int)section, (int)t_section_num, (int)section_offset, (int)buffer_size, (int)size_read); retval = image_read_section(image, t_section_num, section_offset, size_read, buffer + buffer_size, &size_read); if (retval != ERROR_OK || size_read == 0) { free(buffer); goto done; } /* see if we need to pad the section */ while (padding[section]--) (buffer + buffer_size)[size_read++] = 0xff; buffer_size += size_read; section_offset += size_read; if (section_offset >= sections[section]->size) { section++; section_offset = 0; } } retval = ERROR_OK; if (unlock) retval = flash_unlock_address_range(target, run_address, run_size); if (retval == ERROR_OK) { if (erase) { /* calculate and erase sectors */ retval = flash_erase_address_range(target, true, run_address, run_size); } } if (retval == ERROR_OK) { /* write flash sectors */ retval = flash_driver_write(c, buffer, run_address - c->base, run_size); } free(buffer); if (retval != ERROR_OK) { /* abort operation */ goto done; } if (written != NULL) *written += run_size; /* add run size to total written counter */ } done: free(sections); free(padding); return retval; } int flash_write(struct target *target, struct image *image, uint32_t *written, int erase) { return flash_write_unlock(target, image, written, erase, false); } openocd-0.7.0/src/flash/nor/str7x.c0000644000175000001440000005517112134336410014005 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2010 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include #include #include /* Flash registers */ #define FLASH_CR0 0x00000000 #define FLASH_CR1 0x00000004 #define FLASH_DR0 0x00000008 #define FLASH_DR1 0x0000000C #define FLASH_AR 0x00000010 #define FLASH_ER 0x00000014 #define FLASH_NVWPAR 0x0000DFB0 #define FLASH_NVAPR0 0x0000DFB8 #define FLASH_NVAPR1 0x0000DFBC /* FLASH_CR0 register bits */ #define FLASH_WMS 0x80000000 #define FLASH_SUSP 0x40000000 #define FLASH_WPG 0x20000000 #define FLASH_DWPG 0x10000000 #define FLASH_SER 0x08000000 #define FLASH_SPR 0x01000000 #define FLASH_BER 0x04000000 #define FLASH_MER 0x02000000 #define FLASH_LOCK 0x00000010 #define FLASH_BSYA1 0x00000004 #define FLASH_BSYA0 0x00000002 /* FLASH_CR1 register bits */ #define FLASH_B1S 0x02000000 #define FLASH_B0S 0x01000000 #define FLASH_B1F1 0x00020000 #define FLASH_B1F0 0x00010000 #define FLASH_B0F7 0x00000080 #define FLASH_B0F6 0x00000040 #define FLASH_B0F5 0x00000020 #define FLASH_B0F4 0x00000010 #define FLASH_B0F3 0x00000008 #define FLASH_B0F2 0x00000004 #define FLASH_B0F1 0x00000002 #define FLASH_B0F0 0x00000001 /* FLASH_ER register bits */ #define FLASH_WPF 0x00000100 #define FLASH_RESER 0x00000080 #define FLASH_SEQER 0x00000040 #define FLASH_10ER 0x00000008 #define FLASH_PGER 0x00000004 #define FLASH_ERER 0x00000002 #define FLASH_ERR 0x00000001 struct str7x_flash_bank { uint32_t *sector_bits; uint32_t disable_bit; uint32_t busy_bits; uint32_t register_base; }; struct str7x_mem_layout { uint32_t sector_start; uint32_t sector_size; uint32_t sector_bit; }; enum str7x_status_codes { STR7X_CMD_SUCCESS = 0, STR7X_INVALID_COMMAND = 1, STR7X_SRC_ADDR_ERROR = 2, STR7X_DST_ADDR_ERROR = 3, STR7X_SRC_ADDR_NOT_MAPPED = 4, STR7X_DST_ADDR_NOT_MAPPED = 5, STR7X_COUNT_ERROR = 6, STR7X_INVALID_SECTOR = 7, STR7X_SECTOR_NOT_BLANK = 8, STR7X_SECTOR_NOT_PREPARED = 9, STR7X_COMPARE_ERROR = 10, STR7X_BUSY = 11 }; static struct str7x_mem_layout mem_layout_str7bank0[] = { {0x00000000, 0x02000, 0x01}, {0x00002000, 0x02000, 0x02}, {0x00004000, 0x02000, 0x04}, {0x00006000, 0x02000, 0x08}, {0x00008000, 0x08000, 0x10}, {0x00010000, 0x10000, 0x20}, {0x00020000, 0x10000, 0x40}, {0x00030000, 0x10000, 0x80} }; static struct str7x_mem_layout mem_layout_str7bank1[] = { {0x00000000, 0x02000, 0x10000}, {0x00002000, 0x02000, 0x20000} }; static int str7x_get_flash_adr(struct flash_bank *bank, uint32_t reg) { struct str7x_flash_bank *str7x_info = bank->driver_priv; return str7x_info->register_base | reg; } static int str7x_build_block_list(struct flash_bank *bank) { struct str7x_flash_bank *str7x_info = bank->driver_priv; int i; int num_sectors; int b0_sectors = 0, b1_sectors = 0; switch (bank->size) { case 16 * 1024: b1_sectors = 2; break; case 64 * 1024: b0_sectors = 5; break; case 128 * 1024: b0_sectors = 6; break; case 256 * 1024: b0_sectors = 8; break; default: LOG_ERROR("BUG: unknown bank->size encountered"); exit(-1); } num_sectors = b0_sectors + b1_sectors; bank->num_sectors = num_sectors; bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors); str7x_info->sector_bits = malloc(sizeof(uint32_t) * num_sectors); num_sectors = 0; for (i = 0; i < b0_sectors; i++) { bank->sectors[num_sectors].offset = mem_layout_str7bank0[i].sector_start; bank->sectors[num_sectors].size = mem_layout_str7bank0[i].sector_size; bank->sectors[num_sectors].is_erased = -1; /* the reset_init handler marks all the sectors unprotected, * matching hardware after reset; keep the driver in sync */ bank->sectors[num_sectors].is_protected = 0; str7x_info->sector_bits[num_sectors++] = mem_layout_str7bank0[i].sector_bit; } for (i = 0; i < b1_sectors; i++) { bank->sectors[num_sectors].offset = mem_layout_str7bank1[i].sector_start; bank->sectors[num_sectors].size = mem_layout_str7bank1[i].sector_size; bank->sectors[num_sectors].is_erased = -1; /* the reset_init handler marks all the sectors unprotected, * matching hardware after reset; keep the driver in sync */ bank->sectors[num_sectors].is_protected = 0; str7x_info->sector_bits[num_sectors++] = mem_layout_str7bank1[i].sector_bit; } return ERROR_OK; } /* flash bank str7x 0 0 */ FLASH_BANK_COMMAND_HANDLER(str7x_flash_bank_command) { struct str7x_flash_bank *str7x_info; if (CMD_ARGC < 7) return ERROR_COMMAND_SYNTAX_ERROR; str7x_info = malloc(sizeof(struct str7x_flash_bank)); bank->driver_priv = str7x_info; /* set default bits for str71x flash */ str7x_info->busy_bits = (FLASH_LOCK | FLASH_BSYA1 | FLASH_BSYA0); str7x_info->disable_bit = (1 << 1); if (strcmp(CMD_ARGV[6], "STR71x") == 0) str7x_info->register_base = 0x40100000; else if (strcmp(CMD_ARGV[6], "STR73x") == 0) { str7x_info->register_base = 0x80100000; str7x_info->busy_bits = (FLASH_LOCK | FLASH_BSYA0); } else if (strcmp(CMD_ARGV[6], "STR75x") == 0) { str7x_info->register_base = 0x20100000; str7x_info->disable_bit = (1 << 0); } else { LOG_ERROR("unknown STR7x variant: '%s'", CMD_ARGV[6]); free(str7x_info); return ERROR_FLASH_BANK_INVALID; } str7x_build_block_list(bank); return ERROR_OK; } /* wait for flash to become idle or report errors. FIX!!! what's the maximum timeout??? The documentation doesn't state any maximum time.... by inspection it seems > 1000ms is to be expected. 10000ms is long enough that it should cover anything, yet not quite be equivalent to an infinite loop. */ static int str7x_waitbusy(struct flash_bank *bank) { int err; int i; struct target *target = bank->target; struct str7x_flash_bank *str7x_info = bank->driver_priv; for (i = 0 ; i < 10000; i++) { uint32_t retval; err = target_read_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), &retval); if (err != ERROR_OK) return err; if ((retval & str7x_info->busy_bits) == 0) return ERROR_OK; alive_sleep(1); } LOG_ERROR("Timed out waiting for str7x flash"); return ERROR_FAIL; } static int str7x_result(struct flash_bank *bank) { struct target *target = bank->target; uint32_t flash_flags; int retval; retval = target_read_u32(target, str7x_get_flash_adr(bank, FLASH_ER), &flash_flags); if (retval != ERROR_OK) return retval; if (flash_flags & FLASH_WPF) { LOG_ERROR("str7x hw write protection set"); retval = ERROR_FAIL; } if (flash_flags & FLASH_RESER) { LOG_ERROR("str7x suspended program erase not resumed"); retval = ERROR_FAIL; } if (flash_flags & FLASH_10ER) { LOG_ERROR("str7x trying to set bit to 1 when it is already 0"); retval = ERROR_FAIL; } if (flash_flags & FLASH_PGER) { LOG_ERROR("str7x program error"); retval = ERROR_FAIL; } if (flash_flags & FLASH_ERER) { LOG_ERROR("str7x erase error"); retval = ERROR_FAIL; } if (retval == ERROR_OK) { if (flash_flags & FLASH_ERR) { /* this should always be set if one of the others are set... */ LOG_ERROR("str7x write operation failed / bad setup"); retval = ERROR_FAIL; } } return retval; } static int str7x_protect_check(struct flash_bank *bank) { struct str7x_flash_bank *str7x_info = bank->driver_priv; struct target *target = bank->target; int i; uint32_t flash_flags; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } int retval; retval = target_read_u32(target, str7x_get_flash_adr(bank, FLASH_NVWPAR), &flash_flags); if (retval != ERROR_OK) return retval; for (i = 0; i < bank->num_sectors; i++) { if (flash_flags & str7x_info->sector_bits[i]) bank->sectors[i].is_protected = 0; else bank->sectors[i].is_protected = 1; } return ERROR_OK; } static int str7x_erase(struct flash_bank *bank, int first, int last) { struct str7x_flash_bank *str7x_info = bank->driver_priv; struct target *target = bank->target; int i; uint32_t cmd; uint32_t sectors = 0; int err; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } for (i = first; i <= last; i++) sectors |= str7x_info->sector_bits[i]; LOG_DEBUG("sectors: 0x%" PRIx32 "", sectors); /* clear FLASH_ER register */ err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_ER), 0x0); if (err != ERROR_OK) return err; cmd = FLASH_SER; err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd); if (err != ERROR_OK) return err; cmd = sectors; err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR1), cmd); if (err != ERROR_OK) return err; cmd = FLASH_SER | FLASH_WMS; err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd); if (err != ERROR_OK) return err; err = str7x_waitbusy(bank); if (err != ERROR_OK) return err; err = str7x_result(bank); if (err != ERROR_OK) return err; for (i = first; i <= last; i++) bank->sectors[i].is_erased = 1; return ERROR_OK; } static int str7x_protect(struct flash_bank *bank, int set, int first, int last) { struct str7x_flash_bank *str7x_info = bank->driver_priv; struct target *target = bank->target; int i; uint32_t cmd; uint32_t protect_blocks; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } protect_blocks = 0xFFFFFFFF; if (set) { for (i = first; i <= last; i++) protect_blocks &= ~(str7x_info->sector_bits[i]); } /* clear FLASH_ER register */ int err; err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_ER), 0x0); if (err != ERROR_OK) return err; cmd = FLASH_SPR; err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd); if (err != ERROR_OK) return err; cmd = str7x_get_flash_adr(bank, FLASH_NVWPAR); err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), cmd); if (err != ERROR_OK) return err; cmd = protect_blocks; err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_DR0), cmd); if (err != ERROR_OK) return err; cmd = FLASH_SPR | FLASH_WMS; err = target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd); if (err != ERROR_OK) return err; err = str7x_waitbusy(bank); if (err != ERROR_OK) return err; err = str7x_result(bank); if (err != ERROR_OK) return err; return ERROR_OK; } static int str7x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct str7x_flash_bank *str7x_info = bank->driver_priv; struct target *target = bank->target; uint32_t buffer_size = 32768; struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[6]; struct arm_algorithm arm_algo; int retval = ERROR_OK; /* see contib/loaders/flash/str7x.s for src */ static const uint32_t str7x_flash_write_code[] = { /* write: */ 0xe3a04201, /* mov r4, #0x10000000 */ 0xe5824000, /* str r4, [r2, #0x0] */ 0xe5821010, /* str r1, [r2, #0x10] */ 0xe4904004, /* ldr r4, [r0], #4 */ 0xe5824008, /* str r4, [r2, #0x8] */ 0xe4904004, /* ldr r4, [r0], #4 */ 0xe582400c, /* str r4, [r2, #0xc] */ 0xe3a04209, /* mov r4, #0x90000000 */ 0xe5824000, /* str r4, [r2, #0x0] */ /* busy: */ 0xe5924000, /* ldr r4, [r2, #0x0] */ 0xe1140005, /* tst r4, r5 */ 0x1afffffc, /* bne busy */ 0xe5924014, /* ldr r4, [r2, #0x14] */ 0xe31400ff, /* tst r4, #0xff */ 0x03140c01, /* tsteq r4, #0x100 */ 0x1a000002, /* bne exit */ 0xe2811008, /* add r1, r1, #0x8 */ 0xe2533001, /* subs r3, r3, #1 */ 0x1affffec, /* bne write */ /* exit: */ 0xeafffffe, /* b exit */ }; /* flash write code */ if (target_alloc_working_area_try(target, sizeof(str7x_flash_write_code), &write_algorithm) != ERROR_OK) { return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; }; target_write_buffer(target, write_algorithm->address, sizeof(str7x_flash_write_code), (uint8_t *)str7x_flash_write_code); /* memory buffer */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; if (buffer_size <= 256) { /* we already allocated the writing code, but failed to get a * buffer, free the algorithm */ target_free_working_area(target, write_algorithm); LOG_WARNING("no large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_OUT); init_reg_param(®_params[4], "r4", 32, PARAM_IN); init_reg_param(®_params[5], "r5", 32, PARAM_OUT); while (count > 0) { uint32_t thisrun_count = (count > (buffer_size / 8)) ? (buffer_size / 8) : count; target_write_buffer(target, source->address, thisrun_count * 8, buffer); buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, address); buf_set_u32(reg_params[2].value, 0, 32, str7x_get_flash_adr(bank, FLASH_CR0)); buf_set_u32(reg_params[3].value, 0, 32, thisrun_count); buf_set_u32(reg_params[5].value, 0, 32, str7x_info->busy_bits); retval = target_run_algorithm(target, 0, NULL, 6, reg_params, write_algorithm->address, write_algorithm->address + (sizeof(str7x_flash_write_code) - 4), 10000, &arm_algo); if (retval != ERROR_OK) break; if (buf_get_u32(reg_params[4].value, 0, 32) != 0x00) { retval = str7x_result(bank); break; } buffer += thisrun_count * 8; address += thisrun_count * 8; count -= thisrun_count; } target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); destroy_reg_param(®_params[5]); return retval; } static int str7x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t dwords_remaining = (count / 8); uint32_t bytes_remaining = (count & 0x00000007); uint32_t address = bank->base + offset; uint32_t bytes_written = 0; uint32_t cmd; int retval; uint32_t check_address = offset; int i; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset & 0x7) { LOG_WARNING("offset 0x%" PRIx32 " breaks required 8-byte alignment", offset); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } for (i = 0; i < bank->num_sectors; i++) { uint32_t sec_start = bank->sectors[i].offset; uint32_t sec_end = sec_start + bank->sectors[i].size; /* check if destination falls within the current sector */ if ((check_address >= sec_start) && (check_address < sec_end)) { /* check if destination ends in the current sector */ if (offset + count < sec_end) check_address = offset + count; else check_address = sec_end; } } if (check_address != offset + count) return ERROR_FLASH_DST_OUT_OF_BANK; /* clear FLASH_ER register */ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_ER), 0x0); /* multiple dwords (8-byte) to be programmed? */ if (dwords_remaining > 0) { /* try using a block write */ retval = str7x_write_block(bank, buffer, offset, dwords_remaining); if (retval != ERROR_OK) { if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* if block write failed (no sufficient working area), * we use normal (slow) single dword accesses */ LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); } else { return retval; } } else { buffer += dwords_remaining * 8; address += dwords_remaining * 8; dwords_remaining = 0; } } while (dwords_remaining > 0) { /* command */ cmd = FLASH_DWPG; target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd); /* address */ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), address); /* data word 1 */ target_write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, buffer + bytes_written); bytes_written += 4; /* data word 2 */ target_write_memory(target, str7x_get_flash_adr(bank, FLASH_DR1), 4, 1, buffer + bytes_written); bytes_written += 4; /* start programming cycle */ cmd = FLASH_DWPG | FLASH_WMS; target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd); int err; err = str7x_waitbusy(bank); if (err != ERROR_OK) return err; err = str7x_result(bank); if (err != ERROR_OK) return err; dwords_remaining--; address += 8; } if (bytes_remaining) { uint8_t last_dword[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; /* copy the last remaining bytes into the write buffer */ memcpy(last_dword, buffer+bytes_written, bytes_remaining); /* command */ cmd = FLASH_DWPG; target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd); /* address */ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), address); /* data word 1 */ target_write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, last_dword); /* data word 2 */ target_write_memory(target, str7x_get_flash_adr(bank, FLASH_DR1), 4, 1, last_dword + 4); /* start programming cycle */ cmd = FLASH_DWPG | FLASH_WMS; target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd); int err; err = str7x_waitbusy(bank); if (err != ERROR_OK) return err; err = str7x_result(bank); if (err != ERROR_OK) return err; } return ERROR_OK; } static int str7x_probe(struct flash_bank *bank) { return ERROR_OK; } #if 0 COMMAND_HANDLER(str7x_handle_part_id_command) { return ERROR_OK; } #endif static int get_str7x_info(struct flash_bank *bank, char *buf, int buf_size) { snprintf(buf, buf_size, "str7x flash driver info"); /* STR7x flash doesn't support sector protection interrogation. * FLASH_NVWPAR acts as a write only register; its read value * doesn't reflect the actual protection state of the sectors. */ LOG_WARNING("STR7x flash lock information might not be correct " "due to hardware limitations."); return ERROR_OK; } COMMAND_HANDLER(str7x_handle_disable_jtag_command) { struct target *target = NULL; struct str7x_flash_bank *str7x_info = NULL; uint32_t flash_cmd; uint16_t ProtectionLevel = 0; uint16_t ProtectionRegs; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; str7x_info = bank->driver_priv; target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* first we get protection status */ uint32_t reg; target_read_u32(target, str7x_get_flash_adr(bank, FLASH_NVAPR0), ®); if (!(reg & str7x_info->disable_bit)) ProtectionLevel = 1; target_read_u32(target, str7x_get_flash_adr(bank, FLASH_NVAPR1), ®); ProtectionRegs = ~(reg >> 16); while (((ProtectionRegs) != 0) && (ProtectionLevel < 16)) { ProtectionRegs >>= 1; ProtectionLevel++; } if (ProtectionLevel == 0) { flash_cmd = FLASH_SPR; target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd); target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), 0x4010DFB8); target_write_u32(target, str7x_get_flash_adr(bank, FLASH_DR0), 0xFFFFFFFD); flash_cmd = FLASH_SPR | FLASH_WMS; target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd); } else { flash_cmd = FLASH_SPR; target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd); target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), 0x4010DFBC); target_write_u32(target, str7x_get_flash_adr(bank, FLASH_DR0), ~(1 << (15 + ProtectionLevel))); flash_cmd = FLASH_SPR | FLASH_WMS; target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), flash_cmd); } return ERROR_OK; } static const struct command_registration str7x_exec_command_handlers[] = { { .name = "disable_jtag", .usage = "", .handler = str7x_handle_disable_jtag_command, .mode = COMMAND_EXEC, .help = "disable jtag access", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration str7x_command_handlers[] = { { .name = "str7x", .mode = COMMAND_ANY, .help = "str7x flash command group", .usage = "", .chain = str7x_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct flash_driver str7x_flash = { .name = "str7x", .commands = str7x_command_handlers, .flash_bank_command = str7x_flash_bank_command, .erase = str7x_erase, .protect = str7x_protect, .write = str7x_write, .read = default_flash_read, .probe = str7x_probe, .auto_probe = str7x_probe, .erase_check = default_flash_blank_check, .protect_check = str7x_protect_check, .info = get_str7x_info, }; openocd-0.7.0/src/flash/nor/lpcspifi.c0000644000175000001440000007771712137151331014541 00000000000000/*************************************************************************** * Copyright (C) 2012 by George Harris * * george@luminairecoffee.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "spi.h" #include #include #include #include /* Offsets from ssp_base into config & data registers */ #define SSP_CR0 (0x00) /* Control register 0 */ #define SSP_CR1 (0x04) /* Control register 1 */ #define SSP_DATA (0x08) /* Data register (TX and RX) */ #define SSP_SR (0x0C) /* Status register */ #define SSP_CPSR (0x10) /* Clock prescale register */ /* Status register fields */ #define SSP_BSY (0x00000010) /* Timeout in ms */ #define SSP_CMD_TIMEOUT (100) #define SSP_PROBE_TIMEOUT (100) #define SSP_MAX_TIMEOUT (3000) struct lpcspifi_flash_bank { int probed; uint32_t ssp_base; uint32_t io_base; uint32_t ioconfig_base; uint32_t bank_num; uint32_t max_spi_clock_mhz; struct flash_device *dev; }; struct lpcspifi_target { char *name; uint32_t tap_idcode; uint32_t spifi_base; uint32_t ssp_base; uint32_t io_base; uint32_t ioconfig_base; /* base address for the port word pin registers */ }; static struct lpcspifi_target target_devices[] = { /* name, tap_idcode, spifi_base, ssp_base, io_base, ioconfig_base */ { "LPC43xx/18xx", 0x4ba00477, 0x14000000, 0x40083000, 0x400F4000, 0x40086000 }, { NULL, 0, 0, 0, 0, 0 } }; /* flash_bank lpcspifi */ FLASH_BANK_COMMAND_HANDLER(lpcspifi_flash_bank_command) { struct lpcspifi_flash_bank *lpcspifi_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; lpcspifi_info = malloc(sizeof(struct lpcspifi_flash_bank)); if (lpcspifi_info == NULL) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } bank->driver_priv = lpcspifi_info; lpcspifi_info->probed = 0; return ERROR_OK; } static inline int ioconfig_write_reg(struct target *target, uint32_t ioconfig_base, uint32_t offset, uint32_t value) { return target_write_u32(target, ioconfig_base + offset, value); } static inline int ssp_write_reg(struct target *target, uint32_t ssp_base, uint32_t offset, uint32_t value) { return target_write_u32(target, ssp_base + offset, value); } static inline int io_write_reg(struct target *target, uint32_t io_base, uint32_t offset, uint32_t value) { return target_write_u32(target, io_base + offset, value); } static inline int ssp_read_reg(struct target *target, uint32_t ssp_base, uint32_t offset, uint32_t *value) { return target_read_u32(target, ssp_base + offset, value); } static int ssp_setcs(struct target *target, uint32_t io_base, unsigned int value) { return io_write_reg(target, io_base, 0x12ac, value ? 0xffffffff : 0x00000000); } /* Poll the SSP busy flag. When this comes back as 0, the transfer is complete * and the controller is idle. */ static int poll_ssp_busy(struct target *target, uint32_t ssp_base, int timeout) { long long endtime; uint32_t value; int retval; retval = ssp_read_reg(target, ssp_base, SSP_SR, &value); if ((retval == ERROR_OK) && (value & SSP_BSY) == 0) return ERROR_OK; else if (retval != ERROR_OK) return retval; endtime = timeval_ms() + timeout; do { alive_sleep(1); retval = ssp_read_reg(target, ssp_base, SSP_SR, &value); if ((retval == ERROR_OK) && (value & SSP_BSY) == 0) return ERROR_OK; else if (retval != ERROR_OK) return retval; } while (timeval_ms() < endtime); LOG_ERROR("Timeout while polling BSY"); return ERROR_FLASH_OPERATION_FAILED; } /* Un-initialize the ssp module and initialize the SPIFI module */ static int lpcspifi_set_hw_mode(struct flash_bank *bank) { struct target *target = bank->target; struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv; uint32_t ssp_base = lpcspifi_info->ssp_base; struct armv7m_algorithm armv7m_info; struct working_area *spifi_init_algorithm; struct reg_param reg_params[1]; int retval = ERROR_OK; LOG_DEBUG("Uninitializing LPC43xx SSP"); /* Turn off the SSP module */ retval = ssp_write_reg(target, ssp_base, SSP_CR1, 0x00000000); if (retval != ERROR_OK) return retval; /* see contrib/loaders/flash/lpcspifi_init.S for src */ static const uint8_t spifi_init_code[] = { 0x4f, 0xea, 0x00, 0x08, 0xa1, 0xb0, 0x00, 0xaf, 0x4f, 0xf4, 0xc0, 0x43, 0xc4, 0xf2, 0x08, 0x03, 0x4f, 0xf0, 0xf3, 0x02, 0xc3, 0xf8, 0x8c, 0x21, 0x4f, 0xf4, 0xc0, 0x43, 0xc4, 0xf2, 0x08, 0x03, 0x4f, 0xf4, 0xc0, 0x42, 0xc4, 0xf2, 0x08, 0x02, 0x4f, 0xf4, 0xc0, 0x41, 0xc4, 0xf2, 0x08, 0x01, 0x4f, 0xf4, 0xc0, 0x40, 0xc4, 0xf2, 0x08, 0x00, 0x4f, 0xf0, 0xd3, 0x04, 0xc0, 0xf8, 0x9c, 0x41, 0x20, 0x46, 0xc1, 0xf8, 0x98, 0x01, 0x01, 0x46, 0xc2, 0xf8, 0x94, 0x11, 0xc3, 0xf8, 0x90, 0x11, 0x4f, 0xf4, 0xc0, 0x43, 0xc4, 0xf2, 0x08, 0x03, 0x4f, 0xf0, 0x13, 0x02, 0xc3, 0xf8, 0xa0, 0x21, 0x40, 0xf2, 0x18, 0x13, 0xc1, 0xf2, 0x40, 0x03, 0x1b, 0x68, 0x1c, 0x68, 0x40, 0xf2, 0xb4, 0x30, 0xc1, 0xf2, 0x00, 0x00, 0x4f, 0xf0, 0x03, 0x01, 0x4f, 0xf0, 0xc0, 0x02, 0x4f, 0xea, 0x08, 0x03, 0xa0, 0x47, 0x00, 0xf0, 0x00, 0xb8, 0x00, 0xbe }; armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; LOG_DEBUG("Allocating working area for SPIFI init algorithm"); /* Get memory for spifi initialization algorithm */ retval = target_alloc_working_area(target, sizeof(spifi_init_code), &spifi_init_algorithm); if (retval != ERROR_OK) { LOG_ERROR("Insufficient working area to initialize SPIFI "\ "module. You must allocate at least %zdB of working "\ "area in order to use this driver.", sizeof(spifi_init_code) ); return retval; } LOG_DEBUG("Writing algorithm to working area at 0x%08x", spifi_init_algorithm->address); /* Write algorithm to working area */ retval = target_write_buffer(target, spifi_init_algorithm->address, sizeof(spifi_init_code), spifi_init_code ); if (retval != ERROR_OK) { target_free_working_area(target, spifi_init_algorithm); return retval; } init_reg_param(®_params[0], "r0", 32, PARAM_OUT); /* spifi clk speed */ /* For now, the algorithm will set up the SPIFI module * @ the IRC clock speed. In the future, it could be made * a bit smarter to use other clock sources if the user has * already configured them in order to speed up memory- * mapped reads. */ buf_set_u32(reg_params[0].value, 0, 32, 12); /* Run the algorithm */ LOG_DEBUG("Running SPIFI init algorithm"); retval = target_run_algorithm(target, 0 , NULL, 1, reg_params, spifi_init_algorithm->address, spifi_init_algorithm->address + sizeof(spifi_init_code) - 2, 1000, &armv7m_info); if (retval != ERROR_OK) LOG_ERROR("Error executing SPIFI init algorithm"); target_free_working_area(target, spifi_init_algorithm); destroy_reg_param(®_params[0]); return retval; } /* Initialize the ssp module */ static int lpcspifi_set_sw_mode(struct flash_bank *bank) { struct target *target = bank->target; struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv; uint32_t ssp_base = lpcspifi_info->ssp_base; uint32_t io_base = lpcspifi_info->io_base; uint32_t ioconfig_base = lpcspifi_info->ioconfig_base; int retval = ERROR_OK; /* Re-initialize SPIFI. There are a couple of errata on this, so this makes sure that nothing's in an unhappy state. */ retval = lpcspifi_set_hw_mode(bank); /* If we couldn't initialize hardware mode, don't even bother continuing */ if (retval != ERROR_OK) return retval; /* Initialize the pins */ retval = ioconfig_write_reg(target, ioconfig_base, 0x194, 0x00000040); if (retval == ERROR_OK) retval = ioconfig_write_reg(target, ioconfig_base, 0x1a0, 0x00000044); if (retval == ERROR_OK) retval = ioconfig_write_reg(target, ioconfig_base, 0x190, 0x00000040); if (retval == ERROR_OK) retval = ioconfig_write_reg(target, ioconfig_base, 0x19c, 0x000000ed); if (retval == ERROR_OK) retval = ioconfig_write_reg(target, ioconfig_base, 0x198, 0x000000ed); if (retval == ERROR_OK) retval = ioconfig_write_reg(target, ioconfig_base, 0x18c, 0x000000ea); /* Set CS high & as an output */ if (retval == ERROR_OK) retval = io_write_reg(target, io_base, 0x12ac, 0xffffffff); if (retval == ERROR_OK) retval = io_write_reg(target, io_base, 0x2014, 0x00000800); /* Initialize the module */ if (retval == ERROR_OK) retval = ssp_write_reg(target, ssp_base, SSP_CR0, 0x00000007); if (retval == ERROR_OK) retval = ssp_write_reg(target, ssp_base, SSP_CR1, 0x00000000); if (retval == ERROR_OK) retval = ssp_write_reg(target, ssp_base, SSP_CPSR, 0x00000008); if (retval == ERROR_OK) retval = ssp_write_reg(target, ssp_base, SSP_CR1, 0x00000002); /* If something didn't work out, attempt to return SPIFI to HW mode */ if (retval != ERROR_OK) lpcspifi_set_hw_mode(bank); return retval; } /* Read the status register of the external SPI flash chip. */ static int read_status_reg(struct flash_bank *bank, uint32_t *status) { struct target *target = bank->target; struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv; uint32_t ssp_base = lpcspifi_info->ssp_base; uint32_t io_base = lpcspifi_info->io_base; uint32_t value; int retval = ERROR_OK; retval = ssp_setcs(target, io_base, 0); if (retval == ERROR_OK) retval = ssp_write_reg(target, ssp_base, SSP_DATA, SPIFLASH_READ_STATUS); if (retval == ERROR_OK) retval = poll_ssp_busy(target, ssp_base, SSP_CMD_TIMEOUT); if (retval == ERROR_OK) retval = ssp_read_reg(target, ssp_base, SSP_DATA, &value); /* Dummy write to clock in the register */ if (retval == ERROR_OK) retval = ssp_write_reg(target, ssp_base, SSP_DATA, 0x00); if (retval == ERROR_OK) retval = poll_ssp_busy(target, ssp_base, SSP_CMD_TIMEOUT); if (retval == ERROR_OK) retval = ssp_setcs(target, io_base, 1); if (retval == ERROR_OK) retval = ssp_read_reg(target, ssp_base, SSP_DATA, &value); if (retval == ERROR_OK) *status = value; return retval; } /* check for BSY bit in flash status register */ /* timeout in ms */ static int wait_till_ready(struct flash_bank *bank, int timeout) { uint32_t status; int retval; long long endtime; endtime = timeval_ms() + timeout; do { /* read flash status register */ retval = read_status_reg(bank, &status); if (retval != ERROR_OK) return retval; if ((status & SPIFLASH_BSY_BIT) == 0) return ERROR_OK; alive_sleep(1); } while (timeval_ms() < endtime); LOG_ERROR("timeout waiting for flash to finish write/erase operation"); return ERROR_FAIL; } /* Send "write enable" command to SPI flash chip. */ static int lpcspifi_write_enable(struct flash_bank *bank) { struct target *target = bank->target; struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv; uint32_t ssp_base = lpcspifi_info->ssp_base; uint32_t io_base = lpcspifi_info->io_base; uint32_t status, value; int retval = ERROR_OK; retval = ssp_setcs(target, io_base, 0); if (retval == ERROR_OK) retval = ssp_write_reg(target, ssp_base, SSP_DATA, SPIFLASH_WRITE_ENABLE); if (retval == ERROR_OK) retval = poll_ssp_busy(target, ssp_base, SSP_CMD_TIMEOUT); if (retval == ERROR_OK) retval = ssp_read_reg(target, ssp_base, SSP_DATA, &value); if (retval == ERROR_OK) retval = ssp_setcs(target, io_base, 1); /* read flash status register */ if (retval == ERROR_OK) retval = read_status_reg(bank, &status); if (retval != ERROR_OK) return retval; /* Check write enabled */ if ((status & SPIFLASH_WE_BIT) == 0) { LOG_ERROR("Cannot enable write to flash. Status=0x%08" PRIx32, status); return ERROR_FAIL; } return retval; } static int lpcspifi_bulk_erase(struct flash_bank *bank) { struct target *target = bank->target; struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv; uint32_t ssp_base = lpcspifi_info->ssp_base; uint32_t io_base = lpcspifi_info->io_base; uint32_t value; int retval = ERROR_OK; retval = lpcspifi_set_sw_mode(bank); if (retval == ERROR_OK) retval = lpcspifi_write_enable(bank); /* send SPI command "bulk erase" */ if (retval == ERROR_OK) ssp_setcs(target, io_base, 0); if (retval == ERROR_OK) retval = ssp_write_reg(target, ssp_base, SSP_DATA, lpcspifi_info->dev->chip_erase_cmd); if (retval == ERROR_OK) retval = poll_ssp_busy(target, ssp_base, SSP_CMD_TIMEOUT); if (retval == ERROR_OK) retval = ssp_read_reg(target, ssp_base, SSP_DATA, &value); if (retval == ERROR_OK) retval = ssp_setcs(target, io_base, 1); /* poll flash BSY for self-timed bulk erase */ if (retval == ERROR_OK) retval = wait_till_ready(bank, bank->num_sectors*SSP_MAX_TIMEOUT); return retval; } static int lpcspifi_erase(struct flash_bank *bank, int first, int last) { struct target *target = bank->target; struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv; struct reg_param reg_params[4]; struct armv7m_algorithm armv7m_info; struct working_area *erase_algorithm; int retval = ERROR_OK; int sector; LOG_DEBUG("erase from sector %d to sector %d", first, last); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if ((first < 0) || (last < first) || (last >= bank->num_sectors)) { LOG_ERROR("Flash sector invalid"); return ERROR_FLASH_SECTOR_INVALID; } if (!(lpcspifi_info->probed)) { LOG_ERROR("Flash bank not probed"); return ERROR_FLASH_BANK_NOT_PROBED; } for (sector = first; sector <= last; sector++) { if (bank->sectors[sector].is_protected) { LOG_ERROR("Flash sector %d protected", sector); return ERROR_FAIL; } } /* If we're erasing the entire chip and the flash supports * it, use a bulk erase instead of going sector-by-sector. */ if (first == 0 && last == (bank->num_sectors - 1) && lpcspifi_info->dev->chip_erase_cmd != lpcspifi_info->dev->erase_cmd) { LOG_DEBUG("Chip supports the bulk erase command."\ " Will use bulk erase instead of sector-by-sector erase."); retval = lpcspifi_bulk_erase(bank); if (retval == ERROR_OK) { retval = lpcspifi_set_hw_mode(bank); return retval; } else LOG_WARNING("Bulk flash erase failed. Falling back to sector-by-sector erase."); } retval = lpcspifi_set_hw_mode(bank); if (retval != ERROR_OK) return retval; /* see contrib/loaders/flash/lpcspifi_erase.S for src */ static const uint8_t lpcspifi_flash_erase_code[] = { 0x4f, 0xf4, 0xc0, 0x4a, 0xc4, 0xf2, 0x08, 0x0a, 0x4f, 0xf0, 0xea, 0x08, 0xca, 0xf8, 0x8c, 0x81, 0x4f, 0xf0, 0x40, 0x08, 0xca, 0xf8, 0x90, 0x81, 0x4f, 0xf0, 0x40, 0x08, 0xca, 0xf8, 0x94, 0x81, 0x4f, 0xf0, 0xed, 0x08, 0xca, 0xf8, 0x98, 0x81, 0x4f, 0xf0, 0xed, 0x08, 0xca, 0xf8, 0x9c, 0x81, 0x4f, 0xf0, 0x44, 0x08, 0xca, 0xf8, 0xa0, 0x81, 0x4f, 0xf4, 0xc0, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a, 0x4f, 0xf4, 0x00, 0x68, 0xca, 0xf8, 0x14, 0x80, 0x4f, 0xf4, 0x80, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a, 0x4f, 0xf0, 0xff, 0x08, 0xca, 0xf8, 0xab, 0x80, 0x4f, 0xf0, 0x00, 0x0a, 0xc4, 0xf2, 0x05, 0x0a, 0x4f, 0xf0, 0x00, 0x08, 0xc0, 0xf2, 0x00, 0x18, 0xca, 0xf8, 0x94, 0x80, 0x4f, 0xf4, 0x00, 0x5a, 0xc4, 0xf2, 0x05, 0x0a, 0x4f, 0xf0, 0x01, 0x08, 0xca, 0xf8, 0x00, 0x87, 0x4f, 0xf4, 0x40, 0x5a, 0xc4, 0xf2, 0x08, 0x0a, 0x4f, 0xf0, 0x07, 0x08, 0xca, 0xf8, 0x00, 0x80, 0x4f, 0xf0, 0x02, 0x08, 0xca, 0xf8, 0x10, 0x80, 0xca, 0xf8, 0x04, 0x80, 0x00, 0xf0, 0x52, 0xf8, 0x4f, 0xf0, 0x06, 0x09, 0x00, 0xf0, 0x3b, 0xf8, 0x00, 0xf0, 0x48, 0xf8, 0x00, 0xf0, 0x4a, 0xf8, 0x4f, 0xf0, 0x05, 0x09, 0x00, 0xf0, 0x33, 0xf8, 0x4f, 0xf0, 0x00, 0x09, 0x00, 0xf0, 0x2f, 0xf8, 0x00, 0xf0, 0x3c, 0xf8, 0x19, 0xf0, 0x02, 0x0f, 0x00, 0xf0, 0x45, 0x80, 0x00, 0xf0, 0x3a, 0xf8, 0x4f, 0xea, 0x02, 0x09, 0x00, 0xf0, 0x23, 0xf8, 0x4f, 0xea, 0x10, 0x49, 0x00, 0xf0, 0x1f, 0xf8, 0x4f, 0xea, 0x10, 0x29, 0x00, 0xf0, 0x1b, 0xf8, 0x4f, 0xea, 0x00, 0x09, 0x00, 0xf0, 0x17, 0xf8, 0x00, 0xf0, 0x24, 0xf8, 0x00, 0xf0, 0x26, 0xf8, 0x4f, 0xf0, 0x05, 0x09, 0x00, 0xf0, 0x0f, 0xf8, 0x4f, 0xf0, 0x00, 0x09, 0x00, 0xf0, 0x0b, 0xf8, 0x00, 0xf0, 0x18, 0xf8, 0x19, 0xf0, 0x01, 0x0f, 0x7f, 0xf4, 0xf0, 0xaf, 0x01, 0x39, 0xf9, 0xb1, 0x18, 0x44, 0xff, 0xf7, 0xbf, 0xbf, 0x4f, 0xf4, 0x40, 0x5a, 0xc4, 0xf2, 0x08, 0x0a, 0xca, 0xf8, 0x08, 0x90, 0xda, 0xf8, 0x0c, 0x90, 0x19, 0xf0, 0x10, 0x0f, 0x7f, 0xf4, 0xfa, 0xaf, 0xda, 0xf8, 0x08, 0x90, 0x70, 0x47, 0x4f, 0xf0, 0xff, 0x08, 0x00, 0xf0, 0x02, 0xb8, 0x4f, 0xf0, 0x00, 0x08, 0x4f, 0xf4, 0x80, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a, 0xca, 0xf8, 0xab, 0x80, 0x70, 0x47, 0x00, 0x20, 0x00, 0xbe, 0xff, 0xff }; armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; /* Get memory for spifi initialization algorithm */ retval = target_alloc_working_area(target, sizeof(lpcspifi_flash_erase_code), &erase_algorithm); if (retval != ERROR_OK) { LOG_ERROR("Insufficient working area. You must configure a working"\ " area of at least %zdB in order to erase SPIFI flash.", sizeof(lpcspifi_flash_erase_code)); return retval; } /* Write algorithm to working area */ retval = target_write_buffer(target, erase_algorithm->address, sizeof(lpcspifi_flash_erase_code), lpcspifi_flash_erase_code); if (retval != ERROR_OK) { target_free_working_area(target, erase_algorithm); return retval; } init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* Start address */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* Sector count */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* Erase command */ init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* Sector size */ buf_set_u32(reg_params[0].value, 0, 32, bank->sectors[first].offset); buf_set_u32(reg_params[1].value, 0, 32, last - first + 1); buf_set_u32(reg_params[2].value, 0, 32, lpcspifi_info->dev->erase_cmd); buf_set_u32(reg_params[3].value, 0, 32, bank->sectors[first].size); /* Run the algorithm */ retval = target_run_algorithm(target, 0 , NULL, 4, reg_params, erase_algorithm->address, erase_algorithm->address + sizeof(lpcspifi_flash_erase_code) - 4, 3000*(last - first + 1), &armv7m_info); if (retval != ERROR_OK) LOG_ERROR("Error executing flash erase algorithm"); target_free_working_area(target, erase_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); retval = lpcspifi_set_hw_mode(bank); return retval; } static int lpcspifi_protect(struct flash_bank *bank, int set, int first, int last) { int sector; for (sector = first; sector <= last; sector++) bank->sectors[sector].is_protected = set; return ERROR_OK; } static int lpcspifi_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv; uint32_t page_size, fifo_size; struct working_area *fifo; struct reg_param reg_params[5]; struct armv7m_algorithm armv7m_info; struct working_area *write_algorithm; int sector; int retval = ERROR_OK; LOG_DEBUG("offset=0x%08" PRIx32 " count=0x%08" PRIx32, offset, count); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset + count > lpcspifi_info->dev->size_in_bytes) { LOG_WARNING("Writes past end of flash. Extra data discarded."); count = lpcspifi_info->dev->size_in_bytes - offset; } /* Check sector protection */ for (sector = 0; sector < bank->num_sectors; sector++) { /* Start offset in or before this sector? */ /* End offset in or behind this sector? */ if ((offset < (bank->sectors[sector].offset + bank->sectors[sector].size)) && ((offset + count - 1) >= bank->sectors[sector].offset) && bank->sectors[sector].is_protected) { LOG_ERROR("Flash sector %d protected", sector); return ERROR_FAIL; } } page_size = lpcspifi_info->dev->pagesize; retval = lpcspifi_set_hw_mode(bank); if (retval != ERROR_OK) return retval; /* see contrib/loaders/flash/lpcspifi_write.S for src */ static const uint8_t lpcspifi_flash_write_code[] = { 0x4f, 0xf4, 0xc0, 0x4a, 0xc4, 0xf2, 0x08, 0x0a, 0x4f, 0xf0, 0xea, 0x08, 0xca, 0xf8, 0x8c, 0x81, 0x4f, 0xf0, 0x40, 0x08, 0xca, 0xf8, 0x90, 0x81, 0x4f, 0xf0, 0x40, 0x08, 0xca, 0xf8, 0x94, 0x81, 0x4f, 0xf0, 0xed, 0x08, 0xca, 0xf8, 0x98, 0x81, 0x4f, 0xf0, 0xed, 0x08, 0xca, 0xf8, 0x9c, 0x81, 0x4f, 0xf0, 0x44, 0x08, 0xca, 0xf8, 0xa0, 0x81, 0x4f, 0xf4, 0xc0, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a, 0x4f, 0xf4, 0x00, 0x68, 0xca, 0xf8, 0x14, 0x80, 0x4f, 0xf4, 0x80, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a, 0x4f, 0xf0, 0xff, 0x08, 0xca, 0xf8, 0xab, 0x80, 0x4f, 0xf0, 0x00, 0x0a, 0xc4, 0xf2, 0x05, 0x0a, 0x4f, 0xf0, 0x00, 0x08, 0xc0, 0xf2, 0x00, 0x18, 0xca, 0xf8, 0x94, 0x80, 0x4f, 0xf4, 0x00, 0x5a, 0xc4, 0xf2, 0x05, 0x0a, 0x4f, 0xf0, 0x01, 0x08, 0xca, 0xf8, 0x00, 0x87, 0x4f, 0xf4, 0x40, 0x5a, 0xc4, 0xf2, 0x08, 0x0a, 0x4f, 0xf0, 0x07, 0x08, 0xca, 0xf8, 0x00, 0x80, 0x4f, 0xf0, 0x02, 0x08, 0xca, 0xf8, 0x10, 0x80, 0xca, 0xf8, 0x04, 0x80, 0x4f, 0xf0, 0x00, 0x0b, 0xa3, 0x44, 0x93, 0x45, 0x7f, 0xf6, 0xfc, 0xaf, 0x00, 0xf0, 0x6a, 0xf8, 0x4f, 0xf0, 0x06, 0x09, 0x00, 0xf0, 0x53, 0xf8, 0x00, 0xf0, 0x60, 0xf8, 0x00, 0xf0, 0x62, 0xf8, 0x4f, 0xf0, 0x05, 0x09, 0x00, 0xf0, 0x4b, 0xf8, 0x4f, 0xf0, 0x00, 0x09, 0x00, 0xf0, 0x47, 0xf8, 0x00, 0xf0, 0x54, 0xf8, 0x19, 0xf0, 0x02, 0x0f, 0x00, 0xf0, 0x5d, 0x80, 0x00, 0xf0, 0x52, 0xf8, 0x4f, 0xf0, 0x02, 0x09, 0x00, 0xf0, 0x3b, 0xf8, 0x4f, 0xea, 0x12, 0x49, 0x00, 0xf0, 0x37, 0xf8, 0x4f, 0xea, 0x12, 0x29, 0x00, 0xf0, 0x33, 0xf8, 0x4f, 0xea, 0x02, 0x09, 0x00, 0xf0, 0x2f, 0xf8, 0xd0, 0xf8, 0x00, 0x80, 0xb8, 0xf1, 0x00, 0x0f, 0x00, 0xf0, 0x47, 0x80, 0x47, 0x68, 0x47, 0x45, 0x3f, 0xf4, 0xf6, 0xaf, 0x17, 0xf8, 0x01, 0x9b, 0x00, 0xf0, 0x21, 0xf8, 0x8f, 0x42, 0x28, 0xbf, 0x00, 0xf1, 0x08, 0x07, 0x47, 0x60, 0x01, 0x3b, 0xbb, 0xb3, 0x02, 0xf1, 0x01, 0x02, 0x93, 0x45, 0x7f, 0xf4, 0xe6, 0xaf, 0x00, 0xf0, 0x22, 0xf8, 0xa3, 0x44, 0x00, 0xf0, 0x23, 0xf8, 0x4f, 0xf0, 0x05, 0x09, 0x00, 0xf0, 0x0c, 0xf8, 0x4f, 0xf0, 0x00, 0x09, 0x00, 0xf0, 0x08, 0xf8, 0x00, 0xf0, 0x15, 0xf8, 0x19, 0xf0, 0x01, 0x0f, 0x7f, 0xf4, 0xf0, 0xaf, 0xff, 0xf7, 0xa7, 0xbf, 0x4f, 0xf4, 0x40, 0x5a, 0xc4, 0xf2, 0x08, 0x0a, 0xca, 0xf8, 0x08, 0x90, 0xda, 0xf8, 0x0c, 0x90, 0x19, 0xf0, 0x10, 0x0f, 0x7f, 0xf4, 0xfa, 0xaf, 0xda, 0xf8, 0x08, 0x90, 0x70, 0x47, 0x4f, 0xf0, 0xff, 0x08, 0x00, 0xf0, 0x02, 0xb8, 0x4f, 0xf0, 0x00, 0x08, 0x4f, 0xf4, 0x80, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a, 0xca, 0xf8, 0xab, 0x80, 0x70, 0x47, 0x00, 0x20, 0x50, 0x60, 0x30, 0x46, 0x00, 0xbe, 0xff, 0xff }; if (target_alloc_working_area(target, sizeof(lpcspifi_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_ERROR("Insufficient working area. You must configure"\ " a working area > %zdB in order to write to SPIFI flash.", sizeof(lpcspifi_flash_write_code)); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; }; retval = target_write_buffer(target, write_algorithm->address, sizeof(lpcspifi_flash_write_code), lpcspifi_flash_write_code); if (retval != ERROR_OK) { target_free_working_area(target, write_algorithm); return retval; } /* FIFO allocation */ fifo_size = target_get_working_area_avail(target); if (fifo_size == 0) { /* if we already allocated the writing code but failed to get fifo * space, free the algorithm */ target_free_working_area(target, write_algorithm); LOG_ERROR("Insufficient working area. Please allocate at least"\ " %zdB of working area to enable flash writes.", sizeof(lpcspifi_flash_write_code) + 1 ); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } else if (fifo_size < page_size) LOG_WARNING("Working area size is limited; flash writes may be"\ " slow. Increase working area size to at least %zdB"\ " to reduce write times.", sizeof(lpcspifi_flash_write_code) + page_size ); else if (fifo_size > 0x2000) /* Beyond this point, we start to get diminishing returns */ fifo_size = 0x2000; if (target_alloc_working_area(target, fifo_size, &fifo) != ERROR_OK) { target_free_working_area(target, write_algorithm); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; }; armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* buffer start, status (out) */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* buffer end */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* target address */ init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* count (halfword-16bit) */ init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* page size */ buf_set_u32(reg_params[0].value, 0, 32, fifo->address); buf_set_u32(reg_params[1].value, 0, 32, fifo->address + fifo->size); buf_set_u32(reg_params[2].value, 0, 32, offset); buf_set_u32(reg_params[3].value, 0, 32, count); buf_set_u32(reg_params[4].value, 0, 32, page_size); retval = target_run_flash_async_algorithm(target, buffer, count, 1, 0, NULL, 5, reg_params, fifo->address, fifo->size, write_algorithm->address, 0, &armv7m_info ); if (retval != ERROR_OK) LOG_ERROR("Error executing flash write algorithm"); target_free_working_area(target, fifo); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); /* Switch to HW mode before return to prompt */ retval = lpcspifi_set_hw_mode(bank); return retval; } /* Return ID of flash device */ /* On exit, SW mode is kept */ static int lpcspifi_read_flash_id(struct flash_bank *bank, uint32_t *id) { struct target *target = bank->target; struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv; uint32_t ssp_base = lpcspifi_info->ssp_base; uint32_t io_base = lpcspifi_info->io_base; uint32_t value; int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } LOG_DEBUG("Getting ID"); retval = lpcspifi_set_sw_mode(bank); if (retval != ERROR_OK) return retval; /* poll WIP */ if (retval == ERROR_OK) retval = wait_till_ready(bank, SSP_PROBE_TIMEOUT); /* Send SPI command "read ID" */ if (retval == ERROR_OK) retval = ssp_setcs(target, io_base, 0); if (retval == ERROR_OK) retval = ssp_write_reg(target, ssp_base, SSP_DATA, SPIFLASH_READ_ID); if (retval == ERROR_OK) retval = poll_ssp_busy(target, ssp_base, SSP_CMD_TIMEOUT); if (retval == ERROR_OK) retval = ssp_read_reg(target, ssp_base, SSP_DATA, &value); /* Dummy write to clock in data */ if (retval == ERROR_OK) retval = ssp_write_reg(target, ssp_base, SSP_DATA, 0x00); if (retval == ERROR_OK) retval = poll_ssp_busy(target, ssp_base, SSP_CMD_TIMEOUT); if (retval == ERROR_OK) retval = ssp_read_reg(target, ssp_base, SSP_DATA, &value); if (retval == ERROR_OK) ((uint8_t *)id)[0] = value; /* Dummy write to clock in data */ if (retval == ERROR_OK) retval = ssp_write_reg(target, ssp_base, SSP_DATA, 0x00); if (retval == ERROR_OK) retval = poll_ssp_busy(target, ssp_base, SSP_CMD_TIMEOUT); if (retval == ERROR_OK) retval = ssp_read_reg(target, ssp_base, SSP_DATA, &value); if (retval == ERROR_OK) ((uint8_t *)id)[1] = value; /* Dummy write to clock in data */ if (retval == ERROR_OK) retval = ssp_write_reg(target, ssp_base, SSP_DATA, 0x00); if (retval == ERROR_OK) retval = poll_ssp_busy(target, ssp_base, SSP_CMD_TIMEOUT); if (retval == ERROR_OK) retval = ssp_read_reg(target, ssp_base, SSP_DATA, &value); if (retval == ERROR_OK) ((uint8_t *)id)[2] = value; if (retval == ERROR_OK) retval = ssp_setcs(target, io_base, 1); return retval; } static int lpcspifi_probe(struct flash_bank *bank) { struct target *target = bank->target; struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv; uint32_t ssp_base; uint32_t io_base; uint32_t ioconfig_base; struct flash_sector *sectors; uint32_t id = 0; /* silence uninitialized warning */ struct lpcspifi_target *target_device; int retval; /* If we've already probed, we should be fine to skip this time. */ if (lpcspifi_info->probed) return ERROR_OK; lpcspifi_info->probed = 0; for (target_device = target_devices ; target_device->name ; ++target_device) if (target_device->tap_idcode == target->tap->idcode) break; if (!target_device->name) { LOG_ERROR("Device ID 0x%" PRIx32 " is not known as SPIFI capable", target->tap->idcode); return ERROR_FAIL; } ssp_base = target_device->ssp_base; io_base = target_device->io_base; ioconfig_base = target_device->ioconfig_base; lpcspifi_info->ssp_base = ssp_base; lpcspifi_info->io_base = io_base; lpcspifi_info->ioconfig_base = ioconfig_base; lpcspifi_info->bank_num = bank->bank_number; LOG_DEBUG("Valid SPIFI on device %s at address 0x%" PRIx32, target_device->name, bank->base); /* read and decode flash ID; returns in SW mode */ retval = lpcspifi_read_flash_id(bank, &id); if (retval != ERROR_OK) return retval; retval = lpcspifi_set_hw_mode(bank); if (retval != ERROR_OK) return retval; lpcspifi_info->dev = NULL; for (struct flash_device *p = flash_devices; p->name ; p++) if (p->device_id == id) { lpcspifi_info->dev = p; break; } if (!lpcspifi_info->dev) { LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32 ")", id); return ERROR_FAIL; } LOG_INFO("Found flash device \'%s\' (ID 0x%08" PRIx32 ")", lpcspifi_info->dev->name, lpcspifi_info->dev->device_id); /* Set correct size value */ bank->size = lpcspifi_info->dev->size_in_bytes; /* create and fill sectors array */ bank->num_sectors = lpcspifi_info->dev->size_in_bytes / lpcspifi_info->dev->sectorsize; sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); if (sectors == NULL) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } for (int sector = 0; sector < bank->num_sectors; sector++) { sectors[sector].offset = sector * lpcspifi_info->dev->sectorsize; sectors[sector].size = lpcspifi_info->dev->sectorsize; sectors[sector].is_erased = -1; sectors[sector].is_protected = 1; } bank->sectors = sectors; lpcspifi_info->probed = 1; return ERROR_OK; } static int lpcspifi_auto_probe(struct flash_bank *bank) { struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv; if (lpcspifi_info->probed) return ERROR_OK; return lpcspifi_probe(bank); } static int lpcspifi_protect_check(struct flash_bank *bank) { /* Nothing to do. Protection is only handled in SW. */ return ERROR_OK; } static int get_lpcspifi_info(struct flash_bank *bank, char *buf, int buf_size) { struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv; if (!(lpcspifi_info->probed)) { snprintf(buf, buf_size, "\nSPIFI flash bank not probed yet\n"); return ERROR_OK; } snprintf(buf, buf_size, "\nSPIFI flash information:\n" " Device \'%s\' (ID 0x%08x)\n", lpcspifi_info->dev->name, lpcspifi_info->dev->device_id); return ERROR_OK; } struct flash_driver lpcspifi_flash = { .name = "lpcspifi", .flash_bank_command = lpcspifi_flash_bank_command, .erase = lpcspifi_erase, .protect = lpcspifi_protect, .write = lpcspifi_write, .read = default_flash_read, .probe = lpcspifi_probe, .auto_probe = lpcspifi_auto_probe, .erase_check = default_flash_blank_check, .protect_check = lpcspifi_protect_check, .info = get_lpcspifi_info, }; openocd-0.7.0/src/flash/nor/lpc288x.c0000644000175000001440000003435412134336410014126 00000000000000/*************************************************************************** * Copyright (C) 2008 by * * Karl RobinSod * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /*************************************************************************** * There are some things to notice * * You need to unprotect flash sectors each time you connect the OpenOCD * Dumping 1MB takes about 60 Seconds * Full erase (sectors 0-22 inclusive) takes 2-4 seconds * Writing 1MB takes 88 seconds * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include #define LOAD_TIMER_ERASE 0 #define LOAD_TIMER_WRITE 1 #define FLASH_PAGE_SIZE 512 /* LPC288X control registers */ #define DBGU_CIDR 0x8000507C /* LPC288X flash registers */ #define F_CTRL 0x80102000 /* Flash control register R/W 0x5 */ #define F_STAT 0x80102004 /* Flash status register RO 0x45 */ #define F_PROG_TIME 0x80102008 /* Flash program time register R/W 0 */ #define F_WAIT 0x80102010 /* Flash read wait state register R/W 0xC004 */ #define F_CLK_TIME 0x8010201C /* Flash clock divider for 66 kHz generation R/W 0 **/ #define F_INTEN_CLR 0x80102FD8 /* Clear interrupt enable bits WO - */ #define F_INTEN_SET 0x80102FDC /* Set interrupt enable bits WO - */ #define F_INT_STAT 0x80102FE0 /* Interrupt status bits RO 0 */ #define F_INTEN 0x80102FE4 /* Interrupt enable bits RO 0 */ #define F_INT_CLR 0x80102FE8 /* Clear interrupt status bits WO */ #define F_INT_SET 0x80102FEC /* Set interrupt status bits WO - */ #define FLASH_PD 0x80005030 /* Allows turning off the Flash memory for power *savings. R/W 1*/ #define FLASH_INIT 0x80005034 /* Monitors Flash readiness, such as recovery from *Power Down mode. R/W -*/ /* F_CTRL bits */ #define FC_CS 0x0001 #define FC_FUNC 0x0002 #define FC_WEN 0x0004 #define FC_RD_LATCH 0x0020 #define FC_PROTECT 0x0080 #define FC_SET_DATA 0x0400 #define FC_RSSL 0x0800 #define FC_PROG_REQ 0x1000 #define FC_CLR_BUF 0x4000 #define FC_LOAD_REQ 0x8000 /* F_STAT bits */ #define FS_DONE 0x0001 #define FS_PROGGNT 0x0002 #define FS_RDY 0x0004 #define FS_ERR 0x0020 /* F_PROG_TIME */ #define FPT_TIME_MASK 0x7FFF #define FPT_ENABLE 0x8000 /* F_WAIT */ #define FW_WAIT_STATES_MASK 0x00FF #define FW_SET_MASK 0xC000 /* F_CLK_TIME */ #define FCT_CLK_DIV_MASK 0x0FFF struct lpc288x_flash_bank { uint32_t working_area; uint32_t working_area_size; /* chip id register */ uint32_t cidr; const char *target_name; uint32_t cclk; uint32_t sector_size_break; }; static uint32_t lpc288x_wait_status_busy(struct flash_bank *bank, int timeout); static void lpc288x_load_timer(int erase, struct target *target); static void lpc288x_set_flash_clk(struct flash_bank *bank); static uint32_t lpc288x_system_ready(struct flash_bank *bank); static uint32_t lpc288x_wait_status_busy(struct flash_bank *bank, int timeout) { uint32_t status; struct target *target = bank->target; do { alive_sleep(1); timeout--; target_read_u32(target, F_STAT, &status); } while (((status & FS_DONE) == 0) && timeout); if (timeout == 0) { LOG_DEBUG("Timedout!"); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } /* Read device id register and fill in driver info structure */ static int lpc288x_read_part_info(struct flash_bank *bank) { struct lpc288x_flash_bank *lpc288x_info = bank->driver_priv; struct target *target = bank->target; uint32_t cidr; int i = 0; uint32_t offset; if (lpc288x_info->cidr == 0x0102100A) return ERROR_OK;/* already probed, multiple probes may cause memory leak, not *allowed */ /* Read and parse chip identification register */ target_read_u32(target, DBGU_CIDR, &cidr); if (cidr != 0x0102100A) { LOG_WARNING("Cannot identify target as an LPC288X (%08" PRIx32 ")", cidr); return ERROR_FLASH_OPERATION_FAILED; } lpc288x_info->cidr = cidr; lpc288x_info->sector_size_break = 0x000F0000; lpc288x_info->target_name = "LPC288x"; /* setup the sector info... */ offset = bank->base; bank->num_sectors = 23; bank->sectors = malloc(sizeof(struct flash_sector) * 23); for (i = 0; i < 15; i++) { bank->sectors[i].offset = offset; bank->sectors[i].size = 64 * 1024; offset += bank->sectors[i].size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } for (i = 15; i < 23; i++) { bank->sectors[i].offset = offset; bank->sectors[i].size = 8 * 1024; offset += bank->sectors[i].size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } return ERROR_OK; } static int lpc288x_protect_check(struct flash_bank *bank) { return ERROR_OK; } /* flash_bank LPC288x 0 0 0 0 */ FLASH_BANK_COMMAND_HANDLER(lpc288x_flash_bank_command) { struct lpc288x_flash_bank *lpc288x_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; lpc288x_info = malloc(sizeof(struct lpc288x_flash_bank)); bank->driver_priv = lpc288x_info; /* part wasn't probed for info yet */ lpc288x_info->cidr = 0; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], lpc288x_info->cclk); return ERROR_OK; } /* The frequency is the AHB clock frequency divided by (CLK_DIV ×3) + 1. * This must be programmed such that the Flash Programming clock frequency is 66 kHz ± 20%. * AHB = 12 MHz ? * 12000000/66000 = 182 * CLK_DIV = 60 ? */ static void lpc288x_set_flash_clk(struct flash_bank *bank) { uint32_t clk_time; struct lpc288x_flash_bank *lpc288x_info = bank->driver_priv; clk_time = (lpc288x_info->cclk / 66000) / 3; target_write_u32(bank->target, F_CTRL, FC_CS | FC_WEN); target_write_u32(bank->target, F_CLK_TIME, clk_time); } /* AHB tcyc (in ns) 83 ns * LOAD_TIMER_ERASE FPT_TIME = ((400,000,000 / AHB tcyc (in ns)) - 2) / 512 * = 9412 (9500) (AN10548 9375) * LOAD_TIMER_WRITE FPT_TIME = ((1,000,000 / AHB tcyc (in ns)) - 2) / 512 * = 23 (75) (AN10548 72 - is this wrong?) * TODO: Sort out timing calcs ;) */ static void lpc288x_load_timer(int erase, struct target *target) { if (erase == LOAD_TIMER_ERASE) target_write_u32(target, F_PROG_TIME, FPT_ENABLE | 9500); else target_write_u32(target, F_PROG_TIME, FPT_ENABLE | 75); } static uint32_t lpc288x_system_ready(struct flash_bank *bank) { struct lpc288x_flash_bank *lpc288x_info = bank->driver_priv; if (lpc288x_info->cidr == 0) return ERROR_FLASH_BANK_NOT_PROBED; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } return ERROR_OK; } static int lpc288x_erase_check(struct flash_bank *bank) { uint32_t status = lpc288x_system_ready(bank); /* probed? halted? */ if (status != ERROR_OK) { LOG_INFO("Processor not halted/not probed"); return status; } return ERROR_OK; } static int lpc288x_erase(struct flash_bank *bank, int first, int last) { uint32_t status; int sector; struct target *target = bank->target; status = lpc288x_system_ready(bank); /* probed? halted? */ if (status != ERROR_OK) return status; if ((first < 0) || (last < first) || (last >= bank->num_sectors)) { LOG_INFO("Bad sector range"); return ERROR_FLASH_SECTOR_INVALID; } /* Configure the flash controller timing */ lpc288x_set_flash_clk(bank); for (sector = first; sector <= last; sector++) { if (lpc288x_wait_status_busy(bank, 1000) != ERROR_OK) return ERROR_FLASH_OPERATION_FAILED; lpc288x_load_timer(LOAD_TIMER_ERASE, target); target_write_u32(target, bank->sectors[sector].offset, 0x00); target_write_u32(target, F_CTRL, FC_PROG_REQ | FC_PROTECT | FC_CS); } if (lpc288x_wait_status_busy(bank, 1000) != ERROR_OK) return ERROR_FLASH_OPERATION_FAILED; return ERROR_OK; } static int lpc288x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { uint8_t page_buffer[FLASH_PAGE_SIZE]; uint32_t status, source_offset, dest_offset; struct target *target = bank->target; uint32_t bytes_remaining = count; uint32_t first_sector, last_sector, sector, page; int i; /* probed? halted? */ status = lpc288x_system_ready(bank); if (status != ERROR_OK) return status; /* Initialise search indices */ first_sector = last_sector = 0xffffffff; /* validate the write range... */ for (i = 0; i < bank->num_sectors; i++) { if ((offset >= bank->sectors[i].offset) && (offset < (bank->sectors[i].offset + bank->sectors[i].size)) && (first_sector == 0xffffffff)) { first_sector = i; /* all writes must start on a sector boundary... */ if (offset % bank->sectors[i].size) { LOG_INFO( "offset 0x%" PRIx32 " breaks required alignment 0x%" PRIx32 "", offset, bank->sectors[i].size); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } } if (((offset + count) > bank->sectors[i].offset) && ((offset + count) <= (bank->sectors[i].offset + bank->sectors[i].size)) && (last_sector == 0xffffffff)) last_sector = i; } /* Range check... */ if (first_sector == 0xffffffff || last_sector == 0xffffffff) { LOG_INFO("Range check failed %" PRIx32 " %" PRIx32 "", offset, count); return ERROR_FLASH_DST_OUT_OF_BANK; } /* Configure the flash controller timing */ lpc288x_set_flash_clk(bank); /* initialise the offsets */ source_offset = 0; dest_offset = 0; for (sector = first_sector; sector <= last_sector; sector++) { for (page = 0; page < bank->sectors[sector].size / FLASH_PAGE_SIZE; page++) { if (bytes_remaining == 0) { count = 0; memset(page_buffer, 0xFF, FLASH_PAGE_SIZE); } else if (bytes_remaining < FLASH_PAGE_SIZE) { count = bytes_remaining; memset(page_buffer, 0xFF, FLASH_PAGE_SIZE); memcpy(page_buffer, &buffer[source_offset], count); } else { count = FLASH_PAGE_SIZE; memcpy(page_buffer, &buffer[source_offset], count); } /* Wait for flash to become ready */ if (lpc288x_wait_status_busy(bank, 1000) != ERROR_OK) return ERROR_FLASH_OPERATION_FAILED; /* fill flash data latches with 1's */ target_write_u32(target, F_CTRL, FC_CS | FC_SET_DATA | FC_WEN | FC_FUNC); target_write_u32(target, F_CTRL, FC_CS | FC_WEN | FC_FUNC); /*would be better to use the clean target_write_buffer() interface but * it seems not to be a LOT slower.... * bulk_write_memory() is no quicker :(*/ #if 1 if (target_write_memory(target, offset + dest_offset, 4, 128, page_buffer) != ERROR_OK) { LOG_ERROR("Write failed s %" PRIx32 " p %" PRIx32 "", sector, page); return ERROR_FLASH_OPERATION_FAILED; } #else if (target_write_buffer(target, offset + dest_offset, FLASH_PAGE_SIZE, page_buffer) != ERROR_OK) { LOG_INFO("Write to flash buffer failed"); return ERROR_FLASH_OPERATION_FAILED; } #endif dest_offset += FLASH_PAGE_SIZE; source_offset += count; bytes_remaining -= count; lpc288x_load_timer(LOAD_TIMER_WRITE, target); target_write_u32(target, F_CTRL, FC_PROG_REQ | FC_PROTECT | FC_FUNC | FC_CS); } } return ERROR_OK; } static int lpc288x_probe(struct flash_bank *bank) { /* we only deal with LPC2888 so flash config is fixed */ struct lpc288x_flash_bank *lpc288x_info = bank->driver_priv; int retval; if (lpc288x_info->cidr != 0) return ERROR_OK;/* already probed */ if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } retval = lpc288x_read_part_info(bank); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int lpc288x_info(struct flash_bank *bank, char *buf, int buf_size) { snprintf(buf, buf_size, "lpc288x flash driver"); return ERROR_OK; } static int lpc288x_protect(struct flash_bank *bank, int set, int first, int last) { int lockregion, status; uint32_t value; struct target *target = bank->target; /* probed? halted? */ status = lpc288x_system_ready(bank); if (status != ERROR_OK) return status; if ((first < 0) || (last < first) || (last >= bank->num_sectors)) return ERROR_FLASH_SECTOR_INVALID; /* Configure the flash controller timing */ lpc288x_set_flash_clk(bank); for (lockregion = first; lockregion <= last; lockregion++) { if (set) { /* write an odd value to base addy to protect... */ value = 0x01; } else { /* write an even value to base addy to unprotect... */ value = 0x00; } target_write_u32(target, bank->sectors[lockregion].offset, value); target_write_u32(target, F_CTRL, FC_LOAD_REQ | FC_PROTECT | FC_WEN | FC_FUNC | FC_CS); } return ERROR_OK; } struct flash_driver lpc288x_flash = { .name = "lpc288x", .flash_bank_command = lpc288x_flash_bank_command, .erase = lpc288x_erase, .protect = lpc288x_protect, .write = lpc288x_write, .read = default_flash_read, .probe = lpc288x_probe, .auto_probe = lpc288x_probe, .erase_check = lpc288x_erase_check, .protect_check = lpc288x_protect_check, .info = lpc288x_info, }; openocd-0.7.0/src/flash/nor/spi.c0000644000175000001440000001117612134336410013506 00000000000000/*************************************************************************** * Copyright (C) 2012 by George Harris * * george@luminairecoffee.com * * * * Copyright (C) 2010 by Antonio Borneo * * borneo.antonio@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "spi.h" #include /* Shared table of known SPI flash devices for SPI-based flash drivers. Taken * from device datasheets and Linux SPI flash drivers. */ struct flash_device flash_devices[] = { /* name, erase_cmd, chip_erase_cmd, device_id, pagesize, sectorsize, size_in_bytes */ FLASH_ID("st m25p05", 0xd8, 0xC7, 0x00102020, 0x80, 0x8000, 0x10000), FLASH_ID("st m25p10", 0xd8, 0xC7, 0x00112020, 0x80, 0x8000, 0x20000), FLASH_ID("st m25p20", 0xd8, 0xC7, 0x00122020, 0x100, 0x10000, 0x40000), FLASH_ID("st m25p40", 0xd8, 0xC7, 0x00132020, 0x100, 0x10000, 0x80000), FLASH_ID("st m25p80", 0xd8, 0xC7, 0x00142020, 0x100, 0x10000, 0x100000), FLASH_ID("st m25p16", 0xd8, 0xC7, 0x00152020, 0x100, 0x10000, 0x200000), FLASH_ID("st m25p32", 0xd8, 0xC7, 0x00162020, 0x100, 0x10000, 0x400000), FLASH_ID("st m25p64", 0xd8, 0xC7, 0x00172020, 0x100, 0x10000, 0x800000), FLASH_ID("st m25p128", 0xd8, 0xC7, 0x00182020, 0x100, 0x40000, 0x1000000), FLASH_ID("st m45pe10", 0xd8, 0xd8, 0x00114020, 0x100, 0x10000, 0x20000), FLASH_ID("st m45pe20", 0xd8, 0xd8, 0x00124020, 0x100, 0x10000, 0x40000), FLASH_ID("st m45pe40", 0xd8, 0xd8, 0x00134020, 0x100, 0x10000, 0x80000), FLASH_ID("st m45pe80", 0xd8, 0xd8, 0x00144020, 0x100, 0x10000, 0x100000), FLASH_ID("sp s25fl004", 0xd8, 0xC7, 0x00120201, 0x100, 0x10000, 0x80000), FLASH_ID("sp s25fl008", 0xd8, 0xC7, 0x00130201, 0x100, 0x10000, 0x100000), FLASH_ID("sp s25fl016", 0xd8, 0xC7, 0x00140201, 0x100, 0x10000, 0x200000), FLASH_ID("sp s25fl032", 0xd8, 0xC7, 0x00150201, 0x100, 0x10000, 0x400000), FLASH_ID("sp s25fl064", 0xd8, 0xC7, 0x00160201, 0x100, 0x10000, 0x800000), FLASH_ID("atmel 25f512", 0x52, 0xC7, 0x0065001f, 0x80, 0x8000, 0x10000), FLASH_ID("atmel 25f1024", 0x52, 0x62, 0x0060001f, 0x100, 0x8000, 0x20000), FLASH_ID("atmel 25f2048", 0x52, 0x62, 0x0063001f, 0x100, 0x10000, 0x40000), FLASH_ID("atmel 25f4096", 0x52, 0x62, 0x0064001f, 0x100, 0x10000, 0x80000), FLASH_ID("atmel 25fs040", 0xd7, 0xC7, 0x0004661f, 0x100, 0x10000, 0x80000), FLASH_ID("mac 25l512", 0xd8, 0xC7, 0x001020c2, 0x010, 0x10000, 0x10000), FLASH_ID("mac 25l1005", 0xd8, 0xd8, 0x001120c2, 0x010, 0x10000, 0x20000), FLASH_ID("mac 25l2005", 0xd8, 0xC7, 0x001220c2, 0x010, 0x10000, 0x40000), FLASH_ID("mac 25l4005", 0xd8, 0xC7, 0x001320c2, 0x010, 0x10000, 0x80000), FLASH_ID("mac 25l8005", 0xd8, 0xC7, 0x001420c2, 0x010, 0x10000, 0x100000), FLASH_ID("mac 25l1605", 0xd8, 0xC7, 0x001520c2, 0x100, 0x10000, 0x200000), FLASH_ID("mac 25l3205", 0xd8, 0xC7, 0x001620c2, 0x100, 0x10000, 0x400000), FLASH_ID("mac 25l6405", 0xd8, 0xC7, 0x001720c2, 0x100, 0x10000, 0x800000), FLASH_ID("win w25q32dw", 0xd8, 0xC7, 0x001660ef, 0x100, 0x10000, 0x400000), FLASH_ID("win w25q64cv", 0xd8, 0xC7, 0x001740ef, 0x100, 0x10000, 0x800000), FLASH_ID(NULL, 0, 0, 0, 0, 0, 0) }; openocd-0.7.0/src/flash/nor/ocl.c0000644000175000001440000002323412134336410013466 00000000000000/*************************************************************************** * Copyright (C) 2007 by Pavel Chromy * * chromy@asix.cz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "ocl.h" #include struct ocl_priv { struct arm_jtag *jtag_info; unsigned int buflen; unsigned int bufalign; }; static int ocl_erase_check(struct flash_bank *bank) { return ERROR_OK; } static int ocl_protect_check(struct flash_bank *bank) { return ERROR_OK; } /* flash_bank ocl 0 0 0 0 */ FLASH_BANK_COMMAND_HANDLER(ocl_flash_bank_command) { struct arm7_9_common *arm7_9; struct ocl_priv *ocl; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; arm7_9 = target_to_arm7_9(bank->target); if (!is_arm7_9(arm7_9)) return ERROR_TARGET_INVALID; ocl = bank->driver_priv = malloc(sizeof(struct ocl_priv)); ocl->jtag_info = &arm7_9->jtag_info; ocl->buflen = 0; ocl->bufalign = 1; return ERROR_OK; } static int ocl_erase(struct flash_bank *bank, int first, int last) { struct ocl_priv *ocl = bank->driver_priv; int retval; uint32_t dcc_buffer[3]; /* check preconditions */ if (bank->num_sectors == 0) return ERROR_FLASH_BANK_NOT_PROBED; if (bank->target->state != TARGET_RUNNING) { LOG_ERROR("target has to be running to communicate with the loader"); return ERROR_TARGET_NOT_RUNNING; } if ((first == 0) && (last == bank->num_sectors - 1)) { dcc_buffer[0] = OCL_ERASE_ALL; retval = embeddedice_send(ocl->jtag_info, dcc_buffer, 1); if (retval != ERROR_OK) return retval; } else { dcc_buffer[0] = OCL_ERASE_BLOCK; dcc_buffer[1] = first; dcc_buffer[2] = last; retval = embeddedice_send(ocl->jtag_info, dcc_buffer, 3); if (retval != ERROR_OK) return retval; } /* wait for response, fixed timeout of 1 s */ retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 1000); if (retval != ERROR_OK) return retval; /* receive response */ retval = embeddedice_receive(ocl->jtag_info, dcc_buffer + 1, 1); if (retval != ERROR_OK) return retval; if (dcc_buffer[1] != OCL_CMD_DONE) { if (dcc_buffer[0] == OCL_ERASE_ALL) LOG_ERROR("loader response to OCL_ERASE_ALL 0x%08" PRIx32 "", dcc_buffer[1]); else LOG_ERROR("loader response to OCL_ERASE_BLOCK 0x%08" PRIx32 "", dcc_buffer[1]); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } static int ocl_protect(struct flash_bank *bank, int set, int first, int last) { return ERROR_OK; } static int ocl_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct ocl_priv *ocl = bank->driver_priv; int retval; uint32_t *dcc_buffer; uint32_t *dcc_bufptr; int byteofs; int runlen; uint32_t chksum; int i; /* check preconditions */ if (ocl->buflen == 0 || ocl->bufalign == 0) return ERROR_FLASH_BANK_NOT_PROBED; if (bank->target->state != TARGET_RUNNING) { LOG_ERROR("target has to be running to communicate with the loader"); return ERROR_TARGET_NOT_RUNNING; } /* allocate buffer for max. ocl buffer + overhead */ dcc_buffer = malloc(sizeof(uint32_t)*(ocl->buflen/4 + 3)); while (count) { if (count + (offset % ocl->bufalign) > ocl->buflen) runlen = ocl->buflen - (offset % ocl->bufalign); else runlen = count; dcc_buffer[0] = OCL_FLASH_BLOCK | runlen; dcc_buffer[1] = offset; dcc_bufptr = &dcc_buffer[2]; *dcc_bufptr = 0xffffffff; byteofs = (offset % ocl->bufalign) % 4; chksum = OCL_CHKS_INIT; /* copy data to DCC buffer in proper byte order and properly aligned */ for (i = 0; i < runlen; i++) { switch (byteofs++) { case 0: *dcc_bufptr &= *(buffer++) | 0xffffff00; break; case 1: *dcc_bufptr &= ((*(buffer++)) << 8) | 0xffff00ff; break; case 2: *dcc_bufptr &= ((*(buffer++)) << 16) | 0xff00ffff; break; case 3: *dcc_bufptr &= ((*(buffer++)) << 24) | 0x00ffffff; chksum ^= *(dcc_bufptr++); *dcc_bufptr = 0xffffffff; byteofs = 0; break; } } /* add the remaining word to checksum */ if (byteofs) chksum ^= *(dcc_bufptr++); *(dcc_bufptr++) = chksum; /* send the data */ retval = embeddedice_send(ocl->jtag_info, dcc_buffer, dcc_bufptr-dcc_buffer); if (retval != ERROR_OK) { free(dcc_buffer); return retval; } /* wait for response, fixed timeout of 1 s */ retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 1000); if (retval != ERROR_OK) { free(dcc_buffer); return retval; } /* receive response */ retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1); if (retval != ERROR_OK) { free(dcc_buffer); return retval; } if (dcc_buffer[0] != OCL_CMD_DONE) { LOG_ERROR("loader response to OCL_FLASH_BLOCK 0x%08" PRIx32 "", dcc_buffer[0]); free(dcc_buffer); return ERROR_FLASH_OPERATION_FAILED; } count -= runlen; offset += runlen; } free(dcc_buffer); return ERROR_OK; } static int ocl_probe(struct flash_bank *bank) { struct ocl_priv *ocl = bank->driver_priv; int retval; uint32_t dcc_buffer[1]; int sectsize; int i; /* purge pending data in DCC */ embeddedice_receive(ocl->jtag_info, dcc_buffer, 1); dcc_buffer[0] = OCL_PROBE; retval = embeddedice_send(ocl->jtag_info, dcc_buffer, 1); if (retval != ERROR_OK) return retval; /* wait for response, fixed timeout of 1 s */ retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 1000); if (retval != ERROR_OK) return retval; /* receive response */ retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1); if (retval != ERROR_OK) return retval; if (dcc_buffer[0] != OCL_CMD_DONE) { LOG_ERROR("loader response to OCL_PROBE 0x%08" PRIx32 "", dcc_buffer[0]); return ERROR_FLASH_OPERATION_FAILED; } /* receive and fill in parameters, detection of loader is important, receive it one by one */ retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 0); if (retval != ERROR_OK) return retval; retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1); if (retval != ERROR_OK) return retval; bank->base = dcc_buffer[0]; retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 0); if (retval != ERROR_OK) return retval; retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1); if (retval != ERROR_OK) return retval; bank->size = dcc_buffer[0]; retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 0); if (retval != ERROR_OK) return retval; retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1); if (retval != ERROR_OK) return retval; bank->num_sectors = dcc_buffer[0]; retval = embeddedice_handshake(ocl->jtag_info, EICE_COMM_CTRL_WBIT, 0); if (retval != ERROR_OK) return retval; retval = embeddedice_receive(ocl->jtag_info, dcc_buffer, 1); if (retval != ERROR_OK) return retval; ocl->buflen = dcc_buffer[0] & 0xffff; ocl->bufalign = dcc_buffer[0] >> 16; bank->sectors = realloc(bank->sectors, sizeof(struct flash_sector)*bank->num_sectors); if (bank->num_sectors == 0) { LOG_ERROR("number of sectors shall be non zero value"); return ERROR_FLASH_BANK_INVALID; } if (bank->size % bank->num_sectors) { LOG_ERROR("bank size not divisible by number of sectors"); return ERROR_FLASH_BANK_INVALID; } sectsize = bank->size / bank->num_sectors; for (i = 0; i < bank->num_sectors; i++) { bank->sectors[i].offset = i * sectsize; bank->sectors[i].size = sectsize; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = -1; } if (ocl->bufalign == 0) ocl->bufalign = 1; if (ocl->buflen == 0) { LOG_ERROR("buflen shall be non zero value"); return ERROR_FLASH_BANK_INVALID; } if ((ocl->bufalign > ocl->buflen) || (ocl->buflen % ocl->bufalign)) { LOG_ERROR("buflen is not multiple of bufalign"); return ERROR_FLASH_BANK_INVALID; } if (ocl->buflen % 4) { LOG_ERROR("buflen shall be divisible by 4"); return ERROR_FLASH_BANK_INVALID; } return ERROR_OK; } static int ocl_info(struct flash_bank *bank, char *buf, int buf_size) { return ERROR_OK; } static int ocl_auto_probe(struct flash_bank *bank) { struct ocl_priv *ocl = bank->driver_priv; if (ocl->buflen == 0 || ocl->bufalign == 0) return ERROR_FLASH_BANK_NOT_PROBED; return ERROR_OK; } struct flash_driver ocl_flash = { .name = "ocl", .flash_bank_command = ocl_flash_bank_command, .erase = ocl_erase, .protect = ocl_protect, .write = ocl_write, .read = default_flash_read, .probe = ocl_probe, .erase_check = ocl_erase_check, .protect_check = ocl_protect_check, .info = ocl_info, .auto_probe = ocl_auto_probe, }; openocd-0.7.0/src/flash/nor/stm32lx.c0000644000175000001440000006616012137151331014232 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2011 by Clement Burin des Roziers * * clement.burin-des-roziers@hikob.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include #include #include #include /* stm32lx flash register locations */ #define FLASH_BASE 0x40023C00 #define FLASH_ACR 0x40023C00 #define FLASH_PECR 0x40023C04 #define FLASH_PDKEYR 0x40023C08 #define FLASH_PEKEYR 0x40023C0C #define FLASH_PRGKEYR 0x40023C10 #define FLASH_OPTKEYR 0x40023C14 #define FLASH_SR 0x40023C18 #define FLASH_OBR 0x40023C1C #define FLASH_WRPR 0x40023C20 /* FLASH_ACR bites */ #define FLASH_ACR__LATENCY (1<<0) #define FLASH_ACR__PRFTEN (1<<1) #define FLASH_ACR__ACC64 (1<<2) #define FLASH_ACR__SLEEP_PD (1<<3) #define FLASH_ACR__RUN_PD (1<<4) /* FLASH_PECR bits */ #define FLASH_PECR__PELOCK (1<<0) #define FLASH_PECR__PRGLOCK (1<<1) #define FLASH_PECR__OPTLOCK (1<<2) #define FLASH_PECR__PROG (1<<3) #define FLASH_PECR__DATA (1<<4) #define FLASH_PECR__FTDW (1<<8) #define FLASH_PECR__ERASE (1<<9) #define FLASH_PECR__FPRG (1<<10) #define FLASH_PECR__EOPIE (1<<16) #define FLASH_PECR__ERRIE (1<<17) #define FLASH_PECR__OBL_LAUNCH (1<<18) /* FLASH_SR bits */ #define FLASH_SR__BSY (1<<0) #define FLASH_SR__EOP (1<<1) #define FLASH_SR__ENDHV (1<<2) #define FLASH_SR__READY (1<<3) #define FLASH_SR__WRPERR (1<<8) #define FLASH_SR__PGAERR (1<<9) #define FLASH_SR__SIZERR (1<<10) #define FLASH_SR__OPTVERR (1<<11) /* Unlock keys */ #define PEKEY1 0x89ABCDEF #define PEKEY2 0x02030405 #define PRGKEY1 0x8C9DAEBF #define PRGKEY2 0x13141516 #define OPTKEY1 0xFBEAD9C8 #define OPTKEY2 0x24252627 /* other registers */ #define DBGMCU_IDCODE 0xE0042000 #define F_SIZE 0x1FF8004C /* Constants */ #define FLASH_PAGE_SIZE 256 #define FLASH_SECTOR_SIZE 4096 #define FLASH_PAGES_PER_SECTOR 16 #define FLASH_BANK0_ADDRESS 0x08000000 /* stm32lx option byte register location */ #define OB_RDP 0x1FF80000 #define OB_USER 0x1FF80004 #define OB_WRP0_1 0x1FF80008 #define OB_WRP2_3 0x1FF8000C /* OB_RDP values */ #define OB_RDP__LEVEL0 0xFF5500AA #define OB_RDP__LEVEL1 0xFFFF0000 /* stm32lx RCC register locations */ #define RCC_CR 0x40023800 #define RCC_ICSCR 0x40023804 #define RCC_CFGR 0x40023808 /* RCC_ICSCR bits */ #define RCC_ICSCR__MSIRANGE_MASK (7<<13) static int stm32lx_unlock_program_memory(struct flash_bank *bank); static int stm32lx_lock_program_memory(struct flash_bank *bank); static int stm32lx_enable_write_half_page(struct flash_bank *bank); static int stm32lx_erase_sector(struct flash_bank *bank, int sector); static int stm32lx_wait_until_bsy_clear(struct flash_bank *bank); struct stm32lx_flash_bank { int probed; bool has_dual_banks; uint32_t user_bank_size; }; /* flash bank stm32lx 0 0 */ FLASH_BANK_COMMAND_HANDLER(stm32lx_flash_bank_command) { struct stm32lx_flash_bank *stm32lx_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; /* Create the bank structure */ stm32lx_info = malloc(sizeof(struct stm32lx_flash_bank)); /* Check allocation */ if (stm32lx_info == NULL) { LOG_ERROR("failed to allocate bank structure"); return ERROR_FAIL; } bank->driver_priv = stm32lx_info; stm32lx_info->probed = 0; stm32lx_info->has_dual_banks = false; stm32lx_info->user_bank_size = bank->size; return ERROR_OK; } static int stm32lx_protect_check(struct flash_bank *bank) { int retval; struct target *target = bank->target; uint32_t wrpr; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* * Read the WRPR word, and check each bit (corresponding to each * flash sector */ retval = target_read_u32(target, FLASH_WRPR, &wrpr); if (retval != ERROR_OK) return retval; for (int i = 0; i < 32; i++) { if (wrpr & (1 << i)) bank->sectors[i].is_protected = 1; else bank->sectors[i].is_protected = 0; } return ERROR_OK; } static int stm32lx_erase(struct flash_bank *bank, int first, int last) { int retval; /* * It could be possible to do a mass erase if all sectors must be * erased, but it is not implemented yet. */ if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* * Loop over the selected sectors and erase them */ for (int i = first; i <= last; i++) { retval = stm32lx_erase_sector(bank, i); if (retval != ERROR_OK) return retval; bank->sectors[i].is_erased = 1; } return ERROR_OK; } static int stm32lx_protect(struct flash_bank *bank, int set, int first, int last) { LOG_WARNING("protection of the STM32L flash is not implemented"); return ERROR_OK; } static int stm32lx_write_half_pages(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t buffer_size = 16384; struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[3]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; /* see contib/loaders/flash/stm32lx.S for src */ static const uint8_t stm32lx_flash_write_code[] = { /* write_word: */ 0x00, 0x23, /* movs r3, #0 */ 0x04, 0xe0, /* b test_done */ /* write_word: */ 0x51, 0xf8, 0x04, 0xcb, /* ldr ip, [r1], #4 */ 0x40, 0xf8, 0x04, 0xcb, /* str ip, [r0], #4 */ 0x01, 0x33, /* adds r3, #1 */ /* test_done: */ 0x93, 0x42, /* cmp r3, r2 */ 0xf8, 0xd3, /* bcc write_word */ 0x00, 0xbe, /* bkpt 0 */ }; /* Check if there is an even number of half pages (128bytes) */ if (count % 128) { LOG_ERROR("there should be an even number " "of half pages = 128 bytes (count = %" PRIi32 " bytes)", count); return ERROR_FAIL; } /* flash write code */ if (target_alloc_working_area(target, sizeof(stm32lx_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_DEBUG("no working area for block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; }; /* Write the flashing code */ retval = target_write_buffer(target, write_algorithm->address, sizeof(stm32lx_flash_write_code), (uint8_t *)stm32lx_flash_write_code); if (retval != ERROR_OK) { target_free_working_area(target, write_algorithm); return retval; } /* Allocate half pages memory */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { if (buffer_size > 1024) buffer_size -= 1024; else buffer_size /= 2; if (buffer_size <= 256) { /* we already allocated the writing code, but failed to get a * buffer, free the algorithm */ target_free_working_area(target, write_algorithm); LOG_WARNING("no large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* Enable half-page write */ retval = stm32lx_enable_write_half_page(bank); if (retval != ERROR_OK) { target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); return retval; } struct armv7m_common *armv7m = target_to_armv7m(target); if (armv7m == NULL) { /* something is very wrong if armv7m is NULL */ LOG_ERROR("unable to get armv7m target"); return retval; } /* save any DEMCR flags and configure target to catch any Hard Faults */ uint32_t demcr_save = armv7m->demcr; armv7m->demcr = VC_HARDERR; /* Loop while there are bytes to write */ while (count > 0) { uint32_t this_count; this_count = (count > buffer_size) ? buffer_size : count; /* Write the next half pages */ retval = target_write_buffer(target, source->address, this_count, buffer); if (retval != ERROR_OK) break; /* 4: Store useful information in the registers */ /* the destination address of the copy (R0) */ buf_set_u32(reg_params[0].value, 0, 32, address); /* The source address of the copy (R1) */ buf_set_u32(reg_params[1].value, 0, 32, source->address); /* The length of the copy (R2) */ buf_set_u32(reg_params[2].value, 0, 32, this_count / 4); /* 5: Execute the bunch of code */ retval = target_run_algorithm(target, 0, NULL, sizeof(reg_params) / sizeof(*reg_params), reg_params, write_algorithm->address, 0, 10000, &armv7m_info); if (retval != ERROR_OK) break; /* check for Hard Fault */ if (armv7m->exception_number == 3) break; /* 6: Wait while busy */ retval = stm32lx_wait_until_bsy_clear(bank); if (retval != ERROR_OK) break; buffer += this_count; address += this_count; count -= this_count; } /* restore previous flags */ armv7m->demcr = demcr_save; if (armv7m->exception_number == 3) { /* the stm32l15x devices seem to have an issue when blank. * if a ram loader is executed on a blank device it will * Hard Fault, this issue does not happen for a already programmed device. * A related issue is described in the stm32l151xx errata (Doc ID 17721 Rev 6 - 2.1.3). * The workaround of handling the Hard Fault exception does work, but makes the * loader more complicated, as a compromise we manually write the pages, programming time * is reduced by 50% using this slower method. */ LOG_WARNING("couldn't use loader, falling back to page memory writes"); while (count > 0) { uint32_t this_count; this_count = (count > 128) ? 128 : count; /* Write the next half pages */ retval = target_write_buffer(target, address, this_count, buffer); if (retval != ERROR_OK) break; /* Wait while busy */ retval = stm32lx_wait_until_bsy_clear(bank); if (retval != ERROR_OK) break; buffer += this_count; address += this_count; count -= this_count; } } if (retval == ERROR_OK) retval = stm32lx_lock_program_memory(bank); target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); return retval; } static int stm32lx_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t halfpages_number; uint32_t bytes_remaining = 0; uint32_t address = bank->base + offset; uint32_t bytes_written = 0; int retval, retval2; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset & 0x3) { LOG_ERROR("offset 0x%" PRIx32 " breaks required 4-byte alignment", offset); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } retval = stm32lx_unlock_program_memory(bank); if (retval != ERROR_OK) return retval; /* first we need to write any unaligned head bytes upto * the next 128 byte page */ if (offset % 128) bytes_remaining = MIN(count, 128 - (offset % 128)); while (bytes_remaining > 0) { uint8_t value[4] = {0xff, 0xff, 0xff, 0xff}; /* copy remaining bytes into the write buffer */ uint32_t bytes_to_write = MIN(4, bytes_remaining); memcpy(value, buffer + bytes_written, bytes_to_write); retval = target_write_buffer(target, address, 4, value); if (retval != ERROR_OK) goto reset_pg_and_lock; bytes_written += bytes_to_write; bytes_remaining -= bytes_to_write; address += 4; retval = stm32lx_wait_until_bsy_clear(bank); if (retval != ERROR_OK) goto reset_pg_and_lock; } offset += bytes_written; count -= bytes_written; /* this should always pass this check here */ assert((offset % 128) == 0); /* calculate half pages */ halfpages_number = count / 128; if (halfpages_number) { retval = stm32lx_write_half_pages(bank, buffer + bytes_written, offset, 128 * halfpages_number); if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* attempt slow memory writes */ LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); halfpages_number = 0; } else { if (retval != ERROR_OK) return ERROR_FAIL; } } /* write any remaining bytes */ uint32_t page_bytes_written = 128 * halfpages_number; bytes_written += page_bytes_written; address += page_bytes_written; bytes_remaining = count - page_bytes_written; retval = stm32lx_unlock_program_memory(bank); if (retval != ERROR_OK) return retval; while (bytes_remaining > 0) { uint8_t value[4] = {0xff, 0xff, 0xff, 0xff}; /* copy remaining bytes into the write buffer */ uint32_t bytes_to_write = MIN(4, bytes_remaining); memcpy(value, buffer + bytes_written, bytes_to_write); retval = target_write_buffer(target, address, 4, value); if (retval != ERROR_OK) goto reset_pg_and_lock; bytes_written += bytes_to_write; bytes_remaining -= bytes_to_write; address += 4; retval = stm32lx_wait_until_bsy_clear(bank); if (retval != ERROR_OK) goto reset_pg_and_lock; } reset_pg_and_lock: retval2 = stm32lx_lock_program_memory(bank); if (retval == ERROR_OK) retval = retval2; return retval; } static int stm32lx_probe(struct flash_bank *bank) { struct target *target = bank->target; struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv; int i; uint16_t flash_size_in_kb; uint16_t max_flash_size_in_kb; uint32_t device_id; uint32_t base_address = FLASH_BANK0_ADDRESS; uint32_t second_bank_base; uint32_t first_bank_size_in_kb; stm32lx_info->probed = 0; /* read stm32 device id register */ int retval = target_read_u32(target, DBGMCU_IDCODE, &device_id); if (retval != ERROR_OK) return retval; LOG_DEBUG("device id = 0x%08" PRIx32 "", device_id); /* set max flash size depending on family */ switch (device_id & 0xfff) { case 0x416: max_flash_size_in_kb = 128; break; case 0x427: /* single bank, high density */ max_flash_size_in_kb = 256; break; case 0x436: /* According to ST, the devices with id 0x436 have dual bank flash and comes with * a total flash size of 384k or 256kb. However, the first bank is always 192kb, * and second one holds the rest. The reason is that the 256kb version is actually * the same physical flash but only the first 256kb are verified. */ max_flash_size_in_kb = 384; first_bank_size_in_kb = 192; stm32lx_info->has_dual_banks = true; break; default: LOG_WARNING("Cannot identify target as a STM32L family."); return ERROR_FAIL; } /* Get the flash size from target. */ retval = target_read_u16(target, F_SIZE, &flash_size_in_kb); /* Failed reading flash size or flash size invalid (early silicon), * default to max target family */ if (retval != ERROR_OK || flash_size_in_kb == 0xffff || flash_size_in_kb == 0) { LOG_WARNING("STM32L flash size failed, probe inaccurate - assuming %dk flash", max_flash_size_in_kb); flash_size_in_kb = max_flash_size_in_kb; } else if (flash_size_in_kb > max_flash_size_in_kb) { LOG_WARNING("STM32L probed flash size assumed incorrect since FLASH_SIZE=%dk > %dk, - assuming %dk flash", flash_size_in_kb, max_flash_size_in_kb, max_flash_size_in_kb); flash_size_in_kb = max_flash_size_in_kb; } if (stm32lx_info->has_dual_banks) { /* Use the configured base address to determine if this is the first or second flash bank. * Verify that the base address is reasonably correct and determine the flash bank size */ second_bank_base = base_address + first_bank_size_in_kb * 1024; if (bank->base == second_bank_base) { /* This is the second bank */ base_address = second_bank_base; flash_size_in_kb = flash_size_in_kb - first_bank_size_in_kb; } else if (bank->base == 0 || bank->base == base_address) { /* This is the first bank */ flash_size_in_kb = first_bank_size_in_kb; } else { LOG_WARNING("STM32L flash bank base address config is incorrect. 0x%x but should rather be 0x%x or 0x%x", bank->base, base_address, second_bank_base); return ERROR_FAIL; } LOG_INFO("STM32L flash has dual banks. Bank (%d) size is %dkb, base address is 0x%x", bank->bank_number, flash_size_in_kb, base_address); } else { LOG_INFO("STM32L flash size is %dkb, base address is 0x%x", flash_size_in_kb, base_address); } /* if the user sets the size manually then ignore the probed value * this allows us to work around devices that have a invalid flash size register value */ if (stm32lx_info->user_bank_size) { flash_size_in_kb = stm32lx_info->user_bank_size / 1024; LOG_INFO("ignoring flash probed value, using configured bank size: %dkbytes", flash_size_in_kb); } /* STM32L - we have 32 sectors, 16 pages per sector -> 512 pages * 16 pages for a protection area */ /* calculate numbers of sectors (4kB per sector) */ int num_sectors = (flash_size_in_kb * 1024) / FLASH_SECTOR_SIZE; if (bank->sectors) { free(bank->sectors); bank->sectors = NULL; } bank->size = flash_size_in_kb * 1024; bank->base = base_address; bank->num_sectors = num_sectors; bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors); if (bank->sectors == NULL) { LOG_ERROR("failed to allocate bank sectors"); return ERROR_FAIL; } for (i = 0; i < num_sectors; i++) { bank->sectors[i].offset = i * FLASH_SECTOR_SIZE; bank->sectors[i].size = FLASH_SECTOR_SIZE; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } stm32lx_info->probed = 1; return ERROR_OK; } static int stm32lx_auto_probe(struct flash_bank *bank) { struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv; if (stm32lx_info->probed) return ERROR_OK; return stm32lx_probe(bank); } static int stm32lx_erase_check(struct flash_bank *bank) { struct target *target = bank->target; const int buffer_size = 4096; int i; uint32_t nBytes; int retval = ERROR_OK; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } uint8_t *buffer = malloc(buffer_size); if (buffer == NULL) { LOG_ERROR("failed to allocate read buffer"); return ERROR_FAIL; } for (i = 0; i < bank->num_sectors; i++) { uint32_t j; bank->sectors[i].is_erased = 1; /* Loop chunk by chunk over the sector */ for (j = 0; j < bank->sectors[i].size; j += buffer_size) { uint32_t chunk; chunk = buffer_size; if (chunk > (j - bank->sectors[i].size)) chunk = (j - bank->sectors[i].size); retval = target_read_memory(target, bank->base + bank->sectors[i].offset + j, 4, chunk / 4, buffer); if (retval != ERROR_OK) break; for (nBytes = 0; nBytes < chunk; nBytes++) { if (buffer[nBytes] != 0x00) { bank->sectors[i].is_erased = 0; break; } } } if (retval != ERROR_OK) break; } free(buffer); return retval; } static int stm32lx_get_info(struct flash_bank *bank, char *buf, int buf_size) { /* This method must return a string displaying information about the bank */ struct target *target = bank->target; uint32_t device_id; int printed; /* read stm32 device id register */ int retval = target_read_u32(target, DBGMCU_IDCODE, &device_id); if (retval != ERROR_OK) return retval; if ((device_id & 0xfff) == 0x416) { printed = snprintf(buf, buf_size, "stm32lx - Rev: "); buf += printed; buf_size -= printed; switch (device_id >> 16) { case 0x1000: snprintf(buf, buf_size, "A"); break; case 0x1008: snprintf(buf, buf_size, "Y"); break; case 0x1018: snprintf(buf, buf_size, "X"); break; case 0x1038: snprintf(buf, buf_size, "W"); break; case 0x1078: snprintf(buf, buf_size, "V"); break; default: snprintf(buf, buf_size, "unknown"); break; } } else if ((device_id & 0xfff) == 0x436) { printed = snprintf(buf, buf_size, "stm32lx (HD) - Rev: "); buf += printed; buf_size -= printed; switch (device_id >> 16) { case 0x1000: snprintf(buf, buf_size, "A"); break; case 0x1008: snprintf(buf, buf_size, "Z"); break; case 0x1018: snprintf(buf, buf_size, "Y"); break; default: snprintf(buf, buf_size, "unknown"); break; } } else { snprintf(buf, buf_size, "Cannot identify target as a stm32lx"); return ERROR_FAIL; } return ERROR_OK; } static const struct command_registration stm32lx_exec_command_handlers[] = { COMMAND_REGISTRATION_DONE }; static const struct command_registration stm32lx_command_handlers[] = { { .name = "stm32lx", .mode = COMMAND_ANY, .help = "stm32lx flash command group", .usage = "", .chain = stm32lx_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct flash_driver stm32lx_flash = { .name = "stm32lx", .commands = stm32lx_command_handlers, .flash_bank_command = stm32lx_flash_bank_command, .erase = stm32lx_erase, .protect = stm32lx_protect, .write = stm32lx_write, .read = default_flash_read, .probe = stm32lx_probe, .auto_probe = stm32lx_auto_probe, .erase_check = stm32lx_erase_check, .protect_check = stm32lx_protect_check, .info = stm32lx_get_info, }; /* Static methods implementation */ static int stm32lx_unlock_program_memory(struct flash_bank *bank) { struct target *target = bank->target; int retval; uint32_t reg32; /* * Unlocking the program memory is done by unlocking the PECR, * then by writing the 2 PRGKEY to the PRGKEYR register */ /* check flash is not already unlocked */ retval = target_read_u32(target, FLASH_PECR, ®32); if (retval != ERROR_OK) return retval; if ((reg32 & FLASH_PECR__PRGLOCK) == 0) return ERROR_OK; /* To unlock the PECR write the 2 PEKEY to the PEKEYR register */ retval = target_write_u32(target, FLASH_PEKEYR, PEKEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, FLASH_PEKEYR, PEKEY2); if (retval != ERROR_OK) return retval; /* Make sure it worked */ retval = target_read_u32(target, FLASH_PECR, ®32); if (retval != ERROR_OK) return retval; if (reg32 & FLASH_PECR__PELOCK) { LOG_ERROR("PELOCK is not cleared :("); return ERROR_FLASH_OPERATION_FAILED; } retval = target_write_u32(target, FLASH_PRGKEYR, PRGKEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, FLASH_PRGKEYR, PRGKEY2); if (retval != ERROR_OK) return retval; /* Make sure it worked */ retval = target_read_u32(target, FLASH_PECR, ®32); if (retval != ERROR_OK) return retval; if (reg32 & FLASH_PECR__PRGLOCK) { LOG_ERROR("PRGLOCK is not cleared :("); return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } static int stm32lx_enable_write_half_page(struct flash_bank *bank) { struct target *target = bank->target; int retval; uint32_t reg32; /** * Unlock the program memory, then set the FPRG bit in the PECR register. */ retval = stm32lx_unlock_program_memory(bank); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, FLASH_PECR, ®32); if (retval != ERROR_OK) return retval; reg32 |= FLASH_PECR__FPRG; retval = target_write_u32(target, FLASH_PECR, reg32); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, FLASH_PECR, ®32); if (retval != ERROR_OK) return retval; reg32 |= FLASH_PECR__PROG; retval = target_write_u32(target, FLASH_PECR, reg32); return retval; } static int stm32lx_lock_program_memory(struct flash_bank *bank) { struct target *target = bank->target; int retval; uint32_t reg32; /* To lock the program memory, simply set the lock bit and lock PECR */ retval = target_read_u32(target, FLASH_PECR, ®32); if (retval != ERROR_OK) return retval; reg32 |= FLASH_PECR__PRGLOCK; retval = target_write_u32(target, FLASH_PECR, reg32); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, FLASH_PECR, ®32); if (retval != ERROR_OK) return retval; reg32 |= FLASH_PECR__PELOCK; retval = target_write_u32(target, FLASH_PECR, reg32); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int stm32lx_erase_sector(struct flash_bank *bank, int sector) { struct target *target = bank->target; int retval; uint32_t reg32; /* * To erase a sector (i.e. FLASH_PAGES_PER_SECTOR pages), * first unlock the memory, loop over the pages of this sector * and write 0x0 to its first word. */ retval = stm32lx_unlock_program_memory(bank); if (retval != ERROR_OK) return retval; for (int page = 0; page < FLASH_PAGES_PER_SECTOR; page++) { reg32 = FLASH_PECR__PROG | FLASH_PECR__ERASE; retval = target_write_u32(target, FLASH_PECR, reg32); if (retval != ERROR_OK) return retval; retval = stm32lx_wait_until_bsy_clear(bank); if (retval != ERROR_OK) return retval; uint32_t addr = bank->base + bank->sectors[sector].offset + (page * FLASH_PAGE_SIZE); retval = target_write_u32(target, addr, 0x0); if (retval != ERROR_OK) return retval; retval = stm32lx_wait_until_bsy_clear(bank); if (retval != ERROR_OK) return retval; } retval = stm32lx_lock_program_memory(bank); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int stm32lx_wait_until_bsy_clear(struct flash_bank *bank) { struct target *target = bank->target; uint32_t status; int retval = ERROR_OK; int timeout = 100; /* wait for busy to clear */ for (;;) { retval = target_read_u32(target, FLASH_SR, &status); if (retval != ERROR_OK) return retval; if ((status & FLASH_SR__BSY) == 0) break; if (timeout-- <= 0) { LOG_ERROR("timed out waiting for flash"); return ERROR_FAIL; } alive_sleep(1); } if (status & FLASH_SR__WRPERR) { LOG_ERROR("access denied / write protected"); retval = ERROR_FAIL; } if (status & FLASH_SR__PGAERR) { LOG_ERROR("invalid program address"); retval = ERROR_FAIL; } return retval; } openocd-0.7.0/src/flash/nor/stmsmi.c0000644000175000001440000004327612134336410014235 00000000000000/*************************************************************************** * Copyright (C) 2010 by Antonio Borneo * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /* STM Serial Memory Interface (SMI) controller is a SPI bus controller * specifically designed for SPI memories. * Only SPI "mode 3" (CPOL=1 and CPHA=1) is supported. * Two working modes are available: * - SW mode: the SPI is controlled by SW. Any custom commands can be sent * on the bus. * - HW mode: the SPI but is under SMI control. Memory content is directly * accessible in CPU memory space. CPU can read, write and execute memory * content. */ /* ATTENTION: * To have flash memory mapped in CPU memory space, the SMI controller * have to be in "HW mode". This requires following constraints: * 1) The command "reset init" have to initialize SMI controller and put * it in HW mode; * 2) every command in this file have to return to prompt in HW mode. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include "spi.h" #include #include #define SMI_READ_REG(a) (_SMI_READ_REG(a)) #define _SMI_READ_REG(a) \ { \ int __a; \ uint32_t __v; \ \ __a = target_read_u32(target, io_base + (a), &__v); \ if (__a != ERROR_OK) \ return __a; \ __v; \ } #define SMI_WRITE_REG(a, v) \ { \ int __r; \ \ __r = target_write_u32(target, io_base + (a), (v)); \ if (__r != ERROR_OK) \ return __r; \ } #define SMI_POLL_TFF(timeout) \ { \ int __r; \ \ __r = poll_tff(target, io_base, timeout); \ if (__r != ERROR_OK) \ return __r; \ } #define SMI_SET_SW_MODE() SMI_WRITE_REG(SMI_CR1, \ SMI_READ_REG(SMI_CR1) | SMI_SW_MODE) #define SMI_SET_HWWB_MODE() SMI_WRITE_REG(SMI_CR1, \ (SMI_READ_REG(SMI_CR1) | SMI_WB_MODE) & ~SMI_SW_MODE) #define SMI_SET_HW_MODE() SMI_WRITE_REG(SMI_CR1, \ SMI_READ_REG(SMI_CR1) & ~(SMI_SW_MODE | SMI_WB_MODE)) #define SMI_CLEAR_TFF() SMI_WRITE_REG(SMI_SR, ~SMI_TFF) #define SMI_BANK_SIZE (0x01000000) #define SMI_CR1 (0x00) /* Control register 1 */ #define SMI_CR2 (0x04) /* Control register 2 */ #define SMI_SR (0x08) /* Status register */ #define SMI_TR (0x0c) /* TX */ #define SMI_RR (0x10) /* RX */ /* fields in SMI_CR1 */ #define SMI_SW_MODE 0x10000000 /* set to enable SW Mode */ #define SMI_WB_MODE 0x20000000 /* Write Burst Mode */ /* fields in SMI_CR2 */ #define SMI_TX_LEN_1 0x00000001 /* data length = 1 byte */ #define SMI_TX_LEN_4 0x00000004 /* data length = 4 byte */ #define SMI_RX_LEN_3 0x00000030 /* data length = 3 byte */ #define SMI_SEND 0x00000080 /* Send data */ #define SMI_RSR 0x00000400 /* reads status reg */ #define SMI_WE 0x00000800 /* Write Enable */ #define SMI_SEL_BANK0 0x00000000 /* Select Bank0 */ #define SMI_SEL_BANK1 0x00001000 /* Select Bank1 */ #define SMI_SEL_BANK2 0x00002000 /* Select Bank2 */ #define SMI_SEL_BANK3 0x00003000 /* Select Bank3 */ /* fields in SMI_SR */ #define SMI_TFF 0x00000100 /* Transfer Finished Flag */ /* Commands */ #define SMI_READ_ID 0x0000009F /* Read Flash Identification */ /* Timeout in ms */ #define SMI_CMD_TIMEOUT (100) #define SMI_PROBE_TIMEOUT (100) #define SMI_MAX_TIMEOUT (3000) struct stmsmi_flash_bank { int probed; uint32_t io_base; uint32_t bank_num; struct flash_device *dev; }; struct stmsmi_target { char *name; uint32_t tap_idcode; uint32_t smi_base; uint32_t io_base; }; static struct stmsmi_target target_devices[] = { /* name, tap_idcode, smi_base, io_base */ { "SPEAr3xx/6xx", 0x07926041, 0xf8000000, 0xfc000000 }, { "STR75x", 0x4f1f0041, 0x80000000, 0x90000000 }, { NULL, 0, 0, 0 } }; FLASH_BANK_COMMAND_HANDLER(stmsmi_flash_bank_command) { struct stmsmi_flash_bank *stmsmi_info; LOG_DEBUG("%s", __func__); if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; stmsmi_info = malloc(sizeof(struct stmsmi_flash_bank)); if (stmsmi_info == NULL) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } bank->driver_priv = stmsmi_info; stmsmi_info->probed = 0; return ERROR_OK; } /* Poll transmit finished flag */ /* timeout in ms */ static int poll_tff(struct target *target, uint32_t io_base, int timeout) { long long endtime; if (SMI_READ_REG(SMI_SR) & SMI_TFF) return ERROR_OK; endtime = timeval_ms() + timeout; do { alive_sleep(1); if (SMI_READ_REG(SMI_SR) & SMI_TFF) return ERROR_OK; } while (timeval_ms() < endtime); LOG_ERROR("Timeout while polling TFF"); return ERROR_FLASH_OPERATION_FAILED; } /* Read the status register of the external SPI flash chip. * The operation is triggered by setting SMI_RSR bit. * SMI sends the proper SPI command (0x05) and returns value in SMI_SR */ static int read_status_reg(struct flash_bank *bank, uint32_t *status) { struct target *target = bank->target; struct stmsmi_flash_bank *stmsmi_info = bank->driver_priv; uint32_t io_base = stmsmi_info->io_base; /* clear transmit finished flag */ SMI_CLEAR_TFF(); /* Read status */ SMI_WRITE_REG(SMI_CR2, stmsmi_info->bank_num | SMI_RSR); /* Poll transmit finished flag */ SMI_POLL_TFF(SMI_CMD_TIMEOUT); /* clear transmit finished flag */ SMI_CLEAR_TFF(); *status = SMI_READ_REG(SMI_SR) & 0x0000ffff; /* clean-up SMI_CR2 */ SMI_WRITE_REG(SMI_CR2, 0); /* AB: Required ? */ return ERROR_OK; } /* check for WIP (write in progress) bit in status register */ /* timeout in ms */ static int wait_till_ready(struct flash_bank *bank, int timeout) { uint32_t status; int retval; long long endtime; endtime = timeval_ms() + timeout; do { /* read flash status register */ retval = read_status_reg(bank, &status); if (retval != ERROR_OK) return retval; if ((status & SPIFLASH_BSY_BIT) == 0) return ERROR_OK; alive_sleep(1); } while (timeval_ms() < endtime); LOG_ERROR("timeout"); return ERROR_FAIL; } /* Send "write enable" command to SPI flash chip. * The operation is triggered by setting SMI_WE bit, and SMI sends * the proper SPI command (0x06) */ static int smi_write_enable(struct flash_bank *bank) { struct target *target = bank->target; struct stmsmi_flash_bank *stmsmi_info = bank->driver_priv; uint32_t io_base = stmsmi_info->io_base; uint32_t status; int retval; /* Enter in HW mode */ SMI_SET_HW_MODE(); /* AB: is this correct ?*/ /* clear transmit finished flag */ SMI_CLEAR_TFF(); /* Send write enable command */ SMI_WRITE_REG(SMI_CR2, stmsmi_info->bank_num | SMI_WE); /* Poll transmit finished flag */ SMI_POLL_TFF(SMI_CMD_TIMEOUT); /* read flash status register */ retval = read_status_reg(bank, &status); if (retval != ERROR_OK) return retval; /* Check write enabled */ if ((status & SPIFLASH_WE_BIT) == 0) { LOG_ERROR("Cannot enable write to flash. Status=0x%08" PRIx32, status); return ERROR_FAIL; } return ERROR_OK; } static uint32_t erase_command(struct stmsmi_flash_bank *stmsmi_info, uint32_t offset) { union { uint32_t command; uint8_t x[4]; } cmd; cmd.x[0] = stmsmi_info->dev->erase_cmd; cmd.x[1] = offset >> 16; cmd.x[2] = offset >> 8; cmd.x[3] = offset; return cmd.command; } static int smi_erase_sector(struct flash_bank *bank, int sector) { struct target *target = bank->target; struct stmsmi_flash_bank *stmsmi_info = bank->driver_priv; uint32_t io_base = stmsmi_info->io_base; uint32_t cmd; int retval; retval = smi_write_enable(bank); if (retval != ERROR_OK) return retval; /* Switch to SW mode to send sector erase command */ SMI_SET_SW_MODE(); /* clear transmit finished flag */ SMI_CLEAR_TFF(); /* send SPI command "block erase" */ cmd = erase_command(stmsmi_info, bank->sectors[sector].offset); SMI_WRITE_REG(SMI_TR, cmd); SMI_WRITE_REG(SMI_CR2, stmsmi_info->bank_num | SMI_SEND | SMI_TX_LEN_4); /* Poll transmit finished flag */ SMI_POLL_TFF(SMI_CMD_TIMEOUT); /* poll WIP for end of self timed Sector Erase cycle */ retval = wait_till_ready(bank, SMI_MAX_TIMEOUT); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int stmsmi_erase(struct flash_bank *bank, int first, int last) { struct target *target = bank->target; struct stmsmi_flash_bank *stmsmi_info = bank->driver_priv; uint32_t io_base = stmsmi_info->io_base; int retval = ERROR_OK; int sector; LOG_DEBUG("%s: from sector %d to sector %d", __func__, first, last); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if ((first < 0) || (last < first) || (last >= bank->num_sectors)) { LOG_ERROR("Flash sector invalid"); return ERROR_FLASH_SECTOR_INVALID; } if (!(stmsmi_info->probed)) { LOG_ERROR("Flash bank not probed"); return ERROR_FLASH_BANK_NOT_PROBED; } for (sector = first; sector <= last; sector++) { if (bank->sectors[sector].is_protected) { LOG_ERROR("Flash sector %d protected", sector); return ERROR_FAIL; } } for (sector = first; sector <= last; sector++) { retval = smi_erase_sector(bank, sector); if (retval != ERROR_OK) break; keep_alive(); } /* Switch to HW mode before return to prompt */ SMI_SET_HW_MODE(); return retval; } static int stmsmi_protect(struct flash_bank *bank, int set, int first, int last) { int sector; for (sector = first; sector <= last; sector++) bank->sectors[sector].is_protected = set; return ERROR_OK; } static int smi_write_buffer(struct flash_bank *bank, uint8_t *buffer, uint32_t address, uint32_t len) { struct target *target = bank->target; struct stmsmi_flash_bank *stmsmi_info = bank->driver_priv; uint32_t io_base = stmsmi_info->io_base; int retval; LOG_DEBUG("%s: address=0x%08" PRIx32 " len=0x%08" PRIx32, __func__, address, len); retval = smi_write_enable(bank); if (retval != ERROR_OK) return retval; /* HW mode, write burst mode */ SMI_SET_HWWB_MODE(); retval = target_write_buffer(target, address, len, buffer); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int stmsmi_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; struct stmsmi_flash_bank *stmsmi_info = bank->driver_priv; uint32_t io_base = stmsmi_info->io_base; uint32_t cur_count, page_size, page_offset; int sector; int retval = ERROR_OK; LOG_DEBUG("%s: offset=0x%08" PRIx32 " count=0x%08" PRIx32, __func__, offset, count); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset + count > stmsmi_info->dev->size_in_bytes) { LOG_WARNING("Write pasts end of flash. Extra data discarded."); count = stmsmi_info->dev->size_in_bytes - offset; } /* Check sector protection */ for (sector = 0; sector < bank->num_sectors; sector++) { /* Start offset in or before this sector? */ /* End offset in or behind this sector? */ if ((offset < (bank->sectors[sector].offset + bank->sectors[sector].size)) && ((offset + count - 1) >= bank->sectors[sector].offset) && bank->sectors[sector].is_protected) { LOG_ERROR("Flash sector %d protected", sector); return ERROR_FAIL; } } page_size = stmsmi_info->dev->pagesize; /* unaligned buffer head */ if (count > 0 && (offset & 3) != 0) { cur_count = 4 - (offset & 3); if (cur_count > count) cur_count = count; retval = smi_write_buffer(bank, buffer, bank->base + offset, cur_count); if (retval != ERROR_OK) goto err; offset += cur_count; buffer += cur_count; count -= cur_count; } page_offset = offset % page_size; /* central part, aligned words */ while (count >= 4) { /* clip block at page boundary */ if (page_offset + count > page_size) cur_count = page_size - page_offset; else cur_count = count & ~3; retval = smi_write_buffer(bank, buffer, bank->base + offset, cur_count); if (retval != ERROR_OK) goto err; page_offset = 0; buffer += cur_count; offset += cur_count; count -= cur_count; keep_alive(); } /* buffer tail */ if (count > 0) retval = smi_write_buffer(bank, buffer, bank->base + offset, count); err: /* Switch to HW mode before return to prompt */ SMI_SET_HW_MODE(); return retval; } /* Return ID of flash device */ /* On exit, SW mode is kept */ static int read_flash_id(struct flash_bank *bank, uint32_t *id) { struct target *target = bank->target; struct stmsmi_flash_bank *stmsmi_info = bank->driver_priv; uint32_t io_base = stmsmi_info->io_base; int retval; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* poll WIP */ retval = wait_till_ready(bank, SMI_PROBE_TIMEOUT); if (retval != ERROR_OK) return retval; /* enter in SW mode */ SMI_SET_SW_MODE(); /* clear transmit finished flag */ SMI_CLEAR_TFF(); /* Send SPI command "read ID" */ SMI_WRITE_REG(SMI_TR, SMI_READ_ID); SMI_WRITE_REG(SMI_CR2, stmsmi_info->bank_num | SMI_SEND | SMI_RX_LEN_3 | SMI_TX_LEN_1); /* Poll transmit finished flag */ SMI_POLL_TFF(SMI_CMD_TIMEOUT); /* clear transmit finished flag */ SMI_CLEAR_TFF(); /* read ID from Receive Register */ *id = SMI_READ_REG(SMI_RR) & 0x00ffffff; return ERROR_OK; } static int stmsmi_probe(struct flash_bank *bank) { struct target *target = bank->target; struct stmsmi_flash_bank *stmsmi_info = bank->driver_priv; uint32_t io_base; struct flash_sector *sectors; uint32_t id = 0; /* silence uninitialized warning */ struct stmsmi_target *target_device; int retval; if (stmsmi_info->probed) free(bank->sectors); stmsmi_info->probed = 0; for (target_device = target_devices ; target_device->name ; ++target_device) if (target_device->tap_idcode == target->tap->idcode) break; if (!target_device->name) { LOG_ERROR("Device ID 0x%" PRIx32 " is not known as SMI capable", target->tap->idcode); return ERROR_FAIL; } switch (bank->base - target_device->smi_base) { case 0: stmsmi_info->bank_num = SMI_SEL_BANK0; break; case SMI_BANK_SIZE: stmsmi_info->bank_num = SMI_SEL_BANK1; break; case 2*SMI_BANK_SIZE: stmsmi_info->bank_num = SMI_SEL_BANK2; break; case 3*SMI_BANK_SIZE: stmsmi_info->bank_num = SMI_SEL_BANK3; break; default: LOG_ERROR("Invalid SMI base address 0x%" PRIx32, bank->base); return ERROR_FAIL; } io_base = target_device->io_base; stmsmi_info->io_base = io_base; LOG_DEBUG("Valid SMI on device %s at address 0x%" PRIx32, target_device->name, bank->base); /* read and decode flash ID; returns in SW mode */ retval = read_flash_id(bank, &id); SMI_SET_HW_MODE(); if (retval != ERROR_OK) return retval; stmsmi_info->dev = NULL; for (struct flash_device *p = flash_devices; p->name ; p++) if (p->device_id == id) { stmsmi_info->dev = p; break; } if (!stmsmi_info->dev) { LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32 ")", id); return ERROR_FAIL; } LOG_INFO("Found flash device \'%s\' (ID 0x%08" PRIx32 ")", stmsmi_info->dev->name, stmsmi_info->dev->device_id); /* Set correct size value */ bank->size = stmsmi_info->dev->size_in_bytes; /* create and fill sectors array */ bank->num_sectors = stmsmi_info->dev->size_in_bytes / stmsmi_info->dev->sectorsize; sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); if (sectors == NULL) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } for (int sector = 0; sector < bank->num_sectors; sector++) { sectors[sector].offset = sector * stmsmi_info->dev->sectorsize; sectors[sector].size = stmsmi_info->dev->sectorsize; sectors[sector].is_erased = -1; sectors[sector].is_protected = 1; } bank->sectors = sectors; stmsmi_info->probed = 1; return ERROR_OK; } static int stmsmi_auto_probe(struct flash_bank *bank) { struct stmsmi_flash_bank *stmsmi_info = bank->driver_priv; if (stmsmi_info->probed) return ERROR_OK; return stmsmi_probe(bank); } static int stmsmi_protect_check(struct flash_bank *bank) { /* Nothing to do. Protection is only handled in SW. */ return ERROR_OK; } static int get_stmsmi_info(struct flash_bank *bank, char *buf, int buf_size) { struct stmsmi_flash_bank *stmsmi_info = bank->driver_priv; if (!(stmsmi_info->probed)) { snprintf(buf, buf_size, "\nSMI flash bank not probed yet\n"); return ERROR_OK; } snprintf(buf, buf_size, "\nSMI flash information:\n" " Device \'%s\' (ID 0x%08x)\n", stmsmi_info->dev->name, stmsmi_info->dev->device_id); return ERROR_OK; } struct flash_driver stmsmi_flash = { .name = "stmsmi", .flash_bank_command = stmsmi_flash_bank_command, .erase = stmsmi_erase, .protect = stmsmi_protect, .write = stmsmi_write, .read = default_flash_read, .probe = stmsmi_probe, .auto_probe = stmsmi_auto_probe, .erase_check = default_flash_blank_check, .protect_check = stmsmi_protect_check, .info = get_stmsmi_info, }; openocd-0.7.0/src/flash/nor/aduc702x.c0000644000175000001440000003130212134336410014241 00000000000000/*************************************************************************** * Copyright (C) 2008 by Kevin McGuire * * Copyright (C) 2008 by Marcel Wijlaars * * Copyright (C) 2009 by Michael Ashton * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include #include #include #include static int aduc702x_build_sector_list(struct flash_bank *bank); static int aduc702x_check_flash_completion(struct target *target, unsigned int timeout_ms); static int aduc702x_set_write_enable(struct target *target, int enable); #define ADUC702x_FLASH 0xfffff800 #define ADUC702x_FLASH_FEESTA (0*4) #define ADUC702x_FLASH_FEEMOD (1*4) #define ADUC702x_FLASH_FEECON (2*4) #define ADUC702x_FLASH_FEEDAT (3*4) #define ADUC702x_FLASH_FEEADR (4*4) #define ADUC702x_FLASH_FEESIGN (5*4) #define ADUC702x_FLASH_FEEPRO (6*4) #define ADUC702x_FLASH_FEEHIDE (7*4) /* flash bank aduc702x 0 0 0 0 * The ADC7019-28 devices all have the same flash layout */ FLASH_BANK_COMMAND_HANDLER(aduc702x_flash_bank_command) { bank->base = 0x80000; bank->size = 0xF800; /* top 4k not accessible */ aduc702x_build_sector_list(bank); return ERROR_OK; } static int aduc702x_build_sector_list(struct flash_bank *bank) { /* aduc7026_struct flash_bank *aduc7026_info = bank->driver_priv; */ int i = 0; uint32_t offset = 0; /* sector size is 512 */ bank->num_sectors = bank->size / 512; bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); for (i = 0; i < bank->num_sectors; ++i) { bank->sectors[i].offset = offset; bank->sectors[i].size = 512; offset += bank->sectors[i].size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 0; } return ERROR_OK; } static int aduc702x_protect_check(struct flash_bank *bank) { printf("aduc702x_protect_check not implemented yet.\n"); return ERROR_OK; } static int aduc702x_erase(struct flash_bank *bank, int first, int last) { /* int res; */ int x; int count; /* uint32_t v; */ struct target *target = bank->target; aduc702x_set_write_enable(target, 1); /* mass erase */ if (((first | last) == 0) || ((first == 0) && (last >= bank->num_sectors))) { LOG_DEBUG("performing mass erase."); target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEDAT, 0x3cff); target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEADR, 0xffc3); target_write_u8(target, ADUC702x_FLASH + ADUC702x_FLASH_FEECON, 0x06); if (aduc702x_check_flash_completion(target, 3500) != ERROR_OK) { LOG_ERROR("mass erase failed"); aduc702x_set_write_enable(target, 0); return ERROR_FLASH_OPERATION_FAILED; } LOG_DEBUG("mass erase successful."); return ERROR_OK; } else { unsigned long adr; count = last - first + 1; for (x = 0; x < count; ++x) { adr = bank->base + ((first + x) * 512); target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEADR, adr); target_write_u8(target, ADUC702x_FLASH + ADUC702x_FLASH_FEECON, 0x05); if (aduc702x_check_flash_completion(target, 50) != ERROR_OK) { LOG_ERROR("failed to erase sector at address 0x%08lX", adr); aduc702x_set_write_enable(target, 0); return ERROR_FLASH_SECTOR_NOT_ERASED; } LOG_DEBUG("erased sector at address 0x%08lX", adr); } } aduc702x_set_write_enable(target, 0); return ERROR_OK; } static int aduc702x_protect(struct flash_bank *bank, int set, int first, int last) { printf("aduc702x_protect not implemented yet.\n"); return ERROR_FLASH_OPERATION_FAILED; } /* If this fn returns ERROR_TARGET_RESOURCE_NOT_AVAILABLE, then the caller can fall * back to another mechanism that does not require onboard RAM * * Caller should not check for other return values specifically */ static int aduc702x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t buffer_size = 7000; struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[6]; struct arm_algorithm arm_algo; int retval = ERROR_OK; if (((count%2) != 0) || ((offset%2) != 0)) { LOG_ERROR("write block must be multiple of two bytes in offset & length"); return ERROR_FAIL; } /* parameters: r0 - address of source data (absolute) r1 - number of halfwords to be copied r2 - start address in flash (offset from beginning of flash memory) r3 - exit code r4 - base address of flash controller (0xFFFFF800) registers: r5 - scratch r6 - set to 2, used to write flash command */ static const uint32_t aduc702x_flash_write_code[] = { /* <_start>: */ 0xe3a05008, /* mov r5, #8 ; 0x8 */ 0xe5845004, /* str r5, [r4, #4] */ 0xe3a06002, /* mov r6, #2 ; 0x2 */ /* : */ 0xe1c421b0, /* strh r2, [r4, #16] */ 0xe0d050b2, /* ldrh r5, [r0], #2 */ 0xe1c450bc, /* strh r5, [r4, #12] */ 0xe5c46008, /* strb r6, [r4, #8] */ /* : */ 0xe1d430b0, /* ldrh r3, [r4] */ 0xe3130004, /* tst r3, #4 ; 0x4 */ 0x1afffffc, /* bne 1001c */ 0xe2822002, /* add r2, r2, #2 ; 0x2 */ 0xe2511001, /* subs r1, r1, #1 ; 0x1 */ 0x0a000001, /* beq 1003c */ 0xe3130001, /* tst r3, #1 ; 0x1 */ 0x1afffff3, /* bne 1000c */ /* : */ 0xeafffffe /* b 1003c */ }; /* flash write code */ if (target_alloc_working_area(target, sizeof(aduc702x_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } retval = target_write_buffer(target, write_algorithm->address, sizeof(aduc702x_flash_write_code), (uint8_t *)aduc702x_flash_write_code); if (retval != ERROR_OK) return retval; /* memory buffer */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; if (buffer_size <= 256) { /* we already allocated the writing code, but failed to get a buffer, *free the algorithm */ target_free_working_area(target, write_algorithm); LOG_WARNING("no large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_IN); init_reg_param(®_params[4], "r4", 32, PARAM_OUT); while (count > 0) { uint32_t thisrun_count = (count > buffer_size) ? buffer_size : count; retval = target_write_buffer(target, source->address, thisrun_count, buffer); if (retval != ERROR_OK) break; buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, thisrun_count/2); buf_set_u32(reg_params[2].value, 0, 32, address); buf_set_u32(reg_params[4].value, 0, 32, 0xFFFFF800); retval = target_run_algorithm(target, 0, NULL, 5, reg_params, write_algorithm->address, write_algorithm->address + sizeof(aduc702x_flash_write_code) - 4, 10000, &arm_algo); if (retval != ERROR_OK) { LOG_ERROR("error executing aduc702x flash write algorithm"); break; } if ((buf_get_u32(reg_params[3].value, 0, 32) & 1) != 1) { /* FIX!!!! what does this mean??? replace w/sensible error message */ LOG_ERROR("aduc702x detected error writing flash"); retval = ERROR_FAIL; break; } buffer += thisrun_count; address += thisrun_count; count -= thisrun_count; } target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); return retval; } /* All-JTAG, single-access method. Very slow. Used only if there is no * working area available. */ static int aduc702x_write_single(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { uint32_t x; uint8_t b; struct target *target = bank->target; aduc702x_set_write_enable(target, 1); for (x = 0; x < count; x += 2) { /* FEEADR = address */ target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEADR, offset + x); /* set up data */ if ((x + 1) == count) { /* last byte */ target_read_u8(target, offset + x + 1, &b); } else b = buffer[x + 1]; target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEDAT, buffer[x] | (b << 8)); /* do single-write command */ target_write_u8(target, ADUC702x_FLASH + ADUC702x_FLASH_FEECON, 0x02); if (aduc702x_check_flash_completion(target, 1) != ERROR_OK) { LOG_ERROR("single write failed for address 0x%08lX", (unsigned long)(offset + x)); aduc702x_set_write_enable(target, 0); return ERROR_FLASH_OPERATION_FAILED; } } LOG_DEBUG("wrote %d bytes at address 0x%08lX", (int)count, (unsigned long)(offset + x)); aduc702x_set_write_enable(target, 0); return ERROR_OK; } static int aduc702x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { int retval; /* try using a block write */ retval = aduc702x_write_block(bank, buffer, offset, count); if (retval != ERROR_OK) { if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* if block write failed (no sufficient working area), * use normal (slow) JTAG method */ LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); retval = aduc702x_write_single(bank, buffer, offset, count); if (retval != ERROR_OK) { LOG_ERROR("slow write failed"); return ERROR_FLASH_OPERATION_FAILED; } } } return retval; } static int aduc702x_probe(struct flash_bank *bank) { return ERROR_OK; } static int aduc702x_info(struct flash_bank *bank, char *buf, int buf_size) { snprintf(buf, buf_size, "aduc702x flash driver info"); return ERROR_OK; } /* sets FEEMOD bit 3 * enable = 1 enables writes & erases, 0 disables them */ static int aduc702x_set_write_enable(struct target *target, int enable) { /* don't bother to preserve int enable bit here */ target_write_u16(target, ADUC702x_FLASH + ADUC702x_FLASH_FEEMOD, enable ? 8 : 0); return ERROR_OK; } /* wait up to timeout_ms for controller to not be busy, * then check whether the command passed or failed. * * this function sleeps 1ms between checks (after the first one), * so in some cases may slow things down without a usleep after the first read */ static int aduc702x_check_flash_completion(struct target *target, unsigned int timeout_ms) { uint8_t v = 4; long long endtime = timeval_ms() + timeout_ms; while (1) { target_read_u8(target, ADUC702x_FLASH + ADUC702x_FLASH_FEESTA, &v); if ((v & 4) == 0) break; alive_sleep(1); if (timeval_ms() >= endtime) break; } if (v & 2) return ERROR_FAIL; /* if a command is ignored, both the success and fail bits may be 0 */ else if ((v & 3) == 0) return ERROR_FAIL; else return ERROR_OK; } struct flash_driver aduc702x_flash = { .name = "aduc702x", .flash_bank_command = aduc702x_flash_bank_command, .erase = aduc702x_erase, .protect = aduc702x_protect, .write = aduc702x_write, .read = default_flash_read, .probe = aduc702x_probe, .auto_probe = aduc702x_probe, .erase_check = default_flash_blank_check, .protect_check = aduc702x_protect_check, .info = aduc702x_info }; openocd-0.7.0/src/flash/nor/str9x.c0000644000175000001440000004541512134336410014007 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * Copyright (C) 2008 by Oyvind Harboe * * oyvind.harboe@zylin.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include #include /* Flash registers */ #define FLASH_BBSR 0x54000000 /* Boot Bank Size Register */ #define FLASH_NBBSR 0x54000004 /* Non-Boot Bank Size Register */ #define FLASH_BBADR 0x5400000C /* Boot Bank Base Address Register */ #define FLASH_NBBADR 0x54000010 /* Non-Boot Bank Base Address Register */ #define FLASH_CR 0x54000018 /* Control Register */ #define FLASH_SR 0x5400001C /* Status Register */ #define FLASH_BCE5ADDR 0x54000020 /* BC Fifth Entry Target Address Register */ struct str9x_flash_bank { uint32_t *sector_bits; int variant; int bank1; }; enum str9x_status_codes { STR9X_CMD_SUCCESS = 0, STR9X_INVALID_COMMAND = 1, STR9X_SRC_ADDR_ERROR = 2, STR9X_DST_ADDR_ERROR = 3, STR9X_SRC_ADDR_NOT_MAPPED = 4, STR9X_DST_ADDR_NOT_MAPPED = 5, STR9X_COUNT_ERROR = 6, STR9X_INVALID_SECTOR = 7, STR9X_SECTOR_NOT_BLANK = 8, STR9X_SECTOR_NOT_PREPARED = 9, STR9X_COMPARE_ERROR = 10, STR9X_BUSY = 11 }; static uint32_t bank1start = 0x00080000; static int str9x_build_block_list(struct flash_bank *bank) { struct str9x_flash_bank *str9x_info = bank->driver_priv; int i; int num_sectors; int b0_sectors = 0, b1_sectors = 0; uint32_t offset = 0; /* set if we have large flash str9 */ str9x_info->variant = 0; str9x_info->bank1 = 0; switch (bank->size) { case (256 * 1024): b0_sectors = 4; break; case (512 * 1024): b0_sectors = 8; break; case (1024 * 1024): bank1start = 0x00100000; str9x_info->variant = 1; b0_sectors = 16; break; case (2048 * 1024): bank1start = 0x00200000; str9x_info->variant = 1; b0_sectors = 32; break; case (128 * 1024): str9x_info->variant = 1; str9x_info->bank1 = 1; b1_sectors = 8; bank1start = bank->base; break; case (32 * 1024): str9x_info->bank1 = 1; b1_sectors = 4; bank1start = bank->base; break; default: LOG_ERROR("BUG: unknown bank->size encountered"); exit(-1); } num_sectors = b0_sectors + b1_sectors; bank->num_sectors = num_sectors; bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors); str9x_info->sector_bits = malloc(sizeof(uint32_t) * num_sectors); num_sectors = 0; for (i = 0; i < b0_sectors; i++) { bank->sectors[num_sectors].offset = offset; bank->sectors[num_sectors].size = 0x10000; offset += bank->sectors[i].size; bank->sectors[num_sectors].is_erased = -1; bank->sectors[num_sectors].is_protected = 1; str9x_info->sector_bits[num_sectors++] = (1 << i); } for (i = 0; i < b1_sectors; i++) { bank->sectors[num_sectors].offset = offset; bank->sectors[num_sectors].size = str9x_info->variant == 0 ? 0x2000 : 0x4000; offset += bank->sectors[i].size; bank->sectors[num_sectors].is_erased = -1; bank->sectors[num_sectors].is_protected = 1; if (str9x_info->variant) str9x_info->sector_bits[num_sectors++] = (1 << i); else str9x_info->sector_bits[num_sectors++] = (1 << (i + 8)); } return ERROR_OK; } /* flash bank str9x 0 0 */ FLASH_BANK_COMMAND_HANDLER(str9x_flash_bank_command) { struct str9x_flash_bank *str9x_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; str9x_info = malloc(sizeof(struct str9x_flash_bank)); bank->driver_priv = str9x_info; str9x_build_block_list(bank); return ERROR_OK; } static int str9x_protect_check(struct flash_bank *bank) { int retval; struct str9x_flash_bank *str9x_info = bank->driver_priv; struct target *target = bank->target; int i; uint32_t adr; uint32_t status = 0; uint16_t hstatus = 0; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* read level one protection */ if (str9x_info->variant) { if (str9x_info->bank1) { adr = bank1start + 0x18; retval = target_write_u16(target, adr, 0x90); if (retval != ERROR_OK) return retval; retval = target_read_u16(target, adr, &hstatus); if (retval != ERROR_OK) return retval; status = hstatus; } else { adr = bank1start + 0x14; retval = target_write_u16(target, adr, 0x90); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, adr, &status); if (retval != ERROR_OK) return retval; } } else { adr = bank1start + 0x10; retval = target_write_u16(target, adr, 0x90); if (retval != ERROR_OK) return retval; retval = target_read_u16(target, adr, &hstatus); if (retval != ERROR_OK) return retval; status = hstatus; } /* read array command */ retval = target_write_u16(target, adr, 0xFF); if (retval != ERROR_OK) return retval; for (i = 0; i < bank->num_sectors; i++) { if (status & str9x_info->sector_bits[i]) bank->sectors[i].is_protected = 1; else bank->sectors[i].is_protected = 0; } return ERROR_OK; } static int str9x_erase(struct flash_bank *bank, int first, int last) { struct target *target = bank->target; int i; uint32_t adr; uint8_t status; uint8_t erase_cmd; int total_timeout; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Check if we can erase whole bank */ if ((first == 0) && (last == (bank->num_sectors - 1))) { /* Optimize to run erase bank command instead of sector */ erase_cmd = 0x80; /* Add timeout duration since erase bank takes more time */ total_timeout = 1000 * bank->num_sectors; } else { /* Erase sector command */ erase_cmd = 0x20; total_timeout = 1000; } /* this is so the compiler can *know* */ assert(total_timeout > 0); for (i = first; i <= last; i++) { int retval; adr = bank->base + bank->sectors[i].offset; /* erase sectors or block */ retval = target_write_u16(target, adr, erase_cmd); if (retval != ERROR_OK) return retval; retval = target_write_u16(target, adr, 0xD0); if (retval != ERROR_OK) return retval; /* get status */ retval = target_write_u16(target, adr, 0x70); if (retval != ERROR_OK) return retval; int timeout; for (timeout = 0; timeout < total_timeout; timeout++) { retval = target_read_u8(target, adr, &status); if (retval != ERROR_OK) return retval; if (status & 0x80) break; alive_sleep(1); } if (timeout == total_timeout) { LOG_ERROR("erase timed out"); return ERROR_FAIL; } /* clear status, also clear read array */ retval = target_write_u16(target, adr, 0x50); if (retval != ERROR_OK) return retval; /* read array command */ retval = target_write_u16(target, adr, 0xFF); if (retval != ERROR_OK) return retval; if (status & 0x22) { LOG_ERROR("error erasing flash bank, status: 0x%x", status); return ERROR_FLASH_OPERATION_FAILED; } /* If we ran erase bank command, we are finished */ if (erase_cmd == 0x80) break; } for (i = first; i <= last; i++) bank->sectors[i].is_erased = 1; return ERROR_OK; } static int str9x_protect(struct flash_bank *bank, int set, int first, int last) { struct target *target = bank->target; int i; uint32_t adr; uint8_t status; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } for (i = first; i <= last; i++) { /* Level One Protection */ adr = bank->base + bank->sectors[i].offset; target_write_u16(target, adr, 0x60); if (set) target_write_u16(target, adr, 0x01); else target_write_u16(target, adr, 0xD0); /* query status */ target_read_u8(target, adr, &status); /* clear status, also clear read array */ target_write_u16(target, adr, 0x50); /* read array command */ target_write_u16(target, adr, 0xFF); } return ERROR_OK; } static int str9x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t buffer_size = 32768; struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[4]; struct arm_algorithm arm_algo; int retval = ERROR_OK; /* see contib/loaders/flash/str9x.s for src */ static const uint32_t str9x_flash_write_code[] = { /* write: */ 0xe3c14003, /* bic r4, r1, #3 */ 0xe3a03040, /* mov r3, #0x40 */ 0xe1c430b0, /* strh r3, [r4, #0] */ 0xe0d030b2, /* ldrh r3, [r0], #2 */ 0xe0c130b2, /* strh r3, [r1], #2 */ 0xe3a03070, /* mov r3, #0x70 */ 0xe1c430b0, /* strh r3, [r4, #0] */ /* busy: */ 0xe5d43000, /* ldrb r3, [r4, #0] */ 0xe3130080, /* tst r3, #0x80 */ 0x0afffffc, /* beq busy */ 0xe3a05050, /* mov r5, #0x50 */ 0xe1c450b0, /* strh r5, [r4, #0] */ 0xe3a050ff, /* mov r5, #0xFF */ 0xe1c450b0, /* strh r5, [r4, #0] */ 0xe3130012, /* tst r3, #0x12 */ 0x1a000001, /* bne exit */ 0xe2522001, /* subs r2, r2, #1 */ 0x1affffed, /* bne write */ /* exit: */ 0xe1200070, /* bkpt #0 */ }; /* flash write code */ if (target_alloc_working_area(target, sizeof(str9x_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; }; target_write_buffer(target, write_algorithm->address, sizeof(str9x_flash_write_code), (uint8_t *)str9x_flash_write_code); /* memory buffer */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; if (buffer_size <= 256) { /* we already allocated the writing code, but failed to get a * buffer, free the algorithm */ target_free_working_area(target, write_algorithm); LOG_WARNING("no large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_IN); while (count > 0) { uint32_t thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count; target_write_buffer(target, source->address, thisrun_count * 2, buffer); buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, address); buf_set_u32(reg_params[2].value, 0, 32, thisrun_count); retval = target_run_algorithm(target, 0, NULL, 4, reg_params, write_algorithm->address, 0, 10000, &arm_algo); if (retval != ERROR_OK) { LOG_ERROR("error executing str9x flash write algorithm"); retval = ERROR_FLASH_OPERATION_FAILED; break; } if (buf_get_u32(reg_params[3].value, 0, 32) != 0x80) { retval = ERROR_FLASH_OPERATION_FAILED; break; } buffer += thisrun_count * 2; address += thisrun_count * 2; count -= thisrun_count; } target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); return retval; } static int str9x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t words_remaining = (count / 2); uint32_t bytes_remaining = (count & 0x00000001); uint32_t address = bank->base + offset; uint32_t bytes_written = 0; uint8_t status; int retval; uint32_t check_address = offset; uint32_t bank_adr; int i; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset & 0x1) { LOG_WARNING("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } for (i = 0; i < bank->num_sectors; i++) { uint32_t sec_start = bank->sectors[i].offset; uint32_t sec_end = sec_start + bank->sectors[i].size; /* check if destination falls within the current sector */ if ((check_address >= sec_start) && (check_address < sec_end)) { /* check if destination ends in the current sector */ if (offset + count < sec_end) check_address = offset + count; else check_address = sec_end; } } if (check_address != offset + count) return ERROR_FLASH_DST_OUT_OF_BANK; /* multiple half words (2-byte) to be programmed? */ if (words_remaining > 0) { /* try using a block write */ retval = str9x_write_block(bank, buffer, offset, words_remaining); if (retval != ERROR_OK) { if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* if block write failed (no sufficient working area), * we use normal (slow) single dword accesses */ LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); } else if (retval == ERROR_FLASH_OPERATION_FAILED) { LOG_ERROR("flash writing failed"); return ERROR_FLASH_OPERATION_FAILED; } } else { buffer += words_remaining * 2; address += words_remaining * 2; words_remaining = 0; } } while (words_remaining > 0) { bank_adr = address & ~0x03; /* write data command */ target_write_u16(target, bank_adr, 0x40); target_write_memory(target, address, 2, 1, buffer + bytes_written); /* get status command */ target_write_u16(target, bank_adr, 0x70); int timeout; for (timeout = 0; timeout < 1000; timeout++) { target_read_u8(target, bank_adr, &status); if (status & 0x80) break; alive_sleep(1); } if (timeout == 1000) { LOG_ERROR("write timed out"); return ERROR_FAIL; } /* clear status reg and read array */ target_write_u16(target, bank_adr, 0x50); target_write_u16(target, bank_adr, 0xFF); if (status & 0x10) return ERROR_FLASH_OPERATION_FAILED; else if (status & 0x02) return ERROR_FLASH_OPERATION_FAILED; bytes_written += 2; words_remaining--; address += 2; } if (bytes_remaining) { uint8_t last_halfword[2] = {0xff, 0xff}; /* copy the last remaining bytes into the write buffer */ memcpy(last_halfword, buffer+bytes_written, bytes_remaining); bank_adr = address & ~0x03; /* write data command */ target_write_u16(target, bank_adr, 0x40); target_write_memory(target, address, 2, 1, last_halfword); /* query status command */ target_write_u16(target, bank_adr, 0x70); int timeout; for (timeout = 0; timeout < 1000; timeout++) { target_read_u8(target, bank_adr, &status); if (status & 0x80) break; alive_sleep(1); } if (timeout == 1000) { LOG_ERROR("write timed out"); return ERROR_FAIL; } /* clear status reg and read array */ target_write_u16(target, bank_adr, 0x50); target_write_u16(target, bank_adr, 0xFF); if (status & 0x10) return ERROR_FLASH_OPERATION_FAILED; else if (status & 0x02) return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; } static int str9x_probe(struct flash_bank *bank) { return ERROR_OK; } #if 0 COMMAND_HANDLER(str9x_handle_part_id_command) { return ERROR_OK; } #endif static int get_str9x_info(struct flash_bank *bank, char *buf, int buf_size) { snprintf(buf, buf_size, "str9x flash driver info"); return ERROR_OK; } COMMAND_HANDLER(str9x_handle_flash_config_command) { struct target *target = NULL; if (CMD_ARGC < 5) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; uint32_t bbsr, nbbsr, bbadr, nbbadr; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], bbsr); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], nbbsr); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], bbadr); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[4], nbbadr); target = bank->target; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* config flash controller */ target_write_u32(target, FLASH_BBSR, bbsr); target_write_u32(target, FLASH_NBBSR, nbbsr); target_write_u32(target, FLASH_BBADR, bbadr >> 2); target_write_u32(target, FLASH_NBBADR, nbbadr >> 2); /* set bit 18 instruction TCM order as per flash programming manual */ arm966e_write_cp15(target, 62, 0x40000); /* enable flash bank 1 */ target_write_u32(target, FLASH_CR, 0x18); return ERROR_OK; } static const struct command_registration str9x_config_command_handlers[] = { { .name = "flash_config", .handler = str9x_handle_flash_config_command, .mode = COMMAND_EXEC, .help = "Configure str9x flash controller, prior to " "programming the flash.", .usage = "bank_id BBSR NBBSR BBADR NBBADR", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration str9x_command_handlers[] = { { .name = "str9x", .mode = COMMAND_ANY, .help = "str9x flash command group", .usage = "", .chain = str9x_config_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct flash_driver str9x_flash = { .name = "str9x", .commands = str9x_command_handlers, .flash_bank_command = str9x_flash_bank_command, .erase = str9x_erase, .protect = str9x_protect, .write = str9x_write, .read = default_flash_read, .probe = str9x_probe, .auto_probe = str9x_probe, .erase_check = default_flash_blank_check, .protect_check = str9x_protect_check, .info = get_str9x_info, }; openocd-0.7.0/src/flash/nor/tcl.c0000644000175000001440000005555112134336410013502 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Copyright (C) 2007,2008 Øyvind Harboe * * Copyright (C) 2008 by Spencer Oliver * * Copyright (C) 2009 Zachary T Welch * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include #include /** * @file * Implements Tcl commands used to access NOR flash facilities. */ COMMAND_HELPER(flash_command_get_bank, unsigned name_index, struct flash_bank **bank) { const char *name = CMD_ARGV[name_index]; int retval = get_flash_bank_by_name(name, bank); if (retval != ERROR_OK) return retval; if (*bank) return ERROR_OK; unsigned bank_num; COMMAND_PARSE_NUMBER(uint, name, bank_num); return get_flash_bank_by_num(bank_num, bank); } COMMAND_HANDLER(handle_flash_info_command) { struct flash_bank *p; int j = 0; int retval; if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p); if (retval != ERROR_OK) return retval; if (p != NULL) { char buf[1024]; /* attempt auto probe */ retval = p->driver->auto_probe(p); if (retval != ERROR_OK) return retval; /* We must query the hardware to avoid printing stale information! */ retval = p->driver->protect_check(p); if (retval != ERROR_OK) return retval; command_print(CMD_CTX, "#%" PRIu32 " : %s at 0x%8.8" PRIx32 ", size 0x%8.8" PRIx32 ", buswidth %i, chipwidth %i", p->bank_number, p->driver->name, p->base, p->size, p->bus_width, p->chip_width); for (j = 0; j < p->num_sectors; j++) { char *protect_state; if (p->sectors[j].is_protected == 0) protect_state = "not protected"; else if (p->sectors[j].is_protected == 1) protect_state = "protected"; else protect_state = "protection state unknown"; command_print(CMD_CTX, "\t#%3i: 0x%8.8" PRIx32 " (0x%" PRIx32 " %" PRIi32 "kB) %s", j, p->sectors[j].offset, p->sectors[j].size, p->sectors[j].size >> 10, protect_state); } *buf = '\0'; /* initialize buffer, otherwise it migh contain garbage if driver *function fails */ retval = p->driver->info(p, buf, sizeof(buf)); command_print(CMD_CTX, "%s", buf); if (retval != ERROR_OK) LOG_ERROR("error retrieving flash info"); } return retval; } COMMAND_HANDLER(handle_flash_probe_command) { struct flash_bank *p; int retval; if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p); if (retval != ERROR_OK) return retval; if (p) { retval = p->driver->probe(p); if (retval == ERROR_OK) command_print(CMD_CTX, "flash '%s' found at 0x%8.8" PRIx32, p->driver->name, p->base); } else { command_print(CMD_CTX, "flash bank '#%s' is out of bounds", CMD_ARGV[0]); retval = ERROR_FAIL; } return retval; } COMMAND_HANDLER(handle_flash_erase_check_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *p; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p); if (ERROR_OK != retval) return retval; int j; retval = p->driver->erase_check(p); if (retval == ERROR_OK) command_print(CMD_CTX, "successfully checked erase state"); else { command_print(CMD_CTX, "unknown error when checking erase state of flash bank #%s at 0x%8.8" PRIx32, CMD_ARGV[0], p->base); } for (j = 0; j < p->num_sectors; j++) { char *erase_state; if (p->sectors[j].is_erased == 0) erase_state = "not erased"; else if (p->sectors[j].is_erased == 1) erase_state = "erased"; else erase_state = "erase state unknown"; command_print(CMD_CTX, "\t#%3i: 0x%8.8" PRIx32 " (0x%" PRIx32 " %" PRIi32 "kB) %s", j, p->sectors[j].offset, p->sectors[j].size, p->sectors[j].size >> 10, erase_state); } return retval; } COMMAND_HANDLER(handle_flash_erase_address_command) { struct flash_bank *p; int retval = ERROR_OK; uint32_t address; uint32_t length; bool do_pad = false; bool do_unlock = false; struct target *target = get_current_target(CMD_CTX); while (CMD_ARGC >= 3) { /* Optionally pad out the address range to block/sector * boundaries. We can't know if there's data in that part * of the flash; only do padding if we're told to. */ if (strcmp("pad", CMD_ARGV[0]) == 0) do_pad = true; else if (strcmp("unlock", CMD_ARGV[0]) == 0) do_unlock = true; else return ERROR_COMMAND_SYNTAX_ERROR; CMD_ARGC--; CMD_ARGV++; } if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length); if (length <= 0) { command_print(CMD_CTX, "Length must be >0"); return ERROR_COMMAND_SYNTAX_ERROR; } retval = get_flash_bank_by_addr(target, address, true, &p); if (retval != ERROR_OK) return retval; /* We can't know if we did a resume + halt, in which case we no longer know the erased state **/ flash_set_dirty(); struct duration bench; duration_start(&bench); if (do_unlock) retval = flash_unlock_address_range(target, address, length); if (retval == ERROR_OK) retval = flash_erase_address_range(target, do_pad, address, length); if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) { command_print(CMD_CTX, "erased address 0x%8.8x (length %i)" " in %fs (%0.3f KiB/s)", address, length, duration_elapsed(&bench), duration_kbps(&bench, length)); } return retval; } static int flash_check_sector_parameters(struct command_context *cmd_ctx, uint32_t first, uint32_t last, uint32_t num_sectors) { if (!(first <= last)) { command_print(cmd_ctx, "ERROR: " "first sector must be <= last sector"); return ERROR_FAIL; } if (!(last <= (num_sectors - 1))) { command_print(cmd_ctx, "ERROR: last sector must be <= %d", (int) num_sectors - 1); return ERROR_FAIL; } return ERROR_OK; } COMMAND_HANDLER(handle_flash_erase_command) { if (CMD_ARGC != 3) return ERROR_COMMAND_SYNTAX_ERROR; uint32_t first; uint32_t last; struct flash_bank *p; int retval; retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p); if (retval != ERROR_OK) return retval; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], first); if (strcmp(CMD_ARGV[2], "last") == 0) last = p->num_sectors - 1; else COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], last); retval = flash_check_sector_parameters(CMD_CTX, first, last, p->num_sectors); if (retval != ERROR_OK) return retval; struct duration bench; duration_start(&bench); retval = flash_driver_erase(p, first, last); if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) { command_print(CMD_CTX, "erased sectors %" PRIu32 " " "through %" PRIu32 " on flash bank %" PRIu32 " " "in %fs", first, last, p->bank_number, duration_elapsed(&bench)); } return ERROR_OK; } COMMAND_HANDLER(handle_flash_protect_command) { if (CMD_ARGC != 4) return ERROR_COMMAND_SYNTAX_ERROR; uint32_t first; uint32_t last; struct flash_bank *p; int retval; retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p); if (retval != ERROR_OK) return retval; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], first); if (strcmp(CMD_ARGV[2], "last") == 0) last = p->num_sectors - 1; else COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], last); bool set; COMMAND_PARSE_ON_OFF(CMD_ARGV[3], set); retval = flash_check_sector_parameters(CMD_CTX, first, last, p->num_sectors); if (retval != ERROR_OK) return retval; retval = flash_driver_protect(p, set, first, last); if (retval == ERROR_OK) { command_print(CMD_CTX, "%s protection for sectors %i " "through %i on flash bank %" PRIu32 "", (set) ? "set" : "cleared", (int) first, (int) last, p->bank_number); } return retval; } COMMAND_HANDLER(handle_flash_write_image_command) { struct target *target = get_current_target(CMD_CTX); struct image image; uint32_t written; int retval; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; /* flash auto-erase is disabled by default*/ int auto_erase = 0; bool auto_unlock = false; for (;; ) { if (strcmp(CMD_ARGV[0], "erase") == 0) { auto_erase = 1; CMD_ARGV++; CMD_ARGC--; command_print(CMD_CTX, "auto erase enabled"); } else if (strcmp(CMD_ARGV[0], "unlock") == 0) { auto_unlock = true; CMD_ARGV++; CMD_ARGC--; command_print(CMD_CTX, "auto unlock enabled"); } else break; } if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; if (!target) { LOG_ERROR("no target selected"); return ERROR_FAIL; } struct duration bench; duration_start(&bench); if (CMD_ARGC >= 2) { image.base_address_set = 1; COMMAND_PARSE_NUMBER(llong, CMD_ARGV[1], image.base_address); } else { image.base_address_set = 0; image.base_address = 0x0; } image.start_address_set = 0; retval = image_open(&image, CMD_ARGV[0], (CMD_ARGC == 3) ? CMD_ARGV[2] : NULL); if (retval != ERROR_OK) return retval; retval = flash_write_unlock(target, &image, &written, auto_erase, auto_unlock); if (retval != ERROR_OK) { image_close(&image); return retval; } if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) { command_print(CMD_CTX, "wrote %" PRIu32 " bytes from file %s " "in %fs (%0.3f KiB/s)", written, CMD_ARGV[0], duration_elapsed(&bench), duration_kbps(&bench, written)); } image_close(&image); return retval; } COMMAND_HANDLER(handle_flash_fill_command) { int err = ERROR_OK; uint32_t address; uint32_t pattern; uint32_t count; uint32_t wrote = 0; uint32_t cur_size = 0; uint32_t chunk_count; struct target *target = get_current_target(CMD_CTX); unsigned i; uint32_t wordsize; int retval = ERROR_OK; static size_t const chunksize = 1024; uint8_t *chunk = NULL, *readback = NULL; if (CMD_ARGC != 3) { retval = ERROR_COMMAND_SYNTAX_ERROR; goto done; } COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], pattern); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], count); chunk = malloc(chunksize); if (chunk == NULL) return ERROR_FAIL; readback = malloc(chunksize); if (readback == NULL) { free(chunk); return ERROR_FAIL; } if (count == 0) goto done; switch (CMD_NAME[4]) { case 'w': wordsize = 4; break; case 'h': wordsize = 2; break; case 'b': wordsize = 1; break; default: retval = ERROR_COMMAND_SYNTAX_ERROR; goto done; } chunk_count = MIN(count, (chunksize / wordsize)); switch (wordsize) { case 4: for (i = 0; i < chunk_count; i++) target_buffer_set_u32(target, chunk + i * wordsize, pattern); break; case 2: for (i = 0; i < chunk_count; i++) target_buffer_set_u16(target, chunk + i * wordsize, pattern); break; case 1: memset(chunk, pattern, chunk_count); break; default: LOG_ERROR("BUG: can't happen"); exit(-1); } struct duration bench; duration_start(&bench); for (wrote = 0; wrote < (count*wordsize); wrote += cur_size) { struct flash_bank *bank; retval = get_flash_bank_by_addr(target, address, true, &bank); if (retval != ERROR_OK) goto done; cur_size = MIN((count * wordsize - wrote), chunksize); err = flash_driver_write(bank, chunk, address - bank->base + wrote, cur_size); if (err != ERROR_OK) { retval = err; goto done; } err = flash_driver_read(bank, readback, address - bank->base + wrote, cur_size); if (err != ERROR_OK) { retval = err; goto done; } for (i = 0; i < cur_size; i++) { if (readback[i] != chunk[i]) { LOG_ERROR( "Verification error address 0x%08" PRIx32 ", read back 0x%02x, expected 0x%02x", address + wrote + i, readback[i], chunk[i]); retval = ERROR_FAIL; goto done; } } } if ((retval == ERROR_OK) && (duration_measure(&bench) == ERROR_OK)) { command_print(CMD_CTX, "wrote %" PRIu32 " bytes to 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)", wrote, address, duration_elapsed(&bench), duration_kbps(&bench, wrote)); } done: free(readback); free(chunk); return retval; } COMMAND_HANDLER(handle_flash_write_bank_command) { uint32_t offset; uint8_t *buffer; struct fileio fileio; if (CMD_ARGC != 3) return ERROR_COMMAND_SYNTAX_ERROR; struct duration bench; duration_start(&bench); struct flash_bank *p; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p); if (ERROR_OK != retval) return retval; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], offset); if (fileio_open(&fileio, CMD_ARGV[1], FILEIO_READ, FILEIO_BINARY) != ERROR_OK) return ERROR_OK; int filesize; retval = fileio_size(&fileio, &filesize); if (retval != ERROR_OK) { fileio_close(&fileio); return retval; } buffer = malloc(filesize); if (buffer == NULL) { fileio_close(&fileio); LOG_ERROR("Out of memory"); return ERROR_FAIL; } size_t buf_cnt; if (fileio_read(&fileio, filesize, buffer, &buf_cnt) != ERROR_OK) { free(buffer); fileio_close(&fileio); return ERROR_OK; } retval = flash_driver_write(p, buffer, offset, buf_cnt); free(buffer); buffer = NULL; if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) { command_print(CMD_CTX, "wrote %ld bytes from file %s to flash bank %u" " at offset 0x%8.8" PRIx32 " in %fs (%0.3f KiB/s)", (long)filesize, CMD_ARGV[1], p->bank_number, offset, duration_elapsed(&bench), duration_kbps(&bench, filesize)); } fileio_close(&fileio); return retval; } void flash_set_dirty(void) { struct flash_bank *c; int i; /* set all flash to require erasing */ for (c = flash_bank_list(); c; c = c->next) { for (i = 0; i < c->num_sectors; i++) c->sectors[i].is_erased = 0; } } static const struct command_registration flash_exec_command_handlers[] = { { .name = "probe", .handler = handle_flash_probe_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Identify a flash bank.", }, { .name = "info", .handler = handle_flash_info_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Print information about a flash bank.", }, { .name = "erase_check", .handler = handle_flash_erase_check_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Check erase state of all blocks in a " "flash bank.", }, { .name = "erase_sector", .handler = handle_flash_erase_command, .mode = COMMAND_EXEC, .usage = "bank_id first_sector_num last_sector_num", .help = "Erase a range of sectors in a flash bank.", }, { .name = "erase_address", .handler = handle_flash_erase_address_command, .mode = COMMAND_EXEC, .usage = "['pad'] ['unlock'] address length", .help = "Erase flash sectors starting at address and " "continuing for length bytes. If 'pad' is specified, " "data outside that range may also be erased: the start " "address may be decreased, and length increased, so " "that all of the first and last sectors are erased. " "If 'unlock' is specified, then the flash is unprotected " "before erasing.", }, { .name = "fillw", .handler = handle_flash_fill_command, .mode = COMMAND_EXEC, .usage = "address value n", .help = "Fill n words with 32-bit value, starting at " "word address. (No autoerase.)", }, { .name = "fillh", .handler = handle_flash_fill_command, .mode = COMMAND_EXEC, .usage = "address value n", .help = "Fill n halfwords with 16-bit value, starting at " "word address. (No autoerase.)", }, { .name = "fillb", .handler = handle_flash_fill_command, .mode = COMMAND_EXEC, .usage = "address value n", .help = "Fill n bytes with 8-bit value, starting at " "word address. (No autoerase.)", }, { .name = "write_bank", .handler = handle_flash_write_bank_command, .mode = COMMAND_EXEC, .usage = "bank_id filename offset", .help = "Write binary data from file to flash bank, " "starting at specified byte offset from the " "beginning of the bank.", }, { .name = "write_image", .handler = handle_flash_write_image_command, .mode = COMMAND_EXEC, .usage = "[erase] [unlock] filename [offset [file_type]]", .help = "Write an image to flash. Optionally first unprotect " "and/or erase the region to be used. Allow optional " "offset from beginning of bank (defaults to zero)", }, { .name = "protect", .handler = handle_flash_protect_command, .mode = COMMAND_EXEC, .usage = "bank_id first_sector [last_sector|'last'] " "('on'|'off')", .help = "Turn protection on or off for a range of sectors " "in a given flash bank.", }, COMMAND_REGISTRATION_DONE }; static int flash_init_drivers(struct command_context *cmd_ctx) { if (!flash_bank_list()) return ERROR_OK; struct command *parent = command_find_in_context(cmd_ctx, "flash"); return register_commands(cmd_ctx, parent, flash_exec_command_handlers); } COMMAND_HANDLER(handle_flash_bank_command) { if (CMD_ARGC < 7) { LOG_ERROR("usage: flash bank " " "); return ERROR_COMMAND_SYNTAX_ERROR; } /* save bank name and advance arguments for compatibility */ const char *bank_name = *CMD_ARGV++; CMD_ARGC--; struct target *target = get_target(CMD_ARGV[5]); if (target == NULL) { LOG_ERROR("target '%s' not defined", CMD_ARGV[5]); return ERROR_FAIL; } const char *driver_name = CMD_ARGV[0]; struct flash_driver *driver = flash_driver_find_by_name(driver_name); if (NULL == driver) { /* no matching flash driver found */ LOG_ERROR("flash driver '%s' not found", driver_name); return ERROR_FAIL; } /* check the flash bank name is unique */ if (get_flash_bank_by_name_noprobe(bank_name) != NULL) { /* flash bank name already exists */ LOG_ERROR("flash bank name '%s' already exists", bank_name); return ERROR_FAIL; } /* register flash specific commands */ if (NULL != driver->commands) { int retval = register_commands(CMD_CTX, NULL, driver->commands); if (ERROR_OK != retval) { LOG_ERROR("couldn't register '%s' commands", driver_name); return ERROR_FAIL; } } struct flash_bank *c = malloc(sizeof(*c)); c->name = strdup(bank_name); c->target = target; c->driver = driver; c->driver_priv = NULL; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], c->base); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], c->size); COMMAND_PARSE_NUMBER(int, CMD_ARGV[3], c->chip_width); COMMAND_PARSE_NUMBER(int, CMD_ARGV[4], c->bus_width); c->num_sectors = 0; c->sectors = NULL; c->next = NULL; int retval; retval = CALL_COMMAND_HANDLER(driver->flash_bank_command, c); if (ERROR_OK != retval) { LOG_ERROR("'%s' driver rejected flash bank at 0x%8.8" PRIx32 "Usage %s", driver_name, c->base, driver->usage); free(c); return retval; } if (driver->usage == NULL) LOG_DEBUG("'%s' driver usage field missing", driver_name); flash_bank_add(c); return ERROR_OK; } COMMAND_HANDLER(handle_flash_banks_command) { if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; unsigned n = 0; for (struct flash_bank *p = flash_bank_list(); p; p = p->next, n++) { LOG_USER("#%" PRIu32 " : %s (%s) at 0x%8.8" PRIx32 ", size 0x%8.8" PRIx32 ", " "buswidth %u, chipwidth %u", p->bank_number, p->name, p->driver->name, p->base, p->size, p->bus_width, p->chip_width); } return ERROR_OK; } static int jim_flash_list(Jim_Interp *interp, int argc, Jim_Obj * const *argv) { if (argc != 1) { Jim_WrongNumArgs(interp, 1, argv, "no arguments to 'flash list' command"); return JIM_ERR; } Jim_Obj *list = Jim_NewListObj(interp, NULL, 0); for (struct flash_bank *p = flash_bank_list(); p; p = p->next) { Jim_Obj *elem = Jim_NewListObj(interp, NULL, 0); Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "name", -1)); Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, p->driver->name, -1)); Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "base", -1)); Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->base)); Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "size", -1)); Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->size)); Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "bus_width", -1)); Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->bus_width)); Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "chip_width", -1)); Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->chip_width)); Jim_ListAppendElement(interp, list, elem); } Jim_SetResult(interp, list); return JIM_OK; } COMMAND_HANDLER(handle_flash_init_command) { if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; static bool flash_initialized; if (flash_initialized) { LOG_INFO("'flash init' has already been called"); return ERROR_OK; } flash_initialized = true; LOG_DEBUG("Initializing flash devices..."); return flash_init_drivers(CMD_CTX); } static const struct command_registration flash_config_command_handlers[] = { { .name = "bank", .handler = handle_flash_bank_command, .mode = COMMAND_CONFIG, .usage = "bank_id driver_name base_address size_bytes " "chip_width_bytes bus_width_bytes target " "[driver_options ...]", .help = "Define a new bank with the given name, " "using the specified NOR flash driver.", }, { .name = "init", .mode = COMMAND_CONFIG, .handler = handle_flash_init_command, .help = "Initialize flash devices.", }, { .name = "banks", .mode = COMMAND_ANY, .handler = handle_flash_banks_command, .help = "Display table with information about flash banks.", }, { .name = "list", .mode = COMMAND_ANY, .jim_handler = jim_flash_list, .help = "Returns a list of details about the flash banks.", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration flash_command_handlers[] = { { .name = "flash", .mode = COMMAND_ANY, .help = "NOR flash command group", .chain = flash_config_command_handlers, }, COMMAND_REGISTRATION_DONE }; int flash_register_commands(struct command_context *cmd_ctx) { return register_commands(cmd_ctx, NULL, flash_command_handlers); } openocd-0.7.0/src/flash/nor/stm32f2x.c0000644000175000001440000007553312137151331014312 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2011 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include #include #include /* Regarding performance: * * Short story - it might be best to leave the performance at * current levels. * * You may see a jump in speed if you change to using * 32bit words for the block programming. * * Its a shame you cannot use the double word as its * even faster - but you require external VPP for that mode. * * Having said all that 16bit writes give us the widest vdd * operating range, so may be worth adding a note to that effect. * */ /* Danger!!!! The STM32F1x and STM32F2x series actually have * quite different flash controllers. * * What's more scary is that the names of the registers and their * addresses are the same, but the actual bits and what they do are * can be very different. * * To reduce testing complexity and dangers of regressions, * a seperate file is used for stm32fx2x. * * 1mByte part with 4 x 16, 1 x 64, 7 x 128kBytes sectors * * What's the protection page size??? * * Tested with STM3220F-EVAL board. * * STM32F21xx series for reference. * * RM0033 * http://www.st.com/internet/mcu/product/250192.jsp * * PM0059 * www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/ * PROGRAMMING_MANUAL/CD00233952.pdf * * STM32F1x series - notice that this code was copy, pasted and knocked * into a stm32f2x driver, so in case something has been converted or * bugs haven't been fixed, here are the original manuals: * * RM0008 - Reference manual * * RM0042, the Flash programming manual for low-, medium- high-density and * connectivity line STM32F10x devices * * PM0068, the Flash programming manual for XL-density STM32F10x devices. * */ /* Erase time can be as high as 1000ms, 10x this and it's toast... */ #define FLASH_ERASE_TIMEOUT 10000 #define FLASH_WRITE_TIMEOUT 5 #define STM32_FLASH_BASE 0x40023c00 #define STM32_FLASH_ACR 0x40023c00 #define STM32_FLASH_KEYR 0x40023c04 #define STM32_FLASH_OPTKEYR 0x40023c08 #define STM32_FLASH_SR 0x40023c0C #define STM32_FLASH_CR 0x40023c10 #define STM32_FLASH_OPTCR 0x40023c14 #define STM32_FLASH_OPTCR1 0x40023c18 /* FLASH_CR register bits */ #define FLASH_PG (1 << 0) #define FLASH_SER (1 << 1) #define FLASH_MER (1 << 2) #define FLASH_MER1 (1 << 15) #define FLASH_STRT (1 << 16) #define FLASH_PSIZE_8 (0 << 8) #define FLASH_PSIZE_16 (1 << 8) #define FLASH_PSIZE_32 (2 << 8) #define FLASH_PSIZE_64 (3 << 8) #define FLASH_SNB(a) ((a) << 3) #define FLASH_LOCK (1 << 31) /* FLASH_SR register bits */ #define FLASH_BSY (1 << 16) #define FLASH_PGSERR (1 << 7) /* Programming sequence error */ #define FLASH_PGPERR (1 << 6) /* Programming parallelism error */ #define FLASH_PGAERR (1 << 5) /* Programming alignment error */ #define FLASH_WRPERR (1 << 4) /* Write protection error */ #define FLASH_OPERR (1 << 1) /* Operation error */ #define FLASH_ERROR (FLASH_PGSERR | FLASH_PGPERR | FLASH_PGAERR | FLASH_WRPERR | FLASH_OPERR) /* STM32_FLASH_OPTCR register bits */ #define OPT_LOCK (1 << 0) #define OPT_START (1 << 1) /* STM32_FLASH_OBR bit definitions (reading) */ #define OPT_ERROR 0 #define OPT_READOUT 1 #define OPT_RDWDGSW 2 #define OPT_RDRSTSTOP 3 #define OPT_RDRSTSTDBY 4 #define OPT_BFB2 5 /* dual flash bank only */ /* register unlock keys */ #define KEY1 0x45670123 #define KEY2 0xCDEF89AB /* option register unlock key */ #define OPTKEY1 0x08192A3B #define OPTKEY2 0x4C5D6E7F struct stm32x_options { uint8_t RDP; uint8_t user_options; uint32_t protection; }; struct stm32x_flash_bank { struct stm32x_options option_bytes; int probed; bool has_large_mem; /* stm32f42x/stm32f43x family */ uint32_t user_bank_size; }; /* flash bank stm32x 0 0 */ FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command) { struct stm32x_flash_bank *stm32x_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; stm32x_info = malloc(sizeof(struct stm32x_flash_bank)); bank->driver_priv = stm32x_info; stm32x_info->probed = 0; stm32x_info->user_bank_size = bank->size; return ERROR_OK; } static inline int stm32x_get_flash_reg(struct flash_bank *bank, uint32_t reg) { return reg; } static inline int stm32x_get_flash_status(struct flash_bank *bank, uint32_t *status) { struct target *target = bank->target; return target_read_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_SR), status); } static int stm32x_wait_status_busy(struct flash_bank *bank, int timeout) { struct target *target = bank->target; uint32_t status; int retval = ERROR_OK; /* wait for busy to clear */ for (;;) { retval = stm32x_get_flash_status(bank, &status); if (retval != ERROR_OK) return retval; LOG_DEBUG("status: 0x%" PRIx32 "", status); if ((status & FLASH_BSY) == 0) break; if (timeout-- <= 0) { LOG_ERROR("timed out waiting for flash"); return ERROR_FAIL; } alive_sleep(1); } if (status & FLASH_WRPERR) { LOG_ERROR("stm32x device protected"); retval = ERROR_FAIL; } /* Clear but report errors */ if (status & FLASH_ERROR) { /* If this operation fails, we ignore it and report the original * retval */ target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_SR), status & FLASH_ERROR); } return retval; } static int stm32x_unlock_reg(struct target *target) { uint32_t ctrl; /* first check if not already unlocked * otherwise writing on STM32_FLASH_KEYR will fail */ int retval = target_read_u32(target, STM32_FLASH_CR, &ctrl); if (retval != ERROR_OK) return retval; if ((ctrl & FLASH_LOCK) == 0) return ERROR_OK; /* unlock flash registers */ retval = target_write_u32(target, STM32_FLASH_KEYR, KEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, STM32_FLASH_KEYR, KEY2); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, STM32_FLASH_CR, &ctrl); if (retval != ERROR_OK) return retval; if (ctrl & FLASH_LOCK) { LOG_ERROR("flash not unlocked STM32_FLASH_CR: %x", ctrl); return ERROR_TARGET_FAILURE; } return ERROR_OK; } static int stm32x_unlock_option_reg(struct target *target) { uint32_t ctrl; int retval = target_read_u32(target, STM32_FLASH_OPTCR, &ctrl); if (retval != ERROR_OK) return retval; if ((ctrl & OPT_LOCK) == 0) return ERROR_OK; /* unlock option registers */ retval = target_write_u32(target, STM32_FLASH_OPTKEYR, OPTKEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, STM32_FLASH_OPTKEYR, OPTKEY2); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, STM32_FLASH_OPTCR, &ctrl); if (retval != ERROR_OK) return retval; if (ctrl & OPT_LOCK) { LOG_ERROR("options not unlocked STM32_FLASH_OPTCR: %x", ctrl); return ERROR_TARGET_FAILURE; } return ERROR_OK; } static int stm32x_read_options(struct flash_bank *bank) { uint32_t optiondata; struct stm32x_flash_bank *stm32x_info = NULL; struct target *target = bank->target; stm32x_info = bank->driver_priv; /* read current option bytes */ int retval = target_read_u32(target, STM32_FLASH_OPTCR, &optiondata); if (retval != ERROR_OK) return retval; stm32x_info->option_bytes.user_options = optiondata & 0xec; stm32x_info->option_bytes.RDP = (optiondata >> 8) & 0xff; stm32x_info->option_bytes.protection = (optiondata >> 16) & 0xfff; if (stm32x_info->has_large_mem) { retval = target_read_u32(target, STM32_FLASH_OPTCR1, &optiondata); if (retval != ERROR_OK) return retval; /* append protection bits */ stm32x_info->option_bytes.protection |= (optiondata >> 4) & 0x00fff000; } if (stm32x_info->option_bytes.RDP != 0xAA) LOG_INFO("Device Security Bit Set"); return ERROR_OK; } static int stm32x_write_options(struct flash_bank *bank) { struct stm32x_flash_bank *stm32x_info = NULL; struct target *target = bank->target; uint32_t optiondata; stm32x_info = bank->driver_priv; int retval = stm32x_unlock_option_reg(target); if (retval != ERROR_OK) return retval; /* rebuild option data */ optiondata = stm32x_info->option_bytes.user_options; buf_set_u32(&optiondata, 8, 8, stm32x_info->option_bytes.RDP); buf_set_u32(&optiondata, 16, 12, stm32x_info->option_bytes.protection); /* program options */ retval = target_write_u32(target, STM32_FLASH_OPTCR, optiondata); if (retval != ERROR_OK) return retval; if (stm32x_info->has_large_mem) { uint32_t optiondata2 = 0; buf_set_u32(&optiondata2, 16, 12, stm32x_info->option_bytes.protection >> 12); retval = target_write_u32(target, STM32_FLASH_OPTCR1, optiondata2); if (retval != ERROR_OK) return retval; } /* start programming cycle */ retval = target_write_u32(target, STM32_FLASH_OPTCR, optiondata | OPT_START); if (retval != ERROR_OK) return retval; /* wait for completion */ retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); if (retval != ERROR_OK) return retval; /* relock registers */ retval = target_write_u32(target, STM32_FLASH_OPTCR, OPT_LOCK); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int stm32x_protect_check(struct flash_bank *bank) { struct target *target = bank->target; struct stm32x_flash_bank *stm32x_info = bank->driver_priv; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* read write protection settings */ int retval = stm32x_read_options(bank); if (retval != ERROR_OK) { LOG_DEBUG("unable to read option bytes"); return retval; } for (int i = 0; i < bank->num_sectors; i++) { if (stm32x_info->option_bytes.protection & (1 << i)) bank->sectors[i].is_protected = 0; else bank->sectors[i].is_protected = 1; } return ERROR_OK; } static int stm32x_erase(struct flash_bank *bank, int first, int last) { struct target *target = bank->target; int i; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } int retval; retval = stm32x_unlock_reg(target); if (retval != ERROR_OK) return retval; /* Sector Erase To erase a sector, follow the procedure below: 1. Check that no Flash memory operation is ongoing by checking the BSY bit in the FLASH_SR register 2. Set the SER bit and select the sector (out of the 12 sectors in the main memory block) you wish to erase (SNB) in the FLASH_CR register 3. Set the STRT bit in the FLASH_CR register 4. Wait for the BSY bit to be cleared */ for (i = first; i <= last; i++) { retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_SER | FLASH_SNB(i) | FLASH_STRT); if (retval != ERROR_OK) return retval; retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); if (retval != ERROR_OK) return retval; bank->sectors[i].is_erased = 1; } retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int stm32x_protect(struct flash_bank *bank, int set, int first, int last) { struct target *target = bank->target; struct stm32x_flash_bank *stm32x_info = bank->driver_priv; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* read protection settings */ int retval = stm32x_read_options(bank); if (retval != ERROR_OK) { LOG_DEBUG("unable to read option bytes"); return retval; } for (int i = first; i <= last; i++) { if (set) stm32x_info->option_bytes.protection &= ~(1 << i); else stm32x_info->option_bytes.protection |= (1 << i); } retval = stm32x_write_options(bank); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t buffer_size = 16384; struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[5]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; /* see contrib/loaders/flash/stm32f2x.S for src */ static const uint8_t stm32x_flash_write_code[] = { /* wait_fifo: */ 0xD0, 0xF8, 0x00, 0x80, /* ldr r8, [r0, #0] */ 0xB8, 0xF1, 0x00, 0x0F, /* cmp r8, #0 */ 0x1A, 0xD0, /* beq exit */ 0x47, 0x68, /* ldr r7, [r0, #4] */ 0x47, 0x45, /* cmp r7, r8 */ 0xF7, 0xD0, /* beq wait_fifo */ 0xDF, 0xF8, 0x30, 0x60, /* ldr r6, STM32_PROG16 */ 0x26, 0x61, /* str r6, [r4, #STM32_FLASH_CR_OFFSET] */ 0x37, 0xF8, 0x02, 0x6B, /* ldrh r6, [r7], #0x02 */ 0x22, 0xF8, 0x02, 0x6B, /* strh r6, [r2], #0x02 */ /* busy: */ 0xE6, 0x68, /* ldr r6, [r4, #STM32_FLASH_SR_OFFSET] */ 0x16, 0xF4, 0x80, 0x3F, /* tst r6, #0x10000 */ 0xFB, 0xD1, /* bne busy */ 0x16, 0xF0, 0xF0, 0x0F, /* tst r6, #0xf0 */ 0x07, 0xD1, /* bne error */ 0x8F, 0x42, /* cmp r7, r1 */ 0x28, 0xBF, /* it cs */ 0x00, 0xF1, 0x08, 0x07, /* addcs r7, r0, #8 */ 0x47, 0x60, /* str r7, [r0, #4] */ 0x01, 0x3B, /* subs r3, r3, #1 */ 0x13, 0xB1, /* cbz r3, exit */ 0xE1, 0xE7, /* b wait_fifo */ /* error: */ 0x00, 0x21, /* movs r1, #0 */ 0x41, 0x60, /* str r1, [r0, #4] */ /* exit: */ 0x30, 0x46, /* mov r0, r6 */ 0x00, 0xBE, /* bkpt #0x00 */ /* : */ 0x01, 0x01, 0x00, 0x00, /* .word 0x00000101 */ }; if (target_alloc_working_area(target, sizeof(stm32x_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; }; retval = target_write_buffer(target, write_algorithm->address, sizeof(stm32x_flash_write_code), (uint8_t *)stm32x_flash_write_code); if (retval != ERROR_OK) return retval; /* memory buffer */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; if (buffer_size <= 256) { /* we already allocated the writing code, but failed to get a * buffer, free the algorithm */ target_free_working_area(target, write_algorithm); LOG_WARNING("no large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } }; armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* buffer start, status (out) */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* buffer end */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* target address */ init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* count (halfword-16bit) */ init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* flash base */ buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size); buf_set_u32(reg_params[2].value, 0, 32, address); buf_set_u32(reg_params[3].value, 0, 32, count); buf_set_u32(reg_params[4].value, 0, 32, STM32_FLASH_BASE); retval = target_run_flash_async_algorithm(target, buffer, count, 2, 0, NULL, 5, reg_params, source->address, source->size, write_algorithm->address, 0, &armv7m_info); if (retval == ERROR_FLASH_OPERATION_FAILED) { LOG_ERROR("error executing stm32x flash write algorithm"); uint32_t error = buf_get_u32(reg_params[0].value, 0, 32) & FLASH_ERROR; if (error & FLASH_WRPERR) LOG_ERROR("flash memory write protected"); if (error != 0) { LOG_ERROR("flash write failed = %08x", error); /* Clear but report errors */ target_write_u32(target, STM32_FLASH_SR, error); retval = ERROR_FAIL; } } target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); return retval; } static int stm32x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t words_remaining = (count / 2); uint32_t bytes_remaining = (count & 0x00000001); uint32_t address = bank->base + offset; uint32_t bytes_written = 0; int retval; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset & 0x1) { LOG_WARNING("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } retval = stm32x_unlock_reg(target); if (retval != ERROR_OK) return retval; /* multiple half words (2-byte) to be programmed? */ if (words_remaining > 0) { /* try using a block write */ retval = stm32x_write_block(bank, buffer, offset, words_remaining); if (retval != ERROR_OK) { if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* if block write failed (no sufficient working area), * we use normal (slow) single dword accesses */ LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); } } else { buffer += words_remaining * 2; address += words_remaining * 2; words_remaining = 0; } } if ((retval != ERROR_OK) && (retval != ERROR_TARGET_RESOURCE_NOT_AVAILABLE)) return retval; /* Standard programming The Flash memory programming sequence is as follows: 1. Check that no main Flash memory operation is ongoing by checking the BSY bit in the FLASH_SR register. 2. Set the PG bit in the FLASH_CR register 3. Perform the data write operation(s) to the desired memory address (inside main memory block or OTP area): – – Half-word access in case of x16 parallelism – Word access in case of x32 parallelism – 4. Byte access in case of x8 parallelism Double word access in case of x64 parallelism Wait for the BSY bit to be cleared */ while (words_remaining > 0) { uint16_t value; memcpy(&value, buffer + bytes_written, sizeof(uint16_t)); retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PG | FLASH_PSIZE_16); if (retval != ERROR_OK) return retval; retval = target_write_u16(target, address, value); if (retval != ERROR_OK) return retval; retval = stm32x_wait_status_busy(bank, FLASH_WRITE_TIMEOUT); if (retval != ERROR_OK) return retval; bytes_written += 2; words_remaining--; address += 2; } if (bytes_remaining) { retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PG | FLASH_PSIZE_8); if (retval != ERROR_OK) return retval; retval = target_write_u8(target, address, buffer[bytes_written]); if (retval != ERROR_OK) return retval; retval = stm32x_wait_status_busy(bank, FLASH_WRITE_TIMEOUT); if (retval != ERROR_OK) return retval; } return target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK); } static void setup_sector(struct flash_bank *bank, int start, int num, int size) { for (int i = start; i < (start + num) ; i++) { bank->sectors[i].offset = bank->size; bank->sectors[i].size = size; bank->size += bank->sectors[i].size; } } static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id) { /* this checks for a stm32f4x errata issue where a * stm32f2x DBGMCU_IDCODE is incorrectly returned. * If the issue is detected target is forced to stm32f4x Rev A. * Only effects Rev A silicon */ struct target *target = bank->target; uint32_t cpuid; /* read stm32 device id register */ int retval = target_read_u32(target, 0xE0042000, device_id); if (retval != ERROR_OK) return retval; if ((*device_id & 0xfff) == 0x411) { /* read CPUID reg to check core type */ retval = target_read_u32(target, 0xE000ED00, &cpuid); if (retval != ERROR_OK) return retval; /* check for cortex_m4 */ if (((cpuid >> 4) & 0xFFF) == 0xC24) { *device_id &= ~((0xFFFF << 16) | 0xfff); *device_id |= (0x1000 << 16) | 0x413; LOG_INFO("stm32f4x errata detected - fixing incorrect MCU_IDCODE"); } } return retval; } static int stm32x_probe(struct flash_bank *bank) { struct target *target = bank->target; struct stm32x_flash_bank *stm32x_info = bank->driver_priv; int i; uint16_t flash_size_in_kb; uint16_t max_flash_size_in_kb; uint32_t device_id; uint32_t base_address = 0x08000000; stm32x_info->probed = 0; stm32x_info->has_large_mem = false; /* read stm32 device id register */ int retval = stm32x_get_device_id(bank, &device_id); if (retval != ERROR_OK) return retval; LOG_INFO("device id = 0x%08" PRIx32 "", device_id); /* set max flash size depending on family */ switch (device_id & 0xfff) { case 0x411: case 0x413: max_flash_size_in_kb = 1024; break; case 0x419: max_flash_size_in_kb = 2048; stm32x_info->has_large_mem = true; break; default: LOG_WARNING("Cannot identify target as a STM32 family."); return ERROR_FAIL; } /* get flash size from target. */ retval = target_read_u16(target, 0x1FFF7A22, &flash_size_in_kb); /* failed reading flash size or flash size invalid (early silicon), * default to max target family */ if (retval != ERROR_OK || flash_size_in_kb == 0xffff || flash_size_in_kb == 0) { LOG_WARNING("STM32 flash size failed, probe inaccurate - assuming %dk flash", max_flash_size_in_kb); flash_size_in_kb = max_flash_size_in_kb; } /* if the user sets the size manually then ignore the probed value * this allows us to work around devices that have a invalid flash size register value */ if (stm32x_info->user_bank_size) { LOG_INFO("ignoring flash probed value, using configured bank size"); flash_size_in_kb = stm32x_info->user_bank_size / 1024; } LOG_INFO("flash size = %dkbytes", flash_size_in_kb); /* did we assign flash size? */ assert(flash_size_in_kb != 0xffff); /* calculate numbers of pages */ int num_pages = (flash_size_in_kb / 128) + 4; /* check for larger 2048 bytes devices */ if (stm32x_info->has_large_mem) num_pages += 4; /* check that calculation result makes sense */ assert(num_pages > 0); if (bank->sectors) { free(bank->sectors); bank->sectors = NULL; } bank->base = base_address; bank->num_sectors = num_pages; bank->sectors = malloc(sizeof(struct flash_sector) * num_pages); bank->size = 0; /* fixed memory */ setup_sector(bank, 0, 4, 16 * 1024); setup_sector(bank, 4, 1, 64 * 1024); /* dynamic memory */ setup_sector(bank, 4 + 1, MAX(12, num_pages) - 5, 128 * 1024); if (stm32x_info->has_large_mem) { /* fixed memory for larger devices */ setup_sector(bank, 12, 4, 16 * 1024); setup_sector(bank, 16, 1, 64 * 1024); /* dynamic memory for larger devices */ setup_sector(bank, 16 + 1, num_pages - 5 - 12, 128 * 1024); } for (i = 0; i < num_pages; i++) { bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 0; } stm32x_info->probed = 1; return ERROR_OK; } static int stm32x_auto_probe(struct flash_bank *bank) { struct stm32x_flash_bank *stm32x_info = bank->driver_priv; if (stm32x_info->probed) return ERROR_OK; return stm32x_probe(bank); } static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size) { uint32_t device_id; int printed; /* read stm32 device id register */ int retval = stm32x_get_device_id(bank, &device_id); if (retval != ERROR_OK) return retval; if ((device_id & 0xfff) == 0x411) { printed = snprintf(buf, buf_size, "stm32f2x - Rev: "); buf += printed; buf_size -= printed; switch (device_id >> 16) { case 0x1000: snprintf(buf, buf_size, "A"); break; case 0x2000: snprintf(buf, buf_size, "B"); break; case 0x1001: snprintf(buf, buf_size, "Z"); break; case 0x2001: snprintf(buf, buf_size, "Y"); break; case 0x2003: snprintf(buf, buf_size, "X"); break; default: snprintf(buf, buf_size, "unknown"); break; } } else if (((device_id & 0xfff) == 0x413) || ((device_id & 0xfff) == 0x419)) { printed = snprintf(buf, buf_size, "stm32f4x - Rev: "); buf += printed; buf_size -= printed; switch (device_id >> 16) { case 0x1000: snprintf(buf, buf_size, "A"); break; case 0x1001: snprintf(buf, buf_size, "Z"); break; default: snprintf(buf, buf_size, "unknown"); break; } } else { snprintf(buf, buf_size, "Cannot identify target as a stm32x\n"); return ERROR_FAIL; } return ERROR_OK; } COMMAND_HANDLER(stm32x_handle_lock_command) { struct target *target = NULL; struct stm32x_flash_bank *stm32x_info = NULL; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; stm32x_info = bank->driver_priv; target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (stm32x_read_options(bank) != ERROR_OK) { command_print(CMD_CTX, "%s failed to read options", bank->driver->name); return ERROR_OK; } /* set readout protection */ stm32x_info->option_bytes.RDP = 0; if (stm32x_write_options(bank) != ERROR_OK) { command_print(CMD_CTX, "%s failed to lock device", bank->driver->name); return ERROR_OK; } command_print(CMD_CTX, "%s locked", bank->driver->name); return ERROR_OK; } COMMAND_HANDLER(stm32x_handle_unlock_command) { struct target *target = NULL; struct stm32x_flash_bank *stm32x_info = NULL; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; stm32x_info = bank->driver_priv; target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (stm32x_read_options(bank) != ERROR_OK) { command_print(CMD_CTX, "%s failed to read options", bank->driver->name); return ERROR_OK; } /* clear readout protection and complementary option bytes * this will also force a device unlock if set */ stm32x_info->option_bytes.RDP = 0xAA; if (stm32x_write_options(bank) != ERROR_OK) { command_print(CMD_CTX, "%s failed to unlock device", bank->driver->name); return ERROR_OK; } command_print(CMD_CTX, "%s unlocked.\n" "INFO: a reset or power cycle is required " "for the new settings to take effect.", bank->driver->name); return ERROR_OK; } static int stm32x_mass_erase(struct flash_bank *bank) { int retval; struct target *target = bank->target; struct stm32x_flash_bank *stm32x_info = NULL; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } stm32x_info = bank->driver_priv; retval = stm32x_unlock_reg(target); if (retval != ERROR_OK) return retval; /* mass erase flash memory */ if (stm32x_info->has_large_mem) retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_MER | FLASH_MER1); else retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_MER); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_MER | FLASH_STRT); if (retval != ERROR_OK) return retval; retval = stm32x_wait_status_busy(bank, 30000); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); if (retval != ERROR_OK) return retval; return ERROR_OK; } COMMAND_HANDLER(stm32x_handle_mass_erase_command) { int i; if (CMD_ARGC < 1) { command_print(CMD_CTX, "stm32x mass_erase "); return ERROR_COMMAND_SYNTAX_ERROR; } struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; retval = stm32x_mass_erase(bank); if (retval == ERROR_OK) { /* set all sectors as erased */ for (i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_erased = 1; command_print(CMD_CTX, "stm32x mass erase complete"); } else { command_print(CMD_CTX, "stm32x mass erase failed"); } return retval; } static const struct command_registration stm32x_exec_command_handlers[] = { { .name = "lock", .handler = stm32x_handle_lock_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Lock entire flash device.", }, { .name = "unlock", .handler = stm32x_handle_unlock_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Unlock entire protected flash device.", }, { .name = "mass_erase", .handler = stm32x_handle_mass_erase_command, .mode = COMMAND_EXEC, .usage = "bank_id", .help = "Erase entire flash device.", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration stm32x_command_handlers[] = { { .name = "stm32f2x", .mode = COMMAND_ANY, .help = "stm32f2x flash command group", .usage = "", .chain = stm32x_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct flash_driver stm32f2x_flash = { .name = "stm32f2x", .commands = stm32x_command_handlers, .flash_bank_command = stm32x_flash_bank_command, .erase = stm32x_erase, .protect = stm32x_protect, .write = stm32x_write, .read = default_flash_read, .probe = stm32x_probe, .auto_probe = stm32x_auto_probe, .erase_check = default_flash_blank_check, .protect_check = stm32x_protect_check, .info = get_stm32x_info, }; openocd-0.7.0/src/flash/nor/em357.c0000644000175000001440000006265612137151330013563 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * Copyright (C) 2011 by Erik Botö * erik.boto@pelagicore.com * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include #include #include /* em357 register locations */ #define EM357_FLASH_ACR 0x40008000 #define EM357_FLASH_KEYR 0x40008004 #define EM357_FLASH_OPTKEYR 0x40008008 #define EM357_FLASH_SR 0x4000800C #define EM357_FLASH_CR 0x40008010 #define EM357_FLASH_AR 0x40008014 #define EM357_FLASH_OBR 0x4000801C #define EM357_FLASH_WRPR 0x40008020 #define EM357_FPEC_CLK 0x4000402c /* option byte location */ #define EM357_OB_RDP 0x08040800 #define EM357_OB_WRP0 0x08040808 #define EM357_OB_WRP1 0x0804080A #define EM357_OB_WRP2 0x0804080C /* FLASH_CR register bits */ #define FLASH_PG (1 << 0) #define FLASH_PER (1 << 1) #define FLASH_MER (1 << 2) #define FLASH_OPTPG (1 << 4) #define FLASH_OPTER (1 << 5) #define FLASH_STRT (1 << 6) #define FLASH_LOCK (1 << 7) #define FLASH_OPTWRE (1 << 9) /* FLASH_SR register bits */ #define FLASH_BSY (1 << 0) #define FLASH_PGERR (1 << 2) #define FLASH_WRPRTERR (1 << 4) #define FLASH_EOP (1 << 5) /* EM357_FLASH_OBR bit definitions (reading) */ #define OPT_ERROR 0 #define OPT_READOUT 1 /* register unlock keys */ #define KEY1 0x45670123 #define KEY2 0xCDEF89AB struct em357_options { uint16_t RDP; uint16_t user_options; uint16_t protection[3]; }; struct em357_flash_bank { struct em357_options option_bytes; int ppage_size; int probed; }; static int em357_mass_erase(struct flash_bank *bank); /* flash bank em357 0 0 */ FLASH_BANK_COMMAND_HANDLER(em357_flash_bank_command) { struct em357_flash_bank *em357_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; em357_info = malloc(sizeof(struct em357_flash_bank)); bank->driver_priv = em357_info; em357_info->probed = 0; return ERROR_OK; } static inline int em357_get_flash_status(struct flash_bank *bank, uint32_t *status) { struct target *target = bank->target; return target_read_u32(target, EM357_FLASH_SR, status); } static int em357_wait_status_busy(struct flash_bank *bank, int timeout) { struct target *target = bank->target; uint32_t status; int retval = ERROR_OK; /* wait for busy to clear */ for (;; ) { retval = em357_get_flash_status(bank, &status); if (retval != ERROR_OK) return retval; LOG_DEBUG("status: 0x%" PRIx32 "", status); if ((status & FLASH_BSY) == 0) break; if (timeout-- <= 0) { LOG_ERROR("timed out waiting for flash"); return ERROR_FAIL; } alive_sleep(1); } if (status & FLASH_WRPRTERR) { LOG_ERROR("em357 device protected"); retval = ERROR_FAIL; } if (status & FLASH_PGERR) { LOG_ERROR("em357 device programming failed"); retval = ERROR_FAIL; } /* Clear but report errors */ if (status & (FLASH_WRPRTERR | FLASH_PGERR)) { /* If this operation fails, we ignore it and report the original * retval */ target_write_u32(target, EM357_FLASH_SR, FLASH_WRPRTERR | FLASH_PGERR); } return retval; } static int em357_read_options(struct flash_bank *bank) { uint32_t optiondata; struct em357_flash_bank *em357_info = NULL; struct target *target = bank->target; em357_info = bank->driver_priv; /* read current option bytes */ int retval = target_read_u32(target, EM357_FLASH_OBR, &optiondata); if (retval != ERROR_OK) return retval; em357_info->option_bytes.user_options = (uint16_t)0xFFFC | ((optiondata >> 2) & 0x03); em357_info->option_bytes.RDP = (optiondata & (1 << OPT_READOUT)) ? 0xFFFF : 0x5AA5; if (optiondata & (1 << OPT_READOUT)) LOG_INFO("Device Security Bit Set"); /* each bit refers to a 4bank protection */ retval = target_read_u32(target, EM357_FLASH_WRPR, &optiondata); if (retval != ERROR_OK) return retval; em357_info->option_bytes.protection[0] = (uint16_t)optiondata; em357_info->option_bytes.protection[1] = (uint16_t)(optiondata >> 8); em357_info->option_bytes.protection[2] = (uint16_t)(optiondata >> 16); return ERROR_OK; } static int em357_erase_options(struct flash_bank *bank) { struct em357_flash_bank *em357_info = NULL; struct target *target = bank->target; em357_info = bank->driver_priv; /* read current options */ em357_read_options(bank); /* unlock flash registers */ int retval = target_write_u32(target, EM357_FLASH_KEYR, KEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, EM357_FLASH_KEYR, KEY2); if (retval != ERROR_OK) return retval; /* unlock option flash registers */ retval = target_write_u32(target, EM357_FLASH_OPTKEYR, KEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, EM357_FLASH_OPTKEYR, KEY2); if (retval != ERROR_OK) return retval; /* erase option bytes */ retval = target_write_u32(target, EM357_FLASH_CR, FLASH_OPTER | FLASH_OPTWRE); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, EM357_FLASH_CR, FLASH_OPTER | FLASH_STRT | FLASH_OPTWRE); if (retval != ERROR_OK) return retval; retval = em357_wait_status_busy(bank, 10); if (retval != ERROR_OK) return retval; /* clear readout protection and complementary option bytes * this will also force a device unlock if set */ em357_info->option_bytes.RDP = 0x5AA5; return ERROR_OK; } static int em357_write_options(struct flash_bank *bank) { struct em357_flash_bank *em357_info = NULL; struct target *target = bank->target; em357_info = bank->driver_priv; /* unlock flash registers */ int retval = target_write_u32(target, EM357_FLASH_KEYR, KEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, EM357_FLASH_KEYR, KEY2); if (retval != ERROR_OK) return retval; /* unlock option flash registers */ retval = target_write_u32(target, EM357_FLASH_OPTKEYR, KEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, EM357_FLASH_OPTKEYR, KEY2); if (retval != ERROR_OK) return retval; /* program option bytes */ retval = target_write_u32(target, EM357_FLASH_CR, FLASH_OPTPG | FLASH_OPTWRE); if (retval != ERROR_OK) return retval; retval = em357_wait_status_busy(bank, 10); if (retval != ERROR_OK) return retval; /* write protection byte 1 */ retval = target_write_u16(target, EM357_OB_WRP0, em357_info->option_bytes.protection[0]); if (retval != ERROR_OK) return retval; retval = em357_wait_status_busy(bank, 10); if (retval != ERROR_OK) return retval; /* write protection byte 2 */ retval = target_write_u16(target, EM357_OB_WRP1, em357_info->option_bytes.protection[1]); if (retval != ERROR_OK) return retval; retval = em357_wait_status_busy(bank, 10); if (retval != ERROR_OK) return retval; /* write protection byte 3 */ retval = target_write_u16(target, EM357_OB_WRP2, em357_info->option_bytes.protection[2]); if (retval != ERROR_OK) return retval; retval = em357_wait_status_busy(bank, 10); if (retval != ERROR_OK) return retval; /* write readout protection bit */ retval = target_write_u16(target, EM357_OB_RDP, em357_info->option_bytes.RDP); if (retval != ERROR_OK) return retval; retval = em357_wait_status_busy(bank, 10); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, EM357_FLASH_CR, FLASH_LOCK); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int em357_protect_check(struct flash_bank *bank) { struct target *target = bank->target; struct em357_flash_bank *em357_info = bank->driver_priv; uint32_t protection; int i, s; int num_bits; int set; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* each bit refers to a 4bank protection (bit 0-23) */ int retval = target_read_u32(target, EM357_FLASH_WRPR, &protection); if (retval != ERROR_OK) return retval; /* each protection bit is for 4 * 2K pages */ num_bits = (bank->num_sectors / em357_info->ppage_size); for (i = 0; i < num_bits; i++) { set = 1; if (protection & (1 << i)) set = 0; for (s = 0; s < em357_info->ppage_size; s++) bank->sectors[(i * em357_info->ppage_size) + s].is_protected = set; } return ERROR_OK; } static int em357_erase(struct flash_bank *bank, int first, int last) { struct target *target = bank->target; int i; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if ((first == 0) && (last == (bank->num_sectors - 1))) return em357_mass_erase(bank); /* Enable FPEC clock */ target_write_u32(target, EM357_FPEC_CLK, 0x00000001); /* unlock flash registers */ int retval = target_write_u32(target, EM357_FLASH_KEYR, KEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, EM357_FLASH_KEYR, KEY2); if (retval != ERROR_OK) return retval; for (i = first; i <= last; i++) { retval = target_write_u32(target, EM357_FLASH_CR, FLASH_PER); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, EM357_FLASH_AR, bank->base + bank->sectors[i].offset); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, EM357_FLASH_CR, FLASH_PER | FLASH_STRT); if (retval != ERROR_OK) return retval; retval = em357_wait_status_busy(bank, 100); if (retval != ERROR_OK) return retval; bank->sectors[i].is_erased = 1; } retval = target_write_u32(target, EM357_FLASH_CR, FLASH_LOCK); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int em357_protect(struct flash_bank *bank, int set, int first, int last) { struct em357_flash_bank *em357_info = NULL; struct target *target = bank->target; uint16_t prot_reg[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}; int i, reg, bit; int status; uint32_t protection; em357_info = bank->driver_priv; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if ((first % em357_info->ppage_size) != 0) { LOG_WARNING("aligned start protect sector to a %d sector boundary", em357_info->ppage_size); first = first - (first % em357_info->ppage_size); } if (((last + 1) % em357_info->ppage_size) != 0) { LOG_WARNING("aligned end protect sector to a %d sector boundary", em357_info->ppage_size); last++; last = last - (last % em357_info->ppage_size); last--; } /* each bit refers to a 4bank protection */ int retval = target_read_u32(target, EM357_FLASH_WRPR, &protection); if (retval != ERROR_OK) return retval; prot_reg[0] = (uint16_t)protection; prot_reg[1] = (uint16_t)(protection >> 8); prot_reg[2] = (uint16_t)(protection >> 16); for (i = first; i <= last; i++) { reg = (i / em357_info->ppage_size) / 8; bit = (i / em357_info->ppage_size) - (reg * 8); LOG_WARNING("reg, bit: %d, %d", reg, bit); if (set) prot_reg[reg] &= ~(1 << bit); else prot_reg[reg] |= (1 << bit); } status = em357_erase_options(bank); if (retval != ERROR_OK) return status; em357_info->option_bytes.protection[0] = prot_reg[0]; em357_info->option_bytes.protection[1] = prot_reg[1]; em357_info->option_bytes.protection[2] = prot_reg[2]; return em357_write_options(bank); } static int em357_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t buffer_size = 16384; struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[4]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; /* see contib/loaders/flash/stm32x.s for src, the same is used here except for * a modified *_FLASH_BASE */ static const uint8_t em357_flash_write_code[] = { /* #define EM357_FLASH_CR_OFFSET 0x10 * #define EM357_FLASH_SR_OFFSET 0x0C * write: */ 0x08, 0x4c, /* ldr r4, EM357_FLASH_BASE */ 0x1c, 0x44, /* add r4, r3 */ /* write_half_word: */ 0x01, 0x23, /* movs r3, #0x01 */ 0x23, 0x61, /* str r3, [r4, *#EM357_FLASH_CR_OFFSET] */ 0x30, 0xf8, 0x02, 0x3b, /* ldrh r3, [r0], #0x02 */ 0x21, 0xf8, 0x02, 0x3b, /* strh r3, [r1], #0x02 */ /* busy: */ 0xe3, 0x68, /* ldr r3, [r4, *#EM357_FLASH_SR_OFFSET] */ 0x13, 0xf0, 0x01, 0x0f, /* tst r3, #0x01 */ 0xfb, 0xd0, /* beq busy */ 0x13, 0xf0, 0x14, 0x0f, /* tst r3, #0x14 */ 0x01, 0xd1, /* bne exit */ 0x01, 0x3a, /* subs r2, r2, #0x01 */ 0xf0, 0xd1, /* bne write_half_word */ /* exit: */ 0x00, 0xbe, /* bkpt #0x00 */ 0x00, 0x80, 0x00, 0x40, /* EM357_FLASH_BASE: .word 0x40008000 */ }; /* flash write code */ if (target_alloc_working_area(target, sizeof(em357_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } ; retval = target_write_buffer(target, write_algorithm->address, sizeof(em357_flash_write_code), (uint8_t *)em357_flash_write_code); if (retval != ERROR_OK) return retval; /* memory buffer */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; if (buffer_size <= 256) { /* we already allocated the writing code, but failed to get a * buffer, free the algorithm */ target_free_working_area(target, write_algorithm); LOG_WARNING( "no large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_IN_OUT); while (count > 0) { uint32_t thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count; retval = target_write_buffer(target, source->address, thisrun_count * 2, buffer); if (retval != ERROR_OK) break; buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, address); buf_set_u32(reg_params[2].value, 0, 32, thisrun_count); buf_set_u32(reg_params[3].value, 0, 32, 0); retval = target_run_algorithm(target, 0, NULL, 4, reg_params, write_algorithm->address, 0, 10000, &armv7m_info); if (retval != ERROR_OK) { LOG_ERROR("error executing em357 flash write algorithm"); break; } if (buf_get_u32(reg_params[3].value, 0, 32) & FLASH_PGERR) { LOG_ERROR("flash memory not erased before writing"); /* Clear but report errors */ target_write_u32(target, EM357_FLASH_SR, FLASH_PGERR); retval = ERROR_FAIL; break; } if (buf_get_u32(reg_params[3].value, 0, 32) & FLASH_WRPRTERR) { LOG_ERROR("flash memory write protected"); /* Clear but report errors */ target_write_u32(target, EM357_FLASH_SR, FLASH_WRPRTERR); retval = ERROR_FAIL; break; } buffer += thisrun_count * 2; address += thisrun_count * 2; count -= thisrun_count; } target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); return retval; } static int em357_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t words_remaining = (count / 2); uint32_t bytes_remaining = (count & 0x00000001); uint32_t address = bank->base + offset; uint32_t bytes_written = 0; int retval; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset & 0x1) { LOG_WARNING("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } /* unlock flash registers */ retval = target_write_u32(target, EM357_FLASH_KEYR, KEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, EM357_FLASH_KEYR, KEY2); if (retval != ERROR_OK) return retval; target_write_u32(target, EM357_FPEC_CLK, 0x00000001); /* multiple half words (2-byte) to be programmed? */ if (words_remaining > 0) { /* try using a block write */ retval = em357_write_block(bank, buffer, offset, words_remaining); if (retval != ERROR_OK) { if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* if block write failed (no sufficient working area), * we use normal (slow) single dword accesses */ LOG_WARNING( "couldn't use block writes, falling back to single memory accesses"); } } else { buffer += words_remaining * 2; address += words_remaining * 2; words_remaining = 0; } } if ((retval != ERROR_OK) && (retval != ERROR_TARGET_RESOURCE_NOT_AVAILABLE)) return retval; while (words_remaining > 0) { uint16_t value; memcpy(&value, buffer + bytes_written, sizeof(uint16_t)); retval = target_write_u32(target, EM357_FLASH_CR, FLASH_PG); if (retval != ERROR_OK) return retval; retval = target_write_u16(target, address, value); if (retval != ERROR_OK) return retval; retval = em357_wait_status_busy(bank, 5); if (retval != ERROR_OK) return retval; bytes_written += 2; words_remaining--; address += 2; } if (bytes_remaining) { uint16_t value = 0xffff; memcpy(&value, buffer + bytes_written, bytes_remaining); retval = target_write_u32(target, EM357_FLASH_CR, FLASH_PG); if (retval != ERROR_OK) return retval; retval = target_write_u16(target, address, value); if (retval != ERROR_OK) return retval; retval = em357_wait_status_busy(bank, 5); if (retval != ERROR_OK) return retval; } return target_write_u32(target, EM357_FLASH_CR, FLASH_LOCK); } static int em357_probe(struct flash_bank *bank) { struct target *target = bank->target; struct em357_flash_bank *em357_info = bank->driver_priv; int i; uint16_t num_pages; int page_size; uint32_t base_address = 0x08000000; em357_info->probed = 0; switch (bank->size) { case 0x10000: /* 64k -- 64 1k pages */ num_pages = 64; page_size = 1024; break; case 0x20000: /* 128k -- 128 1k pages */ num_pages = 128; page_size = 1024; break; case 0x30000: /* 192k -- 96 2k pages */ num_pages = 96; page_size = 2048; break; case 0x40000: /* 256k -- 128 2k pages */ num_pages = 128; page_size = 2048; break; default: LOG_WARNING("No size specified for em357 flash driver, assuming 192k!"); num_pages = 96; page_size = 2048; break; } /* Enable FPEC CLK */ int retval = target_write_u32(target, EM357_FPEC_CLK, 0x00000001); if (retval != ERROR_OK) return retval; em357_info->ppage_size = 4; LOG_INFO("flash size = %dkbytes", num_pages*page_size/1024); if (bank->sectors) { free(bank->sectors); bank->sectors = NULL; } bank->base = base_address; bank->size = (num_pages * page_size); bank->num_sectors = num_pages; bank->sectors = malloc(sizeof(struct flash_sector) * num_pages); for (i = 0; i < num_pages; i++) { bank->sectors[i].offset = i * page_size; bank->sectors[i].size = page_size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 1; } em357_info->probed = 1; return ERROR_OK; } static int em357_auto_probe(struct flash_bank *bank) { struct em357_flash_bank *em357_info = bank->driver_priv; if (em357_info->probed) return ERROR_OK; return em357_probe(bank); } static int get_em357_info(struct flash_bank *bank, char *buf, int buf_size) { snprintf(buf, buf_size, "em357\n"); return ERROR_OK; } COMMAND_HANDLER(em357_handle_lock_command) { struct target *target = NULL; struct em357_flash_bank *em357_info = NULL; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; em357_info = bank->driver_priv; target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (em357_erase_options(bank) != ERROR_OK) { command_print(CMD_CTX, "em357 failed to erase options"); return ERROR_OK; } /* set readout protection */ em357_info->option_bytes.RDP = 0; if (em357_write_options(bank) != ERROR_OK) { command_print(CMD_CTX, "em357 failed to lock device"); return ERROR_OK; } command_print(CMD_CTX, "em357 locked"); return ERROR_OK; } COMMAND_HANDLER(em357_handle_unlock_command) { struct target *target = NULL; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (em357_erase_options(bank) != ERROR_OK) { command_print(CMD_CTX, "em357 failed to unlock device"); return ERROR_OK; } if (em357_write_options(bank) != ERROR_OK) { command_print(CMD_CTX, "em357 failed to lock device"); return ERROR_OK; } command_print(CMD_CTX, "em357 unlocked.\n" "INFO: a reset or power cycle is required " "for the new settings to take effect."); return ERROR_OK; } static int em357_mass_erase(struct flash_bank *bank) { struct target *target = bank->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Make sure the flash clock is on */ target_write_u32(target, EM357_FPEC_CLK, 0x00000001); /* unlock option flash registers */ int retval = target_write_u32(target, EM357_FLASH_KEYR, KEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, EM357_FLASH_KEYR, KEY2); if (retval != ERROR_OK) return retval; /* mass erase flash memory */ retval = target_write_u32(target, EM357_FLASH_CR, FLASH_MER); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, EM357_FLASH_CR, FLASH_MER | FLASH_STRT); if (retval != ERROR_OK) return retval; retval = em357_wait_status_busy(bank, 100); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, EM357_FLASH_CR, FLASH_LOCK); if (retval != ERROR_OK) return retval; return ERROR_OK; } COMMAND_HANDLER(em357_handle_mass_erase_command) { int i; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; retval = em357_mass_erase(bank); if (retval == ERROR_OK) { /* set all sectors as erased */ for (i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_erased = 1; command_print(CMD_CTX, "em357 mass erase complete"); } else command_print(CMD_CTX, "em357 mass erase failed"); return retval; } static const struct command_registration em357_exec_command_handlers[] = { { .name = "lock", .usage = "", .handler = em357_handle_lock_command, .mode = COMMAND_EXEC, .help = "Lock entire flash device.", }, { .name = "unlock", .usage = "", .handler = em357_handle_unlock_command, .mode = COMMAND_EXEC, .help = "Unlock entire protected flash device.", }, { .name = "mass_erase", .usage = "", .handler = em357_handle_mass_erase_command, .mode = COMMAND_EXEC, .help = "Erase entire flash device.", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration em357_command_handlers[] = { { .name = "em357", .mode = COMMAND_ANY, .help = "em357 flash command group", .usage = "", .chain = em357_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct flash_driver em357_flash = { .name = "em357", .commands = em357_command_handlers, .flash_bank_command = em357_flash_bank_command, .erase = em357_erase, .protect = em357_protect, .write = em357_write, .read = default_flash_read, .probe = em357_probe, .auto_probe = em357_auto_probe, .erase_check = default_flash_blank_check, .protect_check = em357_protect_check, .info = get_em357_info, }; openocd-0.7.0/src/flash/nor/driver.h0000644000175000001440000002076312134336410014215 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Copyright (C) 2007,2008 Øyvind Harboe * * Copyright (C) 2008 by Spencer Oliver * * Copyright (C) 2009 Zachary T Welch * * Copyright (C) 2010 by Antonio Borneo * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef FLASH_NOR_DRIVER_H #define FLASH_NOR_DRIVER_H struct flash_bank; #define __FLASH_BANK_COMMAND(name) \ COMMAND_HELPER(name, struct flash_bank *bank) /** * @brief Provides the implementation-independent structure that defines * all of the callbacks required by OpenOCD flash drivers. * * Driver authors must implement the routines defined here, providing an * instance with the fields filled out. After that, the instance must * be registered in flash.c, so it can be used by the driver lookup system. * * Specifically, the user can issue the command: @par * @code * flash bank DRIVERNAME ...parameters... * @endcode * * OpenOCD will search for the driver with a @c flash_driver_s::name * that matches @c DRIVERNAME. * * The flash subsystem calls some of the other drivers routines a using * corresponding static flash_driver_callback() * routine in flash.c. */ struct flash_driver { /** * Gives a human-readable name of this flash driver, * This field is used to select and initialize the driver. */ const char *name; /** * Gives a human-readable description of arguments. */ const char *usage; /** * An array of driver-specific commands to register. When called * during the "flash bank" command, the driver can register addition * commands to support new flash chip functions. */ const struct command_registration *commands; /** * Finish the "flash bank" command for @a bank. The * @a bank parameter will have been filled in by the core flash * layer when this routine is called, and the driver can store * additional information in its struct flash_bank::driver_priv field. * * The CMD_ARGV are: @par * @code * CMD_ARGV[0] = bank * CMD_ARGV[1] = drivername {name above} * CMD_ARGV[2] = baseaddress * CMD_ARGV[3] = lengthbytes * CMD_ARGV[4] = chip_width_in bytes * CMD_ARGV[5] = bus_width_in_bytes * CMD_ARGV[6] = driver-specific parameters * @endcode * * For example, CMD_ARGV[4] = 2 (for 16 bit flash), * CMD_ARGV[5] = 4 (for 32 bit bus). * * If extra arguments are provided (@a CMD_ARGC > 6), they will * start in @a CMD_ARGV[6]. These can be used to implement * driver-specific extensions. * * @returns ERROR_OK if successful; otherwise, an error code. */ __FLASH_BANK_COMMAND((*flash_bank_command)); /** * Bank/sector erase routine (target-specific). When * called, the flash driver should erase the specified sectors * using whatever means are at its disposal. * * @param bank The bank of flash to be erased. * @param first The number of the first sector to erase, typically 0. * @param last The number of the last sector to erase, typically N-1. * @returns ERROR_OK if successful; otherwise, an error code. */ int (*erase)(struct flash_bank *bank, int first, int last); /** * Bank/sector protection routine (target-specific). * * When called, the driver should enable/disable protection * for MINIMUM the range covered by first..last sectors * inclusive. Some chips have alignment requirements will * cause the actual range to be protected / unprotected to * be larger than the first..last range. * * @param bank The bank to protect or unprotect. * @param set If non-zero, enable protection; if 0, disable it. * @param first The first sector to (un)protect, typicaly 0. * @param last The last sector to (un)project, typically N-1. * @returns ERROR_OK if successful; otherwise, an error code. */ int (*protect)(struct flash_bank *bank, int set, int first, int last); /** * Program data into the flash. Note CPU address will be * "bank->base + offset", while the physical address is * dependent upon current target MMU mappings. * * @param bank The bank to program * @param buffer The data bytes to write. * @param offset The offset into the chip to program. * @param count The number of bytes to write. * @returns ERROR_OK if successful; otherwise, an error code. */ int (*write)(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count); /** * Read data from the flash. Note CPU address will be * "bank->base + offset", while the physical address is * dependent upon current target MMU mappings. * * @param bank The bank to read. * @param buffer The data bytes read. * @param offset The offset into the chip to read. * @param count The number of bytes to read. * @returns ERROR_OK if successful; otherwise, an error code. */ int (*read)(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count); /** * Probe to determine what kind of flash is present. * This is invoked by the "probe" script command. * * @param bank The bank to probe * @returns ERROR_OK if successful; otherwise, an error code. */ int (*probe)(struct flash_bank *bank); /** * Check the erasure status of a flash bank. * When called, the driver routine must perform the required * checks and then set the @c flash_sector_s::is_erased field * for each of the flash banks's sectors. * * @param bank The bank to check * @returns ERROR_OK if successful; otherwise, an error code. */ int (*erase_check)(struct flash_bank *bank); /** * Determine if the specific bank is "protected" or not. * When called, the driver routine must must perform the * required protection check(s) and then set the @c * flash_sector_s::is_protected field for each of the flash * bank's sectors. * * @param bank - the bank to check * @returns ERROR_OK if successful; otherwise, an error code. */ int (*protect_check)(struct flash_bank *bank); /** * Display human-readable information about the flash * bank into the given buffer. Drivers must be careful to avoid * overflowing the buffer. * * @param bank - the bank to get info about * @param char - where to put the text for the human to read * @param buf_size - the size of the human buffer. * @returns ERROR_OK if successful; otherwise, an error code. */ int (*info)(struct flash_bank *bank, char *buf, int buf_size); /** * A more gentle flavor of filash_driver_s::probe, performing * setup with less noise. Generally, driver routines should test * to see if the bank has already been probed; if it has, the * driver probably should not perform its probe a second time. * * This callback is often called from the inside of other * routines (e.g. GDB flash downloads) to autoprobe the flash as * it is programing the flash. * * @param bank - the bank to probe * @returns ERROR_OK if successful; otherwise, an error code. */ int (*auto_probe)(struct flash_bank *bank); }; #define FLASH_BANK_COMMAND_HANDLER(name) \ static __FLASH_BANK_COMMAND(name) /** * Find a NOR flash driver by its name. * @param name The name of the requested driver. * @returns The flash_driver called @c name, or NULL if not found. */ struct flash_driver *flash_driver_find_by_name(const char *name); #endif /* FLASH_NOR_DRIVER_H */ openocd-0.7.0/src/flash/nor/fm3.c0000644000175000001440000007531712137151330013406 00000000000000/*************************************************************************** * Copyright (C) 2011 by Marc Willam, Holger Wech * * openOCD.fseu(AT)de.fujitsu.com * * Copyright (C) 2011 Ronny Strutz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include #include #include #define FLASH_DQ6 0x00000040 /* Data toggle flag bit (TOGG) position */ #define FLASH_DQ5 0x00000020 /* Time limit exceeding flag bit (TLOV) position */ enum fm3_variant { mb9bfxx1, /* Flash Type '1' */ mb9bfxx2, mb9bfxx3, mb9bfxx4, mb9bfxx5, mb9bfxx6, mb9bfxx7, mb9bfxx8, mb9afxx1, /* Flash Type '2' */ mb9afxx2, mb9afxx3, mb9afxx4, mb9afxx5, mb9afxx6, mb9afxx7, mb9afxx8, }; enum fm3_flash_type { fm3_no_flash_type = 0, fm3_flash_type1 = 1, fm3_flash_type2 = 2 }; struct fm3_flash_bank { enum fm3_variant variant; enum fm3_flash_type flashtype; int probed; }; FLASH_BANK_COMMAND_HANDLER(fm3_flash_bank_command) { struct fm3_flash_bank *fm3_info; if (CMD_ARGC < 6) return ERROR_COMMAND_SYNTAX_ERROR; fm3_info = malloc(sizeof(struct fm3_flash_bank)); bank->driver_priv = fm3_info; /* Flash type '1' */ if (strcmp(CMD_ARGV[5], "mb9bfxx1.cpu") == 0) { fm3_info->variant = mb9bfxx1; fm3_info->flashtype = fm3_flash_type1; } else if (strcmp(CMD_ARGV[5], "mb9bfxx2.cpu") == 0) { fm3_info->variant = mb9bfxx2; fm3_info->flashtype = fm3_flash_type1; } else if (strcmp(CMD_ARGV[5], "mb9bfxx3.cpu") == 0) { fm3_info->variant = mb9bfxx3; fm3_info->flashtype = fm3_flash_type1; } else if (strcmp(CMD_ARGV[5], "mb9bfxx4.cpu") == 0) { fm3_info->variant = mb9bfxx4; fm3_info->flashtype = fm3_flash_type1; } else if (strcmp(CMD_ARGV[5], "mb9bfxx5.cpu") == 0) { fm3_info->variant = mb9bfxx5; fm3_info->flashtype = fm3_flash_type1; } else if (strcmp(CMD_ARGV[5], "mb9bfxx6.cpu") == 0) { fm3_info->variant = mb9bfxx6; fm3_info->flashtype = fm3_flash_type1; } else if (strcmp(CMD_ARGV[5], "mb9bfxx7.cpu") == 0) { fm3_info->variant = mb9bfxx7; fm3_info->flashtype = fm3_flash_type1; } else if (strcmp(CMD_ARGV[5], "mb9bfxx8.cpu") == 0) { fm3_info->variant = mb9bfxx8; fm3_info->flashtype = fm3_flash_type1; } else if (strcmp(CMD_ARGV[5], "mb9afxx1.cpu") == 0) { /* Flash type '2' */ fm3_info->variant = mb9afxx1; fm3_info->flashtype = fm3_flash_type2; } else if (strcmp(CMD_ARGV[5], "mb9afxx2.cpu") == 0) { fm3_info->variant = mb9afxx2; fm3_info->flashtype = fm3_flash_type2; } else if (strcmp(CMD_ARGV[5], "mb9afxx3.cpu") == 0) { fm3_info->variant = mb9afxx3; fm3_info->flashtype = fm3_flash_type2; } else if (strcmp(CMD_ARGV[5], "mb9afxx4.cpu") == 0) { fm3_info->variant = mb9afxx4; fm3_info->flashtype = fm3_flash_type2; } else if (strcmp(CMD_ARGV[5], "mb9afxx5.cpu") == 0) { fm3_info->variant = mb9afxx5; fm3_info->flashtype = fm3_flash_type2; } else if (strcmp(CMD_ARGV[5], "mb9afxx6.cpu") == 0) { fm3_info->variant = mb9afxx6; fm3_info->flashtype = fm3_flash_type2; } else if (strcmp(CMD_ARGV[5], "mb9afxx7.cpu") == 0) { fm3_info->variant = mb9afxx7; fm3_info->flashtype = fm3_flash_type2; } else if (strcmp(CMD_ARGV[5], "mb9afxx8.cpu") == 0) { fm3_info->variant = mb9afxx8; fm3_info->flashtype = fm3_flash_type2; } /* unknown Flash type */ else { LOG_ERROR("unknown fm3 variant: %s", CMD_ARGV[5]); free(fm3_info); return ERROR_FLASH_BANK_INVALID; } fm3_info->probed = 0; return ERROR_OK; } /* Data polling algorithm */ static int fm3_busy_wait(struct target *target, uint32_t offset, int timeout_ms) { int retval = ERROR_OK; uint16_t state1, state2; int ms = 0; /* While(1) loop exit via "break" and "return" on error */ while (1) { /* dummy-read - see flash manual */ retval = target_read_u16(target, offset, &state1); if (retval != ERROR_OK) return retval; /* Data polling 1 */ retval = target_read_u16(target, offset, &state1); if (retval != ERROR_OK) return retval; /* Data polling 2 */ retval = target_read_u16(target, offset, &state2); if (retval != ERROR_OK) return retval; /* Flash command finished via polled data equal? */ if ((state1 & FLASH_DQ6) == (state2 & FLASH_DQ6)) break; /* Timeout Flag? */ else if (state1 & FLASH_DQ5) { /* Retry data polling */ /* Data polling 1 */ retval = target_read_u16(target, offset, &state1); if (retval != ERROR_OK) return retval; /* Data polling 2 */ retval = target_read_u16(target, offset, &state2); if (retval != ERROR_OK) return retval; /* Flash command finished via polled data equal? */ if ((state1 & FLASH_DQ6) != (state2 & FLASH_DQ6)) return ERROR_FLASH_OPERATION_FAILED; /* finish anyway */ break; } usleep(1000); ++ms; /* Polling time exceeded? */ if (ms > timeout_ms) { LOG_ERROR("Polling data reading timed out!"); return ERROR_FLASH_OPERATION_FAILED; } } if (retval == ERROR_OK) LOG_DEBUG("fm3_busy_wait(%x) needs about %d ms", offset, ms); return retval; } static int fm3_erase(struct flash_bank *bank, int first, int last) { struct fm3_flash_bank *fm3_info = bank->driver_priv; struct target *target = bank->target; int retval = ERROR_OK; uint32_t u32DummyRead; int sector, odd; uint32_t u32FlashType; uint32_t u32FlashSeqAddress1; uint32_t u32FlashSeqAddress2; u32FlashType = (uint32_t) fm3_info->flashtype; if (u32FlashType == fm3_flash_type1) { u32FlashSeqAddress1 = 0x00001550; u32FlashSeqAddress2 = 0x00000AA8; } else if (u32FlashType == fm3_flash_type2) { u32FlashSeqAddress1 = 0x00000AA8; u32FlashSeqAddress2 = 0x00000554; } else { LOG_ERROR("Flash/Device type unknown!"); return ERROR_FLASH_OPERATION_FAILED; } if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } LOG_INFO("Fujitsu MB9Bxxx: Sector Erase ... (%d to %d)", first, last); /* FASZR = 0x01, Enables CPU Programming Mode (16-bit Flash acccess) */ retval = target_write_u32(target, 0x40000000, 0x0001); if (retval != ERROR_OK) return retval; /* dummy read of FASZR */ retval = target_read_u32(target, 0x40000000, &u32DummyRead); if (retval != ERROR_OK) return retval; for (sector = first ; sector <= last ; sector++) { uint32_t offset = bank->sectors[sector].offset; for (odd = 0; odd < 2 ; odd++) { if (odd) offset += 4; /* Flash unlock sequence */ retval = target_write_u16(target, u32FlashSeqAddress1, 0x00AA); if (retval != ERROR_OK) return retval; retval = target_write_u16(target, u32FlashSeqAddress2, 0x0055); if (retval != ERROR_OK) return retval; retval = target_write_u16(target, u32FlashSeqAddress1, 0x0080); if (retval != ERROR_OK) return retval; retval = target_write_u16(target, u32FlashSeqAddress1, 0x00AA); if (retval != ERROR_OK) return retval; retval = target_write_u16(target, u32FlashSeqAddress2, 0x0055); if (retval != ERROR_OK) return retval; /* Sector erase command (0x0030) */ retval = target_write_u16(target, offset, 0x0030); if (retval != ERROR_OK) return retval; retval = fm3_busy_wait(target, offset, 500); if (retval != ERROR_OK) return retval; } bank->sectors[sector].is_erased = 1; } /* FASZR = 0x02, Enables CPU Run Mode (32-bit Flash acccess) */ retval = target_write_u32(target, 0x40000000, 0x0002); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, 0x40000000, &u32DummyRead); /* dummy read of FASZR */ return retval; } static int fm3_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct fm3_flash_bank *fm3_info = bank->driver_priv; struct target *target = bank->target; uint32_t buffer_size = 2048; /* 8192 for MB9Bxx6! */ struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[6]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; uint32_t u32FlashType; uint32_t u32FlashSeqAddress1; uint32_t u32FlashSeqAddress2; u32FlashType = (uint32_t) fm3_info->flashtype; if (u32FlashType == fm3_flash_type1) { u32FlashSeqAddress1 = 0x00001550; u32FlashSeqAddress2 = 0x00000AA8; } else if (u32FlashType == fm3_flash_type2) { u32FlashSeqAddress1 = 0x00000AA8; u32FlashSeqAddress2 = 0x00000554; } else { LOG_ERROR("Flash/Device type unknown!"); return ERROR_FLASH_OPERATION_FAILED; } /* RAMCODE used for fm3 Flash programming: */ /* R0 keeps source start address (u32Source) */ /* R1 keeps target start address (u32Target) */ /* R2 keeps number of halfwords to write (u32Count) */ /* R3 keeps Flash Sequence address 1 (u32FlashSeq1) */ /* R4 keeps Flash Sequence address 2 (u32FlashSeq2) */ /* R5 returns result value (u32FlashResult) */ const uint8_t fm3_flash_write_code[] = { /* fm3_FLASH_IF->FASZ &= 0xFFFD; */ 0x5F, 0xF0, 0x80, 0x45, /* MOVS.W R5, #(fm3_FLASH_IF->FASZ) */ 0x2D, 0x68, /* LDR R5, [R5] */ 0x4F, 0xF6, 0xFD, 0x76, /* MOVW R6, #0xFFFD */ 0x35, 0x40, /* ANDS R5, R5, R6 */ 0x5F, 0xF0, 0x80, 0x46, /* MOVS.W R6, #(fm3_FLASH_IF->FASZ) */ 0x35, 0x60, /* STR R5, [R6] */ /* fm3_FLASH_IF->FASZ |= 1; */ 0x5F, 0xF0, 0x80, 0x45, /* MOVS.W R5, #(fm3_FLASH_IF->FASZ) */ 0x2D, 0x68, /* LDR R5, [R3] */ 0x55, 0xF0, 0x01, 0x05, /* ORRS.W R5, R5, #1 */ 0x5F, 0xF0, 0x80, 0x46, /* MOVS.W R6, #(fm3_FLASH_IF->FASZ) */ 0x35, 0x60, /* STR R5, [R6] */ /* u32DummyRead = fm3_FLASH_IF->FASZ; */ 0x28, 0x4D, /* LDR.N R5, ??u32DummyRead */ 0x5F, 0xF0, 0x80, 0x46, /* MOVS.W R6, #(fm3_FLASH_IF->FASZ) */ 0x36, 0x68, /* LDR R6, [R6] */ 0x2E, 0x60, /* STR R6, [R5] */ /* u32FlashResult = FLASH_WRITE_NO_RESULT */ 0x26, 0x4D, /* LDR.N R5, ??u32FlashResult */ 0x00, 0x26, /* MOVS R6, #0 */ 0x2E, 0x60, /* STR R6, [R5] */ /* while ((u32Count > 0 ) */ /* && (u32FlashResult */ /* == FLASH_WRITE_NO_RESULT)) */ 0x01, 0x2A, /* L0: CMP R2, #1 */ 0x2C, 0xDB, /* BLT.N L1 */ 0x24, 0x4D, /* LDR.N R5, ??u32FlashResult */ 0x2D, 0x68, /* LDR R5, [R5] */ 0x00, 0x2D, /* CMP R5, #0 */ 0x28, 0xD1, /* BNE.N L1 */ /* *u32FlashSeq1 = FLASH_WRITE_1; */ 0xAA, 0x25, /* MOVS R5, #0xAA */ 0x1D, 0x60, /* STR R5, [R3] */ /* *u32FlashSeq2 = FLASH_WRITE_2; */ 0x55, 0x25, /* MOVS R5, #0x55 */ 0x25, 0x60, /* STR R5, [R4] */ /* *u32FlashSeq1 = FLASH_WRITE_3; */ 0xA0, 0x25, /* MOVS R5, #0xA0 */ 0x1D, 0x60, /* STRH R5, [R3] */ /* *(volatile uint16_t*)u32Target */ /* = *(volatile uint16_t*)u32Source; */ 0x05, 0x88, /* LDRH R5, [R0] */ 0x0D, 0x80, /* STRH R5, [R1] */ /* while (u32FlashResult */ /* == FLASH_WRITE_NO_RESTULT) */ 0x1E, 0x4D, /* L2: LDR.N R5, ??u32FlashResult */ 0x2D, 0x68, /* LDR R5, [R5] */ 0x00, 0x2D, /* CMP R5, #0 */ 0x11, 0xD1, /* BNE.N L3 */ /* if ((*(volatile uint16_t*)u32Target */ /* & FLASH_DQ5) == FLASH_DQ5) */ 0x0D, 0x88, /* LDRH R5, [R1] */ 0xAD, 0x06, /* LSLS R5, R5, #0x1A */ 0x02, 0xD5, /* BPL.N L4 */ /* u32FlashResult = FLASH_WRITE_TIMEOUT */ 0x1A, 0x4D, /* LDR.N R5, ??u32FlashResult */ 0x02, 0x26, /* MOVS R6, #2 */ 0x2E, 0x60, /* STR R6, [R5] */ /* if ((*(volatile uint16_t *)u32Target */ /* & FLASH_DQ7) */ /* == (*(volatile uint16_t*)u32Source */ /* & FLASH_DQ7)) */ 0x0D, 0x88, /* L4: LDRH R5, [R1] */ 0x15, 0xF0, 0x80, 0x05, /* ANDS.W R5, R5, #0x80 */ 0x06, 0x88, /* LDRH R6, [R0] */ 0x16, 0xF0, 0x80, 0x06, /* ANDS.W R6, R6, #0x80 */ 0xB5, 0x42, /* CMP R5, R6 */ 0xED, 0xD1, /* BNE.N L2 */ /* u32FlashResult = FLASH_WRITE_OKAY */ 0x15, 0x4D, /* LDR.N R5, ??u32FlashResult */ 0x01, 0x26, /* MOVS R6, #1 */ 0x2E, 0x60, /* STR R6, [R5] */ 0xE9, 0xE7, /* B.N L2 */ /* if (u32FlashResult */ /* != FLASH_WRITE_TIMEOUT) */ 0x13, 0x4D, /* LDR.N R5, ??u32FlashResult */ 0x2D, 0x68, /* LDR R5, [R5] */ 0x02, 0x2D, /* CMP R5, #2 */ 0x02, 0xD0, /* BEQ.N L5 */ /* u32FlashResult = FLASH_WRITE_NO_RESULT */ 0x11, 0x4D, /* LDR.N R5, ??u32FlashResult */ 0x00, 0x26, /* MOVS R6, #0 */ 0x2E, 0x60, /* STR R6, [R5] */ /* u32Count--; */ 0x52, 0x1E, /* L5: SUBS R2, R2, #1 */ /* u32Source += 2; */ 0x80, 0x1C, /* ADDS R0, R0, #2 */ /* u32Target += 2; */ 0x89, 0x1C, /* ADDS R1, R1, #2 */ 0xD0, 0xE7, /* B.N L0 */ /* fm3_FLASH_IF->FASZ &= 0xFFFE; */ 0x5F, 0xF0, 0x80, 0x45, /* L1: MOVS.W R5, #(fm3_FLASH_IF->FASZ) */ 0x2D, 0x68, /* LDR R5, [R5] */ 0x4F, 0xF6, 0xFE, 0x76, /* MOVW R6, #0xFFFE */ 0x35, 0x40, /* ANDS R5, R5, R6 */ 0x5F, 0xF0, 0x80, 0x46, /* MOVS.W R6, #(fm3_FLASH_IF->FASZ) */ 0x35, 0x60, /* STR R5, [R6] */ /* fm3_FLASH_IF->FASZ |= 2; */ 0x5F, 0xF0, 0x80, 0x45, /* MOVS.W R5, #(fm3_FLASH_IF->FASZ) */ 0x2D, 0x68, /* LDR R5, [R5] */ 0x55, 0xF0, 0x02, 0x05, /* ORRS.W R5, R5, #2 */ 0x5F, 0xF0, 0x80, 0x46, /* MOVS.W R6, #(fm3_FLASH_IF->FASZ) */ 0x35, 0x60, /* STR R5, [R6] */ /* u32DummyRead = fm3_FLASH_IF->FASZ; */ 0x04, 0x4D, /* LDR.N R5, ??u32DummyRead */ 0x5F, 0xF0, 0x80, 0x46, /* MOVS.W R6, #(fm3_FLASH_IF->FASZ) */ 0x36, 0x68, /* LDR R6, [R6] */ 0x2E, 0x60, /* STR R6, [R5] */ /* copy u32FlashResult to R3 for return */ /* value */ 0xDF, 0xF8, 0x08, 0x50, /* LDR.W R5, ??u32FlashResult */ 0x2D, 0x68, /* LDR R5, [R5] */ /* Breakpoint here */ 0x00, 0xBE, /* BKPT #0 */ /* The following address pointers assume, that the code is running from */ /* address 0x1FFF8008. These address pointers will be patched, if a */ /* different start address in RAM is used (e.g. for Flash type 2)! */ 0x00, 0x80, 0xFF, 0x1F, /* u32DummyRead address in RAM (0x1FFF8000) */ 0x04, 0x80, 0xFF, 0x1F /* u32FlashResult address in RAM (0x1FFF8004) */ }; LOG_INFO("Fujitsu MB9B500: FLASH Write ..."); /* disable HW watchdog */ retval = target_write_u32(target, 0x40011C00, 0x1ACCE551); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, 0x40011C00, 0xE5331AAE); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, 0x40011008, 0x00000000); if (retval != ERROR_OK) return retval; count = count / 2; /* number bytes -> number halfwords */ /* check code alignment */ if (offset & 0x1) { LOG_WARNING("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } /* allocate working area with flash programming code */ if (target_alloc_working_area(target, sizeof(fm3_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } retval = target_write_buffer(target, write_algorithm->address, sizeof(fm3_flash_write_code), fm3_flash_write_code); if (retval != ERROR_OK) return retval; /* memory buffer */ while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; if (buffer_size <= 256) { /* free working area, write algorithm already allocated */ target_free_working_area(target, write_algorithm); LOG_WARNING("No large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); /* source start address */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* target start address */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* number of halfwords to program */ init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* Flash Sequence address 1 */ init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* Flash Sequence address 1 */ init_reg_param(®_params[5], "r5", 32, PARAM_IN); /* result */ /* write code buffer and use Flash programming code within fm3 */ /* Set breakpoint to 0 with time-out of 1000 ms */ while (count > 0) { uint32_t thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count; retval = target_write_buffer(target, write_algorithm->address, 8, fm3_flash_write_code); if (retval != ERROR_OK) break; /* Patching 'local variable address' for different RAM addresses */ if (write_algorithm->address != 0x1FFF8008) { /* Algorithm: u32DummyRead: */ retval = target_write_u32(target, (write_algorithm->address) + sizeof(fm3_flash_write_code) - 8, (write_algorithm->address) - 8); if (retval != ERROR_OK) break; /* Algorithm: u32FlashResult: */ retval = target_write_u32(target, (write_algorithm->address) + sizeof(fm3_flash_write_code) - 4, (write_algorithm->address) - 4); if (retval != ERROR_OK) break; } retval = target_write_buffer(target, source->address, thisrun_count * 2, buffer); if (retval != ERROR_OK) break; buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, address); buf_set_u32(reg_params[2].value, 0, 32, thisrun_count); buf_set_u32(reg_params[3].value, 0, 32, u32FlashSeqAddress1); buf_set_u32(reg_params[4].value, 0, 32, u32FlashSeqAddress2); retval = target_run_algorithm(target, 0, NULL, 6, reg_params, write_algorithm->address, 0, 1000, &armv7m_info); if (retval != ERROR_OK) { LOG_ERROR("Error executing fm3 Flash programming algorithm"); retval = ERROR_FLASH_OPERATION_FAILED; break; } if (buf_get_u32(reg_params[5].value, 0, 32) != ERROR_OK) { LOG_ERROR("Fujitsu MB9[A/B]FXXX: Flash programming ERROR (Timeout) -> Reg R3: %x", buf_get_u32(reg_params[5].value, 0, 32)); retval = ERROR_FLASH_OPERATION_FAILED; break; } buffer += thisrun_count * 2; address += thisrun_count * 2; count -= thisrun_count; } target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); destroy_reg_param(®_params[5]); return retval; } static int fm3_probe(struct flash_bank *bank) { struct fm3_flash_bank *fm3_info = bank->driver_priv; uint16_t num_pages; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* -- page-- start -- blocksize - mpu - totalFlash -- page0 0x00000 16k page1 0x04000 16k page2 0x08000 96k ___ fxx3 128k Flash page3 0x20000 128k ___ fxx4 256k Flash page4 0x40000 128k ___ fxx5 384k Flash page5 0x60000 128k ___ fxx6 512k Flash ----------------------- page6 0x80000 128k page7 0xa0000 128k ___ fxx7 256k Flash page8 0xc0000 128k page9 0xe0000 128k ___ fxx8 256k Flash */ num_pages = 10; /* max number of Flash pages for malloc */ fm3_info->probed = 0; bank->sectors = malloc(sizeof(struct flash_sector) * num_pages); bank->base = 0x00000000; bank->size = 32 * 1024; /* bytes */ bank->sectors[0].offset = 0; bank->sectors[0].size = 16 * 1024; bank->sectors[0].is_erased = -1; bank->sectors[0].is_protected = -1; bank->sectors[1].offset = 0x4000; bank->sectors[1].size = 16 * 1024; bank->sectors[1].is_erased = -1; bank->sectors[1].is_protected = -1; if ((fm3_info->variant == mb9bfxx1) || (fm3_info->variant == mb9afxx1)) { num_pages = 3; bank->size = 64 * 1024; /* bytes */ bank->num_sectors = num_pages; bank->sectors[2].offset = 0x8000; bank->sectors[2].size = 32 * 1024; bank->sectors[2].is_erased = -1; bank->sectors[2].is_protected = -1; } if ((fm3_info->variant == mb9bfxx2) || (fm3_info->variant == mb9bfxx4) || (fm3_info->variant == mb9bfxx5) || (fm3_info->variant == mb9bfxx6) || (fm3_info->variant == mb9bfxx7) || (fm3_info->variant == mb9bfxx8) || (fm3_info->variant == mb9afxx2) || (fm3_info->variant == mb9afxx4) || (fm3_info->variant == mb9afxx5) || (fm3_info->variant == mb9afxx6) || (fm3_info->variant == mb9afxx7) || (fm3_info->variant == mb9afxx8)) { num_pages = 3; bank->size = 128 * 1024; /* bytes */ bank->num_sectors = num_pages; bank->sectors[2].offset = 0x8000; bank->sectors[2].size = 96 * 1024; bank->sectors[2].is_erased = -1; bank->sectors[2].is_protected = -1; } if ((fm3_info->variant == mb9bfxx4) || (fm3_info->variant == mb9bfxx5) || (fm3_info->variant == mb9bfxx6) || (fm3_info->variant == mb9bfxx7) || (fm3_info->variant == mb9bfxx8) || (fm3_info->variant == mb9afxx4) || (fm3_info->variant == mb9afxx5) || (fm3_info->variant == mb9afxx6) || (fm3_info->variant == mb9afxx7) || (fm3_info->variant == mb9afxx8)) { num_pages = 4; bank->size = 256 * 1024; /* bytes */ bank->num_sectors = num_pages; bank->sectors[3].offset = 0x20000; bank->sectors[3].size = 128 * 1024; bank->sectors[3].is_erased = -1; bank->sectors[3].is_protected = -1; } if ((fm3_info->variant == mb9bfxx5) || (fm3_info->variant == mb9bfxx6) || (fm3_info->variant == mb9bfxx7) || (fm3_info->variant == mb9bfxx8) || (fm3_info->variant == mb9afxx5) || (fm3_info->variant == mb9afxx6) || (fm3_info->variant == mb9afxx7) || (fm3_info->variant == mb9afxx8)) { num_pages = 5; bank->size = 384 * 1024; /* bytes */ bank->num_sectors = num_pages; bank->sectors[4].offset = 0x40000; bank->sectors[4].size = 128 * 1024; bank->sectors[4].is_erased = -1; bank->sectors[4].is_protected = -1; } if ((fm3_info->variant == mb9bfxx6) || (fm3_info->variant == mb9bfxx7) || (fm3_info->variant == mb9bfxx8) || (fm3_info->variant == mb9afxx6) || (fm3_info->variant == mb9afxx7) || (fm3_info->variant == mb9afxx8)) { num_pages = 6; bank->size = 512 * 1024; /* bytes */ bank->num_sectors = num_pages; bank->sectors[5].offset = 0x60000; bank->sectors[5].size = 128 * 1024; bank->sectors[5].is_erased = -1; bank->sectors[5].is_protected = -1; } if ((fm3_info->variant == mb9bfxx7) || (fm3_info->variant == mb9bfxx8) || (fm3_info->variant == mb9afxx7) || (fm3_info->variant == mb9afxx8)) { num_pages = 8; bank->size = 768 * 1024; /* bytes */ bank->num_sectors = num_pages; bank->sectors[6].offset = 0x80000; bank->sectors[6].size = 128 * 1024; bank->sectors[6].is_erased = -1; bank->sectors[6].is_protected = -1; bank->sectors[7].offset = 0xa0000; bank->sectors[7].size = 128 * 1024; bank->sectors[7].is_erased = -1; bank->sectors[7].is_protected = -1; } if ((fm3_info->variant == mb9bfxx8) || (fm3_info->variant == mb9afxx8)) { num_pages = 10; bank->size = 1024 * 1024; /* bytes */ bank->num_sectors = num_pages; bank->sectors[8].offset = 0xc0000; bank->sectors[8].size = 128 * 1024; bank->sectors[8].is_erased = -1; bank->sectors[8].is_protected = -1; bank->sectors[9].offset = 0xe0000; bank->sectors[9].size = 128 * 1024; bank->sectors[9].is_erased = -1; bank->sectors[9].is_protected = -1; } fm3_info->probed = 1; return ERROR_OK; } static int fm3_auto_probe(struct flash_bank *bank) { struct fm3_flash_bank *fm3_info = bank->driver_priv; if (fm3_info->probed) return ERROR_OK; return fm3_probe(bank); } static int fm3_info(struct flash_bank *bank, char *buf, int buf_size) { snprintf(buf, buf_size, "Fujitsu fm3 Device does not support Chip-ID (Type unknown)"); return ERROR_OK; } /* Chip erase */ static int fm3_chip_erase(struct flash_bank *bank) { struct target *target = bank->target; struct fm3_flash_bank *fm3_info2 = bank->driver_priv; int retval = ERROR_OK; uint32_t u32DummyRead; uint32_t u32FlashType; uint32_t u32FlashSeqAddress1; uint32_t u32FlashSeqAddress2; u32FlashType = (uint32_t) fm3_info2->flashtype; if (u32FlashType == fm3_flash_type1) { LOG_INFO("*** Erasing mb9bfxxx type"); u32FlashSeqAddress1 = 0x00001550; u32FlashSeqAddress2 = 0x00000AA8; } else if (u32FlashType == fm3_flash_type2) { LOG_INFO("*** Erasing mb9afxxx type"); u32FlashSeqAddress1 = 0x00000AA8; u32FlashSeqAddress2 = 0x00000554; } else { LOG_ERROR("Flash/Device type unknown!"); return ERROR_FLASH_OPERATION_FAILED; } if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } LOG_INFO("Fujitsu MB9[AB]xxx: Chip Erase ... (may take several seconds)"); /* Implement Flash chip erase (mass erase) completely on host */ /* FASZR = 0x01, Enables CPU Programming Mode (16-bit Flash access) */ retval = target_write_u32(target, 0x40000000, 0x0001); if (retval != ERROR_OK) return retval; /* dummy read of FASZR */ retval = target_read_u32(target, 0x40000000, &u32DummyRead); if (retval != ERROR_OK) return retval; /* Flash unlock sequence */ retval = target_write_u16(target, u32FlashSeqAddress1, 0x00AA); if (retval != ERROR_OK) return retval; retval = target_write_u16(target, u32FlashSeqAddress2, 0x0055); if (retval != ERROR_OK) return retval; retval = target_write_u16(target, u32FlashSeqAddress1, 0x0080); if (retval != ERROR_OK) return retval; retval = target_write_u16(target, u32FlashSeqAddress1, 0x00AA); if (retval != ERROR_OK) return retval; retval = target_write_u16(target, u32FlashSeqAddress2, 0x0055); if (retval != ERROR_OK) return retval; /* Chip Erase command (0x0010) */ retval = target_write_u16(target, u32FlashSeqAddress1, 0x0010); if (retval != ERROR_OK) return retval; retval = fm3_busy_wait(target, u32FlashSeqAddress2, 20000); /* 20s timeout */ if (retval != ERROR_OK) return retval; /* FASZR = 0x02, Re-enables CPU Run Mode (32-bit Flash access) */ retval = target_write_u32(target, 0x40000000, 0x0002); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, 0x40000000, &u32DummyRead); /* dummy read of FASZR */ return retval; } COMMAND_HANDLER(fm3_handle_chip_erase_command) { int i; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; struct flash_bank *bank; int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); if (ERROR_OK != retval) return retval; if (fm3_chip_erase(bank) == ERROR_OK) { /* set all sectors as erased */ for (i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_erased = 1; command_print(CMD_CTX, "fm3 chip erase complete"); } else { command_print(CMD_CTX, "fm3 chip erase failed"); } return ERROR_OK; } static const struct command_registration fm3_exec_command_handlers[] = { { .name = "chip_erase", .usage = "", .handler = fm3_handle_chip_erase_command, .mode = COMMAND_EXEC, .help = "Erase entire Flash device.", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration fm3_command_handlers[] = { { .name = "fm3", .mode = COMMAND_ANY, .help = "fm3 Flash command group", .usage = "", .chain = fm3_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct flash_driver fm3_flash = { .name = "fm3", .commands = fm3_command_handlers, .flash_bank_command = fm3_flash_bank_command, .erase = fm3_erase, .write = fm3_write_block, .probe = fm3_probe, .auto_probe = fm3_auto_probe, .erase_check = default_flash_blank_check, .info = fm3_info, }; openocd-0.7.0/src/flash/nor/dsp5680xx_flash.c0000644000175000001440000002106212134336410015554 00000000000000/*************************************************************************** * Copyright (C) 2011 by Rodrigo L. Rosa * * rodrigorosa.LG@gmail.com * * * * Based on a file written by: * * Kevin McGuire * * Marcel Wijlaars * * Michael Ashton * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /** * @file dsp5680xx_flash.c * @author Rodrigo L. Rosa * @date Thu Jun 9 18:21:58 2011 * * @brief This file implements the basic functions to run flashing commands * from the TCL interface. * It allows the user to flash the Freescale 5680xx DSP. * * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "imp.h" #include #include #include #include static int dsp5680xx_build_sector_list(struct flash_bank *bank) { uint32_t offset = HFM_FLASH_BASE_ADDR; bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors); int i; for (i = 0; i < bank->num_sectors; ++i) { bank->sectors[i].offset = i * HFM_SECTOR_SIZE; bank->sectors[i].size = HFM_SECTOR_SIZE; offset += bank->sectors[i].size; bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = -1; } LOG_USER("%s not tested yet.", __func__); return ERROR_OK; } /* flash bank dsp5680xx 0 0 0 0 */ FLASH_BANK_COMMAND_HANDLER(dsp5680xx_flash_bank_command) { bank->base = HFM_FLASH_BASE_ADDR; bank->size = HFM_SIZE_BYTES; /* top 4k not accessible */ bank->num_sectors = HFM_SECTOR_COUNT; dsp5680xx_build_sector_list(bank); return ERROR_OK; } /** * A memory mapped register (PROT) holds information regarding sector protection. * Protection refers to undesired core access. * The value in this register is loaded from flash upon reset. * * @param bank * * @return */ static int dsp5680xx_flash_protect_check(struct flash_bank *bank) { int retval = ERROR_OK; uint16_t protected = 0; retval = dsp5680xx_f_protect_check(bank->target, &protected); if (retval != ERROR_OK) { for (int i = 0; i < HFM_SECTOR_COUNT; i++) bank->sectors[i].is_protected = -1; return ERROR_OK; } for (int i = 0; i < HFM_SECTOR_COUNT / 2; i++) { if (protected & 1) { bank->sectors[2 * i].is_protected = 1; bank->sectors[2 * i + 1].is_protected = 1; } else { bank->sectors[2 * i].is_protected = 0; bank->sectors[2 * i + 1].is_protected = 0; } protected = (protected >> 1); } return retval; } /** * Protection funcionality is not implemented. * The current implementation applies/removes security on the chip. * The chip is effectively secured/unsecured after the first reset * following the execution of this function. * * @param bank * @param set Apply or remove security on the chip. * @param first This parameter is ignored. * @param last This parameter is ignored. * * @return */ static int dsp5680xx_flash_protect(struct flash_bank *bank, int set, int first, int last) { /** * This applies security to flash module after next reset, it does * not actually apply protection (protection refers to undesired access from the core) */ int retval; if (set) retval = dsp5680xx_f_lock(bank->target); else { retval = dsp5680xx_f_unlock(bank->target); if (retval == ERROR_OK) { /* mark all as erased */ for (int i = 0; i <= (HFM_SECTOR_COUNT - 1); i++) /* FM does not recognize it as erased if erased via JTAG. */ bank->sectors[i].is_erased = 1; } } return retval; } /** * The dsp5680xx use word addressing. The "/2" that appear in the following code * are a workaround for the fact that OpenOCD uses byte addressing. * * @param bank * @param buffer Data to write to flash. * @param offset * @param count In bytes (2 bytes per address). * * @return */ static int dsp5680xx_flash_write(struct flash_bank *bank, uint8_t * buffer, uint32_t offset, uint32_t count) { int retval; if ((offset + count / 2) > bank->size) { LOG_ERROR("%s: Flash bank cannot fit data.", __func__); return ERROR_FAIL; } if (offset % 2) { /** * Writing to odd addresses not supported. * This chip uses word addressing, Openocd only supports byte addressing. * The workaround results in disabling writing to odd byte addresses */ LOG_ERROR("%s: Writing to odd addresses not supported for this target", __func__); return ERROR_FAIL; } retval = dsp5680xx_f_wr(bank->target, buffer, bank->base + offset / 2, count, 0); uint32_t addr_word; for (addr_word = bank->base + offset / 2; addr_word < count / 2; addr_word += (HFM_SECTOR_SIZE / 2)) { if (retval == ERROR_OK) bank->sectors[addr_word / (HFM_SECTOR_SIZE / 2)].is_erased = 0; else bank->sectors[addr_word / (HFM_SECTOR_SIZE / 2)].is_erased = -1; } return retval; } static int dsp5680xx_probe(struct flash_bank *bank) { LOG_DEBUG("%s not implemented", __func__); return ERROR_OK; } static int dsp5680xx_flash_info(struct flash_bank *bank, char *buf, int buf_size) { snprintf(buf, buf_size, "\ndsp5680xx flash driver info:\n - See comments in code."); return ERROR_OK; } /** * The flash module (FM) on the dsp5680xx supports both individual sector * and mass erase of the flash memory. * If this function is called with @first == @last == 0 or if @first is the * first sector (#0) and @last is the last sector then the mass erase command * is executed (much faster than erasing each sector individually). * * @param bank * @param first * @param last * * @return */ static int dsp5680xx_flash_erase(struct flash_bank *bank, int first, int last) { int retval; retval = dsp5680xx_f_erase(bank->target, (uint32_t) first, (uint32_t) last); if ((!(first | last)) || ((first == 0) && (last == (HFM_SECTOR_COUNT - 1)))) last = HFM_SECTOR_COUNT - 1; if (retval == ERROR_OK) for (int i = first; i <= last; i++) bank->sectors[i].is_erased = 1; else /** * If an error occurred unknown status *is set even though some sector could have been correctly erased. */ for (int i = first; i <= last; i++) bank->sectors[i].is_erased = -1; return retval; } /** * The flash module (FM) on the dsp5680xx support a blank check function. * This function executes the FM's blank check functionality on each and every sector. * * @param bank * * @return */ static int dsp5680xx_flash_erase_check(struct flash_bank *bank) { int retval = ERROR_OK; uint8_t erased = 0; uint32_t i; for (i = 0; i < HFM_SECTOR_COUNT; i++) { if (bank->sectors[i].is_erased == -1) { retval = dsp5680xx_f_erase_check(bank->target, &erased, i); if (retval != ERROR_OK) { bank->sectors[i].is_erased = -1; } else { if (erased) bank->sectors[i].is_erased = 1; else bank->sectors[i].is_erased = 0; } } } return retval; } struct flash_driver dsp5680xx_flash = { .name = "dsp5680xx_flash", .flash_bank_command = dsp5680xx_flash_bank_command, .erase = dsp5680xx_flash_erase, .protect = dsp5680xx_flash_protect, .write = dsp5680xx_flash_write, /* .read = default_flash_read, */ .probe = dsp5680xx_probe, .auto_probe = dsp5680xx_probe, .erase_check = dsp5680xx_flash_erase_check, .protect_check = dsp5680xx_flash_protect_check, .info = dsp5680xx_flash_info }; openocd-0.7.0/src/flash/nor/Makefile.am0000644000175000001440000000124412134336410014576 00000000000000include $(top_srcdir)/common.mk noinst_LTLIBRARIES = libocdflashnor.la libocdflashnor_la_SOURCES = \ core.c \ tcl.c \ $(NOR_DRIVERS) \ drivers.c NOR_DRIVERS = \ aduc702x.c \ at91sam4.c \ at91sam3.c \ at91sam7.c \ avrf.c \ cfi.c \ efm32.c \ em357.c \ faux.c \ lpc2000.c \ lpc288x.c \ lpc2900.c \ lpcspifi.c \ non_cfi.c \ ocl.c \ pic32mx.c \ spi.c \ stmsmi.c \ stellaris.c \ stm32f1x.c \ stm32f2x.c \ stm32lx.c \ str7x.c \ str9x.c \ str9xpec.c \ tms470.c \ virtual.c \ fm3.c \ dsp5680xx_flash.c \ kinetis.c noinst_HEADERS = \ core.h \ cfi.h \ driver.h \ imp.h \ non_cfi.h \ ocl.h \ spi.h MAINTAINERCLEANFILES = $(srcdir)/Makefile.in openocd-0.7.0/src/flash/Makefile.am0000644000175000001440000000061512134336410014001 00000000000000include $(top_srcdir)/common.mk SUBDIRS = \ nor \ nand METASOURCES = AUTO noinst_LTLIBRARIES = libflash.la libflash_la_SOURCES = \ common.c \ mflash.c libflash_la_LIBADD = \ $(top_builddir)/src/flash/nor/libocdflashnor.la \ $(top_builddir)/src/flash/nand/libocdflashnand.la noinst_HEADERS = \ common.h \ mflash.h EXTRA_DIST = startup.tcl MAINTAINERCLEANFILES = $(srcdir)/Makefile.in openocd-0.7.0/src/flash/mflash.h0000644000175000001440000002407712134336410013400 00000000000000/*************************************************************************** * Copyright (C) 2007-2008 by unsik Kim * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef _MFLASH_H #define _MFLASH_H struct command_context; typedef unsigned long mg_io_uint32; typedef unsigned short mg_io_uint16; typedef unsigned char mg_io_uint8; struct mflash_gpio_num { char port[2]; signed short num; }; struct mflash_gpio_drv { const char *name; int (*set_gpio_to_output)(struct mflash_gpio_num gpio); int (*set_gpio_output_val)(struct mflash_gpio_num gpio, uint8_t val); }; typedef struct _mg_io_type_drv_info { mg_io_uint16 general_configuration; /* 00 */ mg_io_uint16 number_of_cylinders; /* 01 */ mg_io_uint16 reserved1; /* 02 */ mg_io_uint16 number_of_heads; /* 03 */ mg_io_uint16 unformatted_bytes_per_track; /* 04 */ mg_io_uint16 unformatted_bytes_per_sector; /* 05 */ mg_io_uint16 sectors_per_track; /* 06 */ mg_io_uint16 vendor_unique1[3]; /* 07/08/09 */ mg_io_uint8 serial_number[20]; /* 10~19 */ mg_io_uint16 buffer_type; /* 20 */ mg_io_uint16 buffer_sector_size; /* 21 */ mg_io_uint16 number_of_ecc_bytes; /* 22 */ mg_io_uint8 firmware_revision[8]; /* 23~26 */ mg_io_uint8 model_number[40]; /* 27 */ mg_io_uint8 maximum_block_transfer; /* 47 low byte */ mg_io_uint8 vendor_unique2; /* 47 high byte */ mg_io_uint16 dword_io; /* 48 */ mg_io_uint16 capabilities; /* 49 */ mg_io_uint16 reserved2; /* 50 */ mg_io_uint8 vendor_unique3; /* 51 low byte */ mg_io_uint8 pio_cycle_timing_mode; /* 51 high byte */ mg_io_uint8 vendor_unique4; /* 52 low byte */ mg_io_uint8 dma_cycle_timing_mode; /* 52 high byte */ mg_io_uint16 translation_fields_valid; /* 53 (low bit) */ mg_io_uint16 number_of_current_cylinders; /* 54 */ mg_io_uint16 number_of_current_heads; /* 55 */ mg_io_uint16 current_sectors_per_track; /* 56 */ mg_io_uint16 current_sector_capacity_lo; /* 57 & 58 */ mg_io_uint16 current_sector_capacity_hi; /* 57 & 58 */ mg_io_uint8 multi_sector_count; /* 59 low */ mg_io_uint8 multi_sector_setting_valid; /* 59 high (low bit) */ mg_io_uint16 total_user_addressable_sectors_lo; /* 60 & 61 */ mg_io_uint16 total_user_addressable_sectors_hi; /* 60 & 61 */ mg_io_uint8 single_dma_modes_supported; /* 62 low byte */ mg_io_uint8 single_dma_transfer_active; /* 62 high byte */ mg_io_uint8 multi_dma_modes_supported; /* 63 low byte */ mg_io_uint8 multi_dma_transfer_active; /* 63 high byte */ mg_io_uint16 adv_pio_mode; mg_io_uint16 min_dma_cyc; mg_io_uint16 recommend_dma_cyc; mg_io_uint16 min_pio_cyc_no_iordy; mg_io_uint16 min_pio_cyc_with_iordy; mg_io_uint8 reserved3[22]; mg_io_uint16 major_ver_num; mg_io_uint16 minor_ver_num; mg_io_uint16 feature_cmd_set_suprt0; mg_io_uint16 feature_cmd_set_suprt1; mg_io_uint16 feature_cmd_set_suprt2; mg_io_uint16 feature_cmd_set_en0; mg_io_uint16 feature_cmd_set_en1; mg_io_uint16 feature_cmd_set_en2; mg_io_uint16 reserved4; mg_io_uint16 req_time_for_security_er_done; mg_io_uint16 req_time_for_enhan_security_er_done; mg_io_uint16 adv_pwr_mgm_lvl_val; mg_io_uint16 reserved5; mg_io_uint16 re_of_hw_rst; mg_io_uint8 reserved6[68]; mg_io_uint16 security_stas; mg_io_uint8 vendor_uniq_bytes[62]; mg_io_uint16 cfa_pwr_mode; mg_io_uint8 reserved7[186]; mg_io_uint16 scts_per_secure_data_unit; mg_io_uint16 integrity_word; } mg_io_type_drv_info; typedef struct _mg_pll_t { unsigned int lock_cyc; unsigned short feedback_div; /* 9bit divider */ unsigned char input_div; /* 5bit divider */ unsigned char output_div; /* 2bit divider */ } mg_pll_t; struct mg_drv_info { mg_io_type_drv_info drv_id; uint32_t tot_sects; }; struct mflash_bank { uint32_t base; struct mflash_gpio_num rst_pin; struct mflash_gpio_drv *gpio_drv; struct target *target; struct mg_drv_info *drv_info; }; int mflash_register_commands(struct command_context *cmd_ctx); #define MG_MFLASH_SECTOR_SIZE (0x200) /* 512Bytes = 2^9 */ #define MG_MFLASH_SECTOR_SIZE_MASK (0x200-1) #define MG_MFLASH_SECTOR_SIZE_SHIFT (9) #define MG_BUFFER_OFFSET 0x8000 #define MG_REG_OFFSET 0xC000 #define MG_REG_FEATURE 0x2 /* write case */ #define MG_REG_ERROR 0x2 /* read case */ #define MG_REG_SECT_CNT 0x4 #define MG_REG_SECT_NUM 0x6 #define MG_REG_CYL_LOW 0x8 #define MG_REG_CYL_HIGH 0xA #define MG_REG_DRV_HEAD 0xC #define MG_REG_COMMAND 0xE /* write case */ #define MG_REG_STATUS 0xE /* read case */ #define MG_REG_DRV_CTRL 0x10 #define MG_REG_BURST_CTRL 0x12 #define MG_OEM_DISK_WAIT_TIME_LONG 15000 /* msec */ #define MG_OEM_DISK_WAIT_TIME_NORMAL 3000 /* msec */ #define MG_OEM_DISK_WAIT_TIME_SHORT 1000 /* msec */ #define MG_PLL_CLK_OUT 66000000.0 /* 66Mhz */ #define MG_PLL_MAX_FEEDBACKDIV_VAL 512 #define MG_PLL_MAX_INPUTDIV_VAL 32 #define MG_PLL_MAX_OUTPUTDIV_VAL 4 #define MG_PLL_STD_INPUTCLK 12000000.0 /* 12Mhz */ #define MG_PLL_STD_LOCKCYCLE 10000 #define MG_UNLOCK_OTP_AREA 0xFF #define MG_FILEIO_CHUNK 1048576 #define ERROR_MG_IO (-1600) #define ERROR_MG_TIMEOUT (-1601) #define ERROR_MG_INVALID_PLL (-1603) #define ERROR_MG_INTERFACE (-1604) #define ERROR_MG_INVALID_OSC (-1605) #define ERROR_MG_UNSUPPORTED_SOC (-1606) typedef enum _mg_io_type_wait { mg_io_wait_bsy = 1, mg_io_wait_not_bsy = 2, mg_io_wait_rdy = 3, mg_io_wait_drq = 4, /* wait for data request */ mg_io_wait_drq_noerr = 5, /* wait for DRQ but ignore the error status bit */ mg_io_wait_rdy_noerr = 6 /* wait for ready, but ignore error status bit */ } mg_io_type_wait; /*= "Status Register" bit masks. */ typedef enum _mg_io_type_rbit_status { mg_io_rbit_status_error = 0x01, /* error bit in status register */ mg_io_rbit_status_corrected_error = 0x04, /* corrected error in status register */ mg_io_rbit_status_data_req = 0x08, /* data request bit in status register */ mg_io_rbit_status_seek_done = 0x10, /* DSC - Drive Seek Complete */ mg_io_rbit_status_write_fault = 0x20, /* DWF - Drive Write Fault */ mg_io_rbit_status_ready = 0x40, mg_io_rbit_status_busy = 0x80 } mg_io_type_rbit_status; /*= "Error Register" bit masks. */ typedef enum _mg_io_type_rbit_error { mg_io_rbit_err_general = 0x01, mg_io_rbit_err_aborted = 0x04, mg_io_rbit_err_bad_sect_num = 0x10, mg_io_rbit_err_uncorrectable = 0x40, mg_io_rbit_err_bad_block = 0x80 } mg_io_type_rbit_error; /* = "Device Control Register" bit. */ typedef enum _mg_io_type_rbit_devc { mg_io_rbit_devc_intr = 0x02, /* interrupt enable bit (1:disable, 0:enable) */ mg_io_rbit_devc_srst = 0x04 /* softwrae reset bit (1:assert, 0:de-assert) */ } mg_io_type_rbit_devc; /* "Drive Select/Head Register" values. */ typedef enum _mg_io_type_rval_dev { mg_io_rval_dev_must_be_on = 0x80, /* These 1 bits are always on */ mg_io_rval_dev_drv_master = (0x00 | mg_io_rval_dev_must_be_on), /* Master */ mg_io_rval_dev_drv_slave0 = (0x10 | mg_io_rval_dev_must_be_on), /* Slave0 */ mg_io_rval_dev_drv_slave1 = (0x20 | mg_io_rval_dev_must_be_on), /* Slave1 */ mg_io_rval_dev_drv_slave2 = (0x30 | mg_io_rval_dev_must_be_on), /* Slave2 */ mg_io_rval_dev_lba_mode = (0x40 | mg_io_rval_dev_must_be_on) } mg_io_type_rval_dev; typedef enum _mg_io_type_cmd { mg_io_cmd_read = 0x20, mg_io_cmd_write = 0x30, mg_io_cmd_setmul = 0xC6, mg_io_cmd_readmul = 0xC4, mg_io_cmd_writemul = 0xC5, mg_io_cmd_idle = 0x97, /* 0xE3 */ mg_io_cmd_idle_immediate = 0x95, /* 0xE1 */ mg_io_cmd_setsleep = 0x99, /* 0xE6 */ mg_io_cmd_stdby = 0x96, /* 0xE2 */ mg_io_cmd_stdby_immediate = 0x94, /* 0xE0 */ mg_io_cmd_identify = 0xEC, mg_io_cmd_set_feature = 0xEF, mg_io_cmd_confirm_write = 0x3C, mg_io_cmd_confirm_read = 0x40, mg_io_cmd_wakeup = 0xC3 } mg_io_type_cmd; typedef enum _mg_feature_id { mg_feature_id_transmode = 0x3 } mg_feature_id; typedef enum _mg_feature_val { mg_feature_val_trans_default = 0x0, mg_feature_val_trans_vcmd = 0x3, mg_feature_val_trand_vcmds = 0x2 } mg_feature_val; typedef enum _mg_vcmd { mg_vcmd_update_xipinfo = 0xFA, /* FWPATCH commmand through IOM I/O */ mg_vcmd_verify_fwpatch = 0xFB, /* FWPATCH commmand through IOM I/O */ mg_vcmd_update_stgdrvinfo = 0xFC, /* IOM identificatin info program command */ mg_vcmd_prep_fwpatch = 0xFD, /* FWPATCH commmand through IOM I/O */ mg_vcmd_exe_fwpatch = 0xFE, /* FWPATCH commmand through IOM I/O */ mg_vcmd_wr_pll = 0x8B, mg_vcmd_purge_nand = 0x8C, /* Only for Seagle */ mg_vcmd_lock_otp = 0x8D, mg_vcmd_rd_otp = 0x8E, mg_vcmd_wr_otp = 0x8F } mg_vcmd; typedef enum _mg_opmode { mg_op_mode_xip = 1, /* TRUE XIP */ mg_op_mode_snd = 2, /* BOOT + Storage */ mg_op_mode_stg = 0 /* Only Storage */ } mg_opmode; #endif openocd-0.7.0/src/flash/mflash.c0000644000175000001440000011235312134336410013366 00000000000000/*************************************************************************** * Copyright (C) 2007-2008 by unsik Kim * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "mflash.h" #include #include #include #include static int s3c2440_set_gpio_to_output(struct mflash_gpio_num gpio); static int s3c2440_set_gpio_output_val(struct mflash_gpio_num gpio, uint8_t val); static int pxa270_set_gpio_to_output(struct mflash_gpio_num gpio); static int pxa270_set_gpio_output_val(struct mflash_gpio_num gpio, uint8_t val); static struct mflash_bank *mflash_bank; static struct mflash_gpio_drv pxa270_gpio = { .name = "pxa270", .set_gpio_to_output = pxa270_set_gpio_to_output, .set_gpio_output_val = pxa270_set_gpio_output_val }; static struct mflash_gpio_drv s3c2440_gpio = { .name = "s3c2440", .set_gpio_to_output = s3c2440_set_gpio_to_output, .set_gpio_output_val = s3c2440_set_gpio_output_val }; static struct mflash_gpio_drv *mflash_gpio[] = { &pxa270_gpio, &s3c2440_gpio, NULL }; #define PXA270_GAFR0_L 0x40E00054 #define PXA270_GAFR3_U 0x40E00070 #define PXA270_GAFR3_U_RESERVED_BITS 0xfffc0000u #define PXA270_GPDR0 0x40E0000C #define PXA270_GPDR3 0x40E0010C #define PXA270_GPDR3_RESERVED_BITS 0xfe000000u #define PXA270_GPSR0 0x40E00018 #define PXA270_GPCR0 0x40E00024 static int pxa270_set_gpio_to_output(struct mflash_gpio_num gpio) { uint32_t addr, value, mask; struct target *target = mflash_bank->target; int ret; /* remove alternate function. */ mask = 0x3u << (gpio.num & 0xF)*2; addr = PXA270_GAFR0_L + (gpio.num >> 4) * 4; ret = target_read_u32(target, addr, &value); if (ret != ERROR_OK) return ret; value &= ~mask; if (addr == PXA270_GAFR3_U) value &= ~PXA270_GAFR3_U_RESERVED_BITS; ret = target_write_u32(target, addr, value); if (ret != ERROR_OK) return ret; /* set direction to output */ mask = 0x1u << (gpio.num & 0x1F); addr = PXA270_GPDR0 + (gpio.num >> 5) * 4; ret = target_read_u32(target, addr, &value); if (ret != ERROR_OK) return ret; value |= mask; if (addr == PXA270_GPDR3) value &= ~PXA270_GPDR3_RESERVED_BITS; ret = target_write_u32(target, addr, value); return ret; } static int pxa270_set_gpio_output_val(struct mflash_gpio_num gpio, uint8_t val) { uint32_t addr, value, mask; struct target *target = mflash_bank->target; int ret; mask = 0x1u << (gpio.num & 0x1F); if (val) addr = PXA270_GPSR0 + (gpio.num >> 5) * 4; else addr = PXA270_GPCR0 + (gpio.num >> 5) * 4; ret = target_read_u32(target, addr, &value); if (ret != ERROR_OK) return ret; value |= mask; ret = target_write_u32(target, addr, value); return ret; } #define S3C2440_GPACON 0x56000000 #define S3C2440_GPADAT 0x56000004 #define S3C2440_GPJCON 0x560000d0 #define S3C2440_GPJDAT 0x560000d4 static int s3c2440_set_gpio_to_output(struct mflash_gpio_num gpio) { uint32_t data, mask, gpio_con; struct target *target = mflash_bank->target; int ret; if (gpio.port[0] >= 'a' && gpio.port[0] <= 'h') gpio_con = S3C2440_GPACON + (gpio.port[0] - 'a') * 0x10; else if (gpio.port[0] == 'j') gpio_con = S3C2440_GPJCON; else { LOG_ERROR("mflash: invalid port %d%s", gpio.num, gpio.port); return ERROR_COMMAND_SYNTAX_ERROR; } ret = target_read_u32(target, gpio_con, &data); if (ret == ERROR_OK) { if (gpio.port[0] == 'a') { mask = 1 << gpio.num; data &= ~mask; } else { mask = 3 << gpio.num * 2; data &= ~mask; data |= (1 << gpio.num * 2); } ret = target_write_u32(target, gpio_con, data); } return ret; } static int s3c2440_set_gpio_output_val(struct mflash_gpio_num gpio, uint8_t val) { uint32_t data, mask, gpio_dat; struct target *target = mflash_bank->target; int ret; if (gpio.port[0] >= 'a' && gpio.port[0] <= 'h') gpio_dat = S3C2440_GPADAT + (gpio.port[0] - 'a') * 0x10; else if (gpio.port[0] == 'j') gpio_dat = S3C2440_GPJDAT; else { LOG_ERROR("mflash: invalid port %d%s", gpio.num, gpio.port); return ERROR_COMMAND_SYNTAX_ERROR; } ret = target_read_u32(target, gpio_dat, &data); if (ret == ERROR_OK) { mask = 1 << gpio.num; if (val) data |= mask; else data &= ~mask; ret = target_write_u32(target, gpio_dat, data); } return ret; } static int mg_hdrst(uint8_t level) { return mflash_bank->gpio_drv->set_gpio_output_val(mflash_bank->rst_pin, level); } static int mg_init_gpio(void) { int ret; struct mflash_gpio_drv *gpio_drv = mflash_bank->gpio_drv; ret = gpio_drv->set_gpio_to_output(mflash_bank->rst_pin); if (ret != ERROR_OK) return ret; ret = gpio_drv->set_gpio_output_val(mflash_bank->rst_pin, 1); return ret; } static int mg_dsk_wait(mg_io_type_wait wait_local, uint32_t time_var) { uint8_t status, error; struct target *target = mflash_bank->target; uint32_t mg_task_reg = mflash_bank->base + MG_REG_OFFSET; int ret; long long t = 0; struct duration bench; duration_start(&bench); while (time_var) { ret = target_read_u8(target, mg_task_reg + MG_REG_STATUS, &status); if (ret != ERROR_OK) return ret; if (status & mg_io_rbit_status_busy) { if (wait_local == mg_io_wait_bsy) return ERROR_OK; } else { switch (wait_local) { case mg_io_wait_not_bsy: return ERROR_OK; case mg_io_wait_rdy_noerr: if (status & mg_io_rbit_status_ready) return ERROR_OK; break; case mg_io_wait_drq_noerr: if (status & mg_io_rbit_status_data_req) return ERROR_OK; break; default: break; } /* Now we check the error condition! */ if (status & mg_io_rbit_status_error) { ret = target_read_u8(target, mg_task_reg + MG_REG_ERROR, &error); if (ret != ERROR_OK) return ret; LOG_ERROR("mflash: io error 0x%02x", error); return ERROR_MG_IO; } switch (wait_local) { case mg_io_wait_rdy: if (status & mg_io_rbit_status_ready) return ERROR_OK; case mg_io_wait_drq: if (status & mg_io_rbit_status_data_req) return ERROR_OK; default: break; } } ret = duration_measure(&bench); if (ERROR_OK == ret) t = duration_elapsed(&bench) * 1000.0; else LOG_ERROR("mflash: duration measurement failed: %d", ret); if (t > time_var) break; } LOG_ERROR("mflash: timeout occured"); return ERROR_MG_TIMEOUT; } static int mg_dsk_srst(uint8_t on) { struct target *target = mflash_bank->target; uint32_t mg_task_reg = mflash_bank->base + MG_REG_OFFSET; uint8_t value; int ret; ret = target_read_u8(target, mg_task_reg + MG_REG_DRV_CTRL, &value); if (ret != ERROR_OK) return ret; if (on) value |= (mg_io_rbit_devc_srst); else value &= ~mg_io_rbit_devc_srst; ret = target_write_u8(target, mg_task_reg + MG_REG_DRV_CTRL, value); return ret; } static int mg_dsk_io_cmd(uint32_t sect_num, uint32_t cnt, uint8_t cmd) { struct target *target = mflash_bank->target; uint32_t mg_task_reg = mflash_bank->base + MG_REG_OFFSET; uint8_t value; int ret; ret = mg_dsk_wait(mg_io_wait_rdy_noerr, MG_OEM_DISK_WAIT_TIME_NORMAL); if (ret != ERROR_OK) return ret; value = mg_io_rval_dev_drv_master | mg_io_rval_dev_lba_mode | ((sect_num >> 24) & 0xf); ret = target_write_u8(target, mg_task_reg + MG_REG_DRV_HEAD, value); ret |= target_write_u8(target, mg_task_reg + MG_REG_SECT_CNT, (uint8_t)cnt); ret |= target_write_u8(target, mg_task_reg + MG_REG_SECT_NUM, (uint8_t)sect_num); ret |= target_write_u8(target, mg_task_reg + MG_REG_CYL_LOW, (uint8_t)(sect_num >> 8)); ret |= target_write_u8(target, mg_task_reg + MG_REG_CYL_HIGH, (uint8_t)(sect_num >> 16)); if (ret != ERROR_OK) return ret; return target_write_u8(target, mg_task_reg + MG_REG_COMMAND, cmd); } static int mg_dsk_drv_info(void) { struct target *target = mflash_bank->target; uint32_t mg_buff = mflash_bank->base + MG_BUFFER_OFFSET; int ret; ret = mg_dsk_io_cmd(0, 1, mg_io_cmd_identify); if (ret != ERROR_OK) return ret; ret = mg_dsk_wait(mg_io_wait_drq, MG_OEM_DISK_WAIT_TIME_NORMAL); if (ret != ERROR_OK) return ret; LOG_INFO("mflash: read drive info"); if (!mflash_bank->drv_info) mflash_bank->drv_info = malloc(sizeof(struct mg_drv_info)); ret = target_read_memory(target, mg_buff, 2, sizeof(mg_io_type_drv_info) >> 1, (uint8_t *)&mflash_bank->drv_info->drv_id); if (ret != ERROR_OK) return ret; mflash_bank->drv_info->tot_sects = (uint32_t)(mflash_bank->drv_info->drv_id.total_user_addressable_sectors_hi << 16) + mflash_bank->drv_info->drv_id.total_user_addressable_sectors_lo; return target_write_u8(target, mflash_bank->base + MG_REG_OFFSET + MG_REG_COMMAND, mg_io_cmd_confirm_read); } static int mg_mflash_rst(void) { int ret; ret = mg_init_gpio(); if (ret != ERROR_OK) return ret; ret = mg_hdrst(0); if (ret != ERROR_OK) return ret; ret = mg_dsk_wait(mg_io_wait_bsy, MG_OEM_DISK_WAIT_TIME_LONG); if (ret != ERROR_OK) return ret; ret = mg_hdrst(1); if (ret != ERROR_OK) return ret; ret = mg_dsk_wait(mg_io_wait_not_bsy, MG_OEM_DISK_WAIT_TIME_LONG); if (ret != ERROR_OK) return ret; ret = mg_dsk_srst(1); if (ret != ERROR_OK) return ret; ret = mg_dsk_wait(mg_io_wait_bsy, MG_OEM_DISK_WAIT_TIME_LONG); if (ret != ERROR_OK) return ret; ret = mg_dsk_srst(0); if (ret != ERROR_OK) return ret; ret = mg_dsk_wait(mg_io_wait_not_bsy, MG_OEM_DISK_WAIT_TIME_LONG); if (ret != ERROR_OK) return ret; LOG_INFO("mflash: reset ok"); return ERROR_OK; } static int mg_mflash_probe(void) { int ret = mg_mflash_rst(); if (ret != ERROR_OK) return ret; return mg_dsk_drv_info(); } COMMAND_HANDLER(mg_probe_cmd) { int ret; ret = mg_mflash_probe(); if (ret == ERROR_OK) { command_print(CMD_CTX, "mflash (total %" PRIu32 " sectors) found at 0x%8.8" PRIx32 "", mflash_bank->drv_info->tot_sects, mflash_bank->base); } return ret; } static int mg_mflash_do_read_sects(void *buff, uint32_t sect_num, uint32_t sect_cnt) { uint32_t i, address; int ret; struct target *target = mflash_bank->target; uint8_t *buff_ptr = buff; ret = mg_dsk_io_cmd(sect_num, sect_cnt, mg_io_cmd_read); if (ret != ERROR_OK) return ret; address = mflash_bank->base + MG_BUFFER_OFFSET; struct duration bench; duration_start(&bench); for (i = 0; i < sect_cnt; i++) { ret = mg_dsk_wait(mg_io_wait_drq, MG_OEM_DISK_WAIT_TIME_NORMAL); if (ret != ERROR_OK) return ret; ret = target_read_memory(target, address, 2, MG_MFLASH_SECTOR_SIZE / 2, buff_ptr); if (ret != ERROR_OK) return ret; buff_ptr += MG_MFLASH_SECTOR_SIZE; ret = target_write_u8(target, mflash_bank->base + MG_REG_OFFSET + MG_REG_COMMAND, mg_io_cmd_confirm_read); if (ret != ERROR_OK) return ret; LOG_DEBUG("mflash: %" PRIu32 " (0x%8.8" PRIx32 ") sector read", sect_num + i, (sect_num + i) * MG_MFLASH_SECTOR_SIZE); ret = duration_measure(&bench); if ((ERROR_OK == ret) && (duration_elapsed(&bench) > 3)) { LOG_INFO("mflash: read %" PRIu32 "'th sectors", sect_num + i); duration_start(&bench); } } return mg_dsk_wait(mg_io_wait_rdy, MG_OEM_DISK_WAIT_TIME_NORMAL); } static int mg_mflash_read_sects(void *buff, uint32_t sect_num, uint32_t sect_cnt) { uint32_t quotient, residue, i; uint8_t *buff_ptr = buff; int ret = ERROR_OK; quotient = sect_cnt >> 8; residue = sect_cnt % 256; for (i = 0; i < quotient; i++) { LOG_DEBUG("mflash: sect num : %" PRIu32 " buff : %p", sect_num, buff_ptr); ret = mg_mflash_do_read_sects(buff_ptr, sect_num, 256); if (ret != ERROR_OK) return ret; sect_num += 256; buff_ptr += 256 * MG_MFLASH_SECTOR_SIZE; } if (residue) { LOG_DEBUG("mflash: sect num : %" PRIx32 " buff : %p", sect_num, buff_ptr); return mg_mflash_do_read_sects(buff_ptr, sect_num, residue); } return ret; } static int mg_mflash_do_write_sects(void *buff, uint32_t sect_num, uint32_t sect_cnt, uint8_t cmd) { uint32_t i, address; int ret; struct target *target = mflash_bank->target; uint8_t *buff_ptr = buff; ret = mg_dsk_io_cmd(sect_num, sect_cnt, cmd); if (ret != ERROR_OK) return ret; address = mflash_bank->base + MG_BUFFER_OFFSET; struct duration bench; duration_start(&bench); for (i = 0; i < sect_cnt; i++) { ret = mg_dsk_wait(mg_io_wait_drq, MG_OEM_DISK_WAIT_TIME_NORMAL); if (ret != ERROR_OK) return ret; ret = target_write_memory(target, address, 2, MG_MFLASH_SECTOR_SIZE / 2, buff_ptr); if (ret != ERROR_OK) return ret; buff_ptr += MG_MFLASH_SECTOR_SIZE; ret = target_write_u8(target, mflash_bank->base + MG_REG_OFFSET + MG_REG_COMMAND, mg_io_cmd_confirm_write); if (ret != ERROR_OK) return ret; LOG_DEBUG("mflash: %" PRIu32 " (0x%8.8" PRIx32 ") sector write", sect_num + i, (sect_num + i) * MG_MFLASH_SECTOR_SIZE); ret = duration_measure(&bench); if ((ERROR_OK == ret) && (duration_elapsed(&bench) > 3)) { LOG_INFO("mflash: wrote %" PRIu32 "'th sectors", sect_num + i); duration_start(&bench); } } if (cmd == mg_io_cmd_write) ret = mg_dsk_wait(mg_io_wait_rdy, MG_OEM_DISK_WAIT_TIME_NORMAL); else ret = mg_dsk_wait(mg_io_wait_rdy, MG_OEM_DISK_WAIT_TIME_LONG); return ret; } static int mg_mflash_write_sects(void *buff, uint32_t sect_num, uint32_t sect_cnt) { uint32_t quotient, residue, i; uint8_t *buff_ptr = buff; int ret = ERROR_OK; quotient = sect_cnt >> 8; residue = sect_cnt % 256; for (i = 0; i < quotient; i++) { LOG_DEBUG("mflash: sect num : %" PRIu32 "buff : %p", sect_num, buff_ptr); ret = mg_mflash_do_write_sects(buff_ptr, sect_num, 256, mg_io_cmd_write); if (ret != ERROR_OK) return ret; sect_num += 256; buff_ptr += 256 * MG_MFLASH_SECTOR_SIZE; } if (residue) { LOG_DEBUG("mflash: sect num : %" PRIu32 " buff : %p", sect_num, buff_ptr); return mg_mflash_do_write_sects(buff_ptr, sect_num, residue, mg_io_cmd_write); } return ret; } static int mg_mflash_read(uint32_t addr, uint8_t *buff, uint32_t len) { uint8_t *buff_ptr = buff; uint8_t sect_buff[MG_MFLASH_SECTOR_SIZE]; uint32_t cur_addr, next_sec_addr, end_addr, cnt, sect_num; int ret = ERROR_OK; cnt = 0; cur_addr = addr; end_addr = addr + len; if (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK) { next_sec_addr = (cur_addr + MG_MFLASH_SECTOR_SIZE) & ~MG_MFLASH_SECTOR_SIZE_MASK; sect_num = cur_addr >> MG_MFLASH_SECTOR_SIZE_SHIFT; ret = mg_mflash_read_sects(sect_buff, sect_num, 1); if (ret != ERROR_OK) return ret; if (end_addr < next_sec_addr) { memcpy(buff_ptr, sect_buff + (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK), end_addr - cur_addr); LOG_DEBUG( "mflash: copies %" PRIu32 " byte from sector offset 0x%8.8" PRIx32 "", end_addr - cur_addr, cur_addr); cur_addr = end_addr; } else { memcpy(buff_ptr, sect_buff + (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK), next_sec_addr - cur_addr); LOG_DEBUG( "mflash: copies %" PRIu32 " byte from sector offset 0x%8.8" PRIx32 "", next_sec_addr - cur_addr, cur_addr); buff_ptr += (next_sec_addr - cur_addr); cur_addr = next_sec_addr; } } if (cur_addr < end_addr) { sect_num = cur_addr >> MG_MFLASH_SECTOR_SIZE_SHIFT; next_sec_addr = cur_addr + MG_MFLASH_SECTOR_SIZE; while (next_sec_addr <= end_addr) { cnt++; next_sec_addr += MG_MFLASH_SECTOR_SIZE; } if (cnt) { ret = mg_mflash_read_sects(buff_ptr, sect_num, cnt); if (ret != ERROR_OK) return ret; } buff_ptr += cnt * MG_MFLASH_SECTOR_SIZE; cur_addr += cnt * MG_MFLASH_SECTOR_SIZE; if (cur_addr < end_addr) { sect_num = cur_addr >> MG_MFLASH_SECTOR_SIZE_SHIFT; ret = mg_mflash_read_sects(sect_buff, sect_num, 1); if (ret != ERROR_OK) return ret; memcpy(buff_ptr, sect_buff, end_addr - cur_addr); LOG_DEBUG("mflash: copies %u byte", (unsigned)(end_addr - cur_addr)); } } return ret; } static int mg_mflash_write(uint32_t addr, uint8_t *buff, uint32_t len) { uint8_t *buff_ptr = buff; uint8_t sect_buff[MG_MFLASH_SECTOR_SIZE]; uint32_t cur_addr, next_sec_addr, end_addr, cnt, sect_num; int ret = ERROR_OK; cnt = 0; cur_addr = addr; end_addr = addr + len; if (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK) { next_sec_addr = (cur_addr + MG_MFLASH_SECTOR_SIZE) & ~MG_MFLASH_SECTOR_SIZE_MASK; sect_num = cur_addr >> MG_MFLASH_SECTOR_SIZE_SHIFT; ret = mg_mflash_read_sects(sect_buff, sect_num, 1); if (ret != ERROR_OK) return ret; if (end_addr < next_sec_addr) { memcpy(sect_buff + (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK), buff_ptr, end_addr - cur_addr); LOG_DEBUG( "mflash: copies %" PRIu32 " byte to sector offset 0x%8.8" PRIx32 "", end_addr - cur_addr, cur_addr); cur_addr = end_addr; } else { memcpy(sect_buff + (cur_addr & MG_MFLASH_SECTOR_SIZE_MASK), buff_ptr, next_sec_addr - cur_addr); LOG_DEBUG( "mflash: copies %" PRIu32 " byte to sector offset 0x%8.8" PRIx32 "", next_sec_addr - cur_addr, cur_addr); buff_ptr += (next_sec_addr - cur_addr); cur_addr = next_sec_addr; } ret = mg_mflash_write_sects(sect_buff, sect_num, 1); if (ret != ERROR_OK) return ret; } if (cur_addr < end_addr) { sect_num = cur_addr >> MG_MFLASH_SECTOR_SIZE_SHIFT; next_sec_addr = cur_addr + MG_MFLASH_SECTOR_SIZE; while (next_sec_addr <= end_addr) { cnt++; next_sec_addr += MG_MFLASH_SECTOR_SIZE; } if (cnt) { ret = mg_mflash_write_sects(buff_ptr, sect_num, cnt); if (ret != ERROR_OK) return ret; } buff_ptr += cnt * MG_MFLASH_SECTOR_SIZE; cur_addr += cnt * MG_MFLASH_SECTOR_SIZE; if (cur_addr < end_addr) { sect_num = cur_addr >> MG_MFLASH_SECTOR_SIZE_SHIFT; ret = mg_mflash_read_sects(sect_buff, sect_num, 1); if (ret != ERROR_OK) return ret; memcpy(sect_buff, buff_ptr, end_addr - cur_addr); LOG_DEBUG("mflash: copies %" PRIu32 " byte", end_addr - cur_addr); ret = mg_mflash_write_sects(sect_buff, sect_num, 1); } } return ret; } COMMAND_HANDLER(mg_write_cmd) { uint32_t address, cnt, res, i; uint8_t *buffer; struct fileio fileio; int ret; if (CMD_ARGC != 3) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], address); ret = fileio_open(&fileio, CMD_ARGV[1], FILEIO_READ, FILEIO_BINARY); if (ret != ERROR_OK) return ret; int filesize; buffer = malloc(MG_FILEIO_CHUNK); if (!buffer) { fileio_close(&fileio); return ERROR_FAIL; } int retval = fileio_size(&fileio, &filesize); if (retval != ERROR_OK) { fileio_close(&fileio); free(buffer); return retval; } cnt = filesize / MG_FILEIO_CHUNK; res = filesize % MG_FILEIO_CHUNK; struct duration bench; duration_start(&bench); size_t buf_cnt; for (i = 0; i < cnt; i++) { ret = fileio_read(&fileio, MG_FILEIO_CHUNK, buffer, &buf_cnt); if (ret != ERROR_OK) goto mg_write_cmd_err; ret = mg_mflash_write(address, buffer, MG_FILEIO_CHUNK); if (ret != ERROR_OK) goto mg_write_cmd_err; address += MG_FILEIO_CHUNK; } if (res) { ret = fileio_read(&fileio, res, buffer, &buf_cnt); if (ret != ERROR_OK) goto mg_write_cmd_err; ret = mg_mflash_write(address, buffer, res); if (ret != ERROR_OK) goto mg_write_cmd_err; } if (duration_measure(&bench) == ERROR_OK) { command_print(CMD_CTX, "wrote %ld bytes from file %s " "in %fs (%0.3f kB/s)", (long)filesize, CMD_ARGV[1], duration_elapsed(&bench), duration_kbps(&bench, filesize)); } free(buffer); fileio_close(&fileio); return ERROR_OK; mg_write_cmd_err: free(buffer); fileio_close(&fileio); return ret; } COMMAND_HANDLER(mg_dump_cmd) { uint32_t address, size, cnt, res, i; uint8_t *buffer; struct fileio fileio; int ret; if (CMD_ARGC != 4) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], address); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], size); ret = fileio_open(&fileio, CMD_ARGV[1], FILEIO_WRITE, FILEIO_BINARY); if (ret != ERROR_OK) return ret; buffer = malloc(MG_FILEIO_CHUNK); if (!buffer) { fileio_close(&fileio); return ERROR_FAIL; } cnt = size / MG_FILEIO_CHUNK; res = size % MG_FILEIO_CHUNK; struct duration bench; duration_start(&bench); size_t size_written; for (i = 0; i < cnt; i++) { ret = mg_mflash_read(address, buffer, MG_FILEIO_CHUNK); if (ret != ERROR_OK) goto mg_dump_cmd_err; ret = fileio_write(&fileio, MG_FILEIO_CHUNK, buffer, &size_written); if (ret != ERROR_OK) goto mg_dump_cmd_err; address += MG_FILEIO_CHUNK; } if (res) { ret = mg_mflash_read(address, buffer, res); if (ret != ERROR_OK) goto mg_dump_cmd_err; ret = fileio_write(&fileio, res, buffer, &size_written); if (ret != ERROR_OK) goto mg_dump_cmd_err; } if (duration_measure(&bench) == ERROR_OK) { command_print(CMD_CTX, "dump image (address 0x%8.8" PRIx32 " " "size %" PRIu32 ") to file %s in %fs (%0.3f kB/s)", address, size, CMD_ARGV[1], duration_elapsed(&bench), duration_kbps(&bench, size)); } free(buffer); fileio_close(&fileio); return ERROR_OK; mg_dump_cmd_err: free(buffer); fileio_close(&fileio); return ret; } static int mg_set_feature(mg_feature_id feature, mg_feature_val config) { struct target *target = mflash_bank->target; uint32_t mg_task_reg = mflash_bank->base + MG_REG_OFFSET; int ret; ret = mg_dsk_wait(mg_io_wait_rdy_noerr, MG_OEM_DISK_WAIT_TIME_NORMAL); if (ret != ERROR_OK) return ret; ret = target_write_u8(target, mg_task_reg + MG_REG_FEATURE, feature); ret |= target_write_u8(target, mg_task_reg + MG_REG_SECT_CNT, config); ret |= target_write_u8(target, mg_task_reg + MG_REG_COMMAND, mg_io_cmd_set_feature); return ret; } static int mg_is_valid_pll(double XIN, int N, double CLK_OUT, int NO) { double v1 = XIN / N; double v2 = CLK_OUT * NO; if (v1 < 1000000 || v1 > 15000000 || v2 < 100000000 || v2 > 500000000) return ERROR_MG_INVALID_PLL; return ERROR_OK; } static int mg_pll_get_M(unsigned short feedback_div) { int i, M; for (i = 1, M = 0; i < 512; i <<= 1, feedback_div >>= 1) M += (feedback_div & 1) * i; return M + 2; } static int mg_pll_get_N(unsigned char input_div) { int i, N; for (i = 1, N = 0; i < 32; i <<= 1, input_div >>= 1) N += (input_div & 1) * i; return N + 2; } static int mg_pll_get_NO(unsigned char output_div) { int i, NO; for (i = 0, NO = 1; i < 2; ++i, output_div >>= 1) if (output_div & 1) NO = NO << 1; return NO; } static double mg_do_calc_pll(double XIN, mg_pll_t *p_pll_val, int is_approximate) { unsigned short i; unsigned char j, k; int M, N, NO; double CLK_OUT; double DIV = 1; double ROUND = 0; if (is_approximate) { DIV = 1000000; ROUND = 500000; } for (i = 0; i < MG_PLL_MAX_FEEDBACKDIV_VAL; ++i) { M = mg_pll_get_M(i); for (j = 0; j < MG_PLL_MAX_INPUTDIV_VAL; ++j) { N = mg_pll_get_N(j); for (k = 0; k < MG_PLL_MAX_OUTPUTDIV_VAL; ++k) { NO = mg_pll_get_NO(k); CLK_OUT = XIN * ((double)M / N) / NO; if ((int)((CLK_OUT + ROUND) / DIV) == (int)(MG_PLL_CLK_OUT / DIV)) { if (mg_is_valid_pll(XIN, N, CLK_OUT, NO) == ERROR_OK) { p_pll_val->lock_cyc = (int)(XIN * MG_PLL_STD_LOCKCYCLE / MG_PLL_STD_INPUTCLK); p_pll_val->feedback_div = i; p_pll_val->input_div = j; p_pll_val->output_div = k; return CLK_OUT; } } } } } return 0; } static double mg_calc_pll(double XIN, mg_pll_t *p_pll_val) { double CLK_OUT; CLK_OUT = mg_do_calc_pll(XIN, p_pll_val, 0); if (!CLK_OUT) return mg_do_calc_pll(XIN, p_pll_val, 1); else return CLK_OUT; } static int mg_verify_interface(void) { uint16_t buff[MG_MFLASH_SECTOR_SIZE >> 1]; uint16_t i, j; uint32_t address = mflash_bank->base + MG_BUFFER_OFFSET; struct target *target = mflash_bank->target; int ret; for (j = 0; j < 10; j++) { for (i = 0; i < MG_MFLASH_SECTOR_SIZE >> 1; i++) buff[i] = i; ret = target_write_memory(target, address, 2, MG_MFLASH_SECTOR_SIZE / 2, (uint8_t *)buff); if (ret != ERROR_OK) return ret; memset(buff, 0xff, MG_MFLASH_SECTOR_SIZE); ret = target_read_memory(target, address, 2, MG_MFLASH_SECTOR_SIZE / 2, (uint8_t *)buff); if (ret != ERROR_OK) return ret; for (i = 0; i < MG_MFLASH_SECTOR_SIZE >> 1; i++) { if (buff[i] != i) { LOG_ERROR("mflash: verify interface fail"); return ERROR_MG_INTERFACE; } } } LOG_INFO("mflash: verify interface ok"); return ret; } static const char g_strSEG_SerialNum[20] = { 'G', 'm', 'n', 'i', '-', 'e', 'e', 'S', 'g', 'a', 'e', 'l', 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }; static const char g_strSEG_FWRev[8] = { 'F', 'X', 'L', 'T', '2', 'v', '0', '.' }; static const char g_strSEG_ModelNum[40] = { 'F', 'X', 'A', 'L', 'H', 'S', '2', 0x20, '0', '0', 's', '7', 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }; static void mg_gen_ataid(mg_io_type_drv_info *pSegIdDrvInfo) { /* b15 is ATA device(0) , b7 is Removable Media Device */ pSegIdDrvInfo->general_configuration = 0x045A; /* 128MB : Cylinder=> 977 , Heads=> 8 , Sectors=> 32 * 256MB : Cylinder=> 980 , Heads=> 16 , Sectors=> 32 * 384MB : Cylinder=> 745 , Heads=> 16 , Sectors=> 63 */ pSegIdDrvInfo->number_of_cylinders = 0x02E9; pSegIdDrvInfo->reserved1 = 0x0; pSegIdDrvInfo->number_of_heads = 0x10; pSegIdDrvInfo->unformatted_bytes_per_track = 0x0; pSegIdDrvInfo->unformatted_bytes_per_sector = 0x0; pSegIdDrvInfo->sectors_per_track = 0x3F; pSegIdDrvInfo->vendor_unique1[0] = 0x000B; pSegIdDrvInfo->vendor_unique1[1] = 0x7570; pSegIdDrvInfo->vendor_unique1[2] = 0x8888; memcpy(pSegIdDrvInfo->serial_number, (void *)g_strSEG_SerialNum, 20); /* 0x2 : dual buffer */ pSegIdDrvInfo->buffer_type = 0x2; /* buffer size : 2KB */ pSegIdDrvInfo->buffer_sector_size = 0x800; pSegIdDrvInfo->number_of_ecc_bytes = 0; memcpy(pSegIdDrvInfo->firmware_revision, (void *)g_strSEG_FWRev, 8); memcpy(pSegIdDrvInfo->model_number, (void *)g_strSEG_ModelNum, 40); pSegIdDrvInfo->maximum_block_transfer = 0x4; pSegIdDrvInfo->vendor_unique2 = 0x0; pSegIdDrvInfo->dword_io = 0x00; /* b11 : IORDY support(PIO Mode 4), b10 : Disable/Enbale IORDY * b9 : LBA support, b8 : DMA mode support */ pSegIdDrvInfo->capabilities = 0x1 << 9; pSegIdDrvInfo->reserved2 = 0x4000; pSegIdDrvInfo->vendor_unique3 = 0x00; /* PIOMode-2 support */ pSegIdDrvInfo->pio_cycle_timing_mode = 0x02; pSegIdDrvInfo->vendor_unique4 = 0x00; /* MultiWord-2 support */ pSegIdDrvInfo->dma_cycle_timing_mode = 0x00; /* b1 : word64~70 is valid * b0 : word54~58 are valid and reflect the current numofcyls,heads,sectors * b2 : If device supports Ultra DMA , set to one to vaildate word88 */ pSegIdDrvInfo->translation_fields_valid = (0x1 << 1) | (0x1 << 0); pSegIdDrvInfo->number_of_current_cylinders = 0x02E9; pSegIdDrvInfo->number_of_current_heads = 0x10; pSegIdDrvInfo->current_sectors_per_track = 0x3F; pSegIdDrvInfo->current_sector_capacity_lo = 0x7570; pSegIdDrvInfo->current_sector_capacity_hi = 0x000B; pSegIdDrvInfo->multi_sector_count = 0x04; /* b8 : Multiple secotr setting valid , b[7:0] num of secotrs per block */ pSegIdDrvInfo->multi_sector_setting_valid = 0x01; pSegIdDrvInfo->total_user_addressable_sectors_lo = 0x7570; pSegIdDrvInfo->total_user_addressable_sectors_hi = 0x000B; pSegIdDrvInfo->single_dma_modes_supported = 0x00; pSegIdDrvInfo->single_dma_transfer_active = 0x00; /* b2 :Multi-word DMA mode 2, b1 : Multi-word DMA mode 1 */ pSegIdDrvInfo->multi_dma_modes_supported = (0x1 << 0); /* b2 :Multi-word DMA mode 2, b1 : Multi-word DMA mode 1 */ pSegIdDrvInfo->multi_dma_transfer_active = (0x1 << 0); /* b0 : PIO Mode-3 support, b1 : PIO Mode-4 support */ pSegIdDrvInfo->adv_pio_mode = 0x00; /* 480(0x1E0)nsec for Multi-word DMA mode0 * 150(0x96) nsec for Multi-word DMA mode1 * 120(0x78) nsec for Multi-word DMA mode2 */ pSegIdDrvInfo->min_dma_cyc = 0x1E0; pSegIdDrvInfo->recommend_dma_cyc = 0x1E0; pSegIdDrvInfo->min_pio_cyc_no_iordy = 0x1E0; pSegIdDrvInfo->min_pio_cyc_with_iordy = 0x1E0; memset((void *)pSegIdDrvInfo->reserved3, 0x00, 22); /* b7 : ATA/ATAPI-7 ,b6 : ATA/ATAPI-6 ,b5 : ATA/ATAPI-5,b4 : ATA/ATAPI-4 */ pSegIdDrvInfo->major_ver_num = 0x7E; /* 0x1C : ATA/ATAPI-6 T13 1532D revision1 */ pSegIdDrvInfo->minor_ver_num = 0x19; /* NOP/READ BUFFER/WRITE BUFFER/Power management feature set support */ pSegIdDrvInfo->feature_cmd_set_suprt0 = 0x7068; /* Features/command set is valid/Advanced Pwr management/CFA feature set * not support */ pSegIdDrvInfo->feature_cmd_set_suprt1 = 0x400C; pSegIdDrvInfo->feature_cmd_set_suprt2 = 0x4000; /* READ/WRITE BUFFER/PWR Management enable */ pSegIdDrvInfo->feature_cmd_set_en0 = 0x7000; /* CFA feature is disabled / Advancde power management disable */ pSegIdDrvInfo->feature_cmd_set_en1 = 0x0; pSegIdDrvInfo->feature_cmd_set_en2 = 0x4000; pSegIdDrvInfo->reserved4 = 0x0; /* 0x1 * 2minutes */ pSegIdDrvInfo->req_time_for_security_er_done = 0x19; pSegIdDrvInfo->req_time_for_enhan_security_er_done = 0x19; /* Advanced power management level 1 */ pSegIdDrvInfo->adv_pwr_mgm_lvl_val = 0x0; pSegIdDrvInfo->reserved5 = 0x0; memset((void *)pSegIdDrvInfo->reserved6, 0x00, 68); /* Security mode feature is disabled */ pSegIdDrvInfo->security_stas = 0x0; memset((void *)pSegIdDrvInfo->vendor_uniq_bytes, 0x00, 62); /* CFA power mode 1 support in maximum 200mA */ pSegIdDrvInfo->cfa_pwr_mode = 0x0100; memset((void *)pSegIdDrvInfo->reserved7, 0x00, 190); } static int mg_storage_config(void) { uint8_t buff[512]; int ret; ret = mg_set_feature(mg_feature_id_transmode, mg_feature_val_trans_vcmd); if (ret != ERROR_OK) return ret; mg_gen_ataid((mg_io_type_drv_info *)(void *)buff); ret = mg_mflash_do_write_sects(buff, 0, 1, mg_vcmd_update_stgdrvinfo); if (ret != ERROR_OK) return ret; ret = mg_set_feature(mg_feature_id_transmode, mg_feature_val_trans_default); if (ret != ERROR_OK) return ret; LOG_INFO("mflash: storage config ok"); return ret; } static int mg_boot_config(void) { uint8_t buff[512]; int ret; ret = mg_set_feature(mg_feature_id_transmode, mg_feature_val_trans_vcmd); if (ret != ERROR_OK) return ret; memset(buff, 0xff, 512); buff[0] = mg_op_mode_snd; /* operation mode */ buff[1] = MG_UNLOCK_OTP_AREA; buff[2] = 4; /* boot size */ *((uint32_t *)(void *)(buff + 4)) = 0; /* XIP size */ ret = mg_mflash_do_write_sects(buff, 0, 1, mg_vcmd_update_xipinfo); if (ret != ERROR_OK) return ret; ret = mg_set_feature(mg_feature_id_transmode, mg_feature_val_trans_default); if (ret != ERROR_OK) return ret; LOG_INFO("mflash: boot config ok"); return ret; } static int mg_set_pll(mg_pll_t *pll) { uint8_t buff[512]; int ret; memset(buff, 0xff, 512); /* PLL Lock cycle and Feedback 9bit Divider */ memcpy(buff, &pll->lock_cyc, sizeof(uint32_t)); memcpy(buff + 4, &pll->feedback_div, sizeof(uint16_t)); buff[6] = pll->input_div; /* PLL Input 5bit Divider */ buff[7] = pll->output_div; /* PLL Output Divider */ ret = mg_set_feature(mg_feature_id_transmode, mg_feature_val_trans_vcmd); if (ret != ERROR_OK) return ret; ret = mg_mflash_do_write_sects(buff, 0, 1, mg_vcmd_wr_pll); if (ret != ERROR_OK) return ret; ret = mg_set_feature(mg_feature_id_transmode, mg_feature_val_trans_default); if (ret != ERROR_OK) return ret; LOG_INFO("mflash: set pll ok"); return ret; } static int mg_erase_nand(void) { int ret; ret = mg_set_feature(mg_feature_id_transmode, mg_feature_val_trans_vcmd); if (ret != ERROR_OK) return ret; ret = mg_mflash_do_write_sects(NULL, 0, 0, mg_vcmd_purge_nand); if (ret != ERROR_OK) return ret; ret = mg_set_feature(mg_feature_id_transmode, mg_feature_val_trans_default); if (ret != ERROR_OK) return ret; LOG_INFO("mflash: erase nand ok"); return ret; } COMMAND_HANDLER(mg_config_cmd) { double fin, fout; mg_pll_t pll; int ret; ret = mg_verify_interface(); if (ret != ERROR_OK) return ret; ret = mg_mflash_rst(); if (ret != ERROR_OK) return ret; switch (CMD_ARGC) { case 2: if (!strcmp(CMD_ARGV[1], "boot")) return mg_boot_config(); else if (!strcmp(CMD_ARGV[1], "storage")) return mg_storage_config(); else return ERROR_COMMAND_NOTFOUND; break; case 3: if (!strcmp(CMD_ARGV[1], "pll")) { unsigned long freq; COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], freq); fin = freq; if (fin > MG_PLL_CLK_OUT) { LOG_ERROR("mflash: input freq. is too large"); return ERROR_MG_INVALID_OSC; } fout = mg_calc_pll(fin, &pll); if (!fout) { LOG_ERROR("mflash: cannot generate valid pll"); return ERROR_MG_INVALID_PLL; } LOG_INFO("mflash: Fout=%" PRIu32 " Hz, feedback=%u," "indiv=%u, outdiv=%u, lock=%u", (uint32_t)fout, pll.feedback_div, pll.input_div, pll.output_div, pll.lock_cyc); ret = mg_erase_nand(); if (ret != ERROR_OK) return ret; return mg_set_pll(&pll); } else return ERROR_COMMAND_NOTFOUND; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } } static const struct command_registration mflash_exec_command_handlers[] = { { .name = "probe", .handler = mg_probe_cmd, .mode = COMMAND_EXEC, .help = "Detect bank configuration information", }, { .name = "write", .handler = mg_write_cmd, .mode = COMMAND_EXEC, /* FIXME bank_num is unused */ .usage = "bank_num filename address", .help = "Write binary file at the specified address.", }, { .name = "dump", .handler = mg_dump_cmd, .mode = COMMAND_EXEC, /* FIXME bank_num is unused */ .usage = "bank_num filename address size", .help = "Write specified number of bytes from a binary file " "to the specified, address.", }, { .name = "config", .handler = mg_config_cmd, .mode = COMMAND_EXEC, .help = "Configure MFLASH options.", .usage = "('boot'|'storage'|'pll' frequency)", }, COMMAND_REGISTRATION_DONE }; static int mflash_init_drivers(struct command_context *cmd_ctx) { if (!mflash_bank) return ERROR_OK; return register_commands(cmd_ctx, NULL, mflash_exec_command_handlers); } COMMAND_HANDLER(handle_mflash_init_command) { if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; static bool mflash_initialized; if (mflash_initialized) { LOG_INFO("'mflash init' has already been called"); return ERROR_OK; } mflash_initialized = true; LOG_DEBUG("Initializing mflash devices..."); return mflash_init_drivers(CMD_CTX); } COMMAND_HANDLER(mg_bank_cmd) { struct target *target; int i; if (CMD_ARGC < 4) return ERROR_COMMAND_SYNTAX_ERROR; target = get_target(CMD_ARGV[3]); if (target == NULL) { LOG_ERROR("target '%s' not defined", CMD_ARGV[3]); return ERROR_FAIL; } mflash_bank = calloc(sizeof(struct mflash_bank), 1); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], mflash_bank->base); /** @todo Verify how this parsing should work, then document it. */ char *str; mflash_bank->rst_pin.num = strtoul(CMD_ARGV[2], &str, 0); if (*str) mflash_bank->rst_pin.port[0] = (uint16_t) tolower((unsigned)str[0]); mflash_bank->target = target; for (i = 0; mflash_gpio[i]; i++) { if (!strcmp(mflash_gpio[i]->name, CMD_ARGV[0])) mflash_bank->gpio_drv = mflash_gpio[i]; } if (!mflash_bank->gpio_drv) { LOG_ERROR("%s is unsupported soc", CMD_ARGV[0]); return ERROR_MG_UNSUPPORTED_SOC; } return ERROR_OK; } static const struct command_registration mflash_config_command_handlers[] = { { .name = "bank", .handler = mg_bank_cmd, .mode = COMMAND_CONFIG, .help = "configure a mflash device bank", .usage = "soc_type base_addr pin_id target", }, { .name = "init", .mode = COMMAND_CONFIG, .handler = handle_mflash_init_command, .help = "initialize mflash devices", .usage = "" }, COMMAND_REGISTRATION_DONE }; static const struct command_registration mflash_command_handler[] = { { .name = "mflash", .mode = COMMAND_ANY, .help = "mflash command group", .usage = "", .chain = mflash_config_command_handlers, }, COMMAND_REGISTRATION_DONE }; int mflash_register_commands(struct command_context *cmd_ctx) { return register_commands(cmd_ctx, NULL, mflash_command_handler); } openocd-0.7.0/src/flash/startup.tcl0000644000175000001440000000341312137151331014152 00000000000000# Defines basic Tcl procs for OpenOCD flash module # # program utility proc # usage: program filename # optional args: verify, reset and address # proc program {filename args} { foreach arg $args { if {[string equal $arg "verify"]} { set verify 1 } elseif {[string equal $arg "reset"]} { set reset 1 } else { set address $arg } } # make sure init is called if {[catch {init}] != 0} { echo "** OpenOCD init Failed **" shutdown return } # reset target and call any init scripts if {[catch {reset init}] != 0} { echo "** Unable to reset target **" shutdown return } # start programming phase echo "** Programming Started **" if {[info exists address]} { set flash_args "$filename $address" } else { set flash_args "$filename" } if {[catch {eval flash write_image erase $flash_args}] == 0} { echo "** Programming Finished **" if {[info exists verify]} { # verify phase echo "** Verify Started **" if {[catch {eval verify_image $flash_args}] == 0} { echo "** Verified OK **" } else { echo "** Verify Failed **" } } if {[info exists reset]} { # reset target if requested # also disable target polling, we are shutting down anyway poll off echo "** Resetting Target **" reset run } } else { echo "** Programming Failed **" } # shutdown OpenOCD shutdown } add_help_text program "write an image to flash, address is only required for binary images. verify, reset are optional" add_usage_text program " \[address\] \[verify\] \[reset\]" # ease migration to updated flash driver proc stm32x args { echo "DEPRECATED! use 'stm32f1x $args' not 'stm32x $args'" eval stm32f1x $args } proc stm32f2xxx args { echo "DEPRECATED! use 'stm32f2x $args' not 'stm32f2xxx $args'" eval stm32f2x $args } openocd-0.7.0/src/main.c0000644000175000001440000000404112134336410011735 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "openocd.h" /* This is the main entry for developer PC hosted OpenOCD. * * OpenOCD can also be used as a library that is linked with * another application(not mainstream yet, but possible), e.g. * w/as an embedded application. * * Those applications will have their own main() implementation * and use bits and pieces from openocd.c. */ int main(int argc, char *argv[]) { /* disable buffering otherwise piping to logs causes problems work */ setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); return openocd_main(argc, argv); } openocd-0.7.0/src/target/0000755000175000001440000000000012141414412012211 500000000000000openocd-0.7.0/src/target/arm946e.c0000644000175000001440000005532512134336410013501 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2010 by Drasko DRASKOVIC * * drasko.draskovic@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm946e.h" #include "target_type.h" #include "arm_opcodes.h" #include "breakpoints.h" #if 0 #define _DEBUG_INSTRUCTION_EXECUTION_ #endif #define NB_CACHE_WAYS 4 #define CP15_CTL 0x02 #define CP15_CTL_DCACHE (1<<2) #define CP15_CTL_ICACHE (1<<12) /** * flag to give info about cache manipulation during debug : * "0" - cache lines are invalidated "on the fly", for affected addresses. * This is prefered from performance point of view. * "1" - cache is invalidated and switched off on debug_entry, and switched back on on restore. * It is kept off during debugging. */ static uint8_t arm946e_preserve_cache; int arm946e_post_debug_entry(struct target *target); void arm946e_pre_restore_context(struct target *target); static int arm946e_read_cp15(struct target *target, int reg_addr, uint32_t *value); int arm946e_init_arch_info(struct target *target, struct arm946e_common *arm946e, struct jtag_tap *tap) { struct arm7_9_common *arm7_9 = &arm946e->arm7_9_common; /* initialize arm7/arm9 specific info (including armv4_5) */ arm9tdmi_init_arch_info(target, arm7_9, tap); arm946e->common_magic = ARM946E_COMMON_MAGIC; /** * The ARM946E-S implements the ARMv5TE architecture which * has the BKPT instruction, so we don't have to use a watchpoint comparator */ arm7_9->arm_bkpt = ARMV5_BKPT(0x0); arm7_9->thumb_bkpt = ARMV5_T_BKPT(0x0) & 0xffff; arm7_9->post_debug_entry = arm946e_post_debug_entry; arm7_9->pre_restore_context = arm946e_pre_restore_context; /** * disabling linefills leads to lockups, so keep them enabled for now * this doesn't affect correctness, but might affect timing issues, if * important data is evicted from the cache during the debug session */ arm946e_preserve_cache = 0; /* override hw single-step capability from ARM9TDMI */ /* arm7_9->has_single_step = 1; */ return ERROR_OK; } static int arm946e_target_create(struct target *target, Jim_Interp *interp) { struct arm946e_common *arm946e = calloc(1, sizeof(struct arm946e_common)); arm946e_init_arch_info(target, arm946e, target->tap); return ERROR_OK; } static int arm946e_verify_pointer(struct command_context *cmd_ctx, struct arm946e_common *arm946e) { if (arm946e->common_magic != ARM946E_COMMON_MAGIC) { command_print(cmd_ctx, "target is not an ARM946"); return ERROR_TARGET_INVALID; } return ERROR_OK; } /* * Update cp15_control_reg, saved on debug_entry. */ static void arm946e_update_cp15_caches(struct target *target, uint32_t value) { struct arm946e_common *arm946e = target_to_arm946(target); arm946e->cp15_control_reg = (arm946e->cp15_control_reg & ~(CP15_CTL_DCACHE|CP15_CTL_ICACHE)) | (value & (CP15_CTL_DCACHE|CP15_CTL_ICACHE)); } /* * REVISIT: The "read_cp15" and "write_cp15" commands could hook up * to eventual mrc() and mcr() routines ... the reg_addr values being * constructed (for CP15 only) from Opcode_1, Opcode_2, and CRn values. * See section 7.3 of the ARM946E-S TRM. */ static int arm946e_read_cp15(struct target *target, int reg_addr, uint32_t *value) { int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; struct scan_field fields[3]; uint8_t reg_addr_buf = reg_addr & 0x3f; uint8_t nr_w_buf = 0; retval = arm_jtag_scann(jtag_info, 0xf, TAP_IDLE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 32; /* REVISIT: table 7-2 shows that bits 31-31 need to be * specified for accessing BIST registers ... */ fields[0].out_value = NULL; fields[0].in_value = NULL; fields[1].num_bits = 6; fields[1].out_value = ®_addr_buf; fields[1].in_value = NULL; fields[2].num_bits = 1; fields[2].out_value = &nr_w_buf; fields[2].in_value = NULL; jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE); fields[0].in_value = (uint8_t *)value; jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE); jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t)value); #ifdef _DEBUG_INSTRUCTION_EXECUTION_ LOG_DEBUG("addr: 0x%x value: %8.8x", reg_addr, *value); #endif retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; return ERROR_OK; } int arm946e_write_cp15(struct target *target, int reg_addr, uint32_t value) { int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; struct scan_field fields[3]; uint8_t reg_addr_buf = reg_addr & 0x3f; uint8_t nr_w_buf = 1; uint8_t value_buf[4]; buf_set_u32(value_buf, 0, 32, value); retval = arm_jtag_scann(jtag_info, 0xf, TAP_IDLE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 32; fields[0].out_value = value_buf; fields[0].in_value = NULL; fields[1].num_bits = 6; fields[1].out_value = ®_addr_buf; fields[1].in_value = NULL; fields[2].num_bits = 1; fields[2].out_value = &nr_w_buf; fields[2].in_value = NULL; jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE); #ifdef _DEBUG_INSTRUCTION_EXECUTION_ LOG_DEBUG("addr: 0x%x value: %8.8x", reg_addr, value); #endif retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; return ERROR_OK; } #define GET_ICACHE_SIZE 6 #define GET_DCACHE_SIZE 18 /* * \param target struct target pointer * \param idsel select GET_ICACHE_SIZE or GET_DCACHE_SIZE * \returns cache size, given in bytes */ static uint32_t arm946e_cp15_get_csize(struct target *target, int idsel) { struct arm946e_common *arm946e = target_to_arm946(target); uint32_t csize = arm946e->cp15_cache_info; if (csize == 0) { if (arm946e_read_cp15(target, 0x01, &csize) == ERROR_OK) arm946e->cp15_cache_info = csize; } if (csize & (1<<(idsel-4))) /* cache absent */ return 0; csize = (csize >> idsel) & 0x0F; return csize ? 1 << (12 + (csize-3)) : 0; } uint32_t arm946e_invalidate_whole_dcache(struct target *target) { uint32_t csize = arm946e_cp15_get_csize(target, GET_DCACHE_SIZE); if (csize == 0) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; /* One line (index) is 32 bytes (8 words) long, 4-way assoc * ARM DDI 0201D, Section 3.3.5 */ int nb_idx = (csize / (4*8*NB_CACHE_WAYS)); /* gives nb of lines (indexes) in the cache */ /* Loop for all segmentde (i.e. ways) */ uint32_t seg; for (seg = 0; seg < NB_CACHE_WAYS; seg++) { /* Loop for all indexes */ int idx; for (idx = 0; idx < nb_idx; idx++) { /* Form and write cp15 index (segment + line idx) */ uint32_t cp15_idx = seg << 30 | idx << 5; int retval = arm946e_write_cp15(target, 0x3a, cp15_idx); if (retval != ERROR_OK) { LOG_DEBUG("ERROR writing index"); return retval; } /* Read dtag */ uint32_t dtag; arm946e_read_cp15(target, 0x16, (uint32_t *) &dtag); /* Check cache line VALID bit */ if (!(dtag >> 4 & 0x1)) continue; /* Clean data cache line */ retval = arm946e_write_cp15(target, 0x35, 0x1); if (retval != ERROR_OK) { LOG_DEBUG("ERROR cleaning cache line"); return retval; } /* Flush data cache line */ retval = arm946e_write_cp15(target, 0x1a, 0x1); if (retval != ERROR_OK) { LOG_DEBUG("ERROR flushing cache line"); return retval; } } } return ERROR_OK; } uint32_t arm946e_invalidate_whole_icache(struct target *target) { /* Check cache presence before flushing - avoid undefined behavior */ uint32_t csize = arm946e_cp15_get_csize(target, GET_ICACHE_SIZE); if (csize == 0) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; LOG_DEBUG("FLUSHING I$"); /** * Invalidate (flush) I$ * mcr 15, 0, r0, cr7, cr5, {0} */ int retval = arm946e_write_cp15(target, 0x0f, 0x1); if (retval != ERROR_OK) { LOG_DEBUG("ERROR flushing I$"); return retval; } return ERROR_OK; } int arm946e_post_debug_entry(struct target *target) { uint32_t ctr_reg = 0x0; uint32_t retval = ERROR_OK; struct arm946e_common *arm946e = target_to_arm946(target); /* See if CACHES are enabled, and save that info * in the context bits, so that arm946e_pre_restore_context() can use them */ arm946e_read_cp15(target, CP15_CTL, (uint32_t *) &ctr_reg); /* Save control reg in the context */ arm946e->cp15_control_reg = ctr_reg; if (arm946e_preserve_cache) { if (ctr_reg & CP15_CTL_DCACHE) { /* Clean and flush D$ */ arm946e_invalidate_whole_dcache(target); /* Disable D$ */ ctr_reg &= ~CP15_CTL_DCACHE; } if (ctr_reg & CP15_CTL_ICACHE) { /* Flush I$ */ arm946e_invalidate_whole_icache(target); /* Disable I$ */ ctr_reg &= ~CP15_CTL_ICACHE; } /* Write the new configuration */ retval = arm946e_write_cp15(target, CP15_CTL, ctr_reg); if (retval != ERROR_OK) { LOG_DEBUG("ERROR disabling cache"); return retval; } } /* if preserve_cache */ return ERROR_OK; } void arm946e_pre_restore_context(struct target *target) { uint32_t ctr_reg = 0x0; uint32_t retval; if (arm946e_preserve_cache) { struct arm946e_common *arm946e = target_to_arm946(target); /* Get the contents of the CTR reg */ arm946e_read_cp15(target, CP15_CTL, (uint32_t *) &ctr_reg); /** * Read-modify-write CP15 control * to reenable I/D-cache operation * NOTE: It is not possible to disable cache by CP15. * if arm946e_preserve_cache debugging flag enabled. */ ctr_reg |= arm946e->cp15_control_reg & (CP15_CTL_DCACHE|CP15_CTL_ICACHE); /* Write the new configuration */ retval = arm946e_write_cp15(target, CP15_CTL, ctr_reg); if (retval != ERROR_OK) LOG_DEBUG("ERROR enabling cache"); } /* if preserve_cache */ } uint32_t arm946e_invalidate_dcache(struct target *target, uint32_t address, uint32_t size, uint32_t count) { uint32_t cur_addr = 0x0; uint32_t cp15_idx, set, way, dtag; uint32_t i = 0; int retval; for (i = 0; i < count*size; i++) { cur_addr = address + i; set = (cur_addr >> 5) & 0xff; /* set field is 8 bits long */ for (way = 0; way < NB_CACHE_WAYS; way++) { /** * Find if the affected address is kept in the cache. * Because JTAG Scan Chain 15 offers limited approach, * we have to loop through all cache ways (segments) and * read cache tags, then compare them with with address. */ /* Form and write cp15 index (segment + line idx) */ cp15_idx = way << 30 | set << 5; retval = arm946e_write_cp15(target, 0x3a, cp15_idx); if (retval != ERROR_OK) { LOG_DEBUG("ERROR writing index"); return retval; } /* Read dtag */ arm946e_read_cp15(target, 0x16, (uint32_t *) &dtag); /* Check cache line VALID bit */ if (!(dtag >> 4 & 0x1)) continue; /* If line is valid and corresponds to affected address - invalidate it */ if (dtag >> 5 == cur_addr >> 5) { /* Clean data cache line */ retval = arm946e_write_cp15(target, 0x35, 0x1); if (retval != ERROR_OK) { LOG_DEBUG("ERROR cleaning cache line"); return retval; } /* Flush data cache line */ retval = arm946e_write_cp15(target, 0x1c, 0x1); if (retval != ERROR_OK) { LOG_DEBUG("ERROR flushing cache line"); return retval; } break; } } /* loop through all 4 ways */ } /* loop through all addresses */ return ERROR_OK; } uint32_t arm946e_invalidate_icache(struct target *target, uint32_t address, uint32_t size, uint32_t count) { uint32_t cur_addr = 0x0; uint32_t cp15_idx, set, way, itag; uint32_t i = 0; int retval; for (i = 0; i < count*size; i++) { cur_addr = address + i; set = (cur_addr >> 5) & 0xff; /* set field is 8 bits long */ for (way = 0; way < NB_CACHE_WAYS; way++) { /* Form and write cp15 index (segment + line idx) */ cp15_idx = way << 30 | set << 5; retval = arm946e_write_cp15(target, 0x3a, cp15_idx); if (retval != ERROR_OK) { LOG_DEBUG("ERROR writing index"); return retval; } /* Read itag */ arm946e_read_cp15(target, 0x17, (uint32_t *) &itag); /* Check cache line VALID bit */ if (!(itag >> 4 & 0x1)) continue; /* If line is valid and corresponds to affected address - invalidate it */ if (itag >> 5 == cur_addr >> 5) { /* Flush I$ line */ retval = arm946e_write_cp15(target, 0x1d, 0x0); if (retval != ERROR_OK) { LOG_DEBUG("ERROR flushing cache line"); return retval; } break; } } /* way loop */ } /* addr loop */ return ERROR_OK; } /** Writes a buffer, in the specified word size, with current MMU settings. */ int arm946e_write_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { int retval; LOG_DEBUG("-"); struct arm946e_common *arm946e = target_to_arm946(target); /* Invalidate D$ if it is ON */ if (!arm946e_preserve_cache && (arm946e->cp15_control_reg & CP15_CTL_DCACHE)) arm946e_invalidate_dcache(target, address, size, count); /** * Write memory */ retval = arm7_9_write_memory(target, address, size, count, buffer); if (retval != ERROR_OK) return retval; /* * * Invalidate I$ if it is ON. * * D$ has been cleaned and flushed before mem write thus forcing it to behave like write-through, * because arm7_9_write_memory() has seen non-valid bit in D$ * and wrote data into physical RAM (without touching or allocating the cache line). * From ARM946ES Technical Reference Manual we can see that it uses "allocate on read-miss" * policy for both I$ and D$ (Chapter 3.2 and 3.3) * * Explanation : * "ARM system developer's guide: designing and optimizing system software" by * Andrew N. Sloss, Dominic Symes and Chris Wright, * Chapter 12.3.3 Allocating Policy on a Cache Miss : * A read allocate on cache miss policy allocates a cache line only during a read from main memory. * If the victim cache line contains valid data, then it is written to main memory before the cache line * is filled with new data. * Under this strategy, a write of new data to memory does not update the contents of the cache memory * unless a cache line was allocated on a previous read from main memory. * If the cache line contains valid data, then the write updates the cache and may update the main memory if * the cache write policy is write-through. * If the data is not in the cache, the controller writes to main memory only. */ if (!arm946e_preserve_cache && (arm946e->cp15_control_reg & CP15_CTL_ICACHE)) arm946e_invalidate_icache(target, address, size, count); return ERROR_OK; } int arm946e_read_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) { int retval; LOG_DEBUG("-"); retval = arm7_9_read_memory(target, address, size, count, buffer); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int jim_arm946e_cp15(Jim_Interp *interp, int argc, Jim_Obj * const *argv) { /* one or two arguments, access a single register (write if second argument is given) */ if (argc < 2 || argc > 3) { Jim_WrongNumArgs(interp, 1, argv, "addr [value]"); return JIM_ERR; } struct command_context *cmd_ctx = current_command_context(interp); assert(cmd_ctx != NULL); struct target *target = get_current_target(cmd_ctx); if (target == NULL) { LOG_ERROR("arm946e: no current target"); return JIM_ERR; } struct arm946e_common *arm946e = target_to_arm946(target); int retval = arm946e_verify_pointer(cmd_ctx, arm946e); if (retval != ERROR_OK) return JIM_ERR; if (target->state != TARGET_HALTED) { command_print(cmd_ctx, "target %s must be stopped for \"cp15\" command", target_name(target)); return JIM_ERR; } long l; uint32_t address; retval = Jim_GetLong(interp, argv[1], &l); address = l; if (JIM_OK != retval) return retval; if (argc == 2) { uint32_t value; retval = arm946e_read_cp15(target, address, &value); if (retval != ERROR_OK) { command_print(cmd_ctx, "%s cp15 reg %" PRIi32 " access failed", target_name(target), address); return JIM_ERR; } retval = jtag_execute_queue(); if (retval != ERROR_OK) return JIM_ERR; char buf[20]; sprintf(buf, "0x%08x", value); /* Return value in hex format */ Jim_SetResultString(interp, buf, -1); } else if (argc == 3) { uint32_t value; retval = Jim_GetLong(interp, argv[2], &l); value = l; if (JIM_OK != retval) return retval; retval = arm946e_write_cp15(target, address, value); if (retval != ERROR_OK) { command_print(cmd_ctx, "%s cp15 reg %" PRIi32 " access failed", target_name(target), address); return JIM_ERR; } if (address == CP15_CTL) arm946e_update_cp15_caches(target, value); } return JIM_OK; } COMMAND_HANDLER(arm946e_handle_idcache) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; int retval; struct target *target = get_current_target(CMD_CTX); struct arm946e_common *arm946e = target_to_arm946(target); retval = arm946e_verify_pointer(CMD_CTX, arm946e); if (retval != ERROR_OK) return retval; if (target->state != TARGET_HALTED) { command_print(CMD_CTX, "target must be stopped for \"%s\" command", CMD_NAME); return ERROR_TARGET_NOT_HALTED; } bool icache = (strcmp(CMD_NAME, "icache") == 0); uint32_t csize = arm946e_cp15_get_csize(target, icache ? GET_ICACHE_SIZE : GET_DCACHE_SIZE) / 1024; if (CMD_ARGC == 0) { bool bena = ((arm946e->cp15_control_reg & (icache ? CP15_CTL_ICACHE : CP15_CTL_DCACHE)) != 0) && (arm946e->cp15_control_reg & 0x1); if (csize == 0) command_print(CMD_CTX, "%s-cache absent", icache ? "I" : "D"); else command_print(CMD_CTX, "%s-cache size: %dK, %s", icache ? "I" : "D", csize, bena ? "enabled" : "disabled"); return ERROR_OK; } bool flush = false; bool enable = false; retval = command_parse_bool_arg(CMD_ARGV[0], &enable); if (retval == ERROR_COMMAND_SYNTAX_ERROR) { if (strcmp(CMD_ARGV[0], "flush") == 0) { flush = true; retval = ERROR_OK; } else return retval; } /* Do not invalidate or change state, if cache is absent */ if (csize == 0) { command_print(CMD_CTX, "%s-cache absent, '%s' operation undefined", icache ? "I" : "D", CMD_ARGV[0]); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* NOTE: flushing entire cache will not preserve lock-down cache regions */ if (icache) { if ((arm946e->cp15_control_reg & CP15_CTL_ICACHE) && !enable) retval = arm946e_invalidate_whole_icache(target); } else { if ((arm946e->cp15_control_reg & CP15_CTL_DCACHE) && !enable) retval = arm946e_invalidate_whole_dcache(target); } if (retval != ERROR_OK || flush) return retval; uint32_t value; retval = arm946e_read_cp15(target, CP15_CTL, &value); if (retval != ERROR_OK) return retval; uint32_t vnew = value; uint32_t cmask = icache ? CP15_CTL_ICACHE : CP15_CTL_DCACHE; if (enable) { if ((value & 0x1) == 0) LOG_WARNING("arm946e: MPU must be enabled for cache to operate"); vnew |= cmask; } else vnew &= ~cmask; if (vnew == value) return ERROR_OK; retval = arm946e_write_cp15(target, CP15_CTL, vnew); if (retval != ERROR_OK) return retval; arm946e_update_cp15_caches(target, vnew); return ERROR_OK; } static const struct command_registration arm946e_exec_command_handlers[] = { { .name = "cp15", .jim_handler = jim_arm946e_cp15, .mode = COMMAND_EXEC, .usage = "regnum [value]", .help = "read/modify cp15 register", }, { .name = "icache", .handler = arm946e_handle_idcache, .mode = COMMAND_EXEC, .usage = "['enable'|'disable'|'flush']", .help = "I-cache info and operations", }, { .name = "dcache", .handler = arm946e_handle_idcache, .mode = COMMAND_EXEC, .usage = "['enable'|'disable'|'flush']", .help = "D-cache info and operations", }, COMMAND_REGISTRATION_DONE }; const struct command_registration arm946e_command_handlers[] = { { .chain = arm9tdmi_command_handlers, }, { .name = "arm946e", .mode = COMMAND_ANY, .help = "arm946e command group", .usage = "", .chain = arm946e_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; /** Holds methods for ARM946 targets. */ struct target_type arm946e_target = { .name = "arm946e", .poll = arm7_9_poll, .arch_state = arm_arch_state, .target_request_data = arm7_9_target_request_data, .halt = arm7_9_halt, .resume = arm7_9_resume, .step = arm7_9_step, .assert_reset = arm7_9_assert_reset, .deassert_reset = arm7_9_deassert_reset, .soft_reset_halt = arm7_9_soft_reset_halt, .get_gdb_reg_list = arm_get_gdb_reg_list, /* .read_memory = arm7_9_read_memory, */ /* .write_memory = arm7_9_write_memory, */ .read_memory = arm946e_read_memory, .write_memory = arm946e_write_memory, .bulk_write_memory = arm7_9_bulk_write_memory, .checksum_memory = arm_checksum_memory, .blank_check_memory = arm_blank_check_memory, .run_algorithm = armv4_5_run_algorithm, .add_breakpoint = arm7_9_add_breakpoint, .remove_breakpoint = arm7_9_remove_breakpoint, /* .add_breakpoint = arm946e_add_breakpoint, */ /* .remove_breakpoint = arm946e_remove_breakpoint, */ .add_watchpoint = arm7_9_add_watchpoint, .remove_watchpoint = arm7_9_remove_watchpoint, .commands = arm946e_command_handlers, .target_create = arm946e_target_create, .init_target = arm9tdmi_init_target, .examine = arm7_9_examine, .check_reset = arm7_9_check_reset, }; openocd-0.7.0/src/target/arm926ejs.h0000644000175000001440000000513312134336410014031 00000000000000/*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef ARM926EJS_H #define ARM926EJS_H #include "arm9tdmi.h" #include "armv4_5_mmu.h" #define ARM926EJS_COMMON_MAGIC 0xa926a926 struct arm926ejs_common { struct arm7_9_common arm7_9_common; uint32_t common_magic; struct armv4_5_mmu_common armv4_5_mmu; int (*read_cp15)(struct target *target, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t *value); int (*write_cp15)(struct target *target, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t value); uint32_t cp15_control_reg; uint32_t d_fsr; uint32_t i_fsr; uint32_t d_far; }; static inline struct arm926ejs_common *target_to_arm926(struct target *target) { return container_of(target->arch_info, struct arm926ejs_common, arm7_9_common.arm); } int arm926ejs_init_arch_info(struct target *target, struct arm926ejs_common *arm926ejs, struct jtag_tap *tap); int arm926ejs_arch_state(struct target *target); int arm926ejs_write_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer); int arm926ejs_soft_reset_halt(struct target *target); extern const struct command_registration arm926ejs_command_handlers[]; #endif /* ARM926EJS_H */ openocd-0.7.0/src/target/arm11.h0000644000175000001440000000752012134336410013232 00000000000000/*************************************************************************** * Copyright (C) 2008 digenius technology GmbH. * * Michael Bruck * * * * Copyright (C) 2008 Georg Acher * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef ARM11_H #define ARM11_H #include "arm.h" #include "arm_dpm.h" #define ARM11_TAP_DEFAULT TAP_INVALID #define CHECK_RETVAL(action) \ do { \ int __retval = (action); \ if (__retval != ERROR_OK) { \ LOG_DEBUG("error while calling \"%s\"", \ # action); \ return __retval; \ } \ } while (0) /* bits from ARMv7 DIDR */ enum arm11_debug_version { ARM11_DEBUG_V6 = 0x01, ARM11_DEBUG_V61 = 0x02, ARM11_DEBUG_V7 = 0x03, ARM11_DEBUG_V7_CP14 = 0x04, }; struct arm11_common { struct arm arm; /** Debug module state. */ struct arm_dpm dpm; struct arm11_sc7_action *bpwp_actions; unsigned bpwp_n; size_t brp; /**< Number of Breakpoint Register Pairs from DIDR */ size_t free_brps; /**< Number of breakpoints allocated */ uint32_t dscr; /**< Last retrieved DSCR value. */ uint32_t saved_rdtr; uint32_t saved_wdtr; bool is_rdtr_saved; bool is_wdtr_saved; bool simulate_reset_on_next_halt; /**< Perform cleanups of the ARM state on next halt **/ /* Per-core configurable options. * NOTE that several of these boolean options should not exist * once the relevant code is known to work correctly. */ bool memwrite_burst; bool memwrite_error_fatal; bool step_irq_enable; bool hardware_step; /** Configured Vector Catch Register settings. */ uint32_t vcr; struct arm_jtag jtag_info; }; static inline struct arm11_common *target_to_arm11(struct target *target) { return container_of(target->arch_info, struct arm11_common, arm); } /** * ARM11 DBGTAP instructions * * http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301f/I1006229.html */ enum arm11_instructions { ARM11_EXTEST = 0x00, ARM11_SCAN_N = 0x02, ARM11_RESTART = 0x04, ARM11_HALT = 0x08, ARM11_INTEST = 0x0C, ARM11_ITRSEL = 0x1D, ARM11_IDCODE = 0x1E, ARM11_BYPASS = 0x1F, }; enum arm11_sc7 { ARM11_SC7_NULL = 0, ARM11_SC7_VCR = 7, ARM11_SC7_PC = 8, ARM11_SC7_BVR0 = 64, ARM11_SC7_BCR0 = 80, ARM11_SC7_WVR0 = 96, ARM11_SC7_WCR0 = 112, }; #endif /* ARM11_H */ openocd-0.7.0/src/target/arm9tdmi.c0000644000175000001440000007205712134336410014041 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2008 by Hongtao Zheng * * hontor@126.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm9tdmi.h" #include "target_type.h" #include "register.h" #include "arm_opcodes.h" /* * NOTE: this holds code that's used with multiple ARM9 processors: * - ARM9TDMI (ARMv4T) ... in ARM920, ARM922, and ARM940 cores * - ARM9E-S (ARMv5TE) ... in ARM946, ARM966, and ARM968 cores * - ARM9EJS (ARMv5TEJ) ... in ARM926 core * * In short, the file name is a misnomer ... it is NOT specific to * that first generation ARM9 processor, or cores using it. */ #if 0 #define _DEBUG_INSTRUCTION_EXECUTION_ #endif enum arm9tdmi_vector_bit { ARM9TDMI_RESET_VECTOR = 0x01, ARM9TDMI_UNDEF_VECTOR = 0x02, ARM9TDMI_SWI_VECTOR = 0x04, ARM9TDMI_PABT_VECTOR = 0x08, ARM9TDMI_DABT_VECTOR = 0x10, /* BIT(5) reserved -- must be zero */ ARM9TDMI_IRQ_VECTOR = 0x40, ARM9TDMI_FIQ_VECTOR = 0x80, }; static const struct arm9tdmi_vector { const char *name; uint32_t value; } arm9tdmi_vectors[] = { {"reset", ARM9TDMI_RESET_VECTOR}, {"undef", ARM9TDMI_UNDEF_VECTOR}, {"swi", ARM9TDMI_SWI_VECTOR}, {"pabt", ARM9TDMI_PABT_VECTOR}, {"dabt", ARM9TDMI_DABT_VECTOR}, {"irq", ARM9TDMI_IRQ_VECTOR}, {"fiq", ARM9TDMI_FIQ_VECTOR}, {0, 0}, }; int arm9tdmi_examine_debug_reason(struct target *target) { int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); /* only check the debug reason if we don't know it already */ if ((target->debug_reason != DBG_REASON_DBGRQ) && (target->debug_reason != DBG_REASON_SINGLESTEP)) { struct scan_field fields[3]; uint8_t databus[4]; uint8_t instructionbus[4]; uint8_t debug_reason; fields[0].num_bits = 32; fields[0].out_value = NULL; fields[0].in_value = databus; fields[1].num_bits = 3; fields[1].out_value = NULL; fields[1].in_value = &debug_reason; fields[2].num_bits = 32; fields[2].out_value = NULL; fields[2].in_value = instructionbus; retval = arm_jtag_scann(&arm7_9->jtag_info, 0x1, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(&arm7_9->jtag_info, arm7_9->jtag_info.intest_instr, NULL, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; jtag_add_dr_scan(arm7_9->jtag_info.tap, 3, fields, TAP_DRPAUSE); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; fields[0].in_value = NULL; fields[0].out_value = databus; fields[1].in_value = NULL; fields[1].out_value = &debug_reason; fields[2].in_value = NULL; fields[2].out_value = instructionbus; jtag_add_dr_scan(arm7_9->jtag_info.tap, 3, fields, TAP_DRPAUSE); if (debug_reason & 0x4) if (debug_reason & 0x2) target->debug_reason = DBG_REASON_WPTANDBKPT; else target->debug_reason = DBG_REASON_WATCHPOINT; else target->debug_reason = DBG_REASON_BREAKPOINT; } return ERROR_OK; } /* put an instruction in the ARM9TDMI pipeline or write the data bus, * and optionally read data */ int arm9tdmi_clock_out(struct arm_jtag *jtag_info, uint32_t instr, uint32_t out, uint32_t *in, int sysspeed) { int retval = ERROR_OK; struct scan_field fields[3]; uint8_t out_buf[4]; uint8_t instr_buf[4]; uint8_t sysspeed_buf = 0x0; /* prepare buffer */ buf_set_u32(out_buf, 0, 32, out); buf_set_u32(instr_buf, 0, 32, flip_u32(instr, 32)); if (sysspeed) buf_set_u32(&sysspeed_buf, 2, 1, 1); retval = arm_jtag_scann(jtag_info, 0x1, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 32; fields[0].out_value = out_buf; fields[0].in_value = NULL; fields[1].num_bits = 3; fields[1].out_value = &sysspeed_buf; fields[1].in_value = NULL; fields[2].num_bits = 32; fields[2].out_value = instr_buf; fields[2].in_value = NULL; if (in) { fields[0].in_value = (uint8_t *)in; jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_DRPAUSE); jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t)in); } else jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_DRPAUSE); jtag_add_runtest(0, TAP_DRPAUSE); #ifdef _DEBUG_INSTRUCTION_EXECUTION_ { retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (in) LOG_DEBUG("instr: 0x%8.8x, out: 0x%8.8x, in: 0x%8.8x", instr, out, *in); else LOG_DEBUG("instr: 0x%8.8x, out: 0x%8.8x", instr, out); } #endif return ERROR_OK; } /* just read data (instruction and data-out = don't care) */ int arm9tdmi_clock_data_in(struct arm_jtag *jtag_info, uint32_t *in) { int retval = ERROR_OK; struct scan_field fields[3]; retval = arm_jtag_scann(jtag_info, 0x1, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 32; fields[0].out_value = NULL; fields[0].in_value = (uint8_t *)in; fields[1].num_bits = 3; fields[1].out_value = NULL; fields[1].in_value = NULL; fields[2].num_bits = 32; fields[2].out_value = NULL; fields[2].in_value = NULL; jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_DRPAUSE); jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t)in); jtag_add_runtest(0, TAP_DRPAUSE); #ifdef _DEBUG_INSTRUCTION_EXECUTION_ { retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (in) LOG_DEBUG("in: 0x%8.8x", *in); else LOG_ERROR("BUG: called with in == NULL"); } #endif return ERROR_OK; } /* clock the target, and read the databus * the *in pointer points to a buffer where elements of 'size' bytes * are stored in big (be == 1) or little (be == 0) endianness */ int arm9tdmi_clock_data_in_endianness(struct arm_jtag *jtag_info, void *in, int size, int be) { int retval = ERROR_OK; struct scan_field fields[2]; retval = arm_jtag_scann(jtag_info, 0x1, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; if (size == 4) { fields[0].num_bits = 32; fields[0].out_value = NULL; fields[0].in_value = in; fields[1].num_bits = 3 + 32; fields[1].out_value = NULL; fields[1].in_value = NULL; } else { /* Discard irrelevant bits of the scan, making sure we don't write more * than size bytes to in */ fields[0].num_bits = size * 8; fields[0].out_value = NULL; fields[0].in_value = in; fields[1].num_bits = 3 + 32 + 32 - size * 8; fields[1].out_value = NULL; fields[1].in_value = NULL; } jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_DRPAUSE); jtag_add_callback4(arm7_9_endianness_callback, (jtag_callback_data_t)in, (jtag_callback_data_t)size, (jtag_callback_data_t)be, (jtag_callback_data_t)0); jtag_add_runtest(0, TAP_DRPAUSE); #ifdef _DEBUG_INSTRUCTION_EXECUTION_ { retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (in) LOG_DEBUG("in: 0x%8.8x", *(uint32_t *)in); else LOG_ERROR("BUG: called with in == NULL"); } #endif return ERROR_OK; } static void arm9tdmi_change_to_arm(struct target *target, uint32_t *r0, uint32_t *pc) { int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* save r0 before using it and put system in ARM state * to allow common handling of ARM and THUMB debugging */ /* fetch STR r0, [r0] */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); /* STR r0, [r0] in Memory */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, r0, 0); /* MOV r0, r15 fetched, STR in Decode */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_MOV(0, 15), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); /* nothing fetched, STR r0, [r0] in Memory */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, pc, 0); /* use pc-relative LDR to clear r0[1:0] (for switch to ARM mode) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), 0, NULL, 0); /* LDR in Decode */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); /* LDR in Execute */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); /* LDR in Memory (to account for interlock) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); /* fetch BX */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_BX(0), 0, NULL, 0); /* NOP fetched, BX in Decode, MOV in Execute */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); /* NOP fetched, BX in Execute (1) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); retval = jtag_execute_queue(); if (retval != ERROR_OK) return; /* fix program counter: * MOV r0, r15 was the 5th instruction (+8) * reading PC in Thumb state gives address of instruction + 4 */ *pc -= 0xc; } void arm9tdmi_read_core_regs(struct target *target, uint32_t mask, uint32_t *core_regs[16]) { int i; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* STMIA r0-15, [r0] at debug speed * register values will start to appear on 4th DCLK */ arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0); /* fetch NOP, STM in DECODE stage */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, STM in EXECUTE stage (1st cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); for (i = 0; i <= 15; i++) { if (mask & (1 << i)) /* nothing fetched, STM in MEMORY (i'th cycle) */ arm9tdmi_clock_data_in(jtag_info, core_regs[i]); } } static void arm9tdmi_read_core_regs_target_buffer(struct target *target, uint32_t mask, void *buffer, int size) { int i; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; int be = (target->endianness == TARGET_BIG_ENDIAN) ? 1 : 0; uint32_t *buf_u32 = buffer; uint16_t *buf_u16 = buffer; uint8_t *buf_u8 = buffer; /* STMIA r0-15, [r0] at debug speed * register values will start to appear on 4th DCLK */ arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0); /* fetch NOP, STM in DECODE stage */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, STM in EXECUTE stage (1st cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); for (i = 0; i <= 15; i++) { if (mask & (1 << i)) /* nothing fetched, STM in MEMORY (i'th cycle) */ switch (size) { case 4: arm9tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be); break; case 2: arm9tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be); break; case 1: arm9tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be); break; } } } static void arm9tdmi_read_xpsr(struct target *target, uint32_t *xpsr, int spsr) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* MRS r0, cpsr */ arm9tdmi_clock_out(jtag_info, ARMV4_5_MRS(0, spsr & 1), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* STR r0, [r15] */ arm9tdmi_clock_out(jtag_info, ARMV4_5_STR(0, 15), 0, NULL, 0); /* fetch NOP, STR in DECODE stage */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, STR in EXECUTE stage (1st cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* nothing fetched, STR in MEMORY */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, xpsr, 0); } static void arm9tdmi_write_xpsr(struct target *target, uint32_t xpsr, int spsr) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; LOG_DEBUG("xpsr: %8.8" PRIx32 ", spsr: %i", xpsr, spsr); /* MSR1 fetched */ arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr & 0xff, 0, 1, spsr), 0, NULL, 0); /* MSR2 fetched, MSR1 in DECODE */ arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff00) >> 8, 0xc, 2, spsr), 0, NULL, 0); /* MSR3 fetched, MSR1 in EXECUTE (1), MSR2 in DECODE */ arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff0000) >> 16, 0x8, 4, spsr), 0, NULL, 0); /* nothing fetched, MSR1 in EXECUTE (2) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* nothing fetched, MSR1 in EXECUTE (3) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* MSR4 fetched, MSR2 in EXECUTE (1), MSR3 in DECODE */ arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff000000) >> 24, 0x4, 8, spsr), 0, NULL, 0); /* nothing fetched, MSR2 in EXECUTE (2) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* nothing fetched, MSR2 in EXECUTE (3) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* NOP fetched, MSR3 in EXECUTE (1), MSR4 in DECODE */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* nothing fetched, MSR3 in EXECUTE (2) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* nothing fetched, MSR3 in EXECUTE (3) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* NOP fetched, MSR4 in EXECUTE (1) */ /* last MSR writes flags, which takes only one cycle */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); } static void arm9tdmi_write_xpsr_im8(struct target *target, uint8_t xpsr_im, int rot, int spsr) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; LOG_DEBUG("xpsr_im: %2.2x, rot: %i, spsr: %i", xpsr_im, rot, spsr); /* MSR fetched */ arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr_im, rot, 1, spsr), 0, NULL, 0); /* NOP fetched, MSR in DECODE */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* NOP fetched, MSR in EXECUTE (1) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* rot == 4 writes flags, which takes only one cycle */ if (rot != 4) { /* nothing fetched, MSR in EXECUTE (2) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* nothing fetched, MSR in EXECUTE (3) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); } } void arm9tdmi_write_core_regs(struct target *target, uint32_t mask, uint32_t core_regs[16]) { int i; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* LDMIA r0-15, [r0] at debug speed * register values will start to appear on 4th DCLK */ arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0); /* fetch NOP, LDM in DECODE stage */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); for (i = 0; i <= 15; i++) { if (mask & (1 << i)) /* nothing fetched, LDM still in EXECUTE (1 + i cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, core_regs[i], NULL, 0); } arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); } void arm9tdmi_load_word_regs(struct target *target, uint32_t mask) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* put system-speed load-multiple into the pipeline */ arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 1), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); } void arm9tdmi_load_hword_reg(struct target *target, int num) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* put system-speed load half-word into the pipeline */ arm9tdmi_clock_out(jtag_info, ARMV4_5_LDRH_IP(num, 0), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); } void arm9tdmi_load_byte_reg(struct target *target, int num) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* put system-speed load byte into the pipeline */ arm9tdmi_clock_out(jtag_info, ARMV4_5_LDRB_IP(num, 0), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); } void arm9tdmi_store_word_regs(struct target *target, uint32_t mask) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* put system-speed store-multiple into the pipeline */ arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask, 0, 1), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); } void arm9tdmi_store_hword_reg(struct target *target, int num) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* put system-speed store half-word into the pipeline */ arm9tdmi_clock_out(jtag_info, ARMV4_5_STRH_IP(num, 0), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); } void arm9tdmi_store_byte_reg(struct target *target, int num) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* put system-speed store byte into the pipeline */ arm9tdmi_clock_out(jtag_info, ARMV4_5_STRB_IP(num, 0), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); } static void arm9tdmi_write_pc(struct target *target, uint32_t pc) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* LDMIA r0-15, [r0] at debug speed * register values will start to appear on 4th DCLK */ arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x8000, 0, 0), 0, NULL, 0); /* fetch NOP, LDM in DECODE stage */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* nothing fetched, LDM in EXECUTE stage (2nd cycle) (output data) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, pc, NULL, 0); /* nothing fetched, LDM in EXECUTE stage (3rd cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, LDM in EXECUTE stage (4th cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, LDM in EXECUTE stage (5th cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); } void arm9tdmi_branch_resume(struct target *target) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; arm9tdmi_clock_out(jtag_info, ARMV4_5_B(0xfffffc, 0), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); } static void arm9tdmi_branch_resume_thumb(struct target *target) { LOG_DEBUG("-"); struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; struct arm_jtag *jtag_info = &arm7_9->jtag_info; struct reg *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; /* LDMIA r0-15, [r0] at debug speed * register values will start to appear on 4th DCLK */ arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x1, 0, 0), 0, NULL, 0); /* fetch NOP, LDM in DECODE stage */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* nothing fetched, LDM in EXECUTE stage (2nd cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, buf_get_u32(arm->pc->value, 0, 32) | 1, NULL, 0); /* nothing fetched, LDM in EXECUTE stage (3rd cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* Branch and eXchange */ arm9tdmi_clock_out(jtag_info, ARMV4_5_BX(0), 0, NULL, 0); embeddedice_read_reg(dbg_stat); /* fetch NOP, BX in DECODE stage */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); embeddedice_read_reg(dbg_stat); /* fetch NOP, BX in EXECUTE stage (1st cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* target is now in Thumb state */ embeddedice_read_reg(dbg_stat); /* load r0 value, MOV_IM in Decode*/ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), 0, NULL, 0); /* fetch NOP, LDR in Decode, MOV_IM in Execute */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); /* fetch NOP, LDR in Execute */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); /* nothing fetched, LDR in EXECUTE stage (2nd cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32), NULL, 0); /* nothing fetched, LDR in EXECUTE stage (3rd cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); embeddedice_read_reg(dbg_stat); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_B(0x7f7), 0, NULL, 1); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); } void arm9tdmi_enable_single_step(struct target *target, uint32_t next_pc) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); if (arm7_9->has_single_step) { buf_set_u32(arm7_9->eice_cache->reg_list[EICE_DBG_CTRL].value, 3, 1, 1); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]); } else arm7_9_enable_eice_step(target, next_pc); } void arm9tdmi_disable_single_step(struct target *target) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); if (arm7_9->has_single_step) { buf_set_u32(arm7_9->eice_cache->reg_list[EICE_DBG_CTRL].value, 3, 1, 0); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]); } else arm7_9_disable_eice_step(target); } static void arm9tdmi_build_reg_cache(struct target *target) { struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); struct arm *arm = target_to_arm(target); (*cache_p) = arm_build_reg_cache(target, arm); } int arm9tdmi_init_target(struct command_context *cmd_ctx, struct target *target) { arm9tdmi_build_reg_cache(target); return ERROR_OK; } int arm9tdmi_init_arch_info(struct target *target, struct arm7_9_common *arm7_9, struct jtag_tap *tap) { /* prepare JTAG information for the new target */ arm7_9->jtag_info.tap = tap; arm7_9->jtag_info.scann_size = 5; /* register arch-specific functions */ arm7_9->examine_debug_reason = arm9tdmi_examine_debug_reason; arm7_9->change_to_arm = arm9tdmi_change_to_arm; arm7_9->read_core_regs = arm9tdmi_read_core_regs; arm7_9->read_core_regs_target_buffer = arm9tdmi_read_core_regs_target_buffer; arm7_9->read_xpsr = arm9tdmi_read_xpsr; arm7_9->write_xpsr = arm9tdmi_write_xpsr; arm7_9->write_xpsr_im8 = arm9tdmi_write_xpsr_im8; arm7_9->write_core_regs = arm9tdmi_write_core_regs; arm7_9->load_word_regs = arm9tdmi_load_word_regs; arm7_9->load_hword_reg = arm9tdmi_load_hword_reg; arm7_9->load_byte_reg = arm9tdmi_load_byte_reg; arm7_9->store_word_regs = arm9tdmi_store_word_regs; arm7_9->store_hword_reg = arm9tdmi_store_hword_reg; arm7_9->store_byte_reg = arm9tdmi_store_byte_reg; arm7_9->write_pc = arm9tdmi_write_pc; arm7_9->branch_resume = arm9tdmi_branch_resume; arm7_9->branch_resume_thumb = arm9tdmi_branch_resume_thumb; arm7_9->enable_single_step = arm9tdmi_enable_single_step; arm7_9->disable_single_step = arm9tdmi_disable_single_step; arm7_9->post_debug_entry = NULL; arm7_9->pre_restore_context = NULL; /* initialize arch-specific breakpoint handling */ arm7_9->arm_bkpt = 0xdeeedeee; arm7_9->thumb_bkpt = 0xdeee; arm7_9->dbgreq_adjust_pc = 3; arm7_9_init_arch_info(target, arm7_9); /* override use of DBGRQ, this is safe on ARM9TDMI */ arm7_9->use_dbgrq = 1; /* all ARM9s have the vector catch register */ arm7_9->has_vector_catch = 1; return ERROR_OK; } static int arm9tdmi_target_create(struct target *target, Jim_Interp *interp) { struct arm7_9_common *arm7_9 = calloc(1, sizeof(struct arm7_9_common)); arm9tdmi_init_arch_info(target, arm7_9, target->tap); arm7_9->arm.is_armv4 = true; return ERROR_OK; } COMMAND_HANDLER(handle_arm9tdmi_catch_vectors_command) { struct target *target = get_current_target(CMD_CTX); struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct reg *vector_catch; uint32_t vector_catch_value; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } /* it's uncommon, but some ARM7 chips can support this */ if (arm7_9->common_magic != ARM7_9_COMMON_MAGIC || !arm7_9->has_vector_catch) { command_print(CMD_CTX, "target doesn't have EmbeddedICE " "with vector_catch"); return ERROR_TARGET_INVALID; } vector_catch = &arm7_9->eice_cache->reg_list[EICE_VEC_CATCH]; /* read the vector catch register if necessary */ if (!vector_catch->valid) embeddedice_read_reg(vector_catch); /* get the current setting */ vector_catch_value = buf_get_u32(vector_catch->value, 0, 8); if (CMD_ARGC > 0) { vector_catch_value = 0x0; if (strcmp(CMD_ARGV[0], "all") == 0) vector_catch_value = 0xdf; else if (strcmp(CMD_ARGV[0], "none") == 0) { /* do nothing */ } else { for (unsigned i = 0; i < CMD_ARGC; i++) { /* go through list of vectors */ unsigned j; for (j = 0; arm9tdmi_vectors[j].name; j++) { if (strcmp(CMD_ARGV[i], arm9tdmi_vectors[j].name) == 0) { vector_catch_value |= arm9tdmi_vectors[j].value; break; } } /* complain if vector wasn't found */ if (!arm9tdmi_vectors[j].name) { command_print(CMD_CTX, "vector '%s' not found, leaving current setting unchanged", CMD_ARGV[i]); /* reread current setting */ vector_catch_value = buf_get_u32( vector_catch->value, 0, 8); break; } } } /* store new settings */ buf_set_u32(vector_catch->value, 0, 8, vector_catch_value); embeddedice_store_reg(vector_catch); } /* output current settings */ for (unsigned i = 0; arm9tdmi_vectors[i].name; i++) { command_print(CMD_CTX, "%s: %s", arm9tdmi_vectors[i].name, (vector_catch_value & arm9tdmi_vectors[i].value) ? "catch" : "don't catch"); } return ERROR_OK; } static const struct command_registration arm9tdmi_exec_command_handlers[] = { { .name = "vector_catch", .handler = handle_arm9tdmi_catch_vectors_command, .mode = COMMAND_EXEC, .help = "Display, after optionally updating, configuration " "of vector catch unit.", .usage = "[all|none|(reset|undef|swi|pabt|dabt|irq|fiq)*]", }, COMMAND_REGISTRATION_DONE }; const struct command_registration arm9tdmi_command_handlers[] = { { .chain = arm7_9_command_handlers, }, { .name = "arm9", .mode = COMMAND_ANY, .help = "arm9 command group", .usage = "", .chain = arm9tdmi_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; /** Holds methods for ARM9TDMI targets. */ struct target_type arm9tdmi_target = { .name = "arm9tdmi", .poll = arm7_9_poll, .arch_state = arm_arch_state, .target_request_data = arm7_9_target_request_data, .halt = arm7_9_halt, .resume = arm7_9_resume, .step = arm7_9_step, .assert_reset = arm7_9_assert_reset, .deassert_reset = arm7_9_deassert_reset, .soft_reset_halt = arm7_9_soft_reset_halt, .get_gdb_reg_list = arm_get_gdb_reg_list, .read_memory = arm7_9_read_memory, .write_memory = arm7_9_write_memory, .bulk_write_memory = arm7_9_bulk_write_memory, .checksum_memory = arm_checksum_memory, .blank_check_memory = arm_blank_check_memory, .run_algorithm = armv4_5_run_algorithm, .add_breakpoint = arm7_9_add_breakpoint, .remove_breakpoint = arm7_9_remove_breakpoint, .add_watchpoint = arm7_9_add_watchpoint, .remove_watchpoint = arm7_9_remove_watchpoint, .commands = arm9tdmi_command_handlers, .target_create = arm9tdmi_target_create, .init_target = arm9tdmi_init_target, .examine = arm7_9_examine, .check_reset = arm7_9_check_reset, }; openocd-0.7.0/src/target/avr32_ap7k.c0000644000175000001440000004107512137151331014166 00000000000000/*************************************************************************** * Copyright (C) 2010 by Oleksandr Tymoshenko * * Based on mips_m4k code: * * Copyright (C) 2008 by Spencer Oliver * * Copyright (C) 2008 by David T.L. Wong * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "jtag/jtag.h" #include "register.h" #include "algorithm.h" #include "target.h" #include "breakpoints.h" #include "target_type.h" #include "avr32_jtag.h" #include "avr32_mem.h" #include "avr32_regs.h" #include "avr32_ap7k.h" static char *avr32_core_reg_list[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc", "sr" }; static struct avr32_core_reg avr32_core_reg_list_arch_info[AVR32NUMCOREREGS] = { {0, NULL, NULL}, {1, NULL, NULL}, {2, NULL, NULL}, {3, NULL, NULL}, {4, NULL, NULL}, {5, NULL, NULL}, {6, NULL, NULL}, {7, NULL, NULL}, {8, NULL, NULL}, {9, NULL, NULL}, {10, NULL, NULL}, {11, NULL, NULL}, {12, NULL, NULL}, {13, NULL, NULL}, {14, NULL, NULL}, {15, NULL, NULL}, {16, NULL, NULL}, }; static int avr32_read_core_reg(struct target *target, int num); static int avr32_write_core_reg(struct target *target, int num); int avr32_ap7k_save_context(struct target *target) { int retval, i; struct avr32_ap7k_common *ap7k = target_to_ap7k(target); retval = avr32_jtag_read_regs(&ap7k->jtag, ap7k->core_regs); if (retval != ERROR_OK) return retval; for (i = 0; i < AVR32NUMCOREREGS; i++) { if (!ap7k->core_cache->reg_list[i].valid) avr32_read_core_reg(target, i); } return ERROR_OK; } int avr32_ap7k_restore_context(struct target *target) { int i; /* get pointers to arch-specific information */ struct avr32_ap7k_common *ap7k = target_to_ap7k(target); for (i = 0; i < AVR32NUMCOREREGS; i++) { if (ap7k->core_cache->reg_list[i].dirty) avr32_write_core_reg(target, i); } /* write core regs */ avr32_jtag_write_regs(&ap7k->jtag, ap7k->core_regs); return ERROR_OK; } static int avr32_read_core_reg(struct target *target, int num) { uint32_t reg_value; /* get pointers to arch-specific information */ struct avr32_ap7k_common *ap7k = target_to_ap7k(target); if ((num < 0) || (num >= AVR32NUMCOREREGS)) return ERROR_COMMAND_SYNTAX_ERROR; reg_value = ap7k->core_regs[num]; buf_set_u32(ap7k->core_cache->reg_list[num].value, 0, 32, reg_value); ap7k->core_cache->reg_list[num].valid = 1; ap7k->core_cache->reg_list[num].dirty = 0; return ERROR_OK; } static int avr32_write_core_reg(struct target *target, int num) { uint32_t reg_value; /* get pointers to arch-specific information */ struct avr32_ap7k_common *ap7k = target_to_ap7k(target); if ((num < 0) || (num >= AVR32NUMCOREREGS)) return ERROR_COMMAND_SYNTAX_ERROR; reg_value = buf_get_u32(ap7k->core_cache->reg_list[num].value, 0, 32); ap7k->core_regs[num] = reg_value; LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num, reg_value); ap7k->core_cache->reg_list[num].valid = 1; ap7k->core_cache->reg_list[num].dirty = 0; return ERROR_OK; } static int avr32_get_core_reg(struct reg *reg) { int retval; struct avr32_core_reg *avr32_reg = reg->arch_info; struct target *target = avr32_reg->target; if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; retval = avr32_read_core_reg(target, avr32_reg->num); return retval; } static int avr32_set_core_reg(struct reg *reg, uint8_t *buf) { struct avr32_core_reg *avr32_reg = reg->arch_info; struct target *target = avr32_reg->target; uint32_t value = buf_get_u32(buf, 0, 32); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; buf_set_u32(reg->value, 0, 32, value); reg->dirty = 1; reg->valid = 1; return ERROR_OK; } static const struct reg_arch_type avr32_reg_type = { .get = avr32_get_core_reg, .set = avr32_set_core_reg, }; static struct reg_cache *avr32_build_reg_cache(struct target *target) { int num_regs = AVR32NUMCOREREGS; struct avr32_ap7k_common *ap7k = target_to_ap7k(target); struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); struct reg_cache *cache = malloc(sizeof(struct reg_cache)); struct reg *reg_list = malloc(sizeof(struct reg) * num_regs); struct avr32_core_reg *arch_info = malloc(sizeof(struct avr32_core_reg) * num_regs); int i; /* Build the process context cache */ cache->name = "avr32 registers"; cache->next = NULL; cache->reg_list = reg_list; cache->num_regs = num_regs; (*cache_p) = cache; ap7k->core_cache = cache; for (i = 0; i < num_regs; i++) { arch_info[i] = avr32_core_reg_list_arch_info[i]; arch_info[i].target = target; arch_info[i].avr32_common = ap7k; reg_list[i].name = avr32_core_reg_list[i]; reg_list[i].size = 32; reg_list[i].value = calloc(1, 4); reg_list[i].dirty = 0; reg_list[i].valid = 0; reg_list[i].type = &avr32_reg_type; reg_list[i].arch_info = &arch_info[i]; } return cache; } static int avr32_ap7k_debug_entry(struct target *target) { uint32_t dpc, dinst; int retval; struct avr32_ap7k_common *ap7k = target_to_ap7k(target); retval = avr32_jtag_nexus_read(&ap7k->jtag, AVR32_OCDREG_DPC, &dpc); if (retval != ERROR_OK) return retval; retval = avr32_jtag_nexus_read(&ap7k->jtag, AVR32_OCDREG_DINST, &dinst); if (retval != ERROR_OK) return retval; ap7k->jtag.dpc = dpc; avr32_ap7k_save_context(target); return ERROR_OK; } static int avr32_ap7k_poll(struct target *target) { uint32_t ds; int retval; struct avr32_ap7k_common *ap7k = target_to_ap7k(target); retval = avr32_jtag_nexus_read(&ap7k->jtag, AVR32_OCDREG_DS, &ds); if (retval != ERROR_OK) return retval; /* check for processor halted */ if (ds & OCDREG_DS_DBA) { if ((target->state == TARGET_RUNNING) || (target->state == TARGET_RESET)) { target->state = TARGET_HALTED; retval = avr32_ap7k_debug_entry(target); if (retval != ERROR_OK) return retval; target_call_event_callbacks(target, TARGET_EVENT_HALTED); } else if (target->state == TARGET_DEBUG_RUNNING) { target->state = TARGET_HALTED; retval = avr32_ap7k_debug_entry(target); if (retval != ERROR_OK) return retval; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); } } else target->state = TARGET_RUNNING; return ERROR_OK; } static int avr32_ap7k_halt(struct target *target) { struct avr32_ap7k_common *ap7k = target_to_ap7k(target); LOG_DEBUG("target->state: %s", target_state_name(target)); if (target->state == TARGET_HALTED) { LOG_DEBUG("target was already halted"); return ERROR_OK; } if (target->state == TARGET_UNKNOWN) LOG_WARNING("target was in unknown state when halt was requested"); if (target->state == TARGET_RESET) { if ((jtag_get_reset_config() & RESET_SRST_PULLS_TRST) && jtag_get_srst()) { LOG_ERROR("can't request a halt while in reset if nSRST pulls nTRST"); return ERROR_TARGET_FAILURE; } else { target->debug_reason = DBG_REASON_DBGRQ; return ERROR_OK; } } avr32_ocd_setbits(&ap7k->jtag, AVR32_OCDREG_DC, OCDREG_DC_DBR); target->debug_reason = DBG_REASON_DBGRQ; return ERROR_OK; } static int avr32_ap7k_assert_reset(struct target *target) { LOG_ERROR("%s: implement me", __func__); return ERROR_OK; } static int avr32_ap7k_deassert_reset(struct target *target) { LOG_ERROR("%s: implement me", __func__); return ERROR_OK; } static int avr32_ap7k_soft_reset_halt(struct target *target) { LOG_ERROR("%s: implement me", __func__); return ERROR_OK; } static int avr32_ap7k_resume(struct target *target, int current, uint32_t address, int handle_breakpoints, int debug_execution) { struct avr32_ap7k_common *ap7k = target_to_ap7k(target); struct breakpoint *breakpoint = NULL; uint32_t resume_pc; int retval; if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!debug_execution) { target_free_all_working_areas(target); /* avr32_ap7k_enable_breakpoints(target); avr32_ap7k_enable_watchpoints(target); */ } /* current = 1: continue on current pc, otherwise continue at
*/ if (!current) { #if 0 if (retval != ERROR_OK) return retval; #endif } resume_pc = buf_get_u32(ap7k->core_cache->reg_list[AVR32_REG_PC].value, 0, 32); avr32_ap7k_restore_context(target); /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) { /* Single step past breakpoint at current address */ breakpoint = breakpoint_find(target, resume_pc); if (breakpoint) { LOG_DEBUG("unset breakpoint at 0x%8.8" PRIx32 "", breakpoint->address); #if 0 avr32_ap7k_unset_breakpoint(target, breakpoint); avr32_ap7k_single_step_core(target); avr32_ap7k_set_breakpoint(target, breakpoint); #endif } } #if 0 /* enable interrupts if we are running */ avr32_ap7k_enable_interrupts(target, !debug_execution); /* exit debug mode */ mips_ejtag_exit_debug(ejtag_info); #endif retval = avr32_ocd_clearbits(&ap7k->jtag, AVR32_OCDREG_DC, OCDREG_DC_DBR); if (retval != ERROR_OK) return retval; retval = avr32_jtag_exec(&ap7k->jtag, RETD); if (retval != ERROR_OK) return retval; target->debug_reason = DBG_REASON_NOTHALTED; /* registers are now invalid */ register_cache_invalidate(ap7k->core_cache); if (!debug_execution) { target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); LOG_DEBUG("target resumed at 0x%" PRIx32 "", resume_pc); } else { target->state = TARGET_DEBUG_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); LOG_DEBUG("target debug resumed at 0x%" PRIx32 "", resume_pc); } return ERROR_OK; } static int avr32_ap7k_step(struct target *target, int current, uint32_t address, int handle_breakpoints) { LOG_ERROR("%s: implement me", __func__); return ERROR_OK; } static int avr32_ap7k_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { LOG_ERROR("%s: implement me", __func__); return ERROR_OK; } static int avr32_ap7k_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { LOG_ERROR("%s: implement me", __func__); return ERROR_OK; } static int avr32_ap7k_add_watchpoint(struct target *target, struct watchpoint *watchpoint) { LOG_ERROR("%s: implement me", __func__); return ERROR_OK; } static int avr32_ap7k_remove_watchpoint(struct target *target, struct watchpoint *watchpoint) { LOG_ERROR("%s: implement me", __func__); return ERROR_OK; } static int avr32_ap7k_read_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct avr32_ap7k_common *ap7k = target_to_ap7k(target); LOG_DEBUG("address: 0x%8.8" PRIx32 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", address, size, count); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* sanitize arguments */ if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer)) return ERROR_COMMAND_SYNTAX_ERROR; if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) return ERROR_TARGET_UNALIGNED_ACCESS; switch (size) { case 4: return avr32_jtag_read_memory32(&ap7k->jtag, address, count, (uint32_t *)(void *)buffer); break; case 2: return avr32_jtag_read_memory16(&ap7k->jtag, address, count, (uint16_t *)(void *)buffer); break; case 1: return avr32_jtag_read_memory8(&ap7k->jtag, address, count, buffer); break; default: break; } return ERROR_OK; } static int avr32_ap7k_write_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct avr32_ap7k_common *ap7k = target_to_ap7k(target); LOG_DEBUG("address: 0x%8.8" PRIx32 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", address, size, count); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* sanitize arguments */ if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer)) return ERROR_COMMAND_SYNTAX_ERROR; if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) return ERROR_TARGET_UNALIGNED_ACCESS; switch (size) { case 4: return avr32_jtag_write_memory32(&ap7k->jtag, address, count, (uint32_t *)(void *)buffer); break; case 2: return avr32_jtag_write_memory16(&ap7k->jtag, address, count, (uint16_t *)(void *)buffer); break; case 1: return avr32_jtag_write_memory8(&ap7k->jtag, address, count, buffer); break; default: break; } return ERROR_OK; } static int avr32_ap7k_init_target(struct command_context *cmd_ctx, struct target *target) { struct avr32_ap7k_common *ap7k = target_to_ap7k(target); ap7k->jtag.tap = target->tap; avr32_build_reg_cache(target); return ERROR_OK; } static int avr32_ap7k_target_create(struct target *target, Jim_Interp *interp) { struct avr32_ap7k_common *ap7k = calloc(1, sizeof(struct avr32_ap7k_common)); ap7k->common_magic = AP7k_COMMON_MAGIC; target->arch_info = ap7k; return ERROR_OK; } static int avr32_ap7k_examine(struct target *target) { uint32_t devid, ds; struct avr32_ap7k_common *ap7k = target_to_ap7k(target); if (!target_was_examined(target)) { target_set_examined(target); avr32_jtag_nexus_read(&ap7k->jtag, AVR32_OCDREG_DID, &devid); LOG_INFO("device id: %08x", devid); avr32_ocd_setbits(&ap7k->jtag, AVR32_OCDREG_DC, OCDREG_DC_DBE); avr32_jtag_nexus_read(&ap7k->jtag, AVR32_OCDREG_DS, &ds); /* check for processor halted */ if (ds & OCDREG_DS_DBA) { LOG_INFO("target is halted"); target->state = TARGET_HALTED; } else target->state = TARGET_RUNNING; } return ERROR_OK; } int avr32_ap7k_arch_state(struct target *target) { struct avr32_ap7k_common *ap7k = target_to_ap7k(target); LOG_USER("target halted due to %s, pc: 0x%8.8" PRIx32 "", debug_reason_name(target), ap7k->jtag.dpc); return ERROR_OK; } int avr32_ap7k_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size) { #if 0 /* get pointers to arch-specific information */ int i; /* include floating point registers */ *reg_list_size = AVR32NUMCOREREGS + AVR32NUMFPREGS; *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); for (i = 0; i < AVR32NUMCOREREGS; i++) (*reg_list)[i] = &mips32->core_cache->reg_list[i]; /* add dummy floating points regs */ for (i = AVR32NUMCOREREGS; i < (AVR32NUMCOREREGS + AVR32NUMFPREGS); i++) (*reg_list)[i] = &avr32_ap7k_gdb_dummy_fp_reg; #endif LOG_ERROR("%s: implement me", __func__); return ERROR_FAIL; } struct target_type avr32_ap7k_target = { .name = "avr32_ap7k", .poll = avr32_ap7k_poll, .arch_state = avr32_ap7k_arch_state, .target_request_data = NULL, .halt = avr32_ap7k_halt, .resume = avr32_ap7k_resume, .step = avr32_ap7k_step, .assert_reset = avr32_ap7k_assert_reset, .deassert_reset = avr32_ap7k_deassert_reset, .soft_reset_halt = avr32_ap7k_soft_reset_halt, .get_gdb_reg_list = avr32_ap7k_get_gdb_reg_list, .read_memory = avr32_ap7k_read_memory, .write_memory = avr32_ap7k_write_memory, /* .checksum_memory = avr32_ap7k_checksum_memory, */ /* .blank_check_memory = avr32_ap7k_blank_check_memory, */ /* .run_algorithm = avr32_ap7k_run_algorithm, */ .add_breakpoint = avr32_ap7k_add_breakpoint, .remove_breakpoint = avr32_ap7k_remove_breakpoint, .add_watchpoint = avr32_ap7k_add_watchpoint, .remove_watchpoint = avr32_ap7k_remove_watchpoint, .target_create = avr32_ap7k_target_create, .init_target = avr32_ap7k_init_target, .examine = avr32_ap7k_examine, }; openocd-0.7.0/src/target/dsp5680xx.h0000644000175000001440000003525112134336410014004 00000000000000/*************************************************************************** * Copyright (C) 2011 by Rodrigo L. Rosa * * rodrigorosa.LG@gmail.com * * * * Based on dsp563xx_once.h written by Mathias Kuester * * mkdorg@users.sourceforge.net * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef DSP5680XX_H #define DSP5680XX_H #include /** * @file dsp5680xx.h * @author Rodrigo Rosa * @date Thu Jun 9 18:54:38 2011 * * @brief Basic support for the 5680xx DSP from Freescale. * The chip has two taps in the JTAG chain, the Master tap and the Core tap. * In this code the Master tap is only used to unlock the flash memory by executing a JTAG instruction. * */ #define S_FILE_DATA_OFFSET 0x200000 #define TIME_DIV_FREESCALE 0.3 /** ---------------------------------------------------------------- * JTAG *---------------------------------------------------------------- */ #define DSP5680XX_JTAG_CORE_TAP_IRLEN 4 #define DSP5680XX_JTAG_MASTER_TAP_IRLEN 8 #define JTAG_STATUS_MASK 0x0F #define JTAG_STATUS_NORMAL 0x01 #define JTAG_STATUS_STOPWAIT 0x05 #define JTAG_STATUS_BUSY 0x09 #define JTAG_STATUS_DEBUG 0x0D #define JTAG_STATUS_DEAD 0x0f #define JTAG_INSTR_EXTEST 0x0 #define JTAG_INSTR_SAMPLE_PRELOAD 0x1 #define JTAG_INSTR_IDCODE 0x2 #define JTAG_INSTR_EXTEST_PULLUP 0x3 #define JTAG_INSTR_HIGHZ 0x4 #define JTAG_INSTR_CLAMP 0x5 #define JTAG_INSTR_ENABLE_ONCE 0x6 #define JTAG_INSTR_DEBUG_REQUEST 0x7 #define JTAG_INSTR_BYPASS 0xF /** * ---------------------------------------------------------------- */ /** ---------------------------------------------------------------- * Master TAP instructions from MC56F8000RM.pdf * ---------------------------------------------------------------- */ #define MASTER_TAP_CMD_BYPASS 0xF #define MASTER_TAP_CMD_IDCODE 0x2 #define MASTER_TAP_CMD_TLM_SEL 0x5 #define MASTER_TAP_CMD_FLASH_ERASE 0x8 /** * ---------------------------------------------------------------- */ /** ---------------------------------------------------------------- * EOnCE control register info * ---------------------------------------------------------------- */ #define DSP5680XX_ONCE_OCR_EX (1<<5) /* EX Bit Definition 0 Remain in the Debug Processing State 1 Leave the Debug Processing State */ #define DSP5680XX_ONCE_OCR_GO (1<<6) /* GO Bit Definition 0 Inactive—No Action Taken 1 Execute Controller Instruction */ #define DSP5680XX_ONCE_OCR_RW (1<<7) /** RW Bit Definition * 0 Write To the Register Specified by the RS[4:0] Bits * 1 ReadFrom the Register Specified by the RS[4:0] Bits * ---------------------------------------------------------------- */ /** ---------------------------------------------------------------- * EOnCE Status Register * ---------------------------------------------------------------- */ #define DSP5680XX_ONCE_OSCR_OS1 (1<<5) #define DSP5680XX_ONCE_OSCR_OS0 (1<<4) /** * ---------------------------------------------------------------- */ /** ---------------------------------------------------------------- * EOnCE Core Status - Describes the operating status of the core controller * ---------------------------------------------------------------- */ #define DSP5680XX_ONCE_OSCR_NORMAL_M (0) /* 00 - Normal - Controller Core Executing Instructions or in Reset */ #define DSP5680XX_ONCE_OSCR_STOPWAIT_M (DSP5680XX_ONCE_OSCR_OS0) /* 01 - Stop/Wait - Controller Core in Stop or Wait Mode */ #define DSP5680XX_ONCE_OSCR_BUSY_M (DSP5680XX_ONCE_OSCR_OS1) /* 10 - Busy - Controller is Performing External or Peripheral Access (Wait States) */ #define DSP5680XX_ONCE_OSCR_DEBUG_M (DSP5680XX_ONCE_OSCR_OS0|DSP5680XX_ONCE_OSCR_OS1) /* 11 - Debug - Controller Core Halted and in Debug Mode */ #define EONCE_STAT_MASK 0x30 /** * ---------------------------------------------------------------- */ /** ---------------------------------------------------------------- * Register Select Encoding (eonce_rev.1.0_0208081.pdf:14) * ---------------------------------------------------------------- */ #define DSP5680XX_ONCE_NOREG 0x00 /* No register selected */ #define DSP5680XX_ONCE_OCR 0x01 /* OnCE Debug Control Register */ #define DSP5680XX_ONCE_OCNTR 0x02 /* OnCE Breakpoint and Trace Counter */ #define DSP5680XX_ONCE_OSR 0x03 /* EOnCE status register */ #define DSP5680XX_ONCE_OBAR 0x04 /* OnCE Breakpoint Address Register */ #define DSP5680XX_ONCE_OBASE 0x05 /* EOnCE Peripheral Base Address register */ #define DSP5680XX_ONCE_OTXRXSR 0x06 /* EOnCE TXRX Status and Control Register (OTXRXSR) */ #define DSP5680XX_ONCE_OTX 0x07 /* EOnCE Transmit register (OTX) */ #define DSP5680XX_ONCE_OPDBR 0x08 /* EOnCE Program Data Bus Register (OPDBR) */ #define DSP5680XX_ONCE_OTX1 0x09 /* EOnCE Upper Transmit register (OTX1) */ #define DSP5680XX_ONCE_OPABFR 0x0A /* OnCE Program Address Register—Fetch cycle */ #define DSP5680XX_ONCE_ORX 0x0B /* EOnCE Receive register (ORX) */ #define DSP5680XX_ONCE_OCNTR_C 0x0C /* Clear OCNTR */ #define DSP5680XX_ONCE_ORX1 0x0D /* EOnCE Upper Receive register (ORX1) */ #define DSP5680XX_ONCE_OTBCR 0x0E /* EOnCE Trace Buffer Control Reg (OTBCR) */ #define DSP5680XX_ONCE_OPABER 0x10 /* OnCE Program Address Register—Execute cycle */ #define DSP5680XX_ONCE_OPFIFO 0x11 /* OnCE Program address FIFO */ #define DSP5680XX_ONCE_OBAR1 0x12 /* EOnCE Breakpoint 1 Unit 0 Address Reg.(OBAR1) */ #define DSP5680XX_ONCE_OPABDR 0x13 /* OnCE Program Address Register—Decode cycle (OPABDR) */ /** * ---------------------------------------------------------------- */ #define FLUSH_COUNT_READ_WRITE 8192 /* This value works, higher values (and lower...) may work as well. */ #define FLUSH_COUNT_FLASH 8192 /** ---------------------------------------------------------------- * HFM (flash module) Commands (ref:MC56F801xRM.pdf:159) * ---------------------------------------------------------------- */ #define HFM_ERASE_VERIFY 0x05 #define HFM_CALCULATE_DATA_SIGNATURE 0x06 #define HFM_WORD_PROGRAM 0x20 #define HFM_PAGE_ERASE 0x40 #define HFM_MASS_ERASE 0x41 #define HFM_CALCULATE_IFR_BLOCK_SIGNATURE 0x66 /** * ---------------------------------------------------------------- */ /** ---------------------------------------------------------------- * Flashing (ref:MC56F801xRM.pdf:159) * ---------------------------------------------------------------- */ #define HFM_BASE_ADDR 0x0F400 /** In x: mem. (write to S_FILE_DATA_OFFSET+HFM_BASE_ADDR * to get data into x: mem.) */ /** * The following are register addresses, not memory * addresses (though all registers are memory mapped) */ #define HFM_CLK_DIV 0x00 /* r/w */ #define HFM_CNFG 0x01 /* r/w */ #define HFM_SECHI 0x03 /* r */ #define HFM_SECLO 0x04 /* r */ #define HFM_PROT 0x10 /* r/w */ #define HFM_PROTB 0x11 /* r/w */ #define HFM_USTAT 0x13 /* r/w */ #define HFM_CMD 0x14 /* r/w */ #define HFM_DATA 0x18 /* r */ #define HFM_OPT1 0x1B /* r */ #define HFM_TSTSIG 0x1D /* r */ #define HFM_EXEC_COMPLETE 0x40 /* User status register (USTAT) masks (MC56F80XXRM.pdf:6.7.5) */ #define HFM_USTAT_MASK_BLANK 0x4 #define HFM_USTAT_MASK_PVIOL_ACCER 0x30 /** * The value used on for the FM clock is important to prevent flashing errors and to prevent deterioration of the FM. * This value was calculated using a spreadsheet tool available on the Freescale website under FAQ 25464. * */ #define HFM_CLK_DEFAULT 0x27 /* 0x27 according to freescale cfg, but 0x40 according to freescale spreadsheet... */ #define HFM_FLASH_BASE_ADDR 0x0 #define HFM_SIZE_BYTES 0x4000 /* bytes */ #define HFM_SIZE_WORDS 0x2000 /* words */ #define HFM_SECTOR_SIZE 0x200 /* Size in bytes */ #define HFM_SECTOR_COUNT 0x20 /* A 16K block in pages of 256 words. */ /** * Writing HFM_LOCK_FLASH to HFM_LOCK_ADDR_L and HFM_LOCK_ADDR_H will enable security on flash after the next reset. */ #define HFM_LOCK_FLASH 0xE70A #define HFM_LOCK_ADDR_L 0x1FF7 #define HFM_LOCK_ADDR_H 0x1FF8 /** * ---------------------------------------------------------------- */ /** ---------------------------------------------------------------- * Register Memory Map (eonce_rev.1.0_0208081.pdf:16) * ---------------------------------------------------------------- */ #define MC568013_EONCE_OBASE_ADDR 0xFF /* The following are relative to EONCE_OBASE_ADDR (EONCE_OBASE_ADDR<<16 + ...) */ #define MC568013_EONCE_TX_RX_ADDR 0xFFFE #define MC568013_EONCE_TX1_RX1_HIGH_ADDR 0xFFFF /* Relative to EONCE_OBASE_ADDR */ #define MC568013_EONCE_OCR 0xFFA0 /* Relative to EONCE_OBASE_ADDR */ /** * ---------------------------------------------------------------- */ /** ---------------------------------------------------------------- * SIM addresses & commands (MC56F80xx.h from freescale) * ---------------------------------------------------------------- */ #define MC568013_SIM_BASE_ADDR 0xF140 #define MC56803x_2x_SIM_BASE_ADDR 0xF100 #define SIM_CMD_RESET 0x10 /** * ---------------------------------------------------------------- */ /** * ---------------------------------------------------------------- * ERROR codes - enable automatic parsing of output * ---------------------------------------------------------------- */ #define DSP5680XX_ERROR_UNKNOWN_OR_ERROR_OPENOCD -100 #define DSP5680XX_ERROR_JTAG_COMM -1 #define DSP5680XX_ERROR_JTAG_RESET -2 #define DSP5680XX_ERROR_JTAG_INVALID_TAP -3 #define DSP5680XX_ERROR_JTAG_DR_LEN_OVERFLOW -4 #define DSP5680XX_ERROR_INVALID_IR_LEN -5 #define DSP5680XX_ERROR_JTAG_TAP_ENABLE_MASTER -6 #define DSP5680XX_ERROR_JTAG_TAP_ENABLE_CORE -7 #define DSP5680XX_ERROR_JTAG_TAP_FIND_MASTER -8 #define DSP5680XX_ERROR_JTAG_TAP_FIND_CORE -9 #define DSP5680XX_ERROR_JTAG_DRSCAN -10 #define DSP5680XX_ERROR_JTAG_IRSCAN -11 #define DSP5680XX_ERROR_ENTER_DEBUG_MODE -12 #define DSP5680XX_ERROR_RESUME -13 #define DSP5680XX_ERROR_WRITE_WITH_TARGET_RUNNING -14 #define DSP5680XX_ERROR_INVALID_DATA_SIZE_UNIT -15 #define DSP5680XX_ERROR_PROTECT_CHECK_INVALID_ARGS -16 #define DSP5680XX_ERROR_FM_BUSY -17 #define DSP5680XX_ERROR_FM_CMD_TIMED_OUT -18 #define DSP5680XX_ERROR_FM_EXEC -19 #define DSP5680XX_ERROR_FM_SET_CLK -20 #define DSP5680XX_ERROR_FLASHING_INVALID_WORD_COUNT -21 #define DSP5680XX_ERROR_FLASHING_CRC -22 #define DSP5680XX_ERROR_FLASHING -23 #define DSP5680XX_ERROR_NOT_IMPLEMENTED_STEP -24 #define DSP5680XX_ERROR_HALT -25 #define DSP5680XX_ERROR_EXIT_DEBUG_MODE -26 #define DSP5680XX_ERROR_TARGET_RUNNING -27 #define DSP5680XX_ERROR_NOT_IN_DEBUG -28 /** * ---------------------------------------------------------------- */ struct dsp5680xx_common { uint32_t stored_pc; int flush; bool debug_mode_enabled; }; extern struct dsp5680xx_common dsp5680xx_context; static inline struct dsp5680xx_common *target_to_dsp5680xx(struct target *target) { return target->arch_info; } /** * Writes to flash memory. * Does not check if flash is erased, it's up to the user to erase the flash before running * this function. * The flashing algorithm runs from RAM, reading from a register to which this function * writes to. The algorithm is open loop, there is no control to verify that the FM read * the register before writing the next data. A closed loop approach was much slower, * and the current implementation does not fail, and if it did the crc check would detect it, * allowing to flash again. * * @param target * @param buffer * @param address Word addressing. * @param count In bytes. * @param is_flash_lock * * @return */ int dsp5680xx_f_wr(struct target *target, uint8_t * buffer, uint32_t address, uint32_t count, int is_flash_lock); /** * The FM has the functionality of checking if the flash array is erased. This function * executes it. It does not support individual sector analysis. * * @param target * @param erased * @param sector This parameter is ignored because the FM does not support checking if * individual sectors are erased. * * @return */ int dsp5680xx_f_erase_check(struct target *target, uint8_t * erased, uint32_t sector); /** * Erases either a sector or the complete flash array. If either the range first-last covers * the complete array or if first == 0 and last == 0 then a mass erase command is executed * on the FM. If not, then individual sectors are erased. * * @param target * @param first * @param last * * @return */ int dsp5680xx_f_erase(struct target *target, int first, int last); /** * Reads the memory mapped protection register. A 1 implies the sector is protected, * a 0 implies the sector is not protected. * * @param target * @param protected Data read from the protection register. * * @return */ int dsp5680xx_f_protect_check(struct target *target, uint16_t * protected); /** * Writes the flash security words with a specific value. The chip's security will be * enabled after the first reset following the execution of this function. * * @param target * * @return */ int dsp5680xx_f_lock(struct target *target); /** * Executes a mass erase command. The must be done from the Master tap. * It is up to the user to select the master tap (jtag tapenable dsp5680xx.chp) * before running this function. * The flash array will be unsecured (and erased) after the first reset following * the execution of this function. * * @param target * * @return */ int dsp5680xx_f_unlock(struct target *target); #endif /* DSP5680XX_H */ openocd-0.7.0/src/target/embeddedice.c0000644000175000001440000004424612134336410014524 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "embeddedice.h" #include "register.h" /** * @file * * This provides lowlevel glue to the EmbeddedICE (or EmbeddedICE-RT) * module found on scan chain 2 in ARM7, ARM9, and some other families * of ARM cores. The module is called "EmbeddedICE-RT" if it has * monitor mode support. * * EmbeddedICE provides basic watchpoint/breakpoint hardware and a Debug * Communications Channel (DCC) used to read or write 32-bit words to * OpenOCD-aware code running on the target CPU. * Newer modules also include vector catch hardware. Some versions * support hardware single-stepping, "monitor mode" debug (which is not * currently supported by OpenOCD), or extended reporting on why the * core entered debug mode. */ static int embeddedice_set_reg_w_exec(struct reg *reg, uint8_t *buf); /* * From: ARM9E-S TRM, DDI 0165, table C-4 (and similar, for other cores) */ static const struct { char *name; unsigned short addr; unsigned short width; } eice_regs[] = { [EICE_DBG_CTRL] = { .name = "debug_ctrl", .addr = 0, /* width is assigned based on EICE version */ }, [EICE_DBG_STAT] = { .name = "debug_status", .addr = 1, /* width is assigned based on EICE version */ }, [EICE_COMMS_CTRL] = { .name = "comms_ctrl", .addr = 4, .width = 6, }, [EICE_COMMS_DATA] = { .name = "comms_data", .addr = 5, .width = 32, }, [EICE_W0_ADDR_VALUE] = { .name = "watch_0_addr_value", .addr = 8, .width = 32, }, [EICE_W0_ADDR_MASK] = { .name = "watch_0_addr_mask", .addr = 9, .width = 32, }, [EICE_W0_DATA_VALUE] = { .name = "watch_0_data_value", .addr = 10, .width = 32, }, [EICE_W0_DATA_MASK] = { .name = "watch_0_data_mask", .addr = 11, .width = 32, }, [EICE_W0_CONTROL_VALUE] = { .name = "watch_0_control_value", .addr = 12, .width = 9, }, [EICE_W0_CONTROL_MASK] = { .name = "watch_0_control_mask", .addr = 13, .width = 8, }, [EICE_W1_ADDR_VALUE] = { .name = "watch_1_addr_value", .addr = 16, .width = 32, }, [EICE_W1_ADDR_MASK] = { .name = "watch_1_addr_mask", .addr = 17, .width = 32, }, [EICE_W1_DATA_VALUE] = { .name = "watch_1_data_value", .addr = 18, .width = 32, }, [EICE_W1_DATA_MASK] = { .name = "watch_1_data_mask", .addr = 19, .width = 32, }, [EICE_W1_CONTROL_VALUE] = { .name = "watch_1_control_value", .addr = 20, .width = 9, }, [EICE_W1_CONTROL_MASK] = { .name = "watch_1_control_mask", .addr = 21, .width = 8, }, /* vector_catch isn't always present */ [EICE_VEC_CATCH] = { .name = "vector_catch", .addr = 2, .width = 8, }, }; static int embeddedice_get_reg(struct reg *reg) { int retval = embeddedice_read_reg(reg); if (retval != ERROR_OK) { LOG_ERROR("error queueing EmbeddedICE register read"); return retval; } retval = jtag_execute_queue(); if (retval != ERROR_OK) LOG_ERROR("EmbeddedICE register read failed"); return retval; } static const struct reg_arch_type eice_reg_type = { .get = embeddedice_get_reg, .set = embeddedice_set_reg_w_exec, }; /** * Probe EmbeddedICE module and set up local records of its registers. * Different versions of the modules have different capabilities, such as * hardware support for vector_catch, single stepping, and monitor mode. */ struct reg_cache *embeddedice_build_reg_cache(struct target *target, struct arm7_9_common *arm7_9) { int retval; struct reg_cache *reg_cache = malloc(sizeof(struct reg_cache)); struct reg *reg_list = NULL; struct embeddedice_reg *arch_info = NULL; struct arm_jtag *jtag_info = &arm7_9->jtag_info; int num_regs = ARRAY_SIZE(eice_regs); int i; int eice_version = 0; /* vector_catch isn't always present */ if (!arm7_9->has_vector_catch) num_regs--; /* the actual registers are kept in two arrays */ reg_list = calloc(num_regs, sizeof(struct reg)); arch_info = calloc(num_regs, sizeof(struct embeddedice_reg)); /* fill in values for the reg cache */ reg_cache->name = "EmbeddedICE registers"; reg_cache->next = NULL; reg_cache->reg_list = reg_list; reg_cache->num_regs = num_regs; /* FIXME the second watchpoint unit on Feroceon and Dragonite * seems not to work ... we should have a way to not set up * its four registers here! */ /* set up registers */ for (i = 0; i < num_regs; i++) { reg_list[i].name = eice_regs[i].name; reg_list[i].size = eice_regs[i].width; reg_list[i].dirty = 0; reg_list[i].valid = 0; reg_list[i].value = calloc(1, 4); reg_list[i].arch_info = &arch_info[i]; reg_list[i].type = &eice_reg_type; arch_info[i].addr = eice_regs[i].addr; arch_info[i].jtag_info = jtag_info; } /* identify EmbeddedICE version by reading DCC control register */ embeddedice_read_reg(®_list[EICE_COMMS_CTRL]); retval = jtag_execute_queue(); if (retval != ERROR_OK) { for (i = 0; i < num_regs; i++) free(reg_list[i].value); free(reg_list); free(reg_cache); free(arch_info); return NULL; } eice_version = buf_get_u32(reg_list[EICE_COMMS_CTRL].value, 28, 4); LOG_INFO("Embedded ICE version %d", eice_version); switch (eice_version) { case 1: /* ARM7TDMI r3, ARM7TDMI-S r3 * * REVISIT docs say ARM7TDMI-S r4 uses version 1 but * that it has 6-bit CTRL and 5-bit STAT... doc bug? * ARM7TDMI r4 docs say EICE v4. */ reg_list[EICE_DBG_CTRL].size = 3; reg_list[EICE_DBG_STAT].size = 5; break; case 2: /* ARM9TDMI */ reg_list[EICE_DBG_CTRL].size = 4; reg_list[EICE_DBG_STAT].size = 5; arm7_9->has_single_step = 1; break; case 3: LOG_ERROR("EmbeddedICE v%d handling might be broken", eice_version); reg_list[EICE_DBG_CTRL].size = 6; reg_list[EICE_DBG_STAT].size = 5; arm7_9->has_single_step = 1; arm7_9->has_monitor_mode = 1; break; case 4: /* ARM7TDMI r4 */ reg_list[EICE_DBG_CTRL].size = 6; reg_list[EICE_DBG_STAT].size = 5; arm7_9->has_monitor_mode = 1; break; case 5: /* ARM9E-S rev 1 */ reg_list[EICE_DBG_CTRL].size = 6; reg_list[EICE_DBG_STAT].size = 5; arm7_9->has_single_step = 1; arm7_9->has_monitor_mode = 1; break; case 6: /* ARM7EJ-S, ARM9E-S rev 2, ARM9EJ-S */ reg_list[EICE_DBG_CTRL].size = 6; reg_list[EICE_DBG_STAT].size = 10; /* DBG_STAT has MOE bits */ arm7_9->has_monitor_mode = 1; break; case 7: LOG_ERROR("EmbeddedICE v%d handling might be broken", eice_version); reg_list[EICE_DBG_CTRL].size = 6; reg_list[EICE_DBG_STAT].size = 5; arm7_9->has_monitor_mode = 1; break; default: /* * The Feroceon implementation has the version number * in some unusual bits. Let feroceon.c validate it * and do the appropriate setup itself. */ if (strcmp(target_type_name(target), "feroceon") == 0 || strcmp(target_type_name(target), "dragonite") == 0) break; LOG_ERROR("unknown EmbeddedICE version " "(comms ctrl: 0x%8.8" PRIx32 ")", buf_get_u32(reg_list[EICE_COMMS_CTRL].value, 0, 32)); } /* On Feroceon and Dragonite the second unit is seemingly missing. */ LOG_INFO("%s: hardware has %d breakpoint/watchpoint unit%s", target_name(target), arm7_9->wp_available_max, (arm7_9->wp_available_max != 1) ? "s" : ""); return reg_cache; } /** * Initialize EmbeddedICE module, if needed. */ int embeddedice_setup(struct target *target) { int retval; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); /* Explicitly disable monitor mode. For now we only support halting * debug ... we don't know how to talk with a resident debug monitor * that manages break requests. ARM's "Angel Debug Monitor" is one * common example of such code. */ if (arm7_9->has_monitor_mode) { struct reg *dbg_ctrl = &arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]; embeddedice_read_reg(dbg_ctrl); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; buf_set_u32(dbg_ctrl->value, 4, 1, 0); embeddedice_set_reg_w_exec(dbg_ctrl, dbg_ctrl->value); } return jtag_execute_queue(); } /** * Queue a read for an EmbeddedICE register into the register cache, * optionally checking the value read. * Note that at this level, all registers are 32 bits wide. */ int embeddedice_read_reg_w_check(struct reg *reg, uint8_t *check_value, uint8_t *check_mask) { struct embeddedice_reg *ice_reg = reg->arch_info; uint8_t reg_addr = ice_reg->addr & 0x1f; struct scan_field fields[3]; uint8_t field1_out[1]; uint8_t field2_out[1]; int retval; retval = arm_jtag_scann(ice_reg->jtag_info, 0x2, TAP_IDLE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(ice_reg->jtag_info, ice_reg->jtag_info->intest_instr, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; /* bits 31:0 -- data (ignored here) */ fields[0].num_bits = 32; fields[0].out_value = reg->value; fields[0].in_value = NULL; fields[0].check_value = NULL; fields[0].check_mask = NULL; /* bits 36:32 -- register */ fields[1].num_bits = 5; fields[1].out_value = field1_out; field1_out[0] = reg_addr; fields[1].in_value = NULL; fields[1].check_value = NULL; fields[1].check_mask = NULL; /* bit 37 -- 0/read */ fields[2].num_bits = 1; fields[2].out_value = field2_out; field2_out[0] = 0; fields[2].in_value = NULL; fields[2].check_value = NULL; fields[2].check_mask = NULL; /* traverse Update-DR, setting address for the next read */ jtag_add_dr_scan(ice_reg->jtag_info->tap, 3, fields, TAP_IDLE); /* bits 31:0 -- the data we're reading (and maybe checking) */ fields[0].in_value = reg->value; fields[0].check_value = check_value; fields[0].check_mask = check_mask; /* when reading the DCC data register, leaving the address field set to * EICE_COMMS_DATA would read the register twice * reading the control register is safe */ field1_out[0] = eice_regs[EICE_COMMS_CTRL].addr; /* traverse Update-DR, reading but with no other side effects */ jtag_add_dr_scan_check(ice_reg->jtag_info->tap, 3, fields, TAP_IDLE); return ERROR_OK; } /** * Receive a block of size 32-bit words from the DCC. * We assume the target is always going to be fast enough (relative to * the JTAG clock) that the debugger won't need to poll the handshake * bit. The JTAG clock is usually at least six times slower than the * functional clock, so the 50+ JTAG clocks needed to receive the word * allow hundreds of instruction cycles (per word) in the target. */ int embeddedice_receive(struct arm_jtag *jtag_info, uint32_t *data, uint32_t size) { struct scan_field fields[3]; uint8_t field1_out[1]; uint8_t field2_out[1]; int retval; retval = arm_jtag_scann(jtag_info, 0x2, TAP_IDLE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 32; fields[0].out_value = NULL; fields[0].in_value = NULL; fields[1].num_bits = 5; fields[1].out_value = field1_out; field1_out[0] = eice_regs[EICE_COMMS_DATA].addr; fields[1].in_value = NULL; fields[2].num_bits = 1; fields[2].out_value = field2_out; field2_out[0] = 0; fields[2].in_value = NULL; jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE); while (size > 0) { /* when reading the last item, set the register address to the DCC control reg, * to avoid reading additional data from the DCC data reg */ if (size == 1) field1_out[0] = eice_regs[EICE_COMMS_CTRL].addr; fields[0].in_value = (uint8_t *)data; jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE); jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t)data); data++; size--; } return jtag_execute_queue(); } /** * Queue a read for an EmbeddedICE register into the register cache, * not checking the value read. */ int embeddedice_read_reg(struct reg *reg) { return embeddedice_read_reg_w_check(reg, NULL, NULL); } /** * Queue a write for an EmbeddedICE register, updating the register cache. * Uses embeddedice_write_reg(). */ void embeddedice_set_reg(struct reg *reg, uint32_t value) { embeddedice_write_reg(reg, value); buf_set_u32(reg->value, 0, reg->size, value); reg->valid = 1; reg->dirty = 0; } /** * Write an EmbeddedICE register, updating the register cache. * Uses embeddedice_set_reg(); not queued. */ static int embeddedice_set_reg_w_exec(struct reg *reg, uint8_t *buf) { int retval; embeddedice_set_reg(reg, buf_get_u32(buf, 0, reg->size)); retval = jtag_execute_queue(); if (retval != ERROR_OK) LOG_ERROR("register write failed"); return retval; } /** * Queue a write for an EmbeddedICE register, bypassing the register cache. */ void embeddedice_write_reg(struct reg *reg, uint32_t value) { struct embeddedice_reg *ice_reg = reg->arch_info; LOG_DEBUG("%i: 0x%8.8" PRIx32 "", ice_reg->addr, value); arm_jtag_scann(ice_reg->jtag_info, 0x2, TAP_IDLE); arm_jtag_set_instr(ice_reg->jtag_info, ice_reg->jtag_info->intest_instr, NULL, TAP_IDLE); uint8_t reg_addr = ice_reg->addr & 0x1f; embeddedice_write_reg_inner(ice_reg->jtag_info->tap, reg_addr, value); } /** * Queue a write for an EmbeddedICE register, using cached value. * Uses embeddedice_write_reg(). */ void embeddedice_store_reg(struct reg *reg) { embeddedice_write_reg(reg, buf_get_u32(reg->value, 0, reg->size)); } /** * Send a block of size 32-bit words to the DCC. * We assume the target is always going to be fast enough (relative to * the JTAG clock) that the debugger won't need to poll the handshake * bit. The JTAG clock is usually at least six times slower than the * functional clock, so the 50+ JTAG clocks needed to receive the word * allow hundreds of instruction cycles (per word) in the target. */ int embeddedice_send(struct arm_jtag *jtag_info, uint32_t *data, uint32_t size) { struct scan_field fields[3]; uint8_t field0_out[4]; uint8_t field1_out[1]; uint8_t field2_out[1]; int retval; retval = arm_jtag_scann(jtag_info, 0x2, TAP_IDLE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 32; fields[0].out_value = field0_out; fields[0].in_value = NULL; fields[1].num_bits = 5; fields[1].out_value = field1_out; field1_out[0] = eice_regs[EICE_COMMS_DATA].addr; fields[1].in_value = NULL; fields[2].num_bits = 1; fields[2].out_value = field2_out; field2_out[0] = 1; fields[2].in_value = NULL; while (size > 0) { buf_set_u32(field0_out, 0, 32, *data); jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE); data++; size--; } /* call to jtag_execute_queue() intentionally omitted */ return ERROR_OK; } /** * Poll DCC control register until read or write handshake completes. */ int embeddedice_handshake(struct arm_jtag *jtag_info, int hsbit, uint32_t timeout) { struct scan_field fields[3]; uint8_t field0_in[4]; uint8_t field1_out[1]; uint8_t field2_out[1]; int retval; uint32_t hsact; struct timeval lap; struct timeval now; if (hsbit == EICE_COMM_CTRL_WBIT) hsact = 1; else if (hsbit == EICE_COMM_CTRL_RBIT) hsact = 0; else { LOG_ERROR("Invalid arguments"); return ERROR_COMMAND_SYNTAX_ERROR; } retval = arm_jtag_scann(jtag_info, 0x2, TAP_IDLE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 32; fields[0].out_value = NULL; fields[0].in_value = field0_in; fields[1].num_bits = 5; fields[1].out_value = field1_out; field1_out[0] = eice_regs[EICE_COMMS_DATA].addr; fields[1].in_value = NULL; fields[2].num_bits = 1; fields[2].out_value = field2_out; field2_out[0] = 0; fields[2].in_value = NULL; jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE); gettimeofday(&lap, NULL); do { jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (buf_get_u32(field0_in, hsbit, 1) == hsact) return ERROR_OK; gettimeofday(&now, NULL); } while ((uint32_t)((now.tv_sec - lap.tv_sec) * 1000 + (now.tv_usec - lap.tv_usec) / 1000) <= timeout); LOG_ERROR("embeddedice handshake timeout"); return ERROR_TARGET_TIMEOUT; } #ifndef HAVE_JTAG_MINIDRIVER_H /** * This is an inner loop of the open loop DCC write of data to target */ void embeddedice_write_dcc(struct jtag_tap *tap, int reg_addr, const uint8_t *buffer, int little, int count) { int i; for (i = 0; i < count; i++) { embeddedice_write_reg_inner(tap, reg_addr, fast_target_buffer_get_u32(buffer, little)); buffer += 4; } } #else /* provided by minidriver */ #endif openocd-0.7.0/src/target/etm_dummy.h0000644000175000001440000000310312134336410014302 00000000000000/*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef ETM_DUMMY_H #define ETM_DUMMY_H #include "etm.h" extern struct etm_capture_driver etm_dummy_capture_driver; #endif /* ETB_H */ openocd-0.7.0/src/target/armv4_5.c0000644000175000001440000012166112137151331013564 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2008 by Oyvind Harboe * * oyvind.harboe@zylin.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm.h" #include "armv4_5.h" #include "arm_jtag.h" #include "breakpoints.h" #include "arm_disassembler.h" #include #include "algorithm.h" #include "register.h" /* offsets into armv4_5 core register cache */ enum { /* ARMV4_5_CPSR = 31, */ ARMV4_5_SPSR_FIQ = 32, ARMV4_5_SPSR_IRQ = 33, ARMV4_5_SPSR_SVC = 34, ARMV4_5_SPSR_ABT = 35, ARMV4_5_SPSR_UND = 36, ARM_SPSR_MON = 39, }; static const uint8_t arm_usr_indices[17] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, ARMV4_5_CPSR, }; static const uint8_t arm_fiq_indices[8] = { 16, 17, 18, 19, 20, 21, 22, ARMV4_5_SPSR_FIQ, }; static const uint8_t arm_irq_indices[3] = { 23, 24, ARMV4_5_SPSR_IRQ, }; static const uint8_t arm_svc_indices[3] = { 25, 26, ARMV4_5_SPSR_SVC, }; static const uint8_t arm_abt_indices[3] = { 27, 28, ARMV4_5_SPSR_ABT, }; static const uint8_t arm_und_indices[3] = { 29, 30, ARMV4_5_SPSR_UND, }; static const uint8_t arm_mon_indices[3] = { 37, 38, ARM_SPSR_MON, }; static const struct { const char *name; unsigned short psr; /* For user and system modes, these list indices for all registers. * otherwise they're just indices for the shadow registers and SPSR. */ unsigned short n_indices; const uint8_t *indices; } arm_mode_data[] = { /* Seven modes are standard from ARM7 on. "System" and "User" share * the same registers; other modes shadow from 3 to 8 registers. */ { .name = "User", .psr = ARM_MODE_USR, .n_indices = ARRAY_SIZE(arm_usr_indices), .indices = arm_usr_indices, }, { .name = "FIQ", .psr = ARM_MODE_FIQ, .n_indices = ARRAY_SIZE(arm_fiq_indices), .indices = arm_fiq_indices, }, { .name = "Supervisor", .psr = ARM_MODE_SVC, .n_indices = ARRAY_SIZE(arm_svc_indices), .indices = arm_svc_indices, }, { .name = "Abort", .psr = ARM_MODE_ABT, .n_indices = ARRAY_SIZE(arm_abt_indices), .indices = arm_abt_indices, }, { .name = "IRQ", .psr = ARM_MODE_IRQ, .n_indices = ARRAY_SIZE(arm_irq_indices), .indices = arm_irq_indices, }, { .name = "Undefined instruction", .psr = ARM_MODE_UND, .n_indices = ARRAY_SIZE(arm_und_indices), .indices = arm_und_indices, }, { .name = "System", .psr = ARM_MODE_SYS, .n_indices = ARRAY_SIZE(arm_usr_indices), .indices = arm_usr_indices, }, /* TrustZone "Security Extensions" add a secure monitor mode. * This is distinct from a "debug monitor" which can support * non-halting debug, in conjunction with some debuggers. */ { .name = "Secure Monitor", .psr = ARM_MODE_MON, .n_indices = ARRAY_SIZE(arm_mon_indices), .indices = arm_mon_indices, }, /* These special modes are currently only supported * by ARMv6M and ARMv7M profiles */ { .name = "Thread", .psr = ARM_MODE_THREAD, }, { .name = "Thread (User)", .psr = ARM_MODE_USER_THREAD, }, { .name = "Handler", .psr = ARM_MODE_HANDLER, }, }; /** Map PSR mode bits to the name of an ARM processor operating mode. */ const char *arm_mode_name(unsigned psr_mode) { for (unsigned i = 0; i < ARRAY_SIZE(arm_mode_data); i++) { if (arm_mode_data[i].psr == psr_mode) return arm_mode_data[i].name; } LOG_ERROR("unrecognized psr mode: %#02x", psr_mode); return "UNRECOGNIZED"; } /** Return true iff the parameter denotes a valid ARM processor mode. */ bool is_arm_mode(unsigned psr_mode) { for (unsigned i = 0; i < ARRAY_SIZE(arm_mode_data); i++) { if (arm_mode_data[i].psr == psr_mode) return true; } return false; } /** Map PSR mode bits to linear number indexing armv4_5_core_reg_map */ int arm_mode_to_number(enum arm_mode mode) { switch (mode) { case ARM_MODE_ANY: /* map MODE_ANY to user mode */ case ARM_MODE_USR: return 0; case ARM_MODE_FIQ: return 1; case ARM_MODE_IRQ: return 2; case ARM_MODE_SVC: return 3; case ARM_MODE_ABT: return 4; case ARM_MODE_UND: return 5; case ARM_MODE_SYS: return 6; case ARM_MODE_MON: return 7; default: LOG_ERROR("invalid mode value encountered %d", mode); return -1; } } /** Map linear number indexing armv4_5_core_reg_map to PSR mode bits. */ enum arm_mode armv4_5_number_to_mode(int number) { switch (number) { case 0: return ARM_MODE_USR; case 1: return ARM_MODE_FIQ; case 2: return ARM_MODE_IRQ; case 3: return ARM_MODE_SVC; case 4: return ARM_MODE_ABT; case 5: return ARM_MODE_UND; case 6: return ARM_MODE_SYS; case 7: return ARM_MODE_MON; default: LOG_ERROR("mode index out of bounds %d", number); return ARM_MODE_ANY; } } static const char *arm_state_strings[] = { "ARM", "Thumb", "Jazelle", "ThumbEE", }; /* Templates for ARM core registers. * * NOTE: offsets in this table are coupled to the arm_mode_data * table above, the armv4_5_core_reg_map array below, and also to * the ARMV4_5_CPSR symbol (which should vanish after ARM11 updates). */ static const struct { /* The name is used for e.g. the "regs" command. */ const char *name; /* The {cookie, mode} tuple uniquely identifies one register. * In a given mode, cookies 0..15 map to registers R0..R15, * with R13..R15 usually called SP, LR, PC. * * MODE_ANY is used as *input* to the mapping, and indicates * various special cases (sigh) and errors. * * Cookie 16 is (currently) confusing, since it indicates * CPSR -or- SPSR depending on whether 'mode' is MODE_ANY. * (Exception modes have both CPSR and SPSR registers ...) */ unsigned cookie; enum arm_mode mode; } arm_core_regs[] = { /* IMPORTANT: we guarantee that the first eight cached registers * correspond to r0..r7, and the fifteenth to PC, so that callers * don't need to map them. */ { .name = "r0", .cookie = 0, .mode = ARM_MODE_ANY, }, { .name = "r1", .cookie = 1, .mode = ARM_MODE_ANY, }, { .name = "r2", .cookie = 2, .mode = ARM_MODE_ANY, }, { .name = "r3", .cookie = 3, .mode = ARM_MODE_ANY, }, { .name = "r4", .cookie = 4, .mode = ARM_MODE_ANY, }, { .name = "r5", .cookie = 5, .mode = ARM_MODE_ANY, }, { .name = "r6", .cookie = 6, .mode = ARM_MODE_ANY, }, { .name = "r7", .cookie = 7, .mode = ARM_MODE_ANY, }, /* NOTE: regs 8..12 might be shadowed by FIQ ... flagging * them as MODE_ANY creates special cases. (ANY means * "not mapped" elsewhere; here it's "everything but FIQ".) */ { .name = "r8", .cookie = 8, .mode = ARM_MODE_ANY, }, { .name = "r9", .cookie = 9, .mode = ARM_MODE_ANY, }, { .name = "r10", .cookie = 10, .mode = ARM_MODE_ANY, }, { .name = "r11", .cookie = 11, .mode = ARM_MODE_ANY, }, { .name = "r12", .cookie = 12, .mode = ARM_MODE_ANY, }, /* NOTE all MODE_USR registers are equivalent to MODE_SYS ones */ { .name = "sp_usr", .cookie = 13, .mode = ARM_MODE_USR, }, { .name = "lr_usr", .cookie = 14, .mode = ARM_MODE_USR, }, /* guaranteed to be at index 15 */ { .name = "pc", .cookie = 15, .mode = ARM_MODE_ANY, }, { .name = "r8_fiq", .cookie = 8, .mode = ARM_MODE_FIQ, }, { .name = "r9_fiq", .cookie = 9, .mode = ARM_MODE_FIQ, }, { .name = "r10_fiq", .cookie = 10, .mode = ARM_MODE_FIQ, }, { .name = "r11_fiq", .cookie = 11, .mode = ARM_MODE_FIQ, }, { .name = "r12_fiq", .cookie = 12, .mode = ARM_MODE_FIQ, }, { .name = "sp_fiq", .cookie = 13, .mode = ARM_MODE_FIQ, }, { .name = "lr_fiq", .cookie = 14, .mode = ARM_MODE_FIQ, }, { .name = "sp_irq", .cookie = 13, .mode = ARM_MODE_IRQ, }, { .name = "lr_irq", .cookie = 14, .mode = ARM_MODE_IRQ, }, { .name = "sp_svc", .cookie = 13, .mode = ARM_MODE_SVC, }, { .name = "lr_svc", .cookie = 14, .mode = ARM_MODE_SVC, }, { .name = "sp_abt", .cookie = 13, .mode = ARM_MODE_ABT, }, { .name = "lr_abt", .cookie = 14, .mode = ARM_MODE_ABT, }, { .name = "sp_und", .cookie = 13, .mode = ARM_MODE_UND, }, { .name = "lr_und", .cookie = 14, .mode = ARM_MODE_UND, }, { .name = "cpsr", .cookie = 16, .mode = ARM_MODE_ANY, }, { .name = "spsr_fiq", .cookie = 16, .mode = ARM_MODE_FIQ, }, { .name = "spsr_irq", .cookie = 16, .mode = ARM_MODE_IRQ, }, { .name = "spsr_svc", .cookie = 16, .mode = ARM_MODE_SVC, }, { .name = "spsr_abt", .cookie = 16, .mode = ARM_MODE_ABT, }, { .name = "spsr_und", .cookie = 16, .mode = ARM_MODE_UND, }, { .name = "sp_mon", .cookie = 13, .mode = ARM_MODE_MON, }, { .name = "lr_mon", .cookie = 14, .mode = ARM_MODE_MON, }, { .name = "spsr_mon", .cookie = 16, .mode = ARM_MODE_MON, }, }; /* map core mode (USR, FIQ, ...) and register number to * indices into the register cache */ const int armv4_5_core_reg_map[8][17] = { { /* USR */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 31 }, { /* FIQ (8 shadows of USR, vs normal 3) */ 0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 15, 32 }, { /* IRQ */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 23, 24, 15, 33 }, { /* SVC */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 25, 26, 15, 34 }, { /* ABT */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 27, 28, 15, 35 }, { /* UND */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 29, 30, 15, 36 }, { /* SYS (same registers as USR) */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 31 }, { /* MON */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 37, 38, 15, 39, } }; /** * Configures host-side ARM records to reflect the specified CPSR. * Later, code can use arm_reg_current() to map register numbers * according to how they are exposed by this mode. */ void arm_set_cpsr(struct arm *arm, uint32_t cpsr) { enum arm_mode mode = cpsr & 0x1f; int num; /* NOTE: this may be called very early, before the register * cache is set up. We can't defend against many errors, in * particular against CPSRs that aren't valid *here* ... */ if (arm->cpsr) { buf_set_u32(arm->cpsr->value, 0, 32, cpsr); arm->cpsr->valid = 1; arm->cpsr->dirty = 0; } arm->core_mode = mode; /* mode_to_number() warned; set up a somewhat-sane mapping */ num = arm_mode_to_number(mode); if (num < 0) { mode = ARM_MODE_USR; num = 0; } arm->map = &armv4_5_core_reg_map[num][0]; arm->spsr = (mode == ARM_MODE_USR || mode == ARM_MODE_SYS) ? NULL : arm->core_cache->reg_list + arm->map[16]; /* Older ARMs won't have the J bit */ enum arm_state state; if (cpsr & (1 << 5)) { /* T */ if (cpsr & (1 << 24)) { /* J */ LOG_WARNING("ThumbEE -- incomplete support"); state = ARM_STATE_THUMB_EE; } else state = ARM_STATE_THUMB; } else { if (cpsr & (1 << 24)) { /* J */ LOG_ERROR("Jazelle state handling is BROKEN!"); state = ARM_STATE_JAZELLE; } else state = ARM_STATE_ARM; } arm->core_state = state; LOG_DEBUG("set CPSR %#8.8x: %s mode, %s state", (unsigned) cpsr, arm_mode_name(mode), arm_state_strings[arm->core_state]); } /** * Returns handle to the register currently mapped to a given number. * Someone must have called arm_set_cpsr() before. * * \param arm This core's state and registers are used. * \param regnum From 0..15 corresponding to R0..R14 and PC. * Note that R0..R7 don't require mapping; you may access those * as the first eight entries in the register cache. Likewise * R15 (PC) doesn't need mapping; you may also access it directly. * However, R8..R14, and SPSR (arm->spsr) *must* be mapped. * CPSR (arm->cpsr) is also not mapped. */ struct reg *arm_reg_current(struct arm *arm, unsigned regnum) { struct reg *r; if (regnum > 16) return NULL; r = arm->core_cache->reg_list + arm->map[regnum]; /* e.g. invalid CPSR said "secure monitor" mode on a core * that doesn't support it... */ if (!r) { LOG_ERROR("Invalid CPSR mode"); r = arm->core_cache->reg_list + regnum; } return r; } static const uint8_t arm_gdb_dummy_fp_value[12]; /** * Dummy FPA registers are required to support GDB on ARM. * Register packets require eight obsolete FPA register values. * Modern ARM cores use Vector Floating Point (VFP), if they * have any floating point support. VFP is not FPA-compatible. */ struct reg arm_gdb_dummy_fp_reg = { .name = "GDB dummy FPA register", .value = (uint8_t *) arm_gdb_dummy_fp_value, .valid = 1, .size = 96, }; static const uint8_t arm_gdb_dummy_fps_value[4]; /** * Dummy FPA status registers are required to support GDB on ARM. * Register packets require an obsolete FPA status register. */ struct reg arm_gdb_dummy_fps_reg = { .name = "GDB dummy FPA status register", .value = (uint8_t *) arm_gdb_dummy_fps_value, .valid = 1, .size = 32, }; static void arm_gdb_dummy_init(void) __attribute__ ((constructor)); static void arm_gdb_dummy_init(void) { register_init_dummy(&arm_gdb_dummy_fp_reg); register_init_dummy(&arm_gdb_dummy_fps_reg); } static int armv4_5_get_core_reg(struct reg *reg) { int retval; struct arm_reg *reg_arch_info = reg->arch_info; struct target *target = reg_arch_info->target; if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } retval = reg_arch_info->arm->read_core_reg(target, reg, reg_arch_info->num, reg_arch_info->mode); if (retval == ERROR_OK) { reg->valid = 1; reg->dirty = 0; } return retval; } static int armv4_5_set_core_reg(struct reg *reg, uint8_t *buf) { struct arm_reg *reg_arch_info = reg->arch_info; struct target *target = reg_arch_info->target; struct arm *armv4_5_target = target_to_arm(target); uint32_t value = buf_get_u32(buf, 0, 32); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Except for CPSR, the "reg" command exposes a writeback model * for the register cache. */ if (reg == armv4_5_target->cpsr) { arm_set_cpsr(armv4_5_target, value); /* Older cores need help to be in ARM mode during halt * mode debug, so we clear the J and T bits if we flush. * For newer cores (v6/v7a/v7r) we don't need that, but * it won't hurt since CPSR is always flushed anyway. */ if (armv4_5_target->core_mode != (enum arm_mode)(value & 0x1f)) { LOG_DEBUG("changing ARM core mode to '%s'", arm_mode_name(value & 0x1f)); value &= ~((1 << 24) | (1 << 5)); armv4_5_target->write_core_reg(target, reg, 16, ARM_MODE_ANY, value); } } else { buf_set_u32(reg->value, 0, 32, value); reg->valid = 1; } reg->dirty = 1; return ERROR_OK; } static const struct reg_arch_type arm_reg_type = { .get = armv4_5_get_core_reg, .set = armv4_5_set_core_reg, }; struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm) { int num_regs = ARRAY_SIZE(arm_core_regs); struct reg_cache *cache = malloc(sizeof(struct reg_cache)); struct reg *reg_list = calloc(num_regs, sizeof(struct reg)); struct arm_reg *reg_arch_info = calloc(num_regs, sizeof(struct arm_reg)); int i; if (!cache || !reg_list || !reg_arch_info) { free(cache); free(reg_list); free(reg_arch_info); return NULL; } cache->name = "ARM registers"; cache->next = NULL; cache->reg_list = reg_list; cache->num_regs = 0; for (i = 0; i < num_regs; i++) { /* Skip registers this core doesn't expose */ if (arm_core_regs[i].mode == ARM_MODE_MON && arm->core_type != ARM_MODE_MON) continue; /* REVISIT handle Cortex-M, which only shadows R13/SP */ reg_arch_info[i].num = arm_core_regs[i].cookie; reg_arch_info[i].mode = arm_core_regs[i].mode; reg_arch_info[i].target = target; reg_arch_info[i].arm = arm; reg_list[i].name = (char *) arm_core_regs[i].name; reg_list[i].size = 32; reg_list[i].value = ®_arch_info[i].value; reg_list[i].type = &arm_reg_type; reg_list[i].arch_info = ®_arch_info[i]; cache->num_regs++; } arm->pc = reg_list + 15; arm->cpsr = reg_list + ARMV4_5_CPSR; arm->core_cache = cache; return cache; } int arm_arch_state(struct target *target) { struct arm *arm = target_to_arm(target); if (arm->common_magic != ARM_COMMON_MAGIC) { LOG_ERROR("BUG: called for a non-ARM target"); return ERROR_FAIL; } LOG_USER("target halted in %s state due to %s, current mode: %s\n" "cpsr: 0x%8.8" PRIx32 " pc: 0x%8.8" PRIx32 "%s", arm_state_strings[arm->core_state], debug_reason_name(target), arm_mode_name(arm->core_mode), buf_get_u32(arm->cpsr->value, 0, 32), buf_get_u32(arm->pc->value, 0, 32), arm->is_semihosting ? ", semihosting" : ""); return ERROR_OK; } #define ARMV4_5_CORE_REG_MODENUM(cache, mode, num) \ (cache->reg_list[armv4_5_core_reg_map[mode][num]]) COMMAND_HANDLER(handle_armv4_5_reg_command) { struct target *target = get_current_target(CMD_CTX); struct arm *arm = target_to_arm(target); struct reg *regs; if (!is_arm(arm)) { command_print(CMD_CTX, "current target isn't an ARM"); return ERROR_FAIL; } if (target->state != TARGET_HALTED) { command_print(CMD_CTX, "error: target must be halted for register accesses"); return ERROR_FAIL; } if (arm->core_type != ARM_MODE_ANY) { command_print(CMD_CTX, "Microcontroller Profile not supported - use standard reg cmd"); return ERROR_OK; } if (!is_arm_mode(arm->core_mode)) { LOG_ERROR("not a valid arm core mode - communication failure?"); return ERROR_FAIL; } if (!arm->full_context) { command_print(CMD_CTX, "error: target doesn't support %s", CMD_NAME); return ERROR_FAIL; } regs = arm->core_cache->reg_list; for (unsigned mode = 0; mode < ARRAY_SIZE(arm_mode_data); mode++) { const char *name; char *sep = "\n"; char *shadow = ""; /* label this bank of registers (or shadows) */ switch (arm_mode_data[mode].psr) { case ARM_MODE_SYS: continue; case ARM_MODE_USR: name = "System and User"; sep = ""; break; case ARM_MODE_MON: if (arm->core_type != ARM_MODE_MON) continue; /* FALLTHROUGH */ default: name = arm_mode_data[mode].name; shadow = "shadow "; break; } command_print(CMD_CTX, "%s%s mode %sregisters", sep, name, shadow); /* display N rows of up to 4 registers each */ for (unsigned i = 0; i < arm_mode_data[mode].n_indices; ) { char output[80]; int output_len = 0; for (unsigned j = 0; j < 4; j++, i++) { uint32_t value; struct reg *reg = regs; if (i >= arm_mode_data[mode].n_indices) break; reg += arm_mode_data[mode].indices[i]; /* REVISIT be smarter about faults... */ if (!reg->valid) arm->full_context(target); value = buf_get_u32(reg->value, 0, 32); output_len += snprintf(output + output_len, sizeof(output) - output_len, "%8s: %8.8" PRIx32 " ", reg->name, value); } command_print(CMD_CTX, "%s", output); } } return ERROR_OK; } COMMAND_HANDLER(handle_armv4_5_core_state_command) { struct target *target = get_current_target(CMD_CTX); struct arm *arm = target_to_arm(target); if (!is_arm(arm)) { command_print(CMD_CTX, "current target isn't an ARM"); return ERROR_FAIL; } if (arm->core_type == ARM_MODE_THREAD) { /* armv7m not supported */ command_print(CMD_CTX, "Unsupported Command"); return ERROR_OK; } if (CMD_ARGC > 0) { if (strcmp(CMD_ARGV[0], "arm") == 0) arm->core_state = ARM_STATE_ARM; if (strcmp(CMD_ARGV[0], "thumb") == 0) arm->core_state = ARM_STATE_THUMB; } command_print(CMD_CTX, "core state: %s", arm_state_strings[arm->core_state]); return ERROR_OK; } COMMAND_HANDLER(handle_arm_disassemble_command) { int retval = ERROR_OK; struct target *target = get_current_target(CMD_CTX); if (target == NULL) { LOG_ERROR("No target selected"); return ERROR_FAIL; } struct arm *arm = target_to_arm(target); uint32_t address; int count = 1; int thumb = 0; if (!is_arm(arm)) { command_print(CMD_CTX, "current target isn't an ARM"); return ERROR_FAIL; } if (arm->core_type == ARM_MODE_THREAD) { /* armv7m is always thumb mode */ thumb = 1; } switch (CMD_ARGC) { case 3: if (strcmp(CMD_ARGV[2], "thumb") != 0) goto usage; thumb = 1; /* FALL THROUGH */ case 2: COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], count); /* FALL THROUGH */ case 1: COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); if (address & 0x01) { if (!thumb) { command_print(CMD_CTX, "Disassemble as Thumb"); thumb = 1; } address &= ~1; } break; default: usage: count = 0; retval = ERROR_COMMAND_SYNTAX_ERROR; } while (count-- > 0) { struct arm_instruction cur_instruction; if (thumb) { /* Always use Thumb2 disassembly for best handling * of 32-bit BL/BLX, and to work with newer cores * (some ARMv6, all ARMv7) that use Thumb2. */ retval = thumb2_opcode(target, address, &cur_instruction); if (retval != ERROR_OK) break; } else { uint32_t opcode; retval = target_read_u32(target, address, &opcode); if (retval != ERROR_OK) break; retval = arm_evaluate_opcode(opcode, address, &cur_instruction) != ERROR_OK; if (retval != ERROR_OK) break; } command_print(CMD_CTX, "%s", cur_instruction.text); address += cur_instruction.instruction_size; } return retval; } static int jim_mcrmrc(Jim_Interp *interp, int argc, Jim_Obj * const *argv) { struct command_context *context; struct target *target; struct arm *arm; int retval; context = current_command_context(interp); assert(context != NULL); target = get_current_target(context); if (target == NULL) { LOG_ERROR("%s: no current target", __func__); return JIM_ERR; } if (!target_was_examined(target)) { LOG_ERROR("%s: not yet examined", target_name(target)); return JIM_ERR; } arm = target_to_arm(target); if (!is_arm(arm)) { LOG_ERROR("%s: not an ARM", target_name(target)); return JIM_ERR; } if ((argc < 6) || (argc > 7)) { /* FIXME use the command name to verify # params... */ LOG_ERROR("%s: wrong number of arguments", __func__); return JIM_ERR; } int cpnum; uint32_t op1; uint32_t op2; uint32_t CRn; uint32_t CRm; uint32_t value; long l; /* NOTE: parameter sequence matches ARM instruction set usage: * MCR pNUM, op1, rX, CRn, CRm, op2 ; write CP from rX * MRC pNUM, op1, rX, CRn, CRm, op2 ; read CP into rX * The "rX" is necessarily omitted; it uses Tcl mechanisms. */ retval = Jim_GetLong(interp, argv[1], &l); if (retval != JIM_OK) return retval; if (l & ~0xf) { LOG_ERROR("%s: %s %d out of range", __func__, "coprocessor", (int) l); return JIM_ERR; } cpnum = l; retval = Jim_GetLong(interp, argv[2], &l); if (retval != JIM_OK) return retval; if (l & ~0x7) { LOG_ERROR("%s: %s %d out of range", __func__, "op1", (int) l); return JIM_ERR; } op1 = l; retval = Jim_GetLong(interp, argv[3], &l); if (retval != JIM_OK) return retval; if (l & ~0xf) { LOG_ERROR("%s: %s %d out of range", __func__, "CRn", (int) l); return JIM_ERR; } CRn = l; retval = Jim_GetLong(interp, argv[4], &l); if (retval != JIM_OK) return retval; if (l & ~0xf) { LOG_ERROR("%s: %s %d out of range", __func__, "CRm", (int) l); return JIM_ERR; } CRm = l; retval = Jim_GetLong(interp, argv[5], &l); if (retval != JIM_OK) return retval; if (l & ~0x7) { LOG_ERROR("%s: %s %d out of range", __func__, "op2", (int) l); return JIM_ERR; } op2 = l; value = 0; /* FIXME don't assume "mrc" vs "mcr" from the number of params; * that could easily be a typo! Check both... * * FIXME change the call syntax here ... simplest to just pass * the MRC() or MCR() instruction to be executed. That will also * let us support the "mrc2" and "mcr2" opcodes (toggling one bit) * if that's ever needed. */ if (argc == 7) { retval = Jim_GetLong(interp, argv[6], &l); if (retval != JIM_OK) return retval; value = l; /* NOTE: parameters reordered! */ /* ARMV4_5_MCR(cpnum, op1, 0, CRn, CRm, op2) */ retval = arm->mcr(target, cpnum, op1, op2, CRn, CRm, value); if (retval != ERROR_OK) return JIM_ERR; } else { /* NOTE: parameters reordered! */ /* ARMV4_5_MRC(cpnum, op1, 0, CRn, CRm, op2) */ retval = arm->mrc(target, cpnum, op1, op2, CRn, CRm, &value); if (retval != ERROR_OK) return JIM_ERR; Jim_SetResult(interp, Jim_NewIntObj(interp, value)); } return JIM_OK; } COMMAND_HANDLER(handle_arm_semihosting_command) { struct target *target = get_current_target(CMD_CTX); if (target == NULL) { LOG_ERROR("No target selected"); return ERROR_FAIL; } struct arm *arm = target_to_arm(target); if (!is_arm(arm)) { command_print(CMD_CTX, "current target isn't an ARM"); return ERROR_FAIL; } if (!arm->setup_semihosting) { command_print(CMD_CTX, "semihosting not supported for current target"); return ERROR_FAIL; } if (CMD_ARGC > 0) { int semihosting; COMMAND_PARSE_ENABLE(CMD_ARGV[0], semihosting); if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } if (arm->setup_semihosting(target, semihosting) != ERROR_OK) { LOG_ERROR("Failed to Configure semihosting"); return ERROR_FAIL; } /* FIXME never let that "catch" be dropped! */ arm->is_semihosting = semihosting; } command_print(CMD_CTX, "semihosting is %s", arm->is_semihosting ? "enabled" : "disabled"); return ERROR_OK; } static const struct command_registration arm_exec_command_handlers[] = { { .name = "reg", .handler = handle_armv4_5_reg_command, .mode = COMMAND_EXEC, .help = "display ARM core registers", .usage = "", }, { .name = "core_state", .handler = handle_armv4_5_core_state_command, .mode = COMMAND_EXEC, .usage = "['arm'|'thumb']", .help = "display/change ARM core state", }, { .name = "disassemble", .handler = handle_arm_disassemble_command, .mode = COMMAND_EXEC, .usage = "address [count ['thumb']]", .help = "disassemble instructions ", }, { .name = "mcr", .mode = COMMAND_EXEC, .jim_handler = &jim_mcrmrc, .help = "write coprocessor register", .usage = "cpnum op1 CRn CRm op2 value", }, { .name = "mrc", .jim_handler = &jim_mcrmrc, .help = "read coprocessor register", .usage = "cpnum op1 CRn CRm op2", }, { "semihosting", .handler = handle_arm_semihosting_command, .mode = COMMAND_EXEC, .usage = "['enable'|'disable']", .help = "activate support for semihosting operations", }, COMMAND_REGISTRATION_DONE }; const struct command_registration arm_command_handlers[] = { { .name = "arm", .mode = COMMAND_ANY, .help = "ARM command group", .usage = "", .chain = arm_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; int arm_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size) { struct arm *arm = target_to_arm(target); int i; if (!is_arm_mode(arm->core_mode)) { LOG_ERROR("not a valid arm core mode - communication failure?"); return ERROR_FAIL; } *reg_list_size = 26; *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); for (i = 0; i < 16; i++) (*reg_list)[i] = arm_reg_current(arm, i); for (i = 16; i < 24; i++) (*reg_list)[i] = &arm_gdb_dummy_fp_reg; (*reg_list)[24] = &arm_gdb_dummy_fps_reg; (*reg_list)[25] = arm->cpsr; return ERROR_OK; } /* wait for execution to complete and check exit point */ static int armv4_5_run_algorithm_completion(struct target *target, uint32_t exit_point, int timeout_ms, void *arch_info) { int retval; struct arm *arm = target_to_arm(target); retval = target_wait_state(target, TARGET_HALTED, timeout_ms); if (retval != ERROR_OK) return retval; if (target->state != TARGET_HALTED) { retval = target_halt(target); if (retval != ERROR_OK) return retval; retval = target_wait_state(target, TARGET_HALTED, 500); if (retval != ERROR_OK) return retval; return ERROR_TARGET_TIMEOUT; } /* fast exit: ARMv5+ code can use BKPT */ if (exit_point && buf_get_u32(arm->pc->value, 0, 32) != exit_point) { LOG_WARNING( "target reentered debug state, but not at the desired exit point: 0x%4.4" PRIx32 "", buf_get_u32(arm->pc->value, 0, 32)); return ERROR_TARGET_TIMEOUT; } return ERROR_OK; } int armv4_5_run_algorithm_inner(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, uint32_t entry_point, uint32_t exit_point, int timeout_ms, void *arch_info, int (*run_it)(struct target *target, uint32_t exit_point, int timeout_ms, void *arch_info)) { struct arm *arm = target_to_arm(target); struct arm_algorithm *arm_algorithm_info = arch_info; enum arm_state core_state = arm->core_state; uint32_t context[17]; uint32_t cpsr; int exit_breakpoint_size = 0; int i; int retval = ERROR_OK; LOG_DEBUG("Running algorithm"); if (arm_algorithm_info->common_magic != ARM_COMMON_MAGIC) { LOG_ERROR("current target isn't an ARMV4/5 target"); return ERROR_TARGET_INVALID; } if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!is_arm_mode(arm->core_mode)) { LOG_ERROR("not a valid arm core mode - communication failure?"); return ERROR_FAIL; } /* armv5 and later can terminate with BKPT instruction; less overhead */ if (!exit_point && arm->is_armv4) { LOG_ERROR("ARMv4 target needs HW breakpoint location"); return ERROR_FAIL; } /* save r0..pc, cpsr-or-spsr, and then cpsr-for-sure; * they'll be restored later. */ for (i = 0; i <= 16; i++) { struct reg *r; r = &ARMV4_5_CORE_REG_MODE(arm->core_cache, arm_algorithm_info->core_mode, i); if (!r->valid) arm->read_core_reg(target, r, i, arm_algorithm_info->core_mode); context[i] = buf_get_u32(r->value, 0, 32); } cpsr = buf_get_u32(arm->cpsr->value, 0, 32); for (i = 0; i < num_mem_params; i++) { retval = target_write_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value); if (retval != ERROR_OK) return retval; } for (i = 0; i < num_reg_params; i++) { struct reg *reg = register_get_by_name(arm->core_cache, reg_params[i].reg_name, 0); if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } if (reg->size != reg_params[i].size) { LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } retval = armv4_5_set_core_reg(reg, reg_params[i].value); if (retval != ERROR_OK) return retval; } arm->core_state = arm_algorithm_info->core_state; if (arm->core_state == ARM_STATE_ARM) exit_breakpoint_size = 4; else if (arm->core_state == ARM_STATE_THUMB) exit_breakpoint_size = 2; else { LOG_ERROR("BUG: can't execute algorithms when not in ARM or Thumb state"); return ERROR_COMMAND_SYNTAX_ERROR; } if (arm_algorithm_info->core_mode != ARM_MODE_ANY) { LOG_DEBUG("setting core_mode: 0x%2.2x", arm_algorithm_info->core_mode); buf_set_u32(arm->cpsr->value, 0, 5, arm_algorithm_info->core_mode); arm->cpsr->dirty = 1; arm->cpsr->valid = 1; } /* terminate using a hardware or (ARMv5+) software breakpoint */ if (exit_point) { retval = breakpoint_add(target, exit_point, exit_breakpoint_size, BKPT_HARD); if (retval != ERROR_OK) { LOG_ERROR("can't add HW breakpoint to terminate algorithm"); return ERROR_TARGET_FAILURE; } } retval = target_resume(target, 0, entry_point, 1, 1); if (retval != ERROR_OK) return retval; retval = run_it(target, exit_point, timeout_ms, arch_info); if (exit_point) breakpoint_remove(target, exit_point); if (retval != ERROR_OK) return retval; for (i = 0; i < num_mem_params; i++) { if (mem_params[i].direction != PARAM_OUT) { int retvaltemp = target_read_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value); if (retvaltemp != ERROR_OK) retval = retvaltemp; } } for (i = 0; i < num_reg_params; i++) { if (reg_params[i].direction != PARAM_OUT) { struct reg *reg = register_get_by_name(arm->core_cache, reg_params[i].reg_name, 0); if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); retval = ERROR_COMMAND_SYNTAX_ERROR; continue; } if (reg->size != reg_params[i].size) { LOG_ERROR( "BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name); retval = ERROR_COMMAND_SYNTAX_ERROR; continue; } buf_set_u32(reg_params[i].value, 0, 32, buf_get_u32(reg->value, 0, 32)); } } /* restore everything we saved before (17 or 18 registers) */ for (i = 0; i <= 16; i++) { uint32_t regvalue; regvalue = buf_get_u32(ARMV4_5_CORE_REG_MODE(arm->core_cache, arm_algorithm_info->core_mode, i).value, 0, 32); if (regvalue != context[i]) { LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32 "", ARMV4_5_CORE_REG_MODE(arm->core_cache, arm_algorithm_info->core_mode, i).name, context[i]); buf_set_u32(ARMV4_5_CORE_REG_MODE(arm->core_cache, arm_algorithm_info->core_mode, i).value, 0, 32, context[i]); ARMV4_5_CORE_REG_MODE(arm->core_cache, arm_algorithm_info->core_mode, i).valid = 1; ARMV4_5_CORE_REG_MODE(arm->core_cache, arm_algorithm_info->core_mode, i).dirty = 1; } } arm_set_cpsr(arm, cpsr); arm->cpsr->dirty = 1; arm->core_state = core_state; return retval; } int armv4_5_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, uint32_t entry_point, uint32_t exit_point, int timeout_ms, void *arch_info) { return armv4_5_run_algorithm_inner(target, num_mem_params, mem_params, num_reg_params, reg_params, entry_point, exit_point, timeout_ms, arch_info, armv4_5_run_algorithm_completion); } /** * Runs ARM code in the target to calculate a CRC32 checksum. * */ int arm_checksum_memory(struct target *target, uint32_t address, uint32_t count, uint32_t *checksum) { struct working_area *crc_algorithm; struct arm_algorithm arm_algo; struct arm *arm = target_to_arm(target); struct reg_param reg_params[2]; int retval; uint32_t i; uint32_t exit_var = 0; /* see contrib/loaders/checksum/armv4_5_crc.s for src */ static const uint32_t arm_crc_code[] = { 0xE1A02000, /* mov r2, r0 */ 0xE3E00000, /* mov r0, #0xffffffff */ 0xE1A03001, /* mov r3, r1 */ 0xE3A04000, /* mov r4, #0 */ 0xEA00000B, /* b ncomp */ /* nbyte: */ 0xE7D21004, /* ldrb r1, [r2, r4] */ 0xE59F7030, /* ldr r7, CRC32XOR */ 0xE0200C01, /* eor r0, r0, r1, asl 24 */ 0xE3A05000, /* mov r5, #0 */ /* loop: */ 0xE3500000, /* cmp r0, #0 */ 0xE1A06080, /* mov r6, r0, asl #1 */ 0xE2855001, /* add r5, r5, #1 */ 0xE1A00006, /* mov r0, r6 */ 0xB0260007, /* eorlt r0, r6, r7 */ 0xE3550008, /* cmp r5, #8 */ 0x1AFFFFF8, /* bne loop */ 0xE2844001, /* add r4, r4, #1 */ /* ncomp: */ 0xE1540003, /* cmp r4, r3 */ 0x1AFFFFF1, /* bne nbyte */ /* end: */ 0xe1200070, /* bkpt #0 */ /* CRC32XOR: */ 0x04C11DB7 /* .word 0x04C11DB7 */ }; retval = target_alloc_working_area(target, sizeof(arm_crc_code), &crc_algorithm); if (retval != ERROR_OK) return retval; /* convert code into a buffer in target endianness */ for (i = 0; i < ARRAY_SIZE(arm_crc_code); i++) { retval = target_write_u32(target, crc_algorithm->address + i * sizeof(uint32_t), arm_crc_code[i]); if (retval != ERROR_OK) return retval; } arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); buf_set_u32(reg_params[1].value, 0, 32, count); /* 20 second timeout/megabyte */ int timeout = 20000 * (1 + (count / (1024 * 1024))); /* armv4 must exit using a hardware breakpoint */ if (arm->is_armv4) exit_var = crc_algorithm->address + sizeof(arm_crc_code) - 8; retval = target_run_algorithm(target, 0, NULL, 2, reg_params, crc_algorithm->address, exit_var, timeout, &arm_algo); if (retval != ERROR_OK) { LOG_ERROR("error executing ARM crc algorithm"); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); target_free_working_area(target, crc_algorithm); return retval; } *checksum = buf_get_u32(reg_params[0].value, 0, 32); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); target_free_working_area(target, crc_algorithm); return ERROR_OK; } /** * Runs ARM code in the target to check whether a memory block holds * all ones. NOR flash which has been erased, and thus may be written, * holds all ones. * */ int arm_blank_check_memory(struct target *target, uint32_t address, uint32_t count, uint32_t *blank) { struct working_area *check_algorithm; struct reg_param reg_params[3]; struct arm_algorithm arm_algo; struct arm *arm = target_to_arm(target); int retval; uint32_t i; uint32_t exit_var = 0; /* see contrib/loaders/erase_check/armv4_5_erase_check.s for src */ static const uint32_t check_code[] = { /* loop: */ 0xe4d03001, /* ldrb r3, [r0], #1 */ 0xe0022003, /* and r2, r2, r3 */ 0xe2511001, /* subs r1, r1, #1 */ 0x1afffffb, /* bne loop */ /* end: */ 0xe1200070, /* bkpt #0 */ }; /* make sure we have a working area */ retval = target_alloc_working_area(target, sizeof(check_code), &check_algorithm); if (retval != ERROR_OK) return retval; /* convert code into a buffer in target endianness */ for (i = 0; i < ARRAY_SIZE(check_code); i++) { retval = target_write_u32(target, check_algorithm->address + i * sizeof(uint32_t), check_code[i]); if (retval != ERROR_OK) return retval; } arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); buf_set_u32(reg_params[1].value, 0, 32, count); init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT); buf_set_u32(reg_params[2].value, 0, 32, 0xff); /* armv4 must exit using a hardware breakpoint */ if (arm->is_armv4) exit_var = check_algorithm->address + sizeof(check_code) - 4; retval = target_run_algorithm(target, 0, NULL, 3, reg_params, check_algorithm->address, exit_var, 10000, &arm_algo); if (retval != ERROR_OK) { destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); target_free_working_area(target, check_algorithm); return retval; } *blank = buf_get_u32(reg_params[2].value, 0, 32); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); target_free_working_area(target, check_algorithm); return ERROR_OK; } static int arm_full_context(struct target *target) { struct arm *arm = target_to_arm(target); unsigned num_regs = arm->core_cache->num_regs; struct reg *reg = arm->core_cache->reg_list; int retval = ERROR_OK; for (; num_regs && retval == ERROR_OK; num_regs--, reg++) { if (reg->valid) continue; retval = armv4_5_get_core_reg(reg); } return retval; } static int arm_default_mrc(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t *value) { LOG_ERROR("%s doesn't implement MRC", target_type_name(target)); return ERROR_FAIL; } static int arm_default_mcr(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t value) { LOG_ERROR("%s doesn't implement MCR", target_type_name(target)); return ERROR_FAIL; } int arm_init_arch_info(struct target *target, struct arm *arm) { target->arch_info = arm; arm->target = target; arm->common_magic = ARM_COMMON_MAGIC; /* core_type may be overridden by subtype logic */ if (arm->core_type != ARM_MODE_THREAD) { arm->core_type = ARM_MODE_ANY; arm_set_cpsr(arm, ARM_MODE_USR); } /* default full_context() has no core-specific optimizations */ if (!arm->full_context && arm->read_core_reg) arm->full_context = arm_full_context; if (!arm->mrc) arm->mrc = arm_default_mrc; if (!arm->mcr) arm->mcr = arm_default_mcr; return ERROR_OK; } openocd-0.7.0/src/target/mips32.c0000644000175000001440000006067312137151331013431 00000000000000/*************************************************************************** * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2008 by David T.L. Wong * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2011 by Drasko DRASKOVIC * * drasko.draskovic@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "mips32.h" #include "breakpoints.h" #include "algorithm.h" #include "register.h" static char *mips32_core_reg_list[] = { "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra", "status", "lo", "hi", "badvaddr", "cause", "pc" }; static const char *mips_isa_strings[] = { "MIPS32", "MIPS16e" }; static struct mips32_core_reg mips32_core_reg_list_arch_info[MIPS32NUMCOREREGS] = { {0, NULL, NULL}, {1, NULL, NULL}, {2, NULL, NULL}, {3, NULL, NULL}, {4, NULL, NULL}, {5, NULL, NULL}, {6, NULL, NULL}, {7, NULL, NULL}, {8, NULL, NULL}, {9, NULL, NULL}, {10, NULL, NULL}, {11, NULL, NULL}, {12, NULL, NULL}, {13, NULL, NULL}, {14, NULL, NULL}, {15, NULL, NULL}, {16, NULL, NULL}, {17, NULL, NULL}, {18, NULL, NULL}, {19, NULL, NULL}, {20, NULL, NULL}, {21, NULL, NULL}, {22, NULL, NULL}, {23, NULL, NULL}, {24, NULL, NULL}, {25, NULL, NULL}, {26, NULL, NULL}, {27, NULL, NULL}, {28, NULL, NULL}, {29, NULL, NULL}, {30, NULL, NULL}, {31, NULL, NULL}, {32, NULL, NULL}, {33, NULL, NULL}, {34, NULL, NULL}, {35, NULL, NULL}, {36, NULL, NULL}, {37, NULL, NULL}, }; /* number of mips dummy fp regs fp0 - fp31 + fsr and fir * we also add 18 unknown registers to handle gdb requests */ #define MIPS32NUMFPREGS (34 + 18) static uint8_t mips32_gdb_dummy_fp_value[] = {0, 0, 0, 0}; static struct reg mips32_gdb_dummy_fp_reg = { .name = "GDB dummy floating-point register", .value = mips32_gdb_dummy_fp_value, .dirty = 0, .valid = 1, .size = 32, .arch_info = NULL, }; static int mips32_get_core_reg(struct reg *reg) { int retval; struct mips32_core_reg *mips32_reg = reg->arch_info; struct target *target = mips32_reg->target; struct mips32_common *mips32_target = target_to_mips32(target); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; retval = mips32_target->read_core_reg(target, mips32_reg->num); return retval; } static int mips32_set_core_reg(struct reg *reg, uint8_t *buf) { struct mips32_core_reg *mips32_reg = reg->arch_info; struct target *target = mips32_reg->target; uint32_t value = buf_get_u32(buf, 0, 32); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; buf_set_u32(reg->value, 0, 32, value); reg->dirty = 1; reg->valid = 1; return ERROR_OK; } static int mips32_read_core_reg(struct target *target, int num) { uint32_t reg_value; /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); if ((num < 0) || (num >= MIPS32NUMCOREREGS)) return ERROR_COMMAND_SYNTAX_ERROR; reg_value = mips32->core_regs[num]; buf_set_u32(mips32->core_cache->reg_list[num].value, 0, 32, reg_value); mips32->core_cache->reg_list[num].valid = 1; mips32->core_cache->reg_list[num].dirty = 0; return ERROR_OK; } static int mips32_write_core_reg(struct target *target, int num) { uint32_t reg_value; /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); if ((num < 0) || (num >= MIPS32NUMCOREREGS)) return ERROR_COMMAND_SYNTAX_ERROR; reg_value = buf_get_u32(mips32->core_cache->reg_list[num].value, 0, 32); mips32->core_regs[num] = reg_value; LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num , reg_value); mips32->core_cache->reg_list[num].valid = 1; mips32->core_cache->reg_list[num].dirty = 0; return ERROR_OK; } int mips32_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size) { /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); int i; /* include floating point registers */ *reg_list_size = MIPS32NUMCOREREGS + MIPS32NUMFPREGS; *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); for (i = 0; i < MIPS32NUMCOREREGS; i++) (*reg_list)[i] = &mips32->core_cache->reg_list[i]; /* add dummy floating points regs */ for (i = MIPS32NUMCOREREGS; i < (MIPS32NUMCOREREGS + MIPS32NUMFPREGS); i++) (*reg_list)[i] = &mips32_gdb_dummy_fp_reg; return ERROR_OK; } int mips32_save_context(struct target *target) { int i; /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; /* read core registers */ mips32_pracc_read_regs(ejtag_info, mips32->core_regs); for (i = 0; i < MIPS32NUMCOREREGS; i++) { if (!mips32->core_cache->reg_list[i].valid) mips32->read_core_reg(target, i); } return ERROR_OK; } int mips32_restore_context(struct target *target) { int i; /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; for (i = 0; i < MIPS32NUMCOREREGS; i++) { if (mips32->core_cache->reg_list[i].dirty) mips32->write_core_reg(target, i); } /* write core regs */ mips32_pracc_write_regs(ejtag_info, mips32->core_regs); return ERROR_OK; } int mips32_arch_state(struct target *target) { struct mips32_common *mips32 = target_to_mips32(target); LOG_USER("target halted in %s mode due to %s, pc: 0x%8.8" PRIx32 "", mips_isa_strings[mips32->isa_mode], debug_reason_name(target), buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32)); return ERROR_OK; } static const struct reg_arch_type mips32_reg_type = { .get = mips32_get_core_reg, .set = mips32_set_core_reg, }; struct reg_cache *mips32_build_reg_cache(struct target *target) { /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); int num_regs = MIPS32NUMCOREREGS; struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); struct reg_cache *cache = malloc(sizeof(struct reg_cache)); struct reg *reg_list = malloc(sizeof(struct reg) * num_regs); struct mips32_core_reg *arch_info = malloc(sizeof(struct mips32_core_reg) * num_regs); int i; register_init_dummy(&mips32_gdb_dummy_fp_reg); /* Build the process context cache */ cache->name = "mips32 registers"; cache->next = NULL; cache->reg_list = reg_list; cache->num_regs = num_regs; (*cache_p) = cache; mips32->core_cache = cache; for (i = 0; i < num_regs; i++) { arch_info[i] = mips32_core_reg_list_arch_info[i]; arch_info[i].target = target; arch_info[i].mips32_common = mips32; reg_list[i].name = mips32_core_reg_list[i]; reg_list[i].size = 32; reg_list[i].value = calloc(1, 4); reg_list[i].dirty = 0; reg_list[i].valid = 0; reg_list[i].type = &mips32_reg_type; reg_list[i].arch_info = &arch_info[i]; } return cache; } int mips32_init_arch_info(struct target *target, struct mips32_common *mips32, struct jtag_tap *tap) { target->arch_info = mips32; mips32->common_magic = MIPS32_COMMON_MAGIC; mips32->fast_data_area = NULL; /* has breakpoint/watchpint unit been scanned */ mips32->bp_scanned = 0; mips32->data_break_list = NULL; mips32->ejtag_info.tap = tap; mips32->read_core_reg = mips32_read_core_reg; mips32->write_core_reg = mips32_write_core_reg; mips32->ejtag_info.scan_delay = 2000000; /* Initial default value */ mips32->ejtag_info.mode = 0; /* Initial default value */ return ERROR_OK; } /* run to exit point. return error if exit point was not reached. */ static int mips32_run_and_wait(struct target *target, uint32_t entry_point, int timeout_ms, uint32_t exit_point, struct mips32_common *mips32) { uint32_t pc; int retval; /* This code relies on the target specific resume() and poll()->debug_entry() * sequence to write register values to the processor and the read them back */ retval = target_resume(target, 0, entry_point, 0, 1); if (retval != ERROR_OK) return retval; retval = target_wait_state(target, TARGET_HALTED, timeout_ms); /* If the target fails to halt due to the breakpoint, force a halt */ if (retval != ERROR_OK || target->state != TARGET_HALTED) { retval = target_halt(target); if (retval != ERROR_OK) return retval; retval = target_wait_state(target, TARGET_HALTED, 500); if (retval != ERROR_OK) return retval; return ERROR_TARGET_TIMEOUT; } pc = buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32); if (exit_point && (pc != exit_point)) { LOG_DEBUG("failed algorithm halted at 0x%" PRIx32 " ", pc); return ERROR_TARGET_TIMEOUT; } return ERROR_OK; } int mips32_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, uint32_t entry_point, uint32_t exit_point, int timeout_ms, void *arch_info) { struct mips32_common *mips32 = target_to_mips32(target); struct mips32_algorithm *mips32_algorithm_info = arch_info; enum mips32_isa_mode isa_mode = mips32->isa_mode; uint32_t context[MIPS32NUMCOREREGS]; int i; int retval = ERROR_OK; LOG_DEBUG("Running algorithm"); /* NOTE: mips32_run_algorithm requires that each algorithm uses a software breakpoint * at the exit point */ if (mips32->common_magic != MIPS32_COMMON_MAGIC) { LOG_ERROR("current target isn't a MIPS32 target"); return ERROR_TARGET_INVALID; } if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* refresh core register cache */ for (i = 0; i < MIPS32NUMCOREREGS; i++) { if (!mips32->core_cache->reg_list[i].valid) mips32->read_core_reg(target, i); context[i] = buf_get_u32(mips32->core_cache->reg_list[i].value, 0, 32); } for (i = 0; i < num_mem_params; i++) { retval = target_write_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value); if (retval != ERROR_OK) return retval; } for (i = 0; i < num_reg_params; i++) { struct reg *reg = register_get_by_name(mips32->core_cache, reg_params[i].reg_name, 0); if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } if (reg->size != reg_params[i].size) { LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } mips32_set_core_reg(reg, reg_params[i].value); } mips32->isa_mode = mips32_algorithm_info->isa_mode; retval = mips32_run_and_wait(target, entry_point, timeout_ms, exit_point, mips32); if (retval != ERROR_OK) return retval; for (i = 0; i < num_mem_params; i++) { if (mem_params[i].direction != PARAM_OUT) { retval = target_read_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value); if (retval != ERROR_OK) return retval; } } for (i = 0; i < num_reg_params; i++) { if (reg_params[i].direction != PARAM_OUT) { struct reg *reg = register_get_by_name(mips32->core_cache, reg_params[i].reg_name, 0); if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } if (reg->size != reg_params[i].size) { LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } buf_set_u32(reg_params[i].value, 0, 32, buf_get_u32(reg->value, 0, 32)); } } /* restore everything we saved before */ for (i = 0; i < MIPS32NUMCOREREGS; i++) { uint32_t regvalue; regvalue = buf_get_u32(mips32->core_cache->reg_list[i].value, 0, 32); if (regvalue != context[i]) { LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32, mips32->core_cache->reg_list[i].name, context[i]); buf_set_u32(mips32->core_cache->reg_list[i].value, 0, 32, context[i]); mips32->core_cache->reg_list[i].valid = 1; mips32->core_cache->reg_list[i].dirty = 1; } } mips32->isa_mode = isa_mode; return ERROR_OK; } int mips32_examine(struct target *target) { struct mips32_common *mips32 = target_to_mips32(target); if (!target_was_examined(target)) { target_set_examined(target); /* we will configure later */ mips32->bp_scanned = 0; mips32->num_inst_bpoints = 0; mips32->num_data_bpoints = 0; mips32->num_inst_bpoints_avail = 0; mips32->num_data_bpoints_avail = 0; } return ERROR_OK; } int mips32_configure_break_unit(struct target *target) { /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); int retval; uint32_t dcr, bpinfo; int i; if (mips32->bp_scanned) return ERROR_OK; /* get info about breakpoint support */ retval = target_read_u32(target, EJTAG_DCR, &dcr); if (retval != ERROR_OK) return retval; if (dcr & EJTAG_DCR_IB) { /* get number of inst breakpoints */ retval = target_read_u32(target, EJTAG_IBS, &bpinfo); if (retval != ERROR_OK) return retval; mips32->num_inst_bpoints = (bpinfo >> 24) & 0x0F; mips32->num_inst_bpoints_avail = mips32->num_inst_bpoints; mips32->inst_break_list = calloc(mips32->num_inst_bpoints, sizeof(struct mips32_comparator)); for (i = 0; i < mips32->num_inst_bpoints; i++) mips32->inst_break_list[i].reg_address = EJTAG_IBA1 + (0x100 * i); /* clear IBIS reg */ retval = target_write_u32(target, EJTAG_IBS, 0); if (retval != ERROR_OK) return retval; } if (dcr & EJTAG_DCR_DB) { /* get number of data breakpoints */ retval = target_read_u32(target, EJTAG_DBS, &bpinfo); if (retval != ERROR_OK) return retval; mips32->num_data_bpoints = (bpinfo >> 24) & 0x0F; mips32->num_data_bpoints_avail = mips32->num_data_bpoints; mips32->data_break_list = calloc(mips32->num_data_bpoints, sizeof(struct mips32_comparator)); for (i = 0; i < mips32->num_data_bpoints; i++) mips32->data_break_list[i].reg_address = EJTAG_DBA1 + (0x100 * i); /* clear DBIS reg */ retval = target_write_u32(target, EJTAG_DBS, 0); if (retval != ERROR_OK) return retval; } /* check if target endianness settings matches debug control register */ if (((dcr & EJTAG_DCR_ENM) && (target->endianness == TARGET_LITTLE_ENDIAN)) || (!(dcr & EJTAG_DCR_ENM) && (target->endianness == TARGET_BIG_ENDIAN))) LOG_WARNING("DCR endianness settings does not match target settings"); LOG_DEBUG("DCR 0x%" PRIx32 " numinst %i numdata %i", dcr, mips32->num_inst_bpoints, mips32->num_data_bpoints); mips32->bp_scanned = 1; return ERROR_OK; } int mips32_enable_interrupts(struct target *target, int enable) { int retval; int update = 0; uint32_t dcr; /* read debug control register */ retval = target_read_u32(target, EJTAG_DCR, &dcr); if (retval != ERROR_OK) return retval; if (enable) { if (!(dcr & EJTAG_DCR_INTE)) { /* enable interrupts */ dcr |= EJTAG_DCR_INTE; update = 1; } } else { if (dcr & EJTAG_DCR_INTE) { /* disable interrupts */ dcr &= ~EJTAG_DCR_INTE; update = 1; } } if (update) { retval = target_write_u32(target, EJTAG_DCR, dcr); if (retval != ERROR_OK) return retval; } return ERROR_OK; } int mips32_checksum_memory(struct target *target, uint32_t address, uint32_t count, uint32_t *checksum) { struct working_area *crc_algorithm; struct reg_param reg_params[2]; struct mips32_algorithm mips32_info; int retval; uint32_t i; /* see contib/loaders/checksum/mips32.s for src */ static const uint32_t mips_crc_code[] = { 0x248C0000, /* addiu $t4, $a0, 0 */ 0x24AA0000, /* addiu $t2, $a1, 0 */ 0x2404FFFF, /* addiu $a0, $zero, 0xffffffff */ 0x10000010, /* beq $zero, $zero, ncomp */ 0x240B0000, /* addiu $t3, $zero, 0 */ /* nbyte: */ 0x81850000, /* lb $a1, ($t4) */ 0x218C0001, /* addi $t4, $t4, 1 */ 0x00052E00, /* sll $a1, $a1, 24 */ 0x3C0204C1, /* lui $v0, 0x04c1 */ 0x00852026, /* xor $a0, $a0, $a1 */ 0x34471DB7, /* ori $a3, $v0, 0x1db7 */ 0x00003021, /* addu $a2, $zero, $zero */ /* loop: */ 0x00044040, /* sll $t0, $a0, 1 */ 0x24C60001, /* addiu $a2, $a2, 1 */ 0x28840000, /* slti $a0, $a0, 0 */ 0x01074826, /* xor $t1, $t0, $a3 */ 0x0124400B, /* movn $t0, $t1, $a0 */ 0x28C30008, /* slti $v1, $a2, 8 */ 0x1460FFF9, /* bne $v1, $zero, loop */ 0x01002021, /* addu $a0, $t0, $zero */ /* ncomp: */ 0x154BFFF0, /* bne $t2, $t3, nbyte */ 0x256B0001, /* addiu $t3, $t3, 1 */ 0x7000003F, /* sdbbp */ }; /* make sure we have a working area */ if (target_alloc_working_area(target, sizeof(mips_crc_code), &crc_algorithm) != ERROR_OK) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; /* convert flash writing code into a buffer in target endianness */ for (i = 0; i < ARRAY_SIZE(mips_crc_code); i++) target_write_u32(target, crc_algorithm->address + i*sizeof(uint32_t), mips_crc_code[i]); mips32_info.common_magic = MIPS32_COMMON_MAGIC; mips32_info.isa_mode = MIPS32_ISA_MIPS32; init_reg_param(®_params[0], "a0", 32, PARAM_IN_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); init_reg_param(®_params[1], "a1", 32, PARAM_OUT); buf_set_u32(reg_params[1].value, 0, 32, count); int timeout = 20000 * (1 + (count / (1024 * 1024))); retval = target_run_algorithm(target, 0, NULL, 2, reg_params, crc_algorithm->address, crc_algorithm->address + (sizeof(mips_crc_code)-4), timeout, &mips32_info); if (retval != ERROR_OK) { destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); target_free_working_area(target, crc_algorithm); return retval; } *checksum = buf_get_u32(reg_params[0].value, 0, 32); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); target_free_working_area(target, crc_algorithm); return ERROR_OK; } /** Checks whether a memory region is zeroed. */ int mips32_blank_check_memory(struct target *target, uint32_t address, uint32_t count, uint32_t *blank) { struct working_area *erase_check_algorithm; struct reg_param reg_params[3]; struct mips32_algorithm mips32_info; int retval; uint32_t i; static const uint32_t erase_check_code[] = { /* nbyte: */ 0x80880000, /* lb $t0, ($a0) */ 0x00C83024, /* and $a2, $a2, $t0 */ 0x24A5FFFF, /* addiu $a1, $a1, -1 */ 0x14A0FFFC, /* bne $a1, $zero, nbyte */ 0x24840001, /* addiu $a0, $a0, 1 */ 0x7000003F /* sdbbp */ }; /* make sure we have a working area */ if (target_alloc_working_area(target, sizeof(erase_check_code), &erase_check_algorithm) != ERROR_OK) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; /* convert flash writing code into a buffer in target endianness */ for (i = 0; i < ARRAY_SIZE(erase_check_code); i++) { target_write_u32(target, erase_check_algorithm->address + i*sizeof(uint32_t), erase_check_code[i]); } mips32_info.common_magic = MIPS32_COMMON_MAGIC; mips32_info.isa_mode = MIPS32_ISA_MIPS32; init_reg_param(®_params[0], "a0", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); init_reg_param(®_params[1], "a1", 32, PARAM_OUT); buf_set_u32(reg_params[1].value, 0, 32, count); init_reg_param(®_params[2], "a2", 32, PARAM_IN_OUT); buf_set_u32(reg_params[2].value, 0, 32, 0xff); retval = target_run_algorithm(target, 0, NULL, 3, reg_params, erase_check_algorithm->address, erase_check_algorithm->address + (sizeof(erase_check_code)-4), 10000, &mips32_info); if (retval != ERROR_OK) { destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); target_free_working_area(target, erase_check_algorithm); return retval; } *blank = buf_get_u32(reg_params[2].value, 0, 32); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); target_free_working_area(target, erase_check_algorithm); return ERROR_OK; } static int mips32_verify_pointer(struct command_context *cmd_ctx, struct mips32_common *mips32) { if (mips32->common_magic != MIPS32_COMMON_MAGIC) { command_print(cmd_ctx, "target is not an MIPS32"); return ERROR_TARGET_INVALID; } return ERROR_OK; } /** * MIPS32 targets expose command interface * to manipulate CP0 registers */ COMMAND_HANDLER(mips32_handle_cp0_command) { int retval; struct target *target = get_current_target(CMD_CTX); struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; retval = mips32_verify_pointer(CMD_CTX, mips32); if (retval != ERROR_OK) return retval; if (target->state != TARGET_HALTED) { command_print(CMD_CTX, "target must be stopped for \"%s\" command", CMD_NAME); return ERROR_OK; } /* two or more argument, access a single register/select (write if third argument is given) */ if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; else { uint32_t cp0_reg, cp0_sel; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], cp0_reg); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], cp0_sel); if (CMD_ARGC == 2) { uint32_t value; retval = mips32_cp0_read(ejtag_info, &value, cp0_reg, cp0_sel); if (retval != ERROR_OK) { command_print(CMD_CTX, "couldn't access reg %" PRIi32, cp0_reg); return ERROR_OK; } command_print(CMD_CTX, "cp0 reg %" PRIi32 ", select %" PRIi32 ": %8.8" PRIx32, cp0_reg, cp0_sel, value); } else if (CMD_ARGC == 3) { uint32_t value; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], value); retval = mips32_cp0_write(ejtag_info, value, cp0_reg, cp0_sel); if (retval != ERROR_OK) { command_print(CMD_CTX, "couldn't access cp0 reg %" PRIi32 ", select %" PRIi32, cp0_reg, cp0_sel); return ERROR_OK; } command_print(CMD_CTX, "cp0 reg %" PRIi32 ", select %" PRIi32 ": %8.8" PRIx32, cp0_reg, cp0_sel, value); } } return ERROR_OK; } COMMAND_HANDLER(mips32_handle_scan_delay_command) { struct target *target = get_current_target(CMD_CTX); struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], ejtag_info->scan_delay); else if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; command_print(CMD_CTX, "scan delay: %d nsec", ejtag_info->scan_delay); if (ejtag_info->scan_delay >= 2000000) { ejtag_info->mode = 0; command_print(CMD_CTX, "running in legacy mode"); } else { ejtag_info->mode = 1; command_print(CMD_CTX, "running in fast queued mode"); } return ERROR_OK; } static const struct command_registration mips32_exec_command_handlers[] = { { .name = "cp0", .handler = mips32_handle_cp0_command, .mode = COMMAND_EXEC, .usage = "regnum select [value]", .help = "display/modify cp0 register", }, { .name = "scan_delay", .handler = mips32_handle_scan_delay_command, .mode = COMMAND_ANY, .help = "display/set scan delay in nano seconds", .usage = "[value]", }, COMMAND_REGISTRATION_DONE }; const struct command_registration mips32_command_handlers[] = { { .name = "mips32", .mode = COMMAND_ANY, .help = "mips32 command group", .usage = "", .chain = mips32_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; openocd-0.7.0/src/target/arm11_dbgtap.c0000644000175000001440000010057612134336410014553 00000000000000/*************************************************************************** * Copyright (C) 2008 digenius technology GmbH. * * Michael Bruck * * * * Copyright (C) 2008,2009 Oyvind Harboe oyvind.harboe@zylin.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm_jtag.h" #include "arm11_dbgtap.h" #include #if 0 #define JTAG_DEBUG(expr ...) do { if (1) \ LOG_DEBUG(expr); } while (0) #else #define JTAG_DEBUG(expr ...) do { if (0) \ LOG_DEBUG(expr); } while (0) #endif /* This pathmove goes from Pause-IR to Shift-IR while avoiding RTI. The behavior of the FTDI driver IIRC was to go via RTI. Conversely there may be other places in this code where the ARM11 code relies on the driver to hit through RTI when coming from Update-?R. */ static const tap_state_t arm11_move_pi_to_si_via_ci[] = { TAP_IREXIT2, TAP_IRUPDATE, TAP_DRSELECT, TAP_IRSELECT, TAP_IRCAPTURE, TAP_IRSHIFT }; /* REVISIT no error handling here! */ static void arm11_add_ir_scan_vc(struct jtag_tap *tap, struct scan_field *fields, tap_state_t state) { if (cmd_queue_cur_state == TAP_IRPAUSE) jtag_add_pathmove(ARRAY_SIZE(arm11_move_pi_to_si_via_ci), arm11_move_pi_to_si_via_ci); jtag_add_ir_scan(tap, fields, state); } static const tap_state_t arm11_move_pd_to_sd_via_cd[] = { TAP_DREXIT2, TAP_DRUPDATE, TAP_DRSELECT, TAP_DRCAPTURE, TAP_DRSHIFT }; /* REVISIT no error handling here! */ void arm11_add_dr_scan_vc(struct jtag_tap *tap, int num_fields, struct scan_field *fields, tap_state_t state) { if (cmd_queue_cur_state == TAP_DRPAUSE) jtag_add_pathmove(ARRAY_SIZE(arm11_move_pd_to_sd_via_cd), arm11_move_pd_to_sd_via_cd); jtag_add_dr_scan(tap, num_fields, fields, state); } /** Code de-clutter: Construct struct scan_field to write out a value * * \param arm11 Target state variable. * \param num_bits Length of the data field * \param out_data pointer to the data that will be sent out * (data is read when it is added to the JTAG queue) * \param in_data pointer to the memory that will receive data that was clocked in * (data is written when the JTAG queue is executed) * \param field target data structure that will be initialized */ void arm11_setup_field(struct arm11_common *arm11, int num_bits, void *out_data, void *in_data, struct scan_field *field) { field->num_bits = num_bits; field->out_value = out_data; field->in_value = in_data; } static const char *arm11_ir_to_string(uint8_t ir) { const char *s = "unknown"; switch (ir) { case ARM11_EXTEST: s = "EXTEST"; break; case ARM11_SCAN_N: s = "SCAN_N"; break; case ARM11_RESTART: s = "RESTART"; break; case ARM11_HALT: s = "HALT"; break; case ARM11_INTEST: s = "INTEST"; break; case ARM11_ITRSEL: s = "ITRSEL"; break; case ARM11_IDCODE: s = "IDCODE"; break; case ARM11_BYPASS: s = "BYPASS"; break; } return s; } /** Write JTAG instruction register * * \param arm11 Target state variable. * \param instr An ARM11 DBGTAP instruction. Use enum #arm11_instructions. * \param state Pass the final TAP state or ARM11_TAP_DEFAULT for the default value (Pause-IR). * * \remarks This adds to the JTAG command queue but does \em not execute it. */ void arm11_add_IR(struct arm11_common *arm11, uint8_t instr, tap_state_t state) { struct jtag_tap *tap = arm11->arm.target->tap; if (buf_get_u32(tap->cur_instr, 0, 5) == instr) { JTAG_DEBUG("IR <= 0x%02x SKIPPED", instr); return; } JTAG_DEBUG("IR <= %s (0x%02x)", arm11_ir_to_string(instr), instr); struct scan_field field; arm11_setup_field(arm11, 5, &instr, NULL, &field); arm11_add_ir_scan_vc(arm11->arm.target->tap, &field, state == ARM11_TAP_DEFAULT ? TAP_IRPAUSE : state); } /** Verify data shifted out from Scan Chain Register (SCREG). */ static void arm11_in_handler_SCAN_N(uint8_t *in_value) { /* Don't expect JTAG layer to modify bits we didn't ask it to read */ uint8_t v = *in_value & 0x1F; if (v != 0x10) { LOG_ERROR("'arm11 target' JTAG error SCREG OUT 0x%02x", v); jtag_set_error(ERROR_FAIL); } } /** Select and write to Scan Chain Register (SCREG) * * This function sets the instruction register to SCAN_N and writes * the data register with the selected chain number. * * http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301f/Cacbjhfg.html * * \param arm11 Target state variable. * \param chain Scan chain that will be selected. * \param state Pass the final TAP state or ARM11_TAP_DEFAULT for the default * value (Pause-DR). * * Changes the current scan chain if needed, transitions to the specified * TAP state, and leaves the IR undefined. * * The chain takes effect when Update-DR is passed (usually when subsequently * the INTEXT/EXTEST instructions are written). * * \warning (Obsolete) Using this twice in a row will \em fail. The first * call will end in Pause-DR. The second call, due to the IR * caching, will not go through Capture-DR when shifting in the * new scan chain number. As a result the verification in * arm11_in_handler_SCAN_N() must fail. * * \remarks This adds to the JTAG command queue but does \em not execute it. */ int arm11_add_debug_SCAN_N(struct arm11_common *arm11, uint8_t chain, tap_state_t state) { /* Don't needlessly switch the scan chain. * NOTE: the ITRSEL instruction fakes SCREG changing; * but leaves its actual value unchanged. */ #if 0 /* FIX!!! the optimization below is broken because we do not */ /* invalidate the cur_scan_chain upon a TRST/TMS. See arm_jtag.c */ /* for example on how to invalidate cur_scan_chain. Tested patches gladly */ /* accepted! */ if (arm11->jtag_info.cur_scan_chain == chain) { JTAG_DEBUG("SCREG <= %d SKIPPED", chain); return jtag_add_statemove((state == ARM11_TAP_DEFAULT) ? TAP_DRPAUSE : state); } #endif JTAG_DEBUG("SCREG <= %d", chain); arm11_add_IR(arm11, ARM11_SCAN_N, ARM11_TAP_DEFAULT); struct scan_field field; uint8_t tmp[1]; arm11_setup_field(arm11, 5, &chain, &tmp, &field); arm11_add_dr_scan_vc(arm11->arm.target->tap, 1, &field, state == ARM11_TAP_DEFAULT ? TAP_DRPAUSE : state); jtag_execute_queue_noclear(); arm11_in_handler_SCAN_N(tmp); arm11->jtag_info.cur_scan_chain = chain; return jtag_execute_queue(); } /** * Queue a DR scan of the ITR register. Caller must have selected * scan chain 4 (ITR), possibly using ITRSEL. * * \param arm11 Target state variable. * \param inst An ARM11 processor instruction/opcode. * \param flag Optional parameter to retrieve the Ready flag; * this address will be written when the JTAG chain is scanned. * \param state The TAP state to enter after the DR scan. * * Going through the TAP_DRUPDATE state writes ITR only if Ready was * previously set. Only the Ready flag is readable by the scan. * * An instruction loaded into ITR is executed when going through the * TAP_IDLE state only if Ready was previously set and the debug state * is properly set up. Depending on the instruction, you may also need * to ensure that the rDTR is ready before that Run-Test/Idle state. */ static void arm11_add_debug_INST(struct arm11_common *arm11, uint32_t inst, uint8_t *flag, tap_state_t state) { JTAG_DEBUG("INST <= 0x%08x", (unsigned) inst); struct scan_field itr[2]; arm11_setup_field(arm11, 32, &inst, NULL, itr + 0); arm11_setup_field(arm11, 1, NULL, flag, itr + 1); arm11_add_dr_scan_vc(arm11->arm.target->tap, ARRAY_SIZE(itr), itr, state); } /** * Read and save the Debug Status and Control Register (DSCR). * * \param arm11 Target state variable. * \return Error status; arm11->dscr is updated on success. * * \remarks This is a stand-alone function that executes the JTAG * command queue. It does not require the ARM11 debug TAP to be * in any particular state. */ int arm11_read_DSCR(struct arm11_common *arm11) { int retval; retval = arm11_add_debug_SCAN_N(arm11, 0x01, ARM11_TAP_DEFAULT); if (retval != ERROR_OK) return retval; arm11_add_IR(arm11, ARM11_INTEST, ARM11_TAP_DEFAULT); uint32_t dscr; struct scan_field chain1_field; arm11_setup_field(arm11, 32, NULL, &dscr, &chain1_field); arm11_add_dr_scan_vc(arm11->arm.target->tap, 1, &chain1_field, TAP_DRPAUSE); CHECK_RETVAL(jtag_execute_queue()); if (arm11->dscr != dscr) JTAG_DEBUG("DSCR = %08x (OLD %08x)", (unsigned) dscr, (unsigned) arm11->dscr); arm11->dscr = dscr; return ERROR_OK; } /** Write the Debug Status and Control Register (DSCR) * * same as CP14 c1 * * \param arm11 Target state variable. * \param dscr DSCR content * * \remarks This is a stand-alone function that executes the JTAG command queue. */ int arm11_write_DSCR(struct arm11_common *arm11, uint32_t dscr) { int retval; retval = arm11_add_debug_SCAN_N(arm11, 0x01, ARM11_TAP_DEFAULT); if (retval != ERROR_OK) return retval; arm11_add_IR(arm11, ARM11_EXTEST, ARM11_TAP_DEFAULT); struct scan_field chain1_field; arm11_setup_field(arm11, 32, &dscr, NULL, &chain1_field); arm11_add_dr_scan_vc(arm11->arm.target->tap, 1, &chain1_field, TAP_DRPAUSE); CHECK_RETVAL(jtag_execute_queue()); JTAG_DEBUG("DSCR <= %08x (OLD %08x)", (unsigned) dscr, (unsigned) arm11->dscr); arm11->dscr = dscr; return ERROR_OK; } /** Prepare the stage for ITR/DTR operations * from the arm11_run_instr... group of functions. * * Put arm11_run_instr_data_prepare() and arm11_run_instr_data_finish() * around a block of arm11_run_instr_... calls. * * Select scan chain 5 to allow quick access to DTR. When scan * chain 4 is needed to put in a register the ITRSel instruction * shortcut is used instead of actually changing the Scan_N * register. * * \param arm11 Target state variable. * */ int arm11_run_instr_data_prepare(struct arm11_common *arm11) { return arm11_add_debug_SCAN_N(arm11, 0x05, ARM11_TAP_DEFAULT); } /** Cleanup after ITR/DTR operations * from the arm11_run_instr... group of functions * * Put arm11_run_instr_data_prepare() and arm11_run_instr_data_finish() * around a block of arm11_run_instr_... calls. * * Any IDLE can lead to an instruction execution when * scan chains 4 or 5 are selected and the IR holds * INTEST or EXTEST. So we must disable that before * any following activities lead to an IDLE. * * \param arm11 Target state variable. * */ int arm11_run_instr_data_finish(struct arm11_common *arm11) { return arm11_add_debug_SCAN_N(arm11, 0x00, ARM11_TAP_DEFAULT); } /** * Execute one or more instructions via ITR. * Caller guarantees that processor is in debug state, that DSCR_ITR_EN * is set, the ITR Ready flag is set (as seen on the previous entry to * TAP_DRCAPTURE), and the DSCR sticky abort flag is clear. * * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block * * \param arm11 Target state variable. * \param opcode Pointer to sequence of ARM opcodes * \param count Number of opcodes to execute * */ static int arm11_run_instr_no_data(struct arm11_common *arm11, uint32_t *opcode, size_t count) { arm11_add_IR(arm11, ARM11_ITRSEL, ARM11_TAP_DEFAULT); while (count--) { arm11_add_debug_INST(arm11, *opcode++, NULL, TAP_IDLE); int i = 0; while (1) { uint8_t flag; arm11_add_debug_INST(arm11, 0, &flag, count ? TAP_IDLE : TAP_DRPAUSE); CHECK_RETVAL(jtag_execute_queue()); if (flag) break; long long then = 0; if (i == 1000) then = timeval_ms(); if (i >= 1000) { if ((timeval_ms()-then) > 1000) { LOG_WARNING( "Timeout (1000ms) waiting for instructions to complete"); return ERROR_FAIL; } } i++; } } return ERROR_OK; } /** Execute one instruction via ITR * * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block * * \param arm11 Target state variable. * \param opcode ARM opcode * */ int arm11_run_instr_no_data1(struct arm11_common *arm11, uint32_t opcode) { return arm11_run_instr_no_data(arm11, &opcode, 1); } /** Execute one instruction via ITR repeatedly while * passing data to the core via DTR on each execution. * * Caller guarantees that processor is in debug state, that DSCR_ITR_EN * is set, the ITR Ready flag is set (as seen on the previous entry to * TAP_DRCAPTURE), and the DSCR sticky abort flag is clear. * * The executed instruction \em must read data from DTR. * * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block * * \param arm11 Target state variable. * \param opcode ARM opcode * \param data Pointer to the data words to be passed to the core * \param count Number of data words and instruction repetitions * */ int arm11_run_instr_data_to_core(struct arm11_common *arm11, uint32_t opcode, uint32_t *data, size_t count) { arm11_add_IR(arm11, ARM11_ITRSEL, ARM11_TAP_DEFAULT); arm11_add_debug_INST(arm11, opcode, NULL, TAP_DRPAUSE); arm11_add_IR(arm11, ARM11_EXTEST, ARM11_TAP_DEFAULT); struct scan_field chain5_fields[3]; uint32_t Data; uint8_t Ready; uint8_t nRetry; arm11_setup_field(arm11, 32, &Data, NULL, chain5_fields + 0); arm11_setup_field(arm11, 1, NULL, &Ready, chain5_fields + 1); arm11_setup_field(arm11, 1, NULL, &nRetry, chain5_fields + 2); while (count--) { int i = 0; do { Data = *data; arm11_add_dr_scan_vc(arm11->arm.target->tap, ARRAY_SIZE( chain5_fields), chain5_fields, TAP_IDLE); CHECK_RETVAL(jtag_execute_queue()); JTAG_DEBUG("DTR Ready %d nRetry %d", Ready, nRetry); long long then = 0; if (i == 1000) then = timeval_ms(); if (i >= 1000) { if ((timeval_ms()-then) > 1000) { LOG_WARNING( "Timeout (1000ms) waiting for instructions to complete"); return ERROR_FAIL; } } i++; } while (!Ready); data++; } arm11_add_IR(arm11, ARM11_INTEST, ARM11_TAP_DEFAULT); int i = 0; do { Data = 0; arm11_add_dr_scan_vc(arm11->arm.target->tap, ARRAY_SIZE( chain5_fields), chain5_fields, TAP_DRPAUSE); CHECK_RETVAL(jtag_execute_queue()); JTAG_DEBUG("DTR Data %08x Ready %d nRetry %d", (unsigned) Data, Ready, nRetry); long long then = 0; if (i == 1000) then = timeval_ms(); if (i >= 1000) { if ((timeval_ms()-then) > 1000) { LOG_WARNING("Timeout (1000ms) waiting for instructions to complete"); return ERROR_FAIL; } } i++; } while (!Ready); return ERROR_OK; } /** JTAG path for arm11_run_instr_data_to_core_noack * * The repeated TAP_IDLE's do not cause a repeated execution * if passed without leaving the state. * * Since this is more than 7 bits (adjustable via adding more * TAP_IDLE's) it produces an artificial delay in the lower * layer (FT2232) that is long enough to finish execution on * the core but still shorter than any manually inducible delays. * * To disable this code, try "memwrite burst false" * * FIX!!! should we use multiple TAP_IDLE here or not??? * * https://lists.berlios.de/pipermail/openocd-development/2009-July/009698.html * https://lists.berlios.de/pipermail/openocd-development/2009-August/009865.html */ static const tap_state_t arm11_MOVE_DRPAUSE_IDLE_DRPAUSE_with_delay[] = { TAP_DREXIT2, TAP_DRUPDATE, TAP_IDLE, TAP_IDLE, TAP_IDLE, TAP_DRSELECT, TAP_DRCAPTURE, TAP_DRSHIFT }; /* This inner loop can be implemented by the minidriver, oftentimes in hardware... The * minidriver can call the default implementation as a fallback or implement it * from scratch. */ int arm11_run_instr_data_to_core_noack_inner_default(struct jtag_tap *tap, uint32_t opcode, uint32_t *data, size_t count) { struct scan_field chain5_fields[3]; chain5_fields[0].num_bits = 32; chain5_fields[0].out_value = NULL; /*&Data*/ chain5_fields[0].in_value = NULL; chain5_fields[1].num_bits = 1; chain5_fields[1].out_value = NULL; chain5_fields[1].in_value = NULL; /*&Ready*/ chain5_fields[2].num_bits = 1; chain5_fields[2].out_value = NULL; chain5_fields[2].in_value = NULL; uint8_t *Readies; unsigned readiesNum = count; unsigned bytes = sizeof(*Readies)*readiesNum; Readies = (uint8_t *) malloc(bytes); if (Readies == NULL) { LOG_ERROR("Out of memory allocating %u bytes", bytes); return ERROR_FAIL; } uint8_t *ReadyPos = Readies; while (count--) { chain5_fields[0].out_value = (void *)(data++); chain5_fields[1].in_value = ReadyPos++; if (count > 0) { jtag_add_dr_scan(tap, ARRAY_SIZE(chain5_fields), chain5_fields, TAP_DRPAUSE); jtag_add_pathmove(ARRAY_SIZE(arm11_MOVE_DRPAUSE_IDLE_DRPAUSE_with_delay), arm11_MOVE_DRPAUSE_IDLE_DRPAUSE_with_delay); } else jtag_add_dr_scan(tap, ARRAY_SIZE(chain5_fields), chain5_fields, TAP_IDLE); } int retval = jtag_execute_queue(); if (retval == ERROR_OK) { unsigned error_count = 0; for (size_t i = 0; i < readiesNum; i++) { if (Readies[i] != 1) error_count++; } if (error_count > 0) { LOG_ERROR("%u words out of %u not transferred", error_count, readiesNum); retval = ERROR_FAIL; } } free(Readies); return retval; } int arm11_run_instr_data_to_core_noack_inner(struct jtag_tap *tap, uint32_t opcode, uint32_t *data, size_t count); #ifndef HAVE_JTAG_MINIDRIVER_H int arm11_run_instr_data_to_core_noack_inner(struct jtag_tap *tap, uint32_t opcode, uint32_t *data, size_t count) { return arm11_run_instr_data_to_core_noack_inner_default(tap, opcode, data, count); } #endif /** Execute one instruction via ITR repeatedly while * passing data to the core via DTR on each execution. * * Caller guarantees that processor is in debug state, that DSCR_ITR_EN * is set, the ITR Ready flag is set (as seen on the previous entry to * TAP_DRCAPTURE), and the DSCR sticky abort flag is clear. * * No Ready check during transmission. * * The executed instruction \em must read data from DTR. * * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block * * \param arm11 Target state variable. * \param opcode ARM opcode * \param data Pointer to the data words to be passed to the core * \param count Number of data words and instruction repetitions * */ int arm11_run_instr_data_to_core_noack(struct arm11_common *arm11, uint32_t opcode, uint32_t *data, size_t count) { arm11_add_IR(arm11, ARM11_ITRSEL, ARM11_TAP_DEFAULT); arm11_add_debug_INST(arm11, opcode, NULL, TAP_DRPAUSE); arm11_add_IR(arm11, ARM11_EXTEST, ARM11_TAP_DEFAULT); int retval = arm11_run_instr_data_to_core_noack_inner(arm11->arm.target->tap, opcode, data, count); if (retval != ERROR_OK) return retval; arm11_add_IR(arm11, ARM11_INTEST, ARM11_TAP_DEFAULT); struct scan_field chain5_fields[3]; arm11_setup_field(arm11, 32, NULL /*&Data*/, NULL, chain5_fields + 0); arm11_setup_field(arm11, 1, NULL, NULL /*&Ready*/, chain5_fields + 1); arm11_setup_field(arm11, 1, NULL, NULL, chain5_fields + 2); uint8_t ready_flag; chain5_fields[1].in_value = &ready_flag; arm11_add_dr_scan_vc(arm11->arm.target->tap, ARRAY_SIZE( chain5_fields), chain5_fields, TAP_DRPAUSE); retval = jtag_execute_queue(); if (retval == ERROR_OK) { if (ready_flag != 1) { LOG_ERROR("last word not transferred"); retval = ERROR_FAIL; } } return retval; } /** Execute an instruction via ITR while handing data into the core via DTR. * * The executed instruction \em must read data from DTR. * * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block * * \param arm11 Target state variable. * \param opcode ARM opcode * \param data Data word to be passed to the core via DTR * */ int arm11_run_instr_data_to_core1(struct arm11_common *arm11, uint32_t opcode, uint32_t data) { return arm11_run_instr_data_to_core(arm11, opcode, &data, 1); } /** Execute one instruction via ITR repeatedly while * reading data from the core via DTR on each execution. * * Caller guarantees that processor is in debug state, that DSCR_ITR_EN * is set, the ITR Ready flag is set (as seen on the previous entry to * TAP_DRCAPTURE), and the DSCR sticky abort flag is clear. * * The executed instruction \em must write data to DTR. * * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block * * \param arm11 Target state variable. * \param opcode ARM opcode * \param data Pointer to an array that receives the data words from the core * \param count Number of data words and instruction repetitions * */ int arm11_run_instr_data_from_core(struct arm11_common *arm11, uint32_t opcode, uint32_t *data, size_t count) { arm11_add_IR(arm11, ARM11_ITRSEL, ARM11_TAP_DEFAULT); arm11_add_debug_INST(arm11, opcode, NULL, TAP_IDLE); arm11_add_IR(arm11, ARM11_INTEST, ARM11_TAP_DEFAULT); struct scan_field chain5_fields[3]; uint32_t Data; uint8_t Ready; uint8_t nRetry; arm11_setup_field(arm11, 32, NULL, &Data, chain5_fields + 0); arm11_setup_field(arm11, 1, NULL, &Ready, chain5_fields + 1); arm11_setup_field(arm11, 1, NULL, &nRetry, chain5_fields + 2); while (count--) { int i = 0; do { arm11_add_dr_scan_vc(arm11->arm.target->tap, ARRAY_SIZE( chain5_fields), chain5_fields, count ? TAP_IDLE : TAP_DRPAUSE); CHECK_RETVAL(jtag_execute_queue()); JTAG_DEBUG("DTR Data %08x Ready %d nRetry %d", (unsigned) Data, Ready, nRetry); long long then = 0; if (i == 1000) then = timeval_ms(); if (i >= 1000) { if ((timeval_ms()-then) > 1000) { LOG_WARNING( "Timeout (1000ms) waiting for instructions to complete"); return ERROR_FAIL; } } i++; } while (!Ready); *data++ = Data; } return ERROR_OK; } /** Execute one instruction via ITR * then load r0 into DTR and read DTR from core. * * The first executed instruction (\p opcode) should write data to r0. * * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block * * \param arm11 Target state variable. * \param opcode ARM opcode to write r0 with the value of interest * \param data Pointer to a data word that receives the value from r0 after \p opcode was executed. * */ int arm11_run_instr_data_from_core_via_r0(struct arm11_common *arm11, uint32_t opcode, uint32_t *data) { int retval; retval = arm11_run_instr_no_data1(arm11, opcode); if (retval != ERROR_OK) return retval; /* MCR p14,0,R0,c0,c5,0 (move r0 -> wDTR -> local var) */ arm11_run_instr_data_from_core(arm11, 0xEE000E15, data, 1); return ERROR_OK; } /** Load data into core via DTR then move it to r0 then * execute one instruction via ITR * * The final executed instruction (\p opcode) should read data from r0. * * \pre arm11_run_instr_data_prepare() / arm11_run_instr_data_finish() block * * \param arm11 Target state variable. * \param opcode ARM opcode to read r0 act upon it * \param data Data word that will be written to r0 before \p opcode is executed * */ int arm11_run_instr_data_to_core_via_r0(struct arm11_common *arm11, uint32_t opcode, uint32_t data) { int retval; /* MRC p14,0,r0,c0,c5,0 */ retval = arm11_run_instr_data_to_core1(arm11, 0xEE100E15, data); if (retval != ERROR_OK) return retval; retval = arm11_run_instr_no_data1(arm11, opcode); if (retval != ERROR_OK) return retval; return ERROR_OK; } /** Apply reads and writes to scan chain 7 * * \see struct arm11_sc7_action * * \param arm11 Target state variable. * \param actions A list of read and/or write instructions * \param count Number of instructions in the list. * */ int arm11_sc7_run(struct arm11_common *arm11, struct arm11_sc7_action *actions, size_t count) { int retval; retval = arm11_add_debug_SCAN_N(arm11, 0x07, ARM11_TAP_DEFAULT); if (retval != ERROR_OK) return retval; arm11_add_IR(arm11, ARM11_EXTEST, ARM11_TAP_DEFAULT); struct scan_field chain7_fields[3]; uint8_t nRW; uint32_t DataOut; uint8_t AddressOut; uint8_t Ready; uint32_t DataIn; uint8_t AddressIn; arm11_setup_field(arm11, 1, &nRW, &Ready, chain7_fields + 0); arm11_setup_field(arm11, 32, &DataOut, &DataIn, chain7_fields + 1); arm11_setup_field(arm11, 7, &AddressOut, &AddressIn, chain7_fields + 2); for (size_t i = 0; i < count + 1; i++) { if (i < count) { nRW = actions[i].write ? 1 : 0; DataOut = actions[i].value; AddressOut = actions[i].address; } else { nRW = 1; DataOut = 0; AddressOut = 0; } /* Timeout here so we don't get stuck. */ int i_n = 0; while (1) { JTAG_DEBUG("SC7 <= c%-3d Data %08x %s", (unsigned) AddressOut, (unsigned) DataOut, nRW ? "write" : "read"); arm11_add_dr_scan_vc(arm11->arm.target->tap, ARRAY_SIZE(chain7_fields), chain7_fields, TAP_DRPAUSE); CHECK_RETVAL(jtag_execute_queue()); /* 'nRW' is 'Ready' on read out */ if (Ready) break; long long then = 0; if (i_n == 1000) then = timeval_ms(); if (i_n >= 1000) { if ((timeval_ms()-then) > 1000) { LOG_WARNING( "Timeout (1000ms) waiting for instructions to complete"); return ERROR_FAIL; } } i_n++; } if (!nRW) JTAG_DEBUG("SC7 => Data %08x", (unsigned) DataIn); if (i > 0) { if (actions[i - 1].address != AddressIn) LOG_WARNING("Scan chain 7 shifted out unexpected address"); if (!actions[i - 1].write) actions[i - 1].value = DataIn; else { if (actions[i - 1].value != DataIn) LOG_WARNING("Scan chain 7 shifted out unexpected data"); } } } return ERROR_OK; } /** Clear VCR and all breakpoints and watchpoints via scan chain 7 * * \param arm11 Target state variable. * */ int arm11_sc7_clear_vbw(struct arm11_common *arm11) { size_t clear_bw_size = arm11->brp + 1; struct arm11_sc7_action *clear_bw = malloc(sizeof(struct arm11_sc7_action) * clear_bw_size); struct arm11_sc7_action *pos = clear_bw; for (size_t i = 0; i < clear_bw_size; i++) { clear_bw[i].write = true; clear_bw[i].value = 0; } for (size_t i = 0; i < arm11->brp; i++) (pos++)->address = ARM11_SC7_BCR0 + i; (pos++)->address = ARM11_SC7_VCR; int retval; retval = arm11_sc7_run(arm11, clear_bw, clear_bw_size); free(clear_bw); return retval; } /** Write VCR register * * \param arm11 Target state variable. * \param value Value to be written */ int arm11_sc7_set_vcr(struct arm11_common *arm11, uint32_t value) { struct arm11_sc7_action set_vcr; set_vcr.write = true; set_vcr.address = ARM11_SC7_VCR; set_vcr.value = value; return arm11_sc7_run(arm11, &set_vcr, 1); } /** Read word from address * * \param arm11 Target state variable. * \param address Memory address to be read * \param result Pointer where to store result * */ int arm11_read_memory_word(struct arm11_common *arm11, uint32_t address, uint32_t *result) { int retval; retval = arm11_run_instr_data_prepare(arm11); if (retval != ERROR_OK) return retval; /* MRC p14,0,r0,c0,c5,0 (r0 = address) */ CHECK_RETVAL(arm11_run_instr_data_to_core1(arm11, 0xee100e15, address)); /* LDC p14,c5,[R0],#4 (DTR = [r0]) */ CHECK_RETVAL(arm11_run_instr_data_from_core(arm11, 0xecb05e01, result, 1)); return arm11_run_instr_data_finish(arm11); } /************************************************************************/ /* * ARM11 provider for the OpenOCD implementation of the standard * architectural ARM v6/v7 "Debug Programmer's Model" (DPM). */ static inline struct arm11_common *dpm_to_arm11(struct arm_dpm *dpm) { return container_of(dpm, struct arm11_common, dpm); } static int arm11_dpm_prepare(struct arm_dpm *dpm) { return arm11_run_instr_data_prepare(dpm_to_arm11(dpm)); } static int arm11_dpm_finish(struct arm_dpm *dpm) { return arm11_run_instr_data_finish(dpm_to_arm11(dpm)); } static int arm11_dpm_instr_write_data_dcc(struct arm_dpm *dpm, uint32_t opcode, uint32_t data) { return arm11_run_instr_data_to_core(dpm_to_arm11(dpm), opcode, &data, 1); } static int arm11_dpm_instr_write_data_r0(struct arm_dpm *dpm, uint32_t opcode, uint32_t data) { return arm11_run_instr_data_to_core_via_r0(dpm_to_arm11(dpm), opcode, data); } static int arm11_dpm_instr_read_data_dcc(struct arm_dpm *dpm, uint32_t opcode, uint32_t *data) { return arm11_run_instr_data_from_core(dpm_to_arm11(dpm), opcode, data, 1); } static int arm11_dpm_instr_read_data_r0(struct arm_dpm *dpm, uint32_t opcode, uint32_t *data) { return arm11_run_instr_data_from_core_via_r0(dpm_to_arm11(dpm), opcode, data); } /* Because arm11_sc7_run() takes a vector of actions, we batch breakpoint * and watchpoint operations instead of running them right away. Since we * pre-allocated our vector, we don't need to worry about space. */ static int arm11_bpwp_enable(struct arm_dpm *dpm, unsigned index_t, uint32_t addr, uint32_t control) { struct arm11_common *arm11 = dpm_to_arm11(dpm); struct arm11_sc7_action *action; action = arm11->bpwp_actions + arm11->bpwp_n; /* Invariant: this bp/wp is disabled. * It also happens that the core is halted here, but for * DPM-based cores we don't actually care about that. */ action[0].write = action[1].write = true; action[0].value = addr; action[1].value = control; switch (index_t) { case 0 ... 15: action[0].address = ARM11_SC7_BVR0 + index_t; action[1].address = ARM11_SC7_BCR0 + index_t; break; case 16 ... 32: index_t -= 16; action[0].address = ARM11_SC7_WVR0 + index_t; action[1].address = ARM11_SC7_WCR0 + index_t; break; default: return ERROR_FAIL; } arm11->bpwp_n += 2; return ERROR_OK; } static int arm11_bpwp_disable(struct arm_dpm *dpm, unsigned index_t) { struct arm11_common *arm11 = dpm_to_arm11(dpm); struct arm11_sc7_action *action; action = arm11->bpwp_actions + arm11->bpwp_n; action[0].write = true; action[0].value = 0; switch (index_t) { case 0 ... 15: action[0].address = ARM11_SC7_BCR0 + index_t; break; case 16 ... 32: index_t -= 16; action[0].address = ARM11_SC7_WCR0 + index_t; break; default: return ERROR_FAIL; } arm11->bpwp_n += 1; return ERROR_OK; } /** Flush any pending breakpoint and watchpoint updates. */ int arm11_bpwp_flush(struct arm11_common *arm11) { int retval; if (!arm11->bpwp_n) return ERROR_OK; retval = arm11_sc7_run(arm11, arm11->bpwp_actions, arm11->bpwp_n); arm11->bpwp_n = 0; return retval; } /** Set up high-level debug module utilities */ int arm11_dpm_init(struct arm11_common *arm11, uint32_t didr) { struct arm_dpm *dpm = &arm11->dpm; int retval; dpm->arm = &arm11->arm; dpm->didr = didr; dpm->prepare = arm11_dpm_prepare; dpm->finish = arm11_dpm_finish; dpm->instr_write_data_dcc = arm11_dpm_instr_write_data_dcc; dpm->instr_write_data_r0 = arm11_dpm_instr_write_data_r0; dpm->instr_read_data_dcc = arm11_dpm_instr_read_data_dcc; dpm->instr_read_data_r0 = arm11_dpm_instr_read_data_r0; dpm->bpwp_enable = arm11_bpwp_enable; dpm->bpwp_disable = arm11_bpwp_disable; retval = arm_dpm_setup(dpm); if (retval != ERROR_OK) return retval; /* alloc enough to enable all breakpoints and watchpoints at once */ arm11->bpwp_actions = calloc(2 * (dpm->nbp + dpm->nwp), sizeof *arm11->bpwp_actions); if (!arm11->bpwp_actions) return ERROR_FAIL; retval = arm_dpm_initialize(dpm); if (retval != ERROR_OK) return retval; return arm11_bpwp_flush(arm11); } openocd-0.7.0/src/target/breakpoints.h0000644000175000001440000000543012134336410014630 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef BREAKPOINTS_H #define BREAKPOINTS_H struct target; enum breakpoint_type { BKPT_HARD, BKPT_SOFT, }; enum watchpoint_rw { WPT_READ = 0, WPT_WRITE = 1, WPT_ACCESS = 2 }; struct breakpoint { uint32_t address; uint32_t asid; int length; enum breakpoint_type type; int set; uint8_t *orig_instr; struct breakpoint *next; uint32_t unique_id; int linked_BRP; }; struct watchpoint { uint32_t address; uint32_t length; uint32_t mask; uint32_t value; enum watchpoint_rw rw; int set; struct watchpoint *next; int unique_id; }; void breakpoint_clear_target(struct target *target); int breakpoint_add(struct target *target, uint32_t address, uint32_t length, enum breakpoint_type type); int context_breakpoint_add(struct target *target, uint32_t asid, uint32_t length, enum breakpoint_type type); int hybrid_breakpoint_add(struct target *target, uint32_t address, uint32_t asid, uint32_t length, enum breakpoint_type type); void breakpoint_remove(struct target *target, uint32_t address); struct breakpoint *breakpoint_find(struct target *target, uint32_t address); void watchpoint_clear_target(struct target *target); int watchpoint_add(struct target *target, uint32_t address, uint32_t length, enum watchpoint_rw rw, uint32_t value, uint32_t mask); void watchpoint_remove(struct target *target, uint32_t address); #endif /* BREAKPOINTS_H */ openocd-0.7.0/src/target/mips32_dmaacc.c0000644000175000001440000003414512134336410014714 00000000000000/*************************************************************************** * Copyright (C) 2008 by John McCarthy * * jgmcc@magma.ca * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2008 by David T.L. Wong * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "mips32_dmaacc.h" static int mips32_dmaacc_read_mem8(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint8_t *buf); static int mips32_dmaacc_read_mem16(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint16_t *buf); static int mips32_dmaacc_read_mem32(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint32_t *buf); static int mips32_dmaacc_write_mem8(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint8_t *buf); static int mips32_dmaacc_write_mem16(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint16_t *buf); static int mips32_dmaacc_write_mem32(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint32_t *buf); /* * The following logic shamelessly cloned from HairyDairyMaid's wrt54g_debrick * to support the Broadcom BCM5352 SoC in the Linksys WRT54GL wireless router * (and any others that support EJTAG DMA transfers). * Note: This only supports memory read/write. Since the BCM5352 doesn't * appear to support PRACC accesses, all debug functions except halt * do not work. Still, this does allow erasing/writing flash as well as * displaying/modifying memory and memory mapped registers. */ static int ejtag_dma_read(struct mips_ejtag *ejtag_info, uint32_t addr, uint32_t *data) { uint32_t v; uint32_t ejtag_ctrl; int retries = RETRY_ATTEMPTS; begin_ejtag_dma_read: /* Setup Address */ v = addr; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); mips_ejtag_drscan_32(ejtag_info, &v); /* Initiate DMA Read & set DSTRT */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); ejtag_ctrl = EJTAG_CTRL_DMAACC | EJTAG_CTRL_DRWN | EJTAG_CTRL_DMA_WORD | EJTAG_CTRL_DSTRT | ejtag_info->ejtag_ctrl; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); /* Wait for DSTRT to Clear */ do { ejtag_ctrl = EJTAG_CTRL_DMAACC | ejtag_info->ejtag_ctrl; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); } while (ejtag_ctrl & EJTAG_CTRL_DSTRT); /* Read Data */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA); mips_ejtag_drscan_32(ejtag_info, data); /* Clear DMA & Check DERR */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); ejtag_ctrl = ejtag_info->ejtag_ctrl; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); if (ejtag_ctrl & EJTAG_CTRL_DERR) { if (retries--) { LOG_ERROR("DMA Read Addr = %08" PRIx32 " Data = ERROR ON READ (retrying)", addr); goto begin_ejtag_dma_read; } else LOG_ERROR("DMA Read Addr = %08" PRIx32 " Data = ERROR ON READ", addr); return ERROR_JTAG_DEVICE_ERROR; } return ERROR_OK; } static int ejtag_dma_read_h(struct mips_ejtag *ejtag_info, uint32_t addr, uint16_t *data) { uint32_t v; uint32_t ejtag_ctrl; int retries = RETRY_ATTEMPTS; begin_ejtag_dma_read_h: /* Setup Address */ v = addr; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); mips_ejtag_drscan_32(ejtag_info, &v); /* Initiate DMA Read & set DSTRT */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); ejtag_ctrl = EJTAG_CTRL_DMAACC | EJTAG_CTRL_DRWN | EJTAG_CTRL_DMA_HALFWORD | EJTAG_CTRL_DSTRT | ejtag_info->ejtag_ctrl; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); /* Wait for DSTRT to Clear */ do { ejtag_ctrl = EJTAG_CTRL_DMAACC | ejtag_info->ejtag_ctrl; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); } while (ejtag_ctrl & EJTAG_CTRL_DSTRT); /* Read Data */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA); mips_ejtag_drscan_32(ejtag_info, &v); /* Clear DMA & Check DERR */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); ejtag_ctrl = ejtag_info->ejtag_ctrl; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); if (ejtag_ctrl & EJTAG_CTRL_DERR) { if (retries--) { LOG_ERROR("DMA Read Addr = %08" PRIx32 " Data = ERROR ON READ (retrying)", addr); goto begin_ejtag_dma_read_h; } else LOG_ERROR("DMA Read Addr = %08" PRIx32 " Data = ERROR ON READ", addr); return ERROR_JTAG_DEVICE_ERROR; } /* Handle the bigendian/littleendian */ if (addr & 0x2) *data = (v >> 16) & 0xffff; else *data = (v & 0x0000ffff); return ERROR_OK; } static int ejtag_dma_read_b(struct mips_ejtag *ejtag_info, uint32_t addr, uint8_t *data) { uint32_t v; uint32_t ejtag_ctrl; int retries = RETRY_ATTEMPTS; begin_ejtag_dma_read_b: /* Setup Address */ v = addr; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); mips_ejtag_drscan_32(ejtag_info, &v); /* Initiate DMA Read & set DSTRT */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); ejtag_ctrl = EJTAG_CTRL_DMAACC | EJTAG_CTRL_DRWN | EJTAG_CTRL_DMA_BYTE | EJTAG_CTRL_DSTRT | ejtag_info->ejtag_ctrl; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); /* Wait for DSTRT to Clear */ do { ejtag_ctrl = EJTAG_CTRL_DMAACC | ejtag_info->ejtag_ctrl; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); } while (ejtag_ctrl & EJTAG_CTRL_DSTRT); /* Read Data */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA); mips_ejtag_drscan_32(ejtag_info, &v); /* Clear DMA & Check DERR */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); ejtag_ctrl = ejtag_info->ejtag_ctrl; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); if (ejtag_ctrl & EJTAG_CTRL_DERR) { if (retries--) { LOG_ERROR("DMA Read Addr = %08" PRIx32 " Data = ERROR ON READ (retrying)", addr); goto begin_ejtag_dma_read_b; } else LOG_ERROR("DMA Read Addr = %08" PRIx32 " Data = ERROR ON READ", addr); return ERROR_JTAG_DEVICE_ERROR; } /* Handle the bigendian/littleendian */ switch (addr & 0x3) { case 0: *data = v & 0xff; break; case 1: *data = (v >> 8) & 0xff; break; case 2: *data = (v >> 16) & 0xff; break; case 3: *data = (v >> 24) & 0xff; break; } return ERROR_OK; } static int ejtag_dma_write(struct mips_ejtag *ejtag_info, uint32_t addr, uint32_t data) { uint32_t v; uint32_t ejtag_ctrl; int retries = RETRY_ATTEMPTS; begin_ejtag_dma_write: /* Setup Address */ v = addr; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); mips_ejtag_drscan_32(ejtag_info, &v); /* Setup Data */ v = data; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA); mips_ejtag_drscan_32(ejtag_info, &v); /* Initiate DMA Write & set DSTRT */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); ejtag_ctrl = EJTAG_CTRL_DMAACC | EJTAG_CTRL_DMA_WORD | EJTAG_CTRL_DSTRT | ejtag_info->ejtag_ctrl; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); /* Wait for DSTRT to Clear */ do { ejtag_ctrl = EJTAG_CTRL_DMAACC | ejtag_info->ejtag_ctrl; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); } while (ejtag_ctrl & EJTAG_CTRL_DSTRT); /* Clear DMA & Check DERR */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); ejtag_ctrl = ejtag_info->ejtag_ctrl; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); if (ejtag_ctrl & EJTAG_CTRL_DERR) { if (retries--) { LOG_ERROR("DMA Write Addr = %08" PRIx32 " Data = ERROR ON WRITE (retrying)", addr); goto begin_ejtag_dma_write; } else LOG_ERROR("DMA Write Addr = %08" PRIx32 " Data = ERROR ON WRITE", addr); return ERROR_JTAG_DEVICE_ERROR; } return ERROR_OK; } static int ejtag_dma_write_h(struct mips_ejtag *ejtag_info, uint32_t addr, uint32_t data) { uint32_t v; uint32_t ejtag_ctrl; int retries = RETRY_ATTEMPTS; /* Handle the bigendian/littleendian */ data &= 0xffff; data |= data << 16; begin_ejtag_dma_write_h: /* Setup Address */ v = addr; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); mips_ejtag_drscan_32(ejtag_info, &v); /* Setup Data */ v = data; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA); mips_ejtag_drscan_32(ejtag_info, &v); /* Initiate DMA Write & set DSTRT */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); ejtag_ctrl = EJTAG_CTRL_DMAACC | EJTAG_CTRL_DMA_HALFWORD | EJTAG_CTRL_DSTRT | ejtag_info->ejtag_ctrl; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); /* Wait for DSTRT to Clear */ do { ejtag_ctrl = EJTAG_CTRL_DMAACC | ejtag_info->ejtag_ctrl; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); } while (ejtag_ctrl & EJTAG_CTRL_DSTRT); /* Clear DMA & Check DERR */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); ejtag_ctrl = ejtag_info->ejtag_ctrl; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); if (ejtag_ctrl & EJTAG_CTRL_DERR) { if (retries--) { LOG_ERROR("DMA Write Addr = %08" PRIx32 " Data = ERROR ON WRITE (retrying)", addr); goto begin_ejtag_dma_write_h; } else LOG_ERROR("DMA Write Addr = %08" PRIx32 " Data = ERROR ON WRITE", addr); return ERROR_JTAG_DEVICE_ERROR; } return ERROR_OK; } static int ejtag_dma_write_b(struct mips_ejtag *ejtag_info, uint32_t addr, uint32_t data) { uint32_t v; uint32_t ejtag_ctrl; int retries = RETRY_ATTEMPTS; /* Handle the bigendian/littleendian */ data &= 0xff; data |= data << 8; data |= data << 16; begin_ejtag_dma_write_b: /* Setup Address*/ v = addr; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); mips_ejtag_drscan_32(ejtag_info, &v); /* Setup Data */ v = data; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA); mips_ejtag_drscan_32(ejtag_info, &v); /* Initiate DMA Write & set DSTRT */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); ejtag_ctrl = EJTAG_CTRL_DMAACC | EJTAG_CTRL_DMA_BYTE | EJTAG_CTRL_DSTRT | ejtag_info->ejtag_ctrl; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); /* Wait for DSTRT to Clear */ do { ejtag_ctrl = EJTAG_CTRL_DMAACC | ejtag_info->ejtag_ctrl; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); } while (ejtag_ctrl & EJTAG_CTRL_DSTRT); /* Clear DMA & Check DERR */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); ejtag_ctrl = ejtag_info->ejtag_ctrl; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); if (ejtag_ctrl & EJTAG_CTRL_DERR) { if (retries--) { LOG_ERROR("DMA Write Addr = %08" PRIx32 " Data = ERROR ON WRITE (retrying)", addr); goto begin_ejtag_dma_write_b; } else LOG_ERROR("DMA Write Addr = %08" PRIx32 " Data = ERROR ON WRITE", addr); return ERROR_JTAG_DEVICE_ERROR; } return ERROR_OK; } int mips32_dmaacc_read_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, void *buf) { switch (size) { case 1: return mips32_dmaacc_read_mem8(ejtag_info, addr, count, (uint8_t *)buf); case 2: return mips32_dmaacc_read_mem16(ejtag_info, addr, count, (uint16_t *)buf); case 4: return mips32_dmaacc_read_mem32(ejtag_info, addr, count, (uint32_t *)buf); } return ERROR_OK; } static int mips32_dmaacc_read_mem32(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint32_t *buf) { int i; int retval; for (i = 0; i < count; i++) { retval = ejtag_dma_read(ejtag_info, addr + i * sizeof(*buf), &buf[i]); if (retval != ERROR_OK) return retval; } return ERROR_OK; } static int mips32_dmaacc_read_mem16(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint16_t *buf) { int i; int retval; for (i = 0; i < count; i++) { retval = ejtag_dma_read_h(ejtag_info, addr + i * sizeof(*buf), &buf[i]); if (retval != ERROR_OK) return retval; } return ERROR_OK; } static int mips32_dmaacc_read_mem8(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint8_t *buf) { int i; int retval; for (i = 0; i < count; i++) { retval = ejtag_dma_read_b(ejtag_info, addr + i * sizeof(*buf), &buf[i]); if (retval != ERROR_OK) return retval; } return ERROR_OK; } int mips32_dmaacc_write_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, void *buf) { switch (size) { case 1: return mips32_dmaacc_write_mem8(ejtag_info, addr, count, (uint8_t *)buf); case 2: return mips32_dmaacc_write_mem16(ejtag_info, addr, count, (uint16_t *)buf); case 4: return mips32_dmaacc_write_mem32(ejtag_info, addr, count, (uint32_t *)buf); } return ERROR_OK; } static int mips32_dmaacc_write_mem32(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint32_t *buf) { int i; int retval; for (i = 0; i < count; i++) { retval = ejtag_dma_write(ejtag_info, addr + i * sizeof(*buf), buf[i]); if (retval != ERROR_OK) return retval; } return ERROR_OK; } static int mips32_dmaacc_write_mem16(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint16_t *buf) { int i; int retval; for (i = 0; i < count; i++) { retval = ejtag_dma_write_h(ejtag_info, addr + i * sizeof(*buf), buf[i]); if (retval != ERROR_OK) return retval; } return ERROR_OK; } static int mips32_dmaacc_write_mem8(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint8_t *buf) { int i; int retval; for (i = 0; i < count; i++) { retval = ejtag_dma_write_b(ejtag_info, addr + i * sizeof(*buf), buf[i]); if (retval != ERROR_OK) return retval; } return ERROR_OK; } openocd-0.7.0/src/target/arm_adi_v5.c0000644000175000001440000015116312137151331014315 00000000000000/*************************************************************************** * Copyright (C) 2006 by Magnus Lundin * * lundin@mlu.mine.nu * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2009-2010 by Oyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2009-2010 by David Brownell * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /** * @file * This file implements support for the ARM Debug Interface version 5 (ADIv5) * debugging architecture. Compared with previous versions, this includes * a low pin-count Serial Wire Debug (SWD) alternative to JTAG for message * transport, and focusses on memory mapped resources as defined by the * CoreSight architecture. * * A key concept in ADIv5 is the Debug Access Port, or DAP. A DAP has two * basic components: a Debug Port (DP) transporting messages to and from a * debugger, and an Access Port (AP) accessing resources. Three types of DP * are defined. One uses only JTAG for communication, and is called JTAG-DP. * One uses only SWD for communication, and is called SW-DP. The third can * use either SWD or JTAG, and is called SWJ-DP. The most common type of AP * is used to access memory mapped resources and is called a MEM-AP. Also a * JTAG-AP is also defined, bridging to JTAG resources; those are uncommon. * * This programming interface allows DAP pipelined operations through a * transaction queue. This primarily affects AP operations (such as using * a MEM-AP to access memory or registers). If the current transaction has * not finished by the time the next one must begin, and the ORUNDETECT bit * is set in the DP_CTRL_STAT register, the SSTICKYORUN status is set and * further AP operations will fail. There are two basic methods to avoid * such overrun errors. One involves polling for status instead of using * transaction piplining. The other involves adding delays to ensure the * AP has enough time to complete one operation before starting the next * one. (For JTAG these delays are controlled by memaccess_tck.) */ /* * Relevant specifications from ARM include: * * ARM(tm) Debug Interface v5 Architecture Specification ARM IHI 0031A * CoreSight(tm) v1.0 Architecture Specification ARM IHI 0029B * * CoreSight(tm) DAP-Lite TRM, ARM DDI 0316D * Cortex-M3(tm) TRM, ARM DDI 0337G */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "jtag/interface.h" #include "arm.h" #include "arm_adi_v5.h" #include /* ARM ADI Specification requires at least 10 bits used for TAR autoincrement */ /* uint32_t tar_block_size(uint32_t address) Return the largest block starting at address that does not cross a tar block size alignment boundary */ static uint32_t max_tar_block_size(uint32_t tar_autoincr_block, uint32_t address) { return (tar_autoincr_block - ((tar_autoincr_block - 1) & address)) >> 2; } /*************************************************************************** * * * DP and MEM-AP register access through APACC and DPACC * * * ***************************************************************************/ /** * Select one of the APs connected to the specified DAP. The * selection is implicitly used with future AP transactions. * This is a NOP if the specified AP is already selected. * * @param dap The DAP * @param apsel Number of the AP to (implicitly) use with further * transactions. This normally identifies a MEM-AP. */ void dap_ap_select(struct adiv5_dap *dap, uint8_t ap) { uint32_t new_ap = (ap << 24) & 0xFF000000; if (new_ap != dap->ap_current) { dap->ap_current = new_ap; /* Switching AP invalidates cached values. * Values MUST BE UPDATED BEFORE AP ACCESS. */ dap->ap_bank_value = -1; dap->ap_csw_value = -1; dap->ap_tar_value = -1; } } /** * Queue transactions setting up transfer parameters for the * currently selected MEM-AP. * * Subsequent transfers using registers like AP_REG_DRW or AP_REG_BD2 * initiate data reads or writes using memory or peripheral addresses. * If the CSW is configured for it, the TAR may be automatically * incremented after each transfer. * * @todo Rename to reflect it being specifically a MEM-AP function. * * @param dap The DAP connected to the MEM-AP. * @param csw MEM-AP Control/Status Word (CSW) register to assign. If this * matches the cached value, the register is not changed. * @param tar MEM-AP Transfer Address Register (TAR) to assign. If this * matches the cached address, the register is not changed. * * @return ERROR_OK if the transaction was properly queued, else a fault code. */ int dap_setup_accessport(struct adiv5_dap *dap, uint32_t csw, uint32_t tar) { int retval; csw = csw | CSW_DBGSWENABLE | CSW_MASTER_DEBUG | CSW_HPROT | dap->apcsw[dap->ap_current >> 24]; if (csw != dap->ap_csw_value) { /* LOG_DEBUG("DAP: Set CSW %x",csw); */ retval = dap_queue_ap_write(dap, AP_REG_CSW, csw); if (retval != ERROR_OK) return retval; dap->ap_csw_value = csw; } if (tar != dap->ap_tar_value) { /* LOG_DEBUG("DAP: Set TAR %x",tar); */ retval = dap_queue_ap_write(dap, AP_REG_TAR, tar); if (retval != ERROR_OK) return retval; dap->ap_tar_value = tar; } /* Disable TAR cache when autoincrementing */ if (csw & CSW_ADDRINC_MASK) dap->ap_tar_value = -1; return ERROR_OK; } /** * Asynchronous (queued) read of a word from memory or a system register. * * @param dap The DAP connected to the MEM-AP performing the read. * @param address Address of the 32-bit word to read; it must be * readable by the currently selected MEM-AP. * @param value points to where the word will be stored when the * transaction queue is flushed (assuming no errors). * * @return ERROR_OK for success. Otherwise a fault code. */ int mem_ap_read_u32(struct adiv5_dap *dap, uint32_t address, uint32_t *value) { int retval; /* Use banked addressing (REG_BDx) to avoid some link traffic * (updating TAR) when reading several consecutive addresses. */ retval = dap_setup_accessport(dap, CSW_32BIT | CSW_ADDRINC_OFF, address & 0xFFFFFFF0); if (retval != ERROR_OK) return retval; return dap_queue_ap_read(dap, AP_REG_BD0 | (address & 0xC), value); } /** * Synchronous read of a word from memory or a system register. * As a side effect, this flushes any queued transactions. * * @param dap The DAP connected to the MEM-AP performing the read. * @param address Address of the 32-bit word to read; it must be * readable by the currently selected MEM-AP. * @param value points to where the result will be stored. * * @return ERROR_OK for success; *value holds the result. * Otherwise a fault code. */ int mem_ap_read_atomic_u32(struct adiv5_dap *dap, uint32_t address, uint32_t *value) { int retval; retval = mem_ap_read_u32(dap, address, value); if (retval != ERROR_OK) return retval; return dap_run(dap); } /** * Asynchronous (queued) write of a word to memory or a system register. * * @param dap The DAP connected to the MEM-AP. * @param address Address to be written; it must be writable by * the currently selected MEM-AP. * @param value Word that will be written to the address when transaction * queue is flushed (assuming no errors). * * @return ERROR_OK for success. Otherwise a fault code. */ int mem_ap_write_u32(struct adiv5_dap *dap, uint32_t address, uint32_t value) { int retval; /* Use banked addressing (REG_BDx) to avoid some link traffic * (updating TAR) when writing several consecutive addresses. */ retval = dap_setup_accessport(dap, CSW_32BIT | CSW_ADDRINC_OFF, address & 0xFFFFFFF0); if (retval != ERROR_OK) return retval; return dap_queue_ap_write(dap, AP_REG_BD0 | (address & 0xC), value); } /** * Synchronous write of a word to memory or a system register. * As a side effect, this flushes any queued transactions. * * @param dap The DAP connected to the MEM-AP. * @param address Address to be written; it must be writable by * the currently selected MEM-AP. * @param value Word that will be written. * * @return ERROR_OK for success; the data was written. Otherwise a fault code. */ int mem_ap_write_atomic_u32(struct adiv5_dap *dap, uint32_t address, uint32_t value) { int retval = mem_ap_write_u32(dap, address, value); if (retval != ERROR_OK) return retval; return dap_run(dap); } /***************************************************************************** * * * mem_ap_write_buf(struct adiv5_dap *dap, uint8_t *buffer, int count, uint32_t address, bool addr_incr) * * * * Write a buffer in target order (little endian) * * * *****************************************************************************/ int mem_ap_write_buf_u32(struct adiv5_dap *dap, const uint8_t *buffer, int count, uint32_t address, bool addr_incr) { int wcount, blocksize, writecount, errorcount = 0, retval = ERROR_OK; uint32_t adr = address; const uint8_t *pBuffer = buffer; uint32_t incr_flag = CSW_ADDRINC_OFF; count >>= 2; wcount = count; /* if we have an unaligned access - reorder data */ if (adr & 0x3u) { for (writecount = 0; writecount < count; writecount++) { int i; uint32_t outvalue; memcpy(&outvalue, pBuffer, sizeof(uint32_t)); for (i = 0; i < 4; i++) { *((uint8_t *)pBuffer + (adr & 0x3)) = outvalue; outvalue >>= 8; adr++; } pBuffer += sizeof(uint32_t); } } while (wcount > 0) { /* Adjust to write blocks within boundaries aligned to the TAR autoincremnent size*/ blocksize = max_tar_block_size(dap->tar_autoincr_block, address); if (wcount < blocksize) blocksize = wcount; /* handle unaligned data at 4k boundary */ if (blocksize == 0) blocksize = 1; if (addr_incr) incr_flag = CSW_ADDRINC_SINGLE; retval = dap_setup_accessport(dap, CSW_32BIT | incr_flag, address); if (retval != ERROR_OK) return retval; for (writecount = 0; writecount < blocksize; writecount++) { uint32_t tmp; tmp = buf_get_u32(buffer + 4 * writecount, 0, 32); retval = dap_queue_ap_write(dap, AP_REG_DRW, tmp); if (retval != ERROR_OK) break; } retval = dap_run(dap); if (retval == ERROR_OK) { wcount = wcount - blocksize; if (addr_incr) address = address + 4 * blocksize; buffer = buffer + 4 * blocksize; } else errorcount++; if (errorcount > 1) { LOG_WARNING("Block write error address 0x%" PRIx32 ", wcount 0x%x", address, wcount); return retval; } } return retval; } static int mem_ap_write_buf_packed_u16(struct adiv5_dap *dap, const uint8_t *buffer, int count, uint32_t address) { int retval = ERROR_OK; int wcount, blocksize, writecount, i; wcount = count >> 1; while (wcount > 0) { int nbytes; /* Adjust to write blocks within boundaries aligned to the TAR autoincremnent size*/ blocksize = max_tar_block_size(dap->tar_autoincr_block, address); if (wcount < blocksize) blocksize = wcount; /* handle unaligned data at 4k boundary */ if (blocksize == 0) blocksize = 1; retval = dap_setup_accessport(dap, CSW_16BIT | CSW_ADDRINC_PACKED, address); if (retval != ERROR_OK) return retval; writecount = blocksize; do { nbytes = MIN((writecount << 1), 4); if (nbytes < 4) { retval = mem_ap_write_buf_u16(dap, buffer, nbytes, address); if (retval != ERROR_OK) { LOG_WARNING("Block write error address " "0x%" PRIx32 ", count 0x%x", address, count); return retval; } address += nbytes >> 1; } else { uint32_t outvalue; memcpy(&outvalue, buffer, sizeof(uint32_t)); for (i = 0; i < nbytes; i++) { *((uint8_t *)buffer + (address & 0x3)) = outvalue; outvalue >>= 8; address++; } memcpy(&outvalue, buffer, sizeof(uint32_t)); retval = dap_queue_ap_write(dap, AP_REG_DRW, outvalue); if (retval != ERROR_OK) break; retval = dap_run(dap); if (retval != ERROR_OK) { LOG_WARNING("Block write error address " "0x%" PRIx32 ", count 0x%x", address, count); return retval; } } buffer += nbytes >> 1; writecount -= nbytes >> 1; } while (writecount); wcount -= blocksize; } return retval; } int mem_ap_write_buf_u16(struct adiv5_dap *dap, const uint8_t *buffer, int count, uint32_t address) { int retval = ERROR_OK; if (count >= 4) return mem_ap_write_buf_packed_u16(dap, buffer, count, address); while (count > 0) { retval = dap_setup_accessport(dap, CSW_16BIT | CSW_ADDRINC_SINGLE, address); if (retval != ERROR_OK) return retval; uint16_t svalue; memcpy(&svalue, buffer, sizeof(uint16_t)); uint32_t outvalue = (uint32_t)svalue << 8 * (address & 0x3); retval = dap_queue_ap_write(dap, AP_REG_DRW, outvalue); if (retval != ERROR_OK) break; retval = dap_run(dap); if (retval != ERROR_OK) break; count -= 2; address += 2; buffer += 2; } return retval; } static int mem_ap_write_buf_packed_u8(struct adiv5_dap *dap, const uint8_t *buffer, int count, uint32_t address) { int retval = ERROR_OK; int wcount, blocksize, writecount, i; wcount = count; while (wcount > 0) { int nbytes; /* Adjust to write blocks within boundaries aligned to the TAR autoincremnent size*/ blocksize = max_tar_block_size(dap->tar_autoincr_block, address); if (wcount < blocksize) blocksize = wcount; retval = dap_setup_accessport(dap, CSW_8BIT | CSW_ADDRINC_PACKED, address); if (retval != ERROR_OK) return retval; writecount = blocksize; do { nbytes = MIN(writecount, 4); if (nbytes < 4) { retval = mem_ap_write_buf_u8(dap, buffer, nbytes, address); if (retval != ERROR_OK) { LOG_WARNING("Block write error address " "0x%" PRIx32 ", count 0x%x", address, count); return retval; } address += nbytes; } else { uint32_t outvalue; memcpy(&outvalue, buffer, sizeof(uint32_t)); for (i = 0; i < nbytes; i++) { *((uint8_t *)buffer + (address & 0x3)) = outvalue; outvalue >>= 8; address++; } memcpy(&outvalue, buffer, sizeof(uint32_t)); retval = dap_queue_ap_write(dap, AP_REG_DRW, outvalue); if (retval != ERROR_OK) break; retval = dap_run(dap); if (retval != ERROR_OK) { LOG_WARNING("Block write error address " "0x%" PRIx32 ", count 0x%x", address, count); return retval; } } buffer += nbytes; writecount -= nbytes; } while (writecount); wcount -= blocksize; } return retval; } int mem_ap_write_buf_u8(struct adiv5_dap *dap, const uint8_t *buffer, int count, uint32_t address) { int retval = ERROR_OK; if (count >= 4) return mem_ap_write_buf_packed_u8(dap, buffer, count, address); while (count > 0) { retval = dap_setup_accessport(dap, CSW_8BIT | CSW_ADDRINC_SINGLE, address); if (retval != ERROR_OK) return retval; uint32_t outvalue = (uint32_t)*buffer << 8 * (address & 0x3); retval = dap_queue_ap_write(dap, AP_REG_DRW, outvalue); if (retval != ERROR_OK) break; retval = dap_run(dap); if (retval != ERROR_OK) break; count--; address++; buffer++; } return retval; } /** * Synchronously read a block of 32-bit words into a buffer * @param dap The DAP connected to the MEM-AP. * @param buffer where the words will be stored (in host byte order). * @param count How many words to read. * @param address Memory address from which to read words; all the * @param addr_incr if true, increment the source address for each u32 * words must be readable by the currently selected MEM-AP. */ int mem_ap_read_buf_u32(struct adiv5_dap *dap, uint8_t *buffer, int count, uint32_t address, bool addr_incr) { int wcount, blocksize, readcount, errorcount = 0, retval = ERROR_OK; uint32_t adr = address; uint8_t *pBuffer = buffer; uint32_t incr_flag = CSW_ADDRINC_OFF; count >>= 2; wcount = count; while (wcount > 0) { /* Adjust to read blocks within boundaries aligned to the * TAR autoincrement size (at least 2^10). Autoincrement * mode avoids an extra per-word roundtrip to update TAR. */ blocksize = max_tar_block_size(dap->tar_autoincr_block, address); if (wcount < blocksize) blocksize = wcount; /* handle unaligned data at 4k boundary */ if (blocksize == 0) blocksize = 1; if (addr_incr) incr_flag = CSW_ADDRINC_SINGLE; retval = dap_setup_accessport(dap, CSW_32BIT | incr_flag, address); if (retval != ERROR_OK) return retval; retval = dap_queue_ap_read_block(dap, AP_REG_DRW, blocksize, buffer); retval = dap_run(dap); if (retval != ERROR_OK) { errorcount++; if (errorcount <= 1) { /* try again */ continue; } LOG_WARNING("Block read error address 0x%" PRIx32, address); return retval; } wcount = wcount - blocksize; if (addr_incr) address += 4 * blocksize; buffer += 4 * blocksize; } /* if we have an unaligned access - reorder data */ if (adr & 0x3u) { for (readcount = 0; readcount < count; readcount++) { int i; uint32_t data; memcpy(&data, pBuffer, sizeof(uint32_t)); for (i = 0; i < 4; i++) { *((uint8_t *)pBuffer) = (data >> 8 * (adr & 0x3)); pBuffer++; adr++; } } } return retval; } static int mem_ap_read_buf_packed_u16(struct adiv5_dap *dap, uint8_t *buffer, int count, uint32_t address) { uint32_t invalue; int retval = ERROR_OK; int wcount, blocksize, readcount, i; wcount = count >> 1; while (wcount > 0) { int nbytes; /* Adjust to read blocks within boundaries aligned to the TAR autoincremnent size*/ blocksize = max_tar_block_size(dap->tar_autoincr_block, address); if (wcount < blocksize) blocksize = wcount; retval = dap_setup_accessport(dap, CSW_16BIT | CSW_ADDRINC_PACKED, address); if (retval != ERROR_OK) return retval; /* handle unaligned data at 4k boundary */ if (blocksize == 0) blocksize = 1; readcount = blocksize; do { retval = dap_queue_ap_read(dap, AP_REG_DRW, &invalue); if (retval != ERROR_OK) return retval; retval = dap_run(dap); if (retval != ERROR_OK) { LOG_WARNING("Block read error address 0x%" PRIx32 ", count 0x%x", address, count); return retval; } nbytes = MIN((readcount << 1), 4); for (i = 0; i < nbytes; i++) { *((uint8_t *)buffer) = (invalue >> 8 * (address & 0x3)); buffer++; address++; } readcount -= (nbytes >> 1); } while (readcount); wcount -= blocksize; } return retval; } /** * Synchronously read a block of 16-bit halfwords into a buffer * @param dap The DAP connected to the MEM-AP. * @param buffer where the halfwords will be stored (in host byte order). * @param count How many halfwords to read. * @param address Memory address from which to read words; all the * words must be readable by the currently selected MEM-AP. */ int mem_ap_read_buf_u16(struct adiv5_dap *dap, uint8_t *buffer, int count, uint32_t address) { uint32_t invalue, i; int retval = ERROR_OK; if (count >= 4) return mem_ap_read_buf_packed_u16(dap, buffer, count, address); while (count > 0) { retval = dap_setup_accessport(dap, CSW_16BIT | CSW_ADDRINC_SINGLE, address); if (retval != ERROR_OK) return retval; retval = dap_queue_ap_read(dap, AP_REG_DRW, &invalue); if (retval != ERROR_OK) break; retval = dap_run(dap); if (retval != ERROR_OK) break; if (address & 0x1) { for (i = 0; i < 2; i++) { *((uint8_t *)buffer) = (invalue >> 8 * (address & 0x3)); buffer++; address++; } } else { uint16_t svalue = (invalue >> 8 * (address & 0x3)); memcpy(buffer, &svalue, sizeof(uint16_t)); address += 2; buffer += 2; } count -= 2; } return retval; } /* FIX!!! is this a potential performance bottleneck w.r.t. requiring too many * roundtrips when jtag_execute_queue() has a large overhead(e.g. for USB)s? * * The solution is to arrange for a large out/in scan in this loop and * and convert data afterwards. */ static int mem_ap_read_buf_packed_u8(struct adiv5_dap *dap, uint8_t *buffer, int count, uint32_t address) { uint32_t invalue; int retval = ERROR_OK; int wcount, blocksize, readcount, i; wcount = count; while (wcount > 0) { int nbytes; /* Adjust to read blocks within boundaries aligned to the TAR autoincremnent size*/ blocksize = max_tar_block_size(dap->tar_autoincr_block, address); if (wcount < blocksize) blocksize = wcount; retval = dap_setup_accessport(dap, CSW_8BIT | CSW_ADDRINC_PACKED, address); if (retval != ERROR_OK) return retval; readcount = blocksize; do { retval = dap_queue_ap_read(dap, AP_REG_DRW, &invalue); if (retval != ERROR_OK) return retval; retval = dap_run(dap); if (retval != ERROR_OK) { LOG_WARNING("Block read error address 0x%" PRIx32 ", count 0x%x", address, count); return retval; } nbytes = MIN(readcount, 4); for (i = 0; i < nbytes; i++) { *((uint8_t *)buffer) = (invalue >> 8 * (address & 0x3)); buffer++; address++; } readcount -= nbytes; } while (readcount); wcount -= blocksize; } return retval; } /** * Synchronously read a block of bytes into a buffer * @param dap The DAP connected to the MEM-AP. * @param buffer where the bytes will be stored. * @param count How many bytes to read. * @param address Memory address from which to read data; all the * data must be readable by the currently selected MEM-AP. */ int mem_ap_read_buf_u8(struct adiv5_dap *dap, uint8_t *buffer, int count, uint32_t address) { uint32_t invalue; int retval = ERROR_OK; if (count >= 4) return mem_ap_read_buf_packed_u8(dap, buffer, count, address); while (count > 0) { retval = dap_setup_accessport(dap, CSW_8BIT | CSW_ADDRINC_SINGLE, address); if (retval != ERROR_OK) return retval; retval = dap_queue_ap_read(dap, AP_REG_DRW, &invalue); if (retval != ERROR_OK) return retval; retval = dap_run(dap); if (retval != ERROR_OK) break; *((uint8_t *)buffer) = (invalue >> 8 * (address & 0x3)); count--; address++; buffer++; } return retval; } /*--------------------------------------------------------------------*/ /* Wrapping function with selection of AP */ /*--------------------------------------------------------------------*/ int mem_ap_sel_read_u32(struct adiv5_dap *swjdp, uint8_t ap, uint32_t address, uint32_t *value) { dap_ap_select(swjdp, ap); return mem_ap_read_u32(swjdp, address, value); } int mem_ap_sel_write_u32(struct adiv5_dap *swjdp, uint8_t ap, uint32_t address, uint32_t value) { dap_ap_select(swjdp, ap); return mem_ap_write_u32(swjdp, address, value); } int mem_ap_sel_read_atomic_u32(struct adiv5_dap *swjdp, uint8_t ap, uint32_t address, uint32_t *value) { dap_ap_select(swjdp, ap); return mem_ap_read_atomic_u32(swjdp, address, value); } int mem_ap_sel_write_atomic_u32(struct adiv5_dap *swjdp, uint8_t ap, uint32_t address, uint32_t value) { dap_ap_select(swjdp, ap); return mem_ap_write_atomic_u32(swjdp, address, value); } int mem_ap_sel_read_buf_u8(struct adiv5_dap *swjdp, uint8_t ap, uint8_t *buffer, int count, uint32_t address) { dap_ap_select(swjdp, ap); return mem_ap_read_buf_u8(swjdp, buffer, count, address); } int mem_ap_sel_read_buf_u16(struct adiv5_dap *swjdp, uint8_t ap, uint8_t *buffer, int count, uint32_t address) { dap_ap_select(swjdp, ap); return mem_ap_read_buf_u16(swjdp, buffer, count, address); } int mem_ap_sel_read_buf_u32_noincr(struct adiv5_dap *swjdp, uint8_t ap, uint8_t *buffer, int count, uint32_t address) { dap_ap_select(swjdp, ap); return mem_ap_read_buf_u32(swjdp, buffer, count, address, false); } int mem_ap_sel_read_buf_u32(struct adiv5_dap *swjdp, uint8_t ap, uint8_t *buffer, int count, uint32_t address) { dap_ap_select(swjdp, ap); return mem_ap_read_buf_u32(swjdp, buffer, count, address, true); } int mem_ap_sel_write_buf_u8(struct adiv5_dap *swjdp, uint8_t ap, const uint8_t *buffer, int count, uint32_t address) { dap_ap_select(swjdp, ap); return mem_ap_write_buf_u8(swjdp, buffer, count, address); } int mem_ap_sel_write_buf_u16(struct adiv5_dap *swjdp, uint8_t ap, const uint8_t *buffer, int count, uint32_t address) { dap_ap_select(swjdp, ap); return mem_ap_write_buf_u16(swjdp, buffer, count, address); } int mem_ap_sel_write_buf_u32(struct adiv5_dap *swjdp, uint8_t ap, const uint8_t *buffer, int count, uint32_t address) { dap_ap_select(swjdp, ap); return mem_ap_write_buf_u32(swjdp, buffer, count, address, true); } int mem_ap_sel_write_buf_u32_noincr(struct adiv5_dap *swjdp, uint8_t ap, const uint8_t *buffer, int count, uint32_t address) { dap_ap_select(swjdp, ap); return mem_ap_write_buf_u32(swjdp, buffer, count, address, false); } #define MDM_REG_STAT 0x00 #define MDM_REG_CTRL 0x04 #define MDM_REG_ID 0xfc #define MDM_STAT_FMEACK (1<<0) #define MDM_STAT_FREADY (1<<1) #define MDM_STAT_SYSSEC (1<<2) #define MDM_STAT_SYSRES (1<<3) #define MDM_STAT_FMEEN (1<<5) #define MDM_STAT_BACKDOOREN (1<<6) #define MDM_STAT_LPEN (1<<7) #define MDM_STAT_VLPEN (1<<8) #define MDM_STAT_LLSMODEXIT (1<<9) #define MDM_STAT_VLLSXMODEXIT (1<<10) #define MDM_STAT_CORE_HALTED (1<<16) #define MDM_STAT_CORE_SLEEPDEEP (1<<17) #define MDM_STAT_CORESLEEPING (1<<18) #define MEM_CTRL_FMEIP (1<<0) #define MEM_CTRL_DBG_DIS (1<<1) #define MEM_CTRL_DBG_REQ (1<<2) #define MEM_CTRL_SYS_RES_REQ (1<<3) #define MEM_CTRL_CORE_HOLD_RES (1<<4) #define MEM_CTRL_VLLSX_DBG_REQ (1<<5) #define MEM_CTRL_VLLSX_DBG_ACK (1<<6) #define MEM_CTRL_VLLSX_STAT_ACK (1<<7) /** * */ int dap_syssec_kinetis_mdmap(struct adiv5_dap *dap) { uint32_t val; int retval; enum reset_types jtag_reset_config = jtag_get_reset_config(); dap_ap_select(dap, 1); /* first check mdm-ap id register */ retval = dap_queue_ap_read(dap, MDM_REG_ID, &val); if (retval != ERROR_OK) return retval; dap_run(dap); if (val != 0x001C0000) { LOG_DEBUG("id doesn't match %08X != 0x001C0000", val); dap_ap_select(dap, 0); return ERROR_FAIL; } /* read and parse status register * it's important that the device is out of * reset here */ retval = dap_queue_ap_read(dap, MDM_REG_STAT, &val); if (retval != ERROR_OK) return retval; dap_run(dap); LOG_DEBUG("MDM_REG_STAT %08X", val); if ((val & (MDM_STAT_SYSSEC|MDM_STAT_FREADY)) != (MDM_STAT_FREADY)) { LOG_DEBUG("MDMAP: system is secured, masserase needed"); if (!(val & MDM_STAT_FMEEN)) LOG_DEBUG("MDMAP: masserase is disabled"); else { /* we need to assert reset */ if (jtag_reset_config & RESET_HAS_SRST) { /* default to asserting srst */ adapter_assert_reset(); } else { LOG_DEBUG("SRST not configured"); dap_ap_select(dap, 0); return ERROR_FAIL; } while (1) { retval = dap_queue_ap_write(dap, MDM_REG_CTRL, MEM_CTRL_FMEIP); if (retval != ERROR_OK) return retval; dap_run(dap); /* read status register and wait for ready */ retval = dap_queue_ap_read(dap, MDM_REG_STAT, &val); if (retval != ERROR_OK) return retval; dap_run(dap); LOG_DEBUG("MDM_REG_STAT %08X", val); if ((val & 1)) break; } while (1) { retval = dap_queue_ap_write(dap, MDM_REG_CTRL, 0); if (retval != ERROR_OK) return retval; dap_run(dap); /* read status register */ retval = dap_queue_ap_read(dap, MDM_REG_STAT, &val); if (retval != ERROR_OK) return retval; dap_run(dap); LOG_DEBUG("MDM_REG_STAT %08X", val); /* read control register and wait for ready */ retval = dap_queue_ap_read(dap, MDM_REG_CTRL, &val); if (retval != ERROR_OK) return retval; dap_run(dap); LOG_DEBUG("MDM_REG_CTRL %08X", val); if (val == 0x00) break; } } } dap_ap_select(dap, 0); return ERROR_OK; } /** */ struct dap_syssec_filter { /** */ uint32_t idcode; /** */ int (*dap_init)(struct adiv5_dap *dap); }; /** */ static struct dap_syssec_filter dap_syssec_filter_data[] = { { 0x4BA00477, dap_syssec_kinetis_mdmap } }; /** * */ int dap_syssec(struct adiv5_dap *dap) { unsigned int i; struct jtag_tap *tap; for (i = 0; i < sizeof(dap_syssec_filter_data); i++) { tap = dap->jtag_info->tap; while (tap != NULL) { if (tap->hasidcode && (dap_syssec_filter_data[i].idcode == tap->idcode)) { LOG_DEBUG("DAP: mdmap_init for idcode: %08x", tap->idcode); dap_syssec_filter_data[i].dap_init(dap); } tap = tap->next_tap; } } return ERROR_OK; } /*--------------------------------------------------------------------------*/ /* FIXME don't import ... just initialize as * part of DAP transport setup */ extern const struct dap_ops jtag_dp_ops; /*--------------------------------------------------------------------------*/ /** * Initialize a DAP. This sets up the power domains, prepares the DP * for further use, and arranges to use AP #0 for all AP operations * until dap_ap-select() changes that policy. * * @param dap The DAP being initialized. * * @todo Rename this. We also need an initialization scheme which account * for SWD transports not just JTAG; that will need to address differences * in layering. (JTAG is useful without any debug target; but not SWD.) * And this may not even use an AHB-AP ... e.g. DAP-Lite uses an APB-AP. */ int ahbap_debugport_init(struct adiv5_dap *dap) { uint32_t ctrlstat; int cnt = 0; int retval; LOG_DEBUG(" "); /* JTAG-DP or SWJ-DP, in JTAG mode * ... for SWD mode this is patched as part * of link switchover */ if (!dap->ops) dap->ops = &jtag_dp_ops; /* Default MEM-AP setup. * * REVISIT AP #0 may be an inappropriate default for this. * Should we probe, or take a hint from the caller? * Presumably we can ignore the possibility of multiple APs. */ dap->ap_current = !0; dap_ap_select(dap, 0); /* DP initialization */ retval = dap_queue_dp_read(dap, DP_CTRL_STAT, NULL); if (retval != ERROR_OK) return retval; retval = dap_queue_dp_write(dap, DP_CTRL_STAT, SSTICKYERR); if (retval != ERROR_OK) return retval; retval = dap_queue_dp_read(dap, DP_CTRL_STAT, NULL); if (retval != ERROR_OK) return retval; dap->dp_ctrl_stat = CDBGPWRUPREQ | CSYSPWRUPREQ; retval = dap_queue_dp_write(dap, DP_CTRL_STAT, dap->dp_ctrl_stat); if (retval != ERROR_OK) return retval; retval = dap_queue_dp_read(dap, DP_CTRL_STAT, &ctrlstat); if (retval != ERROR_OK) return retval; retval = dap_run(dap); if (retval != ERROR_OK) return retval; /* Check that we have debug power domains activated */ while (!(ctrlstat & CDBGPWRUPACK) && (cnt++ < 10)) { LOG_DEBUG("DAP: wait CDBGPWRUPACK"); retval = dap_queue_dp_read(dap, DP_CTRL_STAT, &ctrlstat); if (retval != ERROR_OK) return retval; retval = dap_run(dap); if (retval != ERROR_OK) return retval; alive_sleep(10); } while (!(ctrlstat & CSYSPWRUPACK) && (cnt++ < 10)) { LOG_DEBUG("DAP: wait CSYSPWRUPACK"); retval = dap_queue_dp_read(dap, DP_CTRL_STAT, &ctrlstat); if (retval != ERROR_OK) return retval; retval = dap_run(dap); if (retval != ERROR_OK) return retval; alive_sleep(10); } retval = dap_queue_dp_read(dap, DP_CTRL_STAT, NULL); if (retval != ERROR_OK) return retval; /* With debug power on we can activate OVERRUN checking */ dap->dp_ctrl_stat = CDBGPWRUPREQ | CSYSPWRUPREQ | CORUNDETECT; retval = dap_queue_dp_write(dap, DP_CTRL_STAT, dap->dp_ctrl_stat); if (retval != ERROR_OK) return retval; retval = dap_queue_dp_read(dap, DP_CTRL_STAT, NULL); if (retval != ERROR_OK) return retval; dap_syssec(dap); return ERROR_OK; } /* CID interpretation -- see ARM IHI 0029B section 3 * and ARM IHI 0031A table 13-3. */ static const char *class_description[16] = { "Reserved", "ROM table", "Reserved", "Reserved", "Reserved", "Reserved", "Reserved", "Reserved", "Reserved", "CoreSight component", "Reserved", "Peripheral Test Block", "Reserved", "OptimoDE DESS", "Generic IP component", "PrimeCell or System component" }; static bool is_dap_cid_ok(uint32_t cid3, uint32_t cid2, uint32_t cid1, uint32_t cid0) { return cid3 == 0xb1 && cid2 == 0x05 && ((cid1 & 0x0f) == 0) && cid0 == 0x0d; } /* * This function checks the ID for each access port to find the requested Access Port type */ int dap_find_ap(struct adiv5_dap *dap, enum ap_type type_to_find, uint8_t *ap_num_out) { int ap; /* Maximum AP number is 255 since the SELECT register is 8 bits */ for (ap = 0; ap <= 255; ap++) { /* read the IDR register of the Access Port */ uint32_t id_val = 0; dap_ap_select(dap, ap); int retval = dap_queue_ap_read(dap, AP_REG_IDR, &id_val); if (retval != ERROR_OK) return retval; retval = dap_run(dap); /* IDR bits: * 31-28 : Revision * 27-24 : JEDEC bank (0x4 for ARM) * 23-17 : JEDEC code (0x3B for ARM) * 16 : Mem-AP * 15-8 : Reserved * 7-0 : AP Identity (1=AHB-AP 2=APB-AP 0x10=JTAG-AP) */ /* Reading register for a non-existant AP should not cause an error, * but just to be sure, try to continue searching if an error does happen. */ if ((retval == ERROR_OK) && /* Register read success */ ((id_val & 0x0FFF0000) == 0x04770000) && /* Jedec codes match */ ((id_val & 0xFF) == type_to_find)) { /* type matches*/ LOG_DEBUG("Found %s at AP index: %d (IDR=0x%08X)", (type_to_find == AP_TYPE_AHB_AP) ? "AHB-AP" : (type_to_find == AP_TYPE_APB_AP) ? "APB-AP" : (type_to_find == AP_TYPE_JTAG_AP) ? "JTAG-AP" : "Unknown", ap, id_val); *ap_num_out = ap; return ERROR_OK; } } LOG_DEBUG("No %s found", (type_to_find == AP_TYPE_AHB_AP) ? "AHB-AP" : (type_to_find == AP_TYPE_APB_AP) ? "APB-AP" : (type_to_find == AP_TYPE_JTAG_AP) ? "JTAG-AP" : "Unknown"); return ERROR_FAIL; } int dap_get_debugbase(struct adiv5_dap *dap, int ap, uint32_t *out_dbgbase, uint32_t *out_apid) { uint32_t ap_old; int retval; uint32_t dbgbase, apid; /* AP address is in bits 31:24 of DP_SELECT */ if (ap >= 256) return ERROR_COMMAND_SYNTAX_ERROR; ap_old = dap->ap_current; dap_ap_select(dap, ap); retval = dap_queue_ap_read(dap, AP_REG_BASE, &dbgbase); if (retval != ERROR_OK) return retval; retval = dap_queue_ap_read(dap, AP_REG_IDR, &apid); if (retval != ERROR_OK) return retval; retval = dap_run(dap); if (retval != ERROR_OK) return retval; /* Excavate the device ID code */ struct jtag_tap *tap = dap->jtag_info->tap; while (tap != NULL) { if (tap->hasidcode) break; tap = tap->next_tap; } if (tap == NULL || !tap->hasidcode) return ERROR_OK; dap_ap_select(dap, ap_old); /* The asignment happens only here to prevent modification of these * values before they are certain. */ *out_dbgbase = dbgbase; *out_apid = apid; return ERROR_OK; } int dap_lookup_cs_component(struct adiv5_dap *dap, int ap, uint32_t dbgbase, uint8_t type, uint32_t *addr) { uint32_t ap_old; uint32_t romentry, entry_offset = 0, component_base, devtype; int retval = ERROR_FAIL; if (ap >= 256) return ERROR_COMMAND_SYNTAX_ERROR; ap_old = dap->ap_current; dap_ap_select(dap, ap); do { retval = mem_ap_read_atomic_u32(dap, (dbgbase&0xFFFFF000) | entry_offset, &romentry); if (retval != ERROR_OK) return retval; component_base = (dbgbase & 0xFFFFF000) + (romentry & 0xFFFFF000); if (romentry & 0x1) { retval = mem_ap_read_atomic_u32(dap, (component_base & 0xfffff000) | 0xfcc, &devtype); if (retval != ERROR_OK) return retval; if ((devtype & 0xff) == type) { *addr = component_base; retval = ERROR_OK; break; } } entry_offset += 4; } while (romentry > 0); dap_ap_select(dap, ap_old); return retval; } static int dap_info_command(struct command_context *cmd_ctx, struct adiv5_dap *dap, int ap) { int retval; uint32_t dbgbase = 0, apid = 0; /* Silence gcc by initializing */ int romtable_present = 0; uint8_t mem_ap; uint32_t ap_old; retval = dap_get_debugbase(dap, ap, &dbgbase, &apid); if (retval != ERROR_OK) return retval; ap_old = dap->ap_current; dap_ap_select(dap, ap); /* Now we read ROM table ID registers, ref. ARM IHI 0029B sec */ mem_ap = ((apid&0x10000) && ((apid&0x0F) != 0)); command_print(cmd_ctx, "AP ID register 0x%8.8" PRIx32, apid); if (apid) { switch (apid&0x0F) { case 0: command_print(cmd_ctx, "\tType is JTAG-AP"); break; case 1: command_print(cmd_ctx, "\tType is MEM-AP AHB"); break; case 2: command_print(cmd_ctx, "\tType is MEM-AP APB"); break; default: command_print(cmd_ctx, "\tUnknown AP type"); break; } /* NOTE: a MEM-AP may have a single CoreSight component that's * not a ROM table ... or have no such components at all. */ if (mem_ap) command_print(cmd_ctx, "AP BASE 0x%8.8" PRIx32, dbgbase); } else command_print(cmd_ctx, "No AP found at this ap 0x%x", ap); romtable_present = ((mem_ap) && (dbgbase != 0xFFFFFFFF)); if (romtable_present) { uint32_t cid0, cid1, cid2, cid3, memtype, romentry; uint16_t entry_offset; /* bit 16 of apid indicates a memory access port */ if (dbgbase & 0x02) command_print(cmd_ctx, "\tValid ROM table present"); else command_print(cmd_ctx, "\tROM table in legacy format"); /* Now we read ROM table ID registers, ref. ARM IHI 0029B sec */ retval = mem_ap_read_u32(dap, (dbgbase&0xFFFFF000) | 0xFF0, &cid0); if (retval != ERROR_OK) return retval; retval = mem_ap_read_u32(dap, (dbgbase&0xFFFFF000) | 0xFF4, &cid1); if (retval != ERROR_OK) return retval; retval = mem_ap_read_u32(dap, (dbgbase&0xFFFFF000) | 0xFF8, &cid2); if (retval != ERROR_OK) return retval; retval = mem_ap_read_u32(dap, (dbgbase&0xFFFFF000) | 0xFFC, &cid3); if (retval != ERROR_OK) return retval; retval = mem_ap_read_u32(dap, (dbgbase&0xFFFFF000) | 0xFCC, &memtype); if (retval != ERROR_OK) return retval; retval = dap_run(dap); if (retval != ERROR_OK) return retval; if (!is_dap_cid_ok(cid3, cid2, cid1, cid0)) command_print(cmd_ctx, "\tCID3 0x%2.2x" ", CID2 0x%2.2x" ", CID1 0x%2.2x" ", CID0 0x%2.2x", (unsigned) cid3, (unsigned)cid2, (unsigned) cid1, (unsigned) cid0); if (memtype & 0x01) command_print(cmd_ctx, "\tMEMTYPE system memory present on bus"); else command_print(cmd_ctx, "\tMEMTYPE System memory not present. " "Dedicated debug bus."); /* Now we read ROM table entries from dbgbase&0xFFFFF000) | 0x000 until we get 0x00000000 */ entry_offset = 0; do { retval = mem_ap_read_atomic_u32(dap, (dbgbase&0xFFFFF000) | entry_offset, &romentry); if (retval != ERROR_OK) return retval; command_print(cmd_ctx, "\tROMTABLE[0x%x] = 0x%" PRIx32 "", entry_offset, romentry); if (romentry & 0x01) { uint32_t c_cid0, c_cid1, c_cid2, c_cid3; uint32_t c_pid0, c_pid1, c_pid2, c_pid3, c_pid4; uint32_t component_base; unsigned part_num; char *type, *full; component_base = (dbgbase & 0xFFFFF000) + (romentry & 0xFFFFF000); /* IDs are in last 4K section */ retval = mem_ap_read_atomic_u32(dap, component_base + 0xFE0, &c_pid0); if (retval != ERROR_OK) return retval; c_pid0 &= 0xff; retval = mem_ap_read_atomic_u32(dap, component_base + 0xFE4, &c_pid1); if (retval != ERROR_OK) return retval; c_pid1 &= 0xff; retval = mem_ap_read_atomic_u32(dap, component_base + 0xFE8, &c_pid2); if (retval != ERROR_OK) return retval; c_pid2 &= 0xff; retval = mem_ap_read_atomic_u32(dap, component_base + 0xFEC, &c_pid3); if (retval != ERROR_OK) return retval; c_pid3 &= 0xff; retval = mem_ap_read_atomic_u32(dap, component_base + 0xFD0, &c_pid4); if (retval != ERROR_OK) return retval; c_pid4 &= 0xff; retval = mem_ap_read_atomic_u32(dap, component_base + 0xFF0, &c_cid0); if (retval != ERROR_OK) return retval; c_cid0 &= 0xff; retval = mem_ap_read_atomic_u32(dap, component_base + 0xFF4, &c_cid1); if (retval != ERROR_OK) return retval; c_cid1 &= 0xff; retval = mem_ap_read_atomic_u32(dap, component_base + 0xFF8, &c_cid2); if (retval != ERROR_OK) return retval; c_cid2 &= 0xff; retval = mem_ap_read_atomic_u32(dap, component_base + 0xFFC, &c_cid3); if (retval != ERROR_OK) return retval; c_cid3 &= 0xff; command_print(cmd_ctx, "\t\tComponent base address 0x%" PRIx32 "," "start address 0x%" PRIx32, component_base, /* component may take multiple 4K pages */ component_base - 0x1000*(c_pid4 >> 4)); command_print(cmd_ctx, "\t\tComponent class is 0x%x, %s", (int) (c_cid1 >> 4) & 0xf, /* See ARM IHI 0029B Table 3-3 */ class_description[(c_cid1 >> 4) & 0xf]); /* CoreSight component? */ if (((c_cid1 >> 4) & 0x0f) == 9) { uint32_t devtype; unsigned minor; char *major = "Reserved", *subtype = "Reserved"; retval = mem_ap_read_atomic_u32(dap, (component_base & 0xfffff000) | 0xfcc, &devtype); if (retval != ERROR_OK) return retval; minor = (devtype >> 4) & 0x0f; switch (devtype & 0x0f) { case 0: major = "Miscellaneous"; switch (minor) { case 0: subtype = "other"; break; case 4: subtype = "Validation component"; break; } break; case 1: major = "Trace Sink"; switch (minor) { case 0: subtype = "other"; break; case 1: subtype = "Port"; break; case 2: subtype = "Buffer"; break; } break; case 2: major = "Trace Link"; switch (minor) { case 0: subtype = "other"; break; case 1: subtype = "Funnel, router"; break; case 2: subtype = "Filter"; break; case 3: subtype = "FIFO, buffer"; break; } break; case 3: major = "Trace Source"; switch (minor) { case 0: subtype = "other"; break; case 1: subtype = "Processor"; break; case 2: subtype = "DSP"; break; case 3: subtype = "Engine/Coprocessor"; break; case 4: subtype = "Bus"; break; } break; case 4: major = "Debug Control"; switch (minor) { case 0: subtype = "other"; break; case 1: subtype = "Trigger Matrix"; break; case 2: subtype = "Debug Auth"; break; } break; case 5: major = "Debug Logic"; switch (minor) { case 0: subtype = "other"; break; case 1: subtype = "Processor"; break; case 2: subtype = "DSP"; break; case 3: subtype = "Engine/Coprocessor"; break; } break; } command_print(cmd_ctx, "\t\tType is 0x%2.2x, %s, %s", (unsigned) (devtype & 0xff), major, subtype); /* REVISIT also show 0xfc8 DevId */ } if (!is_dap_cid_ok(cid3, cid2, cid1, cid0)) command_print(cmd_ctx, "\t\tCID3 0%2.2x" ", CID2 0%2.2x" ", CID1 0%2.2x" ", CID0 0%2.2x", (int) c_cid3, (int) c_cid2, (int)c_cid1, (int)c_cid0); command_print(cmd_ctx, "\t\tPeripheral ID[4..0] = hex " "%2.2x %2.2x %2.2x %2.2x %2.2x", (int) c_pid4, (int) c_pid3, (int) c_pid2, (int) c_pid1, (int) c_pid0); /* Part number interpretations are from Cortex * core specs, the CoreSight components TRM * (ARM DDI 0314H), CoreSight System Design * Guide (ARM DGI 0012D) and ETM specs; also * from chip observation (e.g. TI SDTI). */ part_num = (c_pid0 & 0xff); part_num |= (c_pid1 & 0x0f) << 8; switch (part_num) { case 0x000: type = "Cortex-M3 NVIC"; full = "(Interrupt Controller)"; break; case 0x001: type = "Cortex-M3 ITM"; full = "(Instrumentation Trace Module)"; break; case 0x002: type = "Cortex-M3 DWT"; full = "(Data Watchpoint and Trace)"; break; case 0x003: type = "Cortex-M3 FBP"; full = "(Flash Patch and Breakpoint)"; break; case 0x00c: type = "Cortex-M4 SCS"; full = "(System Control Space)"; break; case 0x00d: type = "CoreSight ETM11"; full = "(Embedded Trace)"; break; /* case 0x113: what? */ case 0x120: /* from OMAP3 memmap */ type = "TI SDTI"; full = "(System Debug Trace Interface)"; break; case 0x343: /* from OMAP3 memmap */ type = "TI DAPCTL"; full = ""; break; case 0x906: type = "Coresight CTI"; full = "(Cross Trigger)"; break; case 0x907: type = "Coresight ETB"; full = "(Trace Buffer)"; break; case 0x908: type = "Coresight CSTF"; full = "(Trace Funnel)"; break; case 0x910: type = "CoreSight ETM9"; full = "(Embedded Trace)"; break; case 0x912: type = "Coresight TPIU"; full = "(Trace Port Interface Unit)"; break; case 0x921: type = "Cortex-A8 ETM"; full = "(Embedded Trace)"; break; case 0x922: type = "Cortex-A8 CTI"; full = "(Cross Trigger)"; break; case 0x923: type = "Cortex-M3 TPIU"; full = "(Trace Port Interface Unit)"; break; case 0x924: type = "Cortex-M3 ETM"; full = "(Embedded Trace)"; break; case 0x925: type = "Cortex-M4 ETM"; full = "(Embedded Trace)"; break; case 0x930: type = "Cortex-R4 ETM"; full = "(Embedded Trace)"; break; case 0x9a1: type = "Cortex-M4 TPUI"; full = "(Trace Port Interface Unit)"; break; case 0xc08: type = "Cortex-A8 Debug"; full = "(Debug Unit)"; break; default: type = "-*- unrecognized -*-"; full = ""; break; } command_print(cmd_ctx, "\t\tPart is %s %s", type, full); } else { if (romentry) command_print(cmd_ctx, "\t\tComponent not present"); else command_print(cmd_ctx, "\t\tEnd of ROM table"); } entry_offset += 4; } while (romentry > 0); } else command_print(cmd_ctx, "\tNo ROM table present"); dap_ap_select(dap, ap_old); return ERROR_OK; } COMMAND_HANDLER(handle_dap_info_command) { struct target *target = get_current_target(CMD_CTX); struct arm *arm = target_to_arm(target); struct adiv5_dap *dap = arm->dap; uint32_t apsel; switch (CMD_ARGC) { case 0: apsel = dap->apsel; break; case 1: COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); break; default: return ERROR_COMMAND_SYNTAX_ERROR; } return dap_info_command(CMD_CTX, dap, apsel); } COMMAND_HANDLER(dap_baseaddr_command) { struct target *target = get_current_target(CMD_CTX); struct arm *arm = target_to_arm(target); struct adiv5_dap *dap = arm->dap; uint32_t apsel, baseaddr; int retval; switch (CMD_ARGC) { case 0: apsel = dap->apsel; break; case 1: COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); /* AP address is in bits 31:24 of DP_SELECT */ if (apsel >= 256) return ERROR_COMMAND_SYNTAX_ERROR; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } dap_ap_select(dap, apsel); /* NOTE: assumes we're talking to a MEM-AP, which * has a base address. There are other kinds of AP, * though they're not common for now. This should * use the ID register to verify it's a MEM-AP. */ retval = dap_queue_ap_read(dap, AP_REG_BASE, &baseaddr); if (retval != ERROR_OK) return retval; retval = dap_run(dap); if (retval != ERROR_OK) return retval; command_print(CMD_CTX, "0x%8.8" PRIx32, baseaddr); return retval; } COMMAND_HANDLER(dap_memaccess_command) { struct target *target = get_current_target(CMD_CTX); struct arm *arm = target_to_arm(target); struct adiv5_dap *dap = arm->dap; uint32_t memaccess_tck; switch (CMD_ARGC) { case 0: memaccess_tck = dap->memaccess_tck; break; case 1: COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], memaccess_tck); break; default: return ERROR_COMMAND_SYNTAX_ERROR; } dap->memaccess_tck = memaccess_tck; command_print(CMD_CTX, "memory bus access delay set to %" PRIi32 " tck", dap->memaccess_tck); return ERROR_OK; } COMMAND_HANDLER(dap_apsel_command) { struct target *target = get_current_target(CMD_CTX); struct arm *arm = target_to_arm(target); struct adiv5_dap *dap = arm->dap; uint32_t apsel, apid; int retval; switch (CMD_ARGC) { case 0: apsel = 0; break; case 1: COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); /* AP address is in bits 31:24 of DP_SELECT */ if (apsel >= 256) return ERROR_COMMAND_SYNTAX_ERROR; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } dap->apsel = apsel; dap_ap_select(dap, apsel); retval = dap_queue_ap_read(dap, AP_REG_IDR, &apid); if (retval != ERROR_OK) return retval; retval = dap_run(dap); if (retval != ERROR_OK) return retval; command_print(CMD_CTX, "ap %" PRIi32 " selected, identification register 0x%8.8" PRIx32, apsel, apid); return retval; } COMMAND_HANDLER(dap_apcsw_command) { struct target *target = get_current_target(CMD_CTX); struct arm *arm = target_to_arm(target); struct adiv5_dap *dap = arm->dap; uint32_t apcsw = dap->apcsw[dap->apsel], sprot = 0; switch (CMD_ARGC) { case 0: command_print(CMD_CTX, "apsel %" PRIi32 " selected, csw 0x%8.8" PRIx32, (dap->apsel), apcsw); break; case 1: COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], sprot); /* AP address is in bits 31:24 of DP_SELECT */ if (sprot > 1) return ERROR_COMMAND_SYNTAX_ERROR; if (sprot) apcsw |= CSW_SPROT; else apcsw &= ~CSW_SPROT; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } dap->apcsw[dap->apsel] = apcsw; return 0; } COMMAND_HANDLER(dap_apid_command) { struct target *target = get_current_target(CMD_CTX); struct arm *arm = target_to_arm(target); struct adiv5_dap *dap = arm->dap; uint32_t apsel, apid; int retval; switch (CMD_ARGC) { case 0: apsel = dap->apsel; break; case 1: COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel); /* AP address is in bits 31:24 of DP_SELECT */ if (apsel >= 256) return ERROR_COMMAND_SYNTAX_ERROR; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } dap_ap_select(dap, apsel); retval = dap_queue_ap_read(dap, AP_REG_IDR, &apid); if (retval != ERROR_OK) return retval; retval = dap_run(dap); if (retval != ERROR_OK) return retval; command_print(CMD_CTX, "0x%8.8" PRIx32, apid); return retval; } static const struct command_registration dap_commands[] = { { .name = "info", .handler = handle_dap_info_command, .mode = COMMAND_EXEC, .help = "display ROM table for MEM-AP " "(default currently selected AP)", .usage = "[ap_num]", }, { .name = "apsel", .handler = dap_apsel_command, .mode = COMMAND_EXEC, .help = "Set the currently selected AP (default 0) " "and display the result", .usage = "[ap_num]", }, { .name = "apcsw", .handler = dap_apcsw_command, .mode = COMMAND_EXEC, .help = "Set csw access bit ", .usage = "[sprot]", }, { .name = "apid", .handler = dap_apid_command, .mode = COMMAND_EXEC, .help = "return ID register from AP " "(default currently selected AP)", .usage = "[ap_num]", }, { .name = "baseaddr", .handler = dap_baseaddr_command, .mode = COMMAND_EXEC, .help = "return debug base address from MEM-AP " "(default currently selected AP)", .usage = "[ap_num]", }, { .name = "memaccess", .handler = dap_memaccess_command, .mode = COMMAND_EXEC, .help = "set/get number of extra tck for MEM-AP memory " "bus access [0-255]", .usage = "[cycles]", }, COMMAND_REGISTRATION_DONE }; const struct command_registration dap_command_handlers[] = { { .name = "dap", .mode = COMMAND_EXEC, .help = "DAP command group", .usage = "", .chain = dap_commands, }, COMMAND_REGISTRATION_DONE }; openocd-0.7.0/src/target/arm_opcodes.h0000644000175000001440000002252512137151331014606 00000000000000/* * Copyright (C) 2005 by Dominic Rath * Dominic.Rath@gmx.de * * Copyright (C) 2006 by Magnus Lundin * lundin@mlu.mine.nu * * Copyright (C) 2008 by Spencer Oliver * spen@spen-soft.co.uk * * Copyright (C) 2009 by Øyvind Harboe * oyvind.harboe@zylin.com * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 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. */ #ifndef __ARM_OPCODES_H #define __ARM_OPCODES_H /** * @file * Macros used to generate various ARM or Thumb opcodes. */ /* ARM mode instructions */ /* Store multiple increment after * Rn: base register * List: for each bit in list: store register * S: in priviledged mode: store user-mode registers * W = 1: update the base register. W = 0: leave the base register untouched */ #define ARMV4_5_STMIA(Rn, List, S, W) \ (0xe8800000 | ((S) << 22) | ((W) << 21) | ((Rn) << 16) | (List)) /* Load multiple increment after * Rn: base register * List: for each bit in list: store register * S: in priviledged mode: store user-mode registers * W = 1: update the base register. W = 0: leave the base register untouched */ #define ARMV4_5_LDMIA(Rn, List, S, W) \ (0xe8900000 | ((S) << 22) | ((W) << 21) | ((Rn) << 16) | (List)) /* MOV r8, r8 */ #define ARMV4_5_NOP (0xe1a08008) /* Move PSR to general purpose register * R = 1: SPSR R = 0: CPSR * Rn: target register */ #define ARMV4_5_MRS(Rn, R) (0xe10f0000 | ((R) << 22) | ((Rn) << 12)) /* Store register * Rd: register to store * Rn: base register */ #define ARMV4_5_STR(Rd, Rn) (0xe5800000 | ((Rd) << 12) | ((Rn) << 16)) /* Load register * Rd: register to load * Rn: base register */ #define ARMV4_5_LDR(Rd, Rn) (0xe5900000 | ((Rd) << 12) | ((Rn) << 16)) /* Move general purpose register to PSR * R = 1: SPSR R = 0: CPSR * Field: Field mask * 1: control field 2: extension field 4: status field 8: flags field * Rm: source register */ #define ARMV4_5_MSR_GP(Rm, Field, R) \ (0xe120f000 | (Rm) | ((Field) << 16) | ((R) << 22)) #define ARMV4_5_MSR_IM(Im, Rotate, Field, R) \ (0xe320f000 | (Im) | ((Rotate) << 8) | ((Field) << 16) | ((R) << 22)) /* Load Register Word Immediate Post-Index * Rd: register to load * Rn: base register */ #define ARMV4_5_LDRW_IP(Rd, Rn) (0xe4900004 | ((Rd) << 12) | ((Rn) << 16)) /* Load Register Halfword Immediate Post-Index * Rd: register to load * Rn: base register */ #define ARMV4_5_LDRH_IP(Rd, Rn) (0xe0d000b2 | ((Rd) << 12) | ((Rn) << 16)) /* Load Register Byte Immediate Post-Index * Rd: register to load * Rn: base register */ #define ARMV4_5_LDRB_IP(Rd, Rn) (0xe4d00001 | ((Rd) << 12) | ((Rn) << 16)) /* Store register Word Immediate Post-Index * Rd: register to store * Rn: base register */ #define ARMV4_5_STRW_IP(Rd, Rn) (0xe4800004 | ((Rd) << 12) | ((Rn) << 16)) /* Store register Halfword Immediate Post-Index * Rd: register to store * Rn: base register */ #define ARMV4_5_STRH_IP(Rd, Rn) (0xe0c000b2 | ((Rd) << 12) | ((Rn) << 16)) /* Store register Byte Immediate Post-Index * Rd: register to store * Rn: base register */ #define ARMV4_5_STRB_IP(Rd, Rn) (0xe4c00001 | ((Rd) << 12) | ((Rn) << 16)) /* Branch (and Link) * Im: Branch target (left-shifted by 2 bits, added to PC) * L: 1: branch and link 0: branch only */ #define ARMV4_5_B(Im, L) (0xea000000 | (Im) | ((L) << 24)) /* Branch and exchange (ARM state) * Rm: register holding branch target address */ #define ARMV4_5_BX(Rm) (0xe12fff10 | (Rm)) /* Store data from coprocessor to consecutive memory * See Armv7-A arch doc section A8.6.187 * P: 1=index mode (offset from Rn) * U: 1=add, 0=subtract Rn address with imm * D: Opcode D encoding * W: write back the offset start address to the Rn register * CP: Coprocessor number (4 bits) * CRd: Coprocessor source register (4 bits) * Rn: Base register for memory address (4 bits) * imm: Immediate value (0 - 1020, must be divisible by 4) */ #define ARMV4_5_STC(P, U, D, W, CP, CRd, Rn, imm) \ (0xec000000 | ((P) << 24) | ((U) << 23) | ((D) << 22) | \ ((W) << 21) | ((Rn) << 16) | ((CRd) << 12) | ((CP) << 8) | ((imm)>>2)) /* Loads data from consecutive memory to coprocessor * See Armv7-A arch doc section A8.6.51 * P: 1=index mode (offset from Rn) * U: 1=add, 0=subtract Rn address with imm * D: Opcode D encoding * W: write back the offset start address to the Rn register * CP: Coprocessor number (4 bits) * CRd: Coprocessor dest register (4 bits) * Rn: Base register for memory address (4 bits) * imm: Immediate value (0 - 1020, must be divisible by 4) */ #define ARMV4_5_LDC(P, U, D, W, CP, CRd, Rn, imm) \ (0xec100000 | ((P) << 24) | ((U) << 23) | ((D) << 22) | \ ((W) << 21) | ((Rn) << 16) | ((CRd) << 12) | ((CP) << 8) | ((imm) >> 2)) /* Move to ARM register from coprocessor * CP: Coprocessor number * op1: Coprocessor opcode * Rd: destination register * CRn: first coprocessor operand * CRm: second coprocessor operand * op2: Second coprocessor opcode */ #define ARMV4_5_MRC(CP, op1, Rd, CRn, CRm, op2) \ (0xee100010 | (CRm) | ((op2) << 5) | ((CP) << 8) \ | ((Rd) << 12) | ((CRn) << 16) | ((op1) << 21)) /* Move to coprocessor from ARM register * CP: Coprocessor number * op1: Coprocessor opcode * Rd: destination register * CRn: first coprocessor operand * CRm: second coprocessor operand * op2: Second coprocessor opcode */ #define ARMV4_5_MCR(CP, op1, Rd, CRn, CRm, op2) \ (0xee000010 | (CRm) | ((op2) << 5) | ((CP) << 8) \ | ((Rd) << 12) | ((CRn) << 16) | ((op1) << 21)) /* Breakpoint instruction (ARMv5) * Im: 16-bit immediate */ #define ARMV5_BKPT(Im) (0xe1200070 | ((Im & 0xfff0) << 8) | (Im & 0xf)) /* Thumb mode instructions * * NOTE: these 16-bit opcodes fill both halves of a word with the same * value. The reason for this is that when we need to execute Thumb * opcodes on ARM7/ARM9 cores (to switch to ARM state on debug entry), * we must shift 32 bits to the bus using scan chain 1 ... if we write * both halves, we don't need to track which half matters. On ARMv6 and * ARMv7 we don't execute Thumb instructions in debug mode; the ITR * register does not accept Thumb (or Thumb2) opcodes. */ /* Store register (Thumb mode) * Rd: source register * Rn: base register */ #define ARMV4_5_T_STR(Rd, Rn) \ ((0x6000 | (Rd) | ((Rn) << 3)) | \ ((0x6000 | (Rd) | ((Rn) << 3)) << 16)) /* Load register (Thumb state) * Rd: destination register * Rn: base register */ #define ARMV4_5_T_LDR(Rd, Rn) \ ((0x6800 | ((Rn) << 3) | (Rd)) \ | ((0x6800 | ((Rn) << 3) | (Rd)) << 16)) /* Load multiple (Thumb state) * Rn: base register * List: for each bit in list: store register */ #define ARMV4_5_T_LDMIA(Rn, List) \ ((0xc800 | ((Rn) << 8) | (List)) \ | ((0xc800 | ((Rn) << 8) | (List)) << 16)) /* Load register with PC relative addressing * Rd: register to load */ #define ARMV4_5_T_LDR_PCREL(Rd) \ ((0x4800 | ((Rd) << 8)) \ | ((0x4800 | ((Rd) << 8)) << 16)) /* Move hi register (Thumb mode) * Rd: destination register * Rm: source register */ #define ARMV4_5_T_MOV(Rd, Rm) \ ((0x4600 | ((Rd) & 0x7) | (((Rd) & 0x8) << 4) | \ (((Rm) & 0x7) << 3) | (((Rm) & 0x8) << 3)) \ | ((0x4600 | ((Rd) & 0x7) | (((Rd) & 0x8) << 4) | \ (((Rm) & 0x7) << 3) | (((Rm) & 0x8) << 3)) << 16)) /* No operation (Thumb mode) * NOTE: this is "MOV r8, r8" ... Thumb2 adds two * architected NOPs, 16-bit and 32-bit. */ #define ARMV4_5_T_NOP (0x46c0 | (0x46c0 << 16)) /* Move immediate to register (Thumb state) * Rd: destination register * Im: 8-bit immediate value */ #define ARMV4_5_T_MOV_IM(Rd, Im) \ ((0x2000 | ((Rd) << 8) | (Im)) \ | ((0x2000 | ((Rd) << 8) | (Im)) << 16)) /* Branch and Exchange * Rm: register containing branch target */ #define ARMV4_5_T_BX(Rm) \ ((0x4700 | ((Rm) << 3)) \ | ((0x4700 | ((Rm) << 3)) << 16)) /* Branch (Thumb state) * Imm: Branch target */ #define ARMV4_5_T_B(Imm) \ ((0xe000 | (Imm)) \ | ((0xe000 | (Imm)) << 16)) /* Breakpoint instruction (ARMv5) (Thumb state) * Im: 8-bit immediate */ #define ARMV5_T_BKPT(Im) \ ((0xbe00 | (Im)) \ | ((0xbe00 | (Im)) << 16)) /* Move to Register from Special Register * 32 bit Thumb2 instruction * Rd: destination register * SYSm: source special register */ #define ARM_T2_MRS(Rd, SYSm) \ ((0xF3EF) | ((0x8000 | (Rd << 8) | SYSm) << 16)) /* Move from Register from Special Register * 32 bit Thumb2 instruction * Rd: source register * SYSm: destination special register */ #define ARM_T2_MSR(SYSm, Rn) \ ((0xF380 | (Rn << 8)) | ((0x8800 | SYSm) << 16)) /* Change Processor State. * 16 bit Thumb2 instruction * Rd: source register * IF: A_FLAG and/or I_FLAG and/or F_FLAG */ #define A_FLAG 4 #define I_FLAG 2 #define F_FLAG 1 #define ARM_T2_CPSID(IF) \ ((0xB660 | (1 << 8) | ((IF)&0x3)) \ | ((0xB660 | (1 << 8) | ((IF)&0x3)) << 16)) #define ARM_T2_CPSIE(IF) \ ((0xB660 | (0 << 8) | ((IF)&0x3)) \ | ((0xB660 | (0 << 8) | ((IF)&0x3)) << 16)) #endif /* __ARM_OPCODES_H */ openocd-0.7.0/src/target/arm7tdmi.h0000644000175000001440000000367012134336410014037 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef ARM7TDMI_H #define ARM7TDMI_H #include "embeddedice.h" int arm7tdmi_init_arch_info(struct target *target, struct arm7_9_common *arm7_9, struct jtag_tap *tap); int arm7tdmi_init_target(struct command_context *cmd_ctx, struct target *target); #endif /* ARM7TDMI_H */ openocd-0.7.0/src/target/target.c0000644000175000001440000044755212137151331013607 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008, Duane Ellis * * openocd@duaneeellis.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2008 by Rick Altherr * * kc8apf@kc8apf.net> * * * * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * * * * Copyright (C) ST-Ericsson SA 2011 * * michel.jaouen@stericsson.com : smp minimum support * * * * Copyright (C) 2011 Andreas Fritiofson * * andreas.fritiofson@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include "target.h" #include "target_type.h" #include "target_request.h" #include "breakpoints.h" #include "register.h" #include "trace.h" #include "image.h" #include "rtos/rtos.h" static int target_read_buffer_default(struct target *target, uint32_t address, uint32_t size, uint8_t *buffer); static int target_write_buffer_default(struct target *target, uint32_t address, uint32_t size, const uint8_t *buffer); static int target_array2mem(Jim_Interp *interp, struct target *target, int argc, Jim_Obj * const *argv); static int target_mem2array(Jim_Interp *interp, struct target *target, int argc, Jim_Obj * const *argv); static int target_register_user_commands(struct command_context *cmd_ctx); /* targets */ extern struct target_type arm7tdmi_target; extern struct target_type arm720t_target; extern struct target_type arm9tdmi_target; extern struct target_type arm920t_target; extern struct target_type arm966e_target; extern struct target_type arm946e_target; extern struct target_type arm926ejs_target; extern struct target_type fa526_target; extern struct target_type feroceon_target; extern struct target_type dragonite_target; extern struct target_type xscale_target; extern struct target_type cortexm3_target; extern struct target_type cortexa8_target; extern struct target_type cortexr4_target; extern struct target_type arm11_target; extern struct target_type mips_m4k_target; extern struct target_type avr_target; extern struct target_type dsp563xx_target; extern struct target_type dsp5680xx_target; extern struct target_type testee_target; extern struct target_type avr32_ap7k_target; extern struct target_type hla_target; static struct target_type *target_types[] = { &arm7tdmi_target, &arm9tdmi_target, &arm920t_target, &arm720t_target, &arm966e_target, &arm946e_target, &arm926ejs_target, &fa526_target, &feroceon_target, &dragonite_target, &xscale_target, &cortexm3_target, &cortexa8_target, &cortexr4_target, &arm11_target, &mips_m4k_target, &avr_target, &dsp563xx_target, &dsp5680xx_target, &testee_target, &avr32_ap7k_target, &hla_target, NULL, }; struct target *all_targets; static struct target_event_callback *target_event_callbacks; static struct target_timer_callback *target_timer_callbacks; static const int polling_interval = 100; static const Jim_Nvp nvp_assert[] = { { .name = "assert", NVP_ASSERT }, { .name = "deassert", NVP_DEASSERT }, { .name = "T", NVP_ASSERT }, { .name = "F", NVP_DEASSERT }, { .name = "t", NVP_ASSERT }, { .name = "f", NVP_DEASSERT }, { .name = NULL, .value = -1 } }; static const Jim_Nvp nvp_error_target[] = { { .value = ERROR_TARGET_INVALID, .name = "err-invalid" }, { .value = ERROR_TARGET_INIT_FAILED, .name = "err-init-failed" }, { .value = ERROR_TARGET_TIMEOUT, .name = "err-timeout" }, { .value = ERROR_TARGET_NOT_HALTED, .name = "err-not-halted" }, { .value = ERROR_TARGET_FAILURE, .name = "err-failure" }, { .value = ERROR_TARGET_UNALIGNED_ACCESS , .name = "err-unaligned-access" }, { .value = ERROR_TARGET_DATA_ABORT , .name = "err-data-abort" }, { .value = ERROR_TARGET_RESOURCE_NOT_AVAILABLE , .name = "err-resource-not-available" }, { .value = ERROR_TARGET_TRANSLATION_FAULT , .name = "err-translation-fault" }, { .value = ERROR_TARGET_NOT_RUNNING, .name = "err-not-running" }, { .value = ERROR_TARGET_NOT_EXAMINED, .name = "err-not-examined" }, { .value = -1, .name = NULL } }; static const char *target_strerror_safe(int err) { const Jim_Nvp *n; n = Jim_Nvp_value2name_simple(nvp_error_target, err); if (n->name == NULL) return "unknown"; else return n->name; } static const Jim_Nvp nvp_target_event[] = { { .value = TARGET_EVENT_GDB_HALT, .name = "gdb-halt" }, { .value = TARGET_EVENT_HALTED, .name = "halted" }, { .value = TARGET_EVENT_RESUMED, .name = "resumed" }, { .value = TARGET_EVENT_RESUME_START, .name = "resume-start" }, { .value = TARGET_EVENT_RESUME_END, .name = "resume-end" }, { .name = "gdb-start", .value = TARGET_EVENT_GDB_START }, { .name = "gdb-end", .value = TARGET_EVENT_GDB_END }, { .value = TARGET_EVENT_RESET_START, .name = "reset-start" }, { .value = TARGET_EVENT_RESET_ASSERT_PRE, .name = "reset-assert-pre" }, { .value = TARGET_EVENT_RESET_ASSERT, .name = "reset-assert" }, { .value = TARGET_EVENT_RESET_ASSERT_POST, .name = "reset-assert-post" }, { .value = TARGET_EVENT_RESET_DEASSERT_PRE, .name = "reset-deassert-pre" }, { .value = TARGET_EVENT_RESET_DEASSERT_POST, .name = "reset-deassert-post" }, { .value = TARGET_EVENT_RESET_HALT_PRE, .name = "reset-halt-pre" }, { .value = TARGET_EVENT_RESET_HALT_POST, .name = "reset-halt-post" }, { .value = TARGET_EVENT_RESET_WAIT_PRE, .name = "reset-wait-pre" }, { .value = TARGET_EVENT_RESET_WAIT_POST, .name = "reset-wait-post" }, { .value = TARGET_EVENT_RESET_INIT, .name = "reset-init" }, { .value = TARGET_EVENT_RESET_END, .name = "reset-end" }, { .value = TARGET_EVENT_EXAMINE_START, .name = "examine-start" }, { .value = TARGET_EVENT_EXAMINE_END, .name = "examine-end" }, { .value = TARGET_EVENT_DEBUG_HALTED, .name = "debug-halted" }, { .value = TARGET_EVENT_DEBUG_RESUMED, .name = "debug-resumed" }, { .value = TARGET_EVENT_GDB_ATTACH, .name = "gdb-attach" }, { .value = TARGET_EVENT_GDB_DETACH, .name = "gdb-detach" }, { .value = TARGET_EVENT_GDB_FLASH_WRITE_START, .name = "gdb-flash-write-start" }, { .value = TARGET_EVENT_GDB_FLASH_WRITE_END , .name = "gdb-flash-write-end" }, { .value = TARGET_EVENT_GDB_FLASH_ERASE_START, .name = "gdb-flash-erase-start" }, { .value = TARGET_EVENT_GDB_FLASH_ERASE_END , .name = "gdb-flash-erase-end" }, { .name = NULL, .value = -1 } }; static const Jim_Nvp nvp_target_state[] = { { .name = "unknown", .value = TARGET_UNKNOWN }, { .name = "running", .value = TARGET_RUNNING }, { .name = "halted", .value = TARGET_HALTED }, { .name = "reset", .value = TARGET_RESET }, { .name = "debug-running", .value = TARGET_DEBUG_RUNNING }, { .name = NULL, .value = -1 }, }; static const Jim_Nvp nvp_target_debug_reason[] = { { .name = "debug-request" , .value = DBG_REASON_DBGRQ }, { .name = "breakpoint" , .value = DBG_REASON_BREAKPOINT }, { .name = "watchpoint" , .value = DBG_REASON_WATCHPOINT }, { .name = "watchpoint-and-breakpoint", .value = DBG_REASON_WPTANDBKPT }, { .name = "single-step" , .value = DBG_REASON_SINGLESTEP }, { .name = "target-not-halted" , .value = DBG_REASON_NOTHALTED }, { .name = "undefined" , .value = DBG_REASON_UNDEFINED }, { .name = NULL, .value = -1 }, }; static const Jim_Nvp nvp_target_endian[] = { { .name = "big", .value = TARGET_BIG_ENDIAN }, { .name = "little", .value = TARGET_LITTLE_ENDIAN }, { .name = "be", .value = TARGET_BIG_ENDIAN }, { .name = "le", .value = TARGET_LITTLE_ENDIAN }, { .name = NULL, .value = -1 }, }; static const Jim_Nvp nvp_reset_modes[] = { { .name = "unknown", .value = RESET_UNKNOWN }, { .name = "run" , .value = RESET_RUN }, { .name = "halt" , .value = RESET_HALT }, { .name = "init" , .value = RESET_INIT }, { .name = NULL , .value = -1 }, }; const char *debug_reason_name(struct target *t) { const char *cp; cp = Jim_Nvp_value2name_simple(nvp_target_debug_reason, t->debug_reason)->name; if (!cp) { LOG_ERROR("Invalid debug reason: %d", (int)(t->debug_reason)); cp = "(*BUG*unknown*BUG*)"; } return cp; } const char *target_state_name(struct target *t) { const char *cp; cp = Jim_Nvp_value2name_simple(nvp_target_state, t->state)->name; if (!cp) { LOG_ERROR("Invalid target state: %d", (int)(t->state)); cp = "(*BUG*unknown*BUG*)"; } return cp; } /* determine the number of the new target */ static int new_target_number(void) { struct target *t; int x; /* number is 0 based */ x = -1; t = all_targets; while (t) { if (x < t->target_number) x = t->target_number; t = t->next; } return x + 1; } /* read a uint32_t from a buffer in target memory endianness */ uint32_t target_buffer_get_u32(struct target *target, const uint8_t *buffer) { if (target->endianness == TARGET_LITTLE_ENDIAN) return le_to_h_u32(buffer); else return be_to_h_u32(buffer); } /* read a uint24_t from a buffer in target memory endianness */ uint32_t target_buffer_get_u24(struct target *target, const uint8_t *buffer) { if (target->endianness == TARGET_LITTLE_ENDIAN) return le_to_h_u24(buffer); else return be_to_h_u24(buffer); } /* read a uint16_t from a buffer in target memory endianness */ uint16_t target_buffer_get_u16(struct target *target, const uint8_t *buffer) { if (target->endianness == TARGET_LITTLE_ENDIAN) return le_to_h_u16(buffer); else return be_to_h_u16(buffer); } /* read a uint8_t from a buffer in target memory endianness */ static uint8_t target_buffer_get_u8(struct target *target, const uint8_t *buffer) { return *buffer & 0x0ff; } /* write a uint32_t to a buffer in target memory endianness */ void target_buffer_set_u32(struct target *target, uint8_t *buffer, uint32_t value) { if (target->endianness == TARGET_LITTLE_ENDIAN) h_u32_to_le(buffer, value); else h_u32_to_be(buffer, value); } /* write a uint24_t to a buffer in target memory endianness */ void target_buffer_set_u24(struct target *target, uint8_t *buffer, uint32_t value) { if (target->endianness == TARGET_LITTLE_ENDIAN) h_u24_to_le(buffer, value); else h_u24_to_be(buffer, value); } /* write a uint16_t to a buffer in target memory endianness */ void target_buffer_set_u16(struct target *target, uint8_t *buffer, uint16_t value) { if (target->endianness == TARGET_LITTLE_ENDIAN) h_u16_to_le(buffer, value); else h_u16_to_be(buffer, value); } /* write a uint8_t to a buffer in target memory endianness */ static void target_buffer_set_u8(struct target *target, uint8_t *buffer, uint8_t value) { *buffer = value; } /* write a uint32_t array to a buffer in target memory endianness */ void target_buffer_get_u32_array(struct target *target, const uint8_t *buffer, uint32_t count, uint32_t *dstbuf) { uint32_t i; for (i = 0; i < count; i++) dstbuf[i] = target_buffer_get_u32(target, &buffer[i * 4]); } /* write a uint16_t array to a buffer in target memory endianness */ void target_buffer_get_u16_array(struct target *target, const uint8_t *buffer, uint32_t count, uint16_t *dstbuf) { uint32_t i; for (i = 0; i < count; i++) dstbuf[i] = target_buffer_get_u16(target, &buffer[i * 2]); } /* write a uint32_t array to a buffer in target memory endianness */ void target_buffer_set_u32_array(struct target *target, uint8_t *buffer, uint32_t count, uint32_t *srcbuf) { uint32_t i; for (i = 0; i < count; i++) target_buffer_set_u32(target, &buffer[i * 4], srcbuf[i]); } /* write a uint16_t array to a buffer in target memory endianness */ void target_buffer_set_u16_array(struct target *target, uint8_t *buffer, uint32_t count, uint16_t *srcbuf) { uint32_t i; for (i = 0; i < count; i++) target_buffer_set_u16(target, &buffer[i * 2], srcbuf[i]); } /* return a pointer to a configured target; id is name or number */ struct target *get_target(const char *id) { struct target *target; /* try as tcltarget name */ for (target = all_targets; target; target = target->next) { if (target_name(target) == NULL) continue; if (strcmp(id, target_name(target)) == 0) return target; } /* It's OK to remove this fallback sometime after August 2010 or so */ /* no match, try as number */ unsigned num; if (parse_uint(id, &num) != ERROR_OK) return NULL; for (target = all_targets; target; target = target->next) { if (target->target_number == (int)num) { LOG_WARNING("use '%s' as target identifier, not '%u'", target_name(target), num); return target; } } return NULL; } /* returns a pointer to the n-th configured target */ static struct target *get_target_by_num(int num) { struct target *target = all_targets; while (target) { if (target->target_number == num) return target; target = target->next; } return NULL; } struct target *get_current_target(struct command_context *cmd_ctx) { struct target *target = get_target_by_num(cmd_ctx->current_target); if (target == NULL) { LOG_ERROR("BUG: current_target out of bounds"); exit(-1); } return target; } int target_poll(struct target *target) { int retval; /* We can't poll until after examine */ if (!target_was_examined(target)) { /* Fail silently lest we pollute the log */ return ERROR_FAIL; } retval = target->type->poll(target); if (retval != ERROR_OK) return retval; if (target->halt_issued) { if (target->state == TARGET_HALTED) target->halt_issued = false; else { long long t = timeval_ms() - target->halt_issued_time; if (t > 1000) { target->halt_issued = false; LOG_INFO("Halt timed out, wake up GDB."); target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT); } } } return ERROR_OK; } int target_halt(struct target *target) { int retval; /* We can't poll until after examine */ if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } retval = target->type->halt(target); if (retval != ERROR_OK) return retval; target->halt_issued = true; target->halt_issued_time = timeval_ms(); return ERROR_OK; } /** * Make the target (re)start executing using its saved execution * context (possibly with some modifications). * * @param target Which target should start executing. * @param current True to use the target's saved program counter instead * of the address parameter * @param address Optionally used as the program counter. * @param handle_breakpoints True iff breakpoints at the resumption PC * should be skipped. (For example, maybe execution was stopped by * such a breakpoint, in which case it would be counterprodutive to * let it re-trigger. * @param debug_execution False if all working areas allocated by OpenOCD * should be released and/or restored to their original contents. * (This would for example be true to run some downloaded "helper" * algorithm code, which resides in one such working buffer and uses * another for data storage.) * * @todo Resolve the ambiguity about what the "debug_execution" flag * signifies. For example, Target implementations don't agree on how * it relates to invalidation of the register cache, or to whether * breakpoints and watchpoints should be enabled. (It would seem wrong * to enable breakpoints when running downloaded "helper" algorithms * (debug_execution true), since the breakpoints would be set to match * target firmware being debugged, not the helper algorithm.... and * enabling them could cause such helpers to malfunction (for example, * by overwriting data with a breakpoint instruction. On the other * hand the infrastructure for running such helpers might use this * procedure but rely on hardware breakpoint to detect termination.) */ int target_resume(struct target *target, int current, uint32_t address, int handle_breakpoints, int debug_execution) { int retval; /* We can't poll until after examine */ if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } target_call_event_callbacks(target, TARGET_EVENT_RESUME_START); /* note that resume *must* be asynchronous. The CPU can halt before * we poll. The CPU can even halt at the current PC as a result of * a software breakpoint being inserted by (a bug?) the application. */ retval = target->type->resume(target, current, address, handle_breakpoints, debug_execution); if (retval != ERROR_OK) return retval; target_call_event_callbacks(target, TARGET_EVENT_RESUME_END); return retval; } static int target_process_reset(struct command_context *cmd_ctx, enum target_reset_mode reset_mode) { char buf[100]; int retval; Jim_Nvp *n; n = Jim_Nvp_value2name_simple(nvp_reset_modes, reset_mode); if (n->name == NULL) { LOG_ERROR("invalid reset mode"); return ERROR_FAIL; } /* disable polling during reset to make reset event scripts * more predictable, i.e. dr/irscan & pathmove in events will * not have JTAG operations injected into the middle of a sequence. */ bool save_poll = jtag_poll_get_enabled(); jtag_poll_set_enabled(false); sprintf(buf, "ocd_process_reset %s", n->name); retval = Jim_Eval(cmd_ctx->interp, buf); jtag_poll_set_enabled(save_poll); if (retval != JIM_OK) { Jim_MakeErrorMessage(cmd_ctx->interp); command_print(NULL, "%s\n", Jim_GetString(Jim_GetResult(cmd_ctx->interp), NULL)); return ERROR_FAIL; } /* We want any events to be processed before the prompt */ retval = target_call_timer_callbacks_now(); struct target *target; for (target = all_targets; target; target = target->next) target->type->check_reset(target); return retval; } static int identity_virt2phys(struct target *target, uint32_t virtual, uint32_t *physical) { *physical = virtual; return ERROR_OK; } static int no_mmu(struct target *target, int *enabled) { *enabled = 0; return ERROR_OK; } static int default_examine(struct target *target) { target_set_examined(target); return ERROR_OK; } /* no check by default */ static int default_check_reset(struct target *target) { return ERROR_OK; } int target_examine_one(struct target *target) { return target->type->examine(target); } static int jtag_enable_callback(enum jtag_event event, void *priv) { struct target *target = priv; if (event != JTAG_TAP_EVENT_ENABLE || !target->tap->enabled) return ERROR_OK; jtag_unregister_event_callback(jtag_enable_callback, target); target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_START); int retval = target_examine_one(target); if (retval != ERROR_OK) return retval; target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_END); return retval; } /* Targets that correctly implement init + examine, i.e. * no communication with target during init: * * XScale */ int target_examine(void) { int retval = ERROR_OK; struct target *target; for (target = all_targets; target; target = target->next) { /* defer examination, but don't skip it */ if (!target->tap->enabled) { jtag_register_event_callback(jtag_enable_callback, target); continue; } target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_START); retval = target_examine_one(target); if (retval != ERROR_OK) return retval; target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_END); } return retval; } const char *target_type_name(struct target *target) { return target->type->name; } static int target_soft_reset_halt(struct target *target) { if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } if (!target->type->soft_reset_halt) { LOG_ERROR("Target %s does not support soft_reset_halt", target_name(target)); return ERROR_FAIL; } return target->type->soft_reset_halt(target); } /** * Downloads a target-specific native code algorithm to the target, * and executes it. * Note that some targets may need to set up, enable, * and tear down a breakpoint (hard or * soft) to detect algorithm * termination, while others may support lower overhead schemes where * soft breakpoints embedded in the algorithm automatically terminate the * algorithm. * * @param target used to run the algorithm * @param arch_info target-specific description of the algorithm. */ int target_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_param, uint32_t entry_point, uint32_t exit_point, int timeout_ms, void *arch_info) { int retval = ERROR_FAIL; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); goto done; } if (!target->type->run_algorithm) { LOG_ERROR("Target type '%s' does not support %s", target_type_name(target), __func__); goto done; } target->running_alg = true; retval = target->type->run_algorithm(target, num_mem_params, mem_params, num_reg_params, reg_param, entry_point, exit_point, timeout_ms, arch_info); target->running_alg = false; done: return retval; } /** * Downloads a target-specific native code algorithm to the target, * executes and leaves it running. * * @param target used to run the algorithm * @param arch_info target-specific description of the algorithm. */ int target_start_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, uint32_t entry_point, uint32_t exit_point, void *arch_info) { int retval = ERROR_FAIL; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); goto done; } if (!target->type->start_algorithm) { LOG_ERROR("Target type '%s' does not support %s", target_type_name(target), __func__); goto done; } if (target->running_alg) { LOG_ERROR("Target is already running an algorithm"); goto done; } target->running_alg = true; retval = target->type->start_algorithm(target, num_mem_params, mem_params, num_reg_params, reg_params, entry_point, exit_point, arch_info); done: return retval; } /** * Waits for an algorithm started with target_start_algorithm() to complete. * * @param target used to run the algorithm * @param arch_info target-specific description of the algorithm. */ int target_wait_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, uint32_t exit_point, int timeout_ms, void *arch_info) { int retval = ERROR_FAIL; if (!target->type->wait_algorithm) { LOG_ERROR("Target type '%s' does not support %s", target_type_name(target), __func__); goto done; } if (!target->running_alg) { LOG_ERROR("Target is not running an algorithm"); goto done; } retval = target->type->wait_algorithm(target, num_mem_params, mem_params, num_reg_params, reg_params, exit_point, timeout_ms, arch_info); if (retval != ERROR_TARGET_TIMEOUT) target->running_alg = false; done: return retval; } /** * Executes a target-specific native code algorithm in the target. * It differs from target_run_algorithm in that the algorithm is asynchronous. * Because of this it requires an compliant algorithm: * see contrib/loaders/flash/stm32f1x.S for example. * * @param target used to run the algorithm */ int target_run_flash_async_algorithm(struct target *target, uint8_t *buffer, uint32_t count, int block_size, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, uint32_t buffer_start, uint32_t buffer_size, uint32_t entry_point, uint32_t exit_point, void *arch_info) { int retval; int timeout = 0; /* Set up working area. First word is write pointer, second word is read pointer, * rest is fifo data area. */ uint32_t wp_addr = buffer_start; uint32_t rp_addr = buffer_start + 4; uint32_t fifo_start_addr = buffer_start + 8; uint32_t fifo_end_addr = buffer_start + buffer_size; uint32_t wp = fifo_start_addr; uint32_t rp = fifo_start_addr; /* validate block_size is 2^n */ assert(!block_size || !(block_size & (block_size - 1))); retval = target_write_u32(target, wp_addr, wp); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, rp_addr, rp); if (retval != ERROR_OK) return retval; /* Start up algorithm on target and let it idle while writing the first chunk */ retval = target_start_algorithm(target, num_mem_params, mem_params, num_reg_params, reg_params, entry_point, exit_point, arch_info); if (retval != ERROR_OK) { LOG_ERROR("error starting target flash write algorithm"); return retval; } while (count > 0) { retval = target_read_u32(target, rp_addr, &rp); if (retval != ERROR_OK) { LOG_ERROR("failed to get read pointer"); break; } LOG_DEBUG("count 0x%" PRIx32 " wp 0x%" PRIx32 " rp 0x%" PRIx32, count, wp, rp); if (rp == 0) { LOG_ERROR("flash write algorithm aborted by target"); retval = ERROR_FLASH_OPERATION_FAILED; break; } if ((rp & (block_size - 1)) || rp < fifo_start_addr || rp >= fifo_end_addr) { LOG_ERROR("corrupted fifo read pointer 0x%" PRIx32, rp); break; } /* Count the number of bytes available in the fifo without * crossing the wrap around. Make sure to not fill it completely, * because that would make wp == rp and that's the empty condition. */ uint32_t thisrun_bytes; if (rp > wp) thisrun_bytes = rp - wp - block_size; else if (rp > fifo_start_addr) thisrun_bytes = fifo_end_addr - wp; else thisrun_bytes = fifo_end_addr - wp - block_size; if (thisrun_bytes == 0) { /* Throttle polling a bit if transfer is (much) faster than flash * programming. The exact delay shouldn't matter as long as it's * less than buffer size / flash speed. This is very unlikely to * run when using high latency connections such as USB. */ alive_sleep(10); /* to stop an infinite loop on some targets check and increment a timeout * this issue was observed on a stellaris using the new ICDI interface */ if (timeout++ >= 500) { LOG_ERROR("timeout waiting for algorithm, a target reset is recommended"); return ERROR_FLASH_OPERATION_FAILED; } continue; } /* reset our timeout */ timeout = 0; /* Limit to the amount of data we actually want to write */ if (thisrun_bytes > count * block_size) thisrun_bytes = count * block_size; /* Write data to fifo */ retval = target_write_buffer(target, wp, thisrun_bytes, buffer); if (retval != ERROR_OK) break; /* Update counters and wrap write pointer */ buffer += thisrun_bytes; count -= thisrun_bytes / block_size; wp += thisrun_bytes; if (wp >= fifo_end_addr) wp = fifo_start_addr; /* Store updated write pointer to target */ retval = target_write_u32(target, wp_addr, wp); if (retval != ERROR_OK) break; } if (retval != ERROR_OK) { /* abort flash write algorithm on target */ target_write_u32(target, wp_addr, 0); } int retval2 = target_wait_algorithm(target, num_mem_params, mem_params, num_reg_params, reg_params, exit_point, 10000, arch_info); if (retval2 != ERROR_OK) { LOG_ERROR("error waiting for target flash write algorithm"); retval = retval2; } return retval; } int target_read_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) { if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } return target->type->read_memory(target, address, size, count, buffer); } int target_read_phys_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) { if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } return target->type->read_phys_memory(target, address, size, count, buffer); } int target_write_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } return target->type->write_memory(target, address, size, count, buffer); } int target_write_phys_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } return target->type->write_phys_memory(target, address, size, count, buffer); } static int target_bulk_write_memory_default(struct target *target, uint32_t address, uint32_t count, const uint8_t *buffer) { return target_write_memory(target, address, 4, count, buffer); } int target_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { if ((target->state != TARGET_HALTED) && (breakpoint->type != BKPT_HARD)) { LOG_WARNING("target %s is not halted", target_name(target)); return ERROR_TARGET_NOT_HALTED; } return target->type->add_breakpoint(target, breakpoint); } int target_add_context_breakpoint(struct target *target, struct breakpoint *breakpoint) { if (target->state != TARGET_HALTED) { LOG_WARNING("target %s is not halted", target_name(target)); return ERROR_TARGET_NOT_HALTED; } return target->type->add_context_breakpoint(target, breakpoint); } int target_add_hybrid_breakpoint(struct target *target, struct breakpoint *breakpoint) { if (target->state != TARGET_HALTED) { LOG_WARNING("target %s is not halted", target_name(target)); return ERROR_TARGET_NOT_HALTED; } return target->type->add_hybrid_breakpoint(target, breakpoint); } int target_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { return target->type->remove_breakpoint(target, breakpoint); } int target_add_watchpoint(struct target *target, struct watchpoint *watchpoint) { if (target->state != TARGET_HALTED) { LOG_WARNING("target %s is not halted", target_name(target)); return ERROR_TARGET_NOT_HALTED; } return target->type->add_watchpoint(target, watchpoint); } int target_remove_watchpoint(struct target *target, struct watchpoint *watchpoint) { return target->type->remove_watchpoint(target, watchpoint); } int target_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size) { return target->type->get_gdb_reg_list(target, reg_list, reg_list_size); } int target_step(struct target *target, int current, uint32_t address, int handle_breakpoints) { return target->type->step(target, current, address, handle_breakpoints); } /** * Reset the @c examined flag for the given target. * Pure paranoia -- targets are zeroed on allocation. */ static void target_reset_examined(struct target *target) { target->examined = false; } static int err_read_phys_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) { LOG_ERROR("Not implemented: %s", __func__); return ERROR_FAIL; } static int err_write_phys_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { LOG_ERROR("Not implemented: %s", __func__); return ERROR_FAIL; } static int handle_target(void *priv); static int target_init_one(struct command_context *cmd_ctx, struct target *target) { target_reset_examined(target); struct target_type *type = target->type; if (type->examine == NULL) type->examine = default_examine; if (type->check_reset == NULL) type->check_reset = default_check_reset; assert(type->init_target != NULL); int retval = type->init_target(cmd_ctx, target); if (ERROR_OK != retval) { LOG_ERROR("target '%s' init failed", target_name(target)); return retval; } /* Sanity-check MMU support ... stub in what we must, to help * implement it in stages, but warn if we need to do so. */ if (type->mmu) { if (type->write_phys_memory == NULL) { LOG_ERROR("type '%s' is missing write_phys_memory", type->name); type->write_phys_memory = err_write_phys_memory; } if (type->read_phys_memory == NULL) { LOG_ERROR("type '%s' is missing read_phys_memory", type->name); type->read_phys_memory = err_read_phys_memory; } if (type->virt2phys == NULL) { LOG_ERROR("type '%s' is missing virt2phys", type->name); type->virt2phys = identity_virt2phys; } } else { /* Make sure no-MMU targets all behave the same: make no * distinction between physical and virtual addresses, and * ensure that virt2phys() is always an identity mapping. */ if (type->write_phys_memory || type->read_phys_memory || type->virt2phys) LOG_WARNING("type '%s' has bad MMU hooks", type->name); type->mmu = no_mmu; type->write_phys_memory = type->write_memory; type->read_phys_memory = type->read_memory; type->virt2phys = identity_virt2phys; } if (target->type->read_buffer == NULL) target->type->read_buffer = target_read_buffer_default; if (target->type->write_buffer == NULL) target->type->write_buffer = target_write_buffer_default; if (target->type->bulk_write_memory == NULL) target->type->bulk_write_memory = target_bulk_write_memory_default; return ERROR_OK; } static int target_init(struct command_context *cmd_ctx) { struct target *target; int retval; for (target = all_targets; target; target = target->next) { retval = target_init_one(cmd_ctx, target); if (ERROR_OK != retval) return retval; } if (!all_targets) return ERROR_OK; retval = target_register_user_commands(cmd_ctx); if (ERROR_OK != retval) return retval; retval = target_register_timer_callback(&handle_target, polling_interval, 1, cmd_ctx->interp); if (ERROR_OK != retval) return retval; return ERROR_OK; } COMMAND_HANDLER(handle_target_init_command) { int retval; if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; static bool target_initialized; if (target_initialized) { LOG_INFO("'target init' has already been called"); return ERROR_OK; } target_initialized = true; retval = command_run_line(CMD_CTX, "init_targets"); if (ERROR_OK != retval) return retval; retval = command_run_line(CMD_CTX, "init_board"); if (ERROR_OK != retval) return retval; LOG_DEBUG("Initializing targets..."); return target_init(CMD_CTX); } int target_register_event_callback(int (*callback)(struct target *target, enum target_event event, void *priv), void *priv) { struct target_event_callback **callbacks_p = &target_event_callbacks; if (callback == NULL) return ERROR_COMMAND_SYNTAX_ERROR; if (*callbacks_p) { while ((*callbacks_p)->next) callbacks_p = &((*callbacks_p)->next); callbacks_p = &((*callbacks_p)->next); } (*callbacks_p) = malloc(sizeof(struct target_event_callback)); (*callbacks_p)->callback = callback; (*callbacks_p)->priv = priv; (*callbacks_p)->next = NULL; return ERROR_OK; } int target_register_timer_callback(int (*callback)(void *priv), int time_ms, int periodic, void *priv) { struct target_timer_callback **callbacks_p = &target_timer_callbacks; struct timeval now; if (callback == NULL) return ERROR_COMMAND_SYNTAX_ERROR; if (*callbacks_p) { while ((*callbacks_p)->next) callbacks_p = &((*callbacks_p)->next); callbacks_p = &((*callbacks_p)->next); } (*callbacks_p) = malloc(sizeof(struct target_timer_callback)); (*callbacks_p)->callback = callback; (*callbacks_p)->periodic = periodic; (*callbacks_p)->time_ms = time_ms; gettimeofday(&now, NULL); (*callbacks_p)->when.tv_usec = now.tv_usec + (time_ms % 1000) * 1000; time_ms -= (time_ms % 1000); (*callbacks_p)->when.tv_sec = now.tv_sec + (time_ms / 1000); if ((*callbacks_p)->when.tv_usec > 1000000) { (*callbacks_p)->when.tv_usec = (*callbacks_p)->when.tv_usec - 1000000; (*callbacks_p)->when.tv_sec += 1; } (*callbacks_p)->priv = priv; (*callbacks_p)->next = NULL; return ERROR_OK; } int target_unregister_event_callback(int (*callback)(struct target *target, enum target_event event, void *priv), void *priv) { struct target_event_callback **p = &target_event_callbacks; struct target_event_callback *c = target_event_callbacks; if (callback == NULL) return ERROR_COMMAND_SYNTAX_ERROR; while (c) { struct target_event_callback *next = c->next; if ((c->callback == callback) && (c->priv == priv)) { *p = next; free(c); return ERROR_OK; } else p = &(c->next); c = next; } return ERROR_OK; } static int target_unregister_timer_callback(int (*callback)(void *priv), void *priv) { struct target_timer_callback **p = &target_timer_callbacks; struct target_timer_callback *c = target_timer_callbacks; if (callback == NULL) return ERROR_COMMAND_SYNTAX_ERROR; while (c) { struct target_timer_callback *next = c->next; if ((c->callback == callback) && (c->priv == priv)) { *p = next; free(c); return ERROR_OK; } else p = &(c->next); c = next; } return ERROR_OK; } int target_call_event_callbacks(struct target *target, enum target_event event) { struct target_event_callback *callback = target_event_callbacks; struct target_event_callback *next_callback; if (event == TARGET_EVENT_HALTED) { /* execute early halted first */ target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT); } LOG_DEBUG("target event %i (%s)", event, Jim_Nvp_value2name_simple(nvp_target_event, event)->name); target_handle_event(target, event); while (callback) { next_callback = callback->next; callback->callback(target, event, callback->priv); callback = next_callback; } return ERROR_OK; } static int target_timer_callback_periodic_restart( struct target_timer_callback *cb, struct timeval *now) { int time_ms = cb->time_ms; cb->when.tv_usec = now->tv_usec + (time_ms % 1000) * 1000; time_ms -= (time_ms % 1000); cb->when.tv_sec = now->tv_sec + time_ms / 1000; if (cb->when.tv_usec > 1000000) { cb->when.tv_usec = cb->when.tv_usec - 1000000; cb->when.tv_sec += 1; } return ERROR_OK; } static int target_call_timer_callback(struct target_timer_callback *cb, struct timeval *now) { cb->callback(cb->priv); if (cb->periodic) return target_timer_callback_periodic_restart(cb, now); return target_unregister_timer_callback(cb->callback, cb->priv); } static int target_call_timer_callbacks_check_time(int checktime) { keep_alive(); struct timeval now; gettimeofday(&now, NULL); struct target_timer_callback *callback = target_timer_callbacks; while (callback) { /* cleaning up may unregister and free this callback */ struct target_timer_callback *next_callback = callback->next; bool call_it = callback->callback && ((!checktime && callback->periodic) || now.tv_sec > callback->when.tv_sec || (now.tv_sec == callback->when.tv_sec && now.tv_usec >= callback->when.tv_usec)); if (call_it) { int retval = target_call_timer_callback(callback, &now); if (retval != ERROR_OK) return retval; } callback = next_callback; } return ERROR_OK; } int target_call_timer_callbacks(void) { return target_call_timer_callbacks_check_time(1); } /* invoke periodic callbacks immediately */ int target_call_timer_callbacks_now(void) { return target_call_timer_callbacks_check_time(0); } /* Prints the working area layout for debug purposes */ static void print_wa_layout(struct target *target) { struct working_area *c = target->working_areas; while (c) { LOG_DEBUG("%c%c 0x%08"PRIx32"-0x%08"PRIx32" (%"PRIu32" bytes)", c->backup ? 'b' : ' ', c->free ? ' ' : '*', c->address, c->address + c->size - 1, c->size); c = c->next; } } /* Reduce area to size bytes, create a new free area from the remaining bytes, if any. */ static void target_split_working_area(struct working_area *area, uint32_t size) { assert(area->free); /* Shouldn't split an allocated area */ assert(size <= area->size); /* Caller should guarantee this */ /* Split only if not already the right size */ if (size < area->size) { struct working_area *new_wa = malloc(sizeof(*new_wa)); if (new_wa == NULL) return; new_wa->next = area->next; new_wa->size = area->size - size; new_wa->address = area->address + size; new_wa->backup = NULL; new_wa->user = NULL; new_wa->free = true; area->next = new_wa; area->size = size; /* If backup memory was allocated to this area, it has the wrong size * now so free it and it will be reallocated if/when needed */ if (area->backup) { free(area->backup); area->backup = NULL; } } } /* Merge all adjacent free areas into one */ static void target_merge_working_areas(struct target *target) { struct working_area *c = target->working_areas; while (c && c->next) { assert(c->next->address == c->address + c->size); /* This is an invariant */ /* Find two adjacent free areas */ if (c->free && c->next->free) { /* Merge the last into the first */ c->size += c->next->size; /* Remove the last */ struct working_area *to_be_freed = c->next; c->next = c->next->next; if (to_be_freed->backup) free(to_be_freed->backup); free(to_be_freed); /* If backup memory was allocated to the remaining area, it's has * the wrong size now */ if (c->backup) { free(c->backup); c->backup = NULL; } } else { c = c->next; } } } int target_alloc_working_area_try(struct target *target, uint32_t size, struct working_area **area) { /* Reevaluate working area address based on MMU state*/ if (target->working_areas == NULL) { int retval; int enabled; retval = target->type->mmu(target, &enabled); if (retval != ERROR_OK) return retval; if (!enabled) { if (target->working_area_phys_spec) { LOG_DEBUG("MMU disabled, using physical " "address for working memory 0x%08"PRIx32, target->working_area_phys); target->working_area = target->working_area_phys; } else { LOG_ERROR("No working memory available. " "Specify -work-area-phys to target."); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } else { if (target->working_area_virt_spec) { LOG_DEBUG("MMU enabled, using virtual " "address for working memory 0x%08"PRIx32, target->working_area_virt); target->working_area = target->working_area_virt; } else { LOG_ERROR("No working memory available. " "Specify -work-area-virt to target."); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } /* Set up initial working area on first call */ struct working_area *new_wa = malloc(sizeof(*new_wa)); if (new_wa) { new_wa->next = NULL; new_wa->size = target->working_area_size & ~3UL; /* 4-byte align */ new_wa->address = target->working_area; new_wa->backup = NULL; new_wa->user = NULL; new_wa->free = true; } target->working_areas = new_wa; } /* only allocate multiples of 4 byte */ if (size % 4) size = (size + 3) & (~3UL); struct working_area *c = target->working_areas; /* Find the first large enough working area */ while (c) { if (c->free && c->size >= size) break; c = c->next; } if (c == NULL) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; /* Split the working area into the requested size */ target_split_working_area(c, size); LOG_DEBUG("allocated new working area of %"PRIu32" bytes at address 0x%08"PRIx32, size, c->address); if (target->backup_working_area) { if (c->backup == NULL) { c->backup = malloc(c->size); if (c->backup == NULL) return ERROR_FAIL; } int retval = target_read_memory(target, c->address, 4, c->size / 4, c->backup); if (retval != ERROR_OK) return retval; } /* mark as used, and return the new (reused) area */ c->free = false; *area = c; /* user pointer */ c->user = area; print_wa_layout(target); return ERROR_OK; } int target_alloc_working_area(struct target *target, uint32_t size, struct working_area **area) { int retval; retval = target_alloc_working_area_try(target, size, area); if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) LOG_WARNING("not enough working area available(requested %"PRIu32")", size); return retval; } static int target_restore_working_area(struct target *target, struct working_area *area) { int retval = ERROR_OK; if (target->backup_working_area && area->backup != NULL) { retval = target_write_memory(target, area->address, 4, area->size / 4, area->backup); if (retval != ERROR_OK) LOG_ERROR("failed to restore %"PRIu32" bytes of working area at address 0x%08"PRIx32, area->size, area->address); } return retval; } /* Restore the area's backup memory, if any, and return the area to the allocation pool */ static int target_free_working_area_restore(struct target *target, struct working_area *area, int restore) { int retval = ERROR_OK; if (area->free) return retval; if (restore) { retval = target_restore_working_area(target, area); /* REVISIT: Perhaps the area should be freed even if restoring fails. */ if (retval != ERROR_OK) return retval; } area->free = true; LOG_DEBUG("freed %"PRIu32" bytes of working area at address 0x%08"PRIx32, area->size, area->address); /* mark user pointer invalid */ /* TODO: Is this really safe? It points to some previous caller's memory. * How could we know that the area pointer is still in that place and not * some other vital data? What's the purpose of this, anyway? */ *area->user = NULL; area->user = NULL; target_merge_working_areas(target); print_wa_layout(target); return retval; } int target_free_working_area(struct target *target, struct working_area *area) { return target_free_working_area_restore(target, area, 1); } /* free resources and restore memory, if restoring memory fails, * free up resources anyway */ static void target_free_all_working_areas_restore(struct target *target, int restore) { struct working_area *c = target->working_areas; LOG_DEBUG("freeing all working areas"); /* Loop through all areas, restoring the allocated ones and marking them as free */ while (c) { if (!c->free) { if (restore) target_restore_working_area(target, c); c->free = true; *c->user = NULL; /* Same as above */ c->user = NULL; } c = c->next; } /* Run a merge pass to combine all areas into one */ target_merge_working_areas(target); print_wa_layout(target); } void target_free_all_working_areas(struct target *target) { target_free_all_working_areas_restore(target, 1); } /* Find the largest number of bytes that can be allocated */ uint32_t target_get_working_area_avail(struct target *target) { struct working_area *c = target->working_areas; uint32_t max_size = 0; if (c == NULL) return target->working_area_size; while (c) { if (c->free && max_size < c->size) max_size = c->size; c = c->next; } return max_size; } int target_arch_state(struct target *target) { int retval; if (target == NULL) { LOG_USER("No target has been configured"); return ERROR_OK; } LOG_USER("target state: %s", target_state_name(target)); if (target->state != TARGET_HALTED) return ERROR_OK; retval = target->type->arch_state(target); return retval; } /* Single aligned words are guaranteed to use 16 or 32 bit access * mode respectively, otherwise data is handled as quickly as * possible */ int target_write_buffer(struct target *target, uint32_t address, uint32_t size, const uint8_t *buffer) { LOG_DEBUG("writing buffer of %i byte at 0x%8.8x", (int)size, (unsigned)address); if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } if (size == 0) return ERROR_OK; if ((address + size - 1) < address) { /* GDB can request this when e.g. PC is 0xfffffffc*/ LOG_ERROR("address + size wrapped(0x%08x, 0x%08x)", (unsigned)address, (unsigned)size); return ERROR_FAIL; } return target->type->write_buffer(target, address, size, buffer); } static int target_write_buffer_default(struct target *target, uint32_t address, uint32_t size, const uint8_t *buffer) { int retval = ERROR_OK; if (((address % 2) == 0) && (size == 2)) return target_write_memory(target, address, 2, 1, buffer); /* handle unaligned head bytes */ if (address % 4) { uint32_t unaligned = 4 - (address % 4); if (unaligned > size) unaligned = size; retval = target_write_memory(target, address, 1, unaligned, buffer); if (retval != ERROR_OK) return retval; buffer += unaligned; address += unaligned; size -= unaligned; } /* handle aligned words */ if (size >= 4) { int aligned = size - (size % 4); /* use bulk writes above a certain limit. This may have to be changed */ if (aligned > 128) { retval = target->type->bulk_write_memory(target, address, aligned / 4, buffer); if (retval != ERROR_OK) return retval; } else { retval = target_write_memory(target, address, 4, aligned / 4, buffer); if (retval != ERROR_OK) return retval; } buffer += aligned; address += aligned; size -= aligned; } /* handle tail writes of less than 4 bytes */ if (size > 0) { retval = target_write_memory(target, address, 1, size, buffer); if (retval != ERROR_OK) return retval; } return retval; } /* Single aligned words are guaranteed to use 16 or 32 bit access * mode respectively, otherwise data is handled as quickly as * possible */ int target_read_buffer(struct target *target, uint32_t address, uint32_t size, uint8_t *buffer) { LOG_DEBUG("reading buffer of %i byte at 0x%8.8x", (int)size, (unsigned)address); if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } if (size == 0) return ERROR_OK; if ((address + size - 1) < address) { /* GDB can request this when e.g. PC is 0xfffffffc*/ LOG_ERROR("address + size wrapped(0x%08" PRIx32 ", 0x%08" PRIx32 ")", address, size); return ERROR_FAIL; } return target->type->read_buffer(target, address, size, buffer); } static int target_read_buffer_default(struct target *target, uint32_t address, uint32_t size, uint8_t *buffer) { int retval = ERROR_OK; if (((address % 2) == 0) && (size == 2)) return target_read_memory(target, address, 2, 1, buffer); /* handle unaligned head bytes */ if (address % 4) { uint32_t unaligned = 4 - (address % 4); if (unaligned > size) unaligned = size; retval = target_read_memory(target, address, 1, unaligned, buffer); if (retval != ERROR_OK) return retval; buffer += unaligned; address += unaligned; size -= unaligned; } /* handle aligned words */ if (size >= 4) { int aligned = size - (size % 4); retval = target_read_memory(target, address, 4, aligned / 4, buffer); if (retval != ERROR_OK) return retval; buffer += aligned; address += aligned; size -= aligned; } /*prevent byte access when possible (avoid AHB access limitations in some cases)*/ if (size >= 2) { int aligned = size - (size % 2); retval = target_read_memory(target, address, 2, aligned / 2, buffer); if (retval != ERROR_OK) return retval; buffer += aligned; address += aligned; size -= aligned; } /* handle tail writes of less than 4 bytes */ if (size > 0) { retval = target_read_memory(target, address, 1, size, buffer); if (retval != ERROR_OK) return retval; } return ERROR_OK; } int target_checksum_memory(struct target *target, uint32_t address, uint32_t size, uint32_t* crc) { uint8_t *buffer; int retval; uint32_t i; uint32_t checksum = 0; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } retval = target->type->checksum_memory(target, address, size, &checksum); if (retval != ERROR_OK) { buffer = malloc(size); if (buffer == NULL) { LOG_ERROR("error allocating buffer for section (%d bytes)", (int)size); return ERROR_COMMAND_SYNTAX_ERROR; } retval = target_read_buffer(target, address, size, buffer); if (retval != ERROR_OK) { free(buffer); return retval; } /* convert to target endianness */ for (i = 0; i < (size/sizeof(uint32_t)); i++) { uint32_t target_data; target_data = target_buffer_get_u32(target, &buffer[i*sizeof(uint32_t)]); target_buffer_set_u32(target, &buffer[i*sizeof(uint32_t)], target_data); } retval = image_calculate_checksum(buffer, size, &checksum); free(buffer); } *crc = checksum; return retval; } int target_blank_check_memory(struct target *target, uint32_t address, uint32_t size, uint32_t* blank) { int retval; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } if (target->type->blank_check_memory == 0) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; retval = target->type->blank_check_memory(target, address, size, blank); return retval; } int target_read_u32(struct target *target, uint32_t address, uint32_t *value) { uint8_t value_buf[4]; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } int retval = target_read_memory(target, address, 4, 1, value_buf); if (retval == ERROR_OK) { *value = target_buffer_get_u32(target, value_buf); LOG_DEBUG("address: 0x%8.8" PRIx32 ", value: 0x%8.8" PRIx32 "", address, *value); } else { *value = 0x0; LOG_DEBUG("address: 0x%8.8" PRIx32 " failed", address); } return retval; } int target_read_u16(struct target *target, uint32_t address, uint16_t *value) { uint8_t value_buf[2]; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } int retval = target_read_memory(target, address, 2, 1, value_buf); if (retval == ERROR_OK) { *value = target_buffer_get_u16(target, value_buf); LOG_DEBUG("address: 0x%8.8" PRIx32 ", value: 0x%4.4x", address, *value); } else { *value = 0x0; LOG_DEBUG("address: 0x%8.8" PRIx32 " failed", address); } return retval; } int target_read_u8(struct target *target, uint32_t address, uint8_t *value) { int retval = target_read_memory(target, address, 1, 1, value); if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } if (retval == ERROR_OK) { LOG_DEBUG("address: 0x%8.8" PRIx32 ", value: 0x%2.2x", address, *value); } else { *value = 0x0; LOG_DEBUG("address: 0x%8.8" PRIx32 " failed", address); } return retval; } int target_write_u32(struct target *target, uint32_t address, uint32_t value) { int retval; uint8_t value_buf[4]; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } LOG_DEBUG("address: 0x%8.8" PRIx32 ", value: 0x%8.8" PRIx32 "", address, value); target_buffer_set_u32(target, value_buf, value); retval = target_write_memory(target, address, 4, 1, value_buf); if (retval != ERROR_OK) LOG_DEBUG("failed: %i", retval); return retval; } int target_write_u16(struct target *target, uint32_t address, uint16_t value) { int retval; uint8_t value_buf[2]; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } LOG_DEBUG("address: 0x%8.8" PRIx32 ", value: 0x%8.8x", address, value); target_buffer_set_u16(target, value_buf, value); retval = target_write_memory(target, address, 2, 1, value_buf); if (retval != ERROR_OK) LOG_DEBUG("failed: %i", retval); return retval; } int target_write_u8(struct target *target, uint32_t address, uint8_t value) { int retval; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } LOG_DEBUG("address: 0x%8.8" PRIx32 ", value: 0x%2.2x", address, value); retval = target_write_memory(target, address, 1, 1, &value); if (retval != ERROR_OK) LOG_DEBUG("failed: %i", retval); return retval; } static int find_target(struct command_context *cmd_ctx, const char *name) { struct target *target = get_target(name); if (target == NULL) { LOG_ERROR("Target: %s is unknown, try one of:\n", name); return ERROR_FAIL; } if (!target->tap->enabled) { LOG_USER("Target: TAP %s is disabled, " "can't be the current target\n", target->tap->dotted_name); return ERROR_FAIL; } cmd_ctx->current_target = target->target_number; return ERROR_OK; } COMMAND_HANDLER(handle_targets_command) { int retval = ERROR_OK; if (CMD_ARGC == 1) { retval = find_target(CMD_CTX, CMD_ARGV[0]); if (retval == ERROR_OK) { /* we're done! */ return retval; } } struct target *target = all_targets; command_print(CMD_CTX, " TargetName Type Endian TapName State "); command_print(CMD_CTX, "-- ------------------ ---------- ------ ------------------ ------------"); while (target) { const char *state; char marker = ' '; if (target->tap->enabled) state = target_state_name(target); else state = "tap-disabled"; if (CMD_CTX->current_target == target->target_number) marker = '*'; /* keep columns lined up to match the headers above */ command_print(CMD_CTX, "%2d%c %-18s %-10s %-6s %-18s %s", target->target_number, marker, target_name(target), target_type_name(target), Jim_Nvp_value2name_simple(nvp_target_endian, target->endianness)->name, target->tap->dotted_name, state); target = target->next; } return retval; } /* every 300ms we check for reset & powerdropout and issue a "reset halt" if so. */ static int powerDropout; static int srstAsserted; static int runPowerRestore; static int runPowerDropout; static int runSrstAsserted; static int runSrstDeasserted; static int sense_handler(void) { static int prevSrstAsserted; static int prevPowerdropout; int retval = jtag_power_dropout(&powerDropout); if (retval != ERROR_OK) return retval; int powerRestored; powerRestored = prevPowerdropout && !powerDropout; if (powerRestored) runPowerRestore = 1; long long current = timeval_ms(); static long long lastPower; int waitMore = lastPower + 2000 > current; if (powerDropout && !waitMore) { runPowerDropout = 1; lastPower = current; } retval = jtag_srst_asserted(&srstAsserted); if (retval != ERROR_OK) return retval; int srstDeasserted; srstDeasserted = prevSrstAsserted && !srstAsserted; static long long lastSrst; waitMore = lastSrst + 2000 > current; if (srstDeasserted && !waitMore) { runSrstDeasserted = 1; lastSrst = current; } if (!prevSrstAsserted && srstAsserted) runSrstAsserted = 1; prevSrstAsserted = srstAsserted; prevPowerdropout = powerDropout; if (srstDeasserted || powerRestored) { /* Other than logging the event we can't do anything here. * Issuing a reset is a particularly bad idea as we might * be inside a reset already. */ } return ERROR_OK; } /* process target state changes */ static int handle_target(void *priv) { Jim_Interp *interp = (Jim_Interp *)priv; int retval = ERROR_OK; if (!is_jtag_poll_safe()) { /* polling is disabled currently */ return ERROR_OK; } /* we do not want to recurse here... */ static int recursive; if (!recursive) { recursive = 1; sense_handler(); /* danger! running these procedures can trigger srst assertions and power dropouts. * We need to avoid an infinite loop/recursion here and we do that by * clearing the flags after running these events. */ int did_something = 0; if (runSrstAsserted) { LOG_INFO("srst asserted detected, running srst_asserted proc."); Jim_Eval(interp, "srst_asserted"); did_something = 1; } if (runSrstDeasserted) { Jim_Eval(interp, "srst_deasserted"); did_something = 1; } if (runPowerDropout) { LOG_INFO("Power dropout detected, running power_dropout proc."); Jim_Eval(interp, "power_dropout"); did_something = 1; } if (runPowerRestore) { Jim_Eval(interp, "power_restore"); did_something = 1; } if (did_something) { /* clear detect flags */ sense_handler(); } /* clear action flags */ runSrstAsserted = 0; runSrstDeasserted = 0; runPowerRestore = 0; runPowerDropout = 0; recursive = 0; } /* Poll targets for state changes unless that's globally disabled. * Skip targets that are currently disabled. */ for (struct target *target = all_targets; is_jtag_poll_safe() && target; target = target->next) { if (!target->tap->enabled) continue; if (target->backoff.times > target->backoff.count) { /* do not poll this time as we failed previously */ target->backoff.count++; continue; } target->backoff.count = 0; /* only poll target if we've got power and srst isn't asserted */ if (!powerDropout && !srstAsserted) { /* polling may fail silently until the target has been examined */ retval = target_poll(target); if (retval != ERROR_OK) { /* 100ms polling interval. Increase interval between polling up to 5000ms */ if (target->backoff.times * polling_interval < 5000) { target->backoff.times *= 2; target->backoff.times++; } LOG_USER("Polling target %s failed, GDB will be halted. Polling again in %dms", target_name(target), target->backoff.times * polling_interval); /* Tell GDB to halt the debugger. This allows the user to * run monitor commands to handle the situation. */ target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT); return retval; } /* Since we succeeded, we reset backoff count */ if (target->backoff.times > 0) LOG_USER("Polling target %s succeeded again", target_name(target)); target->backoff.times = 0; } } return retval; } COMMAND_HANDLER(handle_reg_command) { struct target *target; struct reg *reg = NULL; unsigned count = 0; char *value; LOG_DEBUG("-"); target = get_current_target(CMD_CTX); /* list all available registers for the current target */ if (CMD_ARGC == 0) { struct reg_cache *cache = target->reg_cache; count = 0; while (cache) { unsigned i; command_print(CMD_CTX, "===== %s", cache->name); for (i = 0, reg = cache->reg_list; i < cache->num_regs; i++, reg++, count++) { /* only print cached values if they are valid */ if (reg->valid) { value = buf_to_str(reg->value, reg->size, 16); command_print(CMD_CTX, "(%i) %s (/%" PRIu32 "): 0x%s%s", count, reg->name, reg->size, value, reg->dirty ? " (dirty)" : ""); free(value); } else { command_print(CMD_CTX, "(%i) %s (/%" PRIu32 ")", count, reg->name, reg->size) ; } } cache = cache->next; } return ERROR_OK; } /* access a single register by its ordinal number */ if ((CMD_ARGV[0][0] >= '0') && (CMD_ARGV[0][0] <= '9')) { unsigned num; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num); struct reg_cache *cache = target->reg_cache; count = 0; while (cache) { unsigned i; for (i = 0; i < cache->num_regs; i++) { if (count++ == num) { reg = &cache->reg_list[i]; break; } } if (reg) break; cache = cache->next; } if (!reg) { command_print(CMD_CTX, "%i is out of bounds, the current target " "has only %i registers (0 - %i)", num, count, count - 1); return ERROR_OK; } } else { /* access a single register by its name */ reg = register_get_by_name(target->reg_cache, CMD_ARGV[0], 1); if (!reg) { command_print(CMD_CTX, "register %s not found in current target", CMD_ARGV[0]); return ERROR_OK; } } assert(reg != NULL); /* give clang a hint that we *know* reg is != NULL here */ /* display a register */ if ((CMD_ARGC == 1) || ((CMD_ARGC == 2) && !((CMD_ARGV[1][0] >= '0') && (CMD_ARGV[1][0] <= '9')))) { if ((CMD_ARGC == 2) && (strcmp(CMD_ARGV[1], "force") == 0)) reg->valid = 0; if (reg->valid == 0) reg->type->get(reg); value = buf_to_str(reg->value, reg->size, 16); command_print(CMD_CTX, "%s (/%i): 0x%s", reg->name, (int)(reg->size), value); free(value); return ERROR_OK; } /* set register value */ if (CMD_ARGC == 2) { uint8_t *buf = malloc(DIV_ROUND_UP(reg->size, 8)); if (buf == NULL) return ERROR_FAIL; str_to_buf(CMD_ARGV[1], strlen(CMD_ARGV[1]), buf, reg->size, 0); reg->type->set(reg, buf); value = buf_to_str(reg->value, reg->size, 16); command_print(CMD_CTX, "%s (/%i): 0x%s", reg->name, (int)(reg->size), value); free(value); free(buf); return ERROR_OK; } return ERROR_COMMAND_SYNTAX_ERROR; } COMMAND_HANDLER(handle_poll_command) { int retval = ERROR_OK; struct target *target = get_current_target(CMD_CTX); if (CMD_ARGC == 0) { command_print(CMD_CTX, "background polling: %s", jtag_poll_get_enabled() ? "on" : "off"); command_print(CMD_CTX, "TAP: %s (%s)", target->tap->dotted_name, target->tap->enabled ? "enabled" : "disabled"); if (!target->tap->enabled) return ERROR_OK; retval = target_poll(target); if (retval != ERROR_OK) return retval; retval = target_arch_state(target); if (retval != ERROR_OK) return retval; } else if (CMD_ARGC == 1) { bool enable; COMMAND_PARSE_ON_OFF(CMD_ARGV[0], enable); jtag_poll_set_enabled(enable); } else return ERROR_COMMAND_SYNTAX_ERROR; return retval; } COMMAND_HANDLER(handle_wait_halt_command) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; unsigned ms = 5000; if (1 == CMD_ARGC) { int retval = parse_uint(CMD_ARGV[0], &ms); if (ERROR_OK != retval) return ERROR_COMMAND_SYNTAX_ERROR; /* convert seconds (given) to milliseconds (needed) */ ms *= 1000; } struct target *target = get_current_target(CMD_CTX); return target_wait_state(target, TARGET_HALTED, ms); } /* wait for target state to change. The trick here is to have a low * latency for short waits and not to suck up all the CPU time * on longer waits. * * After 500ms, keep_alive() is invoked */ int target_wait_state(struct target *target, enum target_state state, int ms) { int retval; long long then = 0, cur; int once = 1; for (;;) { retval = target_poll(target); if (retval != ERROR_OK) return retval; if (target->state == state) break; cur = timeval_ms(); if (once) { once = 0; then = timeval_ms(); LOG_DEBUG("waiting for target %s...", Jim_Nvp_value2name_simple(nvp_target_state, state)->name); } if (cur-then > 500) keep_alive(); if ((cur-then) > ms) { LOG_ERROR("timed out while waiting for target %s", Jim_Nvp_value2name_simple(nvp_target_state, state)->name); return ERROR_FAIL; } } return ERROR_OK; } COMMAND_HANDLER(handle_halt_command) { LOG_DEBUG("-"); struct target *target = get_current_target(CMD_CTX); int retval = target_halt(target); if (ERROR_OK != retval) return retval; if (CMD_ARGC == 1) { unsigned wait_local; retval = parse_uint(CMD_ARGV[0], &wait_local); if (ERROR_OK != retval) return ERROR_COMMAND_SYNTAX_ERROR; if (!wait_local) return ERROR_OK; } return CALL_COMMAND_HANDLER(handle_wait_halt_command); } COMMAND_HANDLER(handle_soft_reset_halt_command) { struct target *target = get_current_target(CMD_CTX); LOG_USER("requesting target halt and executing a soft reset"); target_soft_reset_halt(target); return ERROR_OK; } COMMAND_HANDLER(handle_reset_command) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; enum target_reset_mode reset_mode = RESET_RUN; if (CMD_ARGC == 1) { const Jim_Nvp *n; n = Jim_Nvp_name2value_simple(nvp_reset_modes, CMD_ARGV[0]); if ((n->name == NULL) || (n->value == RESET_UNKNOWN)) return ERROR_COMMAND_SYNTAX_ERROR; reset_mode = n->value; } /* reset *all* targets */ return target_process_reset(CMD_CTX, reset_mode); } COMMAND_HANDLER(handle_resume_command) { int current = 1; if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; struct target *target = get_current_target(CMD_CTX); /* with no CMD_ARGV, resume from current pc, addr = 0, * with one arguments, addr = CMD_ARGV[0], * handle breakpoints, not debugging */ uint32_t addr = 0; if (CMD_ARGC == 1) { COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], addr); current = 0; } return target_resume(target, current, addr, 1, 0); } COMMAND_HANDLER(handle_step_command) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; LOG_DEBUG("-"); /* with no CMD_ARGV, step from current pc, addr = 0, * with one argument addr = CMD_ARGV[0], * handle breakpoints, debugging */ uint32_t addr = 0; int current_pc = 1; if (CMD_ARGC == 1) { COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], addr); current_pc = 0; } struct target *target = get_current_target(CMD_CTX); return target->type->step(target, current_pc, addr, 1); } static void handle_md_output(struct command_context *cmd_ctx, struct target *target, uint32_t address, unsigned size, unsigned count, const uint8_t *buffer) { const unsigned line_bytecnt = 32; unsigned line_modulo = line_bytecnt / size; char output[line_bytecnt * 4 + 1]; unsigned output_len = 0; const char *value_fmt; switch (size) { case 4: value_fmt = "%8.8x "; break; case 2: value_fmt = "%4.4x "; break; case 1: value_fmt = "%2.2x "; break; default: /* "can't happen", caller checked */ LOG_ERROR("invalid memory read size: %u", size); return; } for (unsigned i = 0; i < count; i++) { if (i % line_modulo == 0) { output_len += snprintf(output + output_len, sizeof(output) - output_len, "0x%8.8x: ", (unsigned)(address + (i*size))); } uint32_t value = 0; const uint8_t *value_ptr = buffer + i * size; switch (size) { case 4: value = target_buffer_get_u32(target, value_ptr); break; case 2: value = target_buffer_get_u16(target, value_ptr); break; case 1: value = *value_ptr; } output_len += snprintf(output + output_len, sizeof(output) - output_len, value_fmt, value); if ((i % line_modulo == line_modulo - 1) || (i == count - 1)) { command_print(cmd_ctx, "%s", output); output_len = 0; } } } COMMAND_HANDLER(handle_md_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; unsigned size = 0; switch (CMD_NAME[2]) { case 'w': size = 4; break; case 'h': size = 2; break; case 'b': size = 1; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } bool physical = strcmp(CMD_ARGV[0], "phys") == 0; int (*fn)(struct target *target, uint32_t address, uint32_t size_value, uint32_t count, uint8_t *buffer); if (physical) { CMD_ARGC--; CMD_ARGV++; fn = target_read_phys_memory; } else fn = target_read_memory; if ((CMD_ARGC < 1) || (CMD_ARGC > 2)) return ERROR_COMMAND_SYNTAX_ERROR; uint32_t address; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); unsigned count = 1; if (CMD_ARGC == 2) COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], count); uint8_t *buffer = calloc(count, size); struct target *target = get_current_target(CMD_CTX); int retval = fn(target, address, size, count, buffer); if (ERROR_OK == retval) handle_md_output(CMD_CTX, target, address, size, count, buffer); free(buffer); return retval; } typedef int (*target_write_fn)(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer); static int target_write_memory_fast(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { return target_write_buffer(target, address, size * count, buffer); } static int target_fill_mem(struct target *target, uint32_t address, target_write_fn fn, unsigned data_size, /* value */ uint32_t b, /* count */ unsigned c) { /* We have to write in reasonably large chunks to be able * to fill large memory areas with any sane speed */ const unsigned chunk_size = 16384; uint8_t *target_buf = malloc(chunk_size * data_size); if (target_buf == NULL) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } for (unsigned i = 0; i < chunk_size; i++) { switch (data_size) { case 4: target_buffer_set_u32(target, target_buf + i * data_size, b); break; case 2: target_buffer_set_u16(target, target_buf + i * data_size, b); break; case 1: target_buffer_set_u8(target, target_buf + i * data_size, b); break; default: exit(-1); } } int retval = ERROR_OK; for (unsigned x = 0; x < c; x += chunk_size) { unsigned current; current = c - x; if (current > chunk_size) current = chunk_size; retval = fn(target, address + x * data_size, data_size, current, target_buf); if (retval != ERROR_OK) break; /* avoid GDB timeouts */ keep_alive(); } free(target_buf); return retval; } COMMAND_HANDLER(handle_mw_command) { if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; bool physical = strcmp(CMD_ARGV[0], "phys") == 0; target_write_fn fn; if (physical) { CMD_ARGC--; CMD_ARGV++; fn = target_write_phys_memory; } else fn = target_write_memory_fast; if ((CMD_ARGC < 2) || (CMD_ARGC > 3)) return ERROR_COMMAND_SYNTAX_ERROR; uint32_t address; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); uint32_t value; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); unsigned count = 1; if (CMD_ARGC == 3) COMMAND_PARSE_NUMBER(uint, CMD_ARGV[2], count); struct target *target = get_current_target(CMD_CTX); unsigned wordsize; switch (CMD_NAME[2]) { case 'w': wordsize = 4; break; case 'h': wordsize = 2; break; case 'b': wordsize = 1; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } return target_fill_mem(target, address, fn, wordsize, value, count); } static COMMAND_HELPER(parse_load_image_command_CMD_ARGV, struct image *image, uint32_t *min_address, uint32_t *max_address) { if (CMD_ARGC < 1 || CMD_ARGC > 5) return ERROR_COMMAND_SYNTAX_ERROR; /* a base address isn't always necessary, * default to 0x0 (i.e. don't relocate) */ if (CMD_ARGC >= 2) { uint32_t addr; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], addr); image->base_address = addr; image->base_address_set = 1; } else image->base_address_set = 0; image->start_address_set = 0; if (CMD_ARGC >= 4) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], *min_address); if (CMD_ARGC == 5) { COMMAND_PARSE_NUMBER(u32, CMD_ARGV[4], *max_address); /* use size (given) to find max (required) */ *max_address += *min_address; } if (*min_address > *max_address) return ERROR_COMMAND_SYNTAX_ERROR; return ERROR_OK; } COMMAND_HANDLER(handle_load_image_command) { uint8_t *buffer; size_t buf_cnt; uint32_t image_size; uint32_t min_address = 0; uint32_t max_address = 0xffffffff; int i; struct image image; int retval = CALL_COMMAND_HANDLER(parse_load_image_command_CMD_ARGV, &image, &min_address, &max_address); if (ERROR_OK != retval) return retval; struct target *target = get_current_target(CMD_CTX); struct duration bench; duration_start(&bench); if (image_open(&image, CMD_ARGV[0], (CMD_ARGC >= 3) ? CMD_ARGV[2] : NULL) != ERROR_OK) return ERROR_OK; image_size = 0x0; retval = ERROR_OK; for (i = 0; i < image.num_sections; i++) { buffer = malloc(image.sections[i].size); if (buffer == NULL) { command_print(CMD_CTX, "error allocating buffer for section (%d bytes)", (int)(image.sections[i].size)); break; } retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt); if (retval != ERROR_OK) { free(buffer); break; } uint32_t offset = 0; uint32_t length = buf_cnt; /* DANGER!!! beware of unsigned comparision here!!! */ if ((image.sections[i].base_address + buf_cnt >= min_address) && (image.sections[i].base_address < max_address)) { if (image.sections[i].base_address < min_address) { /* clip addresses below */ offset += min_address-image.sections[i].base_address; length -= offset; } if (image.sections[i].base_address + buf_cnt > max_address) length -= (image.sections[i].base_address + buf_cnt)-max_address; retval = target_write_buffer(target, image.sections[i].base_address + offset, length, buffer + offset); if (retval != ERROR_OK) { free(buffer); break; } image_size += length; command_print(CMD_CTX, "%u bytes written at address 0x%8.8" PRIx32 "", (unsigned int)length, image.sections[i].base_address + offset); } free(buffer); } if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) { command_print(CMD_CTX, "downloaded %" PRIu32 " bytes " "in %fs (%0.3f KiB/s)", image_size, duration_elapsed(&bench), duration_kbps(&bench, image_size)); } image_close(&image); return retval; } COMMAND_HANDLER(handle_dump_image_command) { struct fileio fileio; uint8_t *buffer; int retval, retvaltemp; uint32_t address, size; struct duration bench; struct target *target = get_current_target(CMD_CTX); if (CMD_ARGC != 3) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], address); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], size); uint32_t buf_size = (size > 4096) ? 4096 : size; buffer = malloc(buf_size); if (!buffer) return ERROR_FAIL; retval = fileio_open(&fileio, CMD_ARGV[0], FILEIO_WRITE, FILEIO_BINARY); if (retval != ERROR_OK) { free(buffer); return retval; } duration_start(&bench); while (size > 0) { size_t size_written; uint32_t this_run_size = (size > buf_size) ? buf_size : size; retval = target_read_buffer(target, address, this_run_size, buffer); if (retval != ERROR_OK) break; retval = fileio_write(&fileio, this_run_size, buffer, &size_written); if (retval != ERROR_OK) break; size -= this_run_size; address += this_run_size; } free(buffer); if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) { int filesize; retval = fileio_size(&fileio, &filesize); if (retval != ERROR_OK) return retval; command_print(CMD_CTX, "dumped %ld bytes in %fs (%0.3f KiB/s)", (long)filesize, duration_elapsed(&bench), duration_kbps(&bench, filesize)); } retvaltemp = fileio_close(&fileio); if (retvaltemp != ERROR_OK) return retvaltemp; return retval; } static COMMAND_HELPER(handle_verify_image_command_internal, int verify) { uint8_t *buffer; size_t buf_cnt; uint32_t image_size; int i; int retval; uint32_t checksum = 0; uint32_t mem_checksum = 0; struct image image; struct target *target = get_current_target(CMD_CTX); if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; if (!target) { LOG_ERROR("no target selected"); return ERROR_FAIL; } struct duration bench; duration_start(&bench); if (CMD_ARGC >= 2) { uint32_t addr; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], addr); image.base_address = addr; image.base_address_set = 1; } else { image.base_address_set = 0; image.base_address = 0x0; } image.start_address_set = 0; retval = image_open(&image, CMD_ARGV[0], (CMD_ARGC == 3) ? CMD_ARGV[2] : NULL); if (retval != ERROR_OK) return retval; image_size = 0x0; int diffs = 0; retval = ERROR_OK; for (i = 0; i < image.num_sections; i++) { buffer = malloc(image.sections[i].size); if (buffer == NULL) { command_print(CMD_CTX, "error allocating buffer for section (%d bytes)", (int)(image.sections[i].size)); break; } retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt); if (retval != ERROR_OK) { free(buffer); break; } if (verify) { /* calculate checksum of image */ retval = image_calculate_checksum(buffer, buf_cnt, &checksum); if (retval != ERROR_OK) { free(buffer); break; } retval = target_checksum_memory(target, image.sections[i].base_address, buf_cnt, &mem_checksum); if (retval != ERROR_OK) { free(buffer); break; } if (checksum != mem_checksum) { /* failed crc checksum, fall back to a binary compare */ uint8_t *data; if (diffs == 0) LOG_ERROR("checksum mismatch - attempting binary compare"); data = (uint8_t *)malloc(buf_cnt); /* Can we use 32bit word accesses? */ int size = 1; int count = buf_cnt; if ((count % 4) == 0) { size *= 4; count /= 4; } retval = target_read_memory(target, image.sections[i].base_address, size, count, data); if (retval == ERROR_OK) { uint32_t t; for (t = 0; t < buf_cnt; t++) { if (data[t] != buffer[t]) { command_print(CMD_CTX, "diff %d address 0x%08x. Was 0x%02x instead of 0x%02x", diffs, (unsigned)(t + image.sections[i].base_address), data[t], buffer[t]); if (diffs++ >= 127) { command_print(CMD_CTX, "More than 128 errors, the rest are not printed."); free(data); free(buffer); goto done; } } keep_alive(); } } free(data); } } else { command_print(CMD_CTX, "address 0x%08" PRIx32 " length 0x%08zx", image.sections[i].base_address, buf_cnt); } free(buffer); image_size += buf_cnt; } if (diffs > 0) command_print(CMD_CTX, "No more differences found."); done: if (diffs > 0) retval = ERROR_FAIL; if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) { command_print(CMD_CTX, "verified %" PRIu32 " bytes " "in %fs (%0.3f KiB/s)", image_size, duration_elapsed(&bench), duration_kbps(&bench, image_size)); } image_close(&image); return retval; } COMMAND_HANDLER(handle_verify_image_command) { return CALL_COMMAND_HANDLER(handle_verify_image_command_internal, 1); } COMMAND_HANDLER(handle_test_image_command) { return CALL_COMMAND_HANDLER(handle_verify_image_command_internal, 0); } static int handle_bp_command_list(struct command_context *cmd_ctx) { struct target *target = get_current_target(cmd_ctx); struct breakpoint *breakpoint = target->breakpoints; while (breakpoint) { if (breakpoint->type == BKPT_SOFT) { char *buf = buf_to_str(breakpoint->orig_instr, breakpoint->length, 16); command_print(cmd_ctx, "IVA breakpoint: 0x%8.8" PRIx32 ", 0x%x, %i, 0x%s", breakpoint->address, breakpoint->length, breakpoint->set, buf); free(buf); } else { if ((breakpoint->address == 0) && (breakpoint->asid != 0)) command_print(cmd_ctx, "Context breakpoint: 0x%8.8" PRIx32 ", 0x%x, %i", breakpoint->asid, breakpoint->length, breakpoint->set); else if ((breakpoint->address != 0) && (breakpoint->asid != 0)) { command_print(cmd_ctx, "Hybrid breakpoint(IVA): 0x%8.8" PRIx32 ", 0x%x, %i", breakpoint->address, breakpoint->length, breakpoint->set); command_print(cmd_ctx, "\t|--->linked with ContextID: 0x%8.8" PRIx32, breakpoint->asid); } else command_print(cmd_ctx, "Breakpoint(IVA): 0x%8.8" PRIx32 ", 0x%x, %i", breakpoint->address, breakpoint->length, breakpoint->set); } breakpoint = breakpoint->next; } return ERROR_OK; } static int handle_bp_command_set(struct command_context *cmd_ctx, uint32_t addr, uint32_t asid, uint32_t length, int hw) { struct target *target = get_current_target(cmd_ctx); if (asid == 0) { int retval = breakpoint_add(target, addr, length, hw); if (ERROR_OK == retval) command_print(cmd_ctx, "breakpoint set at 0x%8.8" PRIx32 "", addr); else { LOG_ERROR("Failure setting breakpoint, the same address(IVA) is already used"); return retval; } } else if (addr == 0) { int retval = context_breakpoint_add(target, asid, length, hw); if (ERROR_OK == retval) command_print(cmd_ctx, "Context breakpoint set at 0x%8.8" PRIx32 "", asid); else { LOG_ERROR("Failure setting breakpoint, the same address(CONTEXTID) is already used"); return retval; } } else { int retval = hybrid_breakpoint_add(target, addr, asid, length, hw); if (ERROR_OK == retval) command_print(cmd_ctx, "Hybrid breakpoint set at 0x%8.8" PRIx32 "", asid); else { LOG_ERROR("Failure setting breakpoint, the same address is already used"); return retval; } } return ERROR_OK; } COMMAND_HANDLER(handle_bp_command) { uint32_t addr; uint32_t asid; uint32_t length; int hw = BKPT_SOFT; switch (CMD_ARGC) { case 0: return handle_bp_command_list(CMD_CTX); case 2: asid = 0; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], addr); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length); return handle_bp_command_set(CMD_CTX, addr, asid, length, hw); case 3: if (strcmp(CMD_ARGV[2], "hw") == 0) { hw = BKPT_HARD; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], addr); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length); asid = 0; return handle_bp_command_set(CMD_CTX, addr, asid, length, hw); } else if (strcmp(CMD_ARGV[2], "hw_ctx") == 0) { hw = BKPT_HARD; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], asid); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length); addr = 0; return handle_bp_command_set(CMD_CTX, addr, asid, length, hw); } case 4: hw = BKPT_HARD; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], addr); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], asid); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], length); return handle_bp_command_set(CMD_CTX, addr, asid, length, hw); default: return ERROR_COMMAND_SYNTAX_ERROR; } } COMMAND_HANDLER(handle_rbp_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; uint32_t addr; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], addr); struct target *target = get_current_target(CMD_CTX); breakpoint_remove(target, addr); return ERROR_OK; } COMMAND_HANDLER(handle_wp_command) { struct target *target = get_current_target(CMD_CTX); if (CMD_ARGC == 0) { struct watchpoint *watchpoint = target->watchpoints; while (watchpoint) { command_print(CMD_CTX, "address: 0x%8.8" PRIx32 ", len: 0x%8.8" PRIx32 ", r/w/a: %i, value: 0x%8.8" PRIx32 ", mask: 0x%8.8" PRIx32, watchpoint->address, watchpoint->length, (int)watchpoint->rw, watchpoint->value, watchpoint->mask); watchpoint = watchpoint->next; } return ERROR_OK; } enum watchpoint_rw type = WPT_ACCESS; uint32_t addr = 0; uint32_t length = 0; uint32_t data_value = 0x0; uint32_t data_mask = 0xffffffff; switch (CMD_ARGC) { case 5: COMMAND_PARSE_NUMBER(u32, CMD_ARGV[4], data_mask); /* fall through */ case 4: COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], data_value); /* fall through */ case 3: switch (CMD_ARGV[2][0]) { case 'r': type = WPT_READ; break; case 'w': type = WPT_WRITE; break; case 'a': type = WPT_ACCESS; break; default: LOG_ERROR("invalid watchpoint mode ('%c')", CMD_ARGV[2][0]); return ERROR_COMMAND_SYNTAX_ERROR; } /* fall through */ case 2: COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], addr); break; default: return ERROR_COMMAND_SYNTAX_ERROR; } int retval = watchpoint_add(target, addr, length, type, data_value, data_mask); if (ERROR_OK != retval) LOG_ERROR("Failure setting watchpoints"); return retval; } COMMAND_HANDLER(handle_rwp_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; uint32_t addr; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], addr); struct target *target = get_current_target(CMD_CTX); watchpoint_remove(target, addr); return ERROR_OK; } /** * Translate a virtual address to a physical address. * * The low-level target implementation must have logged a detailed error * which is forwarded to telnet/GDB session. */ COMMAND_HANDLER(handle_virt2phys_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; uint32_t va; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], va); uint32_t pa; struct target *target = get_current_target(CMD_CTX); int retval = target->type->virt2phys(target, va, &pa); if (retval == ERROR_OK) command_print(CMD_CTX, "Physical address 0x%08" PRIx32 "", pa); return retval; } static void writeData(FILE *f, const void *data, size_t len) { size_t written = fwrite(data, 1, len, f); if (written != len) LOG_ERROR("failed to write %zu bytes: %s", len, strerror(errno)); } static void writeLong(FILE *f, int l) { int i; for (i = 0; i < 4; i++) { char c = (l >> (i*8))&0xff; writeData(f, &c, 1); } } static void writeString(FILE *f, char *s) { writeData(f, s, strlen(s)); } /* Dump a gmon.out histogram file. */ static void writeGmon(uint32_t *samples, uint32_t sampleNum, const char *filename) { uint32_t i; FILE *f = fopen(filename, "w"); if (f == NULL) return; writeString(f, "gmon"); writeLong(f, 0x00000001); /* Version */ writeLong(f, 0); /* padding */ writeLong(f, 0); /* padding */ writeLong(f, 0); /* padding */ uint8_t zero = 0; /* GMON_TAG_TIME_HIST */ writeData(f, &zero, 1); /* figure out bucket size */ uint32_t min = samples[0]; uint32_t max = samples[0]; for (i = 0; i < sampleNum; i++) { if (min > samples[i]) min = samples[i]; if (max < samples[i]) max = samples[i]; } int addressSpace = (max - min + 1); assert(addressSpace >= 2); static const uint32_t maxBuckets = 16 * 1024; /* maximum buckets. */ uint32_t length = addressSpace; if (length > maxBuckets) length = maxBuckets; int *buckets = malloc(sizeof(int)*length); if (buckets == NULL) { fclose(f); return; } memset(buckets, 0, sizeof(int) * length); for (i = 0; i < sampleNum; i++) { uint32_t address = samples[i]; long long a = address - min; long long b = length - 1; long long c = addressSpace - 1; int index_t = (a * b) / c; /* danger!!!! int32 overflows */ buckets[index_t]++; } /* append binary memory gmon.out &profile_hist_hdr ((char*)&profile_hist_hdr + sizeof(struct gmon_hist_hdr)) */ writeLong(f, min); /* low_pc */ writeLong(f, max); /* high_pc */ writeLong(f, length); /* # of samples */ writeLong(f, 100); /* KLUDGE! We lie, ca. 100Hz best case. */ writeString(f, "seconds"); for (i = 0; i < (15-strlen("seconds")); i++) writeData(f, &zero, 1); writeString(f, "s"); /*append binary memory gmon.out profile_hist_data (profile_hist_data + profile_hist_hdr.hist_size) */ char *data = malloc(2 * length); if (data != NULL) { for (i = 0; i < length; i++) { int val; val = buckets[i]; if (val > 65535) val = 65535; data[i * 2] = val&0xff; data[i * 2 + 1] = (val >> 8) & 0xff; } free(buckets); writeData(f, data, length * 2); free(data); } else free(buckets); fclose(f); } /* profiling samples the CPU PC as quickly as OpenOCD is able, * which will be used as a random sampling of PC */ COMMAND_HANDLER(handle_profile_command) { struct target *target = get_current_target(CMD_CTX); struct timeval timeout, now; gettimeofday(&timeout, NULL); if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; unsigned offset; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], offset); timeval_add_time(&timeout, offset, 0); /** * @todo: Some cores let us sample the PC without the * annoying halt/resume step; for example, ARMv7 PCSR. * Provide a way to use that more efficient mechanism. */ command_print(CMD_CTX, "Starting profiling. Halting and resuming the target as often as we can..."); static const int maxSample = 10000; uint32_t *samples = malloc(sizeof(uint32_t)*maxSample); if (samples == NULL) return ERROR_OK; int numSamples = 0; /* hopefully it is safe to cache! We want to stop/restart as quickly as possible. */ struct reg *reg = register_get_by_name(target->reg_cache, "pc", 1); int retval = ERROR_OK; for (;;) { target_poll(target); if (target->state == TARGET_HALTED) { uint32_t t = *((uint32_t *)reg->value); samples[numSamples++] = t; /* current pc, addr = 0, do not handle breakpoints, not debugging */ retval = target_resume(target, 1, 0, 0, 0); target_poll(target); alive_sleep(10); /* sleep 10ms, i.e. <100 samples/second. */ } else if (target->state == TARGET_RUNNING) { /* We want to quickly sample the PC. */ retval = target_halt(target); if (retval != ERROR_OK) { free(samples); return retval; } } else { command_print(CMD_CTX, "Target not halted or running"); retval = ERROR_OK; break; } if (retval != ERROR_OK) break; gettimeofday(&now, NULL); if ((numSamples >= maxSample) || ((now.tv_sec >= timeout.tv_sec) && (now.tv_usec >= timeout.tv_usec))) { command_print(CMD_CTX, "Profiling completed. %d samples.", numSamples); retval = target_poll(target); if (retval != ERROR_OK) { free(samples); return retval; } if (target->state == TARGET_HALTED) { /* current pc, addr = 0, do not handle * breakpoints, not debugging */ target_resume(target, 1, 0, 0, 0); } retval = target_poll(target); if (retval != ERROR_OK) { free(samples); return retval; } writeGmon(samples, numSamples, CMD_ARGV[1]); command_print(CMD_CTX, "Wrote %s", CMD_ARGV[1]); break; } } free(samples); return retval; } static int new_int_array_element(Jim_Interp *interp, const char *varname, int idx, uint32_t val) { char *namebuf; Jim_Obj *nameObjPtr, *valObjPtr; int result; namebuf = alloc_printf("%s(%d)", varname, idx); if (!namebuf) return JIM_ERR; nameObjPtr = Jim_NewStringObj(interp, namebuf, -1); valObjPtr = Jim_NewIntObj(interp, val); if (!nameObjPtr || !valObjPtr) { free(namebuf); return JIM_ERR; } Jim_IncrRefCount(nameObjPtr); Jim_IncrRefCount(valObjPtr); result = Jim_SetVariable(interp, nameObjPtr, valObjPtr); Jim_DecrRefCount(interp, nameObjPtr); Jim_DecrRefCount(interp, valObjPtr); free(namebuf); /* printf("%s(%d) <= 0%08x\n", varname, idx, val); */ return result; } static int jim_mem2array(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { struct command_context *context; struct target *target; context = current_command_context(interp); assert(context != NULL); target = get_current_target(context); if (target == NULL) { LOG_ERROR("mem2array: no current target"); return JIM_ERR; } return target_mem2array(interp, target, argc - 1, argv + 1); } static int target_mem2array(Jim_Interp *interp, struct target *target, int argc, Jim_Obj *const *argv) { long l; uint32_t width; int len; uint32_t addr; uint32_t count; uint32_t v; const char *varname; int n, e, retval; uint32_t i; /* argv[1] = name of array to receive the data * argv[2] = desired width * argv[3] = memory address * argv[4] = count of times to read */ if (argc != 4) { Jim_WrongNumArgs(interp, 1, argv, "varname width addr nelems"); return JIM_ERR; } varname = Jim_GetString(argv[0], &len); /* given "foo" get space for worse case "foo(%d)" .. add 20 */ e = Jim_GetLong(interp, argv[1], &l); width = l; if (e != JIM_OK) return e; e = Jim_GetLong(interp, argv[2], &l); addr = l; if (e != JIM_OK) return e; e = Jim_GetLong(interp, argv[3], &l); len = l; if (e != JIM_OK) return e; switch (width) { case 8: width = 1; break; case 16: width = 2; break; case 32: width = 4; break; default: Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); Jim_AppendStrings(interp, Jim_GetResult(interp), "Invalid width param, must be 8/16/32", NULL); return JIM_ERR; } if (len == 0) { Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: zero width read?", NULL); return JIM_ERR; } if ((addr + (len * width)) < addr) { Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: addr + len - wraps to zero?", NULL); return JIM_ERR; } /* absurd transfer size? */ if (len > 65536) { Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: absurd > 64K item request", NULL); return JIM_ERR; } if ((width == 1) || ((width == 2) && ((addr & 1) == 0)) || ((width == 4) && ((addr & 3) == 0))) { /* all is well */ } else { char buf[100]; Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); sprintf(buf, "mem2array address: 0x%08" PRIx32 " is not aligned for %" PRId32 " byte reads", addr, width); Jim_AppendStrings(interp, Jim_GetResult(interp), buf , NULL); return JIM_ERR; } /* Transfer loop */ /* index counter */ n = 0; size_t buffersize = 4096; uint8_t *buffer = malloc(buffersize); if (buffer == NULL) return JIM_ERR; /* assume ok */ e = JIM_OK; while (len) { /* Slurp... in buffer size chunks */ count = len; /* in objects.. */ if (count > (buffersize / width)) count = (buffersize / width); retval = target_read_memory(target, addr, width, count, buffer); if (retval != ERROR_OK) { /* BOO !*/ LOG_ERROR("mem2array: Read @ 0x%08x, w=%d, cnt=%d, failed", (unsigned int)addr, (int)width, (int)count); Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: cannot read memory", NULL); e = JIM_ERR; break; } else { v = 0; /* shut up gcc */ for (i = 0; i < count ; i++, n++) { switch (width) { case 4: v = target_buffer_get_u32(target, &buffer[i*width]); break; case 2: v = target_buffer_get_u16(target, &buffer[i*width]); break; case 1: v = buffer[i] & 0x0ff; break; } new_int_array_element(interp, varname, n, v); } len -= count; } } free(buffer); Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); return e; } static int get_int_array_element(Jim_Interp *interp, const char *varname, int idx, uint32_t *val) { char *namebuf; Jim_Obj *nameObjPtr, *valObjPtr; int result; long l; namebuf = alloc_printf("%s(%d)", varname, idx); if (!namebuf) return JIM_ERR; nameObjPtr = Jim_NewStringObj(interp, namebuf, -1); if (!nameObjPtr) { free(namebuf); return JIM_ERR; } Jim_IncrRefCount(nameObjPtr); valObjPtr = Jim_GetVariable(interp, nameObjPtr, JIM_ERRMSG); Jim_DecrRefCount(interp, nameObjPtr); free(namebuf); if (valObjPtr == NULL) return JIM_ERR; result = Jim_GetLong(interp, valObjPtr, &l); /* printf("%s(%d) => 0%08x\n", varname, idx, val); */ *val = l; return result; } static int jim_array2mem(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { struct command_context *context; struct target *target; context = current_command_context(interp); assert(context != NULL); target = get_current_target(context); if (target == NULL) { LOG_ERROR("array2mem: no current target"); return JIM_ERR; } return target_array2mem(interp, target, argc-1, argv + 1); } static int target_array2mem(Jim_Interp *interp, struct target *target, int argc, Jim_Obj *const *argv) { long l; uint32_t width; int len; uint32_t addr; uint32_t count; uint32_t v; const char *varname; int n, e, retval; uint32_t i; /* argv[1] = name of array to get the data * argv[2] = desired width * argv[3] = memory address * argv[4] = count to write */ if (argc != 4) { Jim_WrongNumArgs(interp, 0, argv, "varname width addr nelems"); return JIM_ERR; } varname = Jim_GetString(argv[0], &len); /* given "foo" get space for worse case "foo(%d)" .. add 20 */ e = Jim_GetLong(interp, argv[1], &l); width = l; if (e != JIM_OK) return e; e = Jim_GetLong(interp, argv[2], &l); addr = l; if (e != JIM_OK) return e; e = Jim_GetLong(interp, argv[3], &l); len = l; if (e != JIM_OK) return e; switch (width) { case 8: width = 1; break; case 16: width = 2; break; case 32: width = 4; break; default: Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); Jim_AppendStrings(interp, Jim_GetResult(interp), "Invalid width param, must be 8/16/32", NULL); return JIM_ERR; } if (len == 0) { Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: zero width read?", NULL); return JIM_ERR; } if ((addr + (len * width)) < addr) { Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: addr + len - wraps to zero?", NULL); return JIM_ERR; } /* absurd transfer size? */ if (len > 65536) { Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: absurd > 64K item request", NULL); return JIM_ERR; } if ((width == 1) || ((width == 2) && ((addr & 1) == 0)) || ((width == 4) && ((addr & 3) == 0))) { /* all is well */ } else { char buf[100]; Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); sprintf(buf, "array2mem address: 0x%08x is not aligned for %d byte reads", (unsigned int)addr, (int)width); Jim_AppendStrings(interp, Jim_GetResult(interp), buf , NULL); return JIM_ERR; } /* Transfer loop */ /* index counter */ n = 0; /* assume ok */ e = JIM_OK; size_t buffersize = 4096; uint8_t *buffer = malloc(buffersize); if (buffer == NULL) return JIM_ERR; while (len) { /* Slurp... in buffer size chunks */ count = len; /* in objects.. */ if (count > (buffersize / width)) count = (buffersize / width); v = 0; /* shut up gcc */ for (i = 0; i < count; i++, n++) { get_int_array_element(interp, varname, n, &v); switch (width) { case 4: target_buffer_set_u32(target, &buffer[i * width], v); break; case 2: target_buffer_set_u16(target, &buffer[i * width], v); break; case 1: buffer[i] = v & 0x0ff; break; } } len -= count; retval = target_write_memory(target, addr, width, count, buffer); if (retval != ERROR_OK) { /* BOO !*/ LOG_ERROR("array2mem: Write @ 0x%08x, w=%d, cnt=%d, failed", (unsigned int)addr, (int)width, (int)count); Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: cannot read memory", NULL); e = JIM_ERR; break; } } free(buffer); Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); return e; } /* FIX? should we propagate errors here rather than printing them * and continuing? */ void target_handle_event(struct target *target, enum target_event e) { struct target_event_action *teap; for (teap = target->event_action; teap != NULL; teap = teap->next) { if (teap->event == e) { LOG_DEBUG("target: (%d) %s (%s) event: %d (%s) action: %s", target->target_number, target_name(target), target_type_name(target), e, Jim_Nvp_value2name_simple(nvp_target_event, e)->name, Jim_GetString(teap->body, NULL)); if (Jim_EvalObj(teap->interp, teap->body) != JIM_OK) { Jim_MakeErrorMessage(teap->interp); command_print(NULL, "%s\n", Jim_GetString(Jim_GetResult(teap->interp), NULL)); } } } } /** * Returns true only if the target has a handler for the specified event. */ bool target_has_event_action(struct target *target, enum target_event event) { struct target_event_action *teap; for (teap = target->event_action; teap != NULL; teap = teap->next) { if (teap->event == event) return true; } return false; } enum target_cfg_param { TCFG_TYPE, TCFG_EVENT, TCFG_WORK_AREA_VIRT, TCFG_WORK_AREA_PHYS, TCFG_WORK_AREA_SIZE, TCFG_WORK_AREA_BACKUP, TCFG_ENDIAN, TCFG_VARIANT, TCFG_COREID, TCFG_CHAIN_POSITION, TCFG_DBGBASE, TCFG_RTOS, }; static Jim_Nvp nvp_config_opts[] = { { .name = "-type", .value = TCFG_TYPE }, { .name = "-event", .value = TCFG_EVENT }, { .name = "-work-area-virt", .value = TCFG_WORK_AREA_VIRT }, { .name = "-work-area-phys", .value = TCFG_WORK_AREA_PHYS }, { .name = "-work-area-size", .value = TCFG_WORK_AREA_SIZE }, { .name = "-work-area-backup", .value = TCFG_WORK_AREA_BACKUP }, { .name = "-endian" , .value = TCFG_ENDIAN }, { .name = "-variant", .value = TCFG_VARIANT }, { .name = "-coreid", .value = TCFG_COREID }, { .name = "-chain-position", .value = TCFG_CHAIN_POSITION }, { .name = "-dbgbase", .value = TCFG_DBGBASE }, { .name = "-rtos", .value = TCFG_RTOS }, { .name = NULL, .value = -1 } }; static int target_configure(Jim_GetOptInfo *goi, struct target *target) { Jim_Nvp *n; Jim_Obj *o; jim_wide w; char *cp; int e; /* parse config or cget options ... */ while (goi->argc > 0) { Jim_SetEmptyResult(goi->interp); /* Jim_GetOpt_Debug(goi); */ if (target->type->target_jim_configure) { /* target defines a configure function */ /* target gets first dibs on parameters */ e = (*(target->type->target_jim_configure))(target, goi); if (e == JIM_OK) { /* more? */ continue; } if (e == JIM_ERR) { /* An error */ return e; } /* otherwise we 'continue' below */ } e = Jim_GetOpt_Nvp(goi, nvp_config_opts, &n); if (e != JIM_OK) { Jim_GetOpt_NvpUnknown(goi, nvp_config_opts, 0); return e; } switch (n->value) { case TCFG_TYPE: /* not setable */ if (goi->isconfigure) { Jim_SetResultFormatted(goi->interp, "not settable: %s", n->name); return JIM_ERR; } else { no_params: if (goi->argc != 0) { Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "NO PARAMS"); return JIM_ERR; } } Jim_SetResultString(goi->interp, target_type_name(target), -1); /* loop for more */ break; case TCFG_EVENT: if (goi->argc == 0) { Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name? ..."); return JIM_ERR; } e = Jim_GetOpt_Nvp(goi, nvp_target_event, &n); if (e != JIM_OK) { Jim_GetOpt_NvpUnknown(goi, nvp_target_event, 1); return e; } if (goi->isconfigure) { if (goi->argc != 1) { Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name? ?EVENT-BODY?"); return JIM_ERR; } } else { if (goi->argc != 0) { Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name?"); return JIM_ERR; } } { struct target_event_action *teap; teap = target->event_action; /* replace existing? */ while (teap) { if (teap->event == (enum target_event)n->value) break; teap = teap->next; } if (goi->isconfigure) { bool replace = true; if (teap == NULL) { /* create new */ teap = calloc(1, sizeof(*teap)); replace = false; } teap->event = n->value; teap->interp = goi->interp; Jim_GetOpt_Obj(goi, &o); if (teap->body) Jim_DecrRefCount(teap->interp, teap->body); teap->body = Jim_DuplicateObj(goi->interp, o); /* * FIXME: * Tcl/TK - "tk events" have a nice feature. * See the "BIND" command. * We should support that here. * You can specify %X and %Y in the event code. * The idea is: %T - target name. * The idea is: %N - target number * The idea is: %E - event name. */ Jim_IncrRefCount(teap->body); if (!replace) { /* add to head of event list */ teap->next = target->event_action; target->event_action = teap; } Jim_SetEmptyResult(goi->interp); } else { /* get */ if (teap == NULL) Jim_SetEmptyResult(goi->interp); else Jim_SetResult(goi->interp, Jim_DuplicateObj(goi->interp, teap->body)); } } /* loop for more */ break; case TCFG_WORK_AREA_VIRT: if (goi->isconfigure) { target_free_all_working_areas(target); e = Jim_GetOpt_Wide(goi, &w); if (e != JIM_OK) return e; target->working_area_virt = w; target->working_area_virt_spec = true; } else { if (goi->argc != 0) goto no_params; } Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->working_area_virt)); /* loop for more */ break; case TCFG_WORK_AREA_PHYS: if (goi->isconfigure) { target_free_all_working_areas(target); e = Jim_GetOpt_Wide(goi, &w); if (e != JIM_OK) return e; target->working_area_phys = w; target->working_area_phys_spec = true; } else { if (goi->argc != 0) goto no_params; } Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->working_area_phys)); /* loop for more */ break; case TCFG_WORK_AREA_SIZE: if (goi->isconfigure) { target_free_all_working_areas(target); e = Jim_GetOpt_Wide(goi, &w); if (e != JIM_OK) return e; target->working_area_size = w; } else { if (goi->argc != 0) goto no_params; } Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->working_area_size)); /* loop for more */ break; case TCFG_WORK_AREA_BACKUP: if (goi->isconfigure) { target_free_all_working_areas(target); e = Jim_GetOpt_Wide(goi, &w); if (e != JIM_OK) return e; /* make this exactly 1 or 0 */ target->backup_working_area = (!!w); } else { if (goi->argc != 0) goto no_params; } Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->backup_working_area)); /* loop for more e*/ break; case TCFG_ENDIAN: if (goi->isconfigure) { e = Jim_GetOpt_Nvp(goi, nvp_target_endian, &n); if (e != JIM_OK) { Jim_GetOpt_NvpUnknown(goi, nvp_target_endian, 1); return e; } target->endianness = n->value; } else { if (goi->argc != 0) goto no_params; } n = Jim_Nvp_value2name_simple(nvp_target_endian, target->endianness); if (n->name == NULL) { target->endianness = TARGET_LITTLE_ENDIAN; n = Jim_Nvp_value2name_simple(nvp_target_endian, target->endianness); } Jim_SetResultString(goi->interp, n->name, -1); /* loop for more */ break; case TCFG_VARIANT: if (goi->isconfigure) { if (goi->argc < 1) { Jim_SetResultFormatted(goi->interp, "%s ?STRING?", n->name); return JIM_ERR; } if (target->variant) free((void *)(target->variant)); e = Jim_GetOpt_String(goi, &cp, NULL); if (e != JIM_OK) return e; target->variant = strdup(cp); } else { if (goi->argc != 0) goto no_params; } Jim_SetResultString(goi->interp, target->variant, -1); /* loop for more */ break; case TCFG_COREID: if (goi->isconfigure) { e = Jim_GetOpt_Wide(goi, &w); if (e != JIM_OK) return e; target->coreid = (int32_t)w; } else { if (goi->argc != 0) goto no_params; } Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->working_area_size)); /* loop for more */ break; case TCFG_CHAIN_POSITION: if (goi->isconfigure) { Jim_Obj *o_t; struct jtag_tap *tap; target_free_all_working_areas(target); e = Jim_GetOpt_Obj(goi, &o_t); if (e != JIM_OK) return e; tap = jtag_tap_by_jim_obj(goi->interp, o_t); if (tap == NULL) return JIM_ERR; /* make this exactly 1 or 0 */ target->tap = tap; } else { if (goi->argc != 0) goto no_params; } Jim_SetResultString(goi->interp, target->tap->dotted_name, -1); /* loop for more e*/ break; case TCFG_DBGBASE: if (goi->isconfigure) { e = Jim_GetOpt_Wide(goi, &w); if (e != JIM_OK) return e; target->dbgbase = (uint32_t)w; target->dbgbase_set = true; } else { if (goi->argc != 0) goto no_params; } Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->dbgbase)); /* loop for more */ break; case TCFG_RTOS: /* RTOS */ { int result = rtos_create(goi, target); if (result != JIM_OK) return result; } /* loop for more */ break; } } /* while (goi->argc) */ /* done - we return */ return JIM_OK; } static int jim_target_configure(Jim_Interp *interp, int argc, Jim_Obj * const *argv) { Jim_GetOptInfo goi; Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1); goi.isconfigure = !strcmp(Jim_GetString(argv[0], NULL), "configure"); int need_args = 1 + goi.isconfigure; if (goi.argc < need_args) { Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv, goi.isconfigure ? "missing: -option VALUE ..." : "missing: -option ..."); return JIM_ERR; } struct target *target = Jim_CmdPrivData(goi.interp); return target_configure(&goi, target); } static int jim_target_mw(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { const char *cmd_name = Jim_GetString(argv[0], NULL); Jim_GetOptInfo goi; Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1); if (goi.argc < 2 || goi.argc > 4) { Jim_SetResultFormatted(goi.interp, "usage: %s [phys]
[]", cmd_name); return JIM_ERR; } target_write_fn fn; fn = target_write_memory_fast; int e; if (strcmp(Jim_GetString(argv[1], NULL), "phys") == 0) { /* consume it */ struct Jim_Obj *obj; e = Jim_GetOpt_Obj(&goi, &obj); if (e != JIM_OK) return e; fn = target_write_phys_memory; } jim_wide a; e = Jim_GetOpt_Wide(&goi, &a); if (e != JIM_OK) return e; jim_wide b; e = Jim_GetOpt_Wide(&goi, &b); if (e != JIM_OK) return e; jim_wide c = 1; if (goi.argc == 1) { e = Jim_GetOpt_Wide(&goi, &c); if (e != JIM_OK) return e; } /* all args must be consumed */ if (goi.argc != 0) return JIM_ERR; struct target *target = Jim_CmdPrivData(goi.interp); unsigned data_size; if (strcasecmp(cmd_name, "mww") == 0) data_size = 4; else if (strcasecmp(cmd_name, "mwh") == 0) data_size = 2; else if (strcasecmp(cmd_name, "mwb") == 0) data_size = 1; else { LOG_ERROR("command '%s' unknown: ", cmd_name); return JIM_ERR; } return (target_fill_mem(target, a, fn, data_size, b, c) == ERROR_OK) ? JIM_OK : JIM_ERR; } /** * @brief Reads an array of words/halfwords/bytes from target memory starting at specified address. * * Usage: mdw [phys]
[] - for 32 bit reads * mdh [phys]
[] - for 16 bit reads * mdb [phys]
[] - for 8 bit reads * * Count defaults to 1. * * Calls target_read_memory or target_read_phys_memory depending on * the presence of the "phys" argument * Reads the target memory in blocks of max. 32 bytes, and returns an array of ints formatted * to int representation in base16. * Also outputs read data in a human readable form using command_print * * @param phys if present target_read_phys_memory will be used instead of target_read_memory * @param address address where to start the read. May be specified in decimal or hex using the standard "0x" prefix * @param count optional count parameter to read an array of values. If not specified, defaults to 1. * @returns: JIM_ERR on error or JIM_OK on success and sets the result string to an array of ascii formatted numbers * on success, with [] number of elements. * * In case of little endian target: * Example1: "mdw 0x00000000" returns "10123456" * Exmaple2: "mdh 0x00000000 1" returns "3456" * Example3: "mdb 0x00000000" returns "56" * Example4: "mdh 0x00000000 2" returns "3456 1012" * Example5: "mdb 0x00000000 3" returns "56 34 12" **/ static int jim_target_md(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { const char *cmd_name = Jim_GetString(argv[0], NULL); Jim_GetOptInfo goi; Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1); if ((goi.argc < 1) || (goi.argc > 3)) { Jim_SetResultFormatted(goi.interp, "usage: %s [phys]
[]", cmd_name); return JIM_ERR; } int (*fn)(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer); fn = target_read_memory; int e; if (strcmp(Jim_GetString(argv[1], NULL), "phys") == 0) { /* consume it */ struct Jim_Obj *obj; e = Jim_GetOpt_Obj(&goi, &obj); if (e != JIM_OK) return e; fn = target_read_phys_memory; } /* Read address parameter */ jim_wide addr; e = Jim_GetOpt_Wide(&goi, &addr); if (e != JIM_OK) return JIM_ERR; /* If next parameter exists, read it out as the count parameter, if not, set it to 1 (default) */ jim_wide count; if (goi.argc == 1) { e = Jim_GetOpt_Wide(&goi, &count); if (e != JIM_OK) return JIM_ERR; } else count = 1; /* all args must be consumed */ if (goi.argc != 0) return JIM_ERR; jim_wide dwidth = 1; /* shut up gcc */ if (strcasecmp(cmd_name, "mdw") == 0) dwidth = 4; else if (strcasecmp(cmd_name, "mdh") == 0) dwidth = 2; else if (strcasecmp(cmd_name, "mdb") == 0) dwidth = 1; else { LOG_ERROR("command '%s' unknown: ", cmd_name); return JIM_ERR; } /* convert count to "bytes" */ int bytes = count * dwidth; struct target *target = Jim_CmdPrivData(goi.interp); uint8_t target_buf[32]; jim_wide x, y, z; while (bytes > 0) { y = (bytes < 16) ? bytes : 16; /* y = min(bytes, 16); */ /* Try to read out next block */ e = fn(target, addr, dwidth, y / dwidth, target_buf); if (e != ERROR_OK) { Jim_SetResultFormatted(interp, "error reading target @ 0x%08lx", (long)addr); return JIM_ERR; } command_print_sameline(NULL, "0x%08x ", (int)(addr)); switch (dwidth) { case 4: for (x = 0; x < 16 && x < y; x += 4) { z = target_buffer_get_u32(target, &(target_buf[x])); command_print_sameline(NULL, "%08x ", (int)(z)); } for (; (x < 16) ; x += 4) command_print_sameline(NULL, " "); break; case 2: for (x = 0; x < 16 && x < y; x += 2) { z = target_buffer_get_u16(target, &(target_buf[x])); command_print_sameline(NULL, "%04x ", (int)(z)); } for (; (x < 16) ; x += 2) command_print_sameline(NULL, " "); break; case 1: default: for (x = 0 ; (x < 16) && (x < y) ; x += 1) { z = target_buffer_get_u8(target, &(target_buf[x])); command_print_sameline(NULL, "%02x ", (int)(z)); } for (; (x < 16) ; x += 1) command_print_sameline(NULL, " "); break; } /* ascii-ify the bytes */ for (x = 0 ; x < y ; x++) { if ((target_buf[x] >= 0x20) && (target_buf[x] <= 0x7e)) { /* good */ } else { /* smack it */ target_buf[x] = '.'; } } /* space pad */ while (x < 16) { target_buf[x] = ' '; x++; } /* terminate */ target_buf[16] = 0; /* print - with a newline */ command_print_sameline(NULL, "%s\n", target_buf); /* NEXT... */ bytes -= 16; addr += 16; } return JIM_OK; } static int jim_target_mem2array(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { struct target *target = Jim_CmdPrivData(interp); return target_mem2array(interp, target, argc - 1, argv + 1); } static int jim_target_array2mem(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { struct target *target = Jim_CmdPrivData(interp); return target_array2mem(interp, target, argc - 1, argv + 1); } static int jim_target_tap_disabled(Jim_Interp *interp) { Jim_SetResultFormatted(interp, "[TAP is disabled]"); return JIM_ERR; } static int jim_target_examine(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 1) { Jim_WrongNumArgs(interp, 1, argv, "[no parameters]"); return JIM_ERR; } struct target *target = Jim_CmdPrivData(interp); if (!target->tap->enabled) return jim_target_tap_disabled(interp); int e = target->type->examine(target); if (e != ERROR_OK) return JIM_ERR; return JIM_OK; } static int jim_target_halt_gdb(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 1) { Jim_WrongNumArgs(interp, 1, argv, "[no parameters]"); return JIM_ERR; } struct target *target = Jim_CmdPrivData(interp); if (target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT) != ERROR_OK) return JIM_ERR; return JIM_OK; } static int jim_target_poll(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 1) { Jim_WrongNumArgs(interp, 1, argv, "[no parameters]"); return JIM_ERR; } struct target *target = Jim_CmdPrivData(interp); if (!target->tap->enabled) return jim_target_tap_disabled(interp); int e; if (!(target_was_examined(target))) e = ERROR_TARGET_NOT_EXAMINED; else e = target->type->poll(target); if (e != ERROR_OK) return JIM_ERR; return JIM_OK; } static int jim_target_reset(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_GetOptInfo goi; Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1); if (goi.argc != 2) { Jim_WrongNumArgs(interp, 0, argv, "([tT]|[fF]|assert|deassert) BOOL"); return JIM_ERR; } Jim_Nvp *n; int e = Jim_GetOpt_Nvp(&goi, nvp_assert, &n); if (e != JIM_OK) { Jim_GetOpt_NvpUnknown(&goi, nvp_assert, 1); return e; } /* the halt or not param */ jim_wide a; e = Jim_GetOpt_Wide(&goi, &a); if (e != JIM_OK) return e; struct target *target = Jim_CmdPrivData(goi.interp); if (!target->tap->enabled) return jim_target_tap_disabled(interp); if (!(target_was_examined(target))) { LOG_ERROR("Target not examined yet"); return ERROR_TARGET_NOT_EXAMINED; } if (!target->type->assert_reset || !target->type->deassert_reset) { Jim_SetResultFormatted(interp, "No target-specific reset for %s", target_name(target)); return JIM_ERR; } /* determine if we should halt or not. */ target->reset_halt = !!a; /* When this happens - all workareas are invalid. */ target_free_all_working_areas_restore(target, 0); /* do the assert */ if (n->value == NVP_ASSERT) e = target->type->assert_reset(target); else e = target->type->deassert_reset(target); return (e == ERROR_OK) ? JIM_OK : JIM_ERR; } static int jim_target_halt(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 1) { Jim_WrongNumArgs(interp, 1, argv, "[no parameters]"); return JIM_ERR; } struct target *target = Jim_CmdPrivData(interp); if (!target->tap->enabled) return jim_target_tap_disabled(interp); int e = target->type->halt(target); return (e == ERROR_OK) ? JIM_OK : JIM_ERR; } static int jim_target_wait_state(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_GetOptInfo goi; Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1); /* params: statename timeoutmsecs */ if (goi.argc != 2) { const char *cmd_name = Jim_GetString(argv[0], NULL); Jim_SetResultFormatted(goi.interp, "%s ", cmd_name); return JIM_ERR; } Jim_Nvp *n; int e = Jim_GetOpt_Nvp(&goi, nvp_target_state, &n); if (e != JIM_OK) { Jim_GetOpt_NvpUnknown(&goi, nvp_target_state, 1); return e; } jim_wide a; e = Jim_GetOpt_Wide(&goi, &a); if (e != JIM_OK) return e; struct target *target = Jim_CmdPrivData(interp); if (!target->tap->enabled) return jim_target_tap_disabled(interp); e = target_wait_state(target, n->value, a); if (e != ERROR_OK) { Jim_Obj *eObj = Jim_NewIntObj(interp, e); Jim_SetResultFormatted(goi.interp, "target: %s wait %s fails (%#s) %s", target_name(target), n->name, eObj, target_strerror_safe(e)); Jim_FreeNewObj(interp, eObj); return JIM_ERR; } return JIM_OK; } /* List for human, Events defined for this target. * scripts/programs should use 'name cget -event NAME' */ static int jim_target_event_list(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { struct command_context *cmd_ctx = current_command_context(interp); assert(cmd_ctx != NULL); struct target *target = Jim_CmdPrivData(interp); struct target_event_action *teap = target->event_action; command_print(cmd_ctx, "Event actions for target (%d) %s\n", target->target_number, target_name(target)); command_print(cmd_ctx, "%-25s | Body", "Event"); command_print(cmd_ctx, "------------------------- | " "----------------------------------------"); while (teap) { Jim_Nvp *opt = Jim_Nvp_value2name_simple(nvp_target_event, teap->event); command_print(cmd_ctx, "%-25s | %s", opt->name, Jim_GetString(teap->body, NULL)); teap = teap->next; } command_print(cmd_ctx, "***END***"); return JIM_OK; } static int jim_target_current_state(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 1) { Jim_WrongNumArgs(interp, 1, argv, "[no parameters]"); return JIM_ERR; } struct target *target = Jim_CmdPrivData(interp); Jim_SetResultString(interp, target_state_name(target), -1); return JIM_OK; } static int jim_target_invoke_event(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_GetOptInfo goi; Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1); if (goi.argc != 1) { const char *cmd_name = Jim_GetString(argv[0], NULL); Jim_SetResultFormatted(goi.interp, "%s ", cmd_name); return JIM_ERR; } Jim_Nvp *n; int e = Jim_GetOpt_Nvp(&goi, nvp_target_event, &n); if (e != JIM_OK) { Jim_GetOpt_NvpUnknown(&goi, nvp_target_event, 1); return e; } struct target *target = Jim_CmdPrivData(interp); target_handle_event(target, n->value); return JIM_OK; } static const struct command_registration target_instance_command_handlers[] = { { .name = "configure", .mode = COMMAND_CONFIG, .jim_handler = jim_target_configure, .help = "configure a new target for use", .usage = "[target_attribute ...]", }, { .name = "cget", .mode = COMMAND_ANY, .jim_handler = jim_target_configure, .help = "returns the specified target attribute", .usage = "target_attribute", }, { .name = "mww", .mode = COMMAND_EXEC, .jim_handler = jim_target_mw, .help = "Write 32-bit word(s) to target memory", .usage = "address data [count]", }, { .name = "mwh", .mode = COMMAND_EXEC, .jim_handler = jim_target_mw, .help = "Write 16-bit half-word(s) to target memory", .usage = "address data [count]", }, { .name = "mwb", .mode = COMMAND_EXEC, .jim_handler = jim_target_mw, .help = "Write byte(s) to target memory", .usage = "address data [count]", }, { .name = "mdw", .mode = COMMAND_EXEC, .jim_handler = jim_target_md, .help = "Display target memory as 32-bit words", .usage = "address [count]", }, { .name = "mdh", .mode = COMMAND_EXEC, .jim_handler = jim_target_md, .help = "Display target memory as 16-bit half-words", .usage = "address [count]", }, { .name = "mdb", .mode = COMMAND_EXEC, .jim_handler = jim_target_md, .help = "Display target memory as 8-bit bytes", .usage = "address [count]", }, { .name = "array2mem", .mode = COMMAND_EXEC, .jim_handler = jim_target_array2mem, .help = "Writes Tcl array of 8/16/32 bit numbers " "to target memory", .usage = "arrayname bitwidth address count", }, { .name = "mem2array", .mode = COMMAND_EXEC, .jim_handler = jim_target_mem2array, .help = "Loads Tcl array of 8/16/32 bit numbers " "from target memory", .usage = "arrayname bitwidth address count", }, { .name = "eventlist", .mode = COMMAND_EXEC, .jim_handler = jim_target_event_list, .help = "displays a table of events defined for this target", }, { .name = "curstate", .mode = COMMAND_EXEC, .jim_handler = jim_target_current_state, .help = "displays the current state of this target", }, { .name = "arp_examine", .mode = COMMAND_EXEC, .jim_handler = jim_target_examine, .help = "used internally for reset processing", }, { .name = "arp_halt_gdb", .mode = COMMAND_EXEC, .jim_handler = jim_target_halt_gdb, .help = "used internally for reset processing to halt GDB", }, { .name = "arp_poll", .mode = COMMAND_EXEC, .jim_handler = jim_target_poll, .help = "used internally for reset processing", }, { .name = "arp_reset", .mode = COMMAND_EXEC, .jim_handler = jim_target_reset, .help = "used internally for reset processing", }, { .name = "arp_halt", .mode = COMMAND_EXEC, .jim_handler = jim_target_halt, .help = "used internally for reset processing", }, { .name = "arp_waitstate", .mode = COMMAND_EXEC, .jim_handler = jim_target_wait_state, .help = "used internally for reset processing", }, { .name = "invoke-event", .mode = COMMAND_EXEC, .jim_handler = jim_target_invoke_event, .help = "invoke handler for specified event", .usage = "event_name", }, COMMAND_REGISTRATION_DONE }; static int target_create(Jim_GetOptInfo *goi) { Jim_Obj *new_cmd; Jim_Cmd *cmd; const char *cp; char *cp2; int e; int x; struct target *target; struct command_context *cmd_ctx; cmd_ctx = current_command_context(goi->interp); assert(cmd_ctx != NULL); if (goi->argc < 3) { Jim_WrongNumArgs(goi->interp, 1, goi->argv, "?name? ?type? ..options..."); return JIM_ERR; } /* COMMAND */ Jim_GetOpt_Obj(goi, &new_cmd); /* does this command exist? */ cmd = Jim_GetCommand(goi->interp, new_cmd, JIM_ERRMSG); if (cmd) { cp = Jim_GetString(new_cmd, NULL); Jim_SetResultFormatted(goi->interp, "Command/target: %s Exists", cp); return JIM_ERR; } /* TYPE */ e = Jim_GetOpt_String(goi, &cp2, NULL); if (e != JIM_OK) return e; cp = cp2; /* now does target type exist */ for (x = 0 ; target_types[x] ; x++) { if (0 == strcmp(cp, target_types[x]->name)) { /* found */ break; } /* check for deprecated name */ if (target_types[x]->deprecated_name) { if (0 == strcmp(cp, target_types[x]->deprecated_name)) { /* found */ LOG_WARNING("target name is deprecated use: \'%s\'", target_types[x]->name); break; } } } if (target_types[x] == NULL) { Jim_SetResultFormatted(goi->interp, "Unknown target type %s, try one of ", cp); for (x = 0 ; target_types[x] ; x++) { if (target_types[x + 1]) { Jim_AppendStrings(goi->interp, Jim_GetResult(goi->interp), target_types[x]->name, ", ", NULL); } else { Jim_AppendStrings(goi->interp, Jim_GetResult(goi->interp), " or ", target_types[x]->name, NULL); } } return JIM_ERR; } /* Create it */ target = calloc(1, sizeof(struct target)); /* set target number */ target->target_number = new_target_number(); /* allocate memory for each unique target type */ target->type = (struct target_type *)calloc(1, sizeof(struct target_type)); memcpy(target->type, target_types[x], sizeof(struct target_type)); /* will be set by "-endian" */ target->endianness = TARGET_ENDIAN_UNKNOWN; /* default to first core, override with -coreid */ target->coreid = 0; target->working_area = 0x0; target->working_area_size = 0x0; target->working_areas = NULL; target->backup_working_area = 0; target->state = TARGET_UNKNOWN; target->debug_reason = DBG_REASON_UNDEFINED; target->reg_cache = NULL; target->breakpoints = NULL; target->watchpoints = NULL; target->next = NULL; target->arch_info = NULL; target->display = 1; target->halt_issued = false; /* initialize trace information */ target->trace_info = malloc(sizeof(struct trace)); target->trace_info->num_trace_points = 0; target->trace_info->trace_points_size = 0; target->trace_info->trace_points = NULL; target->trace_info->trace_history_size = 0; target->trace_info->trace_history = NULL; target->trace_info->trace_history_pos = 0; target->trace_info->trace_history_overflowed = 0; target->dbgmsg = NULL; target->dbg_msg_enabled = 0; target->endianness = TARGET_ENDIAN_UNKNOWN; target->rtos = NULL; target->rtos_auto_detect = false; /* Do the rest as "configure" options */ goi->isconfigure = 1; e = target_configure(goi, target); if (target->tap == NULL) { Jim_SetResultString(goi->interp, "-chain-position required when creating target", -1); e = JIM_ERR; } if (e != JIM_OK) { free(target->type); free(target); return e; } if (target->endianness == TARGET_ENDIAN_UNKNOWN) { /* default endian to little if not specified */ target->endianness = TARGET_LITTLE_ENDIAN; } /* incase variant is not set */ if (!target->variant) target->variant = strdup(""); cp = Jim_GetString(new_cmd, NULL); target->cmd_name = strdup(cp); /* create the target specific commands */ if (target->type->commands) { e = register_commands(cmd_ctx, NULL, target->type->commands); if (ERROR_OK != e) LOG_ERROR("unable to register '%s' commands", cp); } if (target->type->target_create) (*(target->type->target_create))(target, goi->interp); /* append to end of list */ { struct target **tpp; tpp = &(all_targets); while (*tpp) tpp = &((*tpp)->next); *tpp = target; } /* now - create the new target name command */ const const struct command_registration target_subcommands[] = { { .chain = target_instance_command_handlers, }, { .chain = target->type->commands, }, COMMAND_REGISTRATION_DONE }; const const struct command_registration target_commands[] = { { .name = cp, .mode = COMMAND_ANY, .help = "target command group", .usage = "", .chain = target_subcommands, }, COMMAND_REGISTRATION_DONE }; e = register_commands(cmd_ctx, NULL, target_commands); if (ERROR_OK != e) return JIM_ERR; struct command *c = command_find_in_context(cmd_ctx, cp); assert(c); command_set_handler_data(c, target); return (ERROR_OK == e) ? JIM_OK : JIM_ERR; } static int jim_target_current(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 1) { Jim_WrongNumArgs(interp, 1, argv, "Too many parameters"); return JIM_ERR; } struct command_context *cmd_ctx = current_command_context(interp); assert(cmd_ctx != NULL); Jim_SetResultString(interp, target_name(get_current_target(cmd_ctx)), -1); return JIM_OK; } static int jim_target_types(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 1) { Jim_WrongNumArgs(interp, 1, argv, "Too many parameters"); return JIM_ERR; } Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0)); for (unsigned x = 0; NULL != target_types[x]; x++) { Jim_ListAppendElement(interp, Jim_GetResult(interp), Jim_NewStringObj(interp, target_types[x]->name, -1)); } return JIM_OK; } static int jim_target_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 1) { Jim_WrongNumArgs(interp, 1, argv, "Too many parameters"); return JIM_ERR; } Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0)); struct target *target = all_targets; while (target) { Jim_ListAppendElement(interp, Jim_GetResult(interp), Jim_NewStringObj(interp, target_name(target), -1)); target = target->next; } return JIM_OK; } static int jim_target_smp(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int i; const char *targetname; int retval, len; struct target *target = (struct target *) NULL; struct target_list *head, *curr, *new; curr = (struct target_list *) NULL; head = (struct target_list *) NULL; retval = 0; LOG_DEBUG("%d", argc); /* argv[1] = target to associate in smp * argv[2] = target to assoicate in smp * argv[3] ... */ for (i = 1; i < argc; i++) { targetname = Jim_GetString(argv[i], &len); target = get_target(targetname); LOG_DEBUG("%s ", targetname); if (target) { new = malloc(sizeof(struct target_list)); new->target = target; new->next = (struct target_list *)NULL; if (head == (struct target_list *)NULL) { head = new; curr = head; } else { curr->next = new; curr = new; } } } /* now parse the list of cpu and put the target in smp mode*/ curr = head; while (curr != (struct target_list *)NULL) { target = curr->target; target->smp = 1; target->head = head; curr = curr->next; } if (target && target->rtos) retval = rtos_smp_init(head->target); return retval; } static int jim_target_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_GetOptInfo goi; Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1); if (goi.argc < 3) { Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv, " [ ...]"); return JIM_ERR; } return target_create(&goi); } static int jim_target_number(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_GetOptInfo goi; Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1); /* It's OK to remove this mechanism sometime after August 2010 or so */ LOG_WARNING("don't use numbers as target identifiers; use names"); if (goi.argc != 1) { Jim_SetResultFormatted(goi.interp, "usage: target number "); return JIM_ERR; } jim_wide w; int e = Jim_GetOpt_Wide(&goi, &w); if (e != JIM_OK) return JIM_ERR; struct target *target; for (target = all_targets; NULL != target; target = target->next) { if (target->target_number != w) continue; Jim_SetResultString(goi.interp, target_name(target), -1); return JIM_OK; } { Jim_Obj *wObj = Jim_NewIntObj(goi.interp, w); Jim_SetResultFormatted(goi.interp, "Target: number %#s does not exist", wObj); Jim_FreeNewObj(interp, wObj); } return JIM_ERR; } static int jim_target_count(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 1) { Jim_WrongNumArgs(interp, 1, argv, ""); return JIM_ERR; } unsigned count = 0; struct target *target = all_targets; while (NULL != target) { target = target->next; count++; } Jim_SetResult(interp, Jim_NewIntObj(interp, count)); return JIM_OK; } static const struct command_registration target_subcommand_handlers[] = { { .name = "init", .mode = COMMAND_CONFIG, .handler = handle_target_init_command, .help = "initialize targets", }, { .name = "create", /* REVISIT this should be COMMAND_CONFIG ... */ .mode = COMMAND_ANY, .jim_handler = jim_target_create, .usage = "name type '-chain-position' name [options ...]", .help = "Creates and selects a new target", }, { .name = "current", .mode = COMMAND_ANY, .jim_handler = jim_target_current, .help = "Returns the currently selected target", }, { .name = "types", .mode = COMMAND_ANY, .jim_handler = jim_target_types, .help = "Returns the available target types as " "a list of strings", }, { .name = "names", .mode = COMMAND_ANY, .jim_handler = jim_target_names, .help = "Returns the names of all targets as a list of strings", }, { .name = "number", .mode = COMMAND_ANY, .jim_handler = jim_target_number, .usage = "number", .help = "Returns the name of the numbered target " "(DEPRECATED)", }, { .name = "count", .mode = COMMAND_ANY, .jim_handler = jim_target_count, .help = "Returns the number of targets as an integer " "(DEPRECATED)", }, { .name = "smp", .mode = COMMAND_ANY, .jim_handler = jim_target_smp, .usage = "targetname1 targetname2 ...", .help = "gather several target in a smp list" }, COMMAND_REGISTRATION_DONE }; struct FastLoad { uint32_t address; uint8_t *data; int length; }; static int fastload_num; static struct FastLoad *fastload; static void free_fastload(void) { if (fastload != NULL) { int i; for (i = 0; i < fastload_num; i++) { if (fastload[i].data) free(fastload[i].data); } free(fastload); fastload = NULL; } } COMMAND_HANDLER(handle_fast_load_image_command) { uint8_t *buffer; size_t buf_cnt; uint32_t image_size; uint32_t min_address = 0; uint32_t max_address = 0xffffffff; int i; struct image image; int retval = CALL_COMMAND_HANDLER(parse_load_image_command_CMD_ARGV, &image, &min_address, &max_address); if (ERROR_OK != retval) return retval; struct duration bench; duration_start(&bench); retval = image_open(&image, CMD_ARGV[0], (CMD_ARGC >= 3) ? CMD_ARGV[2] : NULL); if (retval != ERROR_OK) return retval; image_size = 0x0; retval = ERROR_OK; fastload_num = image.num_sections; fastload = (struct FastLoad *)malloc(sizeof(struct FastLoad)*image.num_sections); if (fastload == NULL) { command_print(CMD_CTX, "out of memory"); image_close(&image); return ERROR_FAIL; } memset(fastload, 0, sizeof(struct FastLoad)*image.num_sections); for (i = 0; i < image.num_sections; i++) { buffer = malloc(image.sections[i].size); if (buffer == NULL) { command_print(CMD_CTX, "error allocating buffer for section (%d bytes)", (int)(image.sections[i].size)); retval = ERROR_FAIL; break; } retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt); if (retval != ERROR_OK) { free(buffer); break; } uint32_t offset = 0; uint32_t length = buf_cnt; /* DANGER!!! beware of unsigned comparision here!!! */ if ((image.sections[i].base_address + buf_cnt >= min_address) && (image.sections[i].base_address < max_address)) { if (image.sections[i].base_address < min_address) { /* clip addresses below */ offset += min_address-image.sections[i].base_address; length -= offset; } if (image.sections[i].base_address + buf_cnt > max_address) length -= (image.sections[i].base_address + buf_cnt)-max_address; fastload[i].address = image.sections[i].base_address + offset; fastload[i].data = malloc(length); if (fastload[i].data == NULL) { free(buffer); command_print(CMD_CTX, "error allocating buffer for section (%d bytes)", length); retval = ERROR_FAIL; break; } memcpy(fastload[i].data, buffer + offset, length); fastload[i].length = length; image_size += length; command_print(CMD_CTX, "%u bytes written at address 0x%8.8x", (unsigned int)length, ((unsigned int)(image.sections[i].base_address + offset))); } free(buffer); } if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) { command_print(CMD_CTX, "Loaded %" PRIu32 " bytes " "in %fs (%0.3f KiB/s)", image_size, duration_elapsed(&bench), duration_kbps(&bench, image_size)); command_print(CMD_CTX, "WARNING: image has not been loaded to target!" "You can issue a 'fast_load' to finish loading."); } image_close(&image); if (retval != ERROR_OK) free_fastload(); return retval; } COMMAND_HANDLER(handle_fast_load_command) { if (CMD_ARGC > 0) return ERROR_COMMAND_SYNTAX_ERROR; if (fastload == NULL) { LOG_ERROR("No image in memory"); return ERROR_FAIL; } int i; int ms = timeval_ms(); int size = 0; int retval = ERROR_OK; for (i = 0; i < fastload_num; i++) { struct target *target = get_current_target(CMD_CTX); command_print(CMD_CTX, "Write to 0x%08x, length 0x%08x", (unsigned int)(fastload[i].address), (unsigned int)(fastload[i].length)); retval = target_write_buffer(target, fastload[i].address, fastload[i].length, fastload[i].data); if (retval != ERROR_OK) break; size += fastload[i].length; } if (retval == ERROR_OK) { int after = timeval_ms(); command_print(CMD_CTX, "Loaded image %f kBytes/s", (float)(size/1024.0)/((float)(after-ms)/1000.0)); } return retval; } static const struct command_registration target_command_handlers[] = { { .name = "targets", .handler = handle_targets_command, .mode = COMMAND_ANY, .help = "change current default target (one parameter) " "or prints table of all targets (no parameters)", .usage = "[target]", }, { .name = "target", .mode = COMMAND_CONFIG, .help = "configure target", .chain = target_subcommand_handlers, }, COMMAND_REGISTRATION_DONE }; int target_register_commands(struct command_context *cmd_ctx) { return register_commands(cmd_ctx, NULL, target_command_handlers); } static bool target_reset_nag = true; bool get_target_reset_nag(void) { return target_reset_nag; } COMMAND_HANDLER(handle_target_reset_nag) { return CALL_COMMAND_HANDLER(handle_command_parse_bool, &target_reset_nag, "Nag after each reset about options to improve " "performance"); } COMMAND_HANDLER(handle_ps_command) { struct target *target = get_current_target(CMD_CTX); char *display; if (target->state != TARGET_HALTED) { LOG_INFO("target not halted !!"); return ERROR_OK; } if ((target->rtos) && (target->rtos->type) && (target->rtos->type->ps_command)) { display = target->rtos->type->ps_command(target); command_print(CMD_CTX, "%s", display); free(display); return ERROR_OK; } else { LOG_INFO("failed"); return ERROR_TARGET_FAILURE; } } static const struct command_registration target_exec_command_handlers[] = { { .name = "fast_load_image", .handler = handle_fast_load_image_command, .mode = COMMAND_ANY, .help = "Load image into server memory for later use by " "fast_load; primarily for profiling", .usage = "filename address ['bin'|'ihex'|'elf'|'s19'] " "[min_address [max_length]]", }, { .name = "fast_load", .handler = handle_fast_load_command, .mode = COMMAND_EXEC, .help = "loads active fast load image to current target " "- mainly for profiling purposes", .usage = "", }, { .name = "profile", .handler = handle_profile_command, .mode = COMMAND_EXEC, .usage = "seconds filename", .help = "profiling samples the CPU PC", }, /** @todo don't register virt2phys() unless target supports it */ { .name = "virt2phys", .handler = handle_virt2phys_command, .mode = COMMAND_ANY, .help = "translate a virtual address into a physical address", .usage = "virtual_address", }, { .name = "reg", .handler = handle_reg_command, .mode = COMMAND_EXEC, .help = "display or set a register; with no arguments, " "displays all registers and their values", .usage = "[(register_name|register_number) [value]]", }, { .name = "poll", .handler = handle_poll_command, .mode = COMMAND_EXEC, .help = "poll target state; or reconfigure background polling", .usage = "['on'|'off']", }, { .name = "wait_halt", .handler = handle_wait_halt_command, .mode = COMMAND_EXEC, .help = "wait up to the specified number of milliseconds " "(default 5) for a previously requested halt", .usage = "[milliseconds]", }, { .name = "halt", .handler = handle_halt_command, .mode = COMMAND_EXEC, .help = "request target to halt, then wait up to the specified" "number of milliseconds (default 5) for it to complete", .usage = "[milliseconds]", }, { .name = "resume", .handler = handle_resume_command, .mode = COMMAND_EXEC, .help = "resume target execution from current PC or address", .usage = "[address]", }, { .name = "reset", .handler = handle_reset_command, .mode = COMMAND_EXEC, .usage = "[run|halt|init]", .help = "Reset all targets into the specified mode." "Default reset mode is run, if not given.", }, { .name = "soft_reset_halt", .handler = handle_soft_reset_halt_command, .mode = COMMAND_EXEC, .usage = "", .help = "halt the target and do a soft reset", }, { .name = "step", .handler = handle_step_command, .mode = COMMAND_EXEC, .help = "step one instruction from current PC or address", .usage = "[address]", }, { .name = "mdw", .handler = handle_md_command, .mode = COMMAND_EXEC, .help = "display memory words", .usage = "['phys'] address [count]", }, { .name = "mdh", .handler = handle_md_command, .mode = COMMAND_EXEC, .help = "display memory half-words", .usage = "['phys'] address [count]", }, { .name = "mdb", .handler = handle_md_command, .mode = COMMAND_EXEC, .help = "display memory bytes", .usage = "['phys'] address [count]", }, { .name = "mww", .handler = handle_mw_command, .mode = COMMAND_EXEC, .help = "write memory word", .usage = "['phys'] address value [count]", }, { .name = "mwh", .handler = handle_mw_command, .mode = COMMAND_EXEC, .help = "write memory half-word", .usage = "['phys'] address value [count]", }, { .name = "mwb", .handler = handle_mw_command, .mode = COMMAND_EXEC, .help = "write memory byte", .usage = "['phys'] address value [count]", }, { .name = "bp", .handler = handle_bp_command, .mode = COMMAND_EXEC, .help = "list or set hardware or software breakpoint", .usage = "
[] ['hw'|'hw_ctx']", }, { .name = "rbp", .handler = handle_rbp_command, .mode = COMMAND_EXEC, .help = "remove breakpoint", .usage = "address", }, { .name = "wp", .handler = handle_wp_command, .mode = COMMAND_EXEC, .help = "list (no params) or create watchpoints", .usage = "[address length [('r'|'w'|'a') value [mask]]]", }, { .name = "rwp", .handler = handle_rwp_command, .mode = COMMAND_EXEC, .help = "remove watchpoint", .usage = "address", }, { .name = "load_image", .handler = handle_load_image_command, .mode = COMMAND_EXEC, .usage = "filename address ['bin'|'ihex'|'elf'|'s19'] " "[min_address] [max_length]", }, { .name = "dump_image", .handler = handle_dump_image_command, .mode = COMMAND_EXEC, .usage = "filename address size", }, { .name = "verify_image", .handler = handle_verify_image_command, .mode = COMMAND_EXEC, .usage = "filename [offset [type]]", }, { .name = "test_image", .handler = handle_test_image_command, .mode = COMMAND_EXEC, .usage = "filename [offset [type]]", }, { .name = "mem2array", .mode = COMMAND_EXEC, .jim_handler = jim_mem2array, .help = "read 8/16/32 bit memory and return as a TCL array " "for script processing", .usage = "arrayname bitwidth address count", }, { .name = "array2mem", .mode = COMMAND_EXEC, .jim_handler = jim_array2mem, .help = "convert a TCL array to memory locations " "and write the 8/16/32 bit values", .usage = "arrayname bitwidth address count", }, { .name = "reset_nag", .handler = handle_target_reset_nag, .mode = COMMAND_ANY, .help = "Nag after each reset about options that could have been " "enabled to improve performance. ", .usage = "['enable'|'disable']", }, { .name = "ps", .handler = handle_ps_command, .mode = COMMAND_EXEC, .help = "list all tasks ", .usage = " ", }, COMMAND_REGISTRATION_DONE }; static int target_register_user_commands(struct command_context *cmd_ctx) { int retval = ERROR_OK; retval = target_request_register_commands(cmd_ctx); if (retval != ERROR_OK) return retval; retval = trace_register_commands(cmd_ctx); if (retval != ERROR_OK) return retval; return register_commands(cmd_ctx, NULL, target_exec_command_handlers); } openocd-0.7.0/src/target/etb.h0000644000175000001440000000422112134336410013056 00000000000000/*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef ETB_H #define ETB_H /* ETB registers */ enum { ETB_ID = 0x00, ETB_RAM_DEPTH = 0x01, ETB_RAM_WIDTH = 0x02, ETB_STATUS = 0x03, ETB_RAM_DATA = 0x04, ETB_RAM_READ_POINTER = 0x05, ETB_RAM_WRITE_POINTER = 0x06, ETB_TRIGGER_COUNTER = 0x07, ETB_CTRL = 0x08, }; struct etb { struct etm_context *etm_ctx; struct jtag_tap *tap; uint32_t cur_scan_chain; struct reg_cache *reg_cache; /* ETB parameters */ uint32_t ram_depth; uint32_t ram_width; /** how much trace buffer to fill after trigger */ unsigned trigger_percent; }; struct etb_reg { uint32_t addr; struct etb *etb; }; extern struct etm_capture_driver etb_capture_driver; struct reg_cache *etb_build_reg_cache(struct etb *etb); #endif /* ETB_H */ openocd-0.7.0/src/target/register.h0000644000175000001440000000454212134336410014136 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef REGISTER_H #define REGISTER_H struct target; struct reg { const char *name; void *value; bool dirty; bool valid; uint32_t size; void *arch_info; const struct reg_arch_type *type; }; struct reg_cache { const char *name; struct reg_cache *next; struct reg *reg_list; unsigned num_regs; }; struct reg_arch_type { int (*get)(struct reg *reg); int (*set)(struct reg *reg, uint8_t *buf); }; struct reg *register_get_by_name(struct reg_cache *first, const char *name, bool search_all); struct reg_cache **register_get_last_cache_p(struct reg_cache **first); void register_cache_invalidate(struct reg_cache *cache); void register_init_dummy(struct reg *reg); #endif /* REGISTER_H */ openocd-0.7.0/src/target/mips_m4k.h0000644000175000001440000000437112134336410014035 00000000000000/*************************************************************************** * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2008 by David T.L. Wong * * * * Copyright (C) 2011 by Drasko DRASKOVIC * * drasko.draskovic@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef MIPS_M4K_H #define MIPS_M4K_H struct target; #define MIPSM4K_COMMON_MAGIC 0xB321B321 struct mips_m4k_common { uint32_t common_magic; bool is_pic32mx; struct mips32_common mips32; }; static inline struct mips_m4k_common * target_to_m4k(struct target *target) { return container_of(target->arch_info, struct mips_m4k_common, mips32); } extern const struct command_registration mips_m4k_command_handlers[]; #endif /*MIPS_M4K_H*/ openocd-0.7.0/src/target/arm11_dbgtap.h0000644000175000001440000000761612134336410014561 00000000000000/*************************************************************************** * Copyright (C) 2008 digenius technology GmbH. * * Michael Bruck * * * * Copyright (C) 2008,2009 Oyvind Harboe oyvind.harboe@zylin.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef ARM11_DBGTAP_H #define ARM11_DBGTAP_H #include "arm11.h" /* ARM11 internals */ void arm11_setup_field(struct arm11_common *arm11, int num_bits, void *in_data, void *out_data, struct scan_field *field); void arm11_add_IR(struct arm11_common *arm11, uint8_t instr, tap_state_t state); int arm11_add_debug_SCAN_N(struct arm11_common *arm11, uint8_t chain, tap_state_t state); int arm11_read_DSCR(struct arm11_common *arm11); int arm11_write_DSCR(struct arm11_common *arm11, uint32_t dscr); int arm11_run_instr_data_prepare(struct arm11_common *arm11); int arm11_run_instr_data_finish(struct arm11_common *arm11); int arm11_run_instr_no_data1(struct arm11_common *arm11, uint32_t opcode); int arm11_run_instr_data_to_core(struct arm11_common *arm11, uint32_t opcode, uint32_t *data, size_t count); int arm11_run_instr_data_to_core_noack(struct arm11_common *arm11, uint32_t opcode, uint32_t *data, size_t count); int arm11_run_instr_data_to_core1(struct arm11_common *arm11, uint32_t opcode, uint32_t data); int arm11_run_instr_data_from_core(struct arm11_common *arm11, uint32_t opcode, uint32_t *data, size_t count); int arm11_run_instr_data_from_core_via_r0(struct arm11_common *arm11, uint32_t opcode, uint32_t *data); int arm11_run_instr_data_to_core_via_r0(struct arm11_common *arm11, uint32_t opcode, uint32_t data); void arm11_add_dr_scan_vc(struct jtag_tap *tap, int num_fields, struct scan_field *fields, tap_state_t state); /** * Used with arm11_sc7_run to make a list of read/write commands for * scan chain 7 */ struct arm11_sc7_action { bool write; /**< Access mode: true for write, false for read. */ uint8_t address;/**< Register address mode. Use enum #arm11_sc7 */ /** * If write then set this to value to be written. In read mode * this receives the read value when the function returns. */ uint32_t value; }; int arm11_sc7_run(struct arm11_common *arm11, struct arm11_sc7_action *actions, size_t count); /* Mid-level helper functions */ int arm11_sc7_clear_vbw(struct arm11_common *arm11); int arm11_sc7_set_vcr(struct arm11_common *arm11, uint32_t value); int arm11_read_memory_word(struct arm11_common *arm11, uint32_t address, uint32_t *result); int arm11_dpm_init(struct arm11_common *arm11, uint32_t didr); int arm11_bpwp_flush(struct arm11_common *arm11); #endif /* ARM11_DBGTAP_H */ openocd-0.7.0/src/target/breakpoints.c0000644000175000001440000003372112134336410014627 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) ST-Ericsson SA 2011 * * michel.jaouen@stericsson.com : smp minimum support * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "target.h" #include #include "breakpoints.h" static char *breakpoint_type_strings[] = { "hardware", "software" }; static char *watchpoint_rw_strings[] = { "read", "write", "access" }; /* monotonic counter/id-number for breakpoints and watch points */ static int bpwp_unique_id; int breakpoint_add_internal(struct target *target, uint32_t address, uint32_t length, enum breakpoint_type type) { struct breakpoint *breakpoint = target->breakpoints; struct breakpoint **breakpoint_p = &target->breakpoints; char *reason; int retval; int n; n = 0; while (breakpoint) { n++; if (breakpoint->address == address) { /* FIXME don't assume "same address" means "same * breakpoint" ... check all the parameters before * succeeding. */ LOG_DEBUG("Duplicate Breakpoint address: 0x%08" PRIx32 " (BP %d)", address, breakpoint->unique_id); return ERROR_OK; } breakpoint_p = &breakpoint->next; breakpoint = breakpoint->next; } (*breakpoint_p) = malloc(sizeof(struct breakpoint)); (*breakpoint_p)->address = address; (*breakpoint_p)->asid = 0; (*breakpoint_p)->length = length; (*breakpoint_p)->type = type; (*breakpoint_p)->set = 0; (*breakpoint_p)->orig_instr = malloc(length); (*breakpoint_p)->next = NULL; (*breakpoint_p)->unique_id = bpwp_unique_id++; retval = target_add_breakpoint(target, *breakpoint_p); switch (retval) { case ERROR_OK: break; case ERROR_TARGET_RESOURCE_NOT_AVAILABLE: reason = "resource not available"; goto fail; case ERROR_TARGET_NOT_HALTED: reason = "target running"; goto fail; default: reason = "unknown reason"; fail: LOG_ERROR("can't add breakpoint: %s", reason); free((*breakpoint_p)->orig_instr); free(*breakpoint_p); *breakpoint_p = NULL; return retval; } LOG_DEBUG("added %s breakpoint at 0x%8.8" PRIx32 " of length 0x%8.8x, (BPID: %d)", breakpoint_type_strings[(*breakpoint_p)->type], (*breakpoint_p)->address, (*breakpoint_p)->length, (*breakpoint_p)->unique_id); return ERROR_OK; } int context_breakpoint_add_internal(struct target *target, uint32_t asid, uint32_t length, enum breakpoint_type type) { struct breakpoint *breakpoint = target->breakpoints; struct breakpoint **breakpoint_p = &target->breakpoints; int retval; int n; n = 0; while (breakpoint) { n++; if (breakpoint->asid == asid) { /* FIXME don't assume "same address" means "same * breakpoint" ... check all the parameters before * succeeding. */ LOG_DEBUG("Duplicate Breakpoint asid: 0x%08" PRIx32 " (BP %d)", asid, breakpoint->unique_id); return -1; } breakpoint_p = &breakpoint->next; breakpoint = breakpoint->next; } (*breakpoint_p) = malloc(sizeof(struct breakpoint)); (*breakpoint_p)->address = 0; (*breakpoint_p)->asid = asid; (*breakpoint_p)->length = length; (*breakpoint_p)->type = type; (*breakpoint_p)->set = 0; (*breakpoint_p)->orig_instr = malloc(length); (*breakpoint_p)->next = NULL; (*breakpoint_p)->unique_id = bpwp_unique_id++; retval = target_add_context_breakpoint(target, *breakpoint_p); if (retval != ERROR_OK) { LOG_ERROR("could not add breakpoint"); free((*breakpoint_p)->orig_instr); free(*breakpoint_p); *breakpoint_p = NULL; return retval; } LOG_DEBUG("added %s Context breakpoint at 0x%8.8" PRIx32 " of length 0x%8.8x, (BPID: %d)", breakpoint_type_strings[(*breakpoint_p)->type], (*breakpoint_p)->asid, (*breakpoint_p)->length, (*breakpoint_p)->unique_id); return ERROR_OK; } int hybrid_breakpoint_add_internal(struct target *target, uint32_t address, uint32_t asid, uint32_t length, enum breakpoint_type type) { struct breakpoint *breakpoint = target->breakpoints; struct breakpoint **breakpoint_p = &target->breakpoints; int retval; int n; n = 0; while (breakpoint) { n++; if ((breakpoint->asid == asid) && (breakpoint->address == address)) { /* FIXME don't assume "same address" means "same * breakpoint" ... check all the parameters before * succeeding. */ LOG_DEBUG("Duplicate Hybrid Breakpoint asid: 0x%08" PRIx32 " (BP %d)", asid, breakpoint->unique_id); return -1; } else if ((breakpoint->address == address) && (breakpoint->asid == 0)) { LOG_DEBUG("Duplicate Breakpoint IVA: 0x%08" PRIx32 " (BP %d)", address, breakpoint->unique_id); return -1; } breakpoint_p = &breakpoint->next; breakpoint = breakpoint->next; } (*breakpoint_p) = malloc(sizeof(struct breakpoint)); (*breakpoint_p)->address = address; (*breakpoint_p)->asid = asid; (*breakpoint_p)->length = length; (*breakpoint_p)->type = type; (*breakpoint_p)->set = 0; (*breakpoint_p)->orig_instr = malloc(length); (*breakpoint_p)->next = NULL; (*breakpoint_p)->unique_id = bpwp_unique_id++; retval = target_add_hybrid_breakpoint(target, *breakpoint_p); if (retval != ERROR_OK) { LOG_ERROR("could not add breakpoint"); free((*breakpoint_p)->orig_instr); free(*breakpoint_p); *breakpoint_p = NULL; return retval; } LOG_DEBUG( "added %s Hybrid breakpoint at address 0x%8.8" PRIx32 " of length 0x%8.8x, (BPID: %d)", breakpoint_type_strings[(*breakpoint_p)->type], (*breakpoint_p)->address, (*breakpoint_p)->length, (*breakpoint_p)->unique_id); return ERROR_OK; } int breakpoint_add(struct target *target, uint32_t address, uint32_t length, enum breakpoint_type type) { int retval = ERROR_OK; if (target->smp) { struct target_list *head; struct target *curr; head = target->head; if (type == BKPT_SOFT) return breakpoint_add_internal(head->target, address, length, type); while (head != (struct target_list *)NULL) { curr = head->target; retval = breakpoint_add_internal(curr, address, length, type); if (retval != ERROR_OK) return retval; head = head->next; } return retval; } else return breakpoint_add_internal(target, address, length, type); } int context_breakpoint_add(struct target *target, uint32_t asid, uint32_t length, enum breakpoint_type type) { int retval = ERROR_OK; if (target->smp) { struct target_list *head; struct target *curr; head = target->head; while (head != (struct target_list *)NULL) { curr = head->target; retval = context_breakpoint_add_internal(curr, asid, length, type); if (retval != ERROR_OK) return retval; head = head->next; } return retval; } else return context_breakpoint_add_internal(target, asid, length, type); } int hybrid_breakpoint_add(struct target *target, uint32_t address, uint32_t asid, uint32_t length, enum breakpoint_type type) { int retval = ERROR_OK; if (target->smp) { struct target_list *head; struct target *curr; head = target->head; while (head != (struct target_list *)NULL) { curr = head->target; retval = hybrid_breakpoint_add_internal(curr, address, asid, length, type); if (retval != ERROR_OK) return retval; head = head->next; } return retval; } else return hybrid_breakpoint_add_internal(target, address, asid, length, type); } /* free up a breakpoint */ static void breakpoint_free(struct target *target, struct breakpoint *breakpoint_to_remove) { struct breakpoint *breakpoint = target->breakpoints; struct breakpoint **breakpoint_p = &target->breakpoints; int retval; while (breakpoint) { if (breakpoint == breakpoint_to_remove) break; breakpoint_p = &breakpoint->next; breakpoint = breakpoint->next; } if (breakpoint == NULL) return; retval = target_remove_breakpoint(target, breakpoint); LOG_DEBUG("free BPID: %d --> %d", breakpoint->unique_id, retval); (*breakpoint_p) = breakpoint->next; free(breakpoint->orig_instr); free(breakpoint); } int breakpoint_remove_internal(struct target *target, uint32_t address) { struct breakpoint *breakpoint = target->breakpoints; while (breakpoint) { if ((breakpoint->address == address) && (breakpoint->asid == 0)) break; else if ((breakpoint->address == 0) && (breakpoint->asid == address)) break; else if ((breakpoint->address == address) && (breakpoint->asid != 0)) break; breakpoint = breakpoint->next; } if (breakpoint) { breakpoint_free(target, breakpoint); return 1; } else { if (!target->smp) LOG_ERROR("no breakpoint at address 0x%8.8" PRIx32 " found", address); return 0; } } void breakpoint_remove(struct target *target, uint32_t address) { int found = 0; if (target->smp) { struct target_list *head; struct target *curr; head = target->head; while (head != (struct target_list *)NULL) { curr = head->target; found += breakpoint_remove_internal(curr, address); head = head->next; } if (found == 0) LOG_ERROR("no breakpoint at address 0x%8.8" PRIx32 " found", address); } else breakpoint_remove_internal(target, address); } void breakpoint_clear_target_internal(struct target *target) { LOG_DEBUG("Delete all breakpoints for target: %s", target_name(target)); while (target->breakpoints != NULL) breakpoint_free(target, target->breakpoints); } void breakpoint_clear_target(struct target *target) { if (target->smp) { struct target_list *head; struct target *curr; head = target->head; while (head != (struct target_list *)NULL) { curr = head->target; breakpoint_clear_target_internal(curr); head = head->next; } } else breakpoint_clear_target_internal(target); } struct breakpoint *breakpoint_find(struct target *target, uint32_t address) { struct breakpoint *breakpoint = target->breakpoints; while (breakpoint) { if (breakpoint->address == address) return breakpoint; breakpoint = breakpoint->next; } return NULL; } int watchpoint_add(struct target *target, uint32_t address, uint32_t length, enum watchpoint_rw rw, uint32_t value, uint32_t mask) { struct watchpoint *watchpoint = target->watchpoints; struct watchpoint **watchpoint_p = &target->watchpoints; int retval; char *reason; while (watchpoint) { if (watchpoint->address == address) { if (watchpoint->length != length || watchpoint->value != value || watchpoint->mask != mask || watchpoint->rw != rw) { LOG_ERROR("address 0x%8.8" PRIx32 "already has watchpoint %d", address, watchpoint->unique_id); return ERROR_FAIL; } /* ignore duplicate watchpoint */ return ERROR_OK; } watchpoint_p = &watchpoint->next; watchpoint = watchpoint->next; } (*watchpoint_p) = calloc(1, sizeof(struct watchpoint)); (*watchpoint_p)->address = address; (*watchpoint_p)->length = length; (*watchpoint_p)->value = value; (*watchpoint_p)->mask = mask; (*watchpoint_p)->rw = rw; (*watchpoint_p)->unique_id = bpwp_unique_id++; retval = target_add_watchpoint(target, *watchpoint_p); switch (retval) { case ERROR_OK: break; case ERROR_TARGET_RESOURCE_NOT_AVAILABLE: reason = "resource not available"; goto bye; case ERROR_TARGET_NOT_HALTED: reason = "target running"; goto bye; default: reason = "unrecognized error"; bye: LOG_ERROR("can't add %s watchpoint at 0x%8.8" PRIx32 ", %s", watchpoint_rw_strings[(*watchpoint_p)->rw], address, reason); free(*watchpoint_p); *watchpoint_p = NULL; return retval; } LOG_DEBUG("added %s watchpoint at 0x%8.8" PRIx32 " of length 0x%8.8" PRIx32 " (WPID: %d)", watchpoint_rw_strings[(*watchpoint_p)->rw], (*watchpoint_p)->address, (*watchpoint_p)->length, (*watchpoint_p)->unique_id); return ERROR_OK; } static void watchpoint_free(struct target *target, struct watchpoint *watchpoint_to_remove) { struct watchpoint *watchpoint = target->watchpoints; struct watchpoint **watchpoint_p = &target->watchpoints; int retval; while (watchpoint) { if (watchpoint == watchpoint_to_remove) break; watchpoint_p = &watchpoint->next; watchpoint = watchpoint->next; } if (watchpoint == NULL) return; retval = target_remove_watchpoint(target, watchpoint); LOG_DEBUG("free WPID: %d --> %d", watchpoint->unique_id, retval); (*watchpoint_p) = watchpoint->next; free(watchpoint); } void watchpoint_remove(struct target *target, uint32_t address) { struct watchpoint *watchpoint = target->watchpoints; while (watchpoint) { if (watchpoint->address == address) break; watchpoint = watchpoint->next; } if (watchpoint) watchpoint_free(target, watchpoint); else LOG_ERROR("no watchpoint at address 0x%8.8" PRIx32 " found", address); } void watchpoint_clear_target(struct target *target) { LOG_DEBUG("Delete all watchpoints for target: %s", target_name(target)); while (target->watchpoints != NULL) watchpoint_free(target, target->watchpoints); } openocd-0.7.0/src/target/avr32_mem.h0000644000175000001440000000406712134336410014107 00000000000000/*************************************************************************** * Copyright (C) 2010 by Oleksandr Tymoshenko * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef AVR32_MEM #define AVR32_MEM int avr32_jtag_read_memory32(struct avr32_jtag *jtag_info, uint32_t addr, int count, uint32_t *buffer); int avr32_jtag_read_memory16(struct avr32_jtag *jtag_info, uint32_t addr, int count, uint16_t *buffer); int avr32_jtag_read_memory8(struct avr32_jtag *jtag_info, uint32_t addr, int count, uint8_t *buffer); int avr32_jtag_write_memory32(struct avr32_jtag *jtag_info, uint32_t addr, int count, const uint32_t *buffer); int avr32_jtag_write_memory16(struct avr32_jtag *jtag_info, uint32_t addr, int count, const uint16_t *buffer); int avr32_jtag_write_memory8(struct avr32_jtag *jtag_info, uint32_t addr, int count, const uint8_t *buffer); #endif /* AVR32_MEM */ openocd-0.7.0/src/target/armv7m.h0000644000175000001440000001421712137151331013523 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2006 by Magnus Lundin * * lundin@mlu.mine.nu * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef ARMV7M_COMMON_H #define ARMV7M_COMMON_H #include "arm_adi_v5.h" #include "arm.h" /* define for enabling armv7 gdb workarounds */ #if 1 #define ARMV7_GDB_HACKS #endif #ifdef ARMV7_GDB_HACKS extern uint8_t armv7m_gdb_dummy_cpsr_value[]; extern struct reg armv7m_gdb_dummy_cpsr_reg; #endif extern const int armv7m_psp_reg_map[]; extern const int armv7m_msp_reg_map[]; char *armv7m_exception_string(int number); /* offsets into armv7m core register cache */ enum { /* for convenience, the first set of indices match * the Cortex-M3/-M4 DCRSR selectors */ ARMV7M_R0, ARMV7M_R1, ARMV7M_R2, ARMV7M_R3, ARMV7M_R4, ARMV7M_R5, ARMV7M_R6, ARMV7M_R7, ARMV7M_R8, ARMV7M_R9, ARMV7M_R10, ARMV7M_R11, ARMV7M_R12, ARMV7M_R13, ARMV7M_R14, ARMV7M_PC = 15, ARMV7M_xPSR = 16, ARMV7M_MSP, ARMV7M_PSP, /* this next set of indices is arbitrary */ ARMV7M_PRIMASK, ARMV7M_BASEPRI, ARMV7M_FAULTMASK, ARMV7M_CONTROL, /* 32bit Floating-point registers */ ARMV7M_S0, ARMV7M_S1, ARMV7M_S2, ARMV7M_S3, ARMV7M_S4, ARMV7M_S5, ARMV7M_S6, ARMV7M_S7, ARMV7M_S8, ARMV7M_S9, ARMV7M_S10, ARMV7M_S11, ARMV7M_S12, ARMV7M_S13, ARMV7M_S14, ARMV7M_S15, ARMV7M_S16, ARMV7M_S17, ARMV7M_S18, ARMV7M_S19, ARMV7M_S20, ARMV7M_S21, ARMV7M_S22, ARMV7M_S23, ARMV7M_S24, ARMV7M_S25, ARMV7M_S26, ARMV7M_S27, ARMV7M_S28, ARMV7M_S29, ARMV7M_S30, ARMV7M_S31, /* 64bit Floating-point registers */ ARMV7M_D0, ARMV7M_D1, ARMV7M_D2, ARMV7M_D3, ARMV7M_D4, ARMV7M_D5, ARMV7M_D6, ARMV7M_D7, ARMV7M_D8, ARMV7M_D9, ARMV7M_D10, ARMV7M_D11, ARMV7M_D12, ARMV7M_D13, ARMV7M_D14, ARMV7M_D15, /* Floating-point status registers */ ARMV7M_FPSID, ARMV7M_FPSCR, ARMV7M_FPEXC, ARMV7M_LAST_REG, }; enum { FP_NONE = 0, FPv4_SP, }; #define ARMV7M_COMMON_MAGIC 0x2A452A45 struct armv7m_common { struct arm arm; int common_magic; int exception_number; struct adiv5_dap dap; int fp_feature; uint32_t demcr; /* stlink is a high level adapter, does not support all functions */ bool stlink; /* Direct processor core register read and writes */ int (*load_core_reg_u32)(struct target *target, uint32_t num, uint32_t *value); int (*store_core_reg_u32)(struct target *target, uint32_t num, uint32_t value); int (*examine_debug_reason)(struct target *target); int (*post_debug_entry)(struct target *target); void (*pre_restore_context)(struct target *target); }; static inline struct armv7m_common * target_to_armv7m(struct target *target) { return container_of(target->arch_info, struct armv7m_common, arm); } static inline bool is_armv7m(struct armv7m_common *armv7m) { return armv7m->common_magic == ARMV7M_COMMON_MAGIC; } struct armv7m_algorithm { int common_magic; enum arm_mode core_mode; uint32_t context[ARMV7M_LAST_REG]; /* ARMV7M_NUM_REGS */ }; struct reg_cache *armv7m_build_reg_cache(struct target *target); enum armv7m_mode armv7m_number_to_mode(int number); int armv7m_mode_to_number(enum armv7m_mode mode); int armv7m_arch_state(struct target *target); int armv7m_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size); int armv7m_init_arch_info(struct target *target, struct armv7m_common *armv7m); int armv7m_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, uint32_t entry_point, uint32_t exit_point, int timeout_ms, void *arch_info); int armv7m_start_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, uint32_t entry_point, uint32_t exit_point, void *arch_info); int armv7m_wait_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, uint32_t exit_point, int timeout_ms, void *arch_info); int armv7m_invalidate_core_regs(struct target *target); int armv7m_restore_context(struct target *target); int armv7m_checksum_memory(struct target *target, uint32_t address, uint32_t count, uint32_t *checksum); int armv7m_blank_check_memory(struct target *target, uint32_t address, uint32_t count, uint32_t *blank); int armv7m_maybe_skip_bkpt_inst(struct target *target, bool *inst_found); extern const struct command_registration armv7m_command_handlers[]; #endif /* ARMV7M_H */ openocd-0.7.0/src/target/etm_dummy.c0000644000175000001440000000640512134336410014305 00000000000000/*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm.h" #include "etm_dummy.h" COMMAND_HANDLER(handle_etm_dummy_config_command) { struct target *target; struct arm *arm; target = get_target(CMD_ARGV[0]); if (!target) { LOG_ERROR("target '%s' not defined", CMD_ARGV[0]); return ERROR_FAIL; } arm = target_to_arm(target); if (!is_arm(arm)) { command_print(CMD_CTX, "target '%s' isn't an ARM", CMD_ARGV[0]); return ERROR_FAIL; } if (arm->etm) arm->etm->capture_driver_priv = NULL; else { LOG_ERROR("target has no ETM defined, ETM dummy left unconfigured"); return ERROR_FAIL; } return ERROR_OK; } static const struct command_registration etm_dummy_config_command_handlers[] = { { .name = "config", .handler = handle_etm_dummy_config_command, .mode = COMMAND_CONFIG, .usage = "target", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration etm_dummy_command_handlers[] = { { .name = "etm_dummy", .mode = COMMAND_ANY, .help = "Dummy ETM capture driver command group", .chain = etm_dummy_config_command_handlers, }, COMMAND_REGISTRATION_DONE }; static int etm_dummy_init(struct etm_context *etm_ctx) { return ERROR_OK; } static trace_status_t etm_dummy_status(struct etm_context *etm_ctx) { return TRACE_IDLE; } static int etm_dummy_read_trace(struct etm_context *etm_ctx) { return ERROR_OK; } static int etm_dummy_start_capture(struct etm_context *etm_ctx) { return ERROR_ETM_PORTMODE_NOT_SUPPORTED; } static int etm_dummy_stop_capture(struct etm_context *etm_ctx) { return ERROR_OK; } struct etm_capture_driver etm_dummy_capture_driver = { .name = "dummy", .commands = etm_dummy_command_handlers, .init = etm_dummy_init, .status = etm_dummy_status, .start_capture = etm_dummy_start_capture, .stop_capture = etm_dummy_stop_capture, .read_trace = etm_dummy_read_trace, }; openocd-0.7.0/src/target/armv4_5_cache.c0000644000175000001440000000776712134336410014721 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "armv4_5_cache.h" #include int armv4_5_identify_cache(uint32_t cache_type_reg, struct armv4_5_cache_common *cache) { int size, assoc, M, len, multiplier; cache->ctype = (cache_type_reg & 0x1e000000U) >> 25; cache->separate = (cache_type_reg & 0x01000000U) >> 24; size = (cache_type_reg & 0x1c0000) >> 18; assoc = (cache_type_reg & 0x38000) >> 15; M = (cache_type_reg & 0x4000) >> 14; len = (cache_type_reg & 0x3000) >> 12; multiplier = 2 + M; if ((assoc != 0) || (M != 1)) /* assoc 0 and M 1 means cache absent */ { /* cache is present */ cache->d_u_size.linelen = 1 << (len + 3); cache->d_u_size.associativity = multiplier << (assoc - 1); cache->d_u_size.nsets = 1 << (size + 6 - assoc - len); cache->d_u_size.cachesize = multiplier << (size + 8); } else { /* cache is absent */ cache->d_u_size.linelen = -1; cache->d_u_size.associativity = -1; cache->d_u_size.nsets = -1; cache->d_u_size.cachesize = -1; } if (cache->separate) { size = (cache_type_reg & 0x1c0) >> 6; assoc = (cache_type_reg & 0x38) >> 3; M = (cache_type_reg & 0x4) >> 2; len = (cache_type_reg & 0x3); multiplier = 2 + M; if ((assoc != 0) || (M != 1)) /* assoc 0 and M 1 means cache absent */ { /* cache is present */ cache->i_size.linelen = 1 << (len + 3); cache->i_size.associativity = multiplier << (assoc - 1); cache->i_size.nsets = 1 << (size + 6 - assoc - len); cache->i_size.cachesize = multiplier << (size + 8); } else { /* cache is absent */ cache->i_size.linelen = -1; cache->i_size.associativity = -1; cache->i_size.nsets = -1; cache->i_size.cachesize = -1; } } else cache->i_size = cache->d_u_size; return ERROR_OK; } int armv4_5_handle_cache_info_command(struct command_context *cmd_ctx, struct armv4_5_cache_common *armv4_5_cache) { if (armv4_5_cache->ctype == -1) { command_print(cmd_ctx, "cache not yet identified"); return ERROR_OK; } command_print(cmd_ctx, "cache type: 0x%1.1x, %s", armv4_5_cache->ctype, (armv4_5_cache->separate) ? "separate caches" : "unified cache"); command_print(cmd_ctx, "D-Cache: linelen %i, associativity %i, nsets %i, cachesize 0x%x", armv4_5_cache->d_u_size.linelen, armv4_5_cache->d_u_size.associativity, armv4_5_cache->d_u_size.nsets, armv4_5_cache->d_u_size.cachesize); command_print(cmd_ctx, "I-Cache: linelen %i, associativity %i, nsets %i, cachesize 0x%x", armv4_5_cache->i_size.linelen, armv4_5_cache->i_size.associativity, armv4_5_cache->i_size.nsets, armv4_5_cache->i_size.cachesize); return ERROR_OK; } openocd-0.7.0/src/target/arm9tdmi.h0000644000175000001440000000611312134336410014034 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef ARM9TDMI_H #define ARM9TDMI_H #include "embeddedice.h" int arm9tdmi_init_target(struct command_context *cmd_ctx, struct target *target); int arm9tdmi_init_arch_info(struct target *target, struct arm7_9_common *arm7_9, struct jtag_tap *tap); extern const struct command_registration arm9tdmi_command_handlers[]; int arm9tdmi_clock_out(struct arm_jtag *jtag_info, uint32_t instr, uint32_t out, uint32_t *in, int sysspeed); int arm9tdmi_clock_data_in(struct arm_jtag *jtag_info, uint32_t *in); int arm9tdmi_clock_data_in_endianness(struct arm_jtag *jtag_info, void *in, int size, int be); void arm9tdmi_read_core_regs(struct target *target, uint32_t mask, uint32_t *core_regs[16]); void arm9tdmi_write_core_regs(struct target *target, uint32_t mask, uint32_t core_regs[16]); int arm9tdmi_examine_debug_reason(struct target *target); void arm9tdmi_load_word_regs(struct target *target, uint32_t mask); void arm9tdmi_load_hword_reg(struct target *target, int num); void arm9tdmi_load_byte_reg(struct target *target, int num); void arm9tdmi_store_word_regs(struct target *target, uint32_t mask); void arm9tdmi_store_hword_reg(struct target *target, int num); void arm9tdmi_store_byte_reg(struct target *target, int num); void arm9tdmi_branch_resume(struct target *target); void arm9tdmi_enable_single_step(struct target *target, uint32_t next_pc); void arm9tdmi_disable_single_step(struct target *target); #endif /* ARM9TDMI_H */ openocd-0.7.0/src/target/image.h0000644000175000001440000001002712134336410013367 00000000000000/*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef IMAGE_H #define IMAGE_H #include #ifdef HAVE_ELF_H #include #endif #define IMAGE_MAX_ERROR_STRING (256) #define IMAGE_MAX_SECTIONS (512) #define IMAGE_MEMORY_CACHE_SIZE (2048) enum image_type { IMAGE_BINARY, /* plain binary */ IMAGE_IHEX, /* intel hex-record format */ IMAGE_MEMORY, /* target-memory pseudo-image */ IMAGE_ELF, /* ELF binary */ IMAGE_SRECORD, /* motorola s19 */ IMAGE_BUILDER, /* when building a new image */ }; struct imagesection { uint32_t base_address; uint32_t size; int flags; void *private; /* private data */ }; struct image { enum image_type type; /* image type (plain, ihex, ...) */ void *type_private; /* type private data */ int num_sections; /* number of sections contained in the image */ struct imagesection *sections; /* array of sections */ int base_address_set; /* whether the image has a base address set (for relocation purposes) */ long long base_address; /* base address, if one is set */ int start_address_set; /* whether the image has a start address (entry point) associated */ uint32_t start_address; /* start address, if one is set */ }; struct image_binary { struct fileio fileio; }; struct image_ihex { struct fileio fileio; uint8_t *buffer; }; struct image_memory { struct target *target; uint8_t *cache; uint32_t cache_address; }; struct image_elf { struct fileio fileio; Elf32_Ehdr *header; Elf32_Phdr *segments; uint32_t segment_count; uint8_t endianness; }; struct image_mot { struct fileio fileio; uint8_t *buffer; }; int image_open(struct image *image, const char *url, const char *type_string); int image_read_section(struct image *image, int section, uint32_t offset, uint32_t size, uint8_t *buffer, size_t *size_read); void image_close(struct image *image); int image_add_section(struct image *image, uint32_t base, uint32_t size, int flags, uint8_t *data); int image_calculate_checksum(uint8_t *buffer, uint32_t nbytes, uint32_t *checksum); #define ERROR_IMAGE_FORMAT_ERROR (-1400) #define ERROR_IMAGE_TYPE_UNKNOWN (-1401) #define ERROR_IMAGE_TEMPORARILY_UNAVAILABLE (-1402) #define ERROR_IMAGE_CHECKSUM (-1403) #endif /* IMAGE_H */ openocd-0.7.0/src/target/xscale.c0000644000175000001440000031355412137151331013572 00000000000000/*************************************************************************** * Copyright (C) 2006, 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2009 Michael Schwingen * * michael@schwingen.org * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "breakpoints.h" #include "xscale.h" #include "target_type.h" #include "arm_jtag.h" #include "arm_simulator.h" #include "arm_disassembler.h" #include #include "register.h" #include "image.h" #include "arm_opcodes.h" #include "armv4_5.h" /* * Important XScale documents available as of October 2009 include: * * Intel XScale® Core Developer’s Manual, January 2004 * Order Number: 273473-002 * This has a chapter detailing debug facilities, and punts some * details to chip-specific microarchitecture documents. * * Hot-Debug for Intel XScale® Core Debug White Paper, May 2005 * Document Number: 273539-005 * Less detailed than the developer's manual, but summarizes those * missing details (for most XScales) and gives LOTS of notes about * debugger/handler interaction issues. Presents a simpler reset * and load-handler sequence than the arch doc. (Note, OpenOCD * doesn't currently support "Hot-Debug" as defined there.) * * Chip-specific microarchitecture documents may also be useful. */ /* forward declarations */ static int xscale_resume(struct target *, int current, uint32_t address, int handle_breakpoints, int debug_execution); static int xscale_debug_entry(struct target *); static int xscale_restore_banked(struct target *); static int xscale_get_reg(struct reg *reg); static int xscale_set_reg(struct reg *reg, uint8_t *buf); static int xscale_set_breakpoint(struct target *, struct breakpoint *); static int xscale_set_watchpoint(struct target *, struct watchpoint *); static int xscale_unset_breakpoint(struct target *, struct breakpoint *); static int xscale_read_trace(struct target *); /* This XScale "debug handler" is loaded into the processor's * mini-ICache, which is 2K of code writable only via JTAG. * * FIXME the OpenOCD "bin2char" utility currently doesn't handle * binary files cleanly. It's string oriented, and terminates them * with a NUL character. Better would be to generate the constants * and let other code decide names, scoping, and other housekeeping. */ static /* unsigned const char xscale_debug_handler[] = ... */ #include "xscale_debug.h" static char *const xscale_reg_list[] = { "XSCALE_MAINID", /* 0 */ "XSCALE_CACHETYPE", "XSCALE_CTRL", "XSCALE_AUXCTRL", "XSCALE_TTB", "XSCALE_DAC", "XSCALE_FSR", "XSCALE_FAR", "XSCALE_PID", "XSCALE_CPACCESS", "XSCALE_IBCR0", /* 10 */ "XSCALE_IBCR1", "XSCALE_DBR0", "XSCALE_DBR1", "XSCALE_DBCON", "XSCALE_TBREG", "XSCALE_CHKPT0", "XSCALE_CHKPT1", "XSCALE_DCSR", "XSCALE_TX", "XSCALE_RX", /* 20 */ "XSCALE_TXRXCTRL", }; static const struct xscale_reg xscale_reg_arch_info[] = { {XSCALE_MAINID, NULL}, {XSCALE_CACHETYPE, NULL}, {XSCALE_CTRL, NULL}, {XSCALE_AUXCTRL, NULL}, {XSCALE_TTB, NULL}, {XSCALE_DAC, NULL}, {XSCALE_FSR, NULL}, {XSCALE_FAR, NULL}, {XSCALE_PID, NULL}, {XSCALE_CPACCESS, NULL}, {XSCALE_IBCR0, NULL}, {XSCALE_IBCR1, NULL}, {XSCALE_DBR0, NULL}, {XSCALE_DBR1, NULL}, {XSCALE_DBCON, NULL}, {XSCALE_TBREG, NULL}, {XSCALE_CHKPT0, NULL}, {XSCALE_CHKPT1, NULL}, {XSCALE_DCSR, NULL}, /* DCSR accessed via JTAG or SW */ {-1, NULL}, /* TX accessed via JTAG */ {-1, NULL}, /* RX accessed via JTAG */ {-1, NULL}, /* TXRXCTRL implicit access via JTAG */ }; /* convenience wrapper to access XScale specific registers */ static int xscale_set_reg_u32(struct reg *reg, uint32_t value) { uint8_t buf[4]; buf_set_u32(buf, 0, 32, value); return xscale_set_reg(reg, buf); } static const char xscale_not[] = "target is not an XScale"; static int xscale_verify_pointer(struct command_context *cmd_ctx, struct xscale_common *xscale) { if (xscale->common_magic != XSCALE_COMMON_MAGIC) { command_print(cmd_ctx, xscale_not); return ERROR_TARGET_INVALID; } return ERROR_OK; } static int xscale_jtag_set_instr(struct jtag_tap *tap, uint32_t new_instr, tap_state_t end_state) { assert(tap != NULL); if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != new_instr) { struct scan_field field; uint8_t scratch[4]; memset(&field, 0, sizeof field); field.num_bits = tap->ir_length; field.out_value = scratch; buf_set_u32(scratch, 0, field.num_bits, new_instr); jtag_add_ir_scan(tap, &field, end_state); } return ERROR_OK; } static int xscale_read_dcsr(struct target *target) { struct xscale_common *xscale = target_to_xscale(target); int retval; struct scan_field fields[3]; uint8_t field0 = 0x0; uint8_t field0_check_value = 0x2; uint8_t field0_check_mask = 0x7; uint8_t field2 = 0x0; uint8_t field2_check_value = 0x0; uint8_t field2_check_mask = 0x1; xscale_jtag_set_instr(target->tap, XSCALE_SELDCSR << xscale->xscale_variant, TAP_DRPAUSE); buf_set_u32(&field0, 1, 1, xscale->hold_rst); buf_set_u32(&field0, 2, 1, xscale->external_debug_break); memset(&fields, 0, sizeof fields); fields[0].num_bits = 3; fields[0].out_value = &field0; uint8_t tmp; fields[0].in_value = &tmp; fields[1].num_bits = 32; fields[1].in_value = xscale->reg_cache->reg_list[XSCALE_DCSR].value; fields[2].num_bits = 1; fields[2].out_value = &field2; uint8_t tmp2; fields[2].in_value = &tmp2; jtag_add_dr_scan(target->tap, 3, fields, TAP_DRPAUSE); jtag_check_value_mask(fields + 0, &field0_check_value, &field0_check_mask); jtag_check_value_mask(fields + 2, &field2_check_value, &field2_check_mask); retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("JTAG error while reading DCSR"); return retval; } xscale->reg_cache->reg_list[XSCALE_DCSR].dirty = 0; xscale->reg_cache->reg_list[XSCALE_DCSR].valid = 1; /* write the register with the value we just read * on this second pass, only the first bit of field0 is guaranteed to be 0) */ field0_check_mask = 0x1; fields[1].out_value = xscale->reg_cache->reg_list[XSCALE_DCSR].value; fields[1].in_value = NULL; jtag_add_dr_scan(target->tap, 3, fields, TAP_DRPAUSE); /* DANGER!!! this must be here. It will make sure that the arguments * to jtag_set_check_value() does not go out of scope! */ return jtag_execute_queue(); } static void xscale_getbuf(jtag_callback_data_t arg) { uint8_t *in = (uint8_t *)arg; *((uint32_t *)arg) = buf_get_u32(in, 0, 32); } static int xscale_receive(struct target *target, uint32_t *buffer, int num_words) { if (num_words == 0) return ERROR_COMMAND_SYNTAX_ERROR; struct xscale_common *xscale = target_to_xscale(target); int retval = ERROR_OK; tap_state_t path[3]; struct scan_field fields[3]; uint8_t *field0 = malloc(num_words * 1); uint8_t field0_check_value = 0x2; uint8_t field0_check_mask = 0x6; uint32_t *field1 = malloc(num_words * 4); uint8_t field2_check_value = 0x0; uint8_t field2_check_mask = 0x1; int words_done = 0; int words_scheduled = 0; int i; path[0] = TAP_DRSELECT; path[1] = TAP_DRCAPTURE; path[2] = TAP_DRSHIFT; memset(&fields, 0, sizeof fields); fields[0].num_bits = 3; uint8_t tmp; fields[0].in_value = &tmp; fields[0].check_value = &field0_check_value; fields[0].check_mask = &field0_check_mask; fields[1].num_bits = 32; fields[2].num_bits = 1; uint8_t tmp2; fields[2].in_value = &tmp2; fields[2].check_value = &field2_check_value; fields[2].check_mask = &field2_check_mask; xscale_jtag_set_instr(target->tap, XSCALE_DBGTX << xscale->xscale_variant, TAP_IDLE); jtag_add_runtest(1, TAP_IDLE); /* ensures that we're in the TAP_IDLE state as the above *could be a no-op */ /* repeat until all words have been collected */ int attempts = 0; while (words_done < num_words) { /* schedule reads */ words_scheduled = 0; for (i = words_done; i < num_words; i++) { fields[0].in_value = &field0[i]; jtag_add_pathmove(3, path); fields[1].in_value = (uint8_t *)(field1 + i); jtag_add_dr_scan_check(target->tap, 3, fields, TAP_IDLE); jtag_add_callback(xscale_getbuf, (jtag_callback_data_t)(field1 + i)); words_scheduled++; } retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("JTAG error while receiving data from debug handler"); break; } /* examine results */ for (i = words_done; i < num_words; i++) { if (!(field0[i] & 1)) { /* move backwards if necessary */ int j; for (j = i; j < num_words - 1; j++) { field0[j] = field0[j + 1]; field1[j] = field1[j + 1]; } words_scheduled--; } } if (words_scheduled == 0) { if (attempts++ == 1000) { LOG_ERROR( "Failed to receiving data from debug handler after 1000 attempts"); retval = ERROR_TARGET_TIMEOUT; break; } } words_done += words_scheduled; } for (i = 0; i < num_words; i++) *(buffer++) = buf_get_u32((uint8_t *)&field1[i], 0, 32); free(field1); return retval; } static int xscale_read_tx(struct target *target, int consume) { struct xscale_common *xscale = target_to_xscale(target); tap_state_t path[3]; tap_state_t noconsume_path[6]; int retval; struct timeval timeout, now; struct scan_field fields[3]; uint8_t field0_in = 0x0; uint8_t field0_check_value = 0x2; uint8_t field0_check_mask = 0x6; uint8_t field2_check_value = 0x0; uint8_t field2_check_mask = 0x1; xscale_jtag_set_instr(target->tap, XSCALE_DBGTX << xscale->xscale_variant, TAP_IDLE); path[0] = TAP_DRSELECT; path[1] = TAP_DRCAPTURE; path[2] = TAP_DRSHIFT; noconsume_path[0] = TAP_DRSELECT; noconsume_path[1] = TAP_DRCAPTURE; noconsume_path[2] = TAP_DREXIT1; noconsume_path[3] = TAP_DRPAUSE; noconsume_path[4] = TAP_DREXIT2; noconsume_path[5] = TAP_DRSHIFT; memset(&fields, 0, sizeof fields); fields[0].num_bits = 3; fields[0].in_value = &field0_in; fields[1].num_bits = 32; fields[1].in_value = xscale->reg_cache->reg_list[XSCALE_TX].value; fields[2].num_bits = 1; uint8_t tmp; fields[2].in_value = &tmp; gettimeofday(&timeout, NULL); timeval_add_time(&timeout, 1, 0); for (;; ) { /* if we want to consume the register content (i.e. clear TX_READY), * we have to go straight from Capture-DR to Shift-DR * otherwise, we go from Capture-DR to Exit1-DR to Pause-DR */ if (consume) jtag_add_pathmove(3, path); else jtag_add_pathmove(ARRAY_SIZE(noconsume_path), noconsume_path); jtag_add_dr_scan(target->tap, 3, fields, TAP_IDLE); jtag_check_value_mask(fields + 0, &field0_check_value, &field0_check_mask); jtag_check_value_mask(fields + 2, &field2_check_value, &field2_check_mask); retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("JTAG error while reading TX"); return ERROR_TARGET_TIMEOUT; } gettimeofday(&now, NULL); if ((now.tv_sec > timeout.tv_sec) || ((now.tv_sec == timeout.tv_sec) && (now.tv_usec > timeout.tv_usec))) { LOG_ERROR("time out reading TX register"); return ERROR_TARGET_TIMEOUT; } if (!((!(field0_in & 1)) && consume)) goto done; if (debug_level >= 3) { LOG_DEBUG("waiting 100ms"); alive_sleep(100); /* avoid flooding the logs */ } else keep_alive(); } done: if (!(field0_in & 1)) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; return ERROR_OK; } static int xscale_write_rx(struct target *target) { struct xscale_common *xscale = target_to_xscale(target); int retval; struct timeval timeout, now; struct scan_field fields[3]; uint8_t field0_out = 0x0; uint8_t field0_in = 0x0; uint8_t field0_check_value = 0x2; uint8_t field0_check_mask = 0x6; uint8_t field2 = 0x0; uint8_t field2_check_value = 0x0; uint8_t field2_check_mask = 0x1; xscale_jtag_set_instr(target->tap, XSCALE_DBGRX << xscale->xscale_variant, TAP_IDLE); memset(&fields, 0, sizeof fields); fields[0].num_bits = 3; fields[0].out_value = &field0_out; fields[0].in_value = &field0_in; fields[1].num_bits = 32; fields[1].out_value = xscale->reg_cache->reg_list[XSCALE_RX].value; fields[2].num_bits = 1; fields[2].out_value = &field2; uint8_t tmp; fields[2].in_value = &tmp; gettimeofday(&timeout, NULL); timeval_add_time(&timeout, 1, 0); /* poll until rx_read is low */ LOG_DEBUG("polling RX"); for (;;) { jtag_add_dr_scan(target->tap, 3, fields, TAP_IDLE); jtag_check_value_mask(fields + 0, &field0_check_value, &field0_check_mask); jtag_check_value_mask(fields + 2, &field2_check_value, &field2_check_mask); retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("JTAG error while writing RX"); return retval; } gettimeofday(&now, NULL); if ((now.tv_sec > timeout.tv_sec) || ((now.tv_sec == timeout.tv_sec) && (now.tv_usec > timeout.tv_usec))) { LOG_ERROR("time out writing RX register"); return ERROR_TARGET_TIMEOUT; } if (!(field0_in & 1)) goto done; if (debug_level >= 3) { LOG_DEBUG("waiting 100ms"); alive_sleep(100); /* avoid flooding the logs */ } else keep_alive(); } done: /* set rx_valid */ field2 = 0x1; jtag_add_dr_scan(target->tap, 3, fields, TAP_IDLE); retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("JTAG error while writing RX"); return retval; } return ERROR_OK; } /* send count elements of size byte to the debug handler */ static int xscale_send(struct target *target, const uint8_t *buffer, int count, int size) { struct xscale_common *xscale = target_to_xscale(target); uint32_t t[3]; int bits[3]; int retval; int done_count = 0; xscale_jtag_set_instr(target->tap, XSCALE_DBGRX << xscale->xscale_variant, TAP_IDLE); bits[0] = 3; t[0] = 0; bits[1] = 32; t[2] = 1; bits[2] = 1; int endianness = target->endianness; while (done_count++ < count) { switch (size) { case 4: if (endianness == TARGET_LITTLE_ENDIAN) t[1] = le_to_h_u32(buffer); else t[1] = be_to_h_u32(buffer); break; case 2: if (endianness == TARGET_LITTLE_ENDIAN) t[1] = le_to_h_u16(buffer); else t[1] = be_to_h_u16(buffer); break; case 1: t[1] = buffer[0]; break; default: LOG_ERROR("BUG: size neither 4, 2 nor 1"); return ERROR_COMMAND_SYNTAX_ERROR; } jtag_add_dr_out(target->tap, 3, bits, t, TAP_IDLE); buffer += size; } retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("JTAG error while sending data to debug handler"); return retval; } return ERROR_OK; } static int xscale_send_u32(struct target *target, uint32_t value) { struct xscale_common *xscale = target_to_xscale(target); buf_set_u32(xscale->reg_cache->reg_list[XSCALE_RX].value, 0, 32, value); return xscale_write_rx(target); } static int xscale_write_dcsr(struct target *target, int hold_rst, int ext_dbg_brk) { struct xscale_common *xscale = target_to_xscale(target); int retval; struct scan_field fields[3]; uint8_t field0 = 0x0; uint8_t field0_check_value = 0x2; uint8_t field0_check_mask = 0x7; uint8_t field2 = 0x0; uint8_t field2_check_value = 0x0; uint8_t field2_check_mask = 0x1; if (hold_rst != -1) xscale->hold_rst = hold_rst; if (ext_dbg_brk != -1) xscale->external_debug_break = ext_dbg_brk; xscale_jtag_set_instr(target->tap, XSCALE_SELDCSR << xscale->xscale_variant, TAP_IDLE); buf_set_u32(&field0, 1, 1, xscale->hold_rst); buf_set_u32(&field0, 2, 1, xscale->external_debug_break); memset(&fields, 0, sizeof fields); fields[0].num_bits = 3; fields[0].out_value = &field0; uint8_t tmp; fields[0].in_value = &tmp; fields[1].num_bits = 32; fields[1].out_value = xscale->reg_cache->reg_list[XSCALE_DCSR].value; fields[2].num_bits = 1; fields[2].out_value = &field2; uint8_t tmp2; fields[2].in_value = &tmp2; jtag_add_dr_scan(target->tap, 3, fields, TAP_IDLE); jtag_check_value_mask(fields + 0, &field0_check_value, &field0_check_mask); jtag_check_value_mask(fields + 2, &field2_check_value, &field2_check_mask); retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("JTAG error while writing DCSR"); return retval; } xscale->reg_cache->reg_list[XSCALE_DCSR].dirty = 0; xscale->reg_cache->reg_list[XSCALE_DCSR].valid = 1; return ERROR_OK; } /* parity of the number of bits 0 if even; 1 if odd. for 32 bit words */ static unsigned int parity(unsigned int v) { /* unsigned int ov = v; */ v ^= v >> 16; v ^= v >> 8; v ^= v >> 4; v &= 0xf; /* LOG_DEBUG("parity of 0x%x is %i", ov, (0x6996 >> v) & 1); */ return (0x6996 >> v) & 1; } static int xscale_load_ic(struct target *target, uint32_t va, uint32_t buffer[8]) { struct xscale_common *xscale = target_to_xscale(target); uint8_t packet[4]; uint8_t cmd; int word; struct scan_field fields[2]; LOG_DEBUG("loading miniIC at 0x%8.8" PRIx32 "", va); /* LDIC into IR */ xscale_jtag_set_instr(target->tap, XSCALE_LDIC << xscale->xscale_variant, TAP_IDLE); /* CMD is b011 to load a cacheline into the Mini ICache. * Loading into the main ICache is deprecated, and unused. * It's followed by three zero bits, and 27 address bits. */ buf_set_u32(&cmd, 0, 6, 0x3); /* virtual address of desired cache line */ buf_set_u32(packet, 0, 27, va >> 5); memset(&fields, 0, sizeof fields); fields[0].num_bits = 6; fields[0].out_value = &cmd; fields[1].num_bits = 27; fields[1].out_value = packet; jtag_add_dr_scan(target->tap, 2, fields, TAP_IDLE); /* rest of packet is a cacheline: 8 instructions, with parity */ fields[0].num_bits = 32; fields[0].out_value = packet; fields[1].num_bits = 1; fields[1].out_value = &cmd; for (word = 0; word < 8; word++) { buf_set_u32(packet, 0, 32, buffer[word]); uint32_t value; memcpy(&value, packet, sizeof(uint32_t)); cmd = parity(value); jtag_add_dr_scan(target->tap, 2, fields, TAP_IDLE); } return jtag_execute_queue(); } static int xscale_invalidate_ic_line(struct target *target, uint32_t va) { struct xscale_common *xscale = target_to_xscale(target); uint8_t packet[4]; uint8_t cmd; struct scan_field fields[2]; xscale_jtag_set_instr(target->tap, XSCALE_LDIC << xscale->xscale_variant, TAP_IDLE); /* CMD for invalidate IC line b000, bits [6:4] b000 */ buf_set_u32(&cmd, 0, 6, 0x0); /* virtual address of desired cache line */ buf_set_u32(packet, 0, 27, va >> 5); memset(&fields, 0, sizeof fields); fields[0].num_bits = 6; fields[0].out_value = &cmd; fields[1].num_bits = 27; fields[1].out_value = packet; jtag_add_dr_scan(target->tap, 2, fields, TAP_IDLE); return ERROR_OK; } static int xscale_update_vectors(struct target *target) { struct xscale_common *xscale = target_to_xscale(target); int i; int retval; uint32_t low_reset_branch, high_reset_branch; for (i = 1; i < 8; i++) { /* if there's a static vector specified for this exception, override */ if (xscale->static_high_vectors_set & (1 << i)) xscale->high_vectors[i] = xscale->static_high_vectors[i]; else { retval = target_read_u32(target, 0xffff0000 + 4*i, &xscale->high_vectors[i]); if (retval == ERROR_TARGET_TIMEOUT) return retval; if (retval != ERROR_OK) { /* Some of these reads will fail as part of normal execution */ xscale->high_vectors[i] = ARMV4_5_B(0xfffffe, 0); } } } for (i = 1; i < 8; i++) { if (xscale->static_low_vectors_set & (1 << i)) xscale->low_vectors[i] = xscale->static_low_vectors[i]; else { retval = target_read_u32(target, 0x0 + 4*i, &xscale->low_vectors[i]); if (retval == ERROR_TARGET_TIMEOUT) return retval; if (retval != ERROR_OK) { /* Some of these reads will fail as part of normal execution */ xscale->low_vectors[i] = ARMV4_5_B(0xfffffe, 0); } } } /* calculate branches to debug handler */ low_reset_branch = (xscale->handler_address + 0x20 - 0x0 - 0x8) >> 2; high_reset_branch = (xscale->handler_address + 0x20 - 0xffff0000 - 0x8) >> 2; xscale->low_vectors[0] = ARMV4_5_B((low_reset_branch & 0xffffff), 0); xscale->high_vectors[0] = ARMV4_5_B((high_reset_branch & 0xffffff), 0); /* invalidate and load exception vectors in mini i-cache */ xscale_invalidate_ic_line(target, 0x0); xscale_invalidate_ic_line(target, 0xffff0000); xscale_load_ic(target, 0x0, xscale->low_vectors); xscale_load_ic(target, 0xffff0000, xscale->high_vectors); return ERROR_OK; } static int xscale_arch_state(struct target *target) { struct xscale_common *xscale = target_to_xscale(target); struct arm *arm = &xscale->arm; static const char *state[] = { "disabled", "enabled" }; static const char *arch_dbg_reason[] = { "", "\n(processor reset)", "\n(trace buffer full)" }; if (arm->common_magic != ARM_COMMON_MAGIC) { LOG_ERROR("BUG: called for a non-ARMv4/5 target"); return ERROR_COMMAND_SYNTAX_ERROR; } arm_arch_state(target); LOG_USER("MMU: %s, D-Cache: %s, I-Cache: %s%s", state[xscale->armv4_5_mmu.mmu_enabled], state[xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled], state[xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled], arch_dbg_reason[xscale->arch_debug_reason]); return ERROR_OK; } static int xscale_poll(struct target *target) { int retval = ERROR_OK; if ((target->state == TARGET_RUNNING) || (target->state == TARGET_DEBUG_RUNNING)) { enum target_state previous_state = target->state; retval = xscale_read_tx(target, 0); if (retval == ERROR_OK) { /* there's data to read from the tx register, we entered debug state */ target->state = TARGET_HALTED; /* process debug entry, fetching current mode regs */ retval = xscale_debug_entry(target); } else if (retval != ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { LOG_USER("error while polling TX register, reset CPU"); /* here we "lie" so GDB won't get stuck and a reset can be perfomed */ target->state = TARGET_HALTED; } /* debug_entry could have overwritten target state (i.e. immediate resume) * don't signal event handlers in that case */ if (target->state != TARGET_HALTED) return ERROR_OK; /* if target was running, signal that we halted * otherwise we reentered from debug execution */ if (previous_state == TARGET_RUNNING) target_call_event_callbacks(target, TARGET_EVENT_HALTED); else target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); } return retval; } static int xscale_debug_entry(struct target *target) { struct xscale_common *xscale = target_to_xscale(target); struct arm *arm = &xscale->arm; uint32_t pc; uint32_t buffer[10]; unsigned i; int retval; uint32_t moe; /* clear external dbg break (will be written on next DCSR read) */ xscale->external_debug_break = 0; retval = xscale_read_dcsr(target); if (retval != ERROR_OK) return retval; /* get r0, pc, r1 to r7 and cpsr */ retval = xscale_receive(target, buffer, 10); if (retval != ERROR_OK) return retval; /* move r0 from buffer to register cache */ buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, buffer[0]); arm->core_cache->reg_list[0].dirty = 1; arm->core_cache->reg_list[0].valid = 1; LOG_DEBUG("r0: 0x%8.8" PRIx32 "", buffer[0]); /* move pc from buffer to register cache */ buf_set_u32(arm->pc->value, 0, 32, buffer[1]); arm->pc->dirty = 1; arm->pc->valid = 1; LOG_DEBUG("pc: 0x%8.8" PRIx32 "", buffer[1]); /* move data from buffer to register cache */ for (i = 1; i <= 7; i++) { buf_set_u32(arm->core_cache->reg_list[i].value, 0, 32, buffer[1 + i]); arm->core_cache->reg_list[i].dirty = 1; arm->core_cache->reg_list[i].valid = 1; LOG_DEBUG("r%i: 0x%8.8" PRIx32 "", i, buffer[i + 1]); } arm_set_cpsr(arm, buffer[9]); LOG_DEBUG("cpsr: 0x%8.8" PRIx32 "", buffer[9]); if (!is_arm_mode(arm->core_mode)) { target->state = TARGET_UNKNOWN; LOG_ERROR("cpsr contains invalid mode value - communication failure"); return ERROR_TARGET_FAILURE; } LOG_DEBUG("target entered debug state in %s mode", arm_mode_name(arm->core_mode)); /* get banked registers, r8 to r14, and spsr if not in USR/SYS mode */ if (arm->spsr) { xscale_receive(target, buffer, 8); buf_set_u32(arm->spsr->value, 0, 32, buffer[7]); arm->spsr->dirty = false; arm->spsr->valid = true; } else { /* r8 to r14, but no spsr */ xscale_receive(target, buffer, 7); } /* move data from buffer to right banked register in cache */ for (i = 8; i <= 14; i++) { struct reg *r = arm_reg_current(arm, i); buf_set_u32(r->value, 0, 32, buffer[i - 8]); r->dirty = false; r->valid = true; } /* mark xscale regs invalid to ensure they are retrieved from the * debug handler if requested */ for (i = 0; i < xscale->reg_cache->num_regs; i++) xscale->reg_cache->reg_list[i].valid = 0; /* examine debug reason */ xscale_read_dcsr(target); moe = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 2, 3); /* stored PC (for calculating fixup) */ pc = buf_get_u32(arm->pc->value, 0, 32); switch (moe) { case 0x0: /* Processor reset */ target->debug_reason = DBG_REASON_DBGRQ; xscale->arch_debug_reason = XSCALE_DBG_REASON_RESET; pc -= 4; break; case 0x1: /* Instruction breakpoint hit */ target->debug_reason = DBG_REASON_BREAKPOINT; xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; pc -= 4; break; case 0x2: /* Data breakpoint hit */ target->debug_reason = DBG_REASON_WATCHPOINT; xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; pc -= 4; break; case 0x3: /* BKPT instruction executed */ target->debug_reason = DBG_REASON_BREAKPOINT; xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; pc -= 4; break; case 0x4: /* Ext. debug event */ target->debug_reason = DBG_REASON_DBGRQ; xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; pc -= 4; break; case 0x5: /* Vector trap occured */ target->debug_reason = DBG_REASON_BREAKPOINT; xscale->arch_debug_reason = XSCALE_DBG_REASON_GENERIC; pc -= 4; break; case 0x6: /* Trace buffer full break */ target->debug_reason = DBG_REASON_DBGRQ; xscale->arch_debug_reason = XSCALE_DBG_REASON_TB_FULL; pc -= 4; break; case 0x7: /* Reserved (may flag Hot-Debug support) */ default: LOG_ERROR("Method of Entry is 'Reserved'"); exit(-1); break; } /* apply PC fixup */ buf_set_u32(arm->pc->value, 0, 32, pc); /* on the first debug entry, identify cache type */ if (xscale->armv4_5_mmu.armv4_5_cache.ctype == -1) { uint32_t cache_type_reg; /* read cp15 cache type register */ xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CACHETYPE]); cache_type_reg = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CACHETYPE].value, 0, 32); armv4_5_identify_cache(cache_type_reg, &xscale->armv4_5_mmu.armv4_5_cache); } /* examine MMU and Cache settings * read cp15 control register */ xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CTRL]); xscale->cp15_control_reg = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CTRL].value, 0, 32); xscale->armv4_5_mmu.mmu_enabled = (xscale->cp15_control_reg & 0x1U) ? 1 : 0; xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (xscale->cp15_control_reg & 0x4U) ? 1 : 0; xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled = (xscale->cp15_control_reg & 0x1000U) ? 1 : 0; /* tracing enabled, read collected trace data */ if (xscale->trace.mode != XSCALE_TRACE_DISABLED) { xscale_read_trace(target); /* Resume if entered debug due to buffer fill and we're still collecting * trace data. Note that a debug exception due to trace buffer full * can only happen in fill mode. */ if (xscale->arch_debug_reason == XSCALE_DBG_REASON_TB_FULL) { if (--xscale->trace.fill_counter > 0) xscale_resume(target, 1, 0x0, 1, 0); } else /* entered debug for other reason; reset counter */ xscale->trace.fill_counter = 0; } return ERROR_OK; } static int xscale_halt(struct target *target) { struct xscale_common *xscale = target_to_xscale(target); LOG_DEBUG("target->state: %s", target_state_name(target)); if (target->state == TARGET_HALTED) { LOG_DEBUG("target was already halted"); return ERROR_OK; } else if (target->state == TARGET_UNKNOWN) { /* this must not happen for a xscale target */ LOG_ERROR("target was in unknown state when halt was requested"); return ERROR_TARGET_INVALID; } else if (target->state == TARGET_RESET) LOG_DEBUG("target->state == TARGET_RESET"); else { /* assert external dbg break */ xscale->external_debug_break = 1; xscale_read_dcsr(target); target->debug_reason = DBG_REASON_DBGRQ; } return ERROR_OK; } static int xscale_enable_single_step(struct target *target, uint32_t next_pc) { struct xscale_common *xscale = target_to_xscale(target); struct reg *ibcr0 = &xscale->reg_cache->reg_list[XSCALE_IBCR0]; int retval; if (xscale->ibcr0_used) { struct breakpoint *ibcr0_bp = breakpoint_find(target, buf_get_u32(ibcr0->value, 0, 32) & 0xfffffffe); if (ibcr0_bp) xscale_unset_breakpoint(target, ibcr0_bp); else { LOG_ERROR( "BUG: xscale->ibcr0_used is set, but no breakpoint with that address found"); exit(-1); } } retval = xscale_set_reg_u32(ibcr0, next_pc | 0x1); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int xscale_disable_single_step(struct target *target) { struct xscale_common *xscale = target_to_xscale(target); struct reg *ibcr0 = &xscale->reg_cache->reg_list[XSCALE_IBCR0]; int retval; retval = xscale_set_reg_u32(ibcr0, 0x0); if (retval != ERROR_OK) return retval; return ERROR_OK; } static void xscale_enable_watchpoints(struct target *target) { struct watchpoint *watchpoint = target->watchpoints; while (watchpoint) { if (watchpoint->set == 0) xscale_set_watchpoint(target, watchpoint); watchpoint = watchpoint->next; } } static void xscale_enable_breakpoints(struct target *target) { struct breakpoint *breakpoint = target->breakpoints; /* set any pending breakpoints */ while (breakpoint) { if (breakpoint->set == 0) xscale_set_breakpoint(target, breakpoint); breakpoint = breakpoint->next; } } static void xscale_free_trace_data(struct xscale_common *xscale) { struct xscale_trace_data *td = xscale->trace.data; while (td) { struct xscale_trace_data *next_td = td->next; if (td->entries) free(td->entries); free(td); td = next_td; } xscale->trace.data = NULL; } static int xscale_resume(struct target *target, int current, uint32_t address, int handle_breakpoints, int debug_execution) { struct xscale_common *xscale = target_to_xscale(target); struct arm *arm = &xscale->arm; uint32_t current_pc; int retval; int i; LOG_DEBUG("-"); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!debug_execution) target_free_all_working_areas(target); /* update vector tables */ retval = xscale_update_vectors(target); if (retval != ERROR_OK) return retval; /* current = 1: continue on current pc, otherwise continue at
*/ if (!current) buf_set_u32(arm->pc->value, 0, 32, address); current_pc = buf_get_u32(arm->pc->value, 0, 32); /* if we're at the reset vector, we have to simulate the branch */ if (current_pc == 0x0) { arm_simulate_step(target, NULL); current_pc = buf_get_u32(arm->pc->value, 0, 32); } /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) { struct breakpoint *breakpoint; breakpoint = breakpoint_find(target, buf_get_u32(arm->pc->value, 0, 32)); if (breakpoint != NULL) { uint32_t next_pc; enum trace_mode saved_trace_mode; /* there's a breakpoint at the current PC, we have to step over it */ LOG_DEBUG("unset breakpoint at 0x%8.8" PRIx32 "", breakpoint->address); xscale_unset_breakpoint(target, breakpoint); /* calculate PC of next instruction */ retval = arm_simulate_step(target, &next_pc); if (retval != ERROR_OK) { uint32_t current_opcode; target_read_u32(target, current_pc, ¤t_opcode); LOG_ERROR( "BUG: couldn't calculate PC of next instruction, current opcode was 0x%8.8" PRIx32 "", current_opcode); } LOG_DEBUG("enable single-step"); xscale_enable_single_step(target, next_pc); /* restore banked registers */ retval = xscale_restore_banked(target); if (retval != ERROR_OK) return retval; /* send resume request */ xscale_send_u32(target, 0x30); /* send CPSR */ xscale_send_u32(target, buf_get_u32(arm->cpsr->value, 0, 32)); LOG_DEBUG("writing cpsr with value 0x%8.8" PRIx32, buf_get_u32(arm->cpsr->value, 0, 32)); for (i = 7; i >= 0; i--) { /* send register */ xscale_send_u32(target, buf_get_u32(arm->core_cache->reg_list[i].value, 0, 32)); LOG_DEBUG("writing r%i with value 0x%8.8" PRIx32 "", i, buf_get_u32(arm->core_cache->reg_list[i].value, 0, 32)); } /* send PC */ xscale_send_u32(target, buf_get_u32(arm->pc->value, 0, 32)); LOG_DEBUG("writing PC with value 0x%8.8" PRIx32, buf_get_u32(arm->pc->value, 0, 32)); /* disable trace data collection in xscale_debug_entry() */ saved_trace_mode = xscale->trace.mode; xscale->trace.mode = XSCALE_TRACE_DISABLED; /* wait for and process debug entry */ xscale_debug_entry(target); /* re-enable trace buffer, if enabled previously */ xscale->trace.mode = saved_trace_mode; LOG_DEBUG("disable single-step"); xscale_disable_single_step(target); LOG_DEBUG("set breakpoint at 0x%8.8" PRIx32 "", breakpoint->address); xscale_set_breakpoint(target, breakpoint); } } /* enable any pending breakpoints and watchpoints */ xscale_enable_breakpoints(target); xscale_enable_watchpoints(target); /* restore banked registers */ retval = xscale_restore_banked(target); if (retval != ERROR_OK) return retval; /* send resume request (command 0x30 or 0x31) * clean the trace buffer if it is to be enabled (0x62) */ if (xscale->trace.mode != XSCALE_TRACE_DISABLED) { if (xscale->trace.mode == XSCALE_TRACE_FILL) { /* If trace enabled in fill mode and starting collection of new set * of buffers, initialize buffer counter and free previous buffers */ if (xscale->trace.fill_counter == 0) { xscale->trace.fill_counter = xscale->trace.buffer_fill; xscale_free_trace_data(xscale); } } else /* wrap mode; free previous buffer */ xscale_free_trace_data(xscale); xscale_send_u32(target, 0x62); xscale_send_u32(target, 0x31); } else xscale_send_u32(target, 0x30); /* send CPSR */ xscale_send_u32(target, buf_get_u32(arm->cpsr->value, 0, 32)); LOG_DEBUG("writing cpsr with value 0x%8.8" PRIx32, buf_get_u32(arm->cpsr->value, 0, 32)); for (i = 7; i >= 0; i--) { /* send register */ xscale_send_u32(target, buf_get_u32(arm->core_cache->reg_list[i].value, 0, 32)); LOG_DEBUG("writing r%i with value 0x%8.8" PRIx32 "", i, buf_get_u32(arm->core_cache->reg_list[i].value, 0, 32)); } /* send PC */ xscale_send_u32(target, buf_get_u32(arm->pc->value, 0, 32)); LOG_DEBUG("wrote PC with value 0x%8.8" PRIx32, buf_get_u32(arm->pc->value, 0, 32)); target->debug_reason = DBG_REASON_NOTHALTED; if (!debug_execution) { /* registers are now invalid */ register_cache_invalidate(arm->core_cache); target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); } else { target->state = TARGET_DEBUG_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); } LOG_DEBUG("target resumed"); return ERROR_OK; } static int xscale_step_inner(struct target *target, int current, uint32_t address, int handle_breakpoints) { struct xscale_common *xscale = target_to_xscale(target); struct arm *arm = &xscale->arm; uint32_t next_pc; int retval; int i; target->debug_reason = DBG_REASON_SINGLESTEP; /* calculate PC of next instruction */ retval = arm_simulate_step(target, &next_pc); if (retval != ERROR_OK) { uint32_t current_opcode, current_pc; current_pc = buf_get_u32(arm->pc->value, 0, 32); target_read_u32(target, current_pc, ¤t_opcode); LOG_ERROR( "BUG: couldn't calculate PC of next instruction, current opcode was 0x%8.8" PRIx32 "", current_opcode); return retval; } LOG_DEBUG("enable single-step"); retval = xscale_enable_single_step(target, next_pc); if (retval != ERROR_OK) return retval; /* restore banked registers */ retval = xscale_restore_banked(target); if (retval != ERROR_OK) return retval; /* send resume request (command 0x30 or 0x31) * clean the trace buffer if it is to be enabled (0x62) */ if (xscale->trace.mode != XSCALE_TRACE_DISABLED) { retval = xscale_send_u32(target, 0x62); if (retval != ERROR_OK) return retval; retval = xscale_send_u32(target, 0x31); if (retval != ERROR_OK) return retval; } else { retval = xscale_send_u32(target, 0x30); if (retval != ERROR_OK) return retval; } /* send CPSR */ retval = xscale_send_u32(target, buf_get_u32(arm->cpsr->value, 0, 32)); if (retval != ERROR_OK) return retval; LOG_DEBUG("writing cpsr with value 0x%8.8" PRIx32, buf_get_u32(arm->cpsr->value, 0, 32)); for (i = 7; i >= 0; i--) { /* send register */ retval = xscale_send_u32(target, buf_get_u32(arm->core_cache->reg_list[i].value, 0, 32)); if (retval != ERROR_OK) return retval; LOG_DEBUG("writing r%i with value 0x%8.8" PRIx32 "", i, buf_get_u32(arm->core_cache->reg_list[i].value, 0, 32)); } /* send PC */ retval = xscale_send_u32(target, buf_get_u32(arm->pc->value, 0, 32)); if (retval != ERROR_OK) return retval; LOG_DEBUG("wrote PC with value 0x%8.8" PRIx32, buf_get_u32(arm->pc->value, 0, 32)); target_call_event_callbacks(target, TARGET_EVENT_RESUMED); /* registers are now invalid */ register_cache_invalidate(arm->core_cache); /* wait for and process debug entry */ retval = xscale_debug_entry(target); if (retval != ERROR_OK) return retval; LOG_DEBUG("disable single-step"); retval = xscale_disable_single_step(target); if (retval != ERROR_OK) return retval; target_call_event_callbacks(target, TARGET_EVENT_HALTED); return ERROR_OK; } static int xscale_step(struct target *target, int current, uint32_t address, int handle_breakpoints) { struct arm *arm = target_to_arm(target); struct breakpoint *breakpoint = NULL; uint32_t current_pc; int retval; if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* current = 1: continue on current pc, otherwise continue at
*/ if (!current) buf_set_u32(arm->pc->value, 0, 32, address); current_pc = buf_get_u32(arm->pc->value, 0, 32); /* if we're at the reset vector, we have to simulate the step */ if (current_pc == 0x0) { retval = arm_simulate_step(target, NULL); if (retval != ERROR_OK) return retval; current_pc = buf_get_u32(arm->pc->value, 0, 32); LOG_DEBUG("current pc %" PRIx32, current_pc); target->debug_reason = DBG_REASON_SINGLESTEP; target_call_event_callbacks(target, TARGET_EVENT_HALTED); return ERROR_OK; } /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) breakpoint = breakpoint_find(target, buf_get_u32(arm->pc->value, 0, 32)); if (breakpoint != NULL) { retval = xscale_unset_breakpoint(target, breakpoint); if (retval != ERROR_OK) return retval; } retval = xscale_step_inner(target, current, address, handle_breakpoints); if (retval != ERROR_OK) return retval; if (breakpoint) xscale_set_breakpoint(target, breakpoint); LOG_DEBUG("target stepped"); return ERROR_OK; } static int xscale_assert_reset(struct target *target) { struct xscale_common *xscale = target_to_xscale(target); LOG_DEBUG("target->state: %s", target_state_name(target)); /* select DCSR instruction (set endstate to R-T-I to ensure we don't * end up in T-L-R, which would reset JTAG */ xscale_jtag_set_instr(target->tap, XSCALE_SELDCSR << xscale->xscale_variant, TAP_IDLE); /* set Hold reset, Halt mode and Trap Reset */ buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 30, 1, 0x1); buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 1, 0x1); xscale_write_dcsr(target, 1, 0); /* select BYPASS, because having DCSR selected caused problems on the PXA27x */ xscale_jtag_set_instr(target->tap, ~0, TAP_IDLE); jtag_execute_queue(); /* assert reset */ jtag_add_reset(0, 1); /* sleep 1ms, to be sure we fulfill any requirements */ jtag_add_sleep(1000); jtag_execute_queue(); target->state = TARGET_RESET; if (target->reset_halt) { int retval = target_halt(target); if (retval != ERROR_OK) return retval; } return ERROR_OK; } static int xscale_deassert_reset(struct target *target) { struct xscale_common *xscale = target_to_xscale(target); struct breakpoint *breakpoint = target->breakpoints; LOG_DEBUG("-"); xscale->ibcr_available = 2; xscale->ibcr0_used = 0; xscale->ibcr1_used = 0; xscale->dbr_available = 2; xscale->dbr0_used = 0; xscale->dbr1_used = 0; /* mark all hardware breakpoints as unset */ while (breakpoint) { if (breakpoint->type == BKPT_HARD) breakpoint->set = 0; breakpoint = breakpoint->next; } xscale->trace.mode = XSCALE_TRACE_DISABLED; xscale_free_trace_data(xscale); register_cache_invalidate(xscale->arm.core_cache); /* FIXME mark hardware watchpoints got unset too. Also, * at least some of the XScale registers are invalid... */ /* * REVISIT: *assumes* we had a SRST+TRST reset so the mini-icache * contents got invalidated. Safer to force that, so writing new * contents can't ever fail.. */ { uint32_t address; unsigned buf_cnt; const uint8_t *buffer = xscale_debug_handler; int retval; /* release SRST */ jtag_add_reset(0, 0); /* wait 300ms; 150 and 100ms were not enough */ jtag_add_sleep(300*1000); jtag_add_runtest(2030, TAP_IDLE); jtag_execute_queue(); /* set Hold reset, Halt mode and Trap Reset */ buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 30, 1, 0x1); buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 1, 0x1); xscale_write_dcsr(target, 1, 0); /* Load the debug handler into the mini-icache. Since * it's using halt mode (not monitor mode), it runs in * "Special Debug State" for access to registers, memory, * coprocessors, trace data, etc. */ address = xscale->handler_address; for (unsigned binary_size = sizeof xscale_debug_handler - 1; binary_size > 0; binary_size -= buf_cnt, buffer += buf_cnt) { uint32_t cache_line[8]; unsigned i; buf_cnt = binary_size; if (buf_cnt > 32) buf_cnt = 32; for (i = 0; i < buf_cnt; i += 4) { /* convert LE buffer to host-endian uint32_t */ cache_line[i / 4] = le_to_h_u32(&buffer[i]); } for (; i < 32; i += 4) cache_line[i / 4] = 0xe1a08008; /* only load addresses other than the reset vectors */ if ((address % 0x400) != 0x0) { retval = xscale_load_ic(target, address, cache_line); if (retval != ERROR_OK) return retval; } address += buf_cnt; } ; retval = xscale_load_ic(target, 0x0, xscale->low_vectors); if (retval != ERROR_OK) return retval; retval = xscale_load_ic(target, 0xffff0000, xscale->high_vectors); if (retval != ERROR_OK) return retval; jtag_add_runtest(30, TAP_IDLE); jtag_add_sleep(100000); /* set Hold reset, Halt mode and Trap Reset */ buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 30, 1, 0x1); buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 1, 0x1); xscale_write_dcsr(target, 1, 0); /* clear Hold reset to let the target run (should enter debug handler) */ xscale_write_dcsr(target, 0, 1); target->state = TARGET_RUNNING; if (!target->reset_halt) { jtag_add_sleep(10000); /* we should have entered debug now */ xscale_debug_entry(target); target->state = TARGET_HALTED; /* resume the target */ xscale_resume(target, 1, 0x0, 1, 0); } } return ERROR_OK; } static int xscale_read_core_reg(struct target *target, struct reg *r, int num, enum arm_mode mode) { /** \todo add debug handler support for core register reads */ LOG_ERROR("not implemented"); return ERROR_OK; } static int xscale_write_core_reg(struct target *target, struct reg *r, int num, enum arm_mode mode, uint32_t value) { /** \todo add debug handler support for core register writes */ LOG_ERROR("not implemented"); return ERROR_OK; } static int xscale_full_context(struct target *target) { struct arm *arm = target_to_arm(target); uint32_t *buffer; int i, j; LOG_DEBUG("-"); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } buffer = malloc(4 * 8); /* iterate through processor modes (FIQ, IRQ, SVC, ABT, UND and SYS) * we can't enter User mode on an XScale (unpredictable), * but User shares registers with SYS */ for (i = 1; i < 7; i++) { enum arm_mode mode = armv4_5_number_to_mode(i); bool valid = true; struct reg *r; if (mode == ARM_MODE_USR) continue; /* check if there are invalid registers in the current mode */ for (j = 0; valid && j <= 16; j++) { if (!ARMV4_5_CORE_REG_MODE(arm->core_cache, mode, j).valid) valid = false; } if (valid) continue; /* request banked registers */ xscale_send_u32(target, 0x0); /* send CPSR for desired bank mode */ xscale_send_u32(target, mode | 0xc0 /* I/F bits */); /* get banked registers: r8 to r14; and SPSR * except in USR/SYS mode */ if (mode != ARM_MODE_SYS) { /* SPSR */ r = &ARMV4_5_CORE_REG_MODE(arm->core_cache, mode, 16); xscale_receive(target, buffer, 8); buf_set_u32(r->value, 0, 32, buffer[7]); r->dirty = false; r->valid = true; } else xscale_receive(target, buffer, 7); /* move data from buffer to register cache */ for (j = 8; j <= 14; j++) { r = &ARMV4_5_CORE_REG_MODE(arm->core_cache, mode, j); buf_set_u32(r->value, 0, 32, buffer[j - 8]); r->dirty = false; r->valid = true; } } free(buffer); return ERROR_OK; } static int xscale_restore_banked(struct target *target) { struct arm *arm = target_to_arm(target); int i, j; if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* iterate through processor modes (FIQ, IRQ, SVC, ABT, UND and SYS) * and check if any banked registers need to be written. Ignore * USR mode (number 0) in favor of SYS; we can't enter User mode on * an XScale (unpredictable), but they share all registers. */ for (i = 1; i < 7; i++) { enum arm_mode mode = armv4_5_number_to_mode(i); struct reg *r; if (mode == ARM_MODE_USR) continue; /* check if there are dirty registers in this mode */ for (j = 8; j <= 14; j++) { if (ARMV4_5_CORE_REG_MODE(arm->core_cache, mode, j).dirty) goto dirty; } /* if not USR/SYS, check if the SPSR needs to be written */ if (mode != ARM_MODE_SYS) { if (ARMV4_5_CORE_REG_MODE(arm->core_cache, mode, 16).dirty) goto dirty; } /* there's nothing to flush for this mode */ continue; dirty: /* command 0x1: "send banked registers" */ xscale_send_u32(target, 0x1); /* send CPSR for desired mode */ xscale_send_u32(target, mode | 0xc0 /* I/F bits */); /* send r8 to r14/lr ... only FIQ needs more than r13..r14, * but this protocol doesn't understand that nuance. */ for (j = 8; j <= 14; j++) { r = &ARMV4_5_CORE_REG_MODE(arm->core_cache, mode, j); xscale_send_u32(target, buf_get_u32(r->value, 0, 32)); r->dirty = false; } /* send spsr if not in USR/SYS mode */ if (mode != ARM_MODE_SYS) { r = &ARMV4_5_CORE_REG_MODE(arm->core_cache, mode, 16); xscale_send_u32(target, buf_get_u32(r->value, 0, 32)); r->dirty = false; } } return ERROR_OK; } static int xscale_read_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct xscale_common *xscale = target_to_xscale(target); uint32_t *buf32; uint32_t i; int retval; LOG_DEBUG("address: 0x%8.8" PRIx32 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32, address, size, count); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* sanitize arguments */ if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer)) return ERROR_COMMAND_SYNTAX_ERROR; if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) return ERROR_TARGET_UNALIGNED_ACCESS; /* send memory read request (command 0x1n, n: access size) */ retval = xscale_send_u32(target, 0x10 | size); if (retval != ERROR_OK) return retval; /* send base address for read request */ retval = xscale_send_u32(target, address); if (retval != ERROR_OK) return retval; /* send number of requested data words */ retval = xscale_send_u32(target, count); if (retval != ERROR_OK) return retval; /* receive data from target (count times 32-bit words in host endianness) */ buf32 = malloc(4 * count); retval = xscale_receive(target, buf32, count); if (retval != ERROR_OK) return retval; /* extract data from host-endian buffer into byte stream */ for (i = 0; i < count; i++) { switch (size) { case 4: target_buffer_set_u32(target, buffer, buf32[i]); buffer += 4; break; case 2: target_buffer_set_u16(target, buffer, buf32[i] & 0xffff); buffer += 2; break; case 1: *buffer++ = buf32[i] & 0xff; break; default: LOG_ERROR("invalid read size"); return ERROR_COMMAND_SYNTAX_ERROR; } } free(buf32); /* examine DCSR, to see if Sticky Abort (SA) got set */ retval = xscale_read_dcsr(target); if (retval != ERROR_OK) return retval; if (buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 5, 1) == 1) { /* clear SA bit */ retval = xscale_send_u32(target, 0x60); if (retval != ERROR_OK) return retval; return ERROR_TARGET_DATA_ABORT; } return ERROR_OK; } static int xscale_read_phys_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct xscale_common *xscale = target_to_xscale(target); /* with MMU inactive, there are only physical addresses */ if (!xscale->armv4_5_mmu.mmu_enabled) return xscale_read_memory(target, address, size, count, buffer); /** \todo: provide a non-stub implementation of this routine. */ LOG_ERROR("%s: %s is not implemented. Disable MMU?", target_name(target), __func__); return ERROR_FAIL; } static int xscale_write_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct xscale_common *xscale = target_to_xscale(target); int retval; LOG_DEBUG("address: 0x%8.8" PRIx32 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32, address, size, count); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* sanitize arguments */ if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer)) return ERROR_COMMAND_SYNTAX_ERROR; if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) return ERROR_TARGET_UNALIGNED_ACCESS; /* send memory write request (command 0x2n, n: access size) */ retval = xscale_send_u32(target, 0x20 | size); if (retval != ERROR_OK) return retval; /* send base address for read request */ retval = xscale_send_u32(target, address); if (retval != ERROR_OK) return retval; /* send number of requested data words to be written*/ retval = xscale_send_u32(target, count); if (retval != ERROR_OK) return retval; /* extract data from host-endian buffer into byte stream */ #if 0 for (i = 0; i < count; i++) { switch (size) { case 4: value = target_buffer_get_u32(target, buffer); xscale_send_u32(target, value); buffer += 4; break; case 2: value = target_buffer_get_u16(target, buffer); xscale_send_u32(target, value); buffer += 2; break; case 1: value = *buffer; xscale_send_u32(target, value); buffer += 1; break; default: LOG_ERROR("should never get here"); exit(-1); } } #endif retval = xscale_send(target, buffer, count, size); if (retval != ERROR_OK) return retval; /* examine DCSR, to see if Sticky Abort (SA) got set */ retval = xscale_read_dcsr(target); if (retval != ERROR_OK) return retval; if (buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 5, 1) == 1) { /* clear SA bit */ retval = xscale_send_u32(target, 0x60); if (retval != ERROR_OK) return retval; LOG_ERROR("data abort writing memory"); return ERROR_TARGET_DATA_ABORT; } return ERROR_OK; } static int xscale_write_phys_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct xscale_common *xscale = target_to_xscale(target); /* with MMU inactive, there are only physical addresses */ if (!xscale->armv4_5_mmu.mmu_enabled) return xscale_write_memory(target, address, size, count, buffer); /** \todo: provide a non-stub implementation of this routine. */ LOG_ERROR("%s: %s is not implemented. Disable MMU?", target_name(target), __func__); return ERROR_FAIL; } static int xscale_get_ttb(struct target *target, uint32_t *result) { struct xscale_common *xscale = target_to_xscale(target); uint32_t ttb; int retval; retval = xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_TTB]); if (retval != ERROR_OK) return retval; ttb = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_TTB].value, 0, 32); *result = ttb; return ERROR_OK; } static int xscale_disable_mmu_caches(struct target *target, int mmu, int d_u_cache, int i_cache) { struct xscale_common *xscale = target_to_xscale(target); uint32_t cp15_control; int retval; /* read cp15 control register */ retval = xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CTRL]); if (retval != ERROR_OK) return retval; cp15_control = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CTRL].value, 0, 32); if (mmu) cp15_control &= ~0x1U; if (d_u_cache) { /* clean DCache */ retval = xscale_send_u32(target, 0x50); if (retval != ERROR_OK) return retval; retval = xscale_send_u32(target, xscale->cache_clean_address); if (retval != ERROR_OK) return retval; /* invalidate DCache */ retval = xscale_send_u32(target, 0x51); if (retval != ERROR_OK) return retval; cp15_control &= ~0x4U; } if (i_cache) { /* invalidate ICache */ retval = xscale_send_u32(target, 0x52); if (retval != ERROR_OK) return retval; cp15_control &= ~0x1000U; } /* write new cp15 control register */ retval = xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_CTRL], cp15_control); if (retval != ERROR_OK) return retval; /* execute cpwait to ensure outstanding operations complete */ retval = xscale_send_u32(target, 0x53); return retval; } static int xscale_enable_mmu_caches(struct target *target, int mmu, int d_u_cache, int i_cache) { struct xscale_common *xscale = target_to_xscale(target); uint32_t cp15_control; int retval; /* read cp15 control register */ retval = xscale_get_reg(&xscale->reg_cache->reg_list[XSCALE_CTRL]); if (retval != ERROR_OK) return retval; cp15_control = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_CTRL].value, 0, 32); if (mmu) cp15_control |= 0x1U; if (d_u_cache) cp15_control |= 0x4U; if (i_cache) cp15_control |= 0x1000U; /* write new cp15 control register */ retval = xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_CTRL], cp15_control); if (retval != ERROR_OK) return retval; /* execute cpwait to ensure outstanding operations complete */ retval = xscale_send_u32(target, 0x53); return retval; } static int xscale_set_breakpoint(struct target *target, struct breakpoint *breakpoint) { int retval; struct xscale_common *xscale = target_to_xscale(target); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (breakpoint->set) { LOG_WARNING("breakpoint already set"); return ERROR_OK; } if (breakpoint->type == BKPT_HARD) { uint32_t value = breakpoint->address | 1; if (!xscale->ibcr0_used) { xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR0], value); xscale->ibcr0_used = 1; breakpoint->set = 1; /* breakpoint set on first breakpoint register */ } else if (!xscale->ibcr1_used) { xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR1], value); xscale->ibcr1_used = 1; breakpoint->set = 2; /* breakpoint set on second breakpoint register */ } else {/* bug: availability previously verified in xscale_add_breakpoint() */ LOG_ERROR("BUG: no hardware comparator available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } else if (breakpoint->type == BKPT_SOFT) { if (breakpoint->length == 4) { /* keep the original instruction in target endianness */ retval = target_read_memory(target, breakpoint->address, 4, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; /* write the bkpt instruction in target endianness *(arm7_9->arm_bkpt is host endian) */ retval = target_write_u32(target, breakpoint->address, xscale->arm_bkpt); if (retval != ERROR_OK) return retval; } else { /* keep the original instruction in target endianness */ retval = target_read_memory(target, breakpoint->address, 2, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; /* write the bkpt instruction in target endianness *(arm7_9->arm_bkpt is host endian) */ retval = target_write_u16(target, breakpoint->address, xscale->thumb_bkpt); if (retval != ERROR_OK) return retval; } breakpoint->set = 1; xscale_send_u32(target, 0x50); /* clean dcache */ xscale_send_u32(target, xscale->cache_clean_address); xscale_send_u32(target, 0x51); /* invalidate dcache */ xscale_send_u32(target, 0x52); /* invalidate icache and flush fetch buffers */ } return ERROR_OK; } static int xscale_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct xscale_common *xscale = target_to_xscale(target); if ((breakpoint->type == BKPT_HARD) && (xscale->ibcr_available < 1)) { LOG_ERROR("no breakpoint unit available for hardware breakpoint"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if ((breakpoint->length != 2) && (breakpoint->length != 4)) { LOG_ERROR("only breakpoints of two (Thumb) or four (ARM) bytes length supported"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if (breakpoint->type == BKPT_HARD) xscale->ibcr_available--; return xscale_set_breakpoint(target, breakpoint); } static int xscale_unset_breakpoint(struct target *target, struct breakpoint *breakpoint) { int retval; struct xscale_common *xscale = target_to_xscale(target); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!breakpoint->set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } if (breakpoint->type == BKPT_HARD) { if (breakpoint->set == 1) { xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR0], 0x0); xscale->ibcr0_used = 0; } else if (breakpoint->set == 2) { xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_IBCR1], 0x0); xscale->ibcr1_used = 0; } breakpoint->set = 0; } else { /* restore original instruction (kept in target endianness) */ if (breakpoint->length == 4) { retval = target_write_memory(target, breakpoint->address, 4, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; } else { retval = target_write_memory(target, breakpoint->address, 2, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; } breakpoint->set = 0; xscale_send_u32(target, 0x50); /* clean dcache */ xscale_send_u32(target, xscale->cache_clean_address); xscale_send_u32(target, 0x51); /* invalidate dcache */ xscale_send_u32(target, 0x52); /* invalidate icache and flush fetch buffers */ } return ERROR_OK; } static int xscale_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct xscale_common *xscale = target_to_xscale(target); if (target->state != TARGET_HALTED) { LOG_ERROR("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (breakpoint->set) xscale_unset_breakpoint(target, breakpoint); if (breakpoint->type == BKPT_HARD) xscale->ibcr_available++; return ERROR_OK; } static int xscale_set_watchpoint(struct target *target, struct watchpoint *watchpoint) { struct xscale_common *xscale = target_to_xscale(target); uint32_t enable = 0; struct reg *dbcon = &xscale->reg_cache->reg_list[XSCALE_DBCON]; uint32_t dbcon_value = buf_get_u32(dbcon->value, 0, 32); if (target->state != TARGET_HALTED) { LOG_ERROR("target not halted"); return ERROR_TARGET_NOT_HALTED; } switch (watchpoint->rw) { case WPT_READ: enable = 0x3; break; case WPT_ACCESS: enable = 0x2; break; case WPT_WRITE: enable = 0x1; break; default: LOG_ERROR("BUG: watchpoint->rw neither read, write nor access"); } /* For watchpoint across more than one word, both DBR registers must be enlisted, with the second used as a mask. */ if (watchpoint->length > 4) { if (xscale->dbr0_used || xscale->dbr1_used) { LOG_ERROR("BUG: sufficient hardware comparators unavailable"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* Write mask value to DBR1, based on the length argument. * Address bits ignored by the comparator are those set in mask. */ xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_DBR1], watchpoint->length - 1); xscale->dbr1_used = 1; enable |= 0x100; /* DBCON[M] */ } if (!xscale->dbr0_used) { xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_DBR0], watchpoint->address); dbcon_value |= enable; xscale_set_reg_u32(dbcon, dbcon_value); watchpoint->set = 1; xscale->dbr0_used = 1; } else if (!xscale->dbr1_used) { xscale_set_reg_u32(&xscale->reg_cache->reg_list[XSCALE_DBR1], watchpoint->address); dbcon_value |= enable << 2; xscale_set_reg_u32(dbcon, dbcon_value); watchpoint->set = 2; xscale->dbr1_used = 1; } else { LOG_ERROR("BUG: no hardware comparator available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } return ERROR_OK; } static int xscale_add_watchpoint(struct target *target, struct watchpoint *watchpoint) { struct xscale_common *xscale = target_to_xscale(target); if (xscale->dbr_available < 1) { LOG_ERROR("no more watchpoint registers available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if (watchpoint->value) LOG_WARNING("xscale does not support value, mask arguments; ignoring"); /* check that length is a power of two */ for (uint32_t len = watchpoint->length; len != 1; len /= 2) { if (len % 2) { LOG_ERROR("xscale requires that watchpoint length is a power of two"); return ERROR_COMMAND_ARGUMENT_INVALID; } } if (watchpoint->length == 4) { /* single word watchpoint */ xscale->dbr_available--;/* one DBR reg used */ return ERROR_OK; } /* watchpoints across multiple words require both DBR registers */ if (xscale->dbr_available < 2) { LOG_ERROR("insufficient watchpoint registers available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if (watchpoint->length > watchpoint->address) { LOG_ERROR("xscale does not support watchpoints with length " "greater than address"); return ERROR_COMMAND_ARGUMENT_INVALID; } xscale->dbr_available = 0; return ERROR_OK; } static int xscale_unset_watchpoint(struct target *target, struct watchpoint *watchpoint) { struct xscale_common *xscale = target_to_xscale(target); struct reg *dbcon = &xscale->reg_cache->reg_list[XSCALE_DBCON]; uint32_t dbcon_value = buf_get_u32(dbcon->value, 0, 32); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!watchpoint->set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } if (watchpoint->set == 1) { if (watchpoint->length > 4) { dbcon_value &= ~0x103; /* clear DBCON[M] as well */ xscale->dbr1_used = 0; /* DBR1 was used for mask */ } else dbcon_value &= ~0x3; xscale_set_reg_u32(dbcon, dbcon_value); xscale->dbr0_used = 0; } else if (watchpoint->set == 2) { dbcon_value &= ~0xc; xscale_set_reg_u32(dbcon, dbcon_value); xscale->dbr1_used = 0; } watchpoint->set = 0; return ERROR_OK; } static int xscale_remove_watchpoint(struct target *target, struct watchpoint *watchpoint) { struct xscale_common *xscale = target_to_xscale(target); if (target->state != TARGET_HALTED) { LOG_ERROR("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (watchpoint->set) xscale_unset_watchpoint(target, watchpoint); if (watchpoint->length > 4) xscale->dbr_available++;/* both DBR regs now available */ xscale->dbr_available++; return ERROR_OK; } static int xscale_get_reg(struct reg *reg) { struct xscale_reg *arch_info = reg->arch_info; struct target *target = arch_info->target; struct xscale_common *xscale = target_to_xscale(target); /* DCSR, TX and RX are accessible via JTAG */ if (strcmp(reg->name, "XSCALE_DCSR") == 0) return xscale_read_dcsr(arch_info->target); else if (strcmp(reg->name, "XSCALE_TX") == 0) { /* 1 = consume register content */ return xscale_read_tx(arch_info->target, 1); } else if (strcmp(reg->name, "XSCALE_RX") == 0) { /* can't read from RX register (host -> debug handler) */ return ERROR_OK; } else if (strcmp(reg->name, "XSCALE_TXRXCTRL") == 0) { /* can't (explicitly) read from TXRXCTRL register */ return ERROR_OK; } else {/* Other DBG registers have to be transfered by the debug handler * send CP read request (command 0x40) */ xscale_send_u32(target, 0x40); /* send CP register number */ xscale_send_u32(target, arch_info->dbg_handler_number); /* read register value */ xscale_read_tx(target, 1); buf_cpy(xscale->reg_cache->reg_list[XSCALE_TX].value, reg->value, 32); reg->dirty = 0; reg->valid = 1; } return ERROR_OK; } static int xscale_set_reg(struct reg *reg, uint8_t *buf) { struct xscale_reg *arch_info = reg->arch_info; struct target *target = arch_info->target; struct xscale_common *xscale = target_to_xscale(target); uint32_t value = buf_get_u32(buf, 0, 32); /* DCSR, TX and RX are accessible via JTAG */ if (strcmp(reg->name, "XSCALE_DCSR") == 0) { buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 0, 32, value); return xscale_write_dcsr(arch_info->target, -1, -1); } else if (strcmp(reg->name, "XSCALE_RX") == 0) { buf_set_u32(xscale->reg_cache->reg_list[XSCALE_RX].value, 0, 32, value); return xscale_write_rx(arch_info->target); } else if (strcmp(reg->name, "XSCALE_TX") == 0) { /* can't write to TX register (debug-handler -> host) */ return ERROR_OK; } else if (strcmp(reg->name, "XSCALE_TXRXCTRL") == 0) { /* can't (explicitly) write to TXRXCTRL register */ return ERROR_OK; } else {/* Other DBG registers have to be transfered by the debug handler * send CP write request (command 0x41) */ xscale_send_u32(target, 0x41); /* send CP register number */ xscale_send_u32(target, arch_info->dbg_handler_number); /* send CP register value */ xscale_send_u32(target, value); buf_set_u32(reg->value, 0, 32, value); } return ERROR_OK; } static int xscale_write_dcsr_sw(struct target *target, uint32_t value) { struct xscale_common *xscale = target_to_xscale(target); struct reg *dcsr = &xscale->reg_cache->reg_list[XSCALE_DCSR]; struct xscale_reg *dcsr_arch_info = dcsr->arch_info; /* send CP write request (command 0x41) */ xscale_send_u32(target, 0x41); /* send CP register number */ xscale_send_u32(target, dcsr_arch_info->dbg_handler_number); /* send CP register value */ xscale_send_u32(target, value); buf_set_u32(dcsr->value, 0, 32, value); return ERROR_OK; } static int xscale_read_trace(struct target *target) { struct xscale_common *xscale = target_to_xscale(target); struct arm *arm = &xscale->arm; struct xscale_trace_data **trace_data_p; /* 258 words from debug handler * 256 trace buffer entries * 2 checkpoint addresses */ uint32_t trace_buffer[258]; int is_address[256]; int i, j; unsigned int num_checkpoints = 0; if (target->state != TARGET_HALTED) { LOG_WARNING("target must be stopped to read trace data"); return ERROR_TARGET_NOT_HALTED; } /* send read trace buffer command (command 0x61) */ xscale_send_u32(target, 0x61); /* receive trace buffer content */ xscale_receive(target, trace_buffer, 258); /* parse buffer backwards to identify address entries */ for (i = 255; i >= 0; i--) { /* also count number of checkpointed entries */ if ((trace_buffer[i] & 0xe0) == 0xc0) num_checkpoints++; is_address[i] = 0; if (((trace_buffer[i] & 0xf0) == 0x90) || ((trace_buffer[i] & 0xf0) == 0xd0)) { if (i > 0) is_address[--i] = 1; if (i > 0) is_address[--i] = 1; if (i > 0) is_address[--i] = 1; if (i > 0) is_address[--i] = 1; } } /* search first non-zero entry that is not part of an address */ for (j = 0; (j < 256) && (trace_buffer[j] == 0) && (!is_address[j]); j++) ; if (j == 256) { LOG_DEBUG("no trace data collected"); return ERROR_XSCALE_NO_TRACE_DATA; } /* account for possible partial address at buffer start (wrap mode only) */ if (is_address[0]) { /* first entry is address; complete set of 4? */ i = 1; while (i < 4) if (!is_address[i++]) break; if (i < 4) j += i; /* partial address; can't use it */ } /* if first valid entry is indirect branch, can't use that either (no address) */ if (((trace_buffer[j] & 0xf0) == 0x90) || ((trace_buffer[j] & 0xf0) == 0xd0)) j++; /* walk linked list to terminating entry */ for (trace_data_p = &xscale->trace.data; *trace_data_p; trace_data_p = &(*trace_data_p)->next) ; *trace_data_p = malloc(sizeof(struct xscale_trace_data)); (*trace_data_p)->next = NULL; (*trace_data_p)->chkpt0 = trace_buffer[256]; (*trace_data_p)->chkpt1 = trace_buffer[257]; (*trace_data_p)->last_instruction = buf_get_u32(arm->pc->value, 0, 32); (*trace_data_p)->entries = malloc(sizeof(struct xscale_trace_entry) * (256 - j)); (*trace_data_p)->depth = 256 - j; (*trace_data_p)->num_checkpoints = num_checkpoints; for (i = j; i < 256; i++) { (*trace_data_p)->entries[i - j].data = trace_buffer[i]; if (is_address[i]) (*trace_data_p)->entries[i - j].type = XSCALE_TRACE_ADDRESS; else (*trace_data_p)->entries[i - j].type = XSCALE_TRACE_MESSAGE; } return ERROR_OK; } static int xscale_read_instruction(struct target *target, uint32_t pc, struct arm_instruction *instruction) { struct xscale_common *const xscale = target_to_xscale(target); int i; int section = -1; size_t size_read; uint32_t opcode; int retval; if (!xscale->trace.image) return ERROR_TRACE_IMAGE_UNAVAILABLE; /* search for the section the current instruction belongs to */ for (i = 0; i < xscale->trace.image->num_sections; i++) { if ((xscale->trace.image->sections[i].base_address <= pc) && (xscale->trace.image->sections[i].base_address + xscale->trace.image->sections[i].size > pc)) { section = i; break; } } if (section == -1) { /* current instruction couldn't be found in the image */ return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; } if (xscale->trace.core_state == ARM_STATE_ARM) { uint8_t buf[4]; retval = image_read_section(xscale->trace.image, section, pc - xscale->trace.image->sections[section].base_address, 4, buf, &size_read); if (retval != ERROR_OK) { LOG_ERROR("error while reading instruction"); return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; } opcode = target_buffer_get_u32(target, buf); arm_evaluate_opcode(opcode, pc, instruction); } else if (xscale->trace.core_state == ARM_STATE_THUMB) { uint8_t buf[2]; retval = image_read_section(xscale->trace.image, section, pc - xscale->trace.image->sections[section].base_address, 2, buf, &size_read); if (retval != ERROR_OK) { LOG_ERROR("error while reading instruction"); return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; } opcode = target_buffer_get_u16(target, buf); thumb_evaluate_opcode(opcode, pc, instruction); } else { LOG_ERROR("BUG: unknown core state encountered"); exit(-1); } return ERROR_OK; } /* Extract address encoded into trace data. * Write result to address referenced by argument 'target', or 0 if incomplete. */ static inline void xscale_branch_address(struct xscale_trace_data *trace_data, int i, uint32_t *target) { /* if there are less than four entries prior to the indirect branch message * we can't extract the address */ if (i < 4) *target = 0; else { *target = (trace_data->entries[i-1].data) | (trace_data->entries[i-2].data << 8) | (trace_data->entries[i-3].data << 16) | (trace_data->entries[i-4].data << 24); } } static inline void xscale_display_instruction(struct target *target, uint32_t pc, struct arm_instruction *instruction, struct command_context *cmd_ctx) { int retval = xscale_read_instruction(target, pc, instruction); if (retval == ERROR_OK) command_print(cmd_ctx, "%s", instruction->text); else command_print(cmd_ctx, "0x%8.8" PRIx32 "\t", pc); } static int xscale_analyze_trace(struct target *target, struct command_context *cmd_ctx) { struct xscale_common *xscale = target_to_xscale(target); struct xscale_trace_data *trace_data = xscale->trace.data; int i, retval; uint32_t breakpoint_pc; struct arm_instruction instruction; uint32_t current_pc = 0;/* initialized when address determined */ if (!xscale->trace.image) LOG_WARNING("No trace image loaded; use 'xscale trace_image'"); /* loop for each trace buffer that was loaded from target */ while (trace_data) { int chkpt = 0; /* incremented as checkpointed entries found */ int j; /* FIXME: set this to correct mode when trace buffer is first enabled */ xscale->trace.core_state = ARM_STATE_ARM; /* loop for each entry in this trace buffer */ for (i = 0; i < trace_data->depth; i++) { int exception = 0; uint32_t chkpt_reg = 0x0; uint32_t branch_target = 0; int count; /* trace entry type is upper nybble of 'message byte' */ int trace_msg_type = (trace_data->entries[i].data & 0xf0) >> 4; /* Target addresses of indirect branches are written into buffer * before the message byte representing the branch. Skip past it */ if (trace_data->entries[i].type == XSCALE_TRACE_ADDRESS) continue; switch (trace_msg_type) { case 0: /* Exceptions */ case 1: case 2: case 3: case 4: case 5: case 6: case 7: exception = (trace_data->entries[i].data & 0x70) >> 4; /* FIXME: vector table may be at ffff0000 */ branch_target = (trace_data->entries[i].data & 0xf0) >> 2; break; case 8: /* Direct Branch */ break; case 9: /* Indirect Branch */ xscale_branch_address(trace_data, i, &branch_target); break; case 13: /* Checkpointed Indirect Branch */ xscale_branch_address(trace_data, i, &branch_target); if ((trace_data->num_checkpoints == 2) && (chkpt == 0)) chkpt_reg = trace_data->chkpt1; /* 2 chkpts, this is *oldest */ else chkpt_reg = trace_data->chkpt0; /* 1 chkpt, or 2 and *newest */ chkpt++; break; case 12: /* Checkpointed Direct Branch */ if ((trace_data->num_checkpoints == 2) && (chkpt == 0)) chkpt_reg = trace_data->chkpt1; /* 2 chkpts, this is *oldest */ else chkpt_reg = trace_data->chkpt0; /* 1 chkpt, or 2 and *newest */ /* if no current_pc, checkpoint will be starting point */ if (current_pc == 0) branch_target = chkpt_reg; chkpt++; break; case 15:/* Roll-over */ break; default:/* Reserved */ LOG_WARNING("trace is suspect: invalid trace message byte"); continue; } /* If we don't have the current_pc yet, but we did get the branch target * (either from the trace buffer on indirect branch, or from a checkpoint reg), * then we can start displaying instructions at the next iteration, with * branch_target as the starting point. */ if (current_pc == 0) { current_pc = branch_target; /* remains 0 unless branch_target *obtained */ continue; } /* We have current_pc. Read and display the instructions from the image. * First, display count instructions (lower nybble of message byte). */ count = trace_data->entries[i].data & 0x0f; for (j = 0; j < count; j++) { xscale_display_instruction(target, current_pc, &instruction, cmd_ctx); current_pc += xscale->trace.core_state == ARM_STATE_ARM ? 4 : 2; } /* An additional instruction is implicitly added to count for * rollover and some exceptions: undef, swi, prefetch abort. */ if ((trace_msg_type == 15) || (exception > 0 && exception < 4)) { xscale_display_instruction(target, current_pc, &instruction, cmd_ctx); current_pc += xscale->trace.core_state == ARM_STATE_ARM ? 4 : 2; } if (trace_msg_type == 15) /* rollover */ continue; if (exception) { command_print(cmd_ctx, "--- exception %i ---", exception); continue; } /* not exception or rollover; next instruction is a branch and is * not included in the count */ xscale_display_instruction(target, current_pc, &instruction, cmd_ctx); /* for direct branches, extract branch destination from instruction */ if ((trace_msg_type == 8) || (trace_msg_type == 12)) { retval = xscale_read_instruction(target, current_pc, &instruction); if (retval == ERROR_OK) current_pc = instruction.info.b_bl_bx_blx.target_address; else current_pc = 0; /* branch destination unknown */ /* direct branch w/ checkpoint; can also get from checkpoint reg */ if (trace_msg_type == 12) { if (current_pc == 0) current_pc = chkpt_reg; else if (current_pc != chkpt_reg) /* sanity check */ LOG_WARNING("trace is suspect: checkpoint register " "inconsistent with adddress from image"); } if (current_pc == 0) command_print(cmd_ctx, "address unknown"); continue; } /* indirect branch; the branch destination was read from trace buffer */ if ((trace_msg_type == 9) || (trace_msg_type == 13)) { current_pc = branch_target; /* sanity check (checkpoint reg is redundant) */ if ((trace_msg_type == 13) && (chkpt_reg != branch_target)) LOG_WARNING("trace is suspect: checkpoint register " "inconsistent with address from trace buffer"); } } /* END: for (i = 0; i < trace_data->depth; i++) */ breakpoint_pc = trace_data->last_instruction; /* used below */ trace_data = trace_data->next; } /* END: while (trace_data) */ /* Finally... display all instructions up to the value of the pc when the * debug break occurred (saved when trace data was collected from target). * This is necessary because the trace only records execution branches and 16 * consecutive instructions (rollovers), so last few typically missed. */ if (current_pc == 0) return ERROR_OK;/* current_pc was never found */ /* how many instructions remaining? */ int gap_count = (breakpoint_pc - current_pc) / (xscale->trace.core_state == ARM_STATE_ARM ? 4 : 2); /* should never be negative or over 16, but verify */ if (gap_count < 0 || gap_count > 16) { LOG_WARNING("trace is suspect: excessive gap at end of trace"); return ERROR_OK;/* bail; large number or negative value no good */ } /* display remaining instructions */ for (i = 0; i < gap_count; i++) { xscale_display_instruction(target, current_pc, &instruction, cmd_ctx); current_pc += xscale->trace.core_state == ARM_STATE_ARM ? 4 : 2; } return ERROR_OK; } static const struct reg_arch_type xscale_reg_type = { .get = xscale_get_reg, .set = xscale_set_reg, }; static void xscale_build_reg_cache(struct target *target) { struct xscale_common *xscale = target_to_xscale(target); struct arm *arm = &xscale->arm; struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); struct xscale_reg *arch_info = malloc(sizeof(xscale_reg_arch_info)); int i; int num_regs = ARRAY_SIZE(xscale_reg_arch_info); (*cache_p) = arm_build_reg_cache(target, arm); (*cache_p)->next = malloc(sizeof(struct reg_cache)); cache_p = &(*cache_p)->next; /* fill in values for the xscale reg cache */ (*cache_p)->name = "XScale registers"; (*cache_p)->next = NULL; (*cache_p)->reg_list = malloc(num_regs * sizeof(struct reg)); (*cache_p)->num_regs = num_regs; for (i = 0; i < num_regs; i++) { (*cache_p)->reg_list[i].name = xscale_reg_list[i]; (*cache_p)->reg_list[i].value = calloc(4, 1); (*cache_p)->reg_list[i].dirty = 0; (*cache_p)->reg_list[i].valid = 0; (*cache_p)->reg_list[i].size = 32; (*cache_p)->reg_list[i].arch_info = &arch_info[i]; (*cache_p)->reg_list[i].type = &xscale_reg_type; arch_info[i] = xscale_reg_arch_info[i]; arch_info[i].target = target; } xscale->reg_cache = (*cache_p); } static int xscale_init_target(struct command_context *cmd_ctx, struct target *target) { xscale_build_reg_cache(target); return ERROR_OK; } static int xscale_init_arch_info(struct target *target, struct xscale_common *xscale, struct jtag_tap *tap, const char *variant) { struct arm *arm; uint32_t high_reset_branch, low_reset_branch; int i; arm = &xscale->arm; /* store architecture specfic data */ xscale->common_magic = XSCALE_COMMON_MAGIC; /* we don't really *need* a variant param ... */ if (variant) { int ir_length = 0; if (strcmp(variant, "pxa250") == 0 || strcmp(variant, "pxa255") == 0 || strcmp(variant, "pxa26x") == 0) ir_length = 5; else if (strcmp(variant, "pxa27x") == 0 || strcmp(variant, "ixp42x") == 0 || strcmp(variant, "ixp45x") == 0 || strcmp(variant, "ixp46x") == 0) ir_length = 7; else if (strcmp(variant, "pxa3xx") == 0) ir_length = 11; else LOG_WARNING("%s: unrecognized variant %s", tap->dotted_name, variant); if (ir_length && ir_length != tap->ir_length) { LOG_WARNING("%s: IR length for %s is %d; fixing", tap->dotted_name, variant, ir_length); tap->ir_length = ir_length; } } /* PXA3xx shifts the JTAG instructions */ if (tap->ir_length == 11) xscale->xscale_variant = XSCALE_PXA3XX; else xscale->xscale_variant = XSCALE_IXP4XX_PXA2XX; /* the debug handler isn't installed (and thus not running) at this time */ xscale->handler_address = 0xfe000800; /* clear the vectors we keep locally for reference */ memset(xscale->low_vectors, 0, sizeof(xscale->low_vectors)); memset(xscale->high_vectors, 0, sizeof(xscale->high_vectors)); /* no user-specified vectors have been configured yet */ xscale->static_low_vectors_set = 0x0; xscale->static_high_vectors_set = 0x0; /* calculate branches to debug handler */ low_reset_branch = (xscale->handler_address + 0x20 - 0x0 - 0x8) >> 2; high_reset_branch = (xscale->handler_address + 0x20 - 0xffff0000 - 0x8) >> 2; xscale->low_vectors[0] = ARMV4_5_B((low_reset_branch & 0xffffff), 0); xscale->high_vectors[0] = ARMV4_5_B((high_reset_branch & 0xffffff), 0); for (i = 1; i <= 7; i++) { xscale->low_vectors[i] = ARMV4_5_B(0xfffffe, 0); xscale->high_vectors[i] = ARMV4_5_B(0xfffffe, 0); } /* 64kB aligned region used for DCache cleaning */ xscale->cache_clean_address = 0xfffe0000; xscale->hold_rst = 0; xscale->external_debug_break = 0; xscale->ibcr_available = 2; xscale->ibcr0_used = 0; xscale->ibcr1_used = 0; xscale->dbr_available = 2; xscale->dbr0_used = 0; xscale->dbr1_used = 0; LOG_INFO("%s: hardware has 2 breakpoints and 2 watchpoints", target_name(target)); xscale->arm_bkpt = ARMV5_BKPT(0x0); xscale->thumb_bkpt = ARMV5_T_BKPT(0x0) & 0xffff; xscale->vector_catch = 0x1; xscale->trace.data = NULL; xscale->trace.image = NULL; xscale->trace.mode = XSCALE_TRACE_DISABLED; xscale->trace.buffer_fill = 0; xscale->trace.fill_counter = 0; /* prepare ARMv4/5 specific information */ arm->arch_info = xscale; arm->core_type = ARM_MODE_ANY; arm->read_core_reg = xscale_read_core_reg; arm->write_core_reg = xscale_write_core_reg; arm->full_context = xscale_full_context; arm_init_arch_info(target, arm); xscale->armv4_5_mmu.armv4_5_cache.ctype = -1; xscale->armv4_5_mmu.get_ttb = xscale_get_ttb; xscale->armv4_5_mmu.read_memory = xscale_read_memory; xscale->armv4_5_mmu.write_memory = xscale_write_memory; xscale->armv4_5_mmu.disable_mmu_caches = xscale_disable_mmu_caches; xscale->armv4_5_mmu.enable_mmu_caches = xscale_enable_mmu_caches; xscale->armv4_5_mmu.has_tiny_pages = 1; xscale->armv4_5_mmu.mmu_enabled = 0; return ERROR_OK; } static int xscale_target_create(struct target *target, Jim_Interp *interp) { struct xscale_common *xscale; if (sizeof xscale_debug_handler - 1 > 0x800) { LOG_ERROR("debug_handler.bin: larger than 2kb"); return ERROR_FAIL; } xscale = calloc(1, sizeof(*xscale)); if (!xscale) return ERROR_FAIL; return xscale_init_arch_info(target, xscale, target->tap, target->variant); } COMMAND_HANDLER(xscale_handle_debug_handler_command) { struct target *target = NULL; struct xscale_common *xscale; int retval; uint32_t handler_address; if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; target = get_target(CMD_ARGV[0]); if (target == NULL) { LOG_ERROR("target '%s' not defined", CMD_ARGV[0]); return ERROR_FAIL; } xscale = target_to_xscale(target); retval = xscale_verify_pointer(CMD_CTX, xscale); if (retval != ERROR_OK) return retval; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], handler_address); if (((handler_address >= 0x800) && (handler_address <= 0x1fef800)) || ((handler_address >= 0xfe000800) && (handler_address <= 0xfffff800))) xscale->handler_address = handler_address; else { LOG_ERROR( "xscale debug_handler
must be between 0x800 and 0x1fef800 or between 0xfe000800 and 0xfffff800"); return ERROR_FAIL; } return ERROR_OK; } COMMAND_HANDLER(xscale_handle_cache_clean_address_command) { struct target *target = NULL; struct xscale_common *xscale; int retval; uint32_t cache_clean_address; if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; target = get_target(CMD_ARGV[0]); if (target == NULL) { LOG_ERROR("target '%s' not defined", CMD_ARGV[0]); return ERROR_FAIL; } xscale = target_to_xscale(target); retval = xscale_verify_pointer(CMD_CTX, xscale); if (retval != ERROR_OK) return retval; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], cache_clean_address); if (cache_clean_address & 0xffff) LOG_ERROR("xscale cache_clean_address
must be 64kb aligned"); else xscale->cache_clean_address = cache_clean_address; return ERROR_OK; } COMMAND_HANDLER(xscale_handle_cache_info_command) { struct target *target = get_current_target(CMD_CTX); struct xscale_common *xscale = target_to_xscale(target); int retval; retval = xscale_verify_pointer(CMD_CTX, xscale); if (retval != ERROR_OK) return retval; return armv4_5_handle_cache_info_command(CMD_CTX, &xscale->armv4_5_mmu.armv4_5_cache); } static int xscale_virt2phys(struct target *target, uint32_t virtual, uint32_t *physical) { struct xscale_common *xscale = target_to_xscale(target); uint32_t cb; if (xscale->common_magic != XSCALE_COMMON_MAGIC) { LOG_ERROR(xscale_not); return ERROR_TARGET_INVALID; } uint32_t ret; int retval = armv4_5_mmu_translate_va(target, &xscale->armv4_5_mmu, virtual, &cb, &ret); if (retval != ERROR_OK) return retval; *physical = ret; return ERROR_OK; } static int xscale_mmu(struct target *target, int *enabled) { struct xscale_common *xscale = target_to_xscale(target); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_INVALID; } *enabled = xscale->armv4_5_mmu.mmu_enabled; return ERROR_OK; } COMMAND_HANDLER(xscale_handle_mmu_command) { struct target *target = get_current_target(CMD_CTX); struct xscale_common *xscale = target_to_xscale(target); int retval; retval = xscale_verify_pointer(CMD_CTX, xscale); if (retval != ERROR_OK) return retval; if (target->state != TARGET_HALTED) { command_print(CMD_CTX, "target must be stopped for \"%s\" command", CMD_NAME); return ERROR_OK; } if (CMD_ARGC >= 1) { bool enable; COMMAND_PARSE_ENABLE(CMD_ARGV[0], enable); if (enable) xscale_enable_mmu_caches(target, 1, 0, 0); else xscale_disable_mmu_caches(target, 1, 0, 0); xscale->armv4_5_mmu.mmu_enabled = enable; } command_print(CMD_CTX, "mmu %s", (xscale->armv4_5_mmu.mmu_enabled) ? "enabled" : "disabled"); return ERROR_OK; } COMMAND_HANDLER(xscale_handle_idcache_command) { struct target *target = get_current_target(CMD_CTX); struct xscale_common *xscale = target_to_xscale(target); int retval = xscale_verify_pointer(CMD_CTX, xscale); if (retval != ERROR_OK) return retval; if (target->state != TARGET_HALTED) { command_print(CMD_CTX, "target must be stopped for \"%s\" command", CMD_NAME); return ERROR_OK; } bool icache = false; if (strcmp(CMD_NAME, "icache") == 0) icache = true; if (CMD_ARGC >= 1) { bool enable; COMMAND_PARSE_ENABLE(CMD_ARGV[0], enable); if (icache) { xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled = enable; if (enable) xscale_enable_mmu_caches(target, 0, 0, 1); else xscale_disable_mmu_caches(target, 0, 0, 1); } else { xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = enable; if (enable) xscale_enable_mmu_caches(target, 0, 1, 0); else xscale_disable_mmu_caches(target, 0, 1, 0); } } bool enabled = icache ? xscale->armv4_5_mmu.armv4_5_cache.i_cache_enabled : xscale->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled; const char *msg = enabled ? "enabled" : "disabled"; command_print(CMD_CTX, "%s %s", CMD_NAME, msg); return ERROR_OK; } COMMAND_HANDLER(xscale_handle_vector_catch_command) { struct target *target = get_current_target(CMD_CTX); struct xscale_common *xscale = target_to_xscale(target); int retval; retval = xscale_verify_pointer(CMD_CTX, xscale); if (retval != ERROR_OK) return retval; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; else { COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], xscale->vector_catch); buf_set_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 16, 8, xscale->vector_catch); xscale_write_dcsr(target, -1, -1); } command_print(CMD_CTX, "vector catch mask: 0x%2.2x", xscale->vector_catch); return ERROR_OK; } COMMAND_HANDLER(xscale_handle_vector_table_command) { struct target *target = get_current_target(CMD_CTX); struct xscale_common *xscale = target_to_xscale(target); int err = 0; int retval; retval = xscale_verify_pointer(CMD_CTX, xscale); if (retval != ERROR_OK) return retval; if (CMD_ARGC == 0) { /* print current settings */ int idx; command_print(CMD_CTX, "active user-set static vectors:"); for (idx = 1; idx < 8; idx++) if (xscale->static_low_vectors_set & (1 << idx)) command_print(CMD_CTX, "low %d: 0x%" PRIx32, idx, xscale->static_low_vectors[idx]); for (idx = 1; idx < 8; idx++) if (xscale->static_high_vectors_set & (1 << idx)) command_print(CMD_CTX, "high %d: 0x%" PRIx32, idx, xscale->static_high_vectors[idx]); return ERROR_OK; } if (CMD_ARGC != 3) err = 1; else { int idx; COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], idx); uint32_t vec; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], vec); if (idx < 1 || idx >= 8) err = 1; if (!err && strcmp(CMD_ARGV[0], "low") == 0) { xscale->static_low_vectors_set |= (1<static_low_vectors[idx] = vec; } else if (!err && (strcmp(CMD_ARGV[0], "high") == 0)) { xscale->static_high_vectors_set |= (1<static_high_vectors[idx] = vec; } else err = 1; } if (err) return ERROR_COMMAND_SYNTAX_ERROR; return ERROR_OK; } COMMAND_HANDLER(xscale_handle_trace_buffer_command) { struct target *target = get_current_target(CMD_CTX); struct xscale_common *xscale = target_to_xscale(target); uint32_t dcsr_value; int retval; retval = xscale_verify_pointer(CMD_CTX, xscale); if (retval != ERROR_OK) return retval; if (target->state != TARGET_HALTED) { command_print(CMD_CTX, "target must be stopped for \"%s\" command", CMD_NAME); return ERROR_OK; } if (CMD_ARGC >= 1) { if (strcmp("enable", CMD_ARGV[0]) == 0) xscale->trace.mode = XSCALE_TRACE_WRAP; /* default */ else if (strcmp("disable", CMD_ARGV[0]) == 0) xscale->trace.mode = XSCALE_TRACE_DISABLED; else return ERROR_COMMAND_SYNTAX_ERROR; } if (CMD_ARGC >= 2 && xscale->trace.mode != XSCALE_TRACE_DISABLED) { if (strcmp("fill", CMD_ARGV[1]) == 0) { int buffcount = 1; /* default */ if (CMD_ARGC >= 3) COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], buffcount); if (buffcount < 1) { /* invalid */ command_print(CMD_CTX, "fill buffer count must be > 0"); xscale->trace.mode = XSCALE_TRACE_DISABLED; return ERROR_COMMAND_SYNTAX_ERROR; } xscale->trace.buffer_fill = buffcount; xscale->trace.mode = XSCALE_TRACE_FILL; } else if (strcmp("wrap", CMD_ARGV[1]) == 0) xscale->trace.mode = XSCALE_TRACE_WRAP; else { xscale->trace.mode = XSCALE_TRACE_DISABLED; return ERROR_COMMAND_SYNTAX_ERROR; } } if (xscale->trace.mode != XSCALE_TRACE_DISABLED) { char fill_string[12]; sprintf(fill_string, "fill %" PRId32, xscale->trace.buffer_fill); command_print(CMD_CTX, "trace buffer enabled (%s)", (xscale->trace.mode == XSCALE_TRACE_FILL) ? fill_string : "wrap"); } else command_print(CMD_CTX, "trace buffer disabled"); dcsr_value = buf_get_u32(xscale->reg_cache->reg_list[XSCALE_DCSR].value, 0, 32); if (xscale->trace.mode == XSCALE_TRACE_FILL) xscale_write_dcsr_sw(target, (dcsr_value & 0xfffffffc) | 2); else xscale_write_dcsr_sw(target, dcsr_value & 0xfffffffc); return ERROR_OK; } COMMAND_HANDLER(xscale_handle_trace_image_command) { struct target *target = get_current_target(CMD_CTX); struct xscale_common *xscale = target_to_xscale(target); int retval; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; retval = xscale_verify_pointer(CMD_CTX, xscale); if (retval != ERROR_OK) return retval; if (xscale->trace.image) { image_close(xscale->trace.image); free(xscale->trace.image); command_print(CMD_CTX, "previously loaded image found and closed"); } xscale->trace.image = malloc(sizeof(struct image)); xscale->trace.image->base_address_set = 0; xscale->trace.image->start_address_set = 0; /* a base address isn't always necessary, default to 0x0 (i.e. don't relocate) */ if (CMD_ARGC >= 2) { xscale->trace.image->base_address_set = 1; COMMAND_PARSE_NUMBER(llong, CMD_ARGV[1], xscale->trace.image->base_address); } else xscale->trace.image->base_address_set = 0; if (image_open(xscale->trace.image, CMD_ARGV[0], (CMD_ARGC >= 3) ? CMD_ARGV[2] : NULL) != ERROR_OK) { free(xscale->trace.image); xscale->trace.image = NULL; return ERROR_OK; } return ERROR_OK; } COMMAND_HANDLER(xscale_handle_dump_trace_command) { struct target *target = get_current_target(CMD_CTX); struct xscale_common *xscale = target_to_xscale(target); struct xscale_trace_data *trace_data; struct fileio file; int retval; retval = xscale_verify_pointer(CMD_CTX, xscale); if (retval != ERROR_OK) return retval; if (target->state != TARGET_HALTED) { command_print(CMD_CTX, "target must be stopped for \"%s\" command", CMD_NAME); return ERROR_OK; } if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; trace_data = xscale->trace.data; if (!trace_data) { command_print(CMD_CTX, "no trace data collected"); return ERROR_OK; } if (fileio_open(&file, CMD_ARGV[0], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK) return ERROR_OK; while (trace_data) { int i; fileio_write_u32(&file, trace_data->chkpt0); fileio_write_u32(&file, trace_data->chkpt1); fileio_write_u32(&file, trace_data->last_instruction); fileio_write_u32(&file, trace_data->depth); for (i = 0; i < trace_data->depth; i++) fileio_write_u32(&file, trace_data->entries[i].data | ((trace_data->entries[i].type & 0xffff) << 16)); trace_data = trace_data->next; } fileio_close(&file); return ERROR_OK; } COMMAND_HANDLER(xscale_handle_analyze_trace_buffer_command) { struct target *target = get_current_target(CMD_CTX); struct xscale_common *xscale = target_to_xscale(target); int retval; retval = xscale_verify_pointer(CMD_CTX, xscale); if (retval != ERROR_OK) return retval; xscale_analyze_trace(target, CMD_CTX); return ERROR_OK; } COMMAND_HANDLER(xscale_handle_cp15) { struct target *target = get_current_target(CMD_CTX); struct xscale_common *xscale = target_to_xscale(target); int retval; retval = xscale_verify_pointer(CMD_CTX, xscale); if (retval != ERROR_OK) return retval; if (target->state != TARGET_HALTED) { command_print(CMD_CTX, "target must be stopped for \"%s\" command", CMD_NAME); return ERROR_OK; } uint32_t reg_no = 0; struct reg *reg = NULL; if (CMD_ARGC > 0) { COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], reg_no); /*translate from xscale cp15 register no to openocd register*/ switch (reg_no) { case 0: reg_no = XSCALE_MAINID; break; case 1: reg_no = XSCALE_CTRL; break; case 2: reg_no = XSCALE_TTB; break; case 3: reg_no = XSCALE_DAC; break; case 5: reg_no = XSCALE_FSR; break; case 6: reg_no = XSCALE_FAR; break; case 13: reg_no = XSCALE_PID; break; case 15: reg_no = XSCALE_CPACCESS; break; default: command_print(CMD_CTX, "invalid register number"); return ERROR_COMMAND_SYNTAX_ERROR; } reg = &xscale->reg_cache->reg_list[reg_no]; } if (CMD_ARGC == 1) { uint32_t value; /* read cp15 control register */ xscale_get_reg(reg); value = buf_get_u32(reg->value, 0, 32); command_print(CMD_CTX, "%s (/%i): 0x%" PRIx32 "", reg->name, (int)(reg->size), value); } else if (CMD_ARGC == 2) { uint32_t value; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); /* send CP write request (command 0x41) */ xscale_send_u32(target, 0x41); /* send CP register number */ xscale_send_u32(target, reg_no); /* send CP register value */ xscale_send_u32(target, value); /* execute cpwait to ensure outstanding operations complete */ xscale_send_u32(target, 0x53); } else return ERROR_COMMAND_SYNTAX_ERROR; return ERROR_OK; } static const struct command_registration xscale_exec_command_handlers[] = { { .name = "cache_info", .handler = xscale_handle_cache_info_command, .mode = COMMAND_EXEC, .help = "display information about CPU caches", }, { .name = "mmu", .handler = xscale_handle_mmu_command, .mode = COMMAND_EXEC, .help = "enable or disable the MMU", .usage = "['enable'|'disable']", }, { .name = "icache", .handler = xscale_handle_idcache_command, .mode = COMMAND_EXEC, .help = "display ICache state, optionally enabling or " "disabling it", .usage = "['enable'|'disable']", }, { .name = "dcache", .handler = xscale_handle_idcache_command, .mode = COMMAND_EXEC, .help = "display DCache state, optionally enabling or " "disabling it", .usage = "['enable'|'disable']", }, { .name = "vector_catch", .handler = xscale_handle_vector_catch_command, .mode = COMMAND_EXEC, .help = "set or display 8-bit mask of vectors " "that should trigger debug entry", .usage = "[mask]", }, { .name = "vector_table", .handler = xscale_handle_vector_table_command, .mode = COMMAND_EXEC, .help = "set vector table entry in mini-ICache, " "or display current tables", .usage = "[('high'|'low') index code]", }, { .name = "trace_buffer", .handler = xscale_handle_trace_buffer_command, .mode = COMMAND_EXEC, .help = "display trace buffer status, enable or disable " "tracing, and optionally reconfigure trace mode", .usage = "['enable'|'disable' ['fill' [number]|'wrap']]", }, { .name = "dump_trace", .handler = xscale_handle_dump_trace_command, .mode = COMMAND_EXEC, .help = "dump content of trace buffer to file", .usage = "filename", }, { .name = "analyze_trace", .handler = xscale_handle_analyze_trace_buffer_command, .mode = COMMAND_EXEC, .help = "analyze content of trace buffer", .usage = "", }, { .name = "trace_image", .handler = xscale_handle_trace_image_command, .mode = COMMAND_EXEC, .help = "load image from file to address (default 0)", .usage = "filename [offset [filetype]]", }, { .name = "cp15", .handler = xscale_handle_cp15, .mode = COMMAND_EXEC, .help = "Read or write coprocessor 15 register.", .usage = "register [value]", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration xscale_any_command_handlers[] = { { .name = "debug_handler", .handler = xscale_handle_debug_handler_command, .mode = COMMAND_ANY, .help = "Change address used for debug handler.", .usage = "
", }, { .name = "cache_clean_address", .handler = xscale_handle_cache_clean_address_command, .mode = COMMAND_ANY, .help = "Change address used for cleaning data cache.", .usage = "address", }, { .chain = xscale_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; static const struct command_registration xscale_command_handlers[] = { { .chain = arm_command_handlers, }, { .name = "xscale", .mode = COMMAND_ANY, .help = "xscale command group", .usage = "", .chain = xscale_any_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct target_type xscale_target = { .name = "xscale", .poll = xscale_poll, .arch_state = xscale_arch_state, .target_request_data = NULL, .halt = xscale_halt, .resume = xscale_resume, .step = xscale_step, .assert_reset = xscale_assert_reset, .deassert_reset = xscale_deassert_reset, .soft_reset_halt = NULL, /* REVISIT on some cores, allow exporting iwmmxt registers ... */ .get_gdb_reg_list = arm_get_gdb_reg_list, .read_memory = xscale_read_memory, .read_phys_memory = xscale_read_phys_memory, .write_memory = xscale_write_memory, .write_phys_memory = xscale_write_phys_memory, .checksum_memory = arm_checksum_memory, .blank_check_memory = arm_blank_check_memory, .run_algorithm = armv4_5_run_algorithm, .add_breakpoint = xscale_add_breakpoint, .remove_breakpoint = xscale_remove_breakpoint, .add_watchpoint = xscale_add_watchpoint, .remove_watchpoint = xscale_remove_watchpoint, .commands = xscale_command_handlers, .target_create = xscale_target_create, .init_target = xscale_init_target, .virt2phys = xscale_virt2phys, .mmu = xscale_mmu }; openocd-0.7.0/src/target/smp.h0000644000175000001440000000321112134336410013101 00000000000000/*************************************************************************** * * * Copyright (C) ST-Ericsson SA 2011 * * Author: Michel Jaouen for ST-Ericsson. * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #include "server/server.h" int gdb_read_smp_packet(struct connection *connection, char *packet, int packet_size); int gdb_write_smp_packet(struct connection *connection, char *packet, int packet_size); openocd-0.7.0/src/target/arm.h0000644000175000001440000001547512137151331013100 00000000000000/* * Copyright (C) 2005 by Dominic Rath * Dominic.Rath@gmx.de * * Copyright (C) 2008 by Spencer Oliver * spen@spen-soft.co.uk * * Copyright (C) 2009 by Øyvind Harboe * oyvind.harboe@zylin.com * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 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. */ #ifndef ARM_H #define ARM_H #include #include "target.h" /** * @file * Holds the interface to ARM cores. * * At this writing, only "classic ARM" cores built on the ARMv4 register * and mode model are supported. The Thumb2-only microcontroller profile * support has not yet been integrated, affecting Cortex-M parts. */ /** * Represent state of an ARM core. * * Most numbers match the five low bits of the *PSR registers on * "classic ARM" processors, which build on the ARMv4 processor * modes and register set. * * ARM_MODE_ANY is a magic value, often used as a wildcard. * * Only the microcontroller cores (ARMv6-M, ARMv7-M) support ARM_MODE_THREAD, * ARM_MODE_USER_THREAD, and ARM_MODE_HANDLER. Those are the only modes * they support. */ enum arm_mode { ARM_MODE_USR = 16, ARM_MODE_FIQ = 17, ARM_MODE_IRQ = 18, ARM_MODE_SVC = 19, ARM_MODE_ABT = 23, ARM_MODE_MON = 26, ARM_MODE_UND = 27, ARM_MODE_SYS = 31, ARM_MODE_THREAD = 0, ARM_MODE_USER_THREAD = 1, ARM_MODE_HANDLER = 2, ARM_MODE_ANY = -1 }; const char *arm_mode_name(unsigned psr_mode); bool is_arm_mode(unsigned psr_mode); /** The PSR "T" and "J" bits define the mode of "classic ARM" cores. */ enum arm_state { ARM_STATE_ARM, ARM_STATE_THUMB, ARM_STATE_JAZELLE, ARM_STATE_THUMB_EE, }; #define ARM_COMMON_MAGIC 0x0A450A45 /** * Represents a generic ARM core, with standard application registers. * * There are sixteen application registers (including PC, SP, LR) and a PSR. * Cortex-M series cores do not support as many core states or shadowed * registers as traditional ARM cores, and only support Thumb2 instructions. */ struct arm { int common_magic; struct reg_cache *core_cache; /** Handle to the PC; valid in all core modes. */ struct reg *pc; /** Handle to the CPSR; valid in all core modes. */ struct reg *cpsr; /** Handle to the SPSR; valid only in core modes with an SPSR. */ struct reg *spsr; /** Support for arm_reg_current() */ const int *map; /** * Indicates what registers are in the ARM state core register set. * ARM_MODE_ANY indicates the standard set of 37 registers, * seen on for example ARM7TDMI cores. ARM_MODE_MON indicates three * more registers are shadowed, for "Secure Monitor" mode. * ARM_MODE_THREAD indicates a microcontroller profile core, * which only shadows SP. */ enum arm_mode core_type; /** Record the current core mode: SVC, USR, or some other mode. */ enum arm_mode core_mode; /** Record the current core state: ARM, Thumb, or otherwise. */ enum arm_state core_state; /** Flag reporting unavailability of the BKPT instruction. */ bool is_armv4; /** Flag reporting armv6m based core. */ bool is_armv6m; /** Flag reporting whether semihosting is active. */ bool is_semihosting; /** Value to be returned by semihosting SYS_ERRNO request. */ int semihosting_errno; int (*setup_semihosting)(struct target *target, int enable); /** Backpointer to the target. */ struct target *target; /** Handle for the debug module, if one is present. */ struct arm_dpm *dpm; /** Handle for the Embedded Trace Module, if one is present. */ struct etm_context *etm; /* FIXME all these methods should take "struct arm *" not target */ /** Retrieve all core registers, for display. */ int (*full_context)(struct target *target); /** Retrieve a single core register. */ int (*read_core_reg)(struct target *target, struct reg *reg, int num, enum arm_mode mode); int (*write_core_reg)(struct target *target, struct reg *reg, int num, enum arm_mode mode, uint32_t value); /** Read coprocessor register. */ int (*mrc)(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t *value); /** Write coprocessor register. */ int (*mcr)(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t value); void *arch_info; /** For targets conforming to ARM Debug Interface v5, * this handle references the Debug Access Port (DAP) * used to make requests to the target. */ struct adiv5_dap *dap; }; /** Convert target handle to generic ARM target state handle. */ static inline struct arm *target_to_arm(struct target *target) { assert(target != NULL); return target->arch_info; } static inline bool is_arm(struct arm *arm) { assert(arm != NULL); return arm->common_magic == ARM_COMMON_MAGIC; } struct arm_algorithm { int common_magic; enum arm_mode core_mode; enum arm_state core_state; }; struct arm_reg { int num; enum arm_mode mode; struct target *target; struct arm *arm; uint32_t value; }; struct reg_cache *arm_build_reg_cache(struct target *target, struct arm *arm); extern const struct command_registration arm_command_handlers[]; int arm_arch_state(struct target *target); int arm_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size); int arm_init_arch_info(struct target *target, struct arm *arm); /* REVISIT rename this once it's usable by ARMv7-M */ int armv4_5_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, uint32_t entry_point, uint32_t exit_point, int timeout_ms, void *arch_info); int armv4_5_run_algorithm_inner(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, uint32_t entry_point, uint32_t exit_point, int timeout_ms, void *arch_info, int (*run_it)(struct target *target, uint32_t exit_point, int timeout_ms, void *arch_info)); int arm_checksum_memory(struct target *target, uint32_t address, uint32_t count, uint32_t *checksum); int arm_blank_check_memory(struct target *target, uint32_t address, uint32_t count, uint32_t *blank); void arm_set_cpsr(struct arm *arm, uint32_t cpsr); struct reg *arm_reg_current(struct arm *arm, unsigned regnum); extern struct reg arm_gdb_dummy_fp_reg; extern struct reg arm_gdb_dummy_fps_reg; #endif /* ARM_H */ openocd-0.7.0/src/target/target_request.c0000644000175000001440000002047112134336410015342 00000000000000/*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "target.h" #include "target_request.h" #include "target_type.h" #include "trace.h" static bool got_message; bool target_got_message(void) { bool t = got_message; got_message = false; return t; } static int charmsg_mode; static int target_asciimsg(struct target *target, uint32_t length) { char *msg = malloc(DIV_ROUND_UP(length + 1, 4) * 4); struct debug_msg_receiver *c = target->dbgmsg; target->type->target_request_data(target, DIV_ROUND_UP(length, 4), (uint8_t *)msg); msg[length] = 0; LOG_DEBUG("%s", msg); while (c) { command_print(c->cmd_ctx, "%s", msg); c = c->next; } return ERROR_OK; } static int target_charmsg(struct target *target, uint8_t msg) { LOG_USER_N("%c", msg); return ERROR_OK; } static int target_hexmsg(struct target *target, int size, uint32_t length) { uint8_t *data = malloc(DIV_ROUND_UP(length * size, 4) * 4); char line[128]; int line_len; struct debug_msg_receiver *c = target->dbgmsg; uint32_t i; LOG_DEBUG("size: %i, length: %i", (int)size, (int)length); target->type->target_request_data(target, DIV_ROUND_UP(length * size, 4), (uint8_t *)data); line_len = 0; for (i = 0; i < length; i++) { switch (size) { case 4: line_len += snprintf(line + line_len, 128 - line_len, "%8.8" PRIx32 " ", le_to_h_u32(data + (4*i))); break; case 2: line_len += snprintf(line + line_len, 128 - line_len, "%4.4x ", le_to_h_u16(data + (2*i))); break; case 1: line_len += snprintf(line + line_len, 128 - line_len, "%2.2x ", data[i]); break; } if ((i%8 == 7) || (i == length - 1)) { LOG_DEBUG("%s", line); while (c) { command_print(c->cmd_ctx, "%s", line); c = c->next; } c = target->dbgmsg; line_len = 0; } } free(data); return ERROR_OK; } /* handle requests from the target received by a target specific * side-band channel (e.g. ARM7/9 DCC) */ int target_request(struct target *target, uint32_t request) { target_req_cmd_t target_req_cmd = request & 0xff; /* Record that we got a target message for back-off algorithm */ got_message = true; if (charmsg_mode) { target_charmsg(target, target_req_cmd); return ERROR_OK; } switch (target_req_cmd) { case TARGET_REQ_TRACEMSG: trace_point(target, (request & 0xffffff00) >> 8); break; case TARGET_REQ_DEBUGMSG: if (((request & 0xff00) >> 8) == 0) target_asciimsg(target, (request & 0xffff0000) >> 16); else target_hexmsg(target, (request & 0xff00) >> 8, (request & 0xffff0000) >> 16); break; case TARGET_REQ_DEBUGCHAR: target_charmsg(target, (request & 0x00ff0000) >> 16); break; /* case TARGET_REQ_SEMIHOSTING: * break; */ default: LOG_ERROR("unknown target request: %2.2x", target_req_cmd); break; } return ERROR_OK; } static int add_debug_msg_receiver(struct command_context *cmd_ctx, struct target *target) { struct debug_msg_receiver **p = &target->dbgmsg; if (target == NULL) return ERROR_COMMAND_SYNTAX_ERROR; /* see if there's already a list */ if (*p) { /* find end of linked list */ while ((*p)->next) p = &((*p)->next); p = &((*p)->next); } /* add new debug message receiver */ (*p) = malloc(sizeof(struct debug_msg_receiver)); (*p)->cmd_ctx = cmd_ctx; (*p)->next = NULL; /* enable callback */ target->dbg_msg_enabled = 1; return ERROR_OK; } static struct debug_msg_receiver *find_debug_msg_receiver(struct command_context *cmd_ctx, struct target *target) { int do_all_targets = 0; /* if no target has been specified search all of them */ if (target == NULL) { /* if no targets haven been specified */ if (all_targets == NULL) return NULL; target = all_targets; do_all_targets = 1; } /* so we target != null */ struct debug_msg_receiver **p = &target->dbgmsg; do { while (*p) { if ((*p)->cmd_ctx == cmd_ctx) return *p; p = &((*p)->next); } target = target->next; } while (target && do_all_targets); return NULL; } int delete_debug_msg_receiver(struct command_context *cmd_ctx, struct target *target) { struct debug_msg_receiver **p; struct debug_msg_receiver *c; int do_all_targets = 0; /* if no target has been specified search all of them */ if (target == NULL) { /* if no targets haven been specified */ if (all_targets == NULL) return ERROR_OK; target = all_targets; do_all_targets = 1; } do { p = &target->dbgmsg; c = *p; while (c) { struct debug_msg_receiver *next = c->next; if (c->cmd_ctx == cmd_ctx) { *p = next; free(c); if (*p == NULL) { /* disable callback */ target->dbg_msg_enabled = 0; } return ERROR_OK; } else p = &(c->next); c = next; } target = target->next; } while (target && do_all_targets); return ERROR_OK; } COMMAND_HANDLER(handle_target_request_debugmsgs_command) { struct target *target = get_current_target(CMD_CTX); int receiving = 0; /* see if reciever is already registered */ if (find_debug_msg_receiver(CMD_CTX, target) != NULL) receiving = 1; if (CMD_ARGC > 0) { if (!strcmp(CMD_ARGV[0], "enable") || !strcmp(CMD_ARGV[0], "charmsg")) { /* don't register if this command context is already receiving */ if (!receiving) { receiving = 1; add_debug_msg_receiver(CMD_CTX, target); } charmsg_mode = !strcmp(CMD_ARGV[0], "charmsg"); } else if (!strcmp(CMD_ARGV[0], "disable")) { /* no need to delete a receiver if none is registered */ if (receiving) { receiving = 0; delete_debug_msg_receiver(CMD_CTX, target); } } else return ERROR_COMMAND_SYNTAX_ERROR; } command_print(CMD_CTX, "receiving debug messages from current target %s", (receiving) ? (charmsg_mode ? "charmsg" : "enabled") : "disabled"); return ERROR_OK; } static const struct command_registration target_req_exec_command_handlers[] = { { .name = "debugmsgs", .handler = handle_target_request_debugmsgs_command, .mode = COMMAND_EXEC, .help = "display and/or modify reception of debug messages from target", .usage = "['enable'|'charmsg'|'disable']", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration target_req_command_handlers[] = { { .name = "target_request", .mode = COMMAND_ANY, .help = "target request command group", .usage = "", .chain = target_req_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; int target_request_register_commands(struct command_context *cmd_ctx) { return register_commands(cmd_ctx, NULL, target_req_command_handlers); } openocd-0.7.0/src/target/feroceon.c0000644000175000001440000006373712134336410014120 00000000000000/*************************************************************************** * Copyright (C) 2008-2009 by Marvell Semiconductors, Inc. * * Written by Nicolas Pitre * * * * Copyright (C) 2008 by Hongtao Zheng * * hontor@126.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /* * Marvell Feroceon/Dragonite support. * * The Feroceon core, as found in the Orion and Kirkwood SoCs amongst others, * mimics the ARM926 ICE interface with the following differences: * * - the MOE (method of entry) reporting is not implemented * * - breakpoint/watchpoint comparator #1 is seemingly not implemented * * - due to a different pipeline implementation, some injected debug * instruction sequences have to be somewhat different * * Other issues: * * - asserting DBGRQ doesn't work if target is looping on the undef vector * * - the EICE version signature in the COMMS_CTL reg is next to the flow bits * not at the top, and rather meaningless due to existing discrepencies * * - the DCC channel is half duplex (only one FIFO for both directions) with * seemingly no proper flow control. * * The Dragonite core is the non-mmu version based on the ARM966 model, and * it shares the above issues as well. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm926ejs.h" #include "arm966e.h" #include "target_type.h" #include "register.h" #include "arm_opcodes.h" static int feroceon_assert_reset(struct target *target) { struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; int ud = arm7_9->use_dbgrq; arm7_9->use_dbgrq = 0; if (target->reset_halt) arm7_9_halt(target); arm7_9->use_dbgrq = ud; return arm7_9_assert_reset(target); } static int feroceon_dummy_clock_out(struct arm_jtag *jtag_info, uint32_t instr) { struct scan_field fields[3]; uint8_t out_buf[4]; uint8_t instr_buf[4]; uint8_t sysspeed_buf = 0x0; int retval; /* prepare buffer */ buf_set_u32(out_buf, 0, 32, 0); buf_set_u32(instr_buf, 0, 32, flip_u32(instr, 32)); retval = arm_jtag_scann(jtag_info, 0x1, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 32; fields[0].out_value = out_buf; fields[0].in_value = NULL; fields[1].num_bits = 3; fields[1].out_value = &sysspeed_buf; fields[1].in_value = NULL; fields[2].num_bits = 32; fields[2].out_value = instr_buf; fields[2].in_value = NULL; jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_DRPAUSE); /* no jtag_add_runtest(0, TAP_DRPAUSE) here */ return ERROR_OK; } static void feroceon_change_to_arm(struct target *target, uint32_t *r0, uint32_t *pc) { struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* * save r0 before using it and put system in ARM state * to allow common handling of ARM and THUMB debugging */ feroceon_dummy_clock_out(jtag_info, ARMV4_5_T_NOP); feroceon_dummy_clock_out(jtag_info, ARMV4_5_T_NOP); feroceon_dummy_clock_out(jtag_info, ARMV4_5_T_NOP); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, r0, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_MOV(0, 15), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, pc, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_BX(15), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); jtag_execute_queue(); /* * fix program counter: * MOV R0, PC was the 7th instruction (+12) * reading PC in Thumb state gives address of instruction + 4 */ *pc -= (12 + 4); } static void feroceon_read_core_regs(struct target *target, uint32_t mask, uint32_t *core_regs[16]) { int i; struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; struct arm_jtag *jtag_info = &arm7_9->jtag_info; arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); for (i = 0; i <= 15; i++) if (mask & (1 << i)) arm9tdmi_clock_data_in(jtag_info, core_regs[i]); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); } static void feroceon_read_core_regs_target_buffer(struct target *target, uint32_t mask, void *buffer, int size) { int i; struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; struct arm_jtag *jtag_info = &arm7_9->jtag_info; int be = (target->endianness == TARGET_BIG_ENDIAN) ? 1 : 0; uint32_t *buf_u32 = buffer; uint16_t *buf_u16 = buffer; uint8_t *buf_u8 = buffer; arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); for (i = 0; i <= 15; i++) { if (mask & (1 << i)) { switch (size) { case 4: arm9tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be); break; case 2: arm9tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be); break; case 1: arm9tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be); break; } } } arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); } static void feroceon_read_xpsr(struct target *target, uint32_t *xpsr, int spsr) { struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; struct arm_jtag *jtag_info = &arm7_9->jtag_info; arm9tdmi_clock_out(jtag_info, ARMV4_5_MRS(0, spsr & 1), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, 1, 0, 0), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, xpsr, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); } static void feroceon_write_xpsr(struct target *target, uint32_t xpsr, int spsr) { struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; struct arm_jtag *jtag_info = &arm7_9->jtag_info; LOG_DEBUG("xpsr: %8.8" PRIx32 ", spsr: %i", xpsr, spsr); arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr & 0xff, 0, 1, spsr), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff00) >> 8, 0xc, 2, spsr), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff0000) >> 16, 0x8, 4, spsr), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff000000) >> 24, 0x4, 8, spsr), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); } static void feroceon_write_xpsr_im8(struct target *target, uint8_t xpsr_im, int rot, int spsr) { struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; struct arm_jtag *jtag_info = &arm7_9->jtag_info; LOG_DEBUG("xpsr_im: %2.2x, rot: %i, spsr: %i", xpsr_im, rot, spsr); arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr_im, rot, 1, spsr), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); } static void feroceon_write_core_regs(struct target *target, uint32_t mask, uint32_t core_regs[16]) { int i; struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; struct arm_jtag *jtag_info = &arm7_9->jtag_info; arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); for (i = 0; i <= 15; i++) if (mask & (1 << i)) arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, core_regs[i], NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); } static void feroceon_branch_resume(struct target *target) { struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; struct arm_jtag *jtag_info = &arm7_9->jtag_info; arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_B(0xfffff9, 0), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); arm7_9->need_bypass_before_restart = 1; } static void feroceon_branch_resume_thumb(struct target *target) { LOG_DEBUG("-"); struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; struct arm_jtag *jtag_info = &arm7_9->jtag_info; uint32_t r0 = buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32); uint32_t pc = buf_get_u32(arm->pc->value, 0, 32); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, 0xE28F0001, 0, NULL, 0); /* add r0,pc,#1 */ arm9tdmi_clock_out(jtag_info, ARMV4_5_BX(0), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_LDMIA(0, 0x1), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, r0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); pc = (pc & 2) >> 1; arm9tdmi_clock_out(jtag_info, ARMV4_5_T_B(0x7e9 + pc), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 1); arm7_9->need_bypass_before_restart = 1; } static int feroceon_read_cp15(struct target *target, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t *value) { struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; struct arm_jtag *jtag_info = &arm7_9->jtag_info; int err; arm9tdmi_clock_out(jtag_info, ARMV4_5_MRC(15, op1, 0, CRn, CRm, op2), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); err = arm7_9_execute_sys_speed(target); if (err != ERROR_OK) return err; arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, 1, 0, 0), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, value, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); return jtag_execute_queue(); } static int feroceon_write_cp15(struct target *target, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t value) { struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; struct arm_jtag *jtag_info = &arm7_9->jtag_info; arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 1, 0, 0), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, value, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_MCR(15, op1, 0, CRn, CRm, op2), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); return arm7_9_execute_sys_speed(target); } static void feroceon_set_dbgrq(struct target *target) { struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; struct reg *dbg_ctrl = &arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]; buf_set_u32(dbg_ctrl->value, 0, 8, 2); embeddedice_store_reg(dbg_ctrl); } static void feroceon_enable_single_step(struct target *target, uint32_t next_pc) { struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; /* set a breakpoint there */ embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_VALUE], next_pc); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK], 0); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK], 0xffffffff); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], 0x100); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK], 0xf7); } static void feroceon_disable_single_step(struct target *target) { struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_VALUE]); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK]); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK]); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK]); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE]); } static int feroceon_examine_debug_reason(struct target *target) { /* the MOE is not implemented */ if (target->debug_reason != DBG_REASON_SINGLESTEP) target->debug_reason = DBG_REASON_DBGRQ; return ERROR_OK; } static int feroceon_bulk_write_memory(struct target *target, uint32_t address, uint32_t count, const uint8_t *buffer) { int retval; struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; enum arm_state core_state = arm->core_state; uint32_t x, flip, shift, save[7]; uint32_t i; /* * We can't use the dcc flow control bits, so let's transfer data * with 31 bits and flip the MSB each time a new data word is sent. */ static uint32_t dcc_code[] = { 0xee115e10, /* 3: mrc p14, 0, r5, c1, c0, 0 */ 0xe3a0301e, /* 1: mov r3, #30 */ 0xe3a04002, /* mov r4, #2 */ 0xee111e10, /* 2: mrc p14, 0, r1, c1, c0, 0 */ 0xe1310005, /* teq r1, r5 */ 0x0afffffc, /* beq 1b */ 0xe1a05001, /* mov r5, r1 */ 0xe1a01081, /* mov r1, r1, lsl #1 */ 0xee112e10, /* 3: mrc p14, 0, r2, c1, c0, 0 */ 0xe1320005, /* teq r2, r5 */ 0x0afffffc, /* beq 3b */ 0xe1a05002, /* mov r5, r2 */ 0xe3c22102, /* bic r2, r2, #0x80000000 */ 0xe1811332, /* orr r1, r1, r2, lsr r3 */ 0xe2533001, /* subs r3, r3, #1 */ 0xe4801004, /* str r1, [r0], #4 */ 0xe1a01412, /* mov r1, r2, lsl r4 */ 0xe2844001, /* add r4, r4, #1 */ 0x4affffed, /* bmi 1b */ 0xeafffff3, /* b 3b */ }; uint32_t dcc_size = sizeof(dcc_code); if (!arm7_9->dcc_downloads) return target_write_memory(target, address, 4, count, buffer); /* regrab previously allocated working_area, or allocate a new one */ if (!arm7_9->dcc_working_area) { uint8_t dcc_code_buf[dcc_size]; /* make sure we have a working area */ if (target_alloc_working_area(target, dcc_size, &arm7_9->dcc_working_area) != ERROR_OK) { LOG_INFO("no working area available, falling back to memory writes"); return target_write_memory(target, address, 4, count, buffer); } /* copy target instructions to target endianness */ for (i = 0; i < dcc_size/4; i++) target_buffer_set_u32(target, dcc_code_buf + i*4, dcc_code[i]); /* write DCC code to working area */ retval = target_write_memory(target, arm7_9->dcc_working_area->address, 4, dcc_size/4, dcc_code_buf); if (retval != ERROR_OK) return retval; } /* backup clobbered processor state */ for (i = 0; i <= 5; i++) save[i] = buf_get_u32(arm->core_cache->reg_list[i].value, 0, 32); save[i] = buf_get_u32(arm->pc->value, 0, 32); /* set up target address in r0 */ buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, address); arm->core_cache->reg_list[0].valid = 1; arm->core_cache->reg_list[0].dirty = 1; arm->core_state = ARM_STATE_ARM; embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_COMMS_DATA], 0); arm7_9_resume(target, 0, arm7_9->dcc_working_area->address, 1, 1); /* send data over */ x = 0; flip = 0; shift = 1; for (i = 0; i < count; i++) { uint32_t y = target_buffer_get_u32(target, buffer); uint32_t z = (x >> 1) | (y >> shift) | (flip ^= 0x80000000); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_COMMS_DATA], z); x = y << (32 - shift); if (++shift >= 32 || i + 1 >= count) { z = (x >> 1) | (flip ^= 0x80000000); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_COMMS_DATA], z); x = 0; shift = 1; } buffer += 4; } retval = target_halt(target); if (retval == ERROR_OK) retval = target_wait_state(target, TARGET_HALTED, 500); if (retval == ERROR_OK) { uint32_t endaddress = buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32); if (endaddress != address + count*4) { LOG_ERROR("DCC write failed," " expected end address 0x%08" PRIx32 " got 0x%0" PRIx32 "", address + count*4, endaddress); retval = ERROR_FAIL; } } /* restore target state */ for (i = 0; i <= 5; i++) { buf_set_u32(arm->core_cache->reg_list[i].value, 0, 32, save[i]); arm->core_cache->reg_list[i].valid = 1; arm->core_cache->reg_list[i].dirty = 1; } buf_set_u32(arm->pc->value, 0, 32, save[i]); arm->pc->valid = 1; arm->pc->dirty = 1; arm->core_state = core_state; return retval; } static int feroceon_init_target(struct command_context *cmd_ctx, struct target *target) { arm9tdmi_init_target(cmd_ctx, target); return ERROR_OK; } static void feroceon_common_setup(struct target *target) { struct arm *arm = target->arch_info; struct arm7_9_common *arm7_9 = arm->arch_info; /* override some insn sequence functions */ arm7_9->change_to_arm = feroceon_change_to_arm; arm7_9->read_core_regs = feroceon_read_core_regs; arm7_9->read_core_regs_target_buffer = feroceon_read_core_regs_target_buffer; arm7_9->read_xpsr = feroceon_read_xpsr; arm7_9->write_xpsr = feroceon_write_xpsr; arm7_9->write_xpsr_im8 = feroceon_write_xpsr_im8; arm7_9->write_core_regs = feroceon_write_core_regs; arm7_9->branch_resume = feroceon_branch_resume; arm7_9->branch_resume_thumb = feroceon_branch_resume_thumb; /* must be implemented with only one comparator */ arm7_9->enable_single_step = feroceon_enable_single_step; arm7_9->disable_single_step = feroceon_disable_single_step; /* MOE is not implemented */ arm7_9->examine_debug_reason = feroceon_examine_debug_reason; /* Note: asserting DBGRQ might not win over the undef exception. If that happens then just use "arm7_9 dbgrq disable". */ arm7_9->use_dbgrq = 1; arm7_9->set_special_dbgrq = feroceon_set_dbgrq; /* only one working comparator */ arm7_9->wp_available_max = 1; arm7_9->wp1_used_default = -1; } static int feroceon_target_create(struct target *target, Jim_Interp *interp) { struct arm926ejs_common *arm926ejs = calloc(1, sizeof(struct arm926ejs_common)); arm926ejs_init_arch_info(target, arm926ejs, target->tap); feroceon_common_setup(target); /* the standard ARM926 methods don't always work (don't ask...) */ arm926ejs->read_cp15 = feroceon_read_cp15; arm926ejs->write_cp15 = feroceon_write_cp15; return ERROR_OK; } static int dragonite_target_create(struct target *target, Jim_Interp *interp) { struct arm966e_common *arm966e = calloc(1, sizeof(struct arm966e_common)); arm966e_init_arch_info(target, arm966e, target->tap); feroceon_common_setup(target); return ERROR_OK; } static int feroceon_examine(struct target *target) { struct arm *arm; struct arm7_9_common *arm7_9; int retval; retval = arm7_9_examine(target); if (retval != ERROR_OK) return retval; arm = target->arch_info; arm7_9 = arm->arch_info; /* the COMMS_CTRL bits are all contiguous */ if (buf_get_u32(arm7_9->eice_cache->reg_list[EICE_COMMS_CTRL].value, 2, 4) != 6) LOG_ERROR("unexpected Feroceon EICE version signature"); arm7_9->eice_cache->reg_list[EICE_DBG_CTRL].size = 6; arm7_9->eice_cache->reg_list[EICE_DBG_STAT].size = 5; arm7_9->has_monitor_mode = 1; /* vector catch reg is not initialized on reset */ embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_VEC_CATCH], 0); /* clear monitor mode, enable comparators */ embeddedice_read_reg(&arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]); jtag_execute_queue(); buf_set_u32(arm7_9->eice_cache->reg_list[EICE_DBG_CTRL].value, 4, 1, 0); buf_set_u32(arm7_9->eice_cache->reg_list[EICE_DBG_CTRL].value, 5, 1, 0); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]); return ERROR_OK; } struct target_type feroceon_target = { .name = "feroceon", .poll = arm7_9_poll, .arch_state = arm926ejs_arch_state, .target_request_data = arm7_9_target_request_data, .halt = arm7_9_halt, .resume = arm7_9_resume, .step = arm7_9_step, .assert_reset = feroceon_assert_reset, .deassert_reset = arm7_9_deassert_reset, .soft_reset_halt = arm926ejs_soft_reset_halt, .get_gdb_reg_list = arm_get_gdb_reg_list, .read_memory = arm7_9_read_memory, .write_memory = arm926ejs_write_memory, .bulk_write_memory = feroceon_bulk_write_memory, .checksum_memory = arm_checksum_memory, .blank_check_memory = arm_blank_check_memory, .run_algorithm = armv4_5_run_algorithm, .add_breakpoint = arm7_9_add_breakpoint, .remove_breakpoint = arm7_9_remove_breakpoint, .add_watchpoint = arm7_9_add_watchpoint, .remove_watchpoint = arm7_9_remove_watchpoint, .commands = arm926ejs_command_handlers, .target_create = feroceon_target_create, .init_target = feroceon_init_target, .examine = feroceon_examine, }; struct target_type dragonite_target = { .name = "dragonite", .poll = arm7_9_poll, .arch_state = arm_arch_state, .target_request_data = arm7_9_target_request_data, .halt = arm7_9_halt, .resume = arm7_9_resume, .step = arm7_9_step, .assert_reset = feroceon_assert_reset, .deassert_reset = arm7_9_deassert_reset, .soft_reset_halt = arm7_9_soft_reset_halt, .get_gdb_reg_list = arm_get_gdb_reg_list, .read_memory = arm7_9_read_memory, .write_memory = arm7_9_write_memory, .bulk_write_memory = feroceon_bulk_write_memory, .checksum_memory = arm_checksum_memory, .blank_check_memory = arm_blank_check_memory, .run_algorithm = armv4_5_run_algorithm, .add_breakpoint = arm7_9_add_breakpoint, .remove_breakpoint = arm7_9_remove_breakpoint, .add_watchpoint = arm7_9_add_watchpoint, .remove_watchpoint = arm7_9_remove_watchpoint, .commands = arm966e_command_handlers, .target_create = dragonite_target_create, .init_target = feroceon_init_target, .examine = feroceon_examine, }; openocd-0.7.0/src/target/dsp5680xx.c0000644000175000001440000017524512137151331014007 00000000000000/*************************************************************************** * Copyright (C) 2011 by Rodrigo L. Rosa * * rodrigorosa.LG@gmail.com * * * * Based on dsp563xx_once.h written by Mathias Kuester * * mkdorg@users.sourceforge.net * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "target.h" #include "target_type.h" #include "dsp5680xx.h" struct dsp5680xx_common dsp5680xx_context; #define _E "DSP5680XX_ERROR:%d\nAt:%s:%d:%s" #define err_check(r, c, m) if (r != ERROR_OK) {LOG_ERROR(_E, c, __func__, __LINE__, m); return r; } #define err_check_propagate(retval) if (retval != ERROR_OK) return retval; #define DEBUG_MSG "Debug mode be enabled to read mem." #define DEBUG_FAIL { err_check(ERROR_FAIL, DSP5680XX_ERROR_NOT_IN_DEBUG, DEBUG_MSG) } #define CHECK_DBG if (!dsp5680xx_context.debug_mode_enabled) DEBUG_FAIL #define HALT_MSG "Target must be halted." #define HALT_FAIL { err_check(ERROR_FAIL, DSP5680XX_ERROR_TARGET_RUNNING, HALT_MSG) } #define CHECK_HALT(target) if (target->state != TARGET_HALTED) HALT_FAIL #define check_halt_and_debug(target) { CHECK_HALT(target); CHECK_DBG; } int dsp5680xx_execute_queue(void) { int retval; retval = jtag_execute_queue(); return retval; } /** * Reset state machine */ static int reset_jtag(void) { int retval; tap_state_t states[2]; const char *cp = "RESET"; states[0] = tap_state_by_name(cp); retval = jtag_add_statemove(states[0]); err_check_propagate(retval); retval = jtag_execute_queue(); err_check_propagate(retval); jtag_add_pathmove(0, states + 1); retval = jtag_execute_queue(); return retval; } static int dsp5680xx_drscan(struct target *target, uint8_t *d_in, uint8_t *d_out, int len) { /* -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- * *Inputs: * - d_in: This is the data that will be shifted into the JTAG DR reg. * - d_out: The data that will be shifted out of the JTAG DR reg will stored here * - len: Length of the data to be shifted to JTAG DR. * *Note: If d_out == NULL, discard incoming bits. * *-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- */ int retval = ERROR_OK; if (NULL == target->tap) { retval = ERROR_FAIL; err_check(retval, DSP5680XX_ERROR_JTAG_INVALID_TAP, "Invalid tap"); } if (len > 32) { retval = ERROR_FAIL; err_check(retval, DSP5680XX_ERROR_JTAG_DR_LEN_OVERFLOW, "dr_len overflow, maxium is 32"); } /* TODO what values of len are valid for jtag_add_plain_dr_scan? */ /* can i send as many bits as i want? */ /* is the casting necessary? */ jtag_add_plain_dr_scan(len, d_in, d_out, TAP_IDLE); if (dsp5680xx_context.flush) { retval = dsp5680xx_execute_queue(); err_check(retval, DSP5680XX_ERROR_JTAG_DRSCAN, "drscan failed!"); } if (d_out != NULL) LOG_DEBUG("Data read (%d bits): 0x%04X", len, *d_out); else LOG_DEBUG("Data read was discarded."); return retval; } /** * Test func * * @param target * @param d_in This is the data that will be shifted into the JTAG IR reg. * @param d_out The data that will be shifted out of the JTAG IR reg will be stored here. * @apram ir_len Length of the data to be shifted to JTAG IR. * */ static int dsp5680xx_irscan(struct target *target, uint32_t *d_in, uint32_t *d_out, uint8_t ir_len) { int retval = ERROR_OK; uint16_t tap_ir_len = DSP5680XX_JTAG_MASTER_TAP_IRLEN; if (NULL == target->tap) { retval = ERROR_FAIL; err_check(retval, DSP5680XX_ERROR_JTAG_INVALID_TAP, "Invalid tap"); } if (ir_len != target->tap->ir_length) { if (target->tap->enabled) { retval = ERROR_FAIL; err_check(retval, DSP5680XX_ERROR_INVALID_IR_LEN, "Invalid irlen"); } else { struct jtag_tap *t = jtag_tap_by_string("dsp568013.chp"); if ((t == NULL) || ((t->enabled) && (ir_len != tap_ir_len))) { retval = ERROR_FAIL; err_check(retval, DSP5680XX_ERROR_INVALID_IR_LEN, "Invalid irlen"); } } } jtag_add_plain_ir_scan(ir_len, (uint8_t *) d_in, (uint8_t *) d_out, TAP_IDLE); if (dsp5680xx_context.flush) { retval = dsp5680xx_execute_queue(); err_check(retval, DSP5680XX_ERROR_JTAG_IRSCAN, "irscan failed!"); } return retval; } static int dsp5680xx_jtag_status(struct target *target, uint8_t *status) { uint32_t read_from_ir; uint32_t instr; int retval; instr = JTAG_INSTR_ENABLE_ONCE; retval = dsp5680xx_irscan(target, &instr, &read_from_ir, DSP5680XX_JTAG_CORE_TAP_IRLEN); err_check_propagate(retval); if (status != NULL) *status = (uint8_t) read_from_ir; return ERROR_OK; } static int jtag_data_read(struct target *target, uint8_t *data_read, int num_bits) { uint32_t bogus_instr = 0; int retval = dsp5680xx_drscan(target, (uint8_t *) &bogus_instr, data_read, num_bits); LOG_DEBUG("Data read (%d bits): 0x%04X", num_bits, *data_read); /** TODO remove this or move to jtagio? */ return retval; } #define jtag_data_read8(target, data_read) jtag_data_read(target, data_read, 8) #define jtag_data_read16(target, data_read) jtag_data_read(target, data_read, 16) #define jtag_data_read32(target, data_read) jtag_data_read(target, data_read, 32) static uint32_t data_read_dummy; static int jtag_data_write(struct target *target, uint32_t instr, int num_bits, uint32_t *data_read) { int retval; retval = dsp5680xx_drscan(target, (uint8_t *) &instr, (uint8_t *) &data_read_dummy, num_bits); err_check_propagate(retval); if (data_read != NULL) *data_read = data_read_dummy; return retval; } #define jtag_data_write8(target, instr, data_read) jtag_data_write(target, instr, 8, data_read) #define jtag_data_write16(target, instr, data_read) jtag_data_write(target, instr, 16, data_read) #define jtag_data_write24(target, instr, data_read) jtag_data_write(target, instr, 24, data_read) #define jtag_data_write32(target, instr, data_read) jtag_data_write(target, instr, 32, data_read) /** * Executes EOnCE instruction. * * @param target * @param instr Instruction to execute. * @param rw * @param go * @param ex * @param eonce_status Value read from the EOnCE status register. * * @return */ static int eonce_instruction_exec_single(struct target *target, uint8_t instr, uint8_t rw, uint8_t go, uint8_t ex, uint8_t *eonce_status) { int retval; uint32_t dr_out_tmp; uint8_t instr_with_flags = instr | (rw << 7) | (go << 6) | (ex << 5); retval = jtag_data_write(target, instr_with_flags, 8, &dr_out_tmp); err_check_propagate(retval); if (eonce_status != NULL) *eonce_status = (uint8_t) dr_out_tmp; return retval; } /* wrappers for multi opcode instructions */ #define dsp5680xx_exe_1(target, oc1, oc2, oc3) dsp5680xx_exe1(target, oc1) #define dsp5680xx_exe_2(target, oc1, oc2, oc3) dsp5680xx_exe2(target, oc1, oc2) #define dsp5680xx_exe_3(target, oc1, oc2, oc3) dsp5680xx_exe3(target, oc1, oc2, oc3) #define dsp5680xx_exe_generic(t, words, oc1, oc2, oc3) dsp5680xx_exe_##words(t, oc1, oc2, oc3) /* Executes one word DSP instruction */ static int dsp5680xx_exe1(struct target *target, uint16_t opcode) { int retval; retval = eonce_instruction_exec_single(target, 0x04, 0, 1, 0, NULL); err_check_propagate(retval); retval = jtag_data_write16(target, opcode, NULL); err_check_propagate(retval); return retval; } /* Executes two word DSP instruction */ static int dsp5680xx_exe2(struct target *target, uint16_t opcode1, uint16_t opcode2) { int retval; retval = eonce_instruction_exec_single(target, 0x04, 0, 0, 0, NULL); err_check_propagate(retval); retval = jtag_data_write16(target, opcode1, NULL); err_check_propagate(retval); retval = eonce_instruction_exec_single(target, 0x04, 0, 1, 0, NULL); err_check_propagate(retval); retval = jtag_data_write16(target, opcode2, NULL); err_check_propagate(retval); return retval; } /* Executes three word DSP instruction */ static int dsp5680xx_exe3(struct target *target, uint16_t opcode1, uint16_t opcode2, uint16_t opcode3) { int retval; retval = eonce_instruction_exec_single(target, 0x04, 0, 0, 0, NULL); err_check_propagate(retval); retval = jtag_data_write16(target, opcode1, NULL); err_check_propagate(retval); retval = eonce_instruction_exec_single(target, 0x04, 0, 0, 0, NULL); err_check_propagate(retval); retval = jtag_data_write16(target, opcode2, NULL); err_check_propagate(retval); retval = eonce_instruction_exec_single(target, 0x04, 0, 1, 0, NULL); err_check_propagate(retval); retval = jtag_data_write16(target, opcode3, NULL); err_check_propagate(retval); return retval; } /* *--------------- Real-time data exchange --------------- * The EOnCE Transmit (OTX) and Receive (ORX) registers are data memory mapped, each with an upper * and lower 16 bit word. * Transmit and receive directions are defined from the core’s perspective. * The core writes to the Transmit register and reads the Receive register, and the host through * JTAG writes to the Receive register and reads the Transmit register. * Both registers have a combined data memory mapped OTXRXSR which provides indication when * each may be accessed. * ref: eonce_rev.1.0_0208081.pdf@36 */ /* writes data into upper ORx register of the target */ static int core_tx_upper_data(struct target *target, uint16_t data, uint32_t *eonce_status_low) { int retval; retval = eonce_instruction_exec_single(target, DSP5680XX_ONCE_ORX1, 0, 0, 0, NULL); err_check_propagate(retval); retval = jtag_data_write16(target, data, eonce_status_low); err_check_propagate(retval); return retval; } /* writes data into lower ORx register of the target */ #define CMD1 eonce_instruction_exec_single(target, DSP5680XX_ONCE_ORX, 0, 0, 0, NULL); #define CMD2 jtag_data_write16((t, data) #define core_tx_lower_data(t, data) PT1\ PT2 /** * * @param target * @param data_read: Returns the data read from the upper OTX register via JTAG. * @return: Returns an error code (see error code documentation) */ static int core_rx_upper_data(struct target *target, uint8_t *data_read) { int retval; retval = eonce_instruction_exec_single(target, DSP5680XX_ONCE_OTX1, 1, 0, 0, NULL); err_check_propagate(retval); retval = jtag_data_read16(target, data_read); err_check_propagate(retval); return retval; } /** * * @param target * @param data_read: Returns the data read from the lower OTX register via JTAG. * @return: Returns an error code (see error code documentation) */ static int core_rx_lower_data(struct target *target, uint8_t *data_read) { int retval; retval = eonce_instruction_exec_single(target, DSP5680XX_ONCE_OTX, 1, 0, 0, NULL); err_check_propagate(retval); retval = jtag_data_read16(target, data_read); err_check_propagate(retval); return retval; } /* *-- -- -- -- --- -- -- -- --- -- -- -- --- -- -- -- --- -- -- -- --- -- *-- -- -- -- --- -- -- -Core Instructions- -- -- -- --- -- -- -- --- -- *-- -- -- -- --- -- -- -- --- -- -- -- --- -- -- -- --- -- -- -- --- -- */ #define exe(a, b, c, d, e) dsp5680xx_exe_generic(a, b, c, d, e) /* move.l #value, r0 */ #define core_move_long_to_r0(target, value) exe(target, 3, 0xe418, value&0xffff, value>>16) /* move.l #value, n */ #define core_move_long_to_n(target, value) exe(target, 3, 0xe41e, value&0xffff, value>>16) /* move x:(r0), y0 */ #define core_move_at_r0_to_y0(target) exe(target, 1, 0xF514, 0, 0) /* move x:(r0), y1 */ #define core_move_at_r0_to_y1(target) exe(target, 1, 0xF714, 0, 0) /* move.l x:(r0), y */ #define core_move_long_at_r0_y(target) exe(target, 1, 0xF734, 0, 0) /* move y0, x:(r0) */ #define core_move_y0_at_r0(target) exe(target, 1, 0xd514, 0, 0) /* bfclr #value, x:(r0) */ #define eonce_bfclr_at_r0(target, value) exe(target, 2, 0x8040, value, 0) /* move #value, y0 */ #define core_move_value_to_y0(target, value) exe(target, 2, 0x8745, value, 0) /* move.w y0, x:(r0)+ */ #define core_move_y0_at_r0_inc(target) exe(target, 1, 0xd500, 0, 0) /* move.w y0, p:(r0)+ */ #define core_move_y0_at_pr0_inc(target) exe(target, 1, 0x8560, 0, 0) /* move.w p:(r0)+, y0 */ #define core_move_at_pr0_inc_to_y0(target) exe(target, 1, 0x8568, 0, 0) /* move.w p:(r0)+, y1 */ #define core_move_at_pr0_inc_to_y1(target) exe(target, 1, 0x8768, 0, 0) /* move.l #value, r2 */ #define core_move_long_to_r2(target, value) exe(target, 3, 0xe41A, value&0xffff, value>>16) /* move y0, x:(r2) */ #define core_move_y0_at_r2(target) exe(target, 1, 0xd516, 0, 0) /* move.w #, x:(r2) */ #define core_move_value_at_r2(target, value) exe(target, 2, 0x8642, value, 0) /* move.w #, x:(r0) */ #define core_move_value_at_r0(target, value) exe(target, 2, 0x8640, value, 0) /* move.w #, x:(R2+) */ #define core_move_value_at_r2_disp(target, value, disp) exe(target, 3, 0x8646, value, disp) /* move.w x:(r2), Y0 */ #define core_move_at_r2_to_y0(target) exe(target, 1, 0xF516, 0, 0) /* move.w p:(r2)+, y0 */ #define core_move_at_pr2_inc_to_y0(target) exe(target, 1, 0x856A, 0, 0) /* move.l #value, r3 */ #define core_move_long_to_r1(target, value) exe(target, 3, 0xE419, value&0xffff, value>>16) /* move.l #value, r3 */ #define core_move_long_to_r3(target, value) exe(target, 3, 0xE41B, value&0xffff, value>>16) /* move.w y0, p:(r3)+ */ #define core_move_y0_at_pr3_inc(target) exe(target, 1, 0x8563, 0, 0) /* move.w y0, x:(r3) */ #define core_move_y0_at_r3(target) exe(target, 1, 0xD503, 0, 0) /* move.l #value, r4 */ #define core_move_long_to_r4(target, value) exe(target, 3, 0xE41C, value&0xffff, value>>16) /* move pc, r4 */ #define core_move_pc_to_r4(target) exe(target, 1, 0xE716, 0, 0) /* move.l r4, y */ #define core_move_r4_to_y(target) exe(target, 1, 0xe764, 0, 0) /* move.w p:(r0)+, y0 */ #define core_move_at_pr0_inc_to_y0(target) exe(target, 1, 0x8568, 0, 0) /* move.w x:(r0)+, y0 */ #define core_move_at_r0_inc_to_y0(target) exe(target, 1, 0xf500, 0, 0) /* move x:(r0), y0 */ #define core_move_at_r0_y0(target) exe(target, 1, 0xF514, 0, 0) /* nop */ #define eonce_nop(target) exe(target, 1, 0xe700, 0, 0) /* move.w x:(R2+), Y0 */ #define core_move_at_r2_disp_to_y0(target, disp) exe(target, 2, 0xF542, disp, 0) /* move.w y1, x:(r2) */ #define core_move_y1_at_r2(target) exe(target, 1, 0xd716, 0, 0) /* move.w y1, x:(r0) */ #define core_move_y1_at_r0(target) exe(target, 1, 0xd714, 0, 0) /* move.bp y0, x:(r0)+ */ #define core_move_byte_y0_at_r0(target) exe(target, 1, 0xd5a0, 0, 0) /* move.w y1, p:(r0)+ */ #define core_move_y1_at_pr0_inc(target) exe(target, 1, 0x8760, 0, 0) /* move.w y1, x:(r0)+ */ #define core_move_y1_at_r0_inc(target) exe(target, 1, 0xD700, 0, 0) /* move.l #value, y */ #define core_move_long_to_y(target, value) exe(target, 3, 0xe417, value&0xffff, value>>16) static int core_move_value_to_pc(struct target *target, uint32_t value) { check_halt_and_debug(target); int retval; retval = dsp5680xx_exe_generic(target, 3, 0xE71E, value & 0xffff, value >> 16); err_check_propagate(retval); return retval; } static int eonce_load_TX_RX_to_r0(struct target *target) { int retval; retval = core_move_long_to_r0(target, ((MC568013_EONCE_TX_RX_ADDR) + (MC568013_EONCE_OBASE_ADDR << 16))); return retval; } static int core_load_TX_RX_high_addr_to_r0(struct target *target) { int retval = 0; retval = core_move_long_to_r0(target, ((MC568013_EONCE_TX1_RX1_HIGH_ADDR) + (MC568013_EONCE_OBASE_ADDR << 16))); return retval; } static int dsp5680xx_read_core_reg(struct target *target, uint8_t reg_addr, uint16_t *data_read) { /* TODO implement a general version of this which matches what openocd uses. */ int retval; uint32_t dummy_data_to_shift_into_dr; retval = eonce_instruction_exec_single(target, reg_addr, 1, 0, 0, NULL); err_check_propagate(retval); retval = dsp5680xx_drscan(target, (uint8_t *) &dummy_data_to_shift_into_dr, (uint8_t *) data_read, 8); err_check_propagate(retval); LOG_DEBUG("Reg. data: 0x%02X.", *data_read); return retval; } static int eonce_read_status_reg(struct target *target, uint16_t *data) { int retval; retval = dsp5680xx_read_core_reg(target, DSP5680XX_ONCE_OSR, data); err_check_propagate(retval); return retval; } /** * Takes the core out of debug mode. * * @param target * @param eonce_status Data read from the EOnCE status register. * * @return */ static int eonce_exit_debug_mode(struct target *target, uint8_t *eonce_status) { int retval; retval = eonce_instruction_exec_single(target, 0x1F, 0, 0, 1, eonce_status); err_check_propagate(retval); return retval; } static int switch_tap(struct target *target, struct jtag_tap *master_tap, struct jtag_tap *core_tap) { int retval = ERROR_OK; uint32_t instr; uint32_t ir_out; /* not used, just to make jtag happy. */ if (master_tap == NULL) { master_tap = jtag_tap_by_string("dsp568013.chp"); if (master_tap == NULL) { retval = ERROR_FAIL; const char *msg = "Failed to get master tap."; err_check(retval, DSP5680XX_ERROR_JTAG_TAP_FIND_MASTER, msg); } } if (core_tap == NULL) { core_tap = jtag_tap_by_string("dsp568013.cpu"); if (core_tap == NULL) { retval = ERROR_FAIL; err_check(retval, DSP5680XX_ERROR_JTAG_TAP_FIND_CORE, "Failed to get core tap."); } } if (!(((int)master_tap->enabled) ^ ((int)core_tap->enabled))) { LOG_WARNING ("Master:%d\nCore:%d\nOnly 1 should be enabled.\n", (int)master_tap->enabled, (int)core_tap->enabled); } if (master_tap->enabled) { instr = 0x5; retval = dsp5680xx_irscan(target, &instr, &ir_out, DSP5680XX_JTAG_MASTER_TAP_IRLEN); err_check_propagate(retval); instr = 0x2; retval = dsp5680xx_drscan(target, (uint8_t *) &instr, (uint8_t *) &ir_out, 4); err_check_propagate(retval); core_tap->enabled = true; master_tap->enabled = false; } else { instr = 0x08; retval = dsp5680xx_irscan(target, &instr, &ir_out, DSP5680XX_JTAG_CORE_TAP_IRLEN); err_check_propagate(retval); instr = 0x1; retval = dsp5680xx_drscan(target, (uint8_t *) &instr, (uint8_t *) &ir_out, 4); err_check_propagate(retval); core_tap->enabled = false; master_tap->enabled = true; } return retval; } /** * Puts the core into debug mode, enabling the EOnCE module. * This will not always work, eonce_enter_debug_mode executes much * more complicated routine, which is guaranteed to work, but requires * a reset. This will complicate comm with the flash module, since * after a reset clock divisors must be set again. * This implementation works most of the time, and is not accesible to the * user. * * @param target * @param eonce_status Data read from the EOnCE status register. * * @return */ static int eonce_enter_debug_mode_without_reset(struct target *target, uint16_t *eonce_status) { int retval; uint32_t instr = JTAG_INSTR_DEBUG_REQUEST; uint32_t ir_out; /* not used, just to make jtag happy.*/ /* Debug request #1 */ retval = dsp5680xx_irscan(target, &instr, &ir_out, DSP5680XX_JTAG_CORE_TAP_IRLEN); err_check_propagate(retval); /* Enable EOnCE module */ instr = JTAG_INSTR_ENABLE_ONCE; /* Two rounds of jtag 0x6 (enable eonce) to enable EOnCE. */ retval = dsp5680xx_irscan(target, &instr, &ir_out, DSP5680XX_JTAG_CORE_TAP_IRLEN); err_check_propagate(retval); retval = dsp5680xx_irscan(target, &instr, &ir_out, DSP5680XX_JTAG_CORE_TAP_IRLEN); err_check_propagate(retval); if ((ir_out & JTAG_STATUS_MASK) == JTAG_STATUS_DEBUG) target->state = TARGET_HALTED; else { retval = ERROR_FAIL; err_check_propagate(retval); } /* Verify that debug mode is enabled */ uint16_t data_read_from_dr; retval = eonce_read_status_reg(target, &data_read_from_dr); err_check_propagate(retval); if ((data_read_from_dr & 0x30) == 0x30) { LOG_DEBUG("EOnCE successfully entered debug mode."); dsp5680xx_context.debug_mode_enabled = true; retval = ERROR_OK; } else { dsp5680xx_context.debug_mode_enabled = false; retval = ERROR_TARGET_FAILURE; /** *No error msg here, since there is still hope with full halting sequence */ err_check_propagate(retval); } if (eonce_status != NULL) *eonce_status = data_read_from_dr; return retval; } /** * Puts the core into debug mode, enabling the EOnCE module. * * @param target * @param eonce_status Data read from the EOnCE status register. * * @return */ static int eonce_enter_debug_mode(struct target *target, uint16_t *eonce_status) { int retval = ERROR_OK; uint32_t instr = JTAG_INSTR_DEBUG_REQUEST; uint32_t ir_out; /* not used, just to make jtag happy. */ uint16_t instr_16; uint16_t read_16; /* First try the easy way */ retval = eonce_enter_debug_mode_without_reset(target, eonce_status); if (retval == ERROR_OK) return retval; struct jtag_tap *tap_chp; struct jtag_tap *tap_cpu; tap_chp = jtag_tap_by_string("dsp568013.chp"); if (tap_chp == NULL) { retval = ERROR_FAIL; err_check(retval, DSP5680XX_ERROR_JTAG_TAP_FIND_MASTER, "Failed to get master tap."); } tap_cpu = jtag_tap_by_string("dsp568013.cpu"); if (tap_cpu == NULL) { retval = ERROR_FAIL; err_check(retval, DSP5680XX_ERROR_JTAG_TAP_FIND_CORE, "Failed to get master tap."); } /* Enable master tap */ tap_chp->enabled = true; tap_cpu->enabled = false; instr = MASTER_TAP_CMD_IDCODE; retval = dsp5680xx_irscan(target, &instr, &ir_out, DSP5680XX_JTAG_MASTER_TAP_IRLEN); err_check_propagate(retval); jtag_add_sleep(TIME_DIV_FREESCALE * 100 * 1000); /* Enable EOnCE module */ jtag_add_reset(0, 1); jtag_add_sleep(TIME_DIV_FREESCALE * 200 * 1000); instr = 0x0606ffff; /* This was selected experimentally. */ retval = dsp5680xx_drscan(target, (uint8_t *) &instr, (uint8_t *) &ir_out, 32); err_check_propagate(retval); /* ir_out now hold tap idcode */ /* Enable core tap */ tap_chp->enabled = true; retval = switch_tap(target, tap_chp, tap_cpu); err_check_propagate(retval); instr = JTAG_INSTR_ENABLE_ONCE; /* Two rounds of jtag 0x6 (enable eonce) to enable EOnCE. */ retval = dsp5680xx_irscan(target, &instr, &ir_out, DSP5680XX_JTAG_CORE_TAP_IRLEN); err_check_propagate(retval); instr = JTAG_INSTR_DEBUG_REQUEST; retval = dsp5680xx_irscan(target, &instr, &ir_out, DSP5680XX_JTAG_CORE_TAP_IRLEN); err_check_propagate(retval); instr_16 = 0x1; retval = dsp5680xx_drscan(target, (uint8_t *) &instr_16, (uint8_t *) &read_16, 8); err_check_propagate(retval); instr_16 = 0x20; retval = dsp5680xx_drscan(target, (uint8_t *) &instr_16, (uint8_t *) &read_16, 8); err_check_propagate(retval); jtag_add_sleep(TIME_DIV_FREESCALE * 100 * 1000); jtag_add_reset(0, 0); jtag_add_sleep(TIME_DIV_FREESCALE * 300 * 1000); instr = JTAG_INSTR_ENABLE_ONCE; /* Two rounds of jtag 0x6 (enable eonce) to enable EOnCE. */ for (int i = 0; i < 3; i++) { retval = dsp5680xx_irscan(target, &instr, &ir_out, DSP5680XX_JTAG_CORE_TAP_IRLEN); err_check_propagate(retval); } if ((ir_out & JTAG_STATUS_MASK) == JTAG_STATUS_DEBUG) target->state = TARGET_HALTED; else { retval = ERROR_FAIL; err_check(retval, DSP5680XX_ERROR_HALT, "Failed to halt target."); } for (int i = 0; i < 3; i++) { instr_16 = 0x86; dsp5680xx_drscan(target, (uint8_t *) &instr_16, (uint8_t *) &read_16, 16); instr_16 = 0xff; dsp5680xx_drscan(target, (uint8_t *) &instr_16, (uint8_t *) &read_16, 16); } /* Verify that debug mode is enabled */ uint16_t data_read_from_dr; retval = eonce_read_status_reg(target, &data_read_from_dr); err_check_propagate(retval); if ((data_read_from_dr & 0x30) == 0x30) { LOG_DEBUG("EOnCE successfully entered debug mode."); dsp5680xx_context.debug_mode_enabled = true; retval = ERROR_OK; } else { const char *msg = "Failed to set EOnCE module to debug mode"; retval = ERROR_TARGET_FAILURE; err_check(retval, DSP5680XX_ERROR_ENTER_DEBUG_MODE, msg); } if (eonce_status != NULL) *eonce_status = data_read_from_dr; return retval; } /** * Reads the current value of the program counter and stores it. * * @param target * * @return */ static int eonce_pc_store(struct target *target) { uint8_t tmp[2]; int retval; retval = core_move_pc_to_r4(target); err_check_propagate(retval); retval = core_move_r4_to_y(target); err_check_propagate(retval); retval = eonce_load_TX_RX_to_r0(target); err_check_propagate(retval); retval = core_move_y0_at_r0(target); err_check_propagate(retval); retval = core_rx_lower_data(target, tmp); err_check_propagate(retval); LOG_USER("PC value: 0x%X%X\n", tmp[1], tmp[0]); dsp5680xx_context.stored_pc = (tmp[0] | (tmp[1] << 8)); return ERROR_OK; } static int dsp5680xx_target_create(struct target *target, Jim_Interp *interp) { struct dsp5680xx_common *dsp5680xx = calloc(1, sizeof(struct dsp5680xx_common)); target->arch_info = dsp5680xx; return ERROR_OK; } static int dsp5680xx_init_target(struct command_context *cmd_ctx, struct target *target) { dsp5680xx_context.stored_pc = 0; dsp5680xx_context.flush = 1; dsp5680xx_context.debug_mode_enabled = false; LOG_DEBUG("target initiated!"); /* TODO core tap must be enabled before running these commands, currently * this is done in the .cfg tcl script. */ return ERROR_OK; } static int dsp5680xx_arch_state(struct target *target) { LOG_USER("%s not implemented yet.", __func__); return ERROR_OK; } int dsp5680xx_target_status(struct target *target, uint8_t *jtag_st, uint16_t *eonce_st) { return target->state; } static int dsp5680xx_assert_reset(struct target *target) { target->state = TARGET_RESET; return ERROR_OK; } static int dsp5680xx_deassert_reset(struct target *target) { target->state = TARGET_RUNNING; return ERROR_OK; } static int dsp5680xx_halt(struct target *target) { int retval; uint16_t eonce_status = 0xbeef; if ((target->state == TARGET_HALTED) && (dsp5680xx_context.debug_mode_enabled)) { LOG_USER("Target already halted and in debug mode."); return ERROR_OK; } else { if (target->state == TARGET_HALTED) LOG_USER ("Target already halted, re attempting to enter debug mode."); } retval = eonce_enter_debug_mode(target, &eonce_status); err_check_propagate(retval); retval = eonce_pc_store(target); err_check_propagate(retval); if (dsp5680xx_context.debug_mode_enabled) { retval = eonce_pc_store(target); err_check_propagate(retval); } return retval; } static int dsp5680xx_poll(struct target *target) { int retval; uint8_t jtag_status; uint8_t eonce_status; uint16_t read_tmp; retval = dsp5680xx_jtag_status(target, &jtag_status); err_check_propagate(retval); if (jtag_status == JTAG_STATUS_DEBUG) if (target->state != TARGET_HALTED) { retval = eonce_enter_debug_mode(target, &read_tmp); err_check_propagate(retval); eonce_status = (uint8_t) read_tmp; if ((eonce_status & EONCE_STAT_MASK) != DSP5680XX_ONCE_OSCR_DEBUG_M) { const char *msg = "%s: Failed to put EOnCE in debug mode.Flash locked?..."; LOG_WARNING(msg, __func__); return ERROR_TARGET_FAILURE; } else { target->state = TARGET_HALTED; return ERROR_OK; } } if (jtag_status == JTAG_STATUS_NORMAL) { if (target->state == TARGET_RESET) { retval = dsp5680xx_halt(target); err_check_propagate(retval); retval = eonce_exit_debug_mode(target, &eonce_status); err_check_propagate(retval); if ((eonce_status & EONCE_STAT_MASK) != DSP5680XX_ONCE_OSCR_NORMAL_M) { const char *msg = "%s: JTAG running, but EOnCE run failed.Try resetting.."; LOG_WARNING(msg, __func__); return ERROR_TARGET_FAILURE; } else { target->state = TARGET_RUNNING; return ERROR_OK; } } if (target->state != TARGET_RUNNING) { retval = eonce_read_status_reg(target, &read_tmp); err_check_propagate(retval); eonce_status = (uint8_t) read_tmp; if ((eonce_status & EONCE_STAT_MASK) != DSP5680XX_ONCE_OSCR_NORMAL_M) { LOG_WARNING ("Inconsistent target status. Restart!"); return ERROR_TARGET_FAILURE; } } target->state = TARGET_RUNNING; return ERROR_OK; } if (jtag_status == JTAG_STATUS_DEAD) { LOG_ERROR ("%s: Cannot communicate with JTAG. Check connection...", __func__); target->state = TARGET_UNKNOWN; return ERROR_TARGET_FAILURE; }; if (target->state == TARGET_UNKNOWN) { LOG_ERROR("%s: Target status invalid - communication failure", __func__); return ERROR_TARGET_FAILURE; }; return ERROR_OK; } static int dsp5680xx_resume(struct target *target, int current, uint32_t address, int hb, int d) { if (target->state == TARGET_RUNNING) { LOG_USER("Target already running."); return ERROR_OK; } int retval; uint8_t eonce_status; uint8_t jtag_status; if (dsp5680xx_context.debug_mode_enabled) { if (!current) { retval = core_move_value_to_pc(target, address); err_check_propagate(retval); } int retry = 20; while (retry-- > 1) { retval = eonce_exit_debug_mode(target, &eonce_status); err_check_propagate(retval); if (eonce_status == DSP5680XX_ONCE_OSCR_NORMAL_M) break; } if (retry == 0) { retval = ERROR_TARGET_FAILURE; err_check(retval, DSP5680XX_ERROR_EXIT_DEBUG_MODE, "Failed to exit debug mode..."); } else { target->state = TARGET_RUNNING; dsp5680xx_context.debug_mode_enabled = false; } LOG_DEBUG("EOnCE status: 0x%02X.", eonce_status); } else { /* * If debug mode was not enabled but target was halted, then it is most likely that * access to eonce registers is locked. * Reset target to make it run again. */ jtag_add_reset(0, 1); jtag_add_sleep(TIME_DIV_FREESCALE * 200 * 1000); retval = reset_jtag(); err_check(retval, DSP5680XX_ERROR_JTAG_RESET, "Failed to reset JTAG state machine"); jtag_add_sleep(TIME_DIV_FREESCALE * 100 * 1000); jtag_add_reset(0, 0); jtag_add_sleep(TIME_DIV_FREESCALE * 300 * 1000); retval = dsp5680xx_jtag_status(target, &jtag_status); err_check_propagate(retval); if ((jtag_status & JTAG_STATUS_MASK) == JTAG_STATUS_NORMAL) { target->state = TARGET_RUNNING; dsp5680xx_context.debug_mode_enabled = false; } else { retval = ERROR_TARGET_FAILURE; err_check(retval, DSP5680XX_ERROR_RESUME, "Failed to resume target"); } } return ERROR_OK; } /** * The value of @address determines if it corresponds to P: (program) or X: (dat) memory. * If the address is over 0x200000 then it is considered X: memory, and @pmem = 0. * The special case of 0xFFXXXX is not modified, since it allows to read out the * memory mapped EOnCE registers. * * @param address * @param pmem * * @return */ static int dsp5680xx_convert_address(uint32_t *address, int *pmem) { /* * Distinguish data memory (x) from program memory (p) by the address. * Addresses over S_FILE_DATA_OFFSET are considered (x) memory. */ if (*address >= S_FILE_DATA_OFFSET) { *pmem = 0; if (((*address) & 0xff0000) != 0xff0000) *address -= S_FILE_DATA_OFFSET; } return ERROR_OK; } static int dsp5680xx_read_16_single(struct target *t, uint32_t a, uint8_t *data_read, int r_pmem) { struct target *target = t; uint32_t address = a; int retval; retval = core_move_long_to_r0(target, address); err_check_propagate(retval); if (r_pmem) retval = core_move_at_pr0_inc_to_y0(target); else retval = core_move_at_r0_to_y0(target); err_check_propagate(retval); retval = eonce_load_TX_RX_to_r0(target); err_check_propagate(retval); retval = core_move_y0_at_r0(target); err_check_propagate(retval); /* at this point the data i want is at the reg eonce can read */ retval = core_rx_lower_data(target, data_read); err_check_propagate(retval); LOG_DEBUG("%s:Data read from 0x%06X: 0x%02X%02X", __func__, address, data_read[1], data_read[0]); return retval; } static int dsp5680xx_read_32_single(struct target *t, uint32_t a, uint8_t *data_read, int r_pmem) { struct target *target = t; uint32_t address = a; int retval; address = (address & 0xFFFFF); /* Get data to an intermediate register */ retval = core_move_long_to_r0(target, address); err_check_propagate(retval); if (r_pmem) { retval = core_move_at_pr0_inc_to_y0(target); err_check_propagate(retval); retval = core_move_at_pr0_inc_to_y1(target); err_check_propagate(retval); } else { retval = core_move_at_r0_inc_to_y0(target); err_check_propagate(retval); retval = core_move_at_r0_to_y1(target); err_check_propagate(retval); } /* Get lower part of data to TX/RX */ retval = eonce_load_TX_RX_to_r0(target); err_check_propagate(retval); retval = core_move_y0_at_r0_inc(target); /* This also load TX/RX high to r0 */ err_check_propagate(retval); /* Get upper part of data to TX/RX */ retval = core_move_y1_at_r0(target); err_check_propagate(retval); /* at this point the data i want is at the reg eonce can read */ retval = core_rx_lower_data(target, data_read); err_check_propagate(retval); retval = core_rx_upper_data(target, data_read + 2); err_check_propagate(retval); return retval; } static int dsp5680xx_read(struct target *t, uint32_t a, unsigned size, unsigned count, uint8_t *buf) { struct target *target = t; uint32_t address = a; uint8_t *buffer = buf; check_halt_and_debug(target); int retval = ERROR_OK; int pmem = 1; retval = dsp5680xx_convert_address(&address, &pmem); err_check_propagate(retval); dsp5680xx_context.flush = 0; int counter = FLUSH_COUNT_READ_WRITE; for (unsigned i = 0; i < count; i++) { if (--counter == 0) { dsp5680xx_context.flush = 1; counter = FLUSH_COUNT_READ_WRITE; } switch (size) { case 1: if (!(i % 2)) retval = dsp5680xx_read_16_single(target, address + i / 2, buffer + i, pmem); break; case 2: retval = dsp5680xx_read_16_single(target, address + i, buffer + 2 * i, pmem); break; case 4: retval = dsp5680xx_read_32_single(target, address + 2 * i, buffer + 4 * i, pmem); break; default: LOG_USER("%s: Invalid read size.", __func__); break; } err_check_propagate(retval); dsp5680xx_context.flush = 0; } dsp5680xx_context.flush = 1; retval = dsp5680xx_execute_queue(); err_check_propagate(retval); return retval; } static int dsp5680xx_write_16_single(struct target *t, uint32_t a, uint16_t data, uint8_t w_pmem) { struct target *target = t; uint32_t address = a; int retval = 0; retval = core_move_long_to_r0(target, address); err_check_propagate(retval); if (w_pmem) { retval = core_move_value_to_y0(target, data); err_check_propagate(retval); retval = core_move_y0_at_pr0_inc(target); err_check_propagate(retval); } else { retval = core_move_value_at_r0(target, data); err_check_propagate(retval); } return retval; } static int dsp5680xx_write_32_single(struct target *t, uint32_t a, uint32_t data, int w_pmem) { struct target *target = t; uint32_t address = a; int retval = ERROR_OK; retval = core_move_long_to_r0(target, address); err_check_propagate(retval); retval = core_move_long_to_y(target, data); err_check_propagate(retval); if (w_pmem) retval = core_move_y0_at_pr0_inc(target); else retval = core_move_y0_at_r0_inc(target); err_check_propagate(retval); if (w_pmem) retval = core_move_y1_at_pr0_inc(target); else retval = core_move_y1_at_r0_inc(target); err_check_propagate(retval); return retval; } static int dsp5680xx_write_8(struct target *t, uint32_t a, uint32_t c, const uint8_t *d, int pmem) { struct target *target = t; uint32_t address = a; uint32_t count = c; const uint8_t *data = d; int retval = 0; uint16_t data_16; uint32_t iter; int counter = FLUSH_COUNT_READ_WRITE; for (iter = 0; iter < count / 2; iter++) { if (--counter == 0) { dsp5680xx_context.flush = 1; counter = FLUSH_COUNT_READ_WRITE; } data_16 = (data[2 * iter] | (data[2 * iter + 1] << 8)); retval = dsp5680xx_write_16_single(target, address + iter, data_16, pmem); if (retval != ERROR_OK) { LOG_ERROR("%s: Could not write to p:0x%04X", __func__, address); dsp5680xx_context.flush = 1; return retval; } dsp5680xx_context.flush = 0; } dsp5680xx_context.flush = 1; /* Only one byte left, let's not overwrite the other byte (mem is 16bit) */ /* Need to retrieve the part we do not want to overwrite. */ uint16_t data_old; if ((count == 1) || (count % 2)) { retval = dsp5680xx_read(target, address + iter, 1, 1, (uint8_t *) &data_old); err_check_propagate(retval); if (count == 1) data_old = (((data_old & 0xff) << 8) | data[0]); /* preserve upper byte */ else data_old = (((data_old & 0xff) << 8) | data[2 * iter + 1]); retval = dsp5680xx_write_16_single(target, address + iter, data_old, pmem); err_check_propagate(retval); } return retval; } static int dsp5680xx_write_16(struct target *t, uint32_t a, uint32_t c, const uint8_t *d, int pmem) { struct target *target = t; uint32_t address = a; uint32_t count = c; const uint8_t *data = d; int retval = ERROR_OK; uint32_t iter; int counter = FLUSH_COUNT_READ_WRITE; for (iter = 0; iter < count; iter++) { if (--counter == 0) { dsp5680xx_context.flush = 1; counter = FLUSH_COUNT_READ_WRITE; } retval = dsp5680xx_write_16_single(target, address + iter, data[iter], pmem); if (retval != ERROR_OK) { LOG_ERROR("%s: Could not write to p:0x%04X", __func__, address); dsp5680xx_context.flush = 1; return retval; } dsp5680xx_context.flush = 0; } dsp5680xx_context.flush = 1; return retval; } static int dsp5680xx_write_32(struct target *t, uint32_t a, uint32_t c, const uint8_t *d, int pmem) { struct target *target = t; uint32_t address = a; uint32_t count = c; const uint8_t *data = d; int retval = ERROR_OK; uint32_t iter; int counter = FLUSH_COUNT_READ_WRITE; for (iter = 0; iter < count; iter++) { if (--counter == 0) { dsp5680xx_context.flush = 1; counter = FLUSH_COUNT_READ_WRITE; } retval = dsp5680xx_write_32_single(target, address + (iter << 1), data[iter], pmem); if (retval != ERROR_OK) { LOG_ERROR("%s: Could not write to p:0x%04X", __func__, address); dsp5680xx_context.flush = 1; return retval; } dsp5680xx_context.flush = 0; } dsp5680xx_context.flush = 1; return retval; } /** * Writes @buffer to memory. * The parameter @address determines whether @buffer should be written to * P: (program) memory or X: (dat) memory. * * @param target * @param address * @param size Bytes (1), Half words (2), Words (4). * @param count In bytes. * @param buffer * * @return */ static int dsp5680xx_write(struct target *t, uint32_t a, uint32_t s, uint32_t c, const uint8_t *b) { /* TODO Cannot write 32bit to odd address, will write 0x12345678 as 0x5678 0x0012 */ struct target *target = t; uint32_t address = a; uint32_t count = c; uint8_t const *buffer = b; uint32_t size = s; check_halt_and_debug(target); int retval = 0; int p_mem = 1; retval = dsp5680xx_convert_address(&address, &p_mem); err_check_propagate(retval); switch (size) { case 1: retval = dsp5680xx_write_8(target, address, count, buffer, p_mem); break; case 2: retval = dsp5680xx_write_16(target, address, count, buffer, p_mem); break; case 4: retval = dsp5680xx_write_32(target, address, count, buffer, p_mem); break; default: retval = ERROR_TARGET_DATA_ABORT; err_check(retval, DSP5680XX_ERROR_INVALID_DATA_SIZE_UNIT, "Invalid data size."); break; } return retval; } static int dsp5680xx_write_buffer(struct target *t, uint32_t a, uint32_t size, const uint8_t *b) { check_halt_and_debug(t); return dsp5680xx_write(t, a, 1, size, b); } /** * This function is called by verify_image, it is used to read data from memory. * * @param target * @param address Word addressing. * @param size In bytes. * @param buffer * * @return */ static int dsp5680xx_read_buffer(struct target *t, uint32_t a, uint32_t size, uint8_t *buf) { check_halt_and_debug(t); /* The "/2" solves the byte/word addressing issue.*/ return dsp5680xx_read(t, a, 2, size / 2, buf); } /** * This function is not implemented. * It returns an error in order to get OpenOCD to do read out the data * and calculate the CRC, or try a binary comparison. * * @param target * @param address Start address of the image. * @param size In bytes. * @param checksum * * @return */ static int dsp5680xx_checksum_memory(struct target *t, uint32_t a, uint32_t s, uint32_t *checksum) { return ERROR_FAIL; } /** * Calculates a signature over @word_count words in the data from @buff16. * The algorithm used is the same the FM uses, so the @return may be used to compare * with the one generated by the FM module, and check if flashing was successful. * This algorithm is based on the perl script available from the Freescale website at FAQ 25630. * * @param buff16 * @param word_count * * @return */ static int perl_crc(uint8_t *buff8, uint32_t word_count) { uint16_t checksum = 0xffff; uint16_t data, fbmisr; uint32_t i; for (i = 0; i < word_count; i++) { data = (buff8[2 * i] | (buff8[2 * i + 1] << 8)); fbmisr = (checksum & 2) >> 1 ^ (checksum & 4) >> 2 ^ (checksum & 16) >> 4 ^ (checksum & 0x8000) >> 15; checksum = (data ^ ((checksum << 1) | fbmisr)); } i--; for (; !(i & 0x80000000); i--) { data = (buff8[2 * i] | (buff8[2 * i + 1] << 8)); fbmisr = (checksum & 2) >> 1 ^ (checksum & 4) >> 2 ^ (checksum & 16) >> 4 ^ (checksum & 0x8000) >> 15; checksum = (data ^ ((checksum << 1) | fbmisr)); } return checksum; } /** * Resets the SIM. (System Integration Modul). * * @param target * * @return */ int dsp5680xx_f_SIM_reset(struct target *target) { int retval = ERROR_OK; uint16_t sim_cmd = SIM_CMD_RESET; uint32_t sim_addr; if (strcmp(target->tap->chip, "dsp568013") == 0) { sim_addr = MC568013_SIM_BASE_ADDR + S_FILE_DATA_OFFSET; retval = dsp5680xx_write(target, sim_addr, 1, 2, (const uint8_t *)&sim_cmd); err_check_propagate(retval); } return retval; } /** * Halts the core and resets the SIM. (System Integration Modul). * * @param target * * @return */ static int dsp5680xx_soft_reset_halt(struct target *target) { /* TODO is this what this function is expected to do...? */ int retval; retval = dsp5680xx_halt(target); err_check_propagate(retval); retval = dsp5680xx_f_SIM_reset(target); err_check_propagate(retval); return retval; } int dsp5680xx_f_protect_check(struct target *target, uint16_t *protected) { int retval; check_halt_and_debug(target); if (protected == NULL) { const char *msg = "NULL pointer not valid."; err_check(ERROR_FAIL, DSP5680XX_ERROR_PROTECT_CHECK_INVALID_ARGS, msg); } retval = dsp5680xx_read_16_single(target, HFM_BASE_ADDR | HFM_PROT, (uint8_t *) protected, 0); err_check_propagate(retval); return retval; } /** * Executes a command on the FM module. * Some commands use the parameters @address and @data, others ignore them. * * @param target * @param command Command to execute. * @param address Command parameter. * @param data Command parameter. * @param hfm_ustat FM status register. * @param pmem Address is P: (program) memory (@pmem == 1) or X: (dat) memory (@pmem == 0) * * @return */ static int dsp5680xx_f_ex(struct target *t, uint16_t c, uint32_t a, uint32_t d, uint16_t *h, int p) { struct target *target = t; uint32_t command = c; uint32_t address = a; uint32_t data = d; uint16_t *hfm_ustat = h; int pmem = p; int retval; retval = core_load_TX_RX_high_addr_to_r0(target); err_check_propagate(retval); retval = core_move_long_to_r2(target, HFM_BASE_ADDR); err_check_propagate(retval); uint8_t i[2]; int watchdog = 100; do { retval = core_move_at_r2_disp_to_y0(target, HFM_USTAT); /* read HMF_USTAT */ err_check_propagate(retval); retval = core_move_y0_at_r0(target); err_check_propagate(retval); retval = core_rx_upper_data(target, i); err_check_propagate(retval); if ((watchdog--) == 1) { retval = ERROR_TARGET_FAILURE; const char *msg = "Timed out waiting for FM to finish old command."; err_check(retval, DSP5680XX_ERROR_FM_BUSY, msg); } } while (!(i[0] & 0x40)); /* wait until current command is complete */ dsp5680xx_context.flush = 0; /* write to HFM_CNFG (lock=0,select bank) - flash_desc.bank&0x03, 0x01 == 0x00, 0x01 ??? */ retval = core_move_value_at_r2_disp(target, 0x00, HFM_CNFG); err_check_propagate(retval); /* write to HMF_USTAT, clear PVIOL, ACCERR &BLANK bits */ retval = core_move_value_at_r2_disp(target, 0x04, HFM_USTAT); err_check_propagate(retval); /* clear only one bit at a time */ retval = core_move_value_at_r2_disp(target, 0x10, HFM_USTAT); err_check_propagate(retval); retval = core_move_value_at_r2_disp(target, 0x20, HFM_USTAT); err_check_propagate(retval); /* write to HMF_PROT, clear protection */ retval = core_move_value_at_r2_disp(target, 0x00, HFM_PROT); err_check_propagate(retval); /* write to HMF_PROTB, clear protection */ retval = core_move_value_at_r2_disp(target, 0x00, HFM_PROTB); err_check_propagate(retval); retval = core_move_value_to_y0(target, data); err_check_propagate(retval); /* write to the flash block */ retval = core_move_long_to_r3(target, address); err_check_propagate(retval); if (pmem) { retval = core_move_y0_at_pr3_inc(target); err_check_propagate(retval); } else { retval = core_move_y0_at_r3(target); err_check_propagate(retval); } /* write command to the HFM_CMD reg */ retval = core_move_value_at_r2_disp(target, command, HFM_CMD); err_check_propagate(retval); /* start the command */ retval = core_move_value_at_r2_disp(target, 0x80, HFM_USTAT); err_check_propagate(retval); dsp5680xx_context.flush = 1; retval = dsp5680xx_execute_queue(); err_check_propagate(retval); watchdog = 100; do { /* read HMF_USTAT */ retval = core_move_at_r2_disp_to_y0(target, HFM_USTAT); err_check_propagate(retval); retval = core_move_y0_at_r0(target); err_check_propagate(retval); retval = core_rx_upper_data(target, i); err_check_propagate(retval); if ((watchdog--) == 1) { retval = ERROR_TARGET_FAILURE; err_check(retval, DSP5680XX_ERROR_FM_CMD_TIMED_OUT, "FM execution did not finish."); } } while (!(i[0] & 0x40)); /* wait until the command is complete */ *hfm_ustat = ((i[0] << 8) | (i[1])); if (i[0] & HFM_USTAT_MASK_PVIOL_ACCER) { retval = ERROR_TARGET_FAILURE; const char *msg = "pviol and/or accer bits set. HFM command execution error"; err_check(retval, DSP5680XX_ERROR_FM_EXEC, msg); } return ERROR_OK; } /** * Prior to the execution of any Flash module command, the Flash module Clock Divider (CLKDIV) register must be initialized. The values of this register determine the speed of the internal Flash Clock (FCLK). FCLK must be in the range of 150kHz ≤ FCLK ≤ 200kHz for proper operation of the Flash module. (Running FCLK too slowly wears out the module, while running it too fast under programs Flash leading to bit errors.) * * @param target * * @return */ static int set_fm_ck_div(struct target *target) { uint8_t i[2]; int retval; retval = core_move_long_to_r2(target, HFM_BASE_ADDR); err_check_propagate(retval); retval = core_load_TX_RX_high_addr_to_r0(target); err_check_propagate(retval); /* read HFM_CLKD */ retval = core_move_at_r2_to_y0(target); err_check_propagate(retval); retval = core_move_y0_at_r0(target); err_check_propagate(retval); retval = core_rx_upper_data(target, i); err_check_propagate(retval); unsigned int hfm_at_wrong_value = 0; if ((i[0] & 0x7f) != HFM_CLK_DEFAULT) { LOG_DEBUG("HFM CLK divisor contained incorrect value (0x%02X).", i[0] & 0x7f); hfm_at_wrong_value = 1; } else { LOG_DEBUG ("HFM CLK divisor was already set to correct value (0x%02X).", i[0] & 0x7f); return ERROR_OK; } /* write HFM_CLKD */ retval = core_move_value_at_r2(target, HFM_CLK_DEFAULT); err_check_propagate(retval); /* verify HFM_CLKD */ retval = core_move_at_r2_to_y0(target); err_check_propagate(retval); retval = core_move_y0_at_r0(target); err_check_propagate(retval); retval = core_rx_upper_data(target, i); err_check_propagate(retval); if (i[0] != (0x80 | (HFM_CLK_DEFAULT & 0x7f))) { retval = ERROR_TARGET_FAILURE; err_check(retval, DSP5680XX_ERROR_FM_SET_CLK, "Unable to set HFM CLK divisor."); } if (hfm_at_wrong_value) LOG_DEBUG("HFM CLK divisor set to 0x%02x.", i[0] & 0x7f); return ERROR_OK; } /** * Executes the FM calculate signature command. The FM will calculate over the data from @address to @address + @words -1. The result is written to a register, then read out by this function and returned in @signature. The value @signature may be compared to the the one returned by perl_crc to verify the flash was written correctly. * * @param target * @param address Start of flash array where the signature should be calculated. * @param words Number of words over which the signature should be calculated. * @param signature Value calculated by the FM. * * @return */ static int dsp5680xx_f_signature(struct target *t, uint32_t a, uint32_t words, uint16_t *signature) { struct target *target = t; uint32_t address = a; int retval; uint16_t hfm_ustat; if (!dsp5680xx_context.debug_mode_enabled) { retval = eonce_enter_debug_mode_without_reset(target, NULL); /* * Generate error here, since it is not done in eonce_enter_debug_mode_without_reset */ err_check(retval, DSP5680XX_ERROR_HALT, "Failed to halt target."); } retval = dsp5680xx_f_ex(target, HFM_CALCULATE_DATA_SIGNATURE, address, words, &hfm_ustat, 1); err_check_propagate(retval); retval = dsp5680xx_read_16_single(target, HFM_BASE_ADDR | HFM_DATA, (uint8_t *) signature, 0); return retval; } int dsp5680xx_f_erase_check(struct target *target, uint8_t *erased, uint32_t sector) { int retval; uint16_t hfm_ustat; uint32_t tmp; if (!dsp5680xx_context.debug_mode_enabled) { retval = dsp5680xx_halt(target); err_check_propagate(retval); } retval = set_fm_ck_div(target); err_check_propagate(retval); /* * Check if chip is already erased. */ tmp = HFM_FLASH_BASE_ADDR + sector * HFM_SECTOR_SIZE / 2; retval = dsp5680xx_f_ex(target, HFM_ERASE_VERIFY, tmp, 0, &hfm_ustat, 1); err_check_propagate(retval); if (erased != NULL) *erased = (uint8_t) (hfm_ustat & HFM_USTAT_MASK_BLANK); return retval; } /** * Executes the FM page erase command. * * @param target * @param sector Page to erase. * @param hfm_ustat FM module status register. * * @return */ static int erase_sector(struct target *target, int sector, uint16_t *hfm_ustat) { int retval; uint32_t tmp = HFM_FLASH_BASE_ADDR + sector * HFM_SECTOR_SIZE / 2; retval = dsp5680xx_f_ex(target, HFM_PAGE_ERASE, tmp, 0, hfm_ustat, 1); err_check_propagate(retval); return retval; } /** * Executes the FM mass erase command. Erases the flash array completely. * * @param target * @param hfm_ustat FM module status register. * * @return */ static int mass_erase(struct target *target, uint16_t *hfm_ustat) { int retval; retval = dsp5680xx_f_ex(target, HFM_MASS_ERASE, 0, 0, hfm_ustat, 1); return retval; } int dsp5680xx_f_erase(struct target *target, int first, int last) { int retval; if (!dsp5680xx_context.debug_mode_enabled) { retval = dsp5680xx_halt(target); err_check_propagate(retval); } /* * Reset SIM * */ retval = dsp5680xx_f_SIM_reset(target); err_check_propagate(retval); /* * Set hfmdiv * */ retval = set_fm_ck_div(target); err_check_propagate(retval); uint16_t hfm_ustat; int do_mass_erase = ((!(first | last)) || ((first == 0) && (last == (HFM_SECTOR_COUNT - 1)))); if (do_mass_erase) { /* Mass erase */ retval = mass_erase(target, &hfm_ustat); err_check_propagate(retval); } else { for (int i = first; i <= last; i++) { retval = erase_sector(target, i, &hfm_ustat); err_check_propagate(retval); } } return ERROR_OK; } /* * Algorithm for programming normal p: flash * Follow state machine from "56F801x Peripheral Reference Manual"@163. * Registers to set up before calling: * r0: TX/RX high address. * r2: FM module base address. * r3: Destination address in flash. * * hfm_wait: // wait for buffer empty * brclr #0x80, x:(r2+0x13), hfm_wait * rx_check: // wait for input buffer full * brclr #0x01, x:(r0-2), rx_check * move.w x:(r0), y0 // read from Rx buffer * move.w y0, p:(r3)+ * move.w #0x20, x:(r2+0x14) // write PGM command * move.w #0x80, x:(r2+0x13) // start the command * move.w X:(R2+0x13), A // Read USTAT register * brclr #0x20, A, accerr_check // protection violation check * bfset #0x20, X:(R2+0x13) // clear pviol * bra hfm_wait * accerr_check: * brclr #0x10, A, hfm_wait // access error check * bfset #0x10, X:(R2+0x13) // clear accerr * bra hfm_wait // loop * 0x00000000 0x8A460013807D brclr #0x80, X:(R2+0x13),*+0 * 0x00000003 0xE700 nop * 0x00000004 0xE700 nop * 0x00000005 0x8A44FFFE017B brclr #1, X:(R0-2),*-2 * 0x00000008 0xE700 nop * 0x00000009 0xF514 move.w X:(R0), Y0 * 0x0000000A 0x8563 move.w Y0, P:(R3)+ * 0x0000000B 0x864600200014 move.w #32, X:(R2+0x14) * 0x0000000E 0x864600800013 move.w #128, X:(R2+0x13) * 0x00000011 0xF0420013 move.w X:(R2+0x13), A * 0x00000013 0x8B402004 brclr #0x20, A,*+6 * 0x00000015 0x824600130020 bfset #0x20, X:(R2+0x13) * 0x00000018 0xA967 bra *-24 * 0x00000019 0x8B401065 brclr #0x10, A,*-25 * 0x0000001B 0x824600130010 bfset #0x10, X:(R2+0x13) * 0x0000001E 0xA961 bra *-30 */ const uint16_t pgm_write_pflash[] = { 0x8A46, 0x0013, 0x807D, 0xE700, 0xE700, 0x8A44, 0xFFFE, 0x017B, 0xE700, 0xF514, 0x8563, 0x8646, 0x0020, 0x0014, 0x8646, 0x0080, 0x0013, 0xF042, 0x0013, 0x8B40, 0x2004, 0x8246, 0x0013, 0x0020, 0xA967, 0x8B40, 0x1065, 0x8246, 0x0013, 0x0010, 0xA961 }; const uint32_t pgm_write_pflash_length = 31; int dsp5680xx_f_wr(struct target *t, uint8_t *b, uint32_t a, uint32_t count, int is_flash_lock) { struct target *target = t; uint32_t address = a; uint8_t *buffer = b; int retval = ERROR_OK; if (!dsp5680xx_context.debug_mode_enabled) { retval = eonce_enter_debug_mode(target, NULL); err_check_propagate(retval); } /* * Download the pgm that flashes. * */ const uint32_t len = pgm_write_pflash_length; uint32_t ram_addr = 0x8700; /* * This seems to be a safe address. * This one is the one used by codewarrior in 56801x_flash.cfg */ if (!is_flash_lock) { retval = dsp5680xx_write(target, ram_addr, 1, len * 2, (uint8_t *) pgm_write_pflash); err_check_propagate(retval); retval = dsp5680xx_execute_queue(); err_check_propagate(retval); } /* * Set hfmdiv * */ retval = set_fm_ck_div(target); err_check_propagate(retval); /* * Setup registers needed by pgm_write_pflash * */ dsp5680xx_context.flush = 0; retval = core_move_long_to_r3(target, address); /* Destination address to r3 */ err_check_propagate(retval); core_load_TX_RX_high_addr_to_r0(target); /* TX/RX reg address to r0 */ err_check_propagate(retval); retval = core_move_long_to_r2(target, HFM_BASE_ADDR); /* FM base address to r2 */ err_check_propagate(retval); /* * Run flashing program. * */ /* write to HFM_CNFG (lock=0, select bank) */ retval = core_move_value_at_r2_disp(target, 0x00, HFM_CNFG); err_check_propagate(retval); /* write to HMF_USTAT, clear PVIOL, ACCERR &BLANK bits */ retval = core_move_value_at_r2_disp(target, 0x04, HFM_USTAT); err_check_propagate(retval); /* clear only one bit at a time */ retval = core_move_value_at_r2_disp(target, 0x10, HFM_USTAT); err_check_propagate(retval); retval = core_move_value_at_r2_disp(target, 0x20, HFM_USTAT); err_check_propagate(retval); /* write to HMF_PROT, clear protection */ retval = core_move_value_at_r2_disp(target, 0x00, HFM_PROT); err_check_propagate(retval); /* write to HMF_PROTB, clear protection */ retval = core_move_value_at_r2_disp(target, 0x00, HFM_PROTB); err_check_propagate(retval); if (count % 2) { /* TODO implement handling of odd number of words. */ retval = ERROR_FAIL; const char *msg = "Cannot handle odd number of words."; err_check(retval, DSP5680XX_ERROR_FLASHING_INVALID_WORD_COUNT, msg); } dsp5680xx_context.flush = 1; retval = dsp5680xx_execute_queue(); err_check_propagate(retval); uint32_t drscan_data; uint16_t tmp = (buffer[0] | (buffer[1] << 8)); retval = core_tx_upper_data(target, tmp, &drscan_data); err_check_propagate(retval); retval = dsp5680xx_resume(target, 0, ram_addr, 0, 0); err_check_propagate(retval); int counter = FLUSH_COUNT_FLASH; dsp5680xx_context.flush = 0; uint32_t i; for (i = 1; (i < count / 2) && (i < HFM_SIZE_WORDS); i++) { if (--counter == 0) { dsp5680xx_context.flush = 1; counter = FLUSH_COUNT_FLASH; } tmp = (buffer[2 * i] | (buffer[2 * i + 1] << 8)); retval = core_tx_upper_data(target, tmp, &drscan_data); if (retval != ERROR_OK) { dsp5680xx_context.flush = 1; err_check_propagate(retval); } dsp5680xx_context.flush = 0; } dsp5680xx_context.flush = 1; if (!is_flash_lock) { /* *Verify flash (skip when exec lock sequence) * */ uint16_t signature; uint16_t pc_crc; retval = dsp5680xx_f_signature(target, address, i, &signature); err_check_propagate(retval); pc_crc = perl_crc(buffer, i); if (pc_crc != signature) { retval = ERROR_FAIL; const char *msg = "Flashed data failed CRC check, flash again!"; err_check(retval, DSP5680XX_ERROR_FLASHING_CRC, msg); } } return retval; } int dsp5680xx_f_unlock(struct target *target) { int retval = ERROR_OK; uint16_t eonce_status; uint32_t instr; uint32_t ir_out; struct jtag_tap *tap_chp; struct jtag_tap *tap_cpu; tap_chp = jtag_tap_by_string("dsp568013.chp"); if (tap_chp == NULL) { retval = ERROR_FAIL; err_check(retval, DSP5680XX_ERROR_JTAG_TAP_ENABLE_MASTER, "Failed to get master tap."); } tap_cpu = jtag_tap_by_string("dsp568013.cpu"); if (tap_cpu == NULL) { retval = ERROR_FAIL; err_check(retval, DSP5680XX_ERROR_JTAG_TAP_ENABLE_CORE, "Failed to get master tap."); } retval = eonce_enter_debug_mode_without_reset(target, &eonce_status); if (retval == ERROR_OK) LOG_WARNING("Memory was not locked."); jtag_add_reset(0, 1); jtag_add_sleep(TIME_DIV_FREESCALE * 200 * 1000); retval = reset_jtag(); err_check(retval, DSP5680XX_ERROR_JTAG_RESET, "Failed to reset JTAG state machine"); jtag_add_sleep(150); /* Enable core tap */ tap_chp->enabled = true; retval = switch_tap(target, tap_chp, tap_cpu); err_check_propagate(retval); instr = JTAG_INSTR_DEBUG_REQUEST; retval = dsp5680xx_irscan(target, &instr, &ir_out, DSP5680XX_JTAG_CORE_TAP_IRLEN); err_check_propagate(retval); jtag_add_sleep(TIME_DIV_FREESCALE * 100 * 1000); jtag_add_reset(0, 0); jtag_add_sleep(TIME_DIV_FREESCALE * 300 * 1000); /* Enable master tap */ tap_chp->enabled = false; retval = switch_tap(target, tap_chp, tap_cpu); err_check_propagate(retval); /* Execute mass erase to unlock */ instr = MASTER_TAP_CMD_FLASH_ERASE; retval = dsp5680xx_irscan(target, &instr, &ir_out, DSP5680XX_JTAG_MASTER_TAP_IRLEN); err_check_propagate(retval); instr = HFM_CLK_DEFAULT; retval = dsp5680xx_drscan(target, (uint8_t *) &instr, (uint8_t *) &ir_out, 16); err_check_propagate(retval); jtag_add_sleep(TIME_DIV_FREESCALE * 150 * 1000); jtag_add_reset(0, 1); jtag_add_sleep(TIME_DIV_FREESCALE * 200 * 1000); retval = reset_jtag(); err_check(retval, DSP5680XX_ERROR_JTAG_RESET, "Failed to reset JTAG state machine"); jtag_add_sleep(150); instr = 0x0606ffff; retval = dsp5680xx_drscan(target, (uint8_t *) &instr, (uint8_t *) &ir_out, 32); err_check_propagate(retval); /* enable core tap */ instr = 0x5; retval = dsp5680xx_irscan(target, &instr, &ir_out, DSP5680XX_JTAG_MASTER_TAP_IRLEN); err_check_propagate(retval); instr = 0x2; retval = dsp5680xx_drscan(target, (uint8_t *) &instr, (uint8_t *) &ir_out, 4); err_check_propagate(retval); tap_cpu->enabled = true; tap_chp->enabled = false; target->state = TARGET_RUNNING; dsp5680xx_context.debug_mode_enabled = false; return retval; } int dsp5680xx_f_lock(struct target *target) { int retval; struct jtag_tap *tap_chp; struct jtag_tap *tap_cpu; uint16_t lock_word[] = { HFM_LOCK_FLASH }; retval = dsp5680xx_f_wr(target, (uint8_t *) (lock_word), HFM_LOCK_ADDR_L, 2, 1); err_check_propagate(retval); jtag_add_reset(0, 1); jtag_add_sleep(TIME_DIV_FREESCALE * 200 * 1000); retval = reset_jtag(); err_check(retval, DSP5680XX_ERROR_JTAG_RESET, "Failed to reset JTAG state machine"); jtag_add_sleep(TIME_DIV_FREESCALE * 100 * 1000); jtag_add_reset(0, 0); jtag_add_sleep(TIME_DIV_FREESCALE * 300 * 1000); tap_chp = jtag_tap_by_string("dsp568013.chp"); if (tap_chp == NULL) { retval = ERROR_FAIL; err_check(retval, DSP5680XX_ERROR_JTAG_TAP_ENABLE_MASTER, "Failed to get master tap."); } tap_cpu = jtag_tap_by_string("dsp568013.cpu"); if (tap_cpu == NULL) { retval = ERROR_FAIL; err_check(retval, DSP5680XX_ERROR_JTAG_TAP_ENABLE_CORE, "Failed to get master tap."); } target->state = TARGET_RUNNING; dsp5680xx_context.debug_mode_enabled = false; tap_cpu->enabled = false; tap_chp->enabled = true; retval = switch_tap(target, tap_chp, tap_cpu); return retval; } static int dsp5680xx_step(struct target *target, int current, uint32_t address, int handle_breakpoints) { err_check(ERROR_FAIL, DSP5680XX_ERROR_NOT_IMPLEMENTED_STEP, "Not implemented yet."); } /** Holds methods for dsp5680xx targets. */ struct target_type dsp5680xx_target = { .name = "dsp5680xx", .poll = dsp5680xx_poll, .arch_state = dsp5680xx_arch_state, .target_request_data = NULL, .halt = dsp5680xx_halt, .resume = dsp5680xx_resume, .step = dsp5680xx_step, .write_buffer = dsp5680xx_write_buffer, .read_buffer = dsp5680xx_read_buffer, .assert_reset = dsp5680xx_assert_reset, .deassert_reset = dsp5680xx_deassert_reset, .soft_reset_halt = dsp5680xx_soft_reset_halt, .read_memory = dsp5680xx_read, .write_memory = dsp5680xx_write, .checksum_memory = dsp5680xx_checksum_memory, .target_create = dsp5680xx_target_create, .init_target = dsp5680xx_init_target, }; openocd-0.7.0/src/target/hla_target.c0000644000175000001440000005224512137151331014422 00000000000000/*************************************************************************** * Copyright (C) 2011 by Mathias Kuester * * Mathias Kuester * * * * Copyright (C) 2011 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "jtag/jtag.h" #include "jtag/hla/hla_transport.h" #include "jtag/hla/hla_interface.h" #include "jtag/hla/hla_layout.h" #include "register.h" #include "algorithm.h" #include "target.h" #include "breakpoints.h" #include "target_type.h" #include "armv7m.h" #include "cortex_m.h" #include "arm_semihosting.h" #define ARMV7M_SCS_DCRSR 0xe000edf4 #define ARMV7M_SCS_DCRDR 0xe000edf8 static inline struct hl_interface_s *target_to_adapter(struct target *target) { return target->tap->priv; } static int adapter_load_core_reg_u32(struct target *target, uint32_t num, uint32_t *value) { int retval; struct hl_interface_s *adapter = target_to_adapter(target); LOG_DEBUG("%s", __func__); /* NOTE: we "know" here that the register identifiers used * in the v7m header match the Cortex-M3 Debug Core Register * Selector values for R0..R15, xPSR, MSP, and PSP. */ switch (num) { case 0 ... 18: /* read a normal core register */ retval = adapter->layout->api->read_reg(adapter->fd, num, value); if (retval != ERROR_OK) { LOG_ERROR("JTAG failure %i", retval); return ERROR_JTAG_DEVICE_ERROR; } LOG_DEBUG("load from core reg %i value 0x%" PRIx32 "", (int)num, *value); break; case ARMV7M_FPSID: case ARMV7M_FPEXC: *value = 0; break; case ARMV7M_FPSCR: /* Floating-point Status and Registers */ retval = target_write_u32(target, ARMV7M_SCS_DCRSR, 33); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, ARMV7M_SCS_DCRDR, value); if (retval != ERROR_OK) return retval; LOG_DEBUG("load from core reg %i value 0x%" PRIx32 "", (int)num, *value); break; case ARMV7M_S0 ... ARMV7M_S31: /* Floating-point Status and Registers */ retval = target_write_u32(target, ARMV7M_SCS_DCRSR, num-ARMV7M_S0+64); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, ARMV7M_SCS_DCRDR, value); if (retval != ERROR_OK) return retval; LOG_DEBUG("load from core reg %i value 0x%" PRIx32 "", (int)num, *value); break; case ARMV7M_D0 ... ARMV7M_D15: value = 0; break; case ARMV7M_PRIMASK: case ARMV7M_BASEPRI: case ARMV7M_FAULTMASK: case ARMV7M_CONTROL: /* Cortex-M3 packages these four registers as bitfields * in one Debug Core register. So say r0 and r2 docs; * it was removed from r1 docs, but still works. */ retval = adapter->layout->api->read_reg(adapter->fd, 20, value); if (retval != ERROR_OK) return retval; switch (num) { case ARMV7M_PRIMASK: *value = buf_get_u32((uint8_t *) value, 0, 1); break; case ARMV7M_BASEPRI: *value = buf_get_u32((uint8_t *) value, 8, 8); break; case ARMV7M_FAULTMASK: *value = buf_get_u32((uint8_t *) value, 16, 1); break; case ARMV7M_CONTROL: *value = buf_get_u32((uint8_t *) value, 24, 2); break; } LOG_DEBUG("load from special reg %i value 0x%" PRIx32 "", (int)num, *value); break; default: return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; } static int adapter_store_core_reg_u32(struct target *target, uint32_t num, uint32_t value) { int retval; uint32_t reg; struct armv7m_common *armv7m = target_to_armv7m(target); struct hl_interface_s *adapter = target_to_adapter(target); LOG_DEBUG("%s", __func__); #ifdef ARMV7_GDB_HACKS /* If the LR register is being modified, make sure it will put us * in "thumb" mode, or an INVSTATE exception will occur. This is a * hack to deal with the fact that gdb will sometimes "forge" * return addresses, and doesn't set the LSB correctly (i.e., when * printing expressions containing function calls, it sets LR = 0.) * Valid exception return codes have bit 0 set too. */ if (num == ARMV7M_R14) value |= 0x01; #endif /* NOTE: we "know" here that the register identifiers used * in the v7m header match the Cortex-M3 Debug Core Register * Selector values for R0..R15, xPSR, MSP, and PSP. */ switch (num) { case 0 ... 18: retval = adapter->layout->api->write_reg(adapter->fd, num, value); if (retval != ERROR_OK) { struct reg *r; LOG_ERROR("JTAG failure"); r = armv7m->arm.core_cache->reg_list + num; r->dirty = r->valid; return ERROR_JTAG_DEVICE_ERROR; } LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", (int)num, value); break; case ARMV7M_FPSID: case ARMV7M_FPEXC: break; case ARMV7M_FPSCR: /* Floating-point Status and Registers */ retval = target_write_u32(target, ARMV7M_SCS_DCRDR, value); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, ARMV7M_SCS_DCRSR, 33 | (1<<16)); if (retval != ERROR_OK) return retval; LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", (int)num, value); break; case ARMV7M_S0 ... ARMV7M_S31: /* Floating-point Status and Registers */ retval = target_write_u32(target, ARMV7M_SCS_DCRDR, value); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, ARMV7M_SCS_DCRSR, (num-ARMV7M_S0+64) | (1<<16)); if (retval != ERROR_OK) return retval; LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", (int)num, value); break; case ARMV7M_D0 ... ARMV7M_D15: break; case ARMV7M_PRIMASK: case ARMV7M_BASEPRI: case ARMV7M_FAULTMASK: case ARMV7M_CONTROL: /* Cortex-M3 packages these four registers as bitfields * in one Debug Core register. So say r0 and r2 docs; * it was removed from r1 docs, but still works. */ adapter->layout->api->read_reg(adapter->fd, 20, ®); switch (num) { case ARMV7M_PRIMASK: buf_set_u32((uint8_t *) ®, 0, 1, value); break; case ARMV7M_BASEPRI: buf_set_u32((uint8_t *) ®, 8, 8, value); break; case ARMV7M_FAULTMASK: buf_set_u32((uint8_t *) ®, 16, 1, value); break; case ARMV7M_CONTROL: buf_set_u32((uint8_t *) ®, 24, 2, value); break; } adapter->layout->api->write_reg(adapter->fd, 20, reg); LOG_DEBUG("write special reg %i value 0x%" PRIx32 " ", (int)num, value); break; default: return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; } static int adapter_examine_debug_reason(struct target *target) { if ((target->debug_reason != DBG_REASON_DBGRQ) && (target->debug_reason != DBG_REASON_SINGLESTEP)) { target->debug_reason = DBG_REASON_BREAKPOINT; } return ERROR_OK; } static int adapter_init_arch_info(struct target *target, struct cortex_m3_common *cortex_m3, struct jtag_tap *tap) { struct armv7m_common *armv7m; LOG_DEBUG("%s", __func__); armv7m = &cortex_m3->armv7m; armv7m_init_arch_info(target, armv7m); armv7m->load_core_reg_u32 = adapter_load_core_reg_u32; armv7m->store_core_reg_u32 = adapter_store_core_reg_u32; armv7m->examine_debug_reason = adapter_examine_debug_reason; armv7m->stlink = true; return ERROR_OK; } static int adapter_init_target(struct command_context *cmd_ctx, struct target *target) { LOG_DEBUG("%s", __func__); armv7m_build_reg_cache(target); return ERROR_OK; } static int adapter_target_create(struct target *target, Jim_Interp *interp) { LOG_DEBUG("%s", __func__); struct cortex_m3_common *cortex_m3 = calloc(1, sizeof(struct cortex_m3_common)); if (!cortex_m3) return ERROR_COMMAND_SYNTAX_ERROR; adapter_init_arch_info(target, cortex_m3, target->tap); return ERROR_OK; } static int adapter_load_context(struct target *target) { struct armv7m_common *armv7m = target_to_armv7m(target); int num_regs = armv7m->arm.core_cache->num_regs; for (int i = 0; i < num_regs; i++) { struct reg *r = &armv7m->arm.core_cache->reg_list[i]; if (!r->valid) armv7m->arm.read_core_reg(target, r, i, ARM_MODE_ANY); } return ERROR_OK; } static int adapter_debug_entry(struct target *target) { struct hl_interface_s *adapter = target_to_adapter(target); struct armv7m_common *armv7m = target_to_armv7m(target); struct arm *arm = &armv7m->arm; struct reg *r; uint32_t xPSR; int retval; retval = armv7m->examine_debug_reason(target); if (retval != ERROR_OK) return retval; adapter_load_context(target); /* make sure we clear the vector catch bit */ adapter->layout->api->write_debug_reg(adapter->fd, DCB_DEMCR, TRCENA); r = arm->core_cache->reg_list + ARMV7M_xPSR; xPSR = buf_get_u32(r->value, 0, 32); /* Are we in an exception handler */ if (xPSR & 0x1FF) { armv7m->exception_number = (xPSR & 0x1FF); arm->core_mode = ARM_MODE_HANDLER; arm->map = armv7m_msp_reg_map; } else { unsigned control = buf_get_u32(arm->core_cache ->reg_list[ARMV7M_CONTROL].value, 0, 2); /* is this thread privileged? */ arm->core_mode = control & 1 ? ARM_MODE_USER_THREAD : ARM_MODE_THREAD; /* which stack is it using? */ if (control & 2) arm->map = armv7m_psp_reg_map; else arm->map = armv7m_msp_reg_map; armv7m->exception_number = 0; } LOG_DEBUG("entered debug state in core mode: %s at PC 0x%08" PRIx32 ", target->state: %s", arm_mode_name(arm->core_mode), *(uint32_t *)(arm->pc->value), target_state_name(target)); return retval; } static int adapter_poll(struct target *target) { enum target_state state; struct hl_interface_s *adapter = target_to_adapter(target); struct armv7m_common *armv7m = target_to_armv7m(target); enum target_state prev_target_state = target->state; state = adapter->layout->api->state(adapter->fd); if (state == TARGET_UNKNOWN) { LOG_ERROR("jtag status contains invalid mode value - communication failure"); return ERROR_TARGET_FAILURE; } if (target->state == state) return ERROR_OK; if (state == TARGET_HALTED) { target->state = state; int retval = adapter_debug_entry(target); if (retval != ERROR_OK) return retval; if (prev_target_state == TARGET_DEBUG_RUNNING) { target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); } else { if (arm_semihosting(target, &retval) != 0) return retval; target_call_event_callbacks(target, TARGET_EVENT_HALTED); } LOG_DEBUG("halted: PC: 0x%08x", buf_get_u32(armv7m->arm.pc->value, 0, 32)); } return ERROR_OK; } static int adapter_assert_reset(struct target *target) { int res = ERROR_OK; struct hl_interface_s *adapter = target_to_adapter(target); struct armv7m_common *armv7m = target_to_armv7m(target); bool use_srst_fallback = true; LOG_DEBUG("%s", __func__); enum reset_types jtag_reset_config = jtag_get_reset_config(); bool srst_asserted = false; if (jtag_reset_config & RESET_SRST_NO_GATING) { jtag_add_reset(0, 1); res = adapter->layout->api->assert_srst(adapter->fd, 0); srst_asserted = true; } adapter->layout->api->write_debug_reg(adapter->fd, DCB_DHCSR, DBGKEY|C_DEBUGEN); /* only set vector catch if halt is requested */ if (target->reset_halt) adapter->layout->api->write_debug_reg(adapter->fd, DCB_DEMCR, TRCENA|VC_CORERESET); else adapter->layout->api->write_debug_reg(adapter->fd, DCB_DEMCR, TRCENA); if (jtag_reset_config & RESET_HAS_SRST) { if (!srst_asserted) { jtag_add_reset(0, 1); res = adapter->layout->api->assert_srst(adapter->fd, 0); } if (res == ERROR_COMMAND_NOTFOUND) LOG_ERROR("Hardware srst not supported, falling back to software reset"); else if (res == ERROR_OK) { /* hardware srst supported */ use_srst_fallback = false; } } if (use_srst_fallback) { /* stlink v1 api does not support hardware srst, so we use a software reset fallback */ adapter->layout->api->write_debug_reg(adapter->fd, NVIC_AIRCR, AIRCR_VECTKEY | AIRCR_SYSRESETREQ); } res = adapter->layout->api->reset(adapter->fd); if (res != ERROR_OK) return res; /* registers are now invalid */ register_cache_invalidate(armv7m->arm.core_cache); if (target->reset_halt) { target->state = TARGET_RESET; target->debug_reason = DBG_REASON_DBGRQ; } else { target->state = TARGET_HALTED; } return ERROR_OK; } static int adapter_deassert_reset(struct target *target) { int res; struct hl_interface_s *adapter = target_to_adapter(target); enum reset_types jtag_reset_config = jtag_get_reset_config(); LOG_DEBUG("%s", __func__); if (jtag_reset_config & RESET_HAS_SRST) adapter->layout->api->assert_srst(adapter->fd, 1); /* virtual deassert reset, we need it for the internal * jtag state machine */ jtag_add_reset(0, 0); if (!target->reset_halt) { res = target_resume(target, 1, 0, 0, 0); if (res != ERROR_OK) return res; } return ERROR_OK; } static int adapter_soft_reset_halt(struct target *target) { LOG_DEBUG("%s", __func__); return ERROR_OK; } static int adapter_halt(struct target *target) { int res; struct hl_interface_s *adapter = target_to_adapter(target); LOG_DEBUG("%s", __func__); if (target->state == TARGET_HALTED) { LOG_DEBUG("target was already halted"); return ERROR_OK; } if (target->state == TARGET_UNKNOWN) LOG_WARNING("target was in unknown state when halt was requested"); res = adapter->layout->api->halt(adapter->fd); if (res != ERROR_OK) return res; target->debug_reason = DBG_REASON_DBGRQ; return ERROR_OK; } static int adapter_resume(struct target *target, int current, uint32_t address, int handle_breakpoints, int debug_execution) { int res; struct hl_interface_s *adapter = target_to_adapter(target); struct armv7m_common *armv7m = target_to_armv7m(target); uint32_t resume_pc; struct breakpoint *breakpoint = NULL; struct reg *pc; LOG_DEBUG("%s %d 0x%08x %d %d", __func__, current, address, handle_breakpoints, debug_execution); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!debug_execution) { target_free_all_working_areas(target); cortex_m3_enable_breakpoints(target); cortex_m3_enable_watchpoints(target); } pc = armv7m->arm.pc; if (!current) { buf_set_u32(pc->value, 0, 32, address); pc->dirty = true; pc->valid = true; } if (!breakpoint_find(target, buf_get_u32(pc->value, 0, 32)) && !debug_execution) { armv7m_maybe_skip_bkpt_inst(target, NULL); } resume_pc = buf_get_u32(pc->value, 0, 32); /* write any user vector flags */ res = target_write_u32(target, DCB_DEMCR, TRCENA | armv7m->demcr); if (res != ERROR_OK) return res; armv7m_restore_context(target); /* registers are now invalid */ register_cache_invalidate(armv7m->arm.core_cache); /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) { /* Single step past breakpoint at current address */ breakpoint = breakpoint_find(target, resume_pc); if (breakpoint) { LOG_DEBUG("unset breakpoint at 0x%8.8" PRIx32 " (ID: %d)", breakpoint->address, breakpoint->unique_id); cortex_m3_unset_breakpoint(target, breakpoint); res = adapter->layout->api->step(adapter->fd); if (res != ERROR_OK) return res; cortex_m3_set_breakpoint(target, breakpoint); } } res = adapter->layout->api->run(adapter->fd); if (res != ERROR_OK) return res; target->debug_reason = DBG_REASON_NOTHALTED; if (!debug_execution) { target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); } else { target->state = TARGET_DEBUG_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); } return ERROR_OK; } static int adapter_step(struct target *target, int current, uint32_t address, int handle_breakpoints) { int res; struct hl_interface_s *adapter = target_to_adapter(target); struct armv7m_common *armv7m = target_to_armv7m(target); struct breakpoint *breakpoint = NULL; struct reg *pc = armv7m->arm.pc; bool bkpt_inst_found = false; LOG_DEBUG("%s", __func__); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!current) { buf_set_u32(pc->value, 0, 32, address); pc->dirty = true; pc->valid = true; } uint32_t pc_value = buf_get_u32(pc->value, 0, 32); /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) { breakpoint = breakpoint_find(target, pc_value); if (breakpoint) cortex_m3_unset_breakpoint(target, breakpoint); } armv7m_maybe_skip_bkpt_inst(target, &bkpt_inst_found); target->debug_reason = DBG_REASON_SINGLESTEP; armv7m_restore_context(target); target_call_event_callbacks(target, TARGET_EVENT_RESUMED); res = adapter->layout->api->step(adapter->fd); if (res != ERROR_OK) return res; /* registers are now invalid */ register_cache_invalidate(armv7m->arm.core_cache); if (breakpoint) cortex_m3_set_breakpoint(target, breakpoint); adapter_debug_entry(target); target_call_event_callbacks(target, TARGET_EVENT_HALTED); LOG_INFO("halted: PC: 0x%08x", buf_get_u32(armv7m->arm.pc->value, 0, 32)); return ERROR_OK; } static int adapter_read_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct hl_interface_s *adapter = target_to_adapter(target); int res; uint32_t buffer_threshold = (adapter->param.max_buffer / 4); uint32_t addr_increment = 4; uint32_t c; if (!count || !buffer) return ERROR_COMMAND_SYNTAX_ERROR; LOG_DEBUG("%s 0x%08x %d %d", __func__, address, size, count); /* prepare byte count, buffer threshold * and address increment for none 32bit access */ if (size != 4) { count *= size; buffer_threshold = (adapter->param.max_buffer / 4) / 2; addr_increment = 1; } while (count) { if (count > buffer_threshold) c = buffer_threshold; else c = count; if (size != 4) res = adapter->layout->api->read_mem8(adapter->fd, address, c, buffer); else res = adapter->layout->api->read_mem32(adapter->fd, address, c, buffer); if (res != ERROR_OK) return res; address += (c * addr_increment); buffer += (c * addr_increment); count -= c; } return ERROR_OK; } static int adapter_write_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct hl_interface_s *adapter = target_to_adapter(target); int res; uint32_t buffer_threshold = (adapter->param.max_buffer / 4); uint32_t addr_increment = 4; uint32_t c; if (!count || !buffer) return ERROR_COMMAND_SYNTAX_ERROR; LOG_DEBUG("%s 0x%08x %d %d", __func__, address, size, count); /* prepare byte count, buffer threshold * and address increment for none 32bit access */ if (size != 4) { count *= size; buffer_threshold = (adapter->param.max_buffer / 4) / 2; addr_increment = 1; } while (count) { if (count > buffer_threshold) c = buffer_threshold; else c = count; if (size != 4) res = adapter->layout->api->write_mem8(adapter->fd, address, c, buffer); else res = adapter->layout->api->write_mem32(adapter->fd, address, c, buffer); if (res != ERROR_OK) return res; address += (c * addr_increment); buffer += (c * addr_increment); count -= c; } return ERROR_OK; } static const struct command_registration adapter_command_handlers[] = { { .chain = arm_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct target_type hla_target = { .name = "hla_target", .deprecated_name = "stm32_stlink", .init_target = adapter_init_target, .target_create = adapter_target_create, .examine = cortex_m3_examine, .commands = adapter_command_handlers, .poll = adapter_poll, .arch_state = armv7m_arch_state, .assert_reset = adapter_assert_reset, .deassert_reset = adapter_deassert_reset, .soft_reset_halt = adapter_soft_reset_halt, .halt = adapter_halt, .resume = adapter_resume, .step = adapter_step, .get_gdb_reg_list = armv7m_get_gdb_reg_list, .read_memory = adapter_read_memory, .write_memory = adapter_write_memory, .checksum_memory = armv7m_checksum_memory, .blank_check_memory = armv7m_blank_check_memory, .run_algorithm = armv7m_run_algorithm, .start_algorithm = armv7m_start_algorithm, .wait_algorithm = armv7m_wait_algorithm, .add_breakpoint = cortex_m3_add_breakpoint, .remove_breakpoint = cortex_m3_remove_breakpoint, .add_watchpoint = cortex_m3_add_watchpoint, .remove_watchpoint = cortex_m3_remove_watchpoint, }; openocd-0.7.0/src/target/target_type.h0000644000175000001440000002501112137151331014633 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef TARGET_TYPE_H #define TARGET_TYPE_H #include struct target; /** * This holds methods shared between all instances of a given target * type. For example, all Cortex-M3 targets on a scan chain share * the same method table. */ struct target_type { /** * Name of this type of target. Do @b not access this * field directly, use target_type_name() instead. */ const char *name; const char *deprecated_name; /* poll current target status */ int (*poll)(struct target *target); /* Invoked only from target_arch_state(). * Issue USER() w/architecture specific status. */ int (*arch_state)(struct target *target); /* target request support */ int (*target_request_data)(struct target *target, uint32_t size, uint8_t *buffer); /* halt will log a warning, but return ERROR_OK if the target is already halted. */ int (*halt)(struct target *target); int (*resume)(struct target *target, int current, uint32_t address, int handle_breakpoints, int debug_execution); int (*step)(struct target *target, int current, uint32_t address, int handle_breakpoints); /* target reset control. assert reset can be invoked when OpenOCD and * the target is out of sync. * * A typical example is that the target was power cycled while OpenOCD * thought the target was halted or running. * * assert_reset() can therefore make no assumptions whatsoever about the * state of the target * * Before assert_reset() for the target is invoked, a TRST/tms and * chain validation is executed. TRST should not be asserted * during target assert unless there is no way around it due to * the way reset's are configured. * */ int (*assert_reset)(struct target *target); /** * The implementation is responsible for polling the * target such that target->state reflects the * state correctly. * * Otherwise the following would fail, as there will not * be any "poll" invoked inbetween the "reset run" and * "halt". * * reset run; halt */ int (*deassert_reset)(struct target *target); int (*soft_reset_halt)(struct target *target); /** * Target register access for GDB. Do @b not call this function * directly, use target_get_gdb_reg_list() instead. * * Danger! this function will succeed even if the target is running * and return a register list with dummy values. * * The reason is that GDB connection will fail without a valid register * list, however it is after GDB is connected that monitor commands can * be run to properly initialize the target */ int (*get_gdb_reg_list)(struct target *target, struct reg **reg_list[], int *reg_list_size); /* target memory access * size: 1 = byte (8bit), 2 = half-word (16bit), 4 = word (32bit) * count: number of items of */ /** * Target memory read callback. Do @b not call this function * directly, use target_read_memory() instead. */ int (*read_memory)(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer); /** * Target memory write callback. Do @b not call this function * directly, use target_write_memory() instead. */ int (*write_memory)(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer); /* Default implementation will do some fancy alignment to improve performance, target can override */ int (*read_buffer)(struct target *target, uint32_t address, uint32_t size, uint8_t *buffer); /* Default implementation will do some fancy alignment to improve performance, target can override */ int (*write_buffer)(struct target *target, uint32_t address, uint32_t size, const uint8_t *buffer); /** * Write target memory in multiples of 4 bytes, optimized for * writing large quantities of data. Do @b not call this * function directly, use target_bulk_write_memory() instead. */ int (*bulk_write_memory)(struct target *target, uint32_t address, uint32_t count, const uint8_t *buffer); int (*checksum_memory)(struct target *target, uint32_t address, uint32_t count, uint32_t *checksum); int (*blank_check_memory)(struct target *target, uint32_t address, uint32_t count, uint32_t *blank); /* * target break-/watchpoint control * rw: 0 = write, 1 = read, 2 = access * * Target must be halted while this is invoked as this * will actually set up breakpoints on target. * * The breakpoint hardware will be set up upon adding the * first breakpoint. * * Upon GDB connection all breakpoints/watchpoints are cleared. */ int (*add_breakpoint)(struct target *target, struct breakpoint *breakpoint); int (*add_context_breakpoint)(struct target *target, struct breakpoint *breakpoint); int (*add_hybrid_breakpoint)(struct target *target, struct breakpoint *breakpoint); /* remove breakpoint. hw will only be updated if the target * is currently halted. * However, this method can be invoked on unresponsive targets. */ int (*remove_breakpoint)(struct target *target, struct breakpoint *breakpoint); /* add watchpoint ... see add_breakpoint() comment above. */ int (*add_watchpoint)(struct target *target, struct watchpoint *watchpoint); /* remove watchpoint. hw will only be updated if the target * is currently halted. * However, this method can be invoked on unresponsive targets. */ int (*remove_watchpoint)(struct target *target, struct watchpoint *watchpoint); /** * Target algorithm support. Do @b not call this method directly, * use target_run_algorithm() instead. */ int (*run_algorithm)(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_param, uint32_t entry_point, uint32_t exit_point, int timeout_ms, void *arch_info); int (*start_algorithm)(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_param, uint32_t entry_point, uint32_t exit_point, void *arch_info); int (*wait_algorithm)(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_param, uint32_t exit_point, int timeout_ms, void *arch_info); const struct command_registration *commands; /* called when target is created */ int (*target_create)(struct target *target, Jim_Interp *interp); /* called for various config parameters */ /* returns JIM_CONTINUE - if option not understood */ /* otherwise: JIM_OK, or JIM_ERR, */ int (*target_jim_configure)(struct target *target, Jim_GetOptInfo *goi); /* target commands specifically handled by the target */ /* returns JIM_OK, or JIM_ERR, or JIM_CONTINUE - if option not understood */ int (*target_jim_commands)(struct target *target, Jim_GetOptInfo *goi); /** * This method is used to perform target setup that requires * JTAG access. * * This may be called multiple times. It is called after the * scan chain is initially validated, or later after the target * is enabled by a JRC. It may also be called during some * parts of the reset sequence. * * For one-time initialization tasks, use target_was_examined() * and target_set_examined(). For example, probe the hardware * before setting up chip-specific state, and then set that * flag so you don't do that again. */ int (*examine)(struct target *target); /* Set up structures for target. * * It is illegal to talk to the target at this stage as this fn is invoked * before the JTAG chain has been examined/verified * */ int (*init_target)(struct command_context *cmd_ctx, struct target *target); /* translate from virtual to physical address. Default implementation is successful * no-op(i.e. virtual==physical). */ int (*virt2phys)(struct target *target, uint32_t address, uint32_t *physical); /* read directly from physical memory. caches are bypassed and untouched. * * If the target does not support disabling caches, leaving them untouched, * then minimally the actual physical memory location will be read even * if cache states are unchanged, flushed, etc. * * Default implementation is to call read_memory. */ int (*read_phys_memory)(struct target *target, uint32_t phys_address, uint32_t size, uint32_t count, uint8_t *buffer); /* * same as read_phys_memory, except that it writes... */ int (*write_phys_memory)(struct target *target, uint32_t phys_address, uint32_t size, uint32_t count, const uint8_t *buffer); int (*mmu)(struct target *target, int *enabled); /* after reset is complete, the target can check if things are properly set up. * * This can be used to check if e.g. DCC memory writes have been enabled for * arm7/9 targets, which they really should except in the most contrived * circumstances. */ int (*check_reset)(struct target *target); }; #endif /* TARGET_TYPE_H */ openocd-0.7.0/src/target/armv7m.c0000644000175000001440000006017612137151331013523 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2006 by Magnus Lundin * * lundin@mlu.mine.nu * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * * * * ARMv7-M Architecture, Application Level Reference Manual * * ARM DDI 0405C (September 2008) * * * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "breakpoints.h" #include "armv7m.h" #include "algorithm.h" #include "register.h" #if 0 #define _DEBUG_INSTRUCTION_EXECUTION_ #endif static char *armv7m_exception_strings[] = { "", "Reset", "NMI", "HardFault", "MemManage", "BusFault", "UsageFault", "RESERVED", "RESERVED", "RESERVED", "RESERVED", "SVCall", "DebugMonitor", "RESERVED", "PendSV", "SysTick" }; /* PSP is used in some thread modes */ const int armv7m_psp_reg_map[17] = { ARMV7M_R0, ARMV7M_R1, ARMV7M_R2, ARMV7M_R3, ARMV7M_R4, ARMV7M_R5, ARMV7M_R6, ARMV7M_R7, ARMV7M_R8, ARMV7M_R9, ARMV7M_R10, ARMV7M_R11, ARMV7M_R12, ARMV7M_PSP, ARMV7M_R14, ARMV7M_PC, ARMV7M_xPSR, }; /* MSP is used in handler and some thread modes */ const int armv7m_msp_reg_map[17] = { ARMV7M_R0, ARMV7M_R1, ARMV7M_R2, ARMV7M_R3, ARMV7M_R4, ARMV7M_R5, ARMV7M_R6, ARMV7M_R7, ARMV7M_R8, ARMV7M_R9, ARMV7M_R10, ARMV7M_R11, ARMV7M_R12, ARMV7M_MSP, ARMV7M_R14, ARMV7M_PC, ARMV7M_xPSR, }; #ifdef ARMV7_GDB_HACKS uint8_t armv7m_gdb_dummy_cpsr_value[] = {0, 0, 0, 0}; struct reg armv7m_gdb_dummy_cpsr_reg = { .name = "GDB dummy cpsr register", .value = armv7m_gdb_dummy_cpsr_value, .dirty = 0, .valid = 1, .size = 32, .arch_info = NULL, }; #endif /* * These registers are not memory-mapped. The ARMv7-M profile includes * memory mapped registers too, such as for the NVIC (interrupt controller) * and SysTick (timer) modules; those can mostly be treated as peripherals. * * The ARMv6-M profile is almost identical in this respect, except that it * doesn't include basepri or faultmask registers. */ static const struct { unsigned id; const char *name; unsigned bits; } armv7m_regs[] = { { ARMV7M_R0, "r0", 32 }, { ARMV7M_R1, "r1", 32 }, { ARMV7M_R2, "r2", 32 }, { ARMV7M_R3, "r3", 32 }, { ARMV7M_R4, "r4", 32 }, { ARMV7M_R5, "r5", 32 }, { ARMV7M_R6, "r6", 32 }, { ARMV7M_R7, "r7", 32 }, { ARMV7M_R8, "r8", 32 }, { ARMV7M_R9, "r9", 32 }, { ARMV7M_R10, "r10", 32 }, { ARMV7M_R11, "r11", 32 }, { ARMV7M_R12, "r12", 32 }, { ARMV7M_R13, "sp", 32 }, { ARMV7M_R14, "lr", 32 }, { ARMV7M_PC, "pc", 32 }, { ARMV7M_xPSR, "xPSR", 32 }, { ARMV7M_MSP, "msp", 32 }, { ARMV7M_PSP, "psp", 32 }, { ARMV7M_PRIMASK, "primask", 1 }, { ARMV7M_BASEPRI, "basepri", 8 }, { ARMV7M_FAULTMASK, "faultmask", 1 }, { ARMV7M_CONTROL, "control", 2 }, }; #define ARMV7M_NUM_REGS ARRAY_SIZE(armv7m_regs) /** * Restores target context using the cache of core registers set up * by armv7m_build_reg_cache(), calling optional core-specific hooks. */ int armv7m_restore_context(struct target *target) { int i; struct armv7m_common *armv7m = target_to_armv7m(target); struct reg_cache *cache = armv7m->arm.core_cache; LOG_DEBUG(" "); if (armv7m->pre_restore_context) armv7m->pre_restore_context(target); for (i = ARMV7M_NUM_REGS - 1; i >= 0; i--) { if (cache->reg_list[i].dirty) { uint32_t value = buf_get_u32(cache->reg_list[i].value, 0, 32); armv7m->arm.write_core_reg(target, &cache->reg_list[i], i, ARM_MODE_ANY, value); } } return ERROR_OK; } /* Core state functions */ /** * Maps ISR number (from xPSR) to name. * Note that while names and meanings for the first sixteen are standardized * (with zero not a true exception), external interrupts are only numbered. * They are assigned by vendors, which generally assign different numbers to * peripherals (such as UART0 or a USB peripheral controller). */ char *armv7m_exception_string(int number) { static char enamebuf[32]; if ((number < 0) | (number > 511)) return "Invalid exception"; if (number < 16) return armv7m_exception_strings[number]; sprintf(enamebuf, "External Interrupt(%i)", number - 16); return enamebuf; } static int armv7m_get_core_reg(struct reg *reg) { int retval; struct arm_reg *armv7m_reg = reg->arch_info; struct target *target = armv7m_reg->target; struct arm *arm = target_to_arm(target); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; retval = arm->read_core_reg(target, reg, armv7m_reg->num, arm->core_mode); return retval; } static int armv7m_set_core_reg(struct reg *reg, uint8_t *buf) { struct arm_reg *armv7m_reg = reg->arch_info; struct target *target = armv7m_reg->target; uint32_t value = buf_get_u32(buf, 0, 32); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; buf_set_u32(reg->value, 0, 32, value); reg->dirty = 1; reg->valid = 1; return ERROR_OK; } static int armv7m_read_core_reg(struct target *target, struct reg *r, int num, enum arm_mode mode) { uint32_t reg_value; int retval; struct arm_reg *armv7m_core_reg; struct armv7m_common *armv7m = target_to_armv7m(target); assert(num < (int)armv7m->arm.core_cache->num_regs); armv7m_core_reg = armv7m->arm.core_cache->reg_list[num].arch_info; retval = armv7m->load_core_reg_u32(target, armv7m_core_reg->num, ®_value); buf_set_u32(armv7m->arm.core_cache->reg_list[num].value, 0, 32, reg_value); armv7m->arm.core_cache->reg_list[num].valid = 1; armv7m->arm.core_cache->reg_list[num].dirty = 0; return retval; } static int armv7m_write_core_reg(struct target *target, struct reg *r, int num, enum arm_mode mode, uint32_t value) { int retval; uint32_t reg_value; struct arm_reg *armv7m_core_reg; struct armv7m_common *armv7m = target_to_armv7m(target); assert(num < (int)armv7m->arm.core_cache->num_regs); reg_value = buf_get_u32(armv7m->arm.core_cache->reg_list[num].value, 0, 32); armv7m_core_reg = armv7m->arm.core_cache->reg_list[num].arch_info; retval = armv7m->store_core_reg_u32(target, armv7m_core_reg->num, reg_value); if (retval != ERROR_OK) { LOG_ERROR("JTAG failure"); armv7m->arm.core_cache->reg_list[num].dirty = armv7m->arm.core_cache->reg_list[num].valid; return ERROR_JTAG_DEVICE_ERROR; } LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num, reg_value); armv7m->arm.core_cache->reg_list[num].valid = 1; armv7m->arm.core_cache->reg_list[num].dirty = 0; return ERROR_OK; } /** * Returns generic ARM userspace registers to GDB. * GDB doesn't quite understand that most ARMs don't have floating point * hardware, so this also fakes a set of long-obsolete FPA registers that * are not used in EABI based software stacks. */ int armv7m_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size) { struct armv7m_common *armv7m = target_to_armv7m(target); int i; *reg_list_size = 26; *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); /* * GDB register packet format for ARM: * - the first 16 registers are r0..r15 * - (obsolete) 8 FPA registers * - (obsolete) FPA status * - CPSR */ for (i = 0; i < 16; i++) (*reg_list)[i] = &armv7m->arm.core_cache->reg_list[i]; for (i = 16; i < 24; i++) (*reg_list)[i] = &arm_gdb_dummy_fp_reg; (*reg_list)[24] = &arm_gdb_dummy_fps_reg; #ifdef ARMV7_GDB_HACKS /* use dummy cpsr reg otherwise gdb may try and set the thumb bit */ (*reg_list)[25] = &armv7m_gdb_dummy_cpsr_reg; /* ARMV7M is always in thumb mode, try to make GDB understand this * if it does not support this arch */ *((char *)armv7m->arm.pc->value) |= 1; #else (*reg_list)[25] = &armv7m->arm.core_cache->reg_list[ARMV7M_xPSR]; #endif return ERROR_OK; } /** Runs a Thumb algorithm in the target. */ int armv7m_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, uint32_t entry_point, uint32_t exit_point, int timeout_ms, void *arch_info) { int retval; retval = armv7m_start_algorithm(target, num_mem_params, mem_params, num_reg_params, reg_params, entry_point, exit_point, arch_info); if (retval == ERROR_OK) retval = armv7m_wait_algorithm(target, num_mem_params, mem_params, num_reg_params, reg_params, exit_point, timeout_ms, arch_info); return retval; } /** Starts a Thumb algorithm in the target. */ int armv7m_start_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, uint32_t entry_point, uint32_t exit_point, void *arch_info) { struct armv7m_common *armv7m = target_to_armv7m(target); struct armv7m_algorithm *armv7m_algorithm_info = arch_info; enum arm_mode core_mode = armv7m->arm.core_mode; int retval = ERROR_OK; /* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint * at the exit point */ if (armv7m_algorithm_info->common_magic != ARMV7M_COMMON_MAGIC) { LOG_ERROR("current target isn't an ARMV7M target"); return ERROR_TARGET_INVALID; } if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* refresh core register cache * Not needed if core register cache is always consistent with target process state */ for (unsigned i = 0; i < ARMV7M_NUM_REGS; i++) { armv7m_algorithm_info->context[i] = buf_get_u32( armv7m->arm.core_cache->reg_list[i].value, 0, 32); } for (int i = 0; i < num_mem_params; i++) { /* TODO: Write only out params */ retval = target_write_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value); if (retval != ERROR_OK) return retval; } for (int i = 0; i < num_reg_params; i++) { struct reg *reg = register_get_by_name(armv7m->arm.core_cache, reg_params[i].reg_name, 0); /* uint32_t regvalue; */ if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } if (reg->size != reg_params[i].size) { LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } /* regvalue = buf_get_u32(reg_params[i].value, 0, 32); */ armv7m_set_core_reg(reg, reg_params[i].value); } if (armv7m_algorithm_info->core_mode != ARM_MODE_ANY && armv7m_algorithm_info->core_mode != core_mode) { /* we cannot set ARM_MODE_HANDLER, so use ARM_MODE_THREAD instead */ if (armv7m_algorithm_info->core_mode == ARM_MODE_HANDLER) { armv7m_algorithm_info->core_mode = ARM_MODE_THREAD; LOG_INFO("ARM_MODE_HANDLER not currently supported, using ARM_MODE_THREAD instead"); } LOG_DEBUG("setting core_mode: 0x%2.2x", armv7m_algorithm_info->core_mode); buf_set_u32(armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].value, 0, 1, armv7m_algorithm_info->core_mode); armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].dirty = 1; armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].valid = 1; } /* save previous core mode */ armv7m_algorithm_info->core_mode = core_mode; retval = target_resume(target, 0, entry_point, 1, 1); return retval; } /** Waits for an algorithm in the target. */ int armv7m_wait_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, uint32_t exit_point, int timeout_ms, void *arch_info) { struct armv7m_common *armv7m = target_to_armv7m(target); struct armv7m_algorithm *armv7m_algorithm_info = arch_info; int retval = ERROR_OK; uint32_t pc; /* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint * at the exit point */ if (armv7m_algorithm_info->common_magic != ARMV7M_COMMON_MAGIC) { LOG_ERROR("current target isn't an ARMV7M target"); return ERROR_TARGET_INVALID; } retval = target_wait_state(target, TARGET_HALTED, timeout_ms); /* If the target fails to halt due to the breakpoint, force a halt */ if (retval != ERROR_OK || target->state != TARGET_HALTED) { retval = target_halt(target); if (retval != ERROR_OK) return retval; retval = target_wait_state(target, TARGET_HALTED, 500); if (retval != ERROR_OK) return retval; return ERROR_TARGET_TIMEOUT; } armv7m->load_core_reg_u32(target, 15, &pc); if (exit_point && (pc != exit_point)) { LOG_DEBUG("failed algorithm halted at 0x%" PRIx32 ", expected 0x%" PRIx32, pc, exit_point); return ERROR_TARGET_TIMEOUT; } /* Read memory values to mem_params[] */ for (int i = 0; i < num_mem_params; i++) { if (mem_params[i].direction != PARAM_OUT) { retval = target_read_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value); if (retval != ERROR_OK) return retval; } } /* Copy core register values to reg_params[] */ for (int i = 0; i < num_reg_params; i++) { if (reg_params[i].direction != PARAM_OUT) { struct reg *reg = register_get_by_name(armv7m->arm.core_cache, reg_params[i].reg_name, 0); if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } if (reg->size != reg_params[i].size) { LOG_ERROR( "BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } buf_set_u32(reg_params[i].value, 0, 32, buf_get_u32(reg->value, 0, 32)); } } for (int i = ARMV7M_NUM_REGS - 1; i >= 0; i--) { uint32_t regvalue; regvalue = buf_get_u32(armv7m->arm.core_cache->reg_list[i].value, 0, 32); if (regvalue != armv7m_algorithm_info->context[i]) { LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32, armv7m->arm.core_cache->reg_list[i].name, armv7m_algorithm_info->context[i]); buf_set_u32(armv7m->arm.core_cache->reg_list[i].value, 0, 32, armv7m_algorithm_info->context[i]); armv7m->arm.core_cache->reg_list[i].valid = 1; armv7m->arm.core_cache->reg_list[i].dirty = 1; } } /* restore previous core mode */ if (armv7m_algorithm_info->core_mode != armv7m->arm.core_mode) { LOG_DEBUG("restoring core_mode: 0x%2.2x", armv7m_algorithm_info->core_mode); buf_set_u32(armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].value, 0, 1, armv7m_algorithm_info->core_mode); armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].dirty = 1; armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].valid = 1; } armv7m->arm.core_mode = armv7m_algorithm_info->core_mode; return retval; } /** Logs summary of ARMv7-M state for a halted target. */ int armv7m_arch_state(struct target *target) { struct armv7m_common *armv7m = target_to_armv7m(target); struct arm *arm = &armv7m->arm; uint32_t ctrl, sp; ctrl = buf_get_u32(arm->core_cache->reg_list[ARMV7M_CONTROL].value, 0, 32); sp = buf_get_u32(arm->core_cache->reg_list[ARMV7M_R13].value, 0, 32); LOG_USER("target halted due to %s, current mode: %s %s\n" "xPSR: %#8.8" PRIx32 " pc: %#8.8" PRIx32 " %csp: %#8.8" PRIx32 "%s", debug_reason_name(target), arm_mode_name(arm->core_mode), armv7m_exception_string(armv7m->exception_number), buf_get_u32(arm->cpsr->value, 0, 32), buf_get_u32(arm->pc->value, 0, 32), (ctrl & 0x02) ? 'p' : 'm', sp, arm->is_semihosting ? ", semihosting" : ""); return ERROR_OK; } static const struct reg_arch_type armv7m_reg_type = { .get = armv7m_get_core_reg, .set = armv7m_set_core_reg, }; /** Builds cache of architecturally defined registers. */ struct reg_cache *armv7m_build_reg_cache(struct target *target) { struct armv7m_common *armv7m = target_to_armv7m(target); struct arm *arm = &armv7m->arm; int num_regs = ARMV7M_NUM_REGS; struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); struct reg_cache *cache = malloc(sizeof(struct reg_cache)); struct reg *reg_list = calloc(num_regs, sizeof(struct reg)); struct arm_reg *arch_info = calloc(num_regs, sizeof(struct arm_reg)); int i; #ifdef ARMV7_GDB_HACKS register_init_dummy(&armv7m_gdb_dummy_cpsr_reg); #endif /* Build the process context cache */ cache->name = "arm v7m registers"; cache->next = NULL; cache->reg_list = reg_list; cache->num_regs = num_regs; (*cache_p) = cache; for (i = 0; i < num_regs; i++) { arch_info[i].num = armv7m_regs[i].id; arch_info[i].target = target; arch_info[i].arm = arm; reg_list[i].name = armv7m_regs[i].name; reg_list[i].size = armv7m_regs[i].bits; reg_list[i].value = calloc(1, 4); reg_list[i].dirty = 0; reg_list[i].valid = 0; reg_list[i].type = &armv7m_reg_type; reg_list[i].arch_info = &arch_info[i]; } arm->cpsr = reg_list + ARMV7M_xPSR; arm->pc = reg_list + ARMV7M_PC; arm->core_cache = cache; return cache; } static int armv7m_setup_semihosting(struct target *target, int enable) { /* nothing todo for armv7m */ return ERROR_OK; } /** Sets up target as a generic ARMv7-M core */ int armv7m_init_arch_info(struct target *target, struct armv7m_common *armv7m) { struct arm *arm = &armv7m->arm; armv7m->common_magic = ARMV7M_COMMON_MAGIC; armv7m->fp_feature = FP_NONE; arm->core_type = ARM_MODE_THREAD; arm->arch_info = armv7m; arm->setup_semihosting = armv7m_setup_semihosting; arm->read_core_reg = armv7m_read_core_reg; arm->write_core_reg = armv7m_write_core_reg; return arm_init_arch_info(target, arm); } /** Generates a CRC32 checksum of a memory region. */ int armv7m_checksum_memory(struct target *target, uint32_t address, uint32_t count, uint32_t *checksum) { struct working_area *crc_algorithm; struct armv7m_algorithm armv7m_info; struct reg_param reg_params[2]; int retval; /* see contrib/loaders/checksum/armv7m_crc.s for src */ static const uint8_t cortex_m3_crc_code[] = { /* main: */ 0x02, 0x46, /* mov r2, r0 */ 0x00, 0x20, /* movs r0, #0 */ 0xC0, 0x43, /* mvns r0, r0 */ 0x0A, 0x4E, /* ldr r6, CRC32XOR */ 0x0B, 0x46, /* mov r3, r1 */ 0x00, 0x24, /* movs r4, #0 */ 0x0D, 0xE0, /* b ncomp */ /* nbyte: */ 0x11, 0x5D, /* ldrb r1, [r2, r4] */ 0x09, 0x06, /* lsls r1, r1, #24 */ 0x48, 0x40, /* eors r0, r0, r1 */ 0x00, 0x25, /* movs r5, #0 */ /* loop: */ 0x00, 0x28, /* cmp r0, #0 */ 0x02, 0xDA, /* bge notset */ 0x40, 0x00, /* lsls r0, r0, #1 */ 0x70, 0x40, /* eors r0, r0, r6 */ 0x00, 0xE0, /* b cont */ /* notset: */ 0x40, 0x00, /* lsls r0, r0, #1 */ /* cont: */ 0x01, 0x35, /* adds r5, r5, #1 */ 0x08, 0x2D, /* cmp r5, #8 */ 0xF6, 0xD1, /* bne loop */ 0x01, 0x34, /* adds r4, r4, #1 */ /* ncomp: */ 0x9C, 0x42, /* cmp r4, r3 */ 0xEF, 0xD1, /* bne nbyte */ 0x00, 0xBE, /* bkpt #0 */ 0xB7, 0x1D, 0xC1, 0x04 /* CRC32XOR: .word 0x04c11db7 */ }; retval = target_alloc_working_area(target, sizeof(cortex_m3_crc_code), &crc_algorithm); if (retval != ERROR_OK) return retval; retval = target_write_buffer(target, crc_algorithm->address, sizeof(cortex_m3_crc_code), (uint8_t *)cortex_m3_crc_code); if (retval != ERROR_OK) goto cleanup; armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); buf_set_u32(reg_params[1].value, 0, 32, count); int timeout = 20000 * (1 + (count / (1024 * 1024))); retval = target_run_algorithm(target, 0, NULL, 2, reg_params, crc_algorithm->address, crc_algorithm->address + (sizeof(cortex_m3_crc_code) - 6), timeout, &armv7m_info); if (retval == ERROR_OK) *checksum = buf_get_u32(reg_params[0].value, 0, 32); else LOG_ERROR("error executing cortex_m3 crc algorithm"); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); cleanup: target_free_working_area(target, crc_algorithm); return retval; } /** Checks whether a memory region is zeroed. */ int armv7m_blank_check_memory(struct target *target, uint32_t address, uint32_t count, uint32_t *blank) { struct working_area *erase_check_algorithm; struct reg_param reg_params[3]; struct armv7m_algorithm armv7m_info; int retval; /* see contrib/loaders/erase_check/armv7m_erase_check.s for src */ static const uint8_t erase_check_code[] = { /* loop: */ 0x03, 0x78, /* ldrb r3, [r0] */ 0x01, 0x30, /* adds r0, #1 */ 0x1A, 0x40, /* ands r2, r2, r3 */ 0x01, 0x39, /* subs r1, r1, #1 */ 0xFA, 0xD1, /* bne loop */ 0x00, 0xBE /* bkpt #0 */ }; /* make sure we have a working area */ if (target_alloc_working_area(target, sizeof(erase_check_code), &erase_check_algorithm) != ERROR_OK) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; retval = target_write_buffer(target, erase_check_algorithm->address, sizeof(erase_check_code), (uint8_t *)erase_check_code); if (retval != ERROR_OK) return retval; armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); buf_set_u32(reg_params[1].value, 0, 32, count); init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT); buf_set_u32(reg_params[2].value, 0, 32, 0xff); retval = target_run_algorithm(target, 0, NULL, 3, reg_params, erase_check_algorithm->address, erase_check_algorithm->address + (sizeof(erase_check_code) - 2), 10000, &armv7m_info); if (retval == ERROR_OK) *blank = buf_get_u32(reg_params[2].value, 0, 32); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); target_free_working_area(target, erase_check_algorithm); return retval; } int armv7m_maybe_skip_bkpt_inst(struct target *target, bool *inst_found) { struct armv7m_common *armv7m = target_to_armv7m(target); struct reg *r = armv7m->arm.pc; bool result = false; /* if we halted last time due to a bkpt instruction * then we have to manually step over it, otherwise * the core will break again */ if (target->debug_reason == DBG_REASON_BREAKPOINT) { uint16_t op; uint32_t pc = buf_get_u32(r->value, 0, 32); pc &= ~1; if (target_read_u16(target, pc, &op) == ERROR_OK) { if ((op & 0xFF00) == 0xBE00) { pc = buf_get_u32(r->value, 0, 32) + 2; buf_set_u32(r->value, 0, 32, pc); r->dirty = true; r->valid = true; result = true; LOG_DEBUG("Skipping over BKPT instruction"); } } } if (inst_found) *inst_found = result; return ERROR_OK; } const struct command_registration armv7m_command_handlers[] = { { .chain = arm_command_handlers, }, { .chain = dap_command_handlers, }, COMMAND_REGISTRATION_DONE }; openocd-0.7.0/src/target/arm_simulator.c0000644000175000001440000005163412134336410015167 00000000000000/*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Hongtao Zheng * * hontor@126.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm.h" #include "armv4_5.h" #include "arm_disassembler.h" #include "arm_simulator.h" #include #include "register.h" #include static uint32_t arm_shift(uint8_t shift, uint32_t Rm, uint32_t shift_amount, uint8_t *carry) { uint32_t return_value = 0; shift_amount &= 0xff; if (shift == 0x0) { /* LSL */ if ((shift_amount > 0) && (shift_amount <= 32)) { return_value = Rm << shift_amount; *carry = Rm >> (32 - shift_amount); } else if (shift_amount > 32) { return_value = 0x0; *carry = 0x0; } else /* (shift_amount == 0) */ return_value = Rm; } else if (shift == 0x1) { /* LSR */ if ((shift_amount > 0) && (shift_amount <= 32)) { return_value = Rm >> shift_amount; *carry = (Rm >> (shift_amount - 1)) & 1; } else if (shift_amount > 32) { return_value = 0x0; *carry = 0x0; } else /* (shift_amount == 0) */ return_value = Rm; } else if (shift == 0x2) { /* ASR */ if ((shift_amount > 0) && (shift_amount <= 32)) { /* C right shifts of unsigned values are guaranteed to * be logical (shift in zeroes); simulate an arithmetic * shift (shift in signed-bit) by adding the sign bit * manually */ return_value = Rm >> shift_amount; if (Rm & 0x80000000) return_value |= 0xffffffff << (32 - shift_amount); } else if (shift_amount > 32) { if (Rm & 0x80000000) { return_value = 0xffffffff; *carry = 0x1; } else { return_value = 0x0; *carry = 0x0; } } else /* (shift_amount == 0) */ return_value = Rm; } else if (shift == 0x3) { /* ROR */ if (shift_amount == 0) return_value = Rm; else { shift_amount = shift_amount % 32; return_value = (Rm >> shift_amount) | (Rm << (32 - shift_amount)); *carry = (return_value >> 31) & 0x1; } } else if (shift == 0x4) { /* RRX */ return_value = Rm >> 1; if (*carry) Rm |= 0x80000000; *carry = Rm & 0x1; } return return_value; } static uint32_t arm_shifter_operand(struct arm_sim_interface *sim, int variant, union arm_shifter_operand shifter_operand, uint8_t *shifter_carry_out) { uint32_t return_value; int instruction_size; if (sim->get_state(sim) == ARM_STATE_ARM) instruction_size = 4; else instruction_size = 2; *shifter_carry_out = sim->get_cpsr(sim, 29, 1); if (variant == 0) /* 32-bit immediate */ return_value = shifter_operand.immediate.immediate; else if (variant == 1) {/* immediate shift */ uint32_t Rm = sim->get_reg_mode(sim, shifter_operand.immediate_shift.Rm); /* adjust RM in case the PC is being read */ if (shifter_operand.immediate_shift.Rm == 15) Rm += 2 * instruction_size; return_value = arm_shift(shifter_operand.immediate_shift.shift, Rm, shifter_operand.immediate_shift.shift_imm, shifter_carry_out); } else if (variant == 2) { /* register shift */ uint32_t Rm = sim->get_reg_mode(sim, shifter_operand.register_shift.Rm); uint32_t Rs = sim->get_reg_mode(sim, shifter_operand.register_shift.Rs); /* adjust RM in case the PC is being read */ if (shifter_operand.register_shift.Rm == 15) Rm += 2 * instruction_size; return_value = arm_shift(shifter_operand.immediate_shift.shift, Rm, Rs, shifter_carry_out); } else { LOG_ERROR("BUG: shifter_operand.variant not 0, 1 or 2"); return_value = 0xffffffff; } return return_value; } static int pass_condition(uint32_t cpsr, uint32_t opcode) { switch ((opcode & 0xf0000000) >> 28) { case 0x0: /* EQ */ if (cpsr & 0x40000000) return 1; else return 0; case 0x1: /* NE */ if (!(cpsr & 0x40000000)) return 1; else return 0; case 0x2: /* CS */ if (cpsr & 0x20000000) return 1; else return 0; case 0x3: /* CC */ if (!(cpsr & 0x20000000)) return 1; else return 0; case 0x4: /* MI */ if (cpsr & 0x80000000) return 1; else return 0; case 0x5: /* PL */ if (!(cpsr & 0x80000000)) return 1; else return 0; case 0x6: /* VS */ if (cpsr & 0x10000000) return 1; else return 0; case 0x7: /* VC */ if (!(cpsr & 0x10000000)) return 1; else return 0; case 0x8: /* HI */ if ((cpsr & 0x20000000) && !(cpsr & 0x40000000)) return 1; else return 0; case 0x9: /* LS */ if (!(cpsr & 0x20000000) || (cpsr & 0x40000000)) return 1; else return 0; case 0xa: /* GE */ if (((cpsr & 0x80000000) && (cpsr & 0x10000000)) || (!(cpsr & 0x80000000) && !(cpsr & 0x10000000))) return 1; else return 0; case 0xb: /* LT */ if (((cpsr & 0x80000000) && !(cpsr & 0x10000000)) || (!(cpsr & 0x80000000) && (cpsr & 0x10000000))) return 1; else return 0; case 0xc: /* GT */ if (!(cpsr & 0x40000000) && (((cpsr & 0x80000000) && (cpsr & 0x10000000)) || (!(cpsr & 0x80000000) && !(cpsr & 0x10000000)))) return 1; else return 0; case 0xd: /* LE */ if ((cpsr & 0x40000000) || ((cpsr & 0x80000000) && !(cpsr & 0x10000000)) || (!(cpsr & 0x80000000) && (cpsr & 0x10000000))) return 1; else return 0; case 0xe: case 0xf: return 1; } LOG_ERROR("BUG: should never get here"); return 0; } static int thumb_pass_branch_condition(uint32_t cpsr, uint16_t opcode) { return pass_condition(cpsr, (opcode & 0x0f00) << 20); } /* simulate a single step (if possible) * if the dry_run_pc argument is provided, no state is changed, * but the new pc is stored in the variable pointed at by the argument */ static int arm_simulate_step_core(struct target *target, uint32_t *dry_run_pc, struct arm_sim_interface *sim) { uint32_t current_pc = sim->get_reg(sim, 15); struct arm_instruction instruction; int instruction_size; int retval = ERROR_OK; if (sim->get_state(sim) == ARM_STATE_ARM) { uint32_t opcode; /* get current instruction, and identify it */ retval = target_read_u32(target, current_pc, &opcode); if (retval != ERROR_OK) return retval; retval = arm_evaluate_opcode(opcode, current_pc, &instruction); if (retval != ERROR_OK) return retval; instruction_size = 4; /* check condition code (for all instructions) */ if (!pass_condition(sim->get_cpsr(sim, 0, 32), opcode)) { if (dry_run_pc) *dry_run_pc = current_pc + instruction_size; else sim->set_reg(sim, 15, current_pc + instruction_size); return ERROR_OK; } } else { uint16_t opcode; retval = target_read_u16(target, current_pc, &opcode); if (retval != ERROR_OK) return retval; retval = thumb_evaluate_opcode(opcode, current_pc, &instruction); if (retval != ERROR_OK) return retval; instruction_size = 2; /* check condition code (only for branch (1) instructions) */ if ((opcode & 0xf000) == 0xd000 && !thumb_pass_branch_condition( sim->get_cpsr(sim, 0, 32), opcode)) { if (dry_run_pc) *dry_run_pc = current_pc + instruction_size; else sim->set_reg(sim, 15, current_pc + instruction_size); return ERROR_OK; } /* Deal with 32-bit BL/BLX */ if ((opcode & 0xf800) == 0xf000) { uint32_t high = instruction.info.b_bl_bx_blx.target_address; retval = target_read_u16(target, current_pc+2, &opcode); if (retval != ERROR_OK) return retval; retval = thumb_evaluate_opcode(opcode, current_pc, &instruction); if (retval != ERROR_OK) return retval; instruction.info.b_bl_bx_blx.target_address += high; } } /* examine instruction type */ /* branch instructions */ if ((instruction.type >= ARM_B) && (instruction.type <= ARM_BLX)) { uint32_t target_address; if (instruction.info.b_bl_bx_blx.reg_operand == -1) target_address = instruction.info.b_bl_bx_blx.target_address; else { target_address = sim->get_reg_mode(sim, instruction.info.b_bl_bx_blx.reg_operand); if (instruction.info.b_bl_bx_blx.reg_operand == 15) target_address += 2 * instruction_size; } if (dry_run_pc) { *dry_run_pc = target_address & ~1; return ERROR_OK; } else { if (instruction.type == ARM_B) sim->set_reg(sim, 15, target_address); else if (instruction.type == ARM_BL) { uint32_t old_pc = sim->get_reg(sim, 15); int T = (sim->get_state(sim) == ARM_STATE_THUMB); sim->set_reg_mode(sim, 14, old_pc + 4 + T); sim->set_reg(sim, 15, target_address); } else if (instruction.type == ARM_BX) { if (target_address & 0x1) sim->set_state(sim, ARM_STATE_THUMB); else sim->set_state(sim, ARM_STATE_ARM); sim->set_reg(sim, 15, target_address & 0xfffffffe); } else if (instruction.type == ARM_BLX) { uint32_t old_pc = sim->get_reg(sim, 15); int T = (sim->get_state(sim) == ARM_STATE_THUMB); sim->set_reg_mode(sim, 14, old_pc + 4 + T); if (target_address & 0x1) sim->set_state(sim, ARM_STATE_THUMB); else sim->set_state(sim, ARM_STATE_ARM); sim->set_reg(sim, 15, target_address & 0xfffffffe); } return ERROR_OK; } } /* data processing instructions, except compare instructions (CMP, CMN, TST, TEQ) */ else if (((instruction.type >= ARM_AND) && (instruction.type <= ARM_RSC)) || ((instruction.type >= ARM_ORR) && (instruction.type <= ARM_MVN))) { uint32_t Rd, Rn, shifter_operand; uint8_t C = sim->get_cpsr(sim, 29, 1); uint8_t carry_out; Rd = 0x0; /* ARM_MOV and ARM_MVN does not use Rn */ if ((instruction.type != ARM_MOV) && (instruction.type != ARM_MVN)) Rn = sim->get_reg_mode(sim, instruction.info.data_proc.Rn); else Rn = 0; shifter_operand = arm_shifter_operand(sim, instruction.info.data_proc.variant, instruction.info.data_proc.shifter_operand, &carry_out); /* adjust Rn in case the PC is being read */ if (instruction.info.data_proc.Rn == 15) Rn += 2 * instruction_size; if (instruction.type == ARM_AND) Rd = Rn & shifter_operand; else if (instruction.type == ARM_EOR) Rd = Rn ^ shifter_operand; else if (instruction.type == ARM_SUB) Rd = Rn - shifter_operand; else if (instruction.type == ARM_RSB) Rd = shifter_operand - Rn; else if (instruction.type == ARM_ADD) Rd = Rn + shifter_operand; else if (instruction.type == ARM_ADC) Rd = Rn + shifter_operand + (C & 1); else if (instruction.type == ARM_SBC) Rd = Rn - shifter_operand - (C & 1) ? 0 : 1; else if (instruction.type == ARM_RSC) Rd = shifter_operand - Rn - (C & 1) ? 0 : 1; else if (instruction.type == ARM_ORR) Rd = Rn | shifter_operand; else if (instruction.type == ARM_BIC) Rd = Rn & ~(shifter_operand); else if (instruction.type == ARM_MOV) Rd = shifter_operand; else if (instruction.type == ARM_MVN) Rd = ~shifter_operand; else LOG_WARNING("unhandled instruction type"); if (dry_run_pc) { if (instruction.info.data_proc.Rd == 15) *dry_run_pc = Rd & ~1; else *dry_run_pc = current_pc + instruction_size; return ERROR_OK; } else { if (instruction.info.data_proc.Rd == 15) { sim->set_reg_mode(sim, 15, Rd & ~1); if (Rd & 1) sim->set_state(sim, ARM_STATE_THUMB); else sim->set_state(sim, ARM_STATE_ARM); return ERROR_OK; } sim->set_reg_mode(sim, instruction.info.data_proc.Rd, Rd); LOG_WARNING("no updating of flags yet"); } } /* compare instructions (CMP, CMN, TST, TEQ) */ else if ((instruction.type >= ARM_TST) && (instruction.type <= ARM_CMN)) { if (dry_run_pc) { *dry_run_pc = current_pc + instruction_size; return ERROR_OK; } else LOG_WARNING("no updating of flags yet"); } /* load register instructions */ else if ((instruction.type >= ARM_LDR) && (instruction.type <= ARM_LDRSH)) { uint32_t load_address = 0, modified_address = 0, load_value = 0; uint32_t Rn = sim->get_reg_mode(sim, instruction.info.load_store.Rn); /* adjust Rn in case the PC is being read */ if (instruction.info.load_store.Rn == 15) Rn += 2 * instruction_size; if (instruction.info.load_store.offset_mode == 0) { if (instruction.info.load_store.U) modified_address = Rn + instruction.info.load_store.offset.offset; else modified_address = Rn - instruction.info.load_store.offset.offset; } else if (instruction.info.load_store.offset_mode == 1) { uint32_t offset; uint32_t Rm = sim->get_reg_mode(sim, instruction.info.load_store.offset.reg.Rm); uint8_t shift = instruction.info.load_store.offset.reg.shift; uint8_t shift_imm = instruction.info.load_store.offset.reg.shift_imm; uint8_t carry = sim->get_cpsr(sim, 29, 1); offset = arm_shift(shift, Rm, shift_imm, &carry); if (instruction.info.load_store.U) modified_address = Rn + offset; else modified_address = Rn - offset; } else LOG_ERROR("BUG: offset_mode neither 0 (offset) nor 1 (scaled register)"); if (instruction.info.load_store.index_mode == 0) { /* offset mode * we load from the modified address, but don't change * the base address register */ load_address = modified_address; modified_address = Rn; } else if (instruction.info.load_store.index_mode == 1) { /* pre-indexed mode * we load from the modified address, and write it * back to the base address register */ load_address = modified_address; } else if (instruction.info.load_store.index_mode == 2) { /* post-indexed mode * we load from the unmodified address, and write the * modified address back */ load_address = Rn; } if ((!dry_run_pc) || (instruction.info.load_store.Rd == 15)) { retval = target_read_u32(target, load_address, &load_value); if (retval != ERROR_OK) return retval; } if (dry_run_pc) { if (instruction.info.load_store.Rd == 15) *dry_run_pc = load_value & ~1; else *dry_run_pc = current_pc + instruction_size; return ERROR_OK; } else { if ((instruction.info.load_store.index_mode == 1) || (instruction.info.load_store.index_mode == 2)) sim->set_reg_mode(sim, instruction.info.load_store.Rn, modified_address); if (instruction.info.load_store.Rd == 15) { sim->set_reg_mode(sim, 15, load_value & ~1); if (load_value & 1) sim->set_state(sim, ARM_STATE_THUMB); else sim->set_state(sim, ARM_STATE_ARM); return ERROR_OK; } sim->set_reg_mode(sim, instruction.info.load_store.Rd, load_value); } } /* load multiple instruction */ else if (instruction.type == ARM_LDM) { int i; uint32_t Rn = sim->get_reg_mode(sim, instruction.info.load_store_multiple.Rn); uint32_t load_values[16]; int bits_set = 0; for (i = 0; i < 16; i++) { if (instruction.info.load_store_multiple.register_list & (1 << i)) bits_set++; } switch (instruction.info.load_store_multiple.addressing_mode) { case 0: /* Increment after */ /* Rn = Rn; */ break; case 1: /* Increment before */ Rn = Rn + 4; break; case 2: /* Decrement after */ Rn = Rn - (bits_set * 4) + 4; break; case 3: /* Decrement before */ Rn = Rn - (bits_set * 4); break; } for (i = 0; i < 16; i++) { if (instruction.info.load_store_multiple.register_list & (1 << i)) { if ((!dry_run_pc) || (i == 15)) target_read_u32(target, Rn, &load_values[i]); Rn += 4; } } if (dry_run_pc) { if (instruction.info.load_store_multiple.register_list & 0x8000) { *dry_run_pc = load_values[15] & ~1; return ERROR_OK; } } else { int update_cpsr = 0; if (instruction.info.load_store_multiple.S) { if (instruction.info.load_store_multiple.register_list & 0x8000) update_cpsr = 1; } for (i = 0; i < 16; i++) { if (instruction.info.load_store_multiple.register_list & (1 << i)) { if (i == 15) { uint32_t val = load_values[i]; sim->set_reg_mode(sim, i, val & ~1); if (val & 1) sim->set_state(sim, ARM_STATE_THUMB); else sim->set_state(sim, ARM_STATE_ARM); } else sim->set_reg_mode(sim, i, load_values[i]); } } if (update_cpsr) { uint32_t spsr = sim->get_reg_mode(sim, 16); sim->set_reg(sim, ARMV4_5_CPSR, spsr); } /* base register writeback */ if (instruction.info.load_store_multiple.W) sim->set_reg_mode(sim, instruction.info.load_store_multiple.Rn, Rn); if (instruction.info.load_store_multiple.register_list & 0x8000) return ERROR_OK; } } /* store multiple instruction */ else if (instruction.type == ARM_STM) { int i; if (dry_run_pc) { /* STM wont affect PC (advance by instruction size */ } else { uint32_t Rn = sim->get_reg_mode(sim, instruction.info.load_store_multiple.Rn); int bits_set = 0; for (i = 0; i < 16; i++) { if (instruction.info.load_store_multiple.register_list & (1 << i)) bits_set++; } switch (instruction.info.load_store_multiple.addressing_mode) { case 0: /* Increment after */ /* Rn = Rn; */ break; case 1: /* Increment before */ Rn = Rn + 4; break; case 2: /* Decrement after */ Rn = Rn - (bits_set * 4) + 4; break; case 3: /* Decrement before */ Rn = Rn - (bits_set * 4); break; } for (i = 0; i < 16; i++) { if (instruction.info.load_store_multiple.register_list & (1 << i)) { target_write_u32(target, Rn, sim->get_reg_mode(sim, i)); Rn += 4; } } /* base register writeback */ if (instruction.info.load_store_multiple.W) sim->set_reg_mode(sim, instruction.info.load_store_multiple.Rn, Rn); } } else if (!dry_run_pc) { /* the instruction wasn't handled, but we're supposed to simulate it */ LOG_ERROR("Unimplemented instruction, could not simulate it."); return ERROR_FAIL; } if (dry_run_pc) { *dry_run_pc = current_pc + instruction_size; return ERROR_OK; } else { sim->set_reg(sim, 15, current_pc + instruction_size); return ERROR_OK; } } static uint32_t armv4_5_get_reg(struct arm_sim_interface *sim, int reg) { struct arm *arm = (struct arm *)sim->user_data; return buf_get_u32(arm->core_cache->reg_list[reg].value, 0, 32); } static void armv4_5_set_reg(struct arm_sim_interface *sim, int reg, uint32_t value) { struct arm *arm = (struct arm *)sim->user_data; buf_set_u32(arm->core_cache->reg_list[reg].value, 0, 32, value); } static uint32_t armv4_5_get_reg_mode(struct arm_sim_interface *sim, int reg) { struct arm *arm = (struct arm *)sim->user_data; return buf_get_u32(ARMV4_5_CORE_REG_MODE(arm->core_cache, arm->core_mode, reg).value, 0, 32); } static void armv4_5_set_reg_mode(struct arm_sim_interface *sim, int reg, uint32_t value) { struct arm *arm = (struct arm *)sim->user_data; buf_set_u32(ARMV4_5_CORE_REG_MODE(arm->core_cache, arm->core_mode, reg).value, 0, 32, value); } static uint32_t armv4_5_get_cpsr(struct arm_sim_interface *sim, int pos, int bits) { struct arm *arm = (struct arm *)sim->user_data; return buf_get_u32(arm->cpsr->value, pos, bits); } static enum arm_state armv4_5_get_state(struct arm_sim_interface *sim) { struct arm *arm = (struct arm *)sim->user_data; return arm->core_state; } static void armv4_5_set_state(struct arm_sim_interface *sim, enum arm_state mode) { struct arm *arm = (struct arm *)sim->user_data; arm->core_state = mode; } static enum arm_mode armv4_5_get_mode(struct arm_sim_interface *sim) { struct arm *arm = (struct arm *)sim->user_data; return arm->core_mode; } int arm_simulate_step(struct target *target, uint32_t *dry_run_pc) { struct arm *arm = target_to_arm(target); struct arm_sim_interface sim; sim.user_data = arm; sim.get_reg = &armv4_5_get_reg; sim.set_reg = &armv4_5_set_reg; sim.get_reg_mode = &armv4_5_get_reg_mode; sim.set_reg_mode = &armv4_5_set_reg_mode; sim.get_cpsr = &armv4_5_get_cpsr; sim.get_mode = &armv4_5_get_mode; sim.get_state = &armv4_5_get_state; sim.set_state = &armv4_5_set_state; return arm_simulate_step_core(target, dry_run_pc, &sim); } openocd-0.7.0/src/target/cortex_m.h0000644000175000001440000001515012134336410014127 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2006 by Magnus Lundin * * lundin@mlu.mine.nu * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef CORTEX_M3_H #define CORTEX_M3_H #include "armv7m.h" #define CORTEX_M3_COMMON_MAGIC 0x1A451A45 #define SYSTEM_CONTROL_BASE 0x400FE000 #define CPUID 0xE000ED00 /* Debug Control Block */ #define DCB_DHCSR 0xE000EDF0 #define DCB_DCRSR 0xE000EDF4 #define DCB_DCRDR 0xE000EDF8 #define DCB_DEMCR 0xE000EDFC #define DCRSR_WnR (1 << 16) #define DWT_CTRL 0xE0001000 #define DWT_CYCCNT 0xE0001004 #define DWT_COMP0 0xE0001020 #define DWT_MASK0 0xE0001024 #define DWT_FUNCTION0 0xE0001028 #define FP_CTRL 0xE0002000 #define FP_REMAP 0xE0002004 #define FP_COMP0 0xE0002008 #define FP_COMP1 0xE000200C #define FP_COMP2 0xE0002010 #define FP_COMP3 0xE0002014 #define FP_COMP4 0xE0002018 #define FP_COMP5 0xE000201C #define FP_COMP6 0xE0002020 #define FP_COMP7 0xE0002024 #define FPU_CPACR 0xE000ED88 #define FPU_FPCCR 0xE000EF34 #define FPU_FPCAR 0xE000EF38 #define FPU_FPDSCR 0xE000EF3C /* DCB_DHCSR bit and field definitions */ #define DBGKEY (0xA05F << 16) #define C_DEBUGEN (1 << 0) #define C_HALT (1 << 1) #define C_STEP (1 << 2) #define C_MASKINTS (1 << 3) #define S_REGRDY (1 << 16) #define S_HALT (1 << 17) #define S_SLEEP (1 << 18) #define S_LOCKUP (1 << 19) #define S_RETIRE_ST (1 << 24) #define S_RESET_ST (1 << 25) /* DCB_DEMCR bit and field definitions */ #define TRCENA (1 << 24) #define VC_HARDERR (1 << 10) #define VC_INTERR (1 << 9) #define VC_BUSERR (1 << 8) #define VC_STATERR (1 << 7) #define VC_CHKERR (1 << 6) #define VC_NOCPERR (1 << 5) #define VC_MMERR (1 << 4) #define VC_CORERESET (1 << 0) #define NVIC_ICTR 0xE000E004 #define NVIC_ISE0 0xE000E100 #define NVIC_ICSR 0xE000ED04 #define NVIC_AIRCR 0xE000ED0C #define NVIC_SHCSR 0xE000ED24 #define NVIC_CFSR 0xE000ED28 #define NVIC_MMFSRb 0xE000ED28 #define NVIC_BFSRb 0xE000ED29 #define NVIC_USFSRh 0xE000ED2A #define NVIC_HFSR 0xE000ED2C #define NVIC_DFSR 0xE000ED30 #define NVIC_MMFAR 0xE000ED34 #define NVIC_BFAR 0xE000ED38 /* NVIC_AIRCR bits */ #define AIRCR_VECTKEY (0x5FA << 16) #define AIRCR_SYSRESETREQ (1 << 2) #define AIRCR_VECTCLRACTIVE (1 << 1) #define AIRCR_VECTRESET (1 << 0) /* NVIC_SHCSR bits */ #define SHCSR_BUSFAULTENA (1 << 17) /* NVIC_DFSR bits */ #define DFSR_HALTED 1 #define DFSR_BKPT 2 #define DFSR_DWTTRAP 4 #define DFSR_VCATCH 8 #define FPCR_CODE 0 #define FPCR_LITERAL 1 #define FPCR_REPLACE_REMAP (0 << 30) #define FPCR_REPLACE_BKPT_LOW (1 << 30) #define FPCR_REPLACE_BKPT_HIGH (2 << 30) #define FPCR_REPLACE_BKPT_BOTH (3 << 30) struct cortex_m3_fp_comparator { int used; int type; uint32_t fpcr_value; uint32_t fpcr_address; }; struct cortex_m3_dwt_comparator { int used; uint32_t comp; uint32_t mask; uint32_t function; uint32_t dwt_comparator_address; }; enum cortex_m3_soft_reset_config { CORTEX_M3_RESET_SYSRESETREQ, CORTEX_M3_RESET_VECTRESET, }; enum cortex_m3_isrmasking_mode { CORTEX_M3_ISRMASK_AUTO, CORTEX_M3_ISRMASK_OFF, CORTEX_M3_ISRMASK_ON, }; struct cortex_m3_common { int common_magic; struct arm_jtag jtag_info; /* Context information */ uint32_t dcb_dhcsr; uint32_t nvic_dfsr; /* Debug Fault Status Register - shows reason for debug halt */ uint32_t nvic_icsr; /* Interrupt Control State Register - shows active and pending IRQ */ /* Flash Patch and Breakpoint (FPB) */ int fp_num_lit; int fp_num_code; int fp_code_available; int fpb_enabled; int auto_bp_type; struct cortex_m3_fp_comparator *fp_comparator_list; /* Data Watchpoint and Trace (DWT) */ int dwt_num_comp; int dwt_comp_available; struct cortex_m3_dwt_comparator *dwt_comparator_list; struct reg_cache *dwt_cache; enum cortex_m3_soft_reset_config soft_reset_config; enum cortex_m3_isrmasking_mode isrmasking_mode; struct armv7m_common armv7m; }; static inline struct cortex_m3_common * target_to_cm3(struct target *target) { return container_of(target->arch_info, struct cortex_m3_common, armv7m); } int cortex_m3_examine(struct target *target); int cortex_m3_set_breakpoint(struct target *target, struct breakpoint *breakpoint); int cortex_m3_unset_breakpoint(struct target *target, struct breakpoint *breakpoint); int cortex_m3_add_breakpoint(struct target *target, struct breakpoint *breakpoint); int cortex_m3_remove_breakpoint(struct target *target, struct breakpoint *breakpoint); int cortex_m3_set_watchpoint(struct target *target, struct watchpoint *watchpoint); int cortex_m3_unset_watchpoint(struct target *target, struct watchpoint *watchpoint); int cortex_m3_add_watchpoint(struct target *target, struct watchpoint *watchpoint); int cortex_m3_remove_watchpoint(struct target *target, struct watchpoint *watchpoint); void cortex_m3_enable_breakpoints(struct target *target); void cortex_m3_enable_watchpoints(struct target *target); void cortex_m3_dwt_setup(struct cortex_m3_common *cm3, struct target *target); #endif /* CORTEX_M3_H */ openocd-0.7.0/src/target/dsp563xx.c0000644000175000001440000015661712137151331013724 00000000000000/*************************************************************************** * Copyright (C) 2009-2011 by Mathias Kuester * * mkdorg@users.sourceforge.net * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "target.h" #include "target_type.h" #include "algorithm.h" #include "register.h" #include "dsp563xx.h" #include "dsp563xx_once.h" #define ASM_REG_W_R0 0x60F400 #define ASM_REG_W_R1 0x61F400 #define ASM_REG_W_R2 0x62F400 #define ASM_REG_W_R3 0x63F400 #define ASM_REG_W_R4 0x64F400 #define ASM_REG_W_R5 0x65F400 #define ASM_REG_W_R6 0x66F400 #define ASM_REG_W_R7 0x67F400 #define ASM_REG_W_N0 0x70F400 #define ASM_REG_W_N1 0x71F400 #define ASM_REG_W_N2 0x72F400 #define ASM_REG_W_N3 0x73F400 #define ASM_REG_W_N4 0x74F400 #define ASM_REG_W_N5 0x75F400 #define ASM_REG_W_N6 0x76F400 #define ASM_REG_W_N7 0x77F400 #define ASM_REG_W_M0 0x05F420 #define ASM_REG_W_M1 0x05F421 #define ASM_REG_W_M2 0x05F422 #define ASM_REG_W_M3 0x05F423 #define ASM_REG_W_M4 0x05F424 #define ASM_REG_W_M5 0x05F425 #define ASM_REG_W_M6 0x05F426 #define ASM_REG_W_M7 0x05F427 #define ASM_REG_W_X0 0x44F400 #define ASM_REG_W_X1 0x45F400 #define ASM_REG_W_Y0 0x46F400 #define ASM_REG_W_Y1 0x47F400 #define ASM_REG_W_A0 0x50F400 #define ASM_REG_W_A1 0x54F400 #define ASM_REG_W_A2 0x52F400 #define ASM_REG_W_B0 0x51F400 #define ASM_REG_W_B1 0x55F400 #define ASM_REG_W_B2 0x53F400 #define ASM_REG_W_VBA 0x05F430 #define ASM_REG_W_OMR 0x05F43A #define ASM_REG_W_EP 0x05F42A #define ASM_REG_W_SC 0x05F431 #define ASM_REG_W_SZ 0x05F438 #define ASM_REG_W_SR 0x05F439 #define ASM_REG_W_SP 0x05F43B #define ASM_REG_W_SSH 0x05F43C #define ASM_REG_W_SSL 0x05F43D #define ASM_REG_W_LA 0x05F43E #define ASM_REG_W_LC 0x05F43F #define ASM_REG_W_PC 0x000000 #define ASM_REG_W_IPRC 0xFFFFFF #define ASM_REG_W_IPRP 0xFFFFFE #define ASM_REG_W_BCR 0xFFFFFB #define ASM_REG_W_DCR 0xFFFFFA #define ASM_REG_W_AAR0 0xFFFFF9 #define ASM_REG_W_AAR1 0xFFFFF8 #define ASM_REG_W_AAR2 0xFFFFF7 #define ASM_REG_W_AAR3 0xFFFFF6 enum once_reg_idx { ONCE_REG_IDX_OSCR = 0, ONCE_REG_IDX_OMBC = 1, ONCE_REG_IDX_OBCR = 2, ONCE_REG_IDX_OMLR0 = 3, ONCE_REG_IDX_OMLR1 = 4, ONCE_REG_IDX_OGDBR = 5, ONCE_REG_IDX_OPDBR = 6, ONCE_REG_IDX_OPILR = 7, ONCE_REG_IDX_PDB = 8, ONCE_REG_IDX_OTC = 9, ONCE_REG_IDX_OPABFR = 10, ONCE_REG_IDX_OPABDR = 11, ONCE_REG_IDX_OPABEX = 12, ONCE_REG_IDX_OPABF0 = 13, ONCE_REG_IDX_OPABF1 = 14, ONCE_REG_IDX_OPABF2 = 15, ONCE_REG_IDX_OPABF3 = 16, ONCE_REG_IDX_OPABF4 = 17, ONCE_REG_IDX_OPABF5 = 18, ONCE_REG_IDX_OPABF6 = 19, ONCE_REG_IDX_OPABF7 = 20, ONCE_REG_IDX_OPABF8 = 21, ONCE_REG_IDX_OPABF9 = 22, ONCE_REG_IDX_OPABF10 = 23, ONCE_REG_IDX_OPABF11 = 24, }; static struct once_reg once_regs[] = { {ONCE_REG_IDX_OSCR, DSP563XX_ONCE_OSCR, 24, "OSCR", 0}, {ONCE_REG_IDX_OMBC, DSP563XX_ONCE_OMBC, 24, "OMBC", 0}, {ONCE_REG_IDX_OBCR, DSP563XX_ONCE_OBCR, 24, "OBCR", 0}, {ONCE_REG_IDX_OMLR0, DSP563XX_ONCE_OMLR0, 24, "OMLR0", 0}, {ONCE_REG_IDX_OMLR1, DSP563XX_ONCE_OMLR1, 24, "OMLR1", 0}, {ONCE_REG_IDX_OGDBR, DSP563XX_ONCE_OGDBR, 24, "OGDBR", 0}, {ONCE_REG_IDX_OPDBR, DSP563XX_ONCE_OPDBR, 24, "OPDBR", 0}, {ONCE_REG_IDX_OPILR, DSP563XX_ONCE_OPILR, 24, "OPILR", 0}, {ONCE_REG_IDX_PDB, DSP563XX_ONCE_PDBGOTO, 24, "PDB", 0}, {ONCE_REG_IDX_OTC, DSP563XX_ONCE_OTC, 24, "OTC", 0}, {ONCE_REG_IDX_OPABFR, DSP563XX_ONCE_OPABFR, 24, "OPABFR", 0}, {ONCE_REG_IDX_OPABDR, DSP563XX_ONCE_OPABDR, 24, "OPABDR", 0}, {ONCE_REG_IDX_OPABEX, DSP563XX_ONCE_OPABEX, 24, "OPABEX", 0}, {ONCE_REG_IDX_OPABF0, DSP563XX_ONCE_OPABF11, 25, "OPABF0", 0}, {ONCE_REG_IDX_OPABF1, DSP563XX_ONCE_OPABF11, 25, "OPABF1", 0}, {ONCE_REG_IDX_OPABF2, DSP563XX_ONCE_OPABF11, 25, "OPABF2", 0}, {ONCE_REG_IDX_OPABF3, DSP563XX_ONCE_OPABF11, 25, "OPABF3", 0}, {ONCE_REG_IDX_OPABF4, DSP563XX_ONCE_OPABF11, 25, "OPABF4", 0}, {ONCE_REG_IDX_OPABF5, DSP563XX_ONCE_OPABF11, 25, "OPABF5", 0}, {ONCE_REG_IDX_OPABF6, DSP563XX_ONCE_OPABF11, 25, "OPABF6", 0}, {ONCE_REG_IDX_OPABF7, DSP563XX_ONCE_OPABF11, 25, "OPABF7", 0}, {ONCE_REG_IDX_OPABF8, DSP563XX_ONCE_OPABF11, 25, "OPABF8", 0}, {ONCE_REG_IDX_OPABF9, DSP563XX_ONCE_OPABF11, 25, "OPABF9", 0}, {ONCE_REG_IDX_OPABF10, DSP563XX_ONCE_OPABF11, 25, "OPABF10", 0}, {ONCE_REG_IDX_OPABF11, DSP563XX_ONCE_OPABF11, 25, "OPABF11", 0}, /* {25,0x1f,24,"NRSEL",0}, */ }; enum dsp563xx_reg_idx { DSP563XX_REG_IDX_R0 = 0, DSP563XX_REG_IDX_R1 = 1, DSP563XX_REG_IDX_R2 = 2, DSP563XX_REG_IDX_R3 = 3, DSP563XX_REG_IDX_R4 = 4, DSP563XX_REG_IDX_R5 = 5, DSP563XX_REG_IDX_R6 = 6, DSP563XX_REG_IDX_R7 = 7, DSP563XX_REG_IDX_N0 = 8, DSP563XX_REG_IDX_N1 = 9, DSP563XX_REG_IDX_N2 = 10, DSP563XX_REG_IDX_N3 = 11, DSP563XX_REG_IDX_N4 = 12, DSP563XX_REG_IDX_N5 = 13, DSP563XX_REG_IDX_N6 = 14, DSP563XX_REG_IDX_N7 = 15, DSP563XX_REG_IDX_M0 = 16, DSP563XX_REG_IDX_M1 = 17, DSP563XX_REG_IDX_M2 = 18, DSP563XX_REG_IDX_M3 = 19, DSP563XX_REG_IDX_M4 = 20, DSP563XX_REG_IDX_M5 = 21, DSP563XX_REG_IDX_M6 = 22, DSP563XX_REG_IDX_M7 = 23, DSP563XX_REG_IDX_X0 = 24, DSP563XX_REG_IDX_X1 = 25, DSP563XX_REG_IDX_Y0 = 26, DSP563XX_REG_IDX_Y1 = 27, DSP563XX_REG_IDX_A0 = 28, DSP563XX_REG_IDX_A1 = 29, DSP563XX_REG_IDX_A2 = 30, DSP563XX_REG_IDX_B0 = 31, DSP563XX_REG_IDX_B1 = 32, DSP563XX_REG_IDX_B2 = 33, DSP563XX_REG_IDX_SSH = 34, DSP563XX_REG_IDX_SSL = 35, DSP563XX_REG_IDX_SP = 36, DSP563XX_REG_IDX_EP = 37, DSP563XX_REG_IDX_SZ = 38, DSP563XX_REG_IDX_SC = 39, DSP563XX_REG_IDX_PC = 40, DSP563XX_REG_IDX_SR = 41, DSP563XX_REG_IDX_OMR = 42, DSP563XX_REG_IDX_LA = 43, DSP563XX_REG_IDX_LC = 44, DSP563XX_REG_IDX_VBA = 45, DSP563XX_REG_IDX_IPRC = 46, DSP563XX_REG_IDX_IPRP = 47, DSP563XX_REG_IDX_BCR = 48, DSP563XX_REG_IDX_DCR = 49, DSP563XX_REG_IDX_AAR0 = 50, DSP563XX_REG_IDX_AAR1 = 51, DSP563XX_REG_IDX_AAR2 = 52, DSP563XX_REG_IDX_AAR3 = 53, }; static const struct { unsigned id; const char *name; unsigned bits; /* effective addressing mode encoding */ uint8_t eame; uint32_t instr_mask; } dsp563xx_regs[] = { /* *INDENT-OFF* */ /* address registers */ {DSP563XX_REG_IDX_R0, "r0", 24, 0x10, ASM_REG_W_R0}, {DSP563XX_REG_IDX_R1, "r1", 24, 0x11, ASM_REG_W_R1}, {DSP563XX_REG_IDX_R2, "r2", 24, 0x12, ASM_REG_W_R2}, {DSP563XX_REG_IDX_R3, "r3", 24, 0x13, ASM_REG_W_R3}, {DSP563XX_REG_IDX_R4, "r4", 24, 0x14, ASM_REG_W_R4}, {DSP563XX_REG_IDX_R5, "r5", 24, 0x15, ASM_REG_W_R5}, {DSP563XX_REG_IDX_R6, "r6", 24, 0x16, ASM_REG_W_R6}, {DSP563XX_REG_IDX_R7, "r7", 24, 0x17, ASM_REG_W_R7}, /* offset registers */ {DSP563XX_REG_IDX_N0, "n0", 24, 0x18, ASM_REG_W_N0}, {DSP563XX_REG_IDX_N1, "n1", 24, 0x19, ASM_REG_W_N1}, {DSP563XX_REG_IDX_N2, "n2", 24, 0x1a, ASM_REG_W_N2}, {DSP563XX_REG_IDX_N3, "n3", 24, 0x1b, ASM_REG_W_N3}, {DSP563XX_REG_IDX_N4, "n4", 24, 0x1c, ASM_REG_W_N4}, {DSP563XX_REG_IDX_N5, "n5", 24, 0x1d, ASM_REG_W_N5}, {DSP563XX_REG_IDX_N6, "n6", 24, 0x1e, ASM_REG_W_N6}, {DSP563XX_REG_IDX_N7, "n7", 24, 0x1f, ASM_REG_W_N7}, /* modifier registers */ {DSP563XX_REG_IDX_M0, "m0", 24, 0x20, ASM_REG_W_M0}, {DSP563XX_REG_IDX_M1, "m1", 24, 0x21, ASM_REG_W_M1}, {DSP563XX_REG_IDX_M2, "m2", 24, 0x22, ASM_REG_W_M2}, {DSP563XX_REG_IDX_M3, "m3", 24, 0x23, ASM_REG_W_M3}, {DSP563XX_REG_IDX_M4, "m4", 24, 0x24, ASM_REG_W_M4}, {DSP563XX_REG_IDX_M5, "m5", 24, 0x25, ASM_REG_W_M5}, {DSP563XX_REG_IDX_M6, "m6", 24, 0x26, ASM_REG_W_M6}, {DSP563XX_REG_IDX_M7, "m7", 24, 0x27, ASM_REG_W_M7}, /* data alu input register */ {DSP563XX_REG_IDX_X0, "x0", 24, 0x04, ASM_REG_W_X0}, {DSP563XX_REG_IDX_X1, "x1", 24, 0x05, ASM_REG_W_X1}, {DSP563XX_REG_IDX_Y0, "y0", 24, 0x06, ASM_REG_W_Y0}, {DSP563XX_REG_IDX_Y1, "y1", 24, 0x07, ASM_REG_W_Y1}, /* data alu accumulator register */ {DSP563XX_REG_IDX_A0, "a0", 24, 0x08, ASM_REG_W_A0}, {DSP563XX_REG_IDX_A1, "a1", 24, 0x0c, ASM_REG_W_A1}, {DSP563XX_REG_IDX_A2, "a2", 8, 0x0a, ASM_REG_W_A2}, {DSP563XX_REG_IDX_B0, "b0", 24, 0x09, ASM_REG_W_B0}, {DSP563XX_REG_IDX_B1, "b1", 24, 0x0d, ASM_REG_W_B1}, {DSP563XX_REG_IDX_B2, "b2", 8, 0x0b, ASM_REG_W_B2}, /* stack */ {DSP563XX_REG_IDX_SSH, "ssh", 24, 0x3c, ASM_REG_W_SSH}, {DSP563XX_REG_IDX_SSL, "ssl", 24, 0x3d, ASM_REG_W_SSL}, {DSP563XX_REG_IDX_SP, "sp", 24, 0x3b, ASM_REG_W_SP}, {DSP563XX_REG_IDX_EP, "ep", 24, 0x2a, ASM_REG_W_EP}, {DSP563XX_REG_IDX_SZ, "sz", 24, 0x38, ASM_REG_W_SZ}, {DSP563XX_REG_IDX_SC, "sc", 24, 0x31, ASM_REG_W_SC}, /* system */ {DSP563XX_REG_IDX_PC, "pc", 24, 0x00, ASM_REG_W_PC}, {DSP563XX_REG_IDX_SR, "sr", 24, 0x39, ASM_REG_W_SR}, {DSP563XX_REG_IDX_OMR, "omr", 24, 0x3a, ASM_REG_W_OMR}, {DSP563XX_REG_IDX_LA, "la", 24, 0x3e, ASM_REG_W_LA}, {DSP563XX_REG_IDX_LC, "lc", 24, 0x3f, ASM_REG_W_LC}, /* interrupt */ {DSP563XX_REG_IDX_VBA, "vba", 24, 0x30, ASM_REG_W_VBA}, {DSP563XX_REG_IDX_IPRC, "iprc", 24, 0x00, ASM_REG_W_IPRC}, {DSP563XX_REG_IDX_IPRP, "iprp", 24, 0x00, ASM_REG_W_IPRP}, /* port a */ {DSP563XX_REG_IDX_BCR, "bcr", 24, 0x00, ASM_REG_W_BCR}, {DSP563XX_REG_IDX_DCR, "dcr", 24, 0x00, ASM_REG_W_DCR}, {DSP563XX_REG_IDX_AAR0, "aar0", 24, 0x00, ASM_REG_W_AAR0}, {DSP563XX_REG_IDX_AAR1, "aar1", 24, 0x00, ASM_REG_W_AAR1}, {DSP563XX_REG_IDX_AAR2, "aar2", 24, 0x00, ASM_REG_W_AAR2}, {DSP563XX_REG_IDX_AAR3, "aar3", 24, 0x00, ASM_REG_W_AAR3}, /* *INDENT-ON* */ }; enum memory_type { MEM_X = 0, MEM_Y = 1, MEM_P = 2, MEM_L = 3, }; #define INSTR_JUMP 0x0AF080 /* Effective Addressing Mode Encoding */ #define EAME_R0 0x10 /* instrcution encoder */ /* movep * s - peripheral space X/Y (X=0,Y=1) * w - write/read * d - source/destination register * p - IO short address */ #define INSTR_MOVEP_REG_HIO(s, w, d, p) (0x084000 | \ ((s & 1) << 16) | ((w & 1) << 15) | ((d & 0x3f) << 8) | (p & 0x3f)) /* the gdb register list is send in this order */ uint8_t gdb_reg_list_idx[] = { DSP563XX_REG_IDX_X1, DSP563XX_REG_IDX_X0, DSP563XX_REG_IDX_Y1, DSP563XX_REG_IDX_Y0, DSP563XX_REG_IDX_A2, DSP563XX_REG_IDX_A1, DSP563XX_REG_IDX_A0, DSP563XX_REG_IDX_B2, DSP563XX_REG_IDX_B1, DSP563XX_REG_IDX_B0, DSP563XX_REG_IDX_PC, DSP563XX_REG_IDX_SR, DSP563XX_REG_IDX_OMR, DSP563XX_REG_IDX_LA, DSP563XX_REG_IDX_LC, DSP563XX_REG_IDX_SSH, DSP563XX_REG_IDX_SSL, DSP563XX_REG_IDX_SP, DSP563XX_REG_IDX_EP, DSP563XX_REG_IDX_SZ, DSP563XX_REG_IDX_SC, DSP563XX_REG_IDX_VBA, DSP563XX_REG_IDX_IPRC, DSP563XX_REG_IDX_IPRP, DSP563XX_REG_IDX_BCR, DSP563XX_REG_IDX_DCR, DSP563XX_REG_IDX_AAR0, DSP563XX_REG_IDX_AAR1, DSP563XX_REG_IDX_AAR2, DSP563XX_REG_IDX_AAR3, DSP563XX_REG_IDX_R0, DSP563XX_REG_IDX_R1, DSP563XX_REG_IDX_R2, DSP563XX_REG_IDX_R3, DSP563XX_REG_IDX_R4, DSP563XX_REG_IDX_R5, DSP563XX_REG_IDX_R6, DSP563XX_REG_IDX_R7, DSP563XX_REG_IDX_N0, DSP563XX_REG_IDX_N1, DSP563XX_REG_IDX_N2, DSP563XX_REG_IDX_N3, DSP563XX_REG_IDX_N4, DSP563XX_REG_IDX_N5, DSP563XX_REG_IDX_N6, DSP563XX_REG_IDX_N7, DSP563XX_REG_IDX_M0, DSP563XX_REG_IDX_M1, DSP563XX_REG_IDX_M2, DSP563XX_REG_IDX_M3, DSP563XX_REG_IDX_M4, DSP563XX_REG_IDX_M5, DSP563XX_REG_IDX_M6, DSP563XX_REG_IDX_M7, }; static int dsp563xx_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size) { int i; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; *reg_list_size = DSP563XX_NUMCOREREGS; *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); if (!*reg_list) return ERROR_COMMAND_SYNTAX_ERROR; for (i = 0; i < DSP563XX_NUMCOREREGS; i++) (*reg_list)[i] = &dsp563xx->core_cache->reg_list[gdb_reg_list_idx[i]]; return ERROR_OK; } static int dsp563xx_read_core_reg(struct target *target, int num) { uint32_t reg_value; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); if ((num < 0) || (num >= DSP563XX_NUMCOREREGS)) return ERROR_COMMAND_SYNTAX_ERROR; reg_value = dsp563xx->core_regs[num]; buf_set_u32(dsp563xx->core_cache->reg_list[num].value, 0, 32, reg_value); dsp563xx->core_cache->reg_list[num].valid = 1; dsp563xx->core_cache->reg_list[num].dirty = 0; return ERROR_OK; } static int dsp563xx_write_core_reg(struct target *target, int num) { uint32_t reg_value; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); if ((num < 0) || (num >= DSP563XX_NUMCOREREGS)) return ERROR_COMMAND_SYNTAX_ERROR; reg_value = buf_get_u32(dsp563xx->core_cache->reg_list[num].value, 0, 32); dsp563xx->core_regs[num] = reg_value; dsp563xx->core_cache->reg_list[num].valid = 1; dsp563xx->core_cache->reg_list[num].dirty = 0; return ERROR_OK; } static int dsp563xx_get_core_reg(struct reg *reg) { struct dsp563xx_core_reg *dsp563xx_reg = reg->arch_info; struct target *target = dsp563xx_reg->target; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); LOG_DEBUG("%s", __func__); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; return dsp563xx->read_core_reg(target, dsp563xx_reg->num); } static int dsp563xx_set_core_reg(struct reg *reg, uint8_t *buf) { LOG_DEBUG("%s", __func__); struct dsp563xx_core_reg *dsp563xx_reg = reg->arch_info; struct target *target = dsp563xx_reg->target; uint32_t value = buf_get_u32(buf, 0, 32); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; buf_set_u32(reg->value, 0, reg->size, value); reg->dirty = 1; reg->valid = 1; return ERROR_OK; } static const struct reg_arch_type dsp563xx_reg_type = { .get = dsp563xx_get_core_reg, .set = dsp563xx_set_core_reg, }; static void dsp563xx_build_reg_cache(struct target *target) { struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); struct reg_cache *cache = malloc(sizeof(struct reg_cache)); struct reg *reg_list = malloc(sizeof(struct reg) * DSP563XX_NUMCOREREGS); struct dsp563xx_core_reg *arch_info = malloc( sizeof(struct dsp563xx_core_reg) * DSP563XX_NUMCOREREGS); int i; /* Build the process context cache */ cache->name = "dsp563xx registers"; cache->next = NULL; cache->reg_list = reg_list; cache->num_regs = DSP563XX_NUMCOREREGS; (*cache_p) = cache; dsp563xx->core_cache = cache; for (i = 0; i < DSP563XX_NUMCOREREGS; i++) { arch_info[i].num = dsp563xx_regs[i].id; arch_info[i].name = dsp563xx_regs[i].name; arch_info[i].size = dsp563xx_regs[i].bits; arch_info[i].eame = dsp563xx_regs[i].eame; arch_info[i].instr_mask = dsp563xx_regs[i].instr_mask; arch_info[i].target = target; arch_info[i].dsp563xx_common = dsp563xx; reg_list[i].name = dsp563xx_regs[i].name; reg_list[i].size = 32; /* dsp563xx_regs[i].bits; */ reg_list[i].value = calloc(1, 4); reg_list[i].dirty = 0; reg_list[i].valid = 0; reg_list[i].type = &dsp563xx_reg_type; reg_list[i].arch_info = &arch_info[i]; } } static int dsp563xx_read_register(struct target *target, int num, int force); static int dsp563xx_write_register(struct target *target, int num, int force); static int dsp563xx_reg_read_high_io(struct target *target, uint32_t instr_mask, uint32_t *data) { int err; uint32_t instr; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); /* we use r0 to store temporary data */ if (!dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_R0].valid) dsp563xx->read_core_reg(target, DSP563XX_REG_IDX_R0); /* move source memory to r0 */ instr = INSTR_MOVEP_REG_HIO(MEM_X, 0, EAME_R0, instr_mask); err = dsp563xx_once_execute_sw_ir(target->tap, 0, instr); if (err != ERROR_OK) return err; /* move r0 to debug register */ instr = INSTR_MOVEP_REG_HIO(MEM_X, 1, EAME_R0, 0xfffffc); err = dsp563xx_once_execute_sw_ir(target->tap, 1, instr); if (err != ERROR_OK) return err; /* read debug register */ err = dsp563xx_once_reg_read(target->tap, 1, DSP563XX_ONCE_OGDBR, data); if (err != ERROR_OK) return err; /* r0 is no longer valid on target */ dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_R0].dirty = 1; return ERROR_OK; } static int dsp563xx_reg_write_high_io(struct target *target, uint32_t instr_mask, uint32_t data) { int err; uint32_t instr; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); /* we use r0 to store temporary data */ if (!dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_R0].valid) dsp563xx->read_core_reg(target, DSP563XX_REG_IDX_R0); /* move data to r0 */ err = dsp563xx_once_execute_dw_ir(target->tap, 0, 0x60F400, data); if (err != ERROR_OK) return err; /* move r0 to destination memory */ instr = INSTR_MOVEP_REG_HIO(MEM_X, 1, EAME_R0, instr_mask); err = dsp563xx_once_execute_sw_ir(target->tap, 1, instr); if (err != ERROR_OK) return err; /* r0 is no longer valid on target */ dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_R0].dirty = 1; return ERROR_OK; } static int dsp563xx_reg_read(struct target *target, uint32_t eame, uint32_t *data) { int err; uint32_t instr; instr = INSTR_MOVEP_REG_HIO(MEM_X, 1, eame, 0xfffffc); err = dsp563xx_once_execute_sw_ir(target->tap, 0, instr); if (err != ERROR_OK) return err; /* nop */ err = dsp563xx_once_execute_sw_ir(target->tap, 1, 0x000000); if (err != ERROR_OK) return err; /* read debug register */ return dsp563xx_once_reg_read(target->tap, 1, DSP563XX_ONCE_OGDBR, data); } static int dsp563xx_reg_write(struct target *target, uint32_t instr_mask, uint32_t data) { int err; err = dsp563xx_once_execute_dw_ir(target->tap, 0, instr_mask, data); if (err != ERROR_OK) return err; /* nop */ return dsp563xx_once_execute_sw_ir(target->tap, 1, 0x000000); } static int dsp563xx_reg_pc_read(struct target *target) { struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); /* pc was changed, nothing todo */ if (dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_PC].dirty) return ERROR_OK; /* conditional branch check */ if (once_regs[ONCE_REG_IDX_OPABDR].reg == once_regs[ONCE_REG_IDX_OPABEX].reg) { if ((once_regs[ONCE_REG_IDX_OPABF11].reg & 1) == 0) { LOG_DEBUG("%s conditional branch not supported yet (0x%x 0x%x 0x%x)", __func__, (once_regs[ONCE_REG_IDX_OPABF11].reg >> 1), once_regs[ONCE_REG_IDX_OPABDR].reg, once_regs[ONCE_REG_IDX_OPABEX].reg); /* TODO: use disassembly to set correct pc offset * read 2 words from OPABF11 and disasm the instruction */ dsp563xx->core_regs[DSP563XX_REG_IDX_PC] = (once_regs[ONCE_REG_IDX_OPABF11].reg >> 1) & 0x00FFFFFF; } else { if (once_regs[ONCE_REG_IDX_OPABEX].reg == once_regs[ONCE_REG_IDX_OPABFR].reg) dsp563xx->core_regs[DSP563XX_REG_IDX_PC] = once_regs[ONCE_REG_IDX_OPABEX].reg; else dsp563xx->core_regs[DSP563XX_REG_IDX_PC] = once_regs[ONCE_REG_IDX_OPABEX].reg - 1; } } else dsp563xx->core_regs[DSP563XX_REG_IDX_PC] = once_regs[ONCE_REG_IDX_OPABEX].reg; dsp563xx->read_core_reg(target, DSP563XX_REG_IDX_PC); return ERROR_OK; } static int dsp563xx_reg_ssh_read(struct target *target) { int err; uint32_t sp; struct dsp563xx_core_reg *arch_info; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); arch_info = dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_SSH].arch_info; /* get a valid stack pointer */ err = dsp563xx_read_register(target, DSP563XX_REG_IDX_SP, 0); if (err != ERROR_OK) return err; sp = dsp563xx->core_regs[DSP563XX_REG_IDX_SP]; err = dsp563xx_write_register(target, DSP563XX_REG_IDX_SP, 0); if (err != ERROR_OK) return err; /* get a valid stack count */ err = dsp563xx_read_register(target, DSP563XX_REG_IDX_SC, 0); if (err != ERROR_OK) return err; err = dsp563xx_write_register(target, DSP563XX_REG_IDX_SC, 0); if (err != ERROR_OK) return err; /* get a valid extended pointer */ err = dsp563xx_read_register(target, DSP563XX_REG_IDX_EP, 0); if (err != ERROR_OK) return err; err = dsp563xx_write_register(target, DSP563XX_REG_IDX_EP, 0); if (err != ERROR_OK) return err; if (!sp) sp = 0x00FFFFFF; else { err = dsp563xx_reg_read(target, arch_info->eame, &sp); if (err != ERROR_OK) return err; err = dsp563xx_write_register(target, DSP563XX_REG_IDX_SC, 1); if (err != ERROR_OK) return err; err = dsp563xx_write_register(target, DSP563XX_REG_IDX_SP, 1); if (err != ERROR_OK) return err; err = dsp563xx_write_register(target, DSP563XX_REG_IDX_EP, 1); if (err != ERROR_OK) return err; } dsp563xx->core_regs[DSP563XX_REG_IDX_SSH] = sp; dsp563xx->read_core_reg(target, DSP563XX_REG_IDX_SSH); return ERROR_OK; } static int dsp563xx_reg_ssh_write(struct target *target) { int err; uint32_t sp; struct dsp563xx_core_reg *arch_info; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); arch_info = dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_SSH].arch_info; /* get a valid stack pointer */ err = dsp563xx_read_register(target, DSP563XX_REG_IDX_SP, 0); if (err != ERROR_OK) return err; sp = dsp563xx->core_regs[DSP563XX_REG_IDX_SP]; if (sp) { sp--; /* write new stackpointer */ dsp563xx->core_regs[DSP563XX_REG_IDX_SP] = sp; err = dsp563xx->read_core_reg(target, DSP563XX_REG_IDX_SP); if (err != ERROR_OK) return err; err = dsp563xx_write_register(target, DSP563XX_REG_IDX_SP, 1); if (err != ERROR_OK) return err; err = dsp563xx_reg_write(target, arch_info->instr_mask, dsp563xx->core_regs[DSP563XX_REG_IDX_SSH]); if (err != ERROR_OK) return err; err = dsp563xx_read_register(target, DSP563XX_REG_IDX_SP, 1); if (err != ERROR_OK) return err; err = dsp563xx_read_register(target, DSP563XX_REG_IDX_SSH, 1); if (err != ERROR_OK) return err; } return ERROR_OK; } static int dsp563xx_reg_ssl_read(struct target *target) { int err; uint32_t sp; struct dsp563xx_core_reg *arch_info; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); arch_info = dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_SSL].arch_info; /* get a valid stack pointer */ err = dsp563xx_read_register(target, DSP563XX_REG_IDX_SP, 0); if (err != ERROR_OK) return err; sp = dsp563xx->core_regs[DSP563XX_REG_IDX_SP]; if (!sp) sp = 0x00FFFFFF; else { err = dsp563xx_reg_read(target, arch_info->eame, &sp); if (err != ERROR_OK) return err; } dsp563xx->core_regs[DSP563XX_REG_IDX_SSL] = sp; dsp563xx->read_core_reg(target, DSP563XX_REG_IDX_SSL); return ERROR_OK; } static int dsp563xx_read_register(struct target *target, int num, int force) { int err = ERROR_OK; uint32_t data = 0; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); struct dsp563xx_core_reg *arch_info; if (force) dsp563xx->core_cache->reg_list[num].valid = 0; if (!dsp563xx->core_cache->reg_list[num].valid) { arch_info = dsp563xx->core_cache->reg_list[num].arch_info; switch (arch_info->num) { case DSP563XX_REG_IDX_SSH: err = dsp563xx_reg_ssh_read(target); break; case DSP563XX_REG_IDX_SSL: err = dsp563xx_reg_ssl_read(target); break; case DSP563XX_REG_IDX_PC: err = dsp563xx_reg_pc_read(target); break; case DSP563XX_REG_IDX_IPRC: case DSP563XX_REG_IDX_IPRP: case DSP563XX_REG_IDX_BCR: case DSP563XX_REG_IDX_DCR: case DSP563XX_REG_IDX_AAR0: case DSP563XX_REG_IDX_AAR1: case DSP563XX_REG_IDX_AAR2: case DSP563XX_REG_IDX_AAR3: err = dsp563xx_reg_read_high_io(target, arch_info->instr_mask, &data); if (err == ERROR_OK) { dsp563xx->core_regs[num] = data; dsp563xx->read_core_reg(target, num); } break; default: err = dsp563xx_reg_read(target, arch_info->eame, &data); if (err == ERROR_OK) { dsp563xx->core_regs[num] = data; dsp563xx->read_core_reg(target, num); } break; } } return err; } static int dsp563xx_write_register(struct target *target, int num, int force) { int err = ERROR_OK; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); struct dsp563xx_core_reg *arch_info; if (force) dsp563xx->core_cache->reg_list[num].dirty = 1; if (dsp563xx->core_cache->reg_list[num].dirty) { arch_info = dsp563xx->core_cache->reg_list[num].arch_info; dsp563xx->write_core_reg(target, num); switch (arch_info->num) { case DSP563XX_REG_IDX_SSH: err = dsp563xx_reg_ssh_write(target); break; case DSP563XX_REG_IDX_PC: /* pc is updated on resume, no need to write it here */ break; case DSP563XX_REG_IDX_IPRC: case DSP563XX_REG_IDX_IPRP: case DSP563XX_REG_IDX_BCR: case DSP563XX_REG_IDX_DCR: case DSP563XX_REG_IDX_AAR0: case DSP563XX_REG_IDX_AAR1: case DSP563XX_REG_IDX_AAR2: case DSP563XX_REG_IDX_AAR3: err = dsp563xx_reg_write_high_io(target, arch_info->instr_mask, dsp563xx->core_regs[num]); break; default: err = dsp563xx_reg_write(target, arch_info->instr_mask, dsp563xx->core_regs[num]); if ((err == ERROR_OK) && (arch_info->num == DSP563XX_REG_IDX_SP)) { dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_SSH].valid = 0; dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_SSL].valid = 0; } break; } } return err; } static int dsp563xx_save_context(struct target *target) { int i, err = ERROR_OK; for (i = 0; i < DSP563XX_NUMCOREREGS; i++) { err = dsp563xx_read_register(target, i, 0); if (err != ERROR_OK) break; } return err; } static int dsp563xx_restore_context(struct target *target) { int i, err = ERROR_OK; for (i = 0; i < DSP563XX_NUMCOREREGS; i++) { err = dsp563xx_write_register(target, i, 0); if (err != ERROR_OK) break; } return err; } static void dsp563xx_invalidate_x_context(struct target *target, uint32_t addr_start, uint32_t addr_end) { int i; struct dsp563xx_core_reg *arch_info; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); if (addr_start > ASM_REG_W_IPRC) return; if (addr_start < ASM_REG_W_AAR3) return; for (i = DSP563XX_REG_IDX_IPRC; i < DSP563XX_NUMCOREREGS; i++) { arch_info = dsp563xx->core_cache->reg_list[i].arch_info; if ((arch_info->instr_mask >= addr_start) && (arch_info->instr_mask <= addr_end)) { dsp563xx->core_cache->reg_list[i].valid = 0; dsp563xx->core_cache->reg_list[i].dirty = 0; } } } static int dsp563xx_target_create(struct target *target, Jim_Interp *interp) { struct dsp563xx_common *dsp563xx = calloc(1, sizeof(struct dsp563xx_common)); if (!dsp563xx) return ERROR_COMMAND_SYNTAX_ERROR; dsp563xx->jtag_info.tap = target->tap; target->arch_info = dsp563xx; dsp563xx->read_core_reg = dsp563xx_read_core_reg; dsp563xx->write_core_reg = dsp563xx_write_core_reg; return ERROR_OK; } static int dsp563xx_init_target(struct command_context *cmd_ctx, struct target *target) { LOG_DEBUG("%s", __func__); dsp563xx_build_reg_cache(target); return ERROR_OK; } static int dsp563xx_examine(struct target *target) { uint32_t chip; if (target->tap->hasidcode == false) { LOG_ERROR("no IDCODE present on device"); return ERROR_COMMAND_SYNTAX_ERROR; } if (!target_was_examined(target)) { target_set_examined(target); /* examine core and chip derivate number */ chip = (target->tap->idcode>>12) & 0x3ff; /* core number 0 means DSP563XX */ if (((chip>>5)&0x1f) == 0) chip += 300; LOG_INFO("DSP56%03d device found", chip); } return ERROR_OK; } static int dsp563xx_arch_state(struct target *target) { LOG_DEBUG("%s", __func__); return ERROR_OK; } #define DSP563XX_SR_SA (1<<17) #define DSP563XX_SR_SC (1<<13) static int dsp563xx_debug_once_init(struct target *target) { return dsp563xx_once_read_register(target->tap, 1, once_regs, DSP563XX_NUMONCEREGS); } static int dsp563xx_debug_init(struct target *target) { int err; uint32_t sr; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); struct dsp563xx_core_reg *arch_info; err = dsp563xx_debug_once_init(target); if (err != ERROR_OK) return err; arch_info = dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_SR].arch_info; /* check 24bit mode */ err = dsp563xx_read_register(target, DSP563XX_REG_IDX_SR, 0); if (err != ERROR_OK) return err; sr = dsp563xx->core_regs[DSP563XX_REG_IDX_SR]; if (sr & (DSP563XX_SR_SA | DSP563XX_SR_SC)) { sr &= ~(DSP563XX_SR_SA | DSP563XX_SR_SC); err = dsp563xx_once_execute_dw_ir(target->tap, 1, arch_info->instr_mask, sr); if (err != ERROR_OK) return err; dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_SR].dirty = 1; } err = dsp563xx_read_register(target, DSP563XX_REG_IDX_N0, 0); if (err != ERROR_OK) return err; err = dsp563xx_read_register(target, DSP563XX_REG_IDX_N1, 0); if (err != ERROR_OK) return err; err = dsp563xx_read_register(target, DSP563XX_REG_IDX_M0, 0); if (err != ERROR_OK) return err; err = dsp563xx_read_register(target, DSP563XX_REG_IDX_M1, 0); if (err != ERROR_OK) return err; if (dsp563xx->core_regs[DSP563XX_REG_IDX_N0] != 0x000000) { arch_info = dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_N0].arch_info; err = dsp563xx_reg_write(target, arch_info->instr_mask, 0x000000); if (err != ERROR_OK) return err; } dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_N0].dirty = 1; if (dsp563xx->core_regs[DSP563XX_REG_IDX_N1] != 0x000000) { arch_info = dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_N1].arch_info; err = dsp563xx_reg_write(target, arch_info->instr_mask, 0x000000); if (err != ERROR_OK) return err; } dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_N1].dirty = 1; if (dsp563xx->core_regs[DSP563XX_REG_IDX_M0] != 0xffffff) { arch_info = dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_M0].arch_info; err = dsp563xx_reg_write(target, arch_info->instr_mask, 0xffffff); if (err != ERROR_OK) return err; } dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_M0].dirty = 1; if (dsp563xx->core_regs[DSP563XX_REG_IDX_M1] != 0xffffff) { arch_info = dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_M1].arch_info; err = dsp563xx_reg_write(target, arch_info->instr_mask, 0xffffff); if (err != ERROR_OK) return err; } dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_M1].dirty = 1; err = dsp563xx_save_context(target); if (err != ERROR_OK) return err; return ERROR_OK; } static int dsp563xx_jtag_debug_request(struct target *target) { return dsp563xx_once_request_debug(target->tap, target->state == TARGET_RESET); } static int dsp563xx_poll(struct target *target) { int err; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); uint32_t once_status = 0; int state; state = dsp563xx_once_target_status(target->tap); if (state == TARGET_UNKNOWN) { target->state = state; LOG_ERROR("jtag status contains invalid mode value - communication failure"); return ERROR_TARGET_FAILURE; } err = dsp563xx_once_reg_read(target->tap, 1, DSP563XX_ONCE_OSCR, &once_status); if (err != ERROR_OK) return err; if ((once_status & DSP563XX_ONCE_OSCR_DEBUG_M) == DSP563XX_ONCE_OSCR_DEBUG_M) { if (target->state != TARGET_HALTED) { target->state = TARGET_HALTED; err = dsp563xx_debug_init(target); if (err != ERROR_OK) return err; if (once_status & (DSP563XX_ONCE_OSCR_MBO|DSP563XX_ONCE_OSCR_SWO)) target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); else target_call_event_callbacks(target, TARGET_EVENT_HALTED); LOG_DEBUG("target->state: %s (%x)", target_state_name(target), once_status); LOG_INFO("halted: PC: 0x%x", dsp563xx->core_regs[DSP563XX_REG_IDX_PC]); } } return ERROR_OK; } static int dsp563xx_halt(struct target *target) { int err; LOG_DEBUG("%s", __func__); if (target->state == TARGET_HALTED) { LOG_DEBUG("target was already halted"); return ERROR_OK; } if (target->state == TARGET_UNKNOWN) LOG_WARNING("target was in unknown state when halt was requested"); err = dsp563xx_jtag_debug_request(target); if (err != ERROR_OK) return err; target->debug_reason = DBG_REASON_DBGRQ; return ERROR_OK; } static int dsp563xx_resume(struct target *target, int current, uint32_t address, int handle_breakpoints, int debug_execution) { int err; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); /* check if pc was changed and resume want to execute the next address * if pc was changed from gdb or other interface we will * jump to this address and don't execute the next address * this will not affect the resume command with an address argument * because current is set to zero then */ if (current && dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_PC].dirty) { dsp563xx_write_core_reg(target, DSP563XX_REG_IDX_PC); address = dsp563xx->core_regs[DSP563XX_REG_IDX_PC]; current = 0; } LOG_DEBUG("%s %08X %08X", __func__, current, (unsigned) address); err = dsp563xx_restore_context(target); if (err != ERROR_OK) return err; register_cache_invalidate(dsp563xx->core_cache); if (current) { /* restore pipeline registers and go */ err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OPDBR, once_regs[ONCE_REG_IDX_OPILR].reg); if (err != ERROR_OK) return err; err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OPDBR | DSP563XX_ONCE_OCR_EX | DSP563XX_ONCE_OCR_GO, once_regs[ONCE_REG_IDX_OPDBR].reg); if (err != ERROR_OK) return err; } else { /* set to go register and jump */ err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OPDBR, INSTR_JUMP); if (err != ERROR_OK) return err; err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_PDBGOTO | DSP563XX_ONCE_OCR_EX | DSP563XX_ONCE_OCR_GO, address); if (err != ERROR_OK) return err; } target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); return ERROR_OK; } static int dsp563xx_step_ex(struct target *target, int current, uint32_t address, int handle_breakpoints, int steps) { int err; uint32_t once_status; uint32_t dr_in, cnt; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); if (target->state != TARGET_HALTED) { LOG_DEBUG("target was not halted"); return ERROR_OK; } /* check if pc was changed and step want to execute the next address * if pc was changed from gdb or other interface we will * jump to this address and don't execute the next address * this will not affect the step command with an address argument * because current is set to zero then */ if (current && dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_PC].dirty) { dsp563xx_write_core_reg(target, DSP563XX_REG_IDX_PC); address = dsp563xx->core_regs[DSP563XX_REG_IDX_PC]; current = 0; } LOG_DEBUG("%s %08X %08X", __func__, current, (unsigned) address); err = dsp563xx_jtag_debug_request(target); if (err != ERROR_OK) return err; err = dsp563xx_restore_context(target); if (err != ERROR_OK) return err; /* reset trace mode */ err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OSCR, 0x000000); if (err != ERROR_OK) return err; /* enable trace mode */ err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OSCR, DSP563XX_ONCE_OSCR_TME); if (err != ERROR_OK) return err; cnt = steps; /* on JUMP we need one extra cycle */ if (!current) cnt++; /* load step counter with N-1 */ err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OTC, cnt); if (err != ERROR_OK) return err; if (current) { /* restore pipeline registers and go */ err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OPDBR, once_regs[ONCE_REG_IDX_OPILR].reg); if (err != ERROR_OK) return err; err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OPDBR | DSP563XX_ONCE_OCR_EX | DSP563XX_ONCE_OCR_GO, once_regs[ONCE_REG_IDX_OPDBR].reg); if (err != ERROR_OK) return err; } else { /* set to go register and jump */ err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OPDBR, INSTR_JUMP); if (err != ERROR_OK) return err; err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_PDBGOTO | DSP563XX_ONCE_OCR_EX | DSP563XX_ONCE_OCR_GO, address); if (err != ERROR_OK) return err; } while (1) { err = dsp563xx_once_reg_read(target->tap, 1, DSP563XX_ONCE_OSCR, &once_status); if (err != ERROR_OK) return err; if (once_status & DSP563XX_ONCE_OSCR_TO) { err = dsp563xx_once_reg_read(target->tap, 1, DSP563XX_ONCE_OPABFR, &dr_in); if (err != ERROR_OK) return err; LOG_DEBUG("fetch: %08X", (unsigned) dr_in&0x00ffffff); err = dsp563xx_once_reg_read(target->tap, 1, DSP563XX_ONCE_OPABDR, &dr_in); if (err != ERROR_OK) return err; LOG_DEBUG("decode: %08X", (unsigned) dr_in&0x00ffffff); err = dsp563xx_once_reg_read(target->tap, 1, DSP563XX_ONCE_OPABEX, &dr_in); if (err != ERROR_OK) return err; LOG_DEBUG("execute: %08X", (unsigned) dr_in&0x00ffffff); /* reset trace mode */ err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OSCR, 0x000000); if (err != ERROR_OK) return err; register_cache_invalidate(dsp563xx->core_cache); err = dsp563xx_debug_init(target); if (err != ERROR_OK) return err; break; } } return ERROR_OK; } static int dsp563xx_step(struct target *target, int current, uint32_t address, int handle_breakpoints) { int err; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } err = dsp563xx_step_ex(target, current, address, handle_breakpoints, 0); if (err != ERROR_OK) return err; target->debug_reason = DBG_REASON_SINGLESTEP; target_call_event_callbacks(target, TARGET_EVENT_HALTED); LOG_INFO("halted: PC: 0x%x", dsp563xx->core_regs[DSP563XX_REG_IDX_PC]); return err; } static int dsp563xx_assert_reset(struct target *target) { int retval = 0; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); enum reset_types jtag_reset_config = jtag_get_reset_config(); if (jtag_reset_config & RESET_HAS_SRST) { /* default to asserting srst */ if (jtag_reset_config & RESET_SRST_PULLS_TRST) jtag_add_reset(1, 1); else jtag_add_reset(0, 1); } target->state = TARGET_RESET; jtag_add_sleep(5000); /* registers are now invalid */ register_cache_invalidate(dsp563xx->core_cache); if (target->reset_halt) { retval = target_halt(target); if (retval != ERROR_OK) return retval; } LOG_DEBUG("%s", __func__); return ERROR_OK; } static int dsp563xx_deassert_reset(struct target *target) { int err; /* deassert reset lines */ jtag_add_reset(0, 0); err = dsp563xx_poll(target); if (err != ERROR_OK) return err; if (target->reset_halt) { if (target->state == TARGET_HALTED) { /* after a reset the cpu jmp to the * reset vector and need 2 cycles to fill * the cache (fetch,decode,excecute) */ err = dsp563xx_step_ex(target, 1, 0, 1, 1); if (err != ERROR_OK) return err; } } else target->state = TARGET_RUNNING; LOG_DEBUG("%s", __func__); return ERROR_OK; } static int dsp563xx_soft_reset_halt(struct target *target) { LOG_DEBUG("%s", __func__); return ERROR_OK; } static int dsp563xx_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, uint32_t entry_point, uint32_t exit_point, int timeout_ms, void *arch_info) { int i; int retval = ERROR_OK; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } for (i = 0; i < num_mem_params; i++) { retval = target_write_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value); if (retval != ERROR_OK) return retval; } for (i = 0; i < num_reg_params; i++) { struct reg *reg = register_get_by_name(dsp563xx->core_cache, reg_params[i].reg_name, 0); if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); continue; } if (reg->size != reg_params[i].size) { LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name); continue; } retval = dsp563xx_set_core_reg(reg, reg_params[i].value); if (retval != ERROR_OK) return retval; } /* exec */ retval = target_resume(target, 0, entry_point, 1, 1); if (retval != ERROR_OK) return retval; retval = target_wait_state(target, TARGET_HALTED, timeout_ms); if (retval != ERROR_OK) return retval; for (i = 0; i < num_mem_params; i++) { if (mem_params[i].direction != PARAM_OUT) retval = target_read_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value); if (retval != ERROR_OK) return retval; } for (i = 0; i < num_reg_params; i++) { if (reg_params[i].direction != PARAM_OUT) { struct reg *reg = register_get_by_name(dsp563xx->core_cache, reg_params[i].reg_name, 0); if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); continue; } if (reg->size != reg_params[i].size) { LOG_ERROR( "BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name); continue; } buf_set_u32(reg_params[i].value, 0, 32, buf_get_u32(reg->value, 0, 32)); } } return ERROR_OK; } /* global command context from openocd.c */ extern struct command_context *global_cmd_ctx; static int dsp563xx_get_default_memory(void) { Jim_Interp *interp; Jim_Obj *memspace; char *c; if (!global_cmd_ctx) return MEM_P; interp = global_cmd_ctx->interp; if (!interp) return MEM_P; memspace = Jim_GetGlobalVariableStr(interp, "memspace", JIM_NONE); if (!memspace) return MEM_P; c = (char *)Jim_GetString(memspace, NULL); if (!c) return MEM_P; switch (c[0]) { case '1': return MEM_X; case '2': return MEM_Y; case '3': return MEM_L; default: break; } return MEM_P; } static int dsp563xx_read_memory_core(struct target *target, int mem_type, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) { int err; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); uint32_t i, x; uint32_t data, move_cmd = 0; uint8_t *b; LOG_DEBUG( "memtype: %d address: 0x%8.8" PRIx32 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", mem_type, address, size, count); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } switch (mem_type) { case MEM_X: /* TODO: mark effected queued registers */ move_cmd = 0x61d800; break; case MEM_Y: move_cmd = 0x69d800; break; case MEM_P: move_cmd = 0x07d891; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } /* we use r0 to store temporary data */ if (!dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_R0].valid) dsp563xx->read_core_reg(target, DSP563XX_REG_IDX_R0); /* we use r1 to store temporary data */ if (!dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_R1].valid) dsp563xx->read_core_reg(target, DSP563XX_REG_IDX_R1); /* r0 is no longer valid on target */ dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_R0].dirty = 1; /* r1 is no longer valid on target */ dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_R1].dirty = 1; x = count; b = buffer; err = dsp563xx_once_execute_dw_ir(target->tap, 1, 0x60F400, address); if (err != ERROR_OK) return err; for (i = 0; i < x; i++) { err = dsp563xx_once_execute_sw_ir(target->tap, 0, move_cmd); if (err != ERROR_OK) return err; err = dsp563xx_once_execute_sw_ir(target->tap, 0, 0x08D13C); if (err != ERROR_OK) return err; err = dsp563xx_once_reg_read(target->tap, 0, DSP563XX_ONCE_OGDBR, (uint32_t *)(void *)b); if (err != ERROR_OK) return err; b += 4; } /* flush the jtag queue */ err = jtag_execute_queue(); if (err != ERROR_OK) return err; /* walk over the buffer and fix target endianness */ b = buffer; for (i = 0; i < x; i++) { data = buf_get_u32(b, 0, 32) & 0x00FFFFFF; /* LOG_DEBUG("R: %08X", *((uint32_t*)b)); */ target_buffer_set_u32(target, b, data); b += 4; } return ERROR_OK; } static int dsp563xx_read_memory(struct target *target, int mem_type, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) { int err; uint32_t i, i1; uint8_t *buffer_y, *buffer_x; /* if size equals zero we are called from target read memory * and have to handle the parameter here */ if ((size == 0) && (count != 0)) { size = count % 4; if (size) LOG_DEBUG("size is not aligned to 4 byte"); count = (count - size) / 4; size = 4; } /* we only support 4 byte aligned data */ if ((size != 4) || (!count)) return ERROR_COMMAND_SYNTAX_ERROR; if (mem_type != MEM_L) return dsp563xx_read_memory_core(target, mem_type, address, size, count, buffer); buffer_y = malloc(size * count); if (!buffer_y) return ERROR_COMMAND_SYNTAX_ERROR; buffer_x = malloc(size * count); if (!buffer_x) { free(buffer_y); return ERROR_COMMAND_SYNTAX_ERROR; } err = dsp563xx_read_memory_core(target, MEM_Y, address, size, count / 2, buffer_y); if (err != ERROR_OK) { free(buffer_y); free(buffer_x); return err; } err = dsp563xx_read_memory_core(target, MEM_X, address, size, count / 2, buffer_x); if (err != ERROR_OK) { free(buffer_y); free(buffer_x); return err; } for (i = 0, i1 = 0; i < count; i += 2, i1++) { buf_set_u32(buffer + i*sizeof(uint32_t), 0, 32, buf_get_u32(buffer_y + i1 * sizeof(uint32_t), 0, 32)); buf_set_u32(buffer + (i + 1) * sizeof(uint32_t), 0, 32, buf_get_u32(buffer_x + i1 * sizeof(uint32_t), 0, 32)); } free(buffer_y); free(buffer_x); return ERROR_OK; } static int dsp563xx_read_memory_default(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) { return dsp563xx_read_memory(target, dsp563xx_get_default_memory(), address, size, count, buffer); } static int dsp563xx_read_buffer_default(struct target *target, uint32_t address, uint32_t size, uint8_t *buffer) { return dsp563xx_read_memory(target, dsp563xx_get_default_memory(), address, size, 0, buffer); } static int dsp563xx_write_memory_core(struct target *target, int mem_type, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { int err; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); uint32_t i, x; uint32_t data, move_cmd = 0; const uint8_t *b; LOG_DEBUG( "memtype: %d address: 0x%8.8" PRIx32 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", mem_type, address, size, count); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } switch (mem_type) { case MEM_X: /* invalidate affected x registers */ dsp563xx_invalidate_x_context(target, address, address + count - 1); move_cmd = 0x615800; break; case MEM_Y: move_cmd = 0x695800; break; case MEM_P: move_cmd = 0x075891; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } /* we use r0 to store temporary data */ if (!dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_R0].valid) dsp563xx->read_core_reg(target, DSP563XX_REG_IDX_R0); /* we use r1 to store temporary data */ if (!dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_R1].valid) dsp563xx->read_core_reg(target, DSP563XX_REG_IDX_R1); /* r0 is no longer valid on target */ dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_R0].dirty = 1; /* r1 is no longer valid on target */ dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_R1].dirty = 1; x = count; b = buffer; err = dsp563xx_once_execute_dw_ir(target->tap, 1, 0x60F400, address); if (err != ERROR_OK) return err; for (i = 0; i < x; i++) { data = target_buffer_get_u32(target, b); /* LOG_DEBUG("W: %08X", data); */ data &= 0x00ffffff; err = dsp563xx_once_execute_dw_ir(target->tap, 0, 0x61F400, data); if (err != ERROR_OK) return err; err = dsp563xx_once_execute_sw_ir(target->tap, 0, move_cmd); if (err != ERROR_OK) return err; b += 4; } /* flush the jtag queue */ err = jtag_execute_queue(); if (err != ERROR_OK) return err; return ERROR_OK; } static int dsp563xx_write_memory(struct target *target, int mem_type, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { int err; uint32_t i, i1; uint8_t *buffer_y, *buffer_x; /* if size equals zero we are called from target write memory * and have to handle the parameter here */ if ((size == 0) && (count != 0)) { size = count % 4; if (size) LOG_DEBUG("size is not aligned to 4 byte"); count = (count - size) / 4; size = 4; } /* we only support 4 byte aligned data */ if ((size != 4) || (!count)) return ERROR_COMMAND_SYNTAX_ERROR; if (mem_type != MEM_L) return dsp563xx_write_memory_core(target, mem_type, address, size, count, buffer); buffer_y = malloc(size * count); if (!buffer_y) return ERROR_COMMAND_SYNTAX_ERROR; buffer_x = malloc(size * count); if (!buffer_x) { free(buffer_y); return ERROR_COMMAND_SYNTAX_ERROR; } for (i = 0, i1 = 0; i < count; i += 2, i1++) { buf_set_u32(buffer_y + i1 * sizeof(uint32_t), 0, 32, buf_get_u32(buffer + i * sizeof(uint32_t), 0, 32)); buf_set_u32(buffer_x + i1 * sizeof(uint32_t), 0, 32, buf_get_u32(buffer + (i + 1) * sizeof(uint32_t), 0, 32)); } err = dsp563xx_write_memory_core(target, MEM_Y, address, size, count / 2, buffer_y); if (err != ERROR_OK) { free(buffer_y); free(buffer_x); return err; } err = dsp563xx_write_memory_core(target, MEM_X, address, size, count / 2, buffer_x); if (err != ERROR_OK) { free(buffer_y); free(buffer_x); return err; } free(buffer_y); free(buffer_x); return ERROR_OK; } static int dsp563xx_write_memory_default(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { return dsp563xx_write_memory(target, dsp563xx_get_default_memory(), address, size, count, buffer); } static int dsp563xx_write_buffer_default(struct target *target, uint32_t address, uint32_t size, const uint8_t *buffer) { return dsp563xx_write_memory(target, dsp563xx_get_default_memory(), address, size, 0, buffer); } static int dsp563xx_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { return ERROR_OK; } static int dsp563xx_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { return ERROR_OK; } static int dsp563xx_add_watchpoint(struct target *target, struct watchpoint *watchpoint) { return ERROR_OK; } static int dsp563xx_remove_watchpoint(struct target *target, struct watchpoint *watchpoint) { return ERROR_OK; } static void handle_md_output(struct command_context *cmd_ctx, struct target *target, uint32_t address, unsigned size, unsigned count, const uint8_t *buffer) { const unsigned line_bytecnt = 32; unsigned line_modulo = line_bytecnt / size; char output[line_bytecnt * 4 + 1]; unsigned output_len = 0; const char *value_fmt; switch (size) { case 4: value_fmt = "%8.8x "; break; case 2: value_fmt = "%4.4x "; break; case 1: value_fmt = "%2.2x "; break; default: /* "can't happen", caller checked */ LOG_ERROR("invalid memory read size: %u", size); return; } for (unsigned i = 0; i < count; i++) { if (i % line_modulo == 0) output_len += snprintf(output + output_len, sizeof(output) - output_len, "0x%8.8x: ", (unsigned) (address + i)); uint32_t value = 0; const uint8_t *value_ptr = buffer + i * size; switch (size) { case 4: value = target_buffer_get_u32(target, value_ptr); break; case 2: value = target_buffer_get_u16(target, value_ptr); break; case 1: value = *value_ptr; } output_len += snprintf(output + output_len, sizeof(output) - output_len, value_fmt, value); if ((i % line_modulo == line_modulo - 1) || (i == count - 1)) { command_print(cmd_ctx, "%s", output); output_len = 0; } } } COMMAND_HANDLER(dsp563xx_mem_command) { struct target *target = get_current_target(CMD_CTX); int err = ERROR_OK; int read_mem; uint32_t address = 0; uint32_t count = 1, i; uint32_t pattern = 0; uint32_t mem_type; uint8_t *buffer, *b; switch (CMD_NAME[1]) { case 'w': read_mem = 0; break; case 'd': read_mem = 1; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } switch (CMD_NAME[3]) { case 'x': mem_type = MEM_X; break; case 'y': mem_type = MEM_Y; break; case 'p': mem_type = MEM_P; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } if (CMD_ARGC > 0) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); if (read_mem == 0) { if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC > 1) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], pattern); if (CMD_ARGC > 2) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], count); } if (read_mem == 1) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC > 1) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], count); } buffer = calloc(count, sizeof(uint32_t)); if (read_mem == 1) { err = dsp563xx_read_memory(target, mem_type, address, sizeof(uint32_t), count, buffer); if (err == ERROR_OK) handle_md_output(CMD_CTX, target, address, sizeof(uint32_t), count, buffer); } else { b = buffer; for (i = 0; i < count; i++) { target_buffer_set_u32(target, b, pattern); b += 4; } err = dsp563xx_write_memory(target, mem_type, address, sizeof(uint32_t), count, buffer); } free(buffer); return err; } static const struct command_registration dsp563xx_command_handlers[] = { { .name = "mwwx", .handler = dsp563xx_mem_command, .mode = COMMAND_EXEC, .help = "write x memory words", .usage = "mwwx address value [count]", }, { .name = "mwwy", .handler = dsp563xx_mem_command, .mode = COMMAND_EXEC, .help = "write y memory words", .usage = "mwwy address value [count]", }, { .name = "mwwp", .handler = dsp563xx_mem_command, .mode = COMMAND_EXEC, .help = "write p memory words", .usage = "mwwp address value [count]", }, { .name = "mdwx", .handler = dsp563xx_mem_command, .mode = COMMAND_EXEC, .help = "display x memory words", .usage = "mdwx address [count]", }, { .name = "mdwy", .handler = dsp563xx_mem_command, .mode = COMMAND_EXEC, .help = "display y memory words", .usage = "mdwy address [count]", }, { .name = "mdwp", .handler = dsp563xx_mem_command, .mode = COMMAND_EXEC, .help = "display p memory words", .usage = "mdwp address [count]", }, COMMAND_REGISTRATION_DONE }; /** Holds methods for DSP563XX targets. */ struct target_type dsp563xx_target = { .name = "dsp563xx", .poll = dsp563xx_poll, .arch_state = dsp563xx_arch_state, .target_request_data = NULL, .get_gdb_reg_list = dsp563xx_get_gdb_reg_list, .halt = dsp563xx_halt, .resume = dsp563xx_resume, .step = dsp563xx_step, .assert_reset = dsp563xx_assert_reset, .deassert_reset = dsp563xx_deassert_reset, .soft_reset_halt = dsp563xx_soft_reset_halt, .read_memory = dsp563xx_read_memory_default, .write_memory = dsp563xx_write_memory_default, .read_buffer = dsp563xx_read_buffer_default, .write_buffer = dsp563xx_write_buffer_default, .run_algorithm = dsp563xx_run_algorithm, .add_breakpoint = dsp563xx_add_breakpoint, .remove_breakpoint = dsp563xx_remove_breakpoint, .add_watchpoint = dsp563xx_add_watchpoint, .remove_watchpoint = dsp563xx_remove_watchpoint, .commands = dsp563xx_command_handlers, .target_create = dsp563xx_target_create, .init_target = dsp563xx_init_target, .examine = dsp563xx_examine, }; openocd-0.7.0/src/target/dsp563xx_once.h0000644000175000001440000000776012134336410014727 00000000000000/*************************************************************************** * Copyright (C) 2009 by Mathias Kuester * * mkdorg@users.sourceforge.net * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef DSP563XX_ONCE_H #define DSP563XX_ONCE_H #include #define DSP563XX_ONCE_OCR_EX (1<<5) #define DSP563XX_ONCE_OCR_GO (1<<6) #define DSP563XX_ONCE_OCR_RW (1<<7) #define DSP563XX_ONCE_OSCR_OS1 (1<<7) #define DSP563XX_ONCE_OSCR_OS0 (1<<6) #define DSP563XX_ONCE_OSCR_HIT (1<<5) #define DSP563XX_ONCE_OSCR_TO (1<<4) #define DSP563XX_ONCE_OSCR_MBO (1<<3) #define DSP563XX_ONCE_OSCR_SWO (1<<2) #define DSP563XX_ONCE_OSCR_IME (1<<1) #define DSP563XX_ONCE_OSCR_TME (1<<0) #define DSP563XX_ONCE_OSCR_NORMAL_M (0) #define DSP563XX_ONCE_OSCR_STOPWAIT_M (DSP563XX_ONCE_OSCR_OS0) #define DSP563XX_ONCE_OSCR_BUSY_M (DSP563XX_ONCE_OSCR_OS1) #define DSP563XX_ONCE_OSCR_DEBUG_M (DSP563XX_ONCE_OSCR_OS0|DSP563XX_ONCE_OSCR_OS1) #define DSP563XX_ONCE_OSCR 0x000 /* status/ctrl reg. */ #define DSP563XX_ONCE_OMBC 0x001 /* memory breakp. reg. */ #define DSP563XX_ONCE_OBCR 0x002 /* breakp. ctrl reg */ #define DSP563XX_ONCE_OMLR0 0x005 /* memory limit reg */ #define DSP563XX_ONCE_OMLR1 0x006 /* memory limit reg */ #define DSP563XX_ONCE_OGDBR 0x009 /* gdb reg */ #define DSP563XX_ONCE_OPDBR 0x00A /* pdb reg */ #define DSP563XX_ONCE_OPILR 0x00B /* pil reg */ #define DSP563XX_ONCE_PDBGOTO 0x00C /* pdb to go reg */ #define DSP563XX_ONCE_OTC 0x00D /* trace cnt */ #define DSP563XX_ONCE_TAGB 0x00E /* tags buffer */ #define DSP563XX_ONCE_OPABFR 0x00F /* pab fetch reg */ #define DSP563XX_ONCE_OPABDR 0x010 /* pab decode reg */ #define DSP563XX_ONCE_OPABEX 0x011 /* pab exec reg */ #define DSP563XX_ONCE_OPABF11 0x012 /* trace buffer/inc ptr */ #define DSP563XX_ONCE_NOREG 0x01F /* no register selected */ struct once_reg { uint8_t num; uint8_t addr; uint8_t len; const char *name; uint32_t reg; }; /** */ int dsp563xx_once_request_debug(struct jtag_tap *tap, int reset_state); /** */ int dsp563xx_once_target_status(struct jtag_tap *tap); /** once read registers */ int dsp563xx_once_read_register(struct jtag_tap *tap, int flush, struct once_reg *regs, int len); /** once read register */ int dsp563xx_once_reg_read_ex(struct jtag_tap *tap, int flush, uint8_t reg, uint8_t len, uint32_t * data); /** once read register */ int dsp563xx_once_reg_read(struct jtag_tap *tap, int flush, uint8_t reg, uint32_t * data); /** once write register */ int dsp563xx_once_reg_write(struct jtag_tap *tap, int flush, uint8_t reg, uint32_t data); /** single word instruction */ int dsp563xx_once_execute_sw_ir(struct jtag_tap *tap, int flush, uint32_t opcode); /** double word instruction */ int dsp563xx_once_execute_dw_ir(struct jtag_tap *tap, int flush, uint32_t opcode, uint32_t operand); #endif /* DSP563XX_ONCE_H */ openocd-0.7.0/src/target/cortex_a.h0000644000175000001440000000643512134336410014121 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2006 by Magnus Lundin * * lundin@mlu.mine.nu * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2009 by Dirk Behme * * dirk.behme@gmail.com - copy from cortex_m3 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef CORTEX_A8_H #define CORTEX_A8_H #include "armv7a.h" #define CORTEX_A8_COMMON_MAGIC 0x411fc082 #define CPUDBG_CPUID 0xD00 #define CPUDBG_CTYPR 0xD04 #define CPUDBG_TTYPR 0xD0C #define CPUDBG_LOCKACCESS 0xFB0 #define CPUDBG_LOCKSTATUS 0xFB4 #define BRP_NORMAL 0 #define BRP_CONTEXT 1 #define CORTEX_A8_PADDRDBG_CPU_SHIFT 13 struct cortex_a8_brp { int used; int type; uint32_t value; uint32_t control; uint8_t BRPn; }; struct cortex_a8_common { int common_magic; struct arm_jtag jtag_info; /* Context information */ uint32_t cpudbg_dscr; /* Saved cp15 registers */ uint32_t cp15_control_reg; /* latest cp15 register value written and cpsr processor mode */ uint32_t cp15_control_reg_curr; enum arm_mode curr_mode; /* Breakpoint register pairs */ int brp_num_context; int brp_num; int brp_num_available; struct cortex_a8_brp *brp_list; /* Use cortex_a8_read_regs_through_mem for fast register reads */ int fast_reg_read; struct armv7a_common armv7a_common; }; static inline struct cortex_a8_common * target_to_cortex_a8(struct target *target) { return container_of(target->arch_info, struct cortex_a8_common, armv7a_common.arm); } #endif /* CORTEX_A8_H */ openocd-0.7.0/src/target/arm_jtag.h0000644000175000001440000000635312134336410014100 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef ARM_JTAG #define ARM_JTAG #include struct arm_jtag { struct jtag_tap *tap; uint32_t scann_size; uint32_t scann_instr; uint32_t cur_scan_chain; uint32_t intest_instr; }; int arm_jtag_set_instr_inner(struct arm_jtag *jtag_info, uint32_t new_instr, void *no_verify_capture, tap_state_t end_state); static inline int arm_jtag_set_instr(struct arm_jtag *jtag_info, uint32_t new_instr, void *no_verify_capture, tap_state_t end_state) { /* inline most common code path */ struct jtag_tap *tap; tap = jtag_info->tap; assert(tap != NULL); if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != new_instr) return arm_jtag_set_instr_inner(jtag_info, new_instr, no_verify_capture, end_state); return ERROR_OK; } int arm_jtag_scann_inner(struct arm_jtag *jtag_info, uint32_t new_scan_chain, tap_state_t end_state); static inline int arm_jtag_scann(struct arm_jtag *jtag_info, uint32_t new_scan_chain, tap_state_t end_state) { /* inline most common code path */ int retval = ERROR_OK; if (jtag_info->cur_scan_chain != new_scan_chain) return arm_jtag_scann_inner(jtag_info, new_scan_chain, end_state); return retval; } int arm_jtag_setup_connection(struct arm_jtag *jtag_info); /* use this as a static so we can inline it in -O3 and refer to it via a pointer */ static inline void arm7flip32(jtag_callback_data_t arg) { uint8_t *in = (uint8_t *)arg; *((uint32_t *)arg) = flip_u32(le_to_h_u32(in), 32); } static inline void arm_le_to_h_u32(jtag_callback_data_t arg) { uint8_t *in = (uint8_t *)arg; *((uint32_t *)arg) = le_to_h_u32(in); } #endif /* ARM_JTAG */ openocd-0.7.0/src/target/image.c0000644000175000001440000007702412134336410013374 00000000000000/*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2009 by Franck Hereson * * franck.hereson@secad.fr * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "image.h" #include "target.h" #include /* convert ELF header field to host endianness */ #define field16(elf, field) \ ((elf->endianness == ELFDATA2LSB) ? \ le_to_h_u16((uint8_t *)&field) : be_to_h_u16((uint8_t *)&field)) #define field32(elf, field) \ ((elf->endianness == ELFDATA2LSB) ? \ le_to_h_u32((uint8_t *)&field) : be_to_h_u32((uint8_t *)&field)) static int autodetect_image_type(struct image *image, const char *url) { int retval; struct fileio fileio; size_t read_bytes; uint8_t buffer[9]; /* read the first 4 bytes of image */ retval = fileio_open(&fileio, url, FILEIO_READ, FILEIO_BINARY); if (retval != ERROR_OK) return retval; retval = fileio_read(&fileio, 9, buffer, &read_bytes); if (retval == ERROR_OK) { if (read_bytes != 9) retval = ERROR_FILEIO_OPERATION_FAILED; } fileio_close(&fileio); if (retval != ERROR_OK) return retval; /* check header against known signatures */ if (strncmp((char *)buffer, ELFMAG, SELFMAG) == 0) { LOG_DEBUG("ELF image detected."); image->type = IMAGE_ELF; } else if ((buffer[0] == ':') /* record start byte */ && (isxdigit(buffer[1])) && (isxdigit(buffer[2])) && (isxdigit(buffer[3])) && (isxdigit(buffer[4])) && (isxdigit(buffer[5])) && (isxdigit(buffer[6])) && (buffer[7] == '0') /* record type : 00 -> 05 */ && (buffer[8] >= '0') && (buffer[8] < '6')) { LOG_DEBUG("IHEX image detected."); image->type = IMAGE_IHEX; } else if ((buffer[0] == 'S') /* record start byte */ && (isxdigit(buffer[1])) && (isxdigit(buffer[2])) && (isxdigit(buffer[3])) && (buffer[1] >= '0') && (buffer[1] < '9')) { LOG_DEBUG("S19 image detected."); image->type = IMAGE_SRECORD; } else image->type = IMAGE_BINARY; return ERROR_OK; } static int identify_image_type(struct image *image, const char *type_string, const char *url) { if (type_string) { if (!strcmp(type_string, "bin")) image->type = IMAGE_BINARY; else if (!strcmp(type_string, "ihex")) image->type = IMAGE_IHEX; else if (!strcmp(type_string, "elf")) image->type = IMAGE_ELF; else if (!strcmp(type_string, "mem")) image->type = IMAGE_MEMORY; else if (!strcmp(type_string, "s19")) image->type = IMAGE_SRECORD; else if (!strcmp(type_string, "build")) image->type = IMAGE_BUILDER; else return ERROR_IMAGE_TYPE_UNKNOWN; } else return autodetect_image_type(image, url); return ERROR_OK; } static int image_ihex_buffer_complete_inner(struct image *image, char *lpszLine, struct imagesection *section) { struct image_ihex *ihex = image->type_private; struct fileio *fileio = &ihex->fileio; uint32_t full_address = 0x0; uint32_t cooked_bytes; int i; /* we can't determine the number of sections that we'll have to create ahead of time, * so we locally hold them until parsing is finished */ int filesize; int retval; retval = fileio_size(fileio, &filesize); if (retval != ERROR_OK) return retval; ihex->buffer = malloc(filesize >> 1); cooked_bytes = 0x0; image->num_sections = 0; section[image->num_sections].private = &ihex->buffer[cooked_bytes]; section[image->num_sections].base_address = 0x0; section[image->num_sections].size = 0x0; section[image->num_sections].flags = 0; while (fileio_fgets(fileio, 1023, lpszLine) == ERROR_OK) { uint32_t count; uint32_t address; uint32_t record_type; uint32_t checksum; uint8_t cal_checksum = 0; size_t bytes_read = 0; if (sscanf(&lpszLine[bytes_read], ":%2" SCNx32 "%4" SCNx32 "%2" SCNx32, &count, &address, &record_type) != 3) return ERROR_IMAGE_FORMAT_ERROR; bytes_read += 9; cal_checksum += (uint8_t)count; cal_checksum += (uint8_t)(address >> 8); cal_checksum += (uint8_t)address; cal_checksum += (uint8_t)record_type; if (record_type == 0) { /* Data Record */ if ((full_address & 0xffff) != address) { /* we encountered a nonconsecutive location, create a new section, * unless the current section has zero size, in which case this specifies * the current section's base address */ if (section[image->num_sections].size != 0) { image->num_sections++; if (image->num_sections >= IMAGE_MAX_SECTIONS) { /* too many sections */ LOG_ERROR("Too many sections found in IHEX file"); return ERROR_IMAGE_FORMAT_ERROR; } section[image->num_sections].size = 0x0; section[image->num_sections].flags = 0; section[image->num_sections].private = &ihex->buffer[cooked_bytes]; } section[image->num_sections].base_address = (full_address & 0xffff0000) | address; full_address = (full_address & 0xffff0000) | address; } while (count-- > 0) { unsigned value; sscanf(&lpszLine[bytes_read], "%2x", &value); ihex->buffer[cooked_bytes] = (uint8_t)value; cal_checksum += (uint8_t)ihex->buffer[cooked_bytes]; bytes_read += 2; cooked_bytes += 1; section[image->num_sections].size += 1; full_address++; } } else if (record_type == 1) { /* End of File Record */ /* finish the current section */ image->num_sections++; /* copy section information */ image->sections = malloc(sizeof(struct imagesection) * image->num_sections); for (i = 0; i < image->num_sections; i++) { image->sections[i].private = section[i].private; image->sections[i].base_address = section[i].base_address; image->sections[i].size = section[i].size; image->sections[i].flags = section[i].flags; } return ERROR_OK; } else if (record_type == 2) { /* Linear Address Record */ uint16_t upper_address; sscanf(&lpszLine[bytes_read], "%4hx", &upper_address); cal_checksum += (uint8_t)(upper_address >> 8); cal_checksum += (uint8_t)upper_address; bytes_read += 4; if ((full_address >> 4) != upper_address) { /* we encountered a nonconsecutive location, create a new section, * unless the current section has zero size, in which case this specifies * the current section's base address */ if (section[image->num_sections].size != 0) { image->num_sections++; if (image->num_sections >= IMAGE_MAX_SECTIONS) { /* too many sections */ LOG_ERROR("Too many sections found in IHEX file"); return ERROR_IMAGE_FORMAT_ERROR; } section[image->num_sections].size = 0x0; section[image->num_sections].flags = 0; section[image->num_sections].private = &ihex->buffer[cooked_bytes]; } section[image->num_sections].base_address = (full_address & 0xffff) | (upper_address << 4); full_address = (full_address & 0xffff) | (upper_address << 4); } } else if (record_type == 3) { /* Start Segment Address Record */ uint32_t dummy; /* "Start Segment Address Record" will not be supported * but we must consume it, and do not create an error. */ while (count-- > 0) { sscanf(&lpszLine[bytes_read], "%2" SCNx32, &dummy); cal_checksum += (uint8_t)dummy; bytes_read += 2; } } else if (record_type == 4) { /* Extended Linear Address Record */ uint16_t upper_address; sscanf(&lpszLine[bytes_read], "%4hx", &upper_address); cal_checksum += (uint8_t)(upper_address >> 8); cal_checksum += (uint8_t)upper_address; bytes_read += 4; if ((full_address >> 16) != upper_address) { /* we encountered a nonconsecutive location, create a new section, * unless the current section has zero size, in which case this specifies * the current section's base address */ if (section[image->num_sections].size != 0) { image->num_sections++; if (image->num_sections >= IMAGE_MAX_SECTIONS) { /* too many sections */ LOG_ERROR("Too many sections found in IHEX file"); return ERROR_IMAGE_FORMAT_ERROR; } section[image->num_sections].size = 0x0; section[image->num_sections].flags = 0; section[image->num_sections].private = &ihex->buffer[cooked_bytes]; } section[image->num_sections].base_address = (full_address & 0xffff) | (upper_address << 16); full_address = (full_address & 0xffff) | (upper_address << 16); } } else if (record_type == 5) { /* Start Linear Address Record */ uint32_t start_address; sscanf(&lpszLine[bytes_read], "%8" SCNx32, &start_address); cal_checksum += (uint8_t)(start_address >> 24); cal_checksum += (uint8_t)(start_address >> 16); cal_checksum += (uint8_t)(start_address >> 8); cal_checksum += (uint8_t)start_address; bytes_read += 8; image->start_address_set = 1; image->start_address = be_to_h_u32((uint8_t *)&start_address); } else { LOG_ERROR("unhandled IHEX record type: %i", (int)record_type); return ERROR_IMAGE_FORMAT_ERROR; } sscanf(&lpszLine[bytes_read], "%2" SCNx32, &checksum); if ((uint8_t)checksum != (uint8_t)(~cal_checksum + 1)) { /* checksum failed */ LOG_ERROR("incorrect record checksum found in IHEX file"); return ERROR_IMAGE_CHECKSUM; } } LOG_ERROR("premature end of IHEX file, no end-of-file record found"); return ERROR_IMAGE_FORMAT_ERROR; } /** * Allocate memory dynamically instead of on the stack. This * is important w/embedded hosts. */ static int image_ihex_buffer_complete(struct image *image) { char *lpszLine = malloc(1023); if (lpszLine == NULL) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } struct imagesection *section = malloc(sizeof(struct imagesection) * IMAGE_MAX_SECTIONS); if (section == NULL) { free(lpszLine); LOG_ERROR("Out of memory"); return ERROR_FAIL; } int retval; retval = image_ihex_buffer_complete_inner(image, lpszLine, section); free(section); free(lpszLine); return retval; } static int image_elf_read_headers(struct image *image) { struct image_elf *elf = image->type_private; size_t read_bytes; uint32_t i, j; int retval; uint32_t nload, load_to_vaddr = 0; elf->header = malloc(sizeof(Elf32_Ehdr)); if (elf->header == NULL) { LOG_ERROR("insufficient memory to perform operation "); return ERROR_FILEIO_OPERATION_FAILED; } retval = fileio_read(&elf->fileio, sizeof(Elf32_Ehdr), (uint8_t *)elf->header, &read_bytes); if (retval != ERROR_OK) { LOG_ERROR("cannot read ELF file header, read failed"); return ERROR_FILEIO_OPERATION_FAILED; } if (read_bytes != sizeof(Elf32_Ehdr)) { LOG_ERROR("cannot read ELF file header, only partially read"); return ERROR_FILEIO_OPERATION_FAILED; } if (strncmp((char *)elf->header->e_ident, ELFMAG, SELFMAG) != 0) { LOG_ERROR("invalid ELF file, bad magic number"); return ERROR_IMAGE_FORMAT_ERROR; } if (elf->header->e_ident[EI_CLASS] != ELFCLASS32) { LOG_ERROR("invalid ELF file, only 32bits files are supported"); return ERROR_IMAGE_FORMAT_ERROR; } elf->endianness = elf->header->e_ident[EI_DATA]; if ((elf->endianness != ELFDATA2LSB) && (elf->endianness != ELFDATA2MSB)) { LOG_ERROR("invalid ELF file, unknown endianness setting"); return ERROR_IMAGE_FORMAT_ERROR; } elf->segment_count = field16(elf, elf->header->e_phnum); if (elf->segment_count == 0) { LOG_ERROR("invalid ELF file, no program headers"); return ERROR_IMAGE_FORMAT_ERROR; } retval = fileio_seek(&elf->fileio, field32(elf, elf->header->e_phoff)); if (retval != ERROR_OK) { LOG_ERROR("cannot seek to ELF program header table, read failed"); return retval; } elf->segments = malloc(elf->segment_count*sizeof(Elf32_Phdr)); if (elf->segments == NULL) { LOG_ERROR("insufficient memory to perform operation "); return ERROR_FILEIO_OPERATION_FAILED; } retval = fileio_read(&elf->fileio, elf->segment_count*sizeof(Elf32_Phdr), (uint8_t *)elf->segments, &read_bytes); if (retval != ERROR_OK) { LOG_ERROR("cannot read ELF segment headers, read failed"); return retval; } if (read_bytes != elf->segment_count*sizeof(Elf32_Phdr)) { LOG_ERROR("cannot read ELF segment headers, only partially read"); return ERROR_FILEIO_OPERATION_FAILED; } /* count useful segments (loadable), ignore BSS section */ image->num_sections = 0; for (i = 0; i < elf->segment_count; i++) if ((field32(elf, elf->segments[i].p_type) == PT_LOAD) && (field32(elf, elf->segments[i].p_filesz) != 0)) image->num_sections++; assert(image->num_sections > 0); /** * some ELF linkers produce binaries with *all* the program header * p_paddr fields zero (there can be however one loadable segment * that has valid physical address 0x0). * If we have such a binary with more than * one PT_LOAD header, then use p_vaddr instead of p_paddr * (ARM ELF standard demands p_paddr = 0 anyway, and BFD * library uses this approach to workaround zero-initialized p_paddrs * when obtaining lma - look at elf.c of BDF) */ for (nload = 0, i = 0; i < elf->segment_count; i++) if (elf->segments[i].p_paddr != 0) break; else if ((field32(elf, elf->segments[i].p_type) == PT_LOAD) && (field32(elf, elf->segments[i].p_memsz) != 0)) ++nload; if (i >= elf->segment_count && nload > 1) load_to_vaddr = 1; /* alloc and fill sections array with loadable segments */ image->sections = malloc(image->num_sections * sizeof(struct imagesection)); for (i = 0, j = 0; i < elf->segment_count; i++) { if ((field32(elf, elf->segments[i].p_type) == PT_LOAD) && (field32(elf, elf->segments[i].p_filesz) != 0)) { image->sections[j].size = field32(elf, elf->segments[i].p_filesz); if (load_to_vaddr) image->sections[j].base_address = field32(elf, elf->segments[i].p_vaddr); else image->sections[j].base_address = field32(elf, elf->segments[i].p_paddr); image->sections[j].private = &elf->segments[i]; image->sections[j].flags = field32(elf, elf->segments[i].p_flags); j++; } } image->start_address_set = 1; image->start_address = field32(elf, elf->header->e_entry); return ERROR_OK; } static int image_elf_read_section(struct image *image, int section, uint32_t offset, uint32_t size, uint8_t *buffer, size_t *size_read) { struct image_elf *elf = image->type_private; Elf32_Phdr *segment = (Elf32_Phdr *)image->sections[section].private; size_t read_size, really_read; int retval; *size_read = 0; LOG_DEBUG("load segment %d at 0x%" PRIx32 " (sz = 0x%" PRIx32 ")", section, offset, size); /* read initialized data in current segment if any */ if (offset < field32(elf, segment->p_filesz)) { /* maximal size present in file for the current segment */ read_size = MIN(size, field32(elf, segment->p_filesz) - offset); LOG_DEBUG("read elf: size = 0x%zu at 0x%" PRIx32 "", read_size, field32(elf, segment->p_offset) + offset); /* read initialized area of the segment */ retval = fileio_seek(&elf->fileio, field32(elf, segment->p_offset) + offset); if (retval != ERROR_OK) { LOG_ERROR("cannot find ELF segment content, seek failed"); return retval; } retval = fileio_read(&elf->fileio, read_size, buffer, &really_read); if (retval != ERROR_OK) { LOG_ERROR("cannot read ELF segment content, read failed"); return retval; } size -= read_size; *size_read += read_size; /* need more data ? */ if (!size) return ERROR_OK; } return ERROR_OK; } static int image_mot_buffer_complete_inner(struct image *image, char *lpszLine, struct imagesection *section) { struct image_mot *mot = image->type_private; struct fileio *fileio = &mot->fileio; uint32_t full_address = 0x0; uint32_t cooked_bytes; int i; /* we can't determine the number of sections that we'll have to create ahead of time, * so we locally hold them until parsing is finished */ int retval; int filesize; retval = fileio_size(fileio, &filesize); if (retval != ERROR_OK) return retval; mot->buffer = malloc(filesize >> 1); cooked_bytes = 0x0; image->num_sections = 0; section[image->num_sections].private = &mot->buffer[cooked_bytes]; section[image->num_sections].base_address = 0x0; section[image->num_sections].size = 0x0; section[image->num_sections].flags = 0; while (fileio_fgets(fileio, 1023, lpszLine) == ERROR_OK) { uint32_t count; uint32_t address; uint32_t record_type; uint32_t checksum; uint8_t cal_checksum = 0; uint32_t bytes_read = 0; /* get record type and record length */ if (sscanf(&lpszLine[bytes_read], "S%1" SCNx32 "%2" SCNx32, &record_type, &count) != 2) return ERROR_IMAGE_FORMAT_ERROR; bytes_read += 4; cal_checksum += (uint8_t)count; /* skip checksum byte */ count -= 1; if (record_type == 0) { /* S0 - starting record (optional) */ int iValue; while (count-- > 0) { sscanf(&lpszLine[bytes_read], "%2x", &iValue); cal_checksum += (uint8_t)iValue; bytes_read += 2; } } else if (record_type >= 1 && record_type <= 3) { switch (record_type) { case 1: /* S1 - 16 bit address data record */ sscanf(&lpszLine[bytes_read], "%4" SCNx32, &address); cal_checksum += (uint8_t)(address >> 8); cal_checksum += (uint8_t)address; bytes_read += 4; count -= 2; break; case 2: /* S2 - 24 bit address data record */ sscanf(&lpszLine[bytes_read], "%6" SCNx32, &address); cal_checksum += (uint8_t)(address >> 16); cal_checksum += (uint8_t)(address >> 8); cal_checksum += (uint8_t)address; bytes_read += 6; count -= 3; break; case 3: /* S3 - 32 bit address data record */ sscanf(&lpszLine[bytes_read], "%8" SCNx32, &address); cal_checksum += (uint8_t)(address >> 24); cal_checksum += (uint8_t)(address >> 16); cal_checksum += (uint8_t)(address >> 8); cal_checksum += (uint8_t)address; bytes_read += 8; count -= 4; break; } if (full_address != address) { /* we encountered a nonconsecutive location, create a new section, * unless the current section has zero size, in which case this specifies * the current section's base address */ if (section[image->num_sections].size != 0) { image->num_sections++; section[image->num_sections].size = 0x0; section[image->num_sections].flags = 0; section[image->num_sections].private = &mot->buffer[cooked_bytes]; } section[image->num_sections].base_address = address; full_address = address; } while (count-- > 0) { unsigned value; sscanf(&lpszLine[bytes_read], "%2x", &value); mot->buffer[cooked_bytes] = (uint8_t)value; cal_checksum += (uint8_t)mot->buffer[cooked_bytes]; bytes_read += 2; cooked_bytes += 1; section[image->num_sections].size += 1; full_address++; } } else if (record_type == 5) { /* S5 is the data count record, we ignore it */ uint32_t dummy; while (count-- > 0) { sscanf(&lpszLine[bytes_read], "%2" SCNx32, &dummy); cal_checksum += (uint8_t)dummy; bytes_read += 2; } } else if (record_type >= 7 && record_type <= 9) { /* S7, S8, S9 - ending records for 32, 24 and 16bit */ image->num_sections++; /* copy section information */ image->sections = malloc(sizeof(struct imagesection) * image->num_sections); for (i = 0; i < image->num_sections; i++) { image->sections[i].private = section[i].private; image->sections[i].base_address = section[i].base_address; image->sections[i].size = section[i].size; image->sections[i].flags = section[i].flags; } return ERROR_OK; } else { LOG_ERROR("unhandled S19 record type: %i", (int)(record_type)); return ERROR_IMAGE_FORMAT_ERROR; } /* account for checksum, will always be 0xFF */ sscanf(&lpszLine[bytes_read], "%2" SCNx32, &checksum); cal_checksum += (uint8_t)checksum; if (cal_checksum != 0xFF) { /* checksum failed */ LOG_ERROR("incorrect record checksum found in S19 file"); return ERROR_IMAGE_CHECKSUM; } } LOG_ERROR("premature end of S19 file, no end-of-file record found"); return ERROR_IMAGE_FORMAT_ERROR; } /** * Allocate memory dynamically instead of on the stack. This * is important w/embedded hosts. */ static int image_mot_buffer_complete(struct image *image) { char *lpszLine = malloc(1023); if (lpszLine == NULL) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } struct imagesection *section = malloc(sizeof(struct imagesection) * IMAGE_MAX_SECTIONS); if (section == NULL) { free(lpszLine); LOG_ERROR("Out of memory"); return ERROR_FAIL; } int retval; retval = image_mot_buffer_complete_inner(image, lpszLine, section); free(section); free(lpszLine); return retval; } int image_open(struct image *image, const char *url, const char *type_string) { int retval = ERROR_OK; retval = identify_image_type(image, type_string, url); if (retval != ERROR_OK) return retval; if (image->type == IMAGE_BINARY) { struct image_binary *image_binary; image_binary = image->type_private = malloc(sizeof(struct image_binary)); retval = fileio_open(&image_binary->fileio, url, FILEIO_READ, FILEIO_BINARY); if (retval != ERROR_OK) return retval; int filesize; retval = fileio_size(&image_binary->fileio, &filesize); if (retval != ERROR_OK) { fileio_close(&image_binary->fileio); return retval; } image->num_sections = 1; image->sections = malloc(sizeof(struct imagesection)); image->sections[0].base_address = 0x0; image->sections[0].size = filesize; image->sections[0].flags = 0; } else if (image->type == IMAGE_IHEX) { struct image_ihex *image_ihex; image_ihex = image->type_private = malloc(sizeof(struct image_ihex)); retval = fileio_open(&image_ihex->fileio, url, FILEIO_READ, FILEIO_TEXT); if (retval != ERROR_OK) return retval; retval = image_ihex_buffer_complete(image); if (retval != ERROR_OK) { LOG_ERROR( "failed buffering IHEX image, check daemon output for additional information"); fileio_close(&image_ihex->fileio); return retval; } } else if (image->type == IMAGE_ELF) { struct image_elf *image_elf; image_elf = image->type_private = malloc(sizeof(struct image_elf)); retval = fileio_open(&image_elf->fileio, url, FILEIO_READ, FILEIO_BINARY); if (retval != ERROR_OK) return retval; retval = image_elf_read_headers(image); if (retval != ERROR_OK) { fileio_close(&image_elf->fileio); return retval; } } else if (image->type == IMAGE_MEMORY) { struct target *target = get_target(url); if (target == NULL) { LOG_ERROR("target '%s' not defined", url); return ERROR_FAIL; } struct image_memory *image_memory; image->num_sections = 1; image->sections = malloc(sizeof(struct imagesection)); image->sections[0].base_address = 0x0; image->sections[0].size = 0xffffffff; image->sections[0].flags = 0; image_memory = image->type_private = malloc(sizeof(struct image_memory)); image_memory->target = target; image_memory->cache = NULL; image_memory->cache_address = 0x0; } else if (image->type == IMAGE_SRECORD) { struct image_mot *image_mot; image_mot = image->type_private = malloc(sizeof(struct image_mot)); retval = fileio_open(&image_mot->fileio, url, FILEIO_READ, FILEIO_TEXT); if (retval != ERROR_OK) return retval; retval = image_mot_buffer_complete(image); if (retval != ERROR_OK) { LOG_ERROR( "failed buffering S19 image, check daemon output for additional information"); fileio_close(&image_mot->fileio); return retval; } } else if (image->type == IMAGE_BUILDER) { image->num_sections = 0; image->sections = NULL; image->type_private = NULL; } if (image->base_address_set) { /* relocate */ int section; for (section = 0; section < image->num_sections; section++) image->sections[section].base_address += image->base_address; /* we're done relocating. The two statements below are mainly * for documenation purposes: stop anyone from empirically * thinking they should use these values henceforth. */ image->base_address = 0; image->base_address_set = 0; } return retval; }; int image_read_section(struct image *image, int section, uint32_t offset, uint32_t size, uint8_t *buffer, size_t *size_read) { int retval; /* don't read past the end of a section */ if (offset + size > image->sections[section].size) { LOG_DEBUG( "read past end of section: 0x%8.8" PRIx32 " + 0x%8.8" PRIx32 " > 0x%8.8" PRIx32 "", offset, size, image->sections[section].size); return ERROR_COMMAND_SYNTAX_ERROR; } if (image->type == IMAGE_BINARY) { struct image_binary *image_binary = image->type_private; /* only one section in a plain binary */ if (section != 0) return ERROR_COMMAND_SYNTAX_ERROR; /* seek to offset */ retval = fileio_seek(&image_binary->fileio, offset); if (retval != ERROR_OK) return retval; /* return requested bytes */ retval = fileio_read(&image_binary->fileio, size, buffer, size_read); if (retval != ERROR_OK) return retval; } else if (image->type == IMAGE_IHEX) { memcpy(buffer, (uint8_t *)image->sections[section].private + offset, size); *size_read = size; return ERROR_OK; } else if (image->type == IMAGE_ELF) return image_elf_read_section(image, section, offset, size, buffer, size_read); else if (image->type == IMAGE_MEMORY) { struct image_memory *image_memory = image->type_private; uint32_t address = image->sections[section].base_address + offset; *size_read = 0; while ((size - *size_read) > 0) { uint32_t size_in_cache; if (!image_memory->cache || (address < image_memory->cache_address) || (address >= (image_memory->cache_address + IMAGE_MEMORY_CACHE_SIZE))) { if (!image_memory->cache) image_memory->cache = malloc(IMAGE_MEMORY_CACHE_SIZE); if (target_read_buffer(image_memory->target, address & ~(IMAGE_MEMORY_CACHE_SIZE - 1), IMAGE_MEMORY_CACHE_SIZE, image_memory->cache) != ERROR_OK) { free(image_memory->cache); image_memory->cache = NULL; return ERROR_IMAGE_TEMPORARILY_UNAVAILABLE; } image_memory->cache_address = address & ~(IMAGE_MEMORY_CACHE_SIZE - 1); } size_in_cache = (image_memory->cache_address + IMAGE_MEMORY_CACHE_SIZE) - address; memcpy(buffer + *size_read, image_memory->cache + (address - image_memory->cache_address), (size_in_cache > size) ? size : size_in_cache ); *size_read += (size_in_cache > size) ? size : size_in_cache; address += (size_in_cache > size) ? size : size_in_cache; } } else if (image->type == IMAGE_SRECORD) { memcpy(buffer, (uint8_t *)image->sections[section].private + offset, size); *size_read = size; return ERROR_OK; } else if (image->type == IMAGE_BUILDER) { memcpy(buffer, (uint8_t *)image->sections[section].private + offset, size); *size_read = size; return ERROR_OK; } return ERROR_OK; } int image_add_section(struct image *image, uint32_t base, uint32_t size, int flags, uint8_t *data) { struct imagesection *section; /* only image builder supports adding sections */ if (image->type != IMAGE_BUILDER) return ERROR_COMMAND_SYNTAX_ERROR; /* see if there's a previous section */ if (image->num_sections) { section = &image->sections[image->num_sections - 1]; /* see if it's enough to extend the last section, * adding data to previous sections or merging is not supported */ if (((section->base_address + section->size) == base) && (section->flags == flags)) { section->private = realloc(section->private, section->size + size); memcpy((uint8_t *)section->private + section->size, data, size); section->size += size; return ERROR_OK; } } /* allocate new section */ image->num_sections++; image->sections = realloc(image->sections, sizeof(struct imagesection) * image->num_sections); section = &image->sections[image->num_sections - 1]; section->base_address = base; section->size = size; section->flags = flags; section->private = malloc(sizeof(uint8_t) * size); memcpy((uint8_t *)section->private, data, size); return ERROR_OK; } void image_close(struct image *image) { if (image->type == IMAGE_BINARY) { struct image_binary *image_binary = image->type_private; fileio_close(&image_binary->fileio); } else if (image->type == IMAGE_IHEX) { struct image_ihex *image_ihex = image->type_private; fileio_close(&image_ihex->fileio); if (image_ihex->buffer) { free(image_ihex->buffer); image_ihex->buffer = NULL; } } else if (image->type == IMAGE_ELF) { struct image_elf *image_elf = image->type_private; fileio_close(&image_elf->fileio); if (image_elf->header) { free(image_elf->header); image_elf->header = NULL; } if (image_elf->segments) { free(image_elf->segments); image_elf->segments = NULL; } } else if (image->type == IMAGE_MEMORY) { struct image_memory *image_memory = image->type_private; if (image_memory->cache) { free(image_memory->cache); image_memory->cache = NULL; } } else if (image->type == IMAGE_SRECORD) { struct image_mot *image_mot = image->type_private; fileio_close(&image_mot->fileio); if (image_mot->buffer) { free(image_mot->buffer); image_mot->buffer = NULL; } } else if (image->type == IMAGE_BUILDER) { int i; for (i = 0; i < image->num_sections; i++) { free(image->sections[i].private); image->sections[i].private = NULL; } } if (image->type_private) { free(image->type_private); image->type_private = NULL; } if (image->sections) { free(image->sections); image->sections = NULL; } } int image_calculate_checksum(uint8_t *buffer, uint32_t nbytes, uint32_t *checksum) { uint32_t crc = 0xffffffff; LOG_DEBUG("Calculating checksum"); static uint32_t crc32_table[256]; static bool first_init; if (!first_init) { /* Initialize the CRC table and the decoding table. */ int i, j; unsigned int c; for (i = 0; i < 256; i++) { /* as per gdb */ for (c = i << 24, j = 8; j > 0; --j) c = c & 0x80000000 ? (c << 1) ^ 0x04c11db7 : (c << 1); crc32_table[i] = c; } first_init = true; } while (nbytes > 0) { int run = nbytes; if (run > 32768) run = 32768; nbytes -= run; while (run--) { /* as per gdb */ crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ *buffer++) & 255]; } keep_alive(); } LOG_DEBUG("Calculating checksum done"); *checksum = crc; return ERROR_OK; } openocd-0.7.0/src/target/arm_jtag.c0000644000175000001440000000647612134336410014101 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm_jtag.h" #if 0 #define _ARM_JTAG_SCAN_N_CHECK_ #endif int arm_jtag_set_instr_inner(struct arm_jtag *jtag_info, uint32_t new_instr, void *no_verify_capture, tap_state_t end_state) { struct jtag_tap *tap; tap = jtag_info->tap; struct scan_field field; uint8_t t[4]; field.num_bits = tap->ir_length; field.out_value = t; buf_set_u32(t, 0, field.num_bits, new_instr); field.in_value = NULL; if (no_verify_capture == NULL) jtag_add_ir_scan(tap, &field, end_state); else { /* FIX!!!! this is a kludge!!! arm926ejs.c should reimplement this arm_jtag_set_instr to * have special verification code. */ jtag_add_ir_scan_noverify(tap, &field, end_state); } return ERROR_OK; } int arm_jtag_scann_inner(struct arm_jtag *jtag_info, uint32_t new_scan_chain, tap_state_t end_state) { int retval = ERROR_OK; uint32_t values[1]; int num_bits[1]; values[0] = new_scan_chain; num_bits[0] = jtag_info->scann_size; retval = arm_jtag_set_instr(jtag_info, jtag_info->scann_instr, NULL, end_state); if (retval != ERROR_OK) return retval; jtag_add_dr_out(jtag_info->tap, 1, num_bits, values, end_state); jtag_info->cur_scan_chain = new_scan_chain; return retval; } static int arm_jtag_reset_callback(enum jtag_event event, void *priv) { struct arm_jtag *jtag_info = priv; if (event == JTAG_TRST_ASSERTED) jtag_info->cur_scan_chain = 0; return ERROR_OK; } int arm_jtag_setup_connection(struct arm_jtag *jtag_info) { jtag_info->scann_instr = 0x2; jtag_info->cur_scan_chain = 0; jtag_info->intest_instr = 0xc; return jtag_register_event_callback(arm_jtag_reset_callback, jtag_info); } openocd-0.7.0/src/target/Makefile.in0000644000175000001440000006663312141414276014224 00000000000000# Makefile.in generated by automake 1.13.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ DIST_COMMON = $(top_srcdir)/common.mk $(srcdir)/Makefile.in \ $(srcdir)/Makefile.am $(top_srcdir)/depcomp \ $(nobase_dist_ocddata_DATA) $(noinst_HEADERS) @INTERNAL_JIMTCL_TRUE@am__append_1 = -I$(top_srcdir)/jimtcl \ @INTERNAL_JIMTCL_TRUE@ -I$(top_builddir)/jimtcl subdir = src/target ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/config_subdir.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libtarget_la_LIBADD = am__libtarget_la_SOURCES_DIST = algorithm.c register.c image.c \ breakpoints.c target.c target_request.c testee.c smp.c \ arm_dpm.c arm_jtag.c arm_disassembler.c arm_simulator.c \ arm_semihosting.c arm_adi_v5.c adi_v5_jtag.c adi_v5_swd.c \ embeddedice.c trace.c etb.c etm.c oocd_trace.c etm_dummy.c \ armv4_5.c armv4_5_mmu.c armv4_5_cache.c arm7_9_common.c \ arm7tdmi.c arm720t.c arm9tdmi.c arm920t.c arm966e.c arm946e.c \ arm926ejs.c feroceon.c arm11.c arm11_dbgtap.c armv7m.c \ cortex_m.c armv7a.c cortex_a.c fa526.c xscale.c avr32_ap7k.c \ avr32_jtag.c avr32_mem.c avr32_regs.c mips32.c mips_m4k.c \ mips32_pracc.c mips32_dmaacc.c mips_ejtag.c avrt.c dsp563xx.c \ dsp563xx_once.c dsp5680xx.c hla_target.c am__objects_1 = algorithm.lo register.lo image.lo breakpoints.lo \ target.lo target_request.lo testee.lo smp.lo @OOCD_TRACE_TRUE@am__objects_2 = oocd_trace.lo am__objects_3 = arm_dpm.lo arm_jtag.lo arm_disassembler.lo \ arm_simulator.lo arm_semihosting.lo arm_adi_v5.lo \ adi_v5_jtag.lo adi_v5_swd.lo embeddedice.lo trace.lo etb.lo \ etm.lo $(am__objects_2) etm_dummy.lo am__objects_4 = arm7_9_common.lo arm7tdmi.lo arm720t.lo arm9tdmi.lo \ arm920t.lo arm966e.lo arm946e.lo arm926ejs.lo feroceon.lo am__objects_5 = armv4_5.lo armv4_5_mmu.lo armv4_5_cache.lo \ $(am__objects_4) am__objects_6 = arm11.lo arm11_dbgtap.lo am__objects_7 = armv7m.lo cortex_m.lo armv7a.lo cortex_a.lo am__objects_8 = fa526.lo xscale.lo am__objects_9 = avr32_ap7k.lo avr32_jtag.lo avr32_mem.lo avr32_regs.lo am__objects_10 = mips32.lo mips_m4k.lo mips32_pracc.lo \ mips32_dmaacc.lo mips_ejtag.lo am_libtarget_la_OBJECTS = $(am__objects_1) $(am__objects_3) \ $(am__objects_5) $(am__objects_6) $(am__objects_7) \ $(am__objects_8) $(am__objects_9) $(am__objects_10) avrt.lo \ dsp563xx.lo dsp563xx_once.lo dsp5680xx.lo hla_target.lo libtarget_la_OBJECTS = $(am_libtarget_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libtarget_la_SOURCES) DIST_SOURCES = $(am__libtarget_la_SOURCES_DIST) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(ocddatadir)" DATA = $(nobase_dist_ocddata_DATA) HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CC_FOR_BUILD = @CC_FOR_BUILD@ CFLAGS = @CFLAGS@ CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@ FGREP = @FGREP@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ doxygen_as_html = @doxygen_as_html@ doxygen_as_pdf = @doxygen_as_pdf@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ # common flags used in openocd build AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src \ -I$(top_srcdir)/src/helper -DPKGDATADIR=\"$(pkgdatadir)\" \ -DPKGLIBDIR=\"$(pkglibdir)\" $(am__append_1) @OOCD_TRACE_FALSE@OOCD_TRACE_FILES = @OOCD_TRACE_TRUE@OOCD_TRACE_FILES = oocd_trace.c BIN2C = $(top_builddir)/src/helper/bin2char$(EXEEXT_FOR_BUILD) DEBUG_HANDLER = $(srcdir)/xscale/debug_handler.bin EXTRA_DIST = \ startup.tcl \ $(DEBUG_HANDLER) DEBUG_HEADER = xscale_debug.h BUILT_SOURCES = $(DEBUG_HEADER) CLEANFILES = $(DEBUG_HEADER) METASOURCES = AUTO noinst_LTLIBRARIES = libtarget.la libtarget_la_SOURCES = \ $(TARGET_CORE_SRC) \ $(ARM_DEBUG_SRC) \ $(ARMV4_5_SRC) \ $(ARMV6_SRC) \ $(ARMV7_SRC) \ $(ARM_MISC_SRC) \ $(AVR32_SRC) \ $(MIPS32_SRC) \ avrt.c \ dsp563xx.c \ dsp563xx_once.c \ dsp5680xx.c \ hla_target.c TARGET_CORE_SRC = \ algorithm.c \ register.c \ image.c \ breakpoints.c \ target.c \ target_request.c \ testee.c \ smp.c ARMV4_5_SRC = \ armv4_5.c \ armv4_5_mmu.c \ armv4_5_cache.c \ $(ARM7_9_SRC) ARM7_9_SRC = \ arm7_9_common.c \ arm7tdmi.c \ arm720t.c \ arm9tdmi.c \ arm920t.c \ arm966e.c \ arm946e.c \ arm926ejs.c \ feroceon.c ARM_MISC_SRC = \ fa526.c \ xscale.c ARMV6_SRC = \ arm11.c \ arm11_dbgtap.c ARMV7_SRC = \ armv7m.c \ cortex_m.c \ armv7a.c \ cortex_a.c ARM_DEBUG_SRC = \ arm_dpm.c \ arm_jtag.c \ arm_disassembler.c \ arm_simulator.c \ arm_semihosting.c \ arm_adi_v5.c \ adi_v5_jtag.c \ adi_v5_swd.c \ embeddedice.c \ trace.c \ etb.c \ etm.c \ $(OOCD_TRACE_FILES) \ etm_dummy.c AVR32_SRC = \ avr32_ap7k.c \ avr32_jtag.c \ avr32_mem.c \ avr32_regs.c MIPS32_SRC = \ mips32.c \ mips_m4k.c \ mips32_pracc.c \ mips32_dmaacc.c \ mips_ejtag.c noinst_HEADERS = \ algorithm.h \ arm.h \ arm_dpm.h \ arm_jtag.h \ arm_adi_v5.h \ arm_disassembler.h \ arm_opcodes.h \ arm_simulator.h \ arm_semihosting.h \ arm7_9_common.h \ arm7tdmi.h \ arm720t.h \ arm9tdmi.h \ arm920t.h \ arm926ejs.h \ arm966e.h \ arm946e.h \ arm11.h \ arm11_dbgtap.h \ armv4_5.h \ armv4_5_mmu.h \ armv4_5_cache.h \ armv7a.h \ armv7m.h \ avrt.h \ dsp563xx.h \ dsp563xx_once.h \ dsp5680xx.h \ breakpoints.h \ cortex_m.h \ cortex_a.h \ embeddedice.h \ etb.h \ etm.h \ etm_dummy.h \ image.h \ mips32.h \ mips_m4k.h \ mips_ejtag.h \ mips32_pracc.h \ mips32_dmaacc.h \ oocd_trace.h \ register.h \ target.h \ target_type.h \ trace.h \ target_request.h \ trace.h \ xscale.h \ smp.h \ avr32_ap7k.h \ avr32_jtag.h \ avr32_mem.h \ avr32_regs.h ocddatadir = $(pkglibdir) nobase_dist_ocddata_DATA = MAINTAINERCLEANFILES = $(srcdir)/Makefile.in all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/common.mk $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/target/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/target/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_srcdir)/common.mk: $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libtarget.la: $(libtarget_la_OBJECTS) $(libtarget_la_DEPENDENCIES) $(EXTRA_libtarget_la_DEPENDENCIES) $(AM_V_CCLD)$(LINK) $(libtarget_la_OBJECTS) $(libtarget_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/adi_v5_jtag.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/adi_v5_swd.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/algorithm.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm11.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm11_dbgtap.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm720t.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm7_9_common.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm7tdmi.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm920t.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm926ejs.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm946e.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm966e.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm9tdmi.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm_adi_v5.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm_disassembler.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm_dpm.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm_jtag.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm_semihosting.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm_simulator.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/armv4_5.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/armv4_5_cache.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/armv4_5_mmu.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/armv7a.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/armv7m.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/avr32_ap7k.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/avr32_jtag.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/avr32_mem.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/avr32_regs.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/avrt.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/breakpoints.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cortex_a.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cortex_m.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dsp563xx.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dsp563xx_once.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dsp5680xx.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/embeddedice.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/etb.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/etm.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/etm_dummy.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fa526.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/feroceon.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hla_target.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/image.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mips32.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mips32_dmaacc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mips32_pracc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mips_ejtag.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mips_m4k.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oocd_trace.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/register.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/smp.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/target.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/target_request.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testee.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trace.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xscale.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-nobase_dist_ocddataDATA: $(nobase_dist_ocddata_DATA) @$(NORMAL_INSTALL) @list='$(nobase_dist_ocddata_DATA)'; test -n "$(ocddatadir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(ocddatadir)'"; \ $(MKDIR_P) "$(DESTDIR)$(ocddatadir)" || exit 1; \ fi; \ $(am__nobase_list) | while read dir files; do \ xfiles=; for file in $$files; do \ if test -f "$$file"; then xfiles="$$xfiles $$file"; \ else xfiles="$$xfiles $(srcdir)/$$file"; fi; done; \ test -z "$$xfiles" || { \ test "x$$dir" = x. || { \ echo " $(MKDIR_P) '$(DESTDIR)$(ocddatadir)/$$dir'"; \ $(MKDIR_P) "$(DESTDIR)$(ocddatadir)/$$dir"; }; \ echo " $(INSTALL_DATA) $$xfiles '$(DESTDIR)$(ocddatadir)/$$dir'"; \ $(INSTALL_DATA) $$xfiles "$(DESTDIR)$(ocddatadir)/$$dir" || exit $$?; }; \ done uninstall-nobase_dist_ocddataDATA: @$(NORMAL_UNINSTALL) @list='$(nobase_dist_ocddata_DATA)'; test -n "$(ocddatadir)" || list=; \ $(am__nobase_strip_setup); files=`$(am__nobase_strip)`; \ dir='$(DESTDIR)$(ocddatadir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-am all-am: Makefile $(LTLIBRARIES) $(DATA) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(ocddatadir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-nobase_dist_ocddataDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-nobase_dist_ocddataDATA .MAKE: all check install install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-nobase_dist_ocddataDATA \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \ uninstall-nobase_dist_ocddataDATA $(DEBUG_HEADER): $(BIN2C) $(DEBUG_HANDLER) $(BIN2C) < $(DEBUG_HANDLER) xscale_debug_handler > xscale_debug.h # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: openocd-0.7.0/src/target/armv4_5_cache.h0000644000175000001440000000455112134336410014712 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef ARMV4_5_CACHE_H #define ARMV4_5_CACHE_H struct command_context; struct armv4_5_cachesize { int linelen; int associativity; int nsets; int cachesize; }; struct armv4_5_cache_common { int ctype; /* specify supported cache operations */ int separate; /* separate caches or unified cache */ struct armv4_5_cachesize d_u_size; /* data cache */ struct armv4_5_cachesize i_size; /* instruction cache */ int i_cache_enabled; int d_u_cache_enabled; }; int armv4_5_identify_cache(uint32_t cache_type_reg, struct armv4_5_cache_common *cache); int armv4_5_cache_state(uint32_t cp15_control_reg, struct armv4_5_cache_common *cache); int armv4_5_handle_cache_info_command(struct command_context *cmd_ctx, struct armv4_5_cache_common *armv4_5_cache); enum { ARMV4_5_D_U_CACHE_ENABLED = 0x4, ARMV4_5_I_CACHE_ENABLED = 0x1000, ARMV4_5_WRITE_BUFFER_ENABLED = 0x8, ARMV4_5_CACHE_RR_BIT = 0x5000, }; #endif /* ARMV4_5_CACHE_H */ openocd-0.7.0/src/target/arm720t.h0000644000175000001440000000366612134336410013514 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef ARM720T_H #define ARM720T_H #include "arm7tdmi.h" #include "armv4_5_mmu.h" #define ARM720T_COMMON_MAGIC 0xa720a720 struct arm720t_common { struct arm7_9_common arm7_9_common; uint32_t common_magic; struct armv4_5_mmu_common armv4_5_mmu; uint32_t cp15_control_reg; uint32_t fsr_reg; uint32_t far_reg; }; static inline struct arm720t_common *target_to_arm720(struct target *target) { return container_of(target->arch_info, struct arm720t_common, arm7_9_common.arm); } #endif /* ARM720T_H */ openocd-0.7.0/src/target/arm_dpm.h0000644000175000001440000001513112137151331013725 00000000000000/* * Copyright (C) 2009 by David Brownell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 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. */ #ifndef __ARM_DPM_H #define __ARM_DPM_H /** * @file * This is the interface to the Debug Programmers Model for ARMv6 and * ARMv7 processors. ARMv6 processors (such as ARM11xx implementations) * introduced a model which became part of the ARMv7-AR architecture * which is most familiar through the Cortex-A series parts. While * specific details differ (like how to write the instruction register), * the high level models easily support shared code because those * registers are compatible. */ struct dpm_bpwp { unsigned number; uint32_t address; uint32_t control; /* true if hardware state needs flushing */ bool dirty; }; struct dpm_bp { struct breakpoint *bp; struct dpm_bpwp bpwp; }; struct dpm_wp { struct watchpoint *wp; struct dpm_bpwp bpwp; }; /** * This wraps an implementation of DPM primitives. Each interface * provider supplies a structure like this, which is the glue between * upper level code and the lower level hardware access. * * It is a PRELIMINARY AND INCOMPLETE set of primitives, starting with * support for CPU register access. */ struct arm_dpm { struct arm *arm; /** Cache of DIDR */ uint32_t didr; /** Invoke before a series of instruction operations */ int (*prepare)(struct arm_dpm *); /** Invoke after a series of instruction operations */ int (*finish)(struct arm_dpm *); /* WRITE TO CPU */ /** Runs one instruction, writing data to DCC before execution. */ int (*instr_write_data_dcc)(struct arm_dpm *, uint32_t opcode, uint32_t data); /** Runs one instruction, writing data to R0 before execution. */ int (*instr_write_data_r0)(struct arm_dpm *, uint32_t opcode, uint32_t data); /** Optional core-specific operation invoked after CPSR writes. */ int (*instr_cpsr_sync)(struct arm_dpm *dpm); /* READ FROM CPU */ /** Runs one instruction, reading data from dcc after execution. */ int (*instr_read_data_dcc)(struct arm_dpm *, uint32_t opcode, uint32_t *data); /** Runs one instruction, reading data from r0 after execution. */ int (*instr_read_data_r0)(struct arm_dpm *, uint32_t opcode, uint32_t *data); /* BREAKPOINT/WATCHPOINT SUPPORT */ /** * Enables one breakpoint or watchpoint by writing to the * hardware registers. The specified breakpoint/watchpoint * must currently be disabled. Indices 0..15 are used for * breakpoints; indices 16..31 are for watchpoints. */ int (*bpwp_enable)(struct arm_dpm *, unsigned index_value, uint32_t addr, uint32_t control); /** * Disables one breakpoint or watchpoint by clearing its * hardware control registers. Indices are the same ones * accepted by bpwp_enable(). */ int (*bpwp_disable)(struct arm_dpm *, unsigned index_value); /* The breakpoint and watchpoint arrays are private to the * DPM infrastructure. There are nbp indices in the dbp * array. There are nwp indices in the dwp array. */ unsigned nbp; unsigned nwp; struct dpm_bp *dbp; struct dpm_wp *dwp; /** Address of the instruction which triggered a watchpoint. */ uint32_t wp_pc; /** Recent value of DSCR. */ uint32_t dscr; /* FIXME -- read/write DCSR methods and symbols */ }; int arm_dpm_setup(struct arm_dpm *dpm); int arm_dpm_initialize(struct arm_dpm *dpm); int arm_dpm_read_current_registers(struct arm_dpm *); int dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode); int arm_dpm_write_dirty_registers(struct arm_dpm *, bool bpwp); void arm_dpm_report_wfar(struct arm_dpm *, uint32_t wfar); /* DSCR bits; see ARMv7a arch spec section C10.3.1. * Not all v7 bits are valid in v6. */ #define DSCR_CORE_HALTED (0x1 << 0) #define DSCR_CORE_RESTARTED (0x1 << 1) #define DSCR_ENTRY_MASK (0xF << 2) #define DSCR_STICKY_ABORT_PRECISE (0x1 << 6) #define DSCR_STICKY_ABORT_IMPRECISE (0x1 << 7) #define DSCR_STICKY_UNDEFINED (0x1 << 8) #define DSCR_DBG_NOPWRDWN (0x1 << 9) /* v6 only */ #define DSCR_DBG_ACK (0x1 << 10) #define DSCR_INT_DIS (0x1 << 11) #define DSCR_CP14_USR_COMMS (0x1 << 12) #define DSCR_ITR_EN (0x1 << 13) #define DSCR_HALT_DBG_MODE (0x1 << 14) #define DSCR_MON_DBG_MODE (0x1 << 15) #define DSCR_SEC_PRIV_INVASV_DIS (0x1 << 16) #define DSCR_SEC_PRIV_NINVASV_DIS (0x1 << 17) #define DSCR_NON_SECURE (0x1 << 18) #define DSCR_DSCRD_IMPRECISE_ABORT (0x1 << 19) #define DSCR_EXT_DCC_MASK (0x3 << 20) /* DTR mode */ /* bits 22, 23 are reserved */ #define DSCR_INSTR_COMP (0x1 << 24) #define DSCR_PIPE_ADVANCE (0x1 << 25) #define DSCR_DTRTX_FULL_LATCHED (0x1 << 26) #define DSCR_DTRRX_FULL_LATCHED (0x1 << 27) /* bit 28 is reserved */ #define DSCR_DTR_TX_FULL (0x1 << 29) #define DSCR_DTR_RX_FULL (0x1 << 30) /* bit 31 is reserved */ #define DSCR_ENTRY(dscr) (((dscr) >> 2) & 0xf) #define DSCR_RUN_MODE(dscr) ((dscr) & (DSCR_CORE_HALTED | DSCR_CORE_RESTARTED)) /* Methods of entry into debug mode */ #define DSCR_ENTRY_HALT_REQ (0x0 << 2) #define DSCR_ENTRY_BREAKPOINT (0x1 << 2) #define DSCR_ENTRY_IMPRECISE_WATCHPT (0x2 << 2) #define DSCR_ENTRY_BKPT_INSTR (0x3 << 2) #define DSCR_ENTRY_EXT_DBG_REQ (0x4 << 2) #define DSCR_ENTRY_VECT_CATCH (0x5 << 2) #define DSCR_ENTRY_D_SIDE_ABORT (0x6 << 2) /* v6 only */ #define DSCR_ENTRY_I_SIDE_ABORT (0x7 << 2) /* v6 only */ #define DSCR_ENTRY_OS_UNLOCK (0x8 << 2) #define DSCR_ENTRY_PRECISE_WATCHPT (0xA << 2) /* DTR modes */ #define DSCR_EXT_DCC_NON_BLOCKING (0x0 << 20) #define DSCR_EXT_DCC_STALL_MODE (0x1 << 20) #define DSCR_EXT_DCC_FAST_MODE (0x2 << 20) /* bits 22, 23 are reserved */ /* DRCR (debug run control register) bits */ #define DRCR_HALT (1 << 0) #define DRCR_RESTART (1 << 1) #define DRCR_CLEAR_EXCEPTIONS (1 << 2) void arm_dpm_report_dscr(struct arm_dpm *dpm, uint32_t dcsr); #endif /* __ARM_DPM_H */ openocd-0.7.0/src/target/adi_v5_swd.c0000644000175000001440000002225112134336410014326 00000000000000/*************************************************************************** * * Copyright (C) 2010 by David Brownell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 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. ***************************************************************************/ /** * @file * Utilities to support ARM "Serial Wire Debug" (SWD), a low pin-count debug * link protocol used in cases where JTAG is not wanted. This is coupled to * recent versions of ARM's "CoreSight" debug framework. This specific code * is a transport level interface, with "target/arm_adi_v5.[hc]" code * understanding operation semantics, shared with the JTAG transport. * * Single-DAP support only. * * for details, see "ARM IHI 0031A" * ARM Debug Interface v5 Architecture Specification * especially section 5.3 for SWD protocol * * On many chips (most current Cortex-M3 parts) SWD is a run-time alternative * to JTAG. Boards may support one or both. There are also SWD-only chips, * (using SW-DP not SWJ-DP). * * Even boards that also support JTAG can benefit from SWD support, because * usually there's no way to access the SWO trace view mechanism in JTAG mode. * That is, trace access may require SWD support. * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm.h" #include "arm_adi_v5.h" #include #include #include #include static int swd_queue_dp_read(struct adiv5_dap *dap, unsigned reg, uint32_t *data) { /* REVISIT status return vs ack ... */ return swd->read_reg(swd_cmd(true, false, reg), data); } static int swd_queue_idcode_read(struct adiv5_dap *dap, uint8_t *ack, uint32_t *data) { int status = swd_queue_dp_read(dap, DP_IDCODE, data); if (status < 0) return status; *ack = status; /* ?? */ return ERROR_OK; } static int (swd_queue_dp_write)(struct adiv5_dap *dap, unsigned reg, uint32_t data) { /* REVISIT status return vs ack ... */ return swd->write_reg(swd_cmd(false, false, reg), data); } static int (swd_queue_ap_read)(struct adiv5_dap *dap, unsigned reg, uint32_t *data) { /* REVISIT APSEL ... */ /* REVISIT status return ... */ return swd->read_reg(swd_cmd(true, true, reg), data); } static int (swd_queue_ap_write)(struct adiv5_dap *dap, unsigned reg, uint32_t data) { /* REVISIT APSEL ... */ /* REVISIT status return ... */ return swd->write_reg(swd_cmd(false, true, reg), data); } static int (swd_queue_ap_abort)(struct adiv5_dap *dap, uint8_t *ack) { return ERROR_FAIL; } /** Executes all queued DAP operations. */ static int swd_run(struct adiv5_dap *dap) { /* for now the SWD interface hard-wires a zero-size queue. */ /* FIXME but we still need to check and scrub * any hardware errors ... */ return ERROR_OK; } const struct dap_ops swd_dap_ops = { .is_swd = true, .queue_idcode_read = swd_queue_idcode_read, .queue_dp_read = swd_queue_dp_read, .queue_dp_write = swd_queue_dp_write, .queue_ap_read = swd_queue_ap_read, .queue_ap_write = swd_queue_ap_write, .queue_ap_abort = swd_queue_ap_abort, .run = swd_run, }; /* * This represents the bits which must be sent out on TMS/SWDIO to * switch a DAP implemented using an SWJ-DP module into SWD mode. * These bits are stored (and transmitted) LSB-first. * * See the DAP-Lite specification, section 2.2.5 for information * about making the debug link select SWD or JTAG. (Similar info * is in a few other ARM documents.) */ static const uint8_t jtag2swd_bitseq[] = { /* More than 50 TCK/SWCLK cycles with TMS/SWDIO high, * putting both JTAG and SWD logic into reset state. */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* Switching sequence enables SWD and disables JTAG * NOTE: bits in the DP's IDCODE may expose the need for * an old/obsolete/deprecated sequence (0xb6 0xed). */ 0x9e, 0xe7, /* More than 50 TCK/SWCLK cycles with TMS/SWDIO high, * putting both JTAG and SWD logic into reset state. */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }; /** * Put the debug link into SWD mode, if the target supports it. * The link's initial mode may be either JTAG (for example, * with SWJ-DP after reset) or SWD. * * @param target Enters SWD mode (if possible). * * Note that targets using the JTAG-DP do not support SWD, and that * some targets which could otherwise support it may have have been * configured to disable SWD signaling * * @return ERROR_OK or else a fault code. */ int dap_to_swd(struct target *target) { struct arm *arm = target_to_arm(target); int retval; LOG_DEBUG("Enter SWD mode"); /* REVISIT it's ugly to need to make calls to a "jtag" * subsystem if the link may not be in JTAG mode... */ retval = jtag_add_tms_seq(8 * sizeof(jtag2swd_bitseq), jtag2swd_bitseq, TAP_INVALID); if (retval == ERROR_OK) retval = jtag_execute_queue(); /* set up the DAP's ops vector for SWD mode. */ arm->dap->ops = &swd_dap_ops; return retval; } COMMAND_HANDLER(handle_swd_wcr) { int retval; struct target *target = get_current_target(CMD_CTX); struct arm *arm = target_to_arm(target); struct adiv5_dap *dap = arm->dap; uint32_t wcr; unsigned trn, scale = 0; switch (CMD_ARGC) { /* no-args: just dump state */ case 0: /*retval = swd_queue_dp_read(dap, DP_WCR, &wcr); */ retval = dap_queue_dp_read(dap, DP_WCR, &wcr); if (retval == ERROR_OK) dap->ops->run(dap); if (retval != ERROR_OK) { LOG_ERROR("can't read WCR?"); return retval; } command_print(CMD_CTX, "turnaround=%d, prescale=%d", WCR_TO_TRN(wcr), WCR_TO_PRESCALE(wcr)); return ERROR_OK; case 2: /* TRN and prescale */ COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], scale); if (scale > 7) { LOG_ERROR("prescale %d is too big", scale); return ERROR_FAIL; } /* FALL THROUGH */ case 1: /* TRN only */ COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], trn); if (trn < 1 || trn > 4) { LOG_ERROR("turnaround %d is invalid", trn); return ERROR_FAIL; } wcr = ((trn - 1) << 8) | scale; /* FIXME * write WCR ... * then, re-init adapter with new TRN */ LOG_ERROR("can't yet modify WCR"); return ERROR_FAIL; default: /* too many arguments */ return ERROR_COMMAND_SYNTAX_ERROR; } } static const struct command_registration swd_commands[] = { { /* * Set up SWD and JTAG targets identically, unless/until * infrastructure improves ... meanwhile, ignore all * JTAG-specific stuff like IR length for SWD. * * REVISIT can we verify "just one SWD DAP" here/early? */ .name = "newdap", .jim_handler = jim_jtag_newtap, .mode = COMMAND_CONFIG, .help = "declare a new SWD DAP" }, { .name = "wcr", .handler = handle_swd_wcr, .mode = COMMAND_ANY, .help = "display or update DAP's WCR register", .usage = "turnaround (1..4), prescale (0..7)", }, /* REVISIT -- add a command for SWV trace on/off */ COMMAND_REGISTRATION_DONE }; static const struct command_registration swd_handlers[] = { { .name = "swd", .mode = COMMAND_ANY, .help = "SWD command group", .chain = swd_commands, }, COMMAND_REGISTRATION_DONE }; static int swd_select(struct command_context *ctx) { struct target *target = get_current_target(ctx); int retval; retval = register_commands(ctx, NULL, swd_handlers); if (retval != ERROR_OK) return retval; /* be sure driver is in SWD mode; start * with hardware default TRN (1), it can be changed later */ if (!swd || !swd->read_reg || !swd->write_reg || !swd->init) { LOG_DEBUG("no SWD driver?"); return ERROR_FAIL; } retval = swd->init(1); if (retval != ERROR_OK) { LOG_DEBUG("can't init SWD driver"); return retval; } /* force DAP into SWD mode (not JTAG) */ retval = dap_to_swd(target); return retval; } static int swd_init(struct command_context *ctx) { struct target *target = get_current_target(ctx); struct arm *arm = target_to_arm(target); struct adiv5_dap *dap = arm->dap; uint32_t idcode; int status; /* FIXME validate transport config ... is the * configured DAP present (check IDCODE)? * Is *only* one DAP configured? * * MUST READ IDCODE */ /* Note, debugport_init() does setup too */ uint8_t ack; status = swd_queue_idcode_read(dap, &ack, &idcode); if (status == ERROR_OK) LOG_INFO("SWD IDCODE %#8.8x", idcode); return status; } static struct transport swd_transport = { .name = "swd", .select = swd_select, .init = swd_init, }; static void swd_constructor(void) __attribute__((constructor)); static void swd_constructor(void) { transport_register(&swd_transport); } /** Returns true if the current debug session * is using SWD as its transport. */ bool transport_is_swd(void) { return get_current_transport() == &swd_transport; } openocd-0.7.0/src/target/smp.c0000644000175000001440000001107612137151331013104 00000000000000/*************************************************************************** * * * Copyright (C) ST-Ericsson SA 2011 * * Author: Michel Jaouen for ST-Ericsson. * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "server/server.h" #include "target/target.h" #include "server/gdb_server.h" #include "smp.h" #include "helper/binarybuffer.h" /* implementation of new packet in gdb interface for smp feature */ /* */ /* j : smp status request */ /* J : smp set request */ /* */ /* jc :read core id displayed by gdb connection */ /* reply XXXXXXXX core id is int32_t , 8 hex digits */ /* */ /* Reply ENN error not supported (target not smp) */ /* */ /* JcXX set core id displayed at next gdb continue */ /* maximum 8 bytes described core id int32_t (8 hex digits) */ /* (core id -1 , reserved for returning to normal continue mode) */ /* Reply ENN error not supported(target not smp,core id out of range) */ /* Reply OK : for success */ /* */ /* handling of this packet within gdb can be done by the creation */ /* internal variable by mean of function allocate_computed_value */ /* set $_core 1 => Jc01 packet is sent */ /* print $_core => jc packet is sent and result is affected in $ */ /* Another way to test this packet is the usage of maintenance packet */ /* maint packet Jc01 */ /* maint packet jc */ /* packet j :smp status request */ int gdb_read_smp_packet(struct connection *connection, char *packet, int packet_size) { struct target *target = get_target_from_connection(connection); uint32_t len = sizeof(int32_t); uint8_t *buffer; char *hex_buffer; int retval = ERROR_OK; if (target->smp) { if (strncmp(packet, "jc", 2) == 0) { hex_buffer = malloc(len * 2 + 1); buffer = (uint8_t *)&target->gdb_service->core[0]; int pkt_len = hexify(hex_buffer, (char *)buffer, len, len * 2 + 1); retval = gdb_put_packet(connection, hex_buffer, pkt_len); free(hex_buffer); } } else retval = gdb_put_packet(connection, "E01", 3); return retval; } /* J : smp set request */ int gdb_write_smp_packet(struct connection *connection, char *packet, int packet_size) { struct target *target = get_target_from_connection(connection); char *separator; int coreid = 0; int retval = ERROR_OK; /* skip command character */ if (target->smp) { if (strncmp(packet, "Jc", 2) == 0) { packet += 2; coreid = strtoul(packet, &separator, 16); target->gdb_service->core[1] = coreid; retval = gdb_put_packet(connection, "OK", 2); } } else retval = gdb_put_packet(connection, "E01", 3); return retval; } openocd-0.7.0/src/target/mips32_pracc.c0000644000175000001440000011344312137151331014573 00000000000000/*************************************************************************** * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2008 by David T.L. Wong * * * * Copyright (C) 2009 by David N. Claffey * * * * Copyright (C) 2011 by Drasko DRASKOVIC * * drasko.draskovic@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /* * This version has optimized assembly routines for 32 bit operations: * - read word * - write word * - write array of words * * One thing to be aware of is that the MIPS32 cpu will execute the * instruction after a branch instruction (one delay slot). * * For example: * LW $2, ($5 +10) * B foo * LW $1, ($2 +100) * * The LW $1, ($2 +100) instruction is also executed. If this is * not wanted a NOP can be inserted: * * LW $2, ($5 +10) * B foo * NOP * LW $1, ($2 +100) * * or the code can be changed to: * * B foo * LW $2, ($5 +10) * LW $1, ($2 +100) * * The original code contained NOPs. I have removed these and moved * the branches. * * I also moved the PRACC_STACK to 0xFF204000. This allows * the use of 16 bits offsets to get pointers to the input * and output area relative to the stack. Note that the stack * isn't really a stack (the stack pointer is not 'moving') * but a FIFO simulated in software. * * These changes result in a 35% speed increase when programming an * external flash. * * More improvement could be gained if the registers do no need * to be preserved but in that case the routines should be aware * OpenOCD is used as a flash programmer or as a debug tool. * * Nico Coesel */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "mips32.h" #include "mips32_pracc.h" struct mips32_pracc_context { uint32_t *local_iparam; int num_iparam; uint32_t *local_oparam; int num_oparam; const uint32_t *code; int code_len; uint32_t stack[32]; int stack_offset; struct mips_ejtag *ejtag_info; }; static int mips32_pracc_sync_cache(struct mips_ejtag *ejtag_info, uint32_t start_addr, uint32_t end_addr); static int mips32_pracc_clean_invalidate_cache(struct mips_ejtag *ejtag_info, uint32_t start_addr, uint32_t end_addr); static int wait_for_pracc_rw(struct mips_ejtag *ejtag_info, uint32_t *ctrl) { uint32_t ejtag_ctrl; long long then = timeval_ms(); int timeout; int retval; /* wait for the PrAcc to become "1" */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); while (1) { ejtag_ctrl = ejtag_info->ejtag_ctrl; retval = mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); if (retval != ERROR_OK) return retval; if (ejtag_ctrl & EJTAG_CTRL_PRACC) break; timeout = timeval_ms() - then; if (timeout > 1000) { LOG_DEBUG("DEBUGMODULE: No memory access in progress!"); return ERROR_JTAG_DEVICE_ERROR; } } *ctrl = ejtag_ctrl; return ERROR_OK; } static int mips32_pracc_exec_read(struct mips32_pracc_context *ctx, uint32_t address) { struct mips_ejtag *ejtag_info = ctx->ejtag_info; int offset; uint32_t ejtag_ctrl, data; if ((address >= MIPS32_PRACC_PARAM_IN) && (address < MIPS32_PRACC_PARAM_IN + ctx->num_iparam * 4)) { offset = (address - MIPS32_PRACC_PARAM_IN) / 4; data = ctx->local_iparam[offset]; } else if ((address >= MIPS32_PRACC_PARAM_OUT) && (address < MIPS32_PRACC_PARAM_OUT + ctx->num_oparam * 4)) { offset = (address - MIPS32_PRACC_PARAM_OUT) / 4; data = ctx->local_oparam[offset]; } else if ((address >= MIPS32_PRACC_TEXT) && (address < MIPS32_PRACC_TEXT + ctx->code_len * 4)) { offset = (address - MIPS32_PRACC_TEXT) / 4; data = ctx->code[offset]; } else if (address == MIPS32_PRACC_STACK) { if (ctx->stack_offset <= 0) { LOG_ERROR("Error: Pracc stack out of bounds"); return ERROR_JTAG_DEVICE_ERROR; } /* save to our debug stack */ data = ctx->stack[--ctx->stack_offset]; } else { /* TODO: send JMP 0xFF200000 instruction. Hopefully processor jump back * to start of debug vector */ LOG_ERROR("Error reading unexpected address 0x%8.8" PRIx32 "", address); return ERROR_JTAG_DEVICE_ERROR; } /* Send the data out */ mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_DATA); mips_ejtag_drscan_32_out(ctx->ejtag_info, data); /* Clear the access pending bit (let the processor eat!) */ ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC; mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_CONTROL); mips_ejtag_drscan_32_out(ctx->ejtag_info, ejtag_ctrl); return jtag_execute_queue(); } static int mips32_pracc_exec_write(struct mips32_pracc_context *ctx, uint32_t address) { uint32_t ejtag_ctrl, data; int offset; struct mips_ejtag *ejtag_info = ctx->ejtag_info; int retval; mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_DATA); retval = mips_ejtag_drscan_32(ctx->ejtag_info, &data); if (retval != ERROR_OK) return retval; /* Clear access pending bit */ ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC; mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_CONTROL); mips_ejtag_drscan_32_out(ctx->ejtag_info, ejtag_ctrl); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if ((address >= MIPS32_PRACC_PARAM_OUT) && (address < MIPS32_PRACC_PARAM_OUT + ctx->num_oparam * 4)) { offset = (address - MIPS32_PRACC_PARAM_OUT) / 4; ctx->local_oparam[offset] = data; } else if (address == MIPS32_PRACC_STACK) { if (ctx->stack_offset >= 32) { LOG_ERROR("Error: Pracc stack out of bounds"); return ERROR_JTAG_DEVICE_ERROR; } /* save data onto our stack */ ctx->stack[ctx->stack_offset++] = data; } else { LOG_ERROR("Error writing unexpected address 0x%8.8" PRIx32 "", address); return ERROR_JTAG_DEVICE_ERROR; } return ERROR_OK; } int mips32_pracc_exec(struct mips_ejtag *ejtag_info, int code_len, const uint32_t *code, int num_param_in, uint32_t *param_in, int num_param_out, uint32_t *param_out, int cycle) { uint32_t ejtag_ctrl; uint32_t address; struct mips32_pracc_context ctx; int retval; int pass = 0; ctx.local_iparam = param_in; ctx.local_oparam = param_out; ctx.num_iparam = num_param_in; ctx.num_oparam = num_param_out; ctx.code = code; ctx.code_len = code_len; ctx.ejtag_info = ejtag_info; ctx.stack_offset = 0; while (1) { retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl); if (retval != ERROR_OK) return retval; address = 0; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); retval = mips_ejtag_drscan_32(ejtag_info, &address); if (retval != ERROR_OK) return retval; /* Check for read or write */ if (ejtag_ctrl & EJTAG_CTRL_PRNW) { retval = mips32_pracc_exec_write(&ctx, address); if (retval != ERROR_OK) return retval; } else { /* Check to see if its reading at the debug vector. The first pass through * the module is always read at the vector, so the first one we allow. When * the second read from the vector occurs we are done and just exit. */ if ((address == MIPS32_PRACC_TEXT) && (pass++)) break; retval = mips32_pracc_exec_read(&ctx, address); if (retval != ERROR_OK) return retval; } if (cycle == 0) break; } /* stack sanity check */ if (ctx.stack_offset != 0) LOG_DEBUG("Pracc Stack not zero"); return ERROR_OK; } inline void pracc_queue_init(struct pracc_queue_info *ctx) { ctx->retval = ERROR_OK; ctx->code_count = 0; ctx->store_count = 0; ctx->pracc_list = malloc(2 * ctx->max_code * sizeof(uint32_t)); if (ctx->pracc_list == NULL) { LOG_ERROR("Out of memory"); ctx->retval = ERROR_FAIL; } } inline void pracc_add(struct pracc_queue_info *ctx, uint32_t addr, uint32_t instr) { ctx->pracc_list[ctx->max_code + ctx->code_count] = addr; ctx->pracc_list[ctx->code_count++] = instr; if (addr) ctx->store_count++; } inline void pracc_queue_free(struct pracc_queue_info *ctx) { if (ctx->code_count > ctx->max_code) /* Only for internal check, will be erased */ LOG_ERROR("Internal error, code count: %d > max code: %d", ctx->code_count, ctx->max_code); if (ctx->pracc_list != NULL) free(ctx->pracc_list); } int mips32_pracc_queue_exec(struct mips_ejtag *ejtag_info, struct pracc_queue_info *ctx, uint32_t *buf) { if (ejtag_info->mode == 0) return mips32_pracc_exec(ejtag_info, ctx->code_count, ctx->pracc_list, 0, NULL, ctx->store_count, buf, ctx->code_count - 1); union scan_in { uint8_t scan_96[12]; struct { uint8_t ctrl[4]; uint8_t data[4]; uint8_t addr[4]; } scan_32; } *scan_in = malloc(sizeof(union scan_in) * (ctx->code_count + ctx->store_count)); if (scan_in == NULL) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } unsigned num_clocks = ((uint64_t)(ejtag_info->scan_delay) * jtag_get_speed_khz() + 500000) / 1000000; uint32_t ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ALL); int scan_count = 0; for (int i = 0; i != 2 * ctx->code_count; i++) { uint32_t data = 0; if (i & 1u) { /* Check store address from previous instruction, if not the first */ if (i < 2 || 0 == ctx->pracc_list[ctx->max_code + (i / 2) - 1]) continue; } else data = ctx->pracc_list[i / 2]; jtag_add_clocks(num_clocks); mips_ejtag_add_scan_96(ejtag_info, ejtag_ctrl, data, scan_in[scan_count++].scan_96); } int retval = jtag_execute_queue(); /* execute queued scans */ if (retval != ERROR_OK) goto exit; uint32_t fetch_addr = MIPS32_PRACC_TEXT; /* start address */ scan_count = 0; for (int i = 0; i != 2 * ctx->code_count; i++) { /* verify every pracc access */ uint32_t store_addr = 0; if (i & 1u) { /* Read store addres from previous instruction, if not the first */ store_addr = ctx->pracc_list[ctx->max_code + (i / 2) - 1]; if (i < 2 || 0 == store_addr) continue; } ejtag_ctrl = buf_get_u32(scan_in[scan_count].scan_32.ctrl, 0, 32); if (!(ejtag_ctrl & EJTAG_CTRL_PRACC)) { LOG_ERROR("Error: access not pending count: %d", scan_count); retval = ERROR_FAIL; goto exit; } uint32_t addr = buf_get_u32(scan_in[scan_count].scan_32.addr, 0, 32); if (store_addr != 0) { if (!(ejtag_ctrl & EJTAG_CTRL_PRNW)) { LOG_ERROR("Not a store/write access, count: %d", scan_count); retval = ERROR_FAIL; goto exit; } if (addr != store_addr) { LOG_ERROR("Store address mismatch, read: %x expected: %x count: %d", addr, store_addr, scan_count); retval = ERROR_FAIL; goto exit; } int buf_index = (addr - MIPS32_PRACC_PARAM_OUT) / 4; buf[buf_index] = buf_get_u32(scan_in[scan_count].scan_32.data, 0, 32); } else { if (ejtag_ctrl & EJTAG_CTRL_PRNW) { LOG_ERROR("Not a fetch/read access, count: %d", scan_count); retval = ERROR_FAIL; goto exit; } if (addr != fetch_addr) { LOG_ERROR("Fetch addr mismatch, read: %x expected: %x count: %d", addr, fetch_addr, scan_count); retval = ERROR_FAIL; goto exit; } fetch_addr += 4; } scan_count++; } exit: free(scan_in); return retval; } int mips32_pracc_read_u32(struct mips_ejtag *ejtag_info, uint32_t addr, uint32_t *buf) { struct pracc_queue_info ctx = {.max_code = 9}; pracc_queue_init(&ctx); if (ctx.retval != ERROR_OK) goto exit; pracc_add(&ctx, 0, MIPS32_MTC0(15, 31, 0)); /* move $15 to COP0 DeSave */ pracc_add(&ctx, 0, MIPS32_LUI(15, PRACC_UPPER_BASE_ADDR)); /* $15 = MIPS32_PRACC_BASE_ADDR */ pracc_add(&ctx, 0, MIPS32_LUI(8, UPPER16((addr + 0x8000)))); /* load $8 with modified upper address */ pracc_add(&ctx, 0, MIPS32_LW(8, LOWER16(addr), 8)); /* lw $8, LOWER16(addr)($8) */ pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT, MIPS32_SW(8, PRACC_OUT_OFFSET, 15)); /* sw $8,PRACC_OUT_OFFSET($15) */ pracc_add(&ctx, 0, MIPS32_LUI(8, UPPER16(ejtag_info->reg8))); /* restore upper 16 of $8 */ pracc_add(&ctx, 0, MIPS32_ORI(8, 8, LOWER16(ejtag_info->reg8))); /* restore lower 16 of $8 */ pracc_add(&ctx, 0, MIPS32_B(NEG16(ctx.code_count + 1))); /* jump to start */ pracc_add(&ctx, 0, MIPS32_MFC0(15, 31, 0)); /* move COP0 DeSave to $15 */ ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, buf); exit: pracc_queue_free(&ctx); return ctx.retval; } int mips32_pracc_read_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, void *buf) { if (count == 1 && size == 4) return mips32_pracc_read_u32(ejtag_info, addr, (uint32_t *)buf); uint32_t *data = NULL; struct pracc_queue_info ctx = {.max_code = 256 * 3 + 9 + 1}; /* alloc memory for the worst case */ pracc_queue_init(&ctx); if (ctx.retval != ERROR_OK) goto exit; if (size != 4) { data = malloc(256 * sizeof(uint32_t)); if (data == NULL) { LOG_ERROR("Out of memory"); goto exit; } } uint32_t *buf32 = buf; uint16_t *buf16 = buf; uint8_t *buf8 = buf; while (count) { ctx.code_count = 0; ctx.store_count = 0; int this_round_count = (count > 256) ? 256 : count; uint32_t last_upper_base_addr = UPPER16((addr + 0x8000)); pracc_add(&ctx, 0, MIPS32_MTC0(15, 31, 0)); /* save $15 in DeSave */ pracc_add(&ctx, 0, MIPS32_LUI(15, PRACC_UPPER_BASE_ADDR)); /* $15 = MIPS32_PRACC_BASE_ADDR */ pracc_add(&ctx, 0, MIPS32_LUI(9, last_upper_base_addr)); /* load the upper memory address in $9 */ for (int i = 0; i != this_round_count; i++) { /* Main code loop */ uint32_t upper_base_addr = UPPER16((addr + 0x8000)); if (last_upper_base_addr != upper_base_addr) { /* if needed, change upper address in $9 */ pracc_add(&ctx, 0, MIPS32_LUI(9, upper_base_addr)); last_upper_base_addr = upper_base_addr; } if (size == 4) pracc_add(&ctx, 0, MIPS32_LW(8, LOWER16(addr), 9)); /* load from memory to $8 */ else if (size == 2) pracc_add(&ctx, 0, MIPS32_LHU(8, LOWER16(addr), 9)); else pracc_add(&ctx, 0, MIPS32_LBU(8, LOWER16(addr), 9)); pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + i * 4, MIPS32_SW(8, PRACC_OUT_OFFSET + i * 4, 15)); /* store $8 at param out */ addr += size; } pracc_add(&ctx, 0, MIPS32_LUI(8, UPPER16(ejtag_info->reg8))); /* restore upper 16 bits of reg 8 */ pracc_add(&ctx, 0, MIPS32_ORI(8, 8, LOWER16(ejtag_info->reg8))); /* restore lower 16 bits of reg 8 */ pracc_add(&ctx, 0, MIPS32_LUI(9, UPPER16(ejtag_info->reg9))); /* restore upper 16 bits of reg 9 */ pracc_add(&ctx, 0, MIPS32_ORI(9, 9, LOWER16(ejtag_info->reg9))); /* restore lower 16 bits of reg 9 */ pracc_add(&ctx, 0, MIPS32_B(NEG16(ctx.code_count + 1))); /* jump to start */ pracc_add(&ctx, 0, MIPS32_MFC0(15, 31, 0)); /* restore $15 from DeSave */ if (size == 4) { ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, buf32); if (ctx.retval != ERROR_OK) goto exit; buf32 += this_round_count; } else { ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, data); if (ctx.retval != ERROR_OK) goto exit; uint32_t *data_p = data; for (int i = 0; i != this_round_count; i++) { if (size == 2) *buf16++ = *data_p++; else *buf8++ = *data_p++; } } count -= this_round_count; } exit: pracc_queue_free(&ctx); if (data != NULL) free(data); return ctx.retval; } int mips32_cp0_read(struct mips_ejtag *ejtag_info, uint32_t *val, uint32_t cp0_reg, uint32_t cp0_sel) { struct pracc_queue_info ctx = {.max_code = 8}; pracc_queue_init(&ctx); if (ctx.retval != ERROR_OK) goto exit; pracc_add(&ctx, 0, MIPS32_MTC0(15, 31, 0)); /* move $15 to COP0 DeSave */ pracc_add(&ctx, 0, MIPS32_LUI(15, PRACC_UPPER_BASE_ADDR)); /* $15 = MIPS32_PRACC_BASE_ADDR */ pracc_add(&ctx, 0, MIPS32_MFC0(8, 0, 0) | (cp0_reg << 11) | cp0_sel); /* move COP0 [cp0_reg select] to $8 */ pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT, MIPS32_SW(8, PRACC_OUT_OFFSET, 15)); /* store $8 to pracc_out */ pracc_add(&ctx, 0, MIPS32_MFC0(15, 31, 0)); /* move COP0 DeSave to $15 */ pracc_add(&ctx, 0, MIPS32_LUI(8, UPPER16(ejtag_info->reg8))); /* restore upper 16 bits of $8 */ pracc_add(&ctx, 0, MIPS32_B(NEG16(ctx.code_count + 1))); /* jump to start */ pracc_add(&ctx, 0, MIPS32_ORI(8, 8, LOWER16(ejtag_info->reg8))); /* restore lower 16 bits of $8 */ ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, val); exit: pracc_queue_free(&ctx); return ctx.retval; /** * Note that our input parametes cp0_reg and cp0_sel * are numbers (not gprs) which make part of mfc0 instruction opcode. * * These are not fix, but can be different for each mips32_cp0_read() function call, * and that is why we must insert them directly into opcode, * i.e. we can not pass it on EJTAG microprogram stack (via param_in), * and put them into the gprs later from MIPS32_PRACC_STACK * because mfc0 do not use gpr as a parameter for the cp0_reg and select part, * but plain (immediate) number. * * MIPS32_MTC0 is implemented via MIPS32_R_INST macro. * In order to insert our parameters, we must change rd and funct fields. * * code[2] |= (cp0_reg << 11) | cp0_sel; change rd and funct of MIPS32_R_INST macro **/ } int mips32_cp0_write(struct mips_ejtag *ejtag_info, uint32_t val, uint32_t cp0_reg, uint32_t cp0_sel) { struct pracc_queue_info ctx = {.max_code = 6}; pracc_queue_init(&ctx); if (ctx.retval != ERROR_OK) goto exit; pracc_add(&ctx, 0, MIPS32_MTC0(15, 31, 0)); /* move $15 to COP0 DeSave */ pracc_add(&ctx, 0, MIPS32_LUI(15, UPPER16(val))); /* Load val to $15 */ pracc_add(&ctx, 0, MIPS32_ORI(15, 15, LOWER16(val))); pracc_add(&ctx, 0, MIPS32_MTC0(15, 0, 0) | (cp0_reg << 11) | cp0_sel); /* write cp0 reg / sel */ pracc_add(&ctx, 0, MIPS32_B(NEG16(ctx.code_count + 1))); /* jump to start */ pracc_add(&ctx, 0, MIPS32_MFC0(15, 31, 0)); /* move COP0 DeSave to $15 */ ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL); exit: pracc_queue_free(&ctx); return ctx.retval; /** * Note that MIPS32_MTC0 macro is implemented via MIPS32_R_INST macro. * In order to insert our parameters, we must change rd and funct fields. * code[3] |= (cp0_reg << 11) | cp0_sel; change rd and funct fields of MIPS32_R_INST macro **/ } /** * \b mips32_pracc_sync_cache * * Synchronize Caches to Make Instruction Writes Effective * (ref. doc. MIPS32 Architecture For Programmers Volume II: The MIPS32 Instruction Set, * Document Number: MD00086, Revision 2.00, June 9, 2003) * * When the instruction stream is written, the SYNCI instruction should be used * in conjunction with other instructions to make the newly-written instructions effective. * * Explanation : * A program that loads another program into memory is actually writing the D- side cache. * The instructions it has loaded can't be executed until they reach the I-cache. * * After the instructions have been written, the loader should arrange * to write back any containing D-cache line and invalidate any locations * already in the I-cache. * * You can do that with cache instructions, but those instructions are only available in kernel mode, * and a loader writing instructions for the use of its own process need not be privileged software. * * In the latest MIPS32/64 CPUs, MIPS provides the synci instruction, * which does the whole job for a cache-line-sized chunk of the memory you just loaded: * That is, it arranges a D-cache write-back and an I-cache invalidate. * * To employ synci at user level, you need to know the size of a cache line, * and that can be obtained with a rdhwr SYNCI_Step * from one of the standard “hardware registersâ€. */ static int mips32_pracc_sync_cache(struct mips_ejtag *ejtag_info, uint32_t start_addr, uint32_t end_addr) { static const uint32_t code[] = { /* start: */ MIPS32_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */ MIPS32_LUI(15, UPPER16(MIPS32_PRACC_STACK)), /* $15 = MIPS32_PRACC_STACK */ MIPS32_ORI(15, 15, LOWER16(MIPS32_PRACC_STACK)), MIPS32_SW(8, 0, 15), /* sw $8,($15) */ MIPS32_SW(9, 0, 15), /* sw $9,($15) */ MIPS32_SW(10, 0, 15), /* sw $10,($15) */ MIPS32_SW(11, 0, 15), /* sw $11,($15) */ MIPS32_LUI(8, UPPER16(MIPS32_PRACC_PARAM_IN)), /* $8 = MIPS32_PRACC_PARAM_IN */ MIPS32_ORI(8, 8, LOWER16(MIPS32_PRACC_PARAM_IN)), MIPS32_LW(9, 0, 8), /* Load write start_addr to $9 */ MIPS32_LW(10, 4, 8), /* Load write end_addr to $10 */ MIPS32_RDHWR(11, MIPS32_SYNCI_STEP), /* $11 = MIPS32_SYNCI_STEP */ MIPS32_BEQ(11, 0, 6), /* beq $11, $0, end */ MIPS32_NOP, /* synci_loop : */ MIPS32_SYNCI(0, 9), /* synci 0($9) */ MIPS32_SLTU(8, 10, 9), /* sltu $8, $10, $9 # $8 = $10 < $9 ? 1 : 0 */ MIPS32_BNE(8, 0, NEG16(3)), /* bne $8, $0, synci_loop */ MIPS32_ADDU(9, 9, 11), /* $9 += MIPS32_SYNCI_STEP */ MIPS32_SYNC, /* end: */ MIPS32_LW(11, 0, 15), /* lw $11,($15) */ MIPS32_LW(10, 0, 15), /* lw $10,($15) */ MIPS32_LW(9, 0, 15), /* lw $9,($15) */ MIPS32_LW(8, 0, 15), /* lw $8,($15) */ MIPS32_B(NEG16(24)), /* b start */ MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */ }; /* TODO remove array */ uint32_t *param_in = malloc(2 * sizeof(uint32_t)); int retval; param_in[0] = start_addr; param_in[1] = end_addr; retval = mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, 2, param_in, 0, NULL, 1); free(param_in); return retval; } /** * \b mips32_pracc_clean_invalidate_cache * * Writeback D$ and Invalidate I$ * so that the instructions written can be visible to CPU */ static int mips32_pracc_clean_invalidate_cache(struct mips_ejtag *ejtag_info, uint32_t start_addr, uint32_t end_addr) { static const uint32_t code[] = { /* start: */ MIPS32_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */ MIPS32_LUI(15, UPPER16(MIPS32_PRACC_STACK)), /* $15 = MIPS32_PRACC_STACK */ MIPS32_ORI(15, 15, LOWER16(MIPS32_PRACC_STACK)), MIPS32_SW(8, 0, 15), /* sw $8,($15) */ MIPS32_SW(9, 0, 15), /* sw $9,($15) */ MIPS32_SW(10, 0, 15), /* sw $10,($15) */ MIPS32_SW(11, 0, 15), /* sw $11,($15) */ MIPS32_LUI(8, UPPER16(MIPS32_PRACC_PARAM_IN)), /* $8 = MIPS32_PRACC_PARAM_IN */ MIPS32_ORI(8, 8, LOWER16(MIPS32_PRACC_PARAM_IN)), MIPS32_LW(9, 0, 8), /* Load write start_addr to $9 */ MIPS32_LW(10, 4, 8), /* Load write end_addr to $10 */ MIPS32_LW(11, 8, 8), /* Load write clsiz to $11 */ /* cache_loop: */ MIPS32_SLTU(8, 10, 9), /* sltu $8, $10, $9 : $8 <- $10 < $9 ? */ MIPS32_BGTZ(8, 6), /* bgtz $8, end */ MIPS32_NOP, MIPS32_CACHE(MIPS32_CACHE_D_HIT_WRITEBACK, 0, 9), /* cache Hit_Writeback_D, 0($9) */ MIPS32_CACHE(MIPS32_CACHE_I_HIT_INVALIDATE, 0, 9), /* cache Hit_Invalidate_I, 0($9) */ MIPS32_ADDU(9, 9, 11), /* $9 += $11 */ MIPS32_B(NEG16(7)), /* b cache_loop */ MIPS32_NOP, /* end: */ MIPS32_LW(11, 0, 15), /* lw $11,($15) */ MIPS32_LW(10, 0, 15), /* lw $10,($15) */ MIPS32_LW(9, 0, 15), /* lw $9,($15) */ MIPS32_LW(8, 0, 15), /* lw $8,($15) */ MIPS32_B(NEG16(25)), /* b start */ MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */ }; /** * Find cache line size in bytes */ uint32_t conf; uint32_t dl, clsiz; mips32_cp0_read(ejtag_info, &conf, 16, 1); dl = (conf & MIPS32_CONFIG1_DL_MASK) >> MIPS32_CONFIG1_DL_SHIFT; /* dl encoding : dl=1 => 4 bytes, dl=2 => 8 bytes, etc... */ clsiz = 0x2 << dl; /* TODO remove array */ uint32_t *param_in = malloc(3 * sizeof(uint32_t)); int retval; param_in[0] = start_addr; param_in[1] = end_addr; param_in[2] = clsiz; retval = mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, 3, param_in, 0, NULL, 1); free(param_in); return retval; } static int mips32_pracc_write_mem_generic(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, void *buf) { struct pracc_queue_info ctx = {.max_code = 128 * 3 + 6 + 1}; /* alloc memory for the worst case */ pracc_queue_init(&ctx); if (ctx.retval != ERROR_OK) goto exit; uint32_t *buf32 = buf; uint16_t *buf16 = buf; uint8_t *buf8 = buf; while (count) { ctx.code_count = 0; ctx.store_count = 0; int this_round_count = (count > 128) ? 128 : count; uint32_t last_upper_base_addr = UPPER16((addr + 0x8000)); pracc_add(&ctx, 0, MIPS32_MTC0(15, 31, 0)); /* save $15 in DeSave */ pracc_add(&ctx, 0, MIPS32_LUI(15, last_upper_base_addr)); /* load $15 with memory base address */ for (int i = 0; i != this_round_count; i++) { uint32_t upper_base_addr = UPPER16((addr + 0x8000)); if (last_upper_base_addr != upper_base_addr) { pracc_add(&ctx, 0, MIPS32_LUI(15, upper_base_addr)); /* if needed, change upper address in $15*/ last_upper_base_addr = upper_base_addr; } if (size == 4) { /* for word writes check if one half word is 0 and load it accordingly */ if (LOWER16(*buf32) == 0) pracc_add(&ctx, 0, MIPS32_LUI(8, UPPER16(*buf32))); /* load only upper value */ else if (UPPER16(*buf32) == 0) pracc_add(&ctx, 0, MIPS32_ORI(8, 0, LOWER16(*buf32))); /* load only lower */ else { pracc_add(&ctx, 0, MIPS32_LUI(8, UPPER16(*buf32))); /* load upper and lower */ pracc_add(&ctx, 0, MIPS32_ORI(8, 8, LOWER16(*buf32))); } pracc_add(&ctx, 0, MIPS32_SW(8, LOWER16(addr), 15)); /* store word to memory */ buf32++; } else if (size == 2) { pracc_add(&ctx, 0, MIPS32_ORI(8, 0, *buf16)); /* load lower value */ pracc_add(&ctx, 0, MIPS32_SH(8, LOWER16(addr), 15)); /* store half word to memory */ buf16++; } else { pracc_add(&ctx, 0, MIPS32_ORI(8, 0, *buf8)); /* load lower value */ pracc_add(&ctx, 0, MIPS32_SB(8, LOWER16(addr), 15)); /* store byte to memory */ buf8++; } addr += size; } pracc_add(&ctx, 0, MIPS32_LUI(8, UPPER16(ejtag_info->reg8))); /* restore upper 16 bits of reg 8 */ pracc_add(&ctx, 0, MIPS32_ORI(8, 8, LOWER16(ejtag_info->reg8))); /* restore lower 16 bits of reg 8 */ pracc_add(&ctx, 0, MIPS32_B(NEG16(ctx.code_count + 1))); /* jump to start */ pracc_add(&ctx, 0, MIPS32_MFC0(15, 31, 0)); /* restore $15 from DeSave */ ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL); if (ctx.retval != ERROR_OK) goto exit; count -= this_round_count; } exit: pracc_queue_free(&ctx); return ctx.retval; } int mips32_pracc_write_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, void *buf) { int retval = mips32_pracc_write_mem_generic(ejtag_info, addr, size, count, buf); if (retval != ERROR_OK) return retval; /** * If we are in the cachable regoion and cache is activated, * we must clean D$ + invalidate I$ after we did the write, * so that changes do not continue to live only in D$, but to be * replicated in I$ also (maybe we wrote the istructions) */ uint32_t conf = 0; int cached = 0; if ((KSEGX(addr) == KSEG1) || ((addr >= 0xff200000) && (addr <= 0xff3fffff))) return retval; /*Nothing to do*/ mips32_cp0_read(ejtag_info, &conf, 16, 0); switch (KSEGX(addr)) { case KUSEG: cached = (conf & MIPS32_CONFIG0_KU_MASK) >> MIPS32_CONFIG0_KU_SHIFT; break; case KSEG0: cached = (conf & MIPS32_CONFIG0_K0_MASK) >> MIPS32_CONFIG0_K0_SHIFT; break; case KSEG2: case KSEG3: cached = (conf & MIPS32_CONFIG0_K23_MASK) >> MIPS32_CONFIG0_K23_SHIFT; break; default: /* what ? */ break; } /** * Check cachablitiy bits coherency algorithm - * is the region cacheable or uncached. * If cacheable we have to synchronize the cache */ if (cached == 0x3) { uint32_t start_addr, end_addr; uint32_t rel; start_addr = addr; end_addr = addr + count * size; /** select cache synchronisation mechanism based on Architecture Release */ rel = (conf & MIPS32_CONFIG0_AR_MASK) >> MIPS32_CONFIG0_AR_SHIFT; switch (rel) { case MIPS32_ARCH_REL1: /* MIPS32/64 Release 1 - we must use cache instruction */ mips32_pracc_clean_invalidate_cache(ejtag_info, start_addr, end_addr); break; case MIPS32_ARCH_REL2: /* MIPS32/64 Release 2 - we can use synci instruction */ mips32_pracc_sync_cache(ejtag_info, start_addr, end_addr); break; default: /* what ? */ break; } } return retval; } int mips32_pracc_write_regs(struct mips_ejtag *ejtag_info, uint32_t *regs) { static const uint32_t cp0_write_code[] = { MIPS32_MTC0(1, 12, 0), /* move $1 to status */ MIPS32_MTLO(1), /* move $1 to lo */ MIPS32_MTHI(1), /* move $1 to hi */ MIPS32_MTC0(1, 8, 0), /* move $1 to badvaddr */ MIPS32_MTC0(1, 13, 0), /* move $1 to cause*/ MIPS32_MTC0(1, 24, 0), /* move $1 to depc (pc) */ }; struct pracc_queue_info ctx = {.max_code = 37 * 2 + 6 + 1}; pracc_queue_init(&ctx); if (ctx.retval != ERROR_OK) goto exit; /* load registers 2 to 31 with lui and ori instructions, check if some instructions can be saved */ for (int i = 2; i < 32; i++) { if (LOWER16((regs[i])) == 0) /* if lower half word is 0, lui instruction only */ pracc_add(&ctx, 0, MIPS32_LUI(i, UPPER16((regs[i])))); else if (UPPER16((regs[i])) == 0) /* if upper half word is 0, ori with $0 only*/ pracc_add(&ctx, 0, MIPS32_ORI(i, 0, LOWER16((regs[i])))); else { /* default, load with lui and ori instructions */ pracc_add(&ctx, 0, MIPS32_LUI(i, UPPER16((regs[i])))); pracc_add(&ctx, 0, MIPS32_ORI(i, i, LOWER16((regs[i])))); } } for (int i = 0; i != 6; i++) { pracc_add(&ctx, 0, MIPS32_LUI(1, UPPER16((regs[i + 32])))); /* load CPO value in $1, with lui and ori */ pracc_add(&ctx, 0, MIPS32_ORI(1, 1, LOWER16((regs[i + 32])))); pracc_add(&ctx, 0, cp0_write_code[i]); /* write value from $1 to CPO register */ } pracc_add(&ctx, 0, MIPS32_LUI(1, UPPER16((regs[1])))); /* load upper half word in $1 */ pracc_add(&ctx, 0, MIPS32_B(NEG16(ctx.code_count + 1))); /* jump to start */ pracc_add(&ctx, 0, MIPS32_ORI(1, 1, LOWER16((regs[1])))); /* load lower half word in $1 */ ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL); ejtag_info->reg8 = regs[8]; ejtag_info->reg9 = regs[9]; exit: pracc_queue_free(&ctx); return ctx.retval; } int mips32_pracc_read_regs(struct mips_ejtag *ejtag_info, uint32_t *regs) { static int cp0_read_code[] = { MIPS32_MFC0(8, 12, 0), /* move status to $8 */ MIPS32_MFLO(8), /* move lo to $8 */ MIPS32_MFHI(8), /* move hi to $8 */ MIPS32_MFC0(8, 8, 0), /* move badvaddr to $8 */ MIPS32_MFC0(8, 13, 0), /* move cause to $8 */ MIPS32_MFC0(8, 24, 0), /* move depc (pc) to $8 */ }; struct pracc_queue_info ctx = {.max_code = 48}; pracc_queue_init(&ctx); if (ctx.retval != ERROR_OK) goto exit; pracc_add(&ctx, 0, MIPS32_MTC0(1, 31, 0)); /* move $1 to COP0 DeSave */ pracc_add(&ctx, 0, MIPS32_LUI(1, PRACC_UPPER_BASE_ADDR)); /* $1 = MIP32_PRACC_BASE_ADDR */ for (int i = 2; i != 32; i++) /* store GPR's 2 to 31 */ pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + (i * 4), MIPS32_SW(i, PRACC_OUT_OFFSET + (i * 4), 1)); for (int i = 0; i != 6; i++) { pracc_add(&ctx, 0, cp0_read_code[i]); /* load COP0 needed registers to $8 */ pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + (i + 32) * 4, /* store $8 at PARAM OUT */ MIPS32_SW(8, PRACC_OUT_OFFSET + (i + 32) * 4, 1)); } pracc_add(&ctx, 0, MIPS32_MFC0(8, 31, 0)); /* move DeSave to $8, reg1 value */ pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + 4, /* store reg1 value from $8 to param out */ MIPS32_SW(8, PRACC_OUT_OFFSET + 4, 1)); pracc_add(&ctx, 0, MIPS32_B(NEG16(ctx.code_count + 1))); /* jump to start */ pracc_add(&ctx, 0, MIPS32_MFC0(1, 31, 0)); /* move COP0 DeSave to $1, restore reg1 */ if (ejtag_info->mode == 0) ctx.store_count++; /* Needed by legacy code, due to offset from reg0 */ ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, regs); ejtag_info->reg8 = regs[8]; /* reg8 is saved but not restored, next called function should restore it */ ejtag_info->reg9 = regs[9]; exit: pracc_queue_free(&ctx); return ctx.retval; } /* fastdata upload/download requires an initialized working area * to load the download code; it should not be called otherwise * fetch order from the fastdata area * 1. start addr * 2. end addr * 3. data ... */ int mips32_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, struct working_area *source, int write_t, uint32_t addr, int count, uint32_t *buf) { uint32_t handler_code[] = { /* caution when editing, table is modified below */ /* r15 points to the start of this code */ MIPS32_SW(8, MIPS32_FASTDATA_HANDLER_SIZE - 4, 15), MIPS32_SW(9, MIPS32_FASTDATA_HANDLER_SIZE - 8, 15), MIPS32_SW(10, MIPS32_FASTDATA_HANDLER_SIZE - 12, 15), MIPS32_SW(11, MIPS32_FASTDATA_HANDLER_SIZE - 16, 15), /* start of fastdata area in t0 */ MIPS32_LUI(8, UPPER16(MIPS32_PRACC_FASTDATA_AREA)), MIPS32_ORI(8, 8, LOWER16(MIPS32_PRACC_FASTDATA_AREA)), MIPS32_LW(9, 0, 8), /* start addr in t1 */ MIPS32_LW(10, 0, 8), /* end addr to t2 */ /* loop: */ /* 8 */ MIPS32_LW(11, 0, 0), /* lw t3,[t8 | r9] */ /* 9 */ MIPS32_SW(11, 0, 0), /* sw t3,[r9 | r8] */ MIPS32_BNE(10, 9, NEG16(3)), /* bne $t2,t1,loop */ MIPS32_ADDI(9, 9, 4), /* addi t1,t1,4 */ MIPS32_LW(8, MIPS32_FASTDATA_HANDLER_SIZE - 4, 15), MIPS32_LW(9, MIPS32_FASTDATA_HANDLER_SIZE - 8, 15), MIPS32_LW(10, MIPS32_FASTDATA_HANDLER_SIZE - 12, 15), MIPS32_LW(11, MIPS32_FASTDATA_HANDLER_SIZE - 16, 15), MIPS32_LUI(15, UPPER16(MIPS32_PRACC_TEXT)), MIPS32_ORI(15, 15, LOWER16(MIPS32_PRACC_TEXT)), MIPS32_JR(15), /* jr start */ MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */ }; uint32_t jmp_code[] = { MIPS32_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */ /* 1 */ MIPS32_LUI(15, 0), /* addr of working area added below */ /* 2 */ MIPS32_ORI(15, 15, 0), /* addr of working area added below */ MIPS32_JR(15), /* jump to ram program */ MIPS32_NOP, }; int retval, i; uint32_t val, ejtag_ctrl, address; if (source->size < MIPS32_FASTDATA_HANDLER_SIZE) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; if (write_t) { handler_code[8] = MIPS32_LW(11, 0, 8); /* load data from probe at fastdata area */ handler_code[9] = MIPS32_SW(11, 0, 9); /* store data to RAM @ r9 */ } else { handler_code[8] = MIPS32_LW(11, 0, 9); /* load data from RAM @ r9 */ handler_code[9] = MIPS32_SW(11, 0, 8); /* store data to probe at fastdata area */ } /* write program into RAM */ if (write_t != ejtag_info->fast_access_save) { mips32_pracc_write_mem_generic(ejtag_info, source->address, 4, ARRAY_SIZE(handler_code), handler_code); /* save previous operation to speed to any consecutive read/writes */ ejtag_info->fast_access_save = write_t; } LOG_DEBUG("%s using 0x%.8" PRIx32 " for write handler", __func__, source->address); jmp_code[1] |= UPPER16(source->address); jmp_code[2] |= LOWER16(source->address); for (i = 0; i < (int) ARRAY_SIZE(jmp_code); i++) { retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl); if (retval != ERROR_OK) return retval; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA); mips_ejtag_drscan_32_out(ejtag_info, jmp_code[i]); /* Clear the access pending bit (let the processor eat!) */ ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); mips_ejtag_drscan_32_out(ejtag_info, ejtag_ctrl); } /* wait PrAcc pending bit for FASTDATA write */ retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl); if (retval != ERROR_OK) return retval; /* next fetch to dmseg should be in FASTDATA_AREA, check */ address = 0; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); retval = mips_ejtag_drscan_32(ejtag_info, &address); if (retval != ERROR_OK) return retval; if (address != MIPS32_PRACC_FASTDATA_AREA) return ERROR_FAIL; /* Send the load start address */ val = addr; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_FASTDATA); mips_ejtag_fastdata_scan(ejtag_info, 1, &val); retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl); if (retval != ERROR_OK) return retval; /* Send the load end address */ val = addr + (count - 1) * 4; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_FASTDATA); mips_ejtag_fastdata_scan(ejtag_info, 1, &val); unsigned num_clocks = 0; /* like in legacy code */ if (ejtag_info->mode != 0) num_clocks = ((uint64_t)(ejtag_info->scan_delay) * jtag_get_speed_khz() + 500000) / 1000000; for (i = 0; i < count; i++) { jtag_add_clocks(num_clocks); retval = mips_ejtag_fastdata_scan(ejtag_info, write_t, buf++); if (retval != ERROR_OK) return retval; } retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("fastdata load failed"); return retval; } retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl); if (retval != ERROR_OK) return retval; address = 0; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS); retval = mips_ejtag_drscan_32(ejtag_info, &address); if (retval != ERROR_OK) return retval; if (address != MIPS32_PRACC_TEXT) LOG_ERROR("mini program did not return to start"); return retval; } openocd-0.7.0/src/target/trace.c0000644000175000001440000001312212134336410013375 00000000000000/*************************************************************************** * Copyright (C) 2005, 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "trace.h" #include "target.h" int trace_point(struct target *target, uint32_t number) { struct trace *trace = target->trace_info; LOG_DEBUG("tracepoint: %i", (int)number); if (number < trace->num_trace_points) trace->trace_points[number].hit_counter++; if (trace->trace_history_size) { trace->trace_history[trace->trace_history_pos++] = number; if (trace->trace_history_pos == trace->trace_history_size) { trace->trace_history_pos = 0; trace->trace_history_overflowed = 1; } } return ERROR_OK; } COMMAND_HANDLER(handle_trace_point_command) { struct target *target = get_current_target(CMD_CTX); struct trace *trace = target->trace_info; if (CMD_ARGC == 0) { uint32_t i; for (i = 0; i < trace->num_trace_points; i++) { command_print(CMD_CTX, "trace point 0x%8.8" PRIx32 " (%lld times hit)", trace->trace_points[i].address, (long long)trace->trace_points[i].hit_counter); } return ERROR_OK; } if (!strcmp(CMD_ARGV[0], "clear")) { if (trace->trace_points) { free(trace->trace_points); trace->trace_points = NULL; } trace->num_trace_points = 0; trace->trace_points_size = 0; return ERROR_OK; } /* resize array if necessary */ if (!trace->trace_points || (trace->trace_points_size == trace->num_trace_points)) { trace->trace_points = realloc(trace->trace_points, sizeof(struct trace_point) * (trace->trace_points_size + 32)); trace->trace_points_size += 32; } uint32_t address; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); trace->trace_points[trace->num_trace_points].address = address; trace->trace_points[trace->num_trace_points].hit_counter = 0; trace->num_trace_points++; return ERROR_OK; } COMMAND_HANDLER(handle_trace_history_command) { struct target *target = get_current_target(CMD_CTX); struct trace *trace = target->trace_info; if (CMD_ARGC > 0) { trace->trace_history_pos = 0; trace->trace_history_overflowed = 0; if (!strcmp(CMD_ARGV[0], "clear")) { /* clearing is implicit, we've just reset position anyway */ return ERROR_OK; } if (trace->trace_history) free(trace->trace_history); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], trace->trace_history_size); trace->trace_history = malloc(sizeof(uint32_t) * trace->trace_history_size); command_print(CMD_CTX, "new trace history size: %i", (int)(trace->trace_history_size)); } else { uint32_t i; uint32_t first = 0; uint32_t last = trace->trace_history_pos; if (!trace->trace_history_size) { command_print(CMD_CTX, "trace history buffer is not allocated"); return ERROR_OK; } if (trace->trace_history_overflowed) { first = trace->trace_history_pos; last = trace->trace_history_pos - 1; } for (i = first; (i % trace->trace_history_size) != last; i++) { if (trace->trace_history[i % trace->trace_history_size] < trace->num_trace_points) { uint32_t address; address = trace->trace_points[trace->trace_history[i % trace->trace_history_size]].address; command_print(CMD_CTX, "trace point %i: 0x%8.8" PRIx32 "", (int)(trace->trace_history[i % trace->trace_history_size]), address); } else command_print(CMD_CTX, "trace point %i: -not defined-", (int)(trace->trace_history[i % trace->trace_history_size])); } } return ERROR_OK; } static const struct command_registration trace_exec_command_handlers[] = { { .name = "history", .handler = handle_trace_history_command, .mode = COMMAND_EXEC, .help = "display trace history, clear history or set size", .usage = "['clear'|size]", }, { .name = "point", .handler = handle_trace_point_command, .mode = COMMAND_EXEC, .help = "display trace points, clear list of trace points, " "or add new tracepoint at address", .usage = "['clear'|address]", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration trace_command_handlers[] = { { .name = "trace", .mode = COMMAND_EXEC, .help = "trace command group", .usage = "", .chain = trace_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; int trace_register_commands(struct command_context *cmd_ctx) { return register_commands(cmd_ctx, NULL, trace_command_handlers); } openocd-0.7.0/src/target/embeddedice.h0000644000175000001440000001052212134336410014517 00000000000000/*************************************************************************** * Copyright (C) 2005, 2006 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef EMBEDDED_ICE_H #define EMBEDDED_ICE_H #include "arm7_9_common.h" enum { EICE_DBG_CTRL = 0, EICE_DBG_STAT = 1, EICE_COMMS_CTRL = 2, EICE_COMMS_DATA = 3, EICE_W0_ADDR_VALUE = 4, EICE_W0_ADDR_MASK = 5, EICE_W0_DATA_VALUE = 6, EICE_W0_DATA_MASK = 7, EICE_W0_CONTROL_VALUE = 8, EICE_W0_CONTROL_MASK = 9, EICE_W1_ADDR_VALUE = 10, EICE_W1_ADDR_MASK = 11, EICE_W1_DATA_VALUE = 12, EICE_W1_DATA_MASK = 13, EICE_W1_CONTROL_VALUE = 14, EICE_W1_CONTROL_MASK = 15, EICE_VEC_CATCH = 16 }; enum { EICE_DBG_CONTROL_ICEDIS = 5, EICE_DBG_CONTROL_MONEN = 4, EICE_DBG_CONTROL_INTDIS = 2, EICE_DBG_CONTROL_DBGRQ = 1, EICE_DBG_CONTROL_DBGACK = 0, }; enum { EICE_DBG_STATUS_IJBIT = 5, EICE_DBG_STATUS_ITBIT = 4, EICE_DBG_STATUS_SYSCOMP = 3, EICE_DBG_STATUS_IFEN = 2, EICE_DBG_STATUS_DBGRQ = 1, EICE_DBG_STATUS_DBGACK = 0 }; enum { EICE_W_CTRL_ENABLE = 0x100, EICE_W_CTRL_RANGE = 0x80, EICE_W_CTRL_CHAIN = 0x40, EICE_W_CTRL_EXTERN = 0x20, EICE_W_CTRL_nTRANS = 0x10, EICE_W_CTRL_nOPC = 0x8, EICE_W_CTRL_MAS = 0x6, EICE_W_CTRL_ITBIT = 0x2, EICE_W_CTRL_nRW = 0x1 }; enum { EICE_COMM_CTRL_WBIT = 1, EICE_COMM_CTRL_RBIT = 0 }; struct embeddedice_reg { int addr; struct arm_jtag *jtag_info; }; struct reg_cache *embeddedice_build_reg_cache(struct target *target, struct arm7_9_common *arm7_9); int embeddedice_setup(struct target *target); int embeddedice_read_reg(struct reg *reg); int embeddedice_read_reg_w_check(struct reg *reg, uint8_t *check_value, uint8_t *check_mask); void embeddedice_write_reg(struct reg *reg, uint32_t value); void embeddedice_store_reg(struct reg *reg); void embeddedice_set_reg(struct reg *reg, uint32_t value); int embeddedice_receive(struct arm_jtag *jtag_info, uint32_t *data, uint32_t size); int embeddedice_send(struct arm_jtag *jtag_info, uint32_t *data, uint32_t size); int embeddedice_handshake(struct arm_jtag *jtag_info, int hsbit, uint32_t timeout); /* If many embeddedice_write_reg() follow eachother, then the >1 invocations can be * this faster version of embeddedice_write_reg */ static inline void embeddedice_write_reg_inner(struct jtag_tap *tap, int reg_addr, uint32_t value) { static const int embeddedice_num_bits[] = {32, 6}; uint32_t values[2]; values[0] = value; values[1] = (1 << 5) | reg_addr; jtag_add_dr_out(tap, 2, embeddedice_num_bits, values, TAP_IDLE); } void embeddedice_write_dcc(struct jtag_tap *tap, int reg_addr, const uint8_t *buffer, int little, int count); #endif /* EMBEDDED_ICE_H */ openocd-0.7.0/src/target/cortex_m.c0000644000175000001440000020427512137175623014144 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2006 by Magnus Lundin * * lundin@mlu.mine.nu * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * * * * * * Cortex-M3(tm) TRM, ARM DDI 0337E (r1p1) and 0337G (r2p0) * * * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "jtag/interface.h" #include "breakpoints.h" #include "cortex_m.h" #include "target_request.h" #include "target_type.h" #include "arm_disassembler.h" #include "register.h" #include "arm_opcodes.h" #include "arm_semihosting.h" #include /* NOTE: most of this should work fine for the Cortex-M1 and * Cortex-M0 cores too, although they're ARMv6-M not ARMv7-M. * Some differences: M0/M1 doesn't have FBP remapping or the * DWT tracing/profiling support. (So the cycle counter will * not be usable; the other stuff isn't currently used here.) * * Although there are some workarounds for errata seen only in r0p0 * silicon, such old parts are hard to find and thus not much tested * any longer. */ /** * Returns the type of a break point required by address location */ #define BKPT_TYPE_BY_ADDR(addr) ((addr) < 0x20000000 ? BKPT_HARD : BKPT_SOFT) /* forward declarations */ static int cortex_m3_store_core_reg_u32(struct target *target, uint32_t num, uint32_t value); static int cortexm3_dap_read_coreregister_u32(struct adiv5_dap *swjdp, uint32_t *value, int regnum) { int retval; uint32_t dcrdr; /* because the DCB_DCRDR is used for the emulated dcc channel * we have to save/restore the DCB_DCRDR when used */ retval = mem_ap_read_u32(swjdp, DCB_DCRDR, &dcrdr); if (retval != ERROR_OK) return retval; /* mem_ap_write_u32(swjdp, DCB_DCRSR, regnum); */ retval = dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRSR & 0xFFFFFFF0); if (retval != ERROR_OK) return retval; retval = dap_queue_ap_write(swjdp, AP_REG_BD0 | (DCB_DCRSR & 0xC), regnum); if (retval != ERROR_OK) return retval; /* mem_ap_read_u32(swjdp, DCB_DCRDR, value); */ retval = dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRDR & 0xFFFFFFF0); if (retval != ERROR_OK) return retval; retval = dap_queue_ap_read(swjdp, AP_REG_BD0 | (DCB_DCRDR & 0xC), value); if (retval != ERROR_OK) return retval; retval = dap_run(swjdp); if (retval != ERROR_OK) return retval; /* restore DCB_DCRDR - this needs to be in a seperate * transaction otherwise the emulated DCC channel breaks */ if (retval == ERROR_OK) retval = mem_ap_write_atomic_u32(swjdp, DCB_DCRDR, dcrdr); return retval; } static int cortexm3_dap_write_coreregister_u32(struct adiv5_dap *swjdp, uint32_t value, int regnum) { int retval; uint32_t dcrdr; /* because the DCB_DCRDR is used for the emulated dcc channel * we have to save/restore the DCB_DCRDR when used */ retval = mem_ap_read_u32(swjdp, DCB_DCRDR, &dcrdr); if (retval != ERROR_OK) return retval; /* mem_ap_write_u32(swjdp, DCB_DCRDR, core_regs[i]); */ retval = dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRDR & 0xFFFFFFF0); if (retval != ERROR_OK) return retval; retval = dap_queue_ap_write(swjdp, AP_REG_BD0 | (DCB_DCRDR & 0xC), value); if (retval != ERROR_OK) return retval; /* mem_ap_write_u32(swjdp, DCB_DCRSR, i | DCRSR_WnR); */ retval = dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRSR & 0xFFFFFFF0); if (retval != ERROR_OK) return retval; retval = dap_queue_ap_write(swjdp, AP_REG_BD0 | (DCB_DCRSR & 0xC), regnum | DCRSR_WnR); if (retval != ERROR_OK) return retval; retval = dap_run(swjdp); if (retval != ERROR_OK) return retval; /* restore DCB_DCRDR - this needs to be in a seperate * transaction otherwise the emulated DCC channel breaks */ if (retval == ERROR_OK) retval = mem_ap_write_atomic_u32(swjdp, DCB_DCRDR, dcrdr); return retval; } static int cortex_m3_write_debug_halt_mask(struct target *target, uint32_t mask_on, uint32_t mask_off) { struct cortex_m3_common *cortex_m3 = target_to_cm3(target); struct adiv5_dap *swjdp = cortex_m3->armv7m.arm.dap; /* mask off status bits */ cortex_m3->dcb_dhcsr &= ~((0xFFFF << 16) | mask_off); /* create new register mask */ cortex_m3->dcb_dhcsr |= DBGKEY | C_DEBUGEN | mask_on; return mem_ap_write_atomic_u32(swjdp, DCB_DHCSR, cortex_m3->dcb_dhcsr); } static int cortex_m3_clear_halt(struct target *target) { struct cortex_m3_common *cortex_m3 = target_to_cm3(target); struct adiv5_dap *swjdp = cortex_m3->armv7m.arm.dap; int retval; /* clear step if any */ cortex_m3_write_debug_halt_mask(target, C_HALT, C_STEP); /* Read Debug Fault Status Register */ retval = mem_ap_read_atomic_u32(swjdp, NVIC_DFSR, &cortex_m3->nvic_dfsr); if (retval != ERROR_OK) return retval; /* Clear Debug Fault Status */ retval = mem_ap_write_atomic_u32(swjdp, NVIC_DFSR, cortex_m3->nvic_dfsr); if (retval != ERROR_OK) return retval; LOG_DEBUG(" NVIC_DFSR 0x%" PRIx32 "", cortex_m3->nvic_dfsr); return ERROR_OK; } static int cortex_m3_single_step_core(struct target *target) { struct cortex_m3_common *cortex_m3 = target_to_cm3(target); struct adiv5_dap *swjdp = cortex_m3->armv7m.arm.dap; uint32_t dhcsr_save; int retval; /* backup dhcsr reg */ dhcsr_save = cortex_m3->dcb_dhcsr; /* Mask interrupts before clearing halt, if done already. This avoids * Erratum 377497 (fixed in r1p0) where setting MASKINTS while clearing * HALT can put the core into an unknown state. */ if (!(cortex_m3->dcb_dhcsr & C_MASKINTS)) { retval = mem_ap_write_atomic_u32(swjdp, DCB_DHCSR, DBGKEY | C_MASKINTS | C_HALT | C_DEBUGEN); if (retval != ERROR_OK) return retval; } retval = mem_ap_write_atomic_u32(swjdp, DCB_DHCSR, DBGKEY | C_MASKINTS | C_STEP | C_DEBUGEN); if (retval != ERROR_OK) return retval; LOG_DEBUG(" "); /* restore dhcsr reg */ cortex_m3->dcb_dhcsr = dhcsr_save; cortex_m3_clear_halt(target); return ERROR_OK; } static int cortex_m3_endreset_event(struct target *target) { int i; int retval; uint32_t dcb_demcr; struct cortex_m3_common *cortex_m3 = target_to_cm3(target); struct armv7m_common *armv7m = &cortex_m3->armv7m; struct adiv5_dap *swjdp = cortex_m3->armv7m.arm.dap; struct cortex_m3_fp_comparator *fp_list = cortex_m3->fp_comparator_list; struct cortex_m3_dwt_comparator *dwt_list = cortex_m3->dwt_comparator_list; /* REVISIT The four debug monitor bits are currently ignored... */ retval = mem_ap_read_atomic_u32(swjdp, DCB_DEMCR, &dcb_demcr); if (retval != ERROR_OK) return retval; LOG_DEBUG("DCB_DEMCR = 0x%8.8" PRIx32 "", dcb_demcr); /* this register is used for emulated dcc channel */ retval = mem_ap_write_u32(swjdp, DCB_DCRDR, 0); if (retval != ERROR_OK) return retval; /* Enable debug requests */ retval = mem_ap_read_atomic_u32(swjdp, DCB_DHCSR, &cortex_m3->dcb_dhcsr); if (retval != ERROR_OK) return retval; if (!(cortex_m3->dcb_dhcsr & C_DEBUGEN)) { retval = mem_ap_write_u32(swjdp, DCB_DHCSR, DBGKEY | C_DEBUGEN); if (retval != ERROR_OK) return retval; } /* clear any interrupt masking */ cortex_m3_write_debug_halt_mask(target, 0, C_MASKINTS); /* Enable features controlled by ITM and DWT blocks, and catch only * the vectors we were told to pay attention to. * * Target firmware is responsible for all fault handling policy * choices *EXCEPT* explicitly scripted overrides like "vector_catch" * or manual updates to the NVIC SHCSR and CCR registers. */ retval = mem_ap_write_u32(swjdp, DCB_DEMCR, TRCENA | armv7m->demcr); if (retval != ERROR_OK) return retval; /* Paranoia: evidently some (early?) chips don't preserve all the * debug state (including FBP, DWT, etc) across reset... */ /* Enable FPB */ retval = target_write_u32(target, FP_CTRL, 3); if (retval != ERROR_OK) return retval; cortex_m3->fpb_enabled = 1; /* Restore FPB registers */ for (i = 0; i < cortex_m3->fp_num_code + cortex_m3->fp_num_lit; i++) { retval = target_write_u32(target, fp_list[i].fpcr_address, fp_list[i].fpcr_value); if (retval != ERROR_OK) return retval; } /* Restore DWT registers */ for (i = 0; i < cortex_m3->dwt_num_comp; i++) { retval = target_write_u32(target, dwt_list[i].dwt_comparator_address + 0, dwt_list[i].comp); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, dwt_list[i].dwt_comparator_address + 4, dwt_list[i].mask); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, dwt_list[i].dwt_comparator_address + 8, dwt_list[i].function); if (retval != ERROR_OK) return retval; } retval = dap_run(swjdp); if (retval != ERROR_OK) return retval; register_cache_invalidate(armv7m->arm.core_cache); /* make sure we have latest dhcsr flags */ retval = mem_ap_read_atomic_u32(swjdp, DCB_DHCSR, &cortex_m3->dcb_dhcsr); return retval; } static int cortex_m3_examine_debug_reason(struct target *target) { struct cortex_m3_common *cortex_m3 = target_to_cm3(target); /* THIS IS NOT GOOD, TODO - better logic for detection of debug state reason * only check the debug reason if we don't know it already */ if ((target->debug_reason != DBG_REASON_DBGRQ) && (target->debug_reason != DBG_REASON_SINGLESTEP)) { if (cortex_m3->nvic_dfsr & DFSR_BKPT) { target->debug_reason = DBG_REASON_BREAKPOINT; if (cortex_m3->nvic_dfsr & DFSR_DWTTRAP) target->debug_reason = DBG_REASON_WPTANDBKPT; } else if (cortex_m3->nvic_dfsr & DFSR_DWTTRAP) target->debug_reason = DBG_REASON_WATCHPOINT; else if (cortex_m3->nvic_dfsr & DFSR_VCATCH) target->debug_reason = DBG_REASON_BREAKPOINT; else /* EXTERNAL, HALTED */ target->debug_reason = DBG_REASON_UNDEFINED; } return ERROR_OK; } static int cortex_m3_examine_exception_reason(struct target *target) { uint32_t shcsr = 0, except_sr = 0, cfsr = -1, except_ar = -1; struct armv7m_common *armv7m = target_to_armv7m(target); struct adiv5_dap *swjdp = armv7m->arm.dap; int retval; retval = mem_ap_read_u32(swjdp, NVIC_SHCSR, &shcsr); if (retval != ERROR_OK) return retval; switch (armv7m->exception_number) { case 2: /* NMI */ break; case 3: /* Hard Fault */ retval = mem_ap_read_atomic_u32(swjdp, NVIC_HFSR, &except_sr); if (retval != ERROR_OK) return retval; if (except_sr & 0x40000000) { retval = mem_ap_read_u32(swjdp, NVIC_CFSR, &cfsr); if (retval != ERROR_OK) return retval; } break; case 4: /* Memory Management */ retval = mem_ap_read_u32(swjdp, NVIC_CFSR, &except_sr); if (retval != ERROR_OK) return retval; retval = mem_ap_read_u32(swjdp, NVIC_MMFAR, &except_ar); if (retval != ERROR_OK) return retval; break; case 5: /* Bus Fault */ retval = mem_ap_read_u32(swjdp, NVIC_CFSR, &except_sr); if (retval != ERROR_OK) return retval; retval = mem_ap_read_u32(swjdp, NVIC_BFAR, &except_ar); if (retval != ERROR_OK) return retval; break; case 6: /* Usage Fault */ retval = mem_ap_read_u32(swjdp, NVIC_CFSR, &except_sr); if (retval != ERROR_OK) return retval; break; case 11: /* SVCall */ break; case 12: /* Debug Monitor */ retval = mem_ap_read_u32(swjdp, NVIC_DFSR, &except_sr); if (retval != ERROR_OK) return retval; break; case 14: /* PendSV */ break; case 15: /* SysTick */ break; default: except_sr = 0; break; } retval = dap_run(swjdp); if (retval == ERROR_OK) LOG_DEBUG("%s SHCSR 0x%" PRIx32 ", SR 0x%" PRIx32 ", CFSR 0x%" PRIx32 ", AR 0x%" PRIx32, armv7m_exception_string(armv7m->exception_number), shcsr, except_sr, cfsr, except_ar); return retval; } static int cortex_m3_debug_entry(struct target *target) { int i; uint32_t xPSR; int retval; struct cortex_m3_common *cortex_m3 = target_to_cm3(target); struct armv7m_common *armv7m = &cortex_m3->armv7m; struct arm *arm = &armv7m->arm; struct adiv5_dap *swjdp = armv7m->arm.dap; struct reg *r; LOG_DEBUG(" "); cortex_m3_clear_halt(target); retval = mem_ap_read_atomic_u32(swjdp, DCB_DHCSR, &cortex_m3->dcb_dhcsr); if (retval != ERROR_OK) return retval; retval = armv7m->examine_debug_reason(target); if (retval != ERROR_OK) return retval; /* Examine target state and mode * First load register accessible through core debug port */ int num_regs = arm->core_cache->num_regs; for (i = 0; i < num_regs; i++) { r = &armv7m->arm.core_cache->reg_list[i]; if (!r->valid) arm->read_core_reg(target, r, i, ARM_MODE_ANY); } r = arm->core_cache->reg_list + ARMV7M_xPSR; xPSR = buf_get_u32(r->value, 0, 32); #ifdef ARMV7_GDB_HACKS /* FIXME this breaks on scan chains with more than one Cortex-M3. * Instead, each CM3 should have its own dummy value... */ /* copy real xpsr reg for gdb, setting thumb bit */ buf_set_u32(armv7m_gdb_dummy_cpsr_value, 0, 32, xPSR); buf_set_u32(armv7m_gdb_dummy_cpsr_value, 5, 1, 1); armv7m_gdb_dummy_cpsr_reg.valid = r->valid; armv7m_gdb_dummy_cpsr_reg.dirty = r->dirty; #endif /* For IT instructions xPSR must be reloaded on resume and clear on debug exec */ if (xPSR & 0xf00) { r->dirty = r->valid; cortex_m3_store_core_reg_u32(target, 16, xPSR & ~0xff); } /* Are we in an exception handler */ if (xPSR & 0x1FF) { armv7m->exception_number = (xPSR & 0x1FF); arm->core_mode = ARM_MODE_HANDLER; arm->map = armv7m_msp_reg_map; } else { unsigned control = buf_get_u32(arm->core_cache ->reg_list[ARMV7M_CONTROL].value, 0, 2); /* is this thread privileged? */ arm->core_mode = control & 1 ? ARM_MODE_USER_THREAD : ARM_MODE_THREAD; /* which stack is it using? */ if (control & 2) arm->map = armv7m_psp_reg_map; else arm->map = armv7m_msp_reg_map; armv7m->exception_number = 0; } if (armv7m->exception_number) cortex_m3_examine_exception_reason(target); LOG_DEBUG("entered debug state in core mode: %s at PC 0x%" PRIx32 ", target->state: %s", arm_mode_name(arm->core_mode), *(uint32_t *)(arm->pc->value), target_state_name(target)); if (armv7m->post_debug_entry) { retval = armv7m->post_debug_entry(target); if (retval != ERROR_OK) return retval; } return ERROR_OK; } static int cortex_m3_poll(struct target *target) { int detected_failure = ERROR_OK; int retval = ERROR_OK; enum target_state prev_target_state = target->state; struct cortex_m3_common *cortex_m3 = target_to_cm3(target); struct adiv5_dap *swjdp = cortex_m3->armv7m.arm.dap; /* Read from Debug Halting Control and Status Register */ retval = mem_ap_read_atomic_u32(swjdp, DCB_DHCSR, &cortex_m3->dcb_dhcsr); if (retval != ERROR_OK) { target->state = TARGET_UNKNOWN; return retval; } /* Recover from lockup. See ARMv7-M architecture spec, * section B1.5.15 "Unrecoverable exception cases". */ if (cortex_m3->dcb_dhcsr & S_LOCKUP) { LOG_ERROR("%s -- clearing lockup after double fault", target_name(target)); cortex_m3_write_debug_halt_mask(target, C_HALT, 0); target->debug_reason = DBG_REASON_DBGRQ; /* We have to execute the rest (the "finally" equivalent, but * still throw this exception again). */ detected_failure = ERROR_FAIL; /* refresh status bits */ retval = mem_ap_read_atomic_u32(swjdp, DCB_DHCSR, &cortex_m3->dcb_dhcsr); if (retval != ERROR_OK) return retval; } if (cortex_m3->dcb_dhcsr & S_RESET_ST) { /* check if still in reset */ retval = mem_ap_read_atomic_u32(swjdp, DCB_DHCSR, &cortex_m3->dcb_dhcsr); if (retval != ERROR_OK) return retval; if (cortex_m3->dcb_dhcsr & S_RESET_ST) { target->state = TARGET_RESET; return ERROR_OK; } } if (target->state == TARGET_RESET) { /* Cannot switch context while running so endreset is * called with target->state == TARGET_RESET */ LOG_DEBUG("Exit from reset with dcb_dhcsr 0x%" PRIx32, cortex_m3->dcb_dhcsr); cortex_m3_endreset_event(target); target->state = TARGET_RUNNING; prev_target_state = TARGET_RUNNING; } if (cortex_m3->dcb_dhcsr & S_HALT) { target->state = TARGET_HALTED; if ((prev_target_state == TARGET_RUNNING) || (prev_target_state == TARGET_RESET)) { retval = cortex_m3_debug_entry(target); if (retval != ERROR_OK) return retval; if (arm_semihosting(target, &retval) != 0) return retval; target_call_event_callbacks(target, TARGET_EVENT_HALTED); } if (prev_target_state == TARGET_DEBUG_RUNNING) { LOG_DEBUG(" "); retval = cortex_m3_debug_entry(target); if (retval != ERROR_OK) return retval; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); } } /* REVISIT when S_SLEEP is set, it's in a Sleep or DeepSleep state. * How best to model low power modes? */ if (target->state == TARGET_UNKNOWN) { /* check if processor is retiring instructions */ if (cortex_m3->dcb_dhcsr & S_RETIRE_ST) { target->state = TARGET_RUNNING; retval = ERROR_OK; } } /* Did we detect a failure condition that we cleared? */ if (detected_failure != ERROR_OK) retval = detected_failure; return retval; } static int cortex_m3_halt(struct target *target) { LOG_DEBUG("target->state: %s", target_state_name(target)); if (target->state == TARGET_HALTED) { LOG_DEBUG("target was already halted"); return ERROR_OK; } if (target->state == TARGET_UNKNOWN) LOG_WARNING("target was in unknown state when halt was requested"); if (target->state == TARGET_RESET) { if ((jtag_get_reset_config() & RESET_SRST_PULLS_TRST) && jtag_get_srst()) { LOG_ERROR("can't request a halt while in reset if nSRST pulls nTRST"); return ERROR_TARGET_FAILURE; } else { /* we came here in a reset_halt or reset_init sequence * debug entry was already prepared in cortex_m3_assert_reset() */ target->debug_reason = DBG_REASON_DBGRQ; return ERROR_OK; } } /* Write to Debug Halting Control and Status Register */ cortex_m3_write_debug_halt_mask(target, C_HALT, 0); target->debug_reason = DBG_REASON_DBGRQ; return ERROR_OK; } static int cortex_m3_soft_reset_halt(struct target *target) { struct cortex_m3_common *cortex_m3 = target_to_cm3(target); struct adiv5_dap *swjdp = cortex_m3->armv7m.arm.dap; uint32_t dcb_dhcsr = 0; int retval, timeout = 0; /* Enter debug state on reset; restore DEMCR in endreset_event() */ retval = mem_ap_write_u32(swjdp, DCB_DEMCR, TRCENA | VC_HARDERR | VC_BUSERR | VC_CORERESET); if (retval != ERROR_OK) return retval; /* Request a core-only reset */ retval = mem_ap_write_atomic_u32(swjdp, NVIC_AIRCR, AIRCR_VECTKEY | AIRCR_VECTRESET); if (retval != ERROR_OK) return retval; target->state = TARGET_RESET; /* registers are now invalid */ register_cache_invalidate(cortex_m3->armv7m.arm.core_cache); while (timeout < 100) { retval = mem_ap_read_atomic_u32(swjdp, DCB_DHCSR, &dcb_dhcsr); if (retval == ERROR_OK) { retval = mem_ap_read_atomic_u32(swjdp, NVIC_DFSR, &cortex_m3->nvic_dfsr); if (retval != ERROR_OK) return retval; if ((dcb_dhcsr & S_HALT) && (cortex_m3->nvic_dfsr & DFSR_VCATCH)) { LOG_DEBUG("system reset-halted, DHCSR 0x%08x, " "DFSR 0x%08x", (unsigned) dcb_dhcsr, (unsigned) cortex_m3->nvic_dfsr); cortex_m3_poll(target); /* FIXME restore user's vector catch config */ return ERROR_OK; } else LOG_DEBUG("waiting for system reset-halt, " "DHCSR 0x%08x, %d ms", (unsigned) dcb_dhcsr, timeout); } timeout++; alive_sleep(1); } return ERROR_OK; } void cortex_m3_enable_breakpoints(struct target *target) { struct breakpoint *breakpoint = target->breakpoints; /* set any pending breakpoints */ while (breakpoint) { if (!breakpoint->set) cortex_m3_set_breakpoint(target, breakpoint); breakpoint = breakpoint->next; } } static int cortex_m3_resume(struct target *target, int current, uint32_t address, int handle_breakpoints, int debug_execution) { struct armv7m_common *armv7m = target_to_armv7m(target); struct breakpoint *breakpoint = NULL; uint32_t resume_pc; struct reg *r; if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!debug_execution) { target_free_all_working_areas(target); cortex_m3_enable_breakpoints(target); cortex_m3_enable_watchpoints(target); } if (debug_execution) { r = armv7m->arm.core_cache->reg_list + ARMV7M_PRIMASK; /* Disable interrupts */ /* We disable interrupts in the PRIMASK register instead of * masking with C_MASKINTS. This is probably the same issue * as Cortex-M3 Erratum 377493 (fixed in r1p0): C_MASKINTS * in parallel with disabled interrupts can cause local faults * to not be taken. * * REVISIT this clearly breaks non-debug execution, since the * PRIMASK register state isn't saved/restored... workaround * by never resuming app code after debug execution. */ buf_set_u32(r->value, 0, 1, 1); r->dirty = true; r->valid = true; /* Make sure we are in Thumb mode */ r = armv7m->arm.core_cache->reg_list + ARMV7M_xPSR; buf_set_u32(r->value, 24, 1, 1); r->dirty = true; r->valid = true; } /* current = 1: continue on current pc, otherwise continue at
*/ r = armv7m->arm.pc; if (!current) { buf_set_u32(r->value, 0, 32, address); r->dirty = true; r->valid = true; } /* if we halted last time due to a bkpt instruction * then we have to manually step over it, otherwise * the core will break again */ if (!breakpoint_find(target, buf_get_u32(r->value, 0, 32)) && !debug_execution) armv7m_maybe_skip_bkpt_inst(target, NULL); resume_pc = buf_get_u32(r->value, 0, 32); armv7m_restore_context(target); /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) { /* Single step past breakpoint at current address */ breakpoint = breakpoint_find(target, resume_pc); if (breakpoint) { LOG_DEBUG("unset breakpoint at 0x%8.8" PRIx32 " (ID: %d)", breakpoint->address, breakpoint->unique_id); cortex_m3_unset_breakpoint(target, breakpoint); cortex_m3_single_step_core(target); cortex_m3_set_breakpoint(target, breakpoint); } } /* Restart core */ cortex_m3_write_debug_halt_mask(target, 0, C_HALT); target->debug_reason = DBG_REASON_NOTHALTED; /* registers are now invalid */ register_cache_invalidate(armv7m->arm.core_cache); if (!debug_execution) { target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); LOG_DEBUG("target resumed at 0x%" PRIx32 "", resume_pc); } else { target->state = TARGET_DEBUG_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); LOG_DEBUG("target debug resumed at 0x%" PRIx32 "", resume_pc); } return ERROR_OK; } /* int irqstepcount = 0; */ static int cortex_m3_step(struct target *target, int current, uint32_t address, int handle_breakpoints) { struct cortex_m3_common *cortex_m3 = target_to_cm3(target); struct armv7m_common *armv7m = &cortex_m3->armv7m; struct adiv5_dap *swjdp = armv7m->arm.dap; struct breakpoint *breakpoint = NULL; struct reg *pc = armv7m->arm.pc; bool bkpt_inst_found = false; int retval; bool isr_timed_out = false; if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* current = 1: continue on current pc, otherwise continue at
*/ if (!current) buf_set_u32(pc->value, 0, 32, address); uint32_t pc_value = buf_get_u32(pc->value, 0, 32); /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) { breakpoint = breakpoint_find(target, pc_value); if (breakpoint) cortex_m3_unset_breakpoint(target, breakpoint); } armv7m_maybe_skip_bkpt_inst(target, &bkpt_inst_found); target->debug_reason = DBG_REASON_SINGLESTEP; armv7m_restore_context(target); target_call_event_callbacks(target, TARGET_EVENT_RESUMED); /* if no bkpt instruction is found at pc then we can perform * a normal step, otherwise we have to manually step over the bkpt * instruction - as such simulate a step */ if (bkpt_inst_found == false) { /* Automatic ISR masking mode off: Just step over the next instruction */ if ((cortex_m3->isrmasking_mode != CORTEX_M3_ISRMASK_AUTO)) cortex_m3_write_debug_halt_mask(target, C_STEP, C_HALT); else { /* Process interrupts during stepping in a way they don't interfere * debugging. * * Principle: * * Set a temporary break point at the current pc and let the core run * with interrupts enabled. Pending interrupts get served and we run * into the breakpoint again afterwards. Then we step over the next * instruction with interrupts disabled. * * If the pending interrupts don't complete within time, we leave the * core running. This may happen if the interrupts trigger faster * than the core can process them or the handler doesn't return. * * If no more breakpoints are available we simply do a step with * interrupts enabled. * */ /* 2012-09-29 ph * * If a break point is already set on the lower half word then a break point on * the upper half word will not break again when the core is restarted. So we * just step over the instruction with interrupts disabled. * * The documentation has no information about this, it was found by observation * on STM32F1 and STM32F2. Proper explanation welcome. STM32F0 dosen't seem to * suffer from this problem. * * To add some confusion: pc_value has bit 0 always set, while the breakpoint * address has it always cleared. The former is done to indicate thumb mode * to gdb. * */ if ((pc_value & 0x02) && breakpoint_find(target, pc_value & ~0x03)) { LOG_DEBUG("Stepping over next instruction with interrupts disabled"); cortex_m3_write_debug_halt_mask(target, C_HALT | C_MASKINTS, 0); cortex_m3_write_debug_halt_mask(target, C_STEP, C_HALT); /* Re-enable interrupts */ cortex_m3_write_debug_halt_mask(target, C_HALT, C_MASKINTS); } else { /* Set a temporary break point */ if (breakpoint) retval = cortex_m3_set_breakpoint(target, breakpoint); else retval = breakpoint_add(target, pc_value, 2, BKPT_TYPE_BY_ADDR(pc_value)); bool tmp_bp_set = (retval == ERROR_OK); /* No more breakpoints left, just do a step */ if (!tmp_bp_set) cortex_m3_write_debug_halt_mask(target, C_STEP, C_HALT); else { /* Start the core */ LOG_DEBUG("Starting core to serve pending interrupts"); int64_t t_start = timeval_ms(); cortex_m3_write_debug_halt_mask(target, 0, C_HALT | C_STEP); /* Wait for pending handlers to complete or timeout */ do { retval = mem_ap_read_atomic_u32(swjdp, DCB_DHCSR, &cortex_m3->dcb_dhcsr); if (retval != ERROR_OK) { target->state = TARGET_UNKNOWN; return retval; } isr_timed_out = ((timeval_ms() - t_start) > 500); } while (!((cortex_m3->dcb_dhcsr & S_HALT) || isr_timed_out)); /* only remove breakpoint if we created it */ if (breakpoint) cortex_m3_unset_breakpoint(target, breakpoint); else { /* Remove the temporary breakpoint */ breakpoint_remove(target, pc_value); } if (isr_timed_out) { LOG_DEBUG("Interrupt handlers didn't complete within time, " "leaving target running"); } else { /* Step over next instruction with interrupts disabled */ cortex_m3_write_debug_halt_mask(target, C_HALT | C_MASKINTS, 0); cortex_m3_write_debug_halt_mask(target, C_STEP, C_HALT); /* Re-enable interrupts */ cortex_m3_write_debug_halt_mask(target, C_HALT, C_MASKINTS); } } } } } retval = mem_ap_read_atomic_u32(swjdp, DCB_DHCSR, &cortex_m3->dcb_dhcsr); if (retval != ERROR_OK) return retval; /* registers are now invalid */ register_cache_invalidate(armv7m->arm.core_cache); if (breakpoint) cortex_m3_set_breakpoint(target, breakpoint); if (isr_timed_out) { /* Leave the core running. The user has to stop execution manually. */ target->debug_reason = DBG_REASON_NOTHALTED; target->state = TARGET_RUNNING; return ERROR_OK; } LOG_DEBUG("target stepped dcb_dhcsr = 0x%" PRIx32 " nvic_icsr = 0x%" PRIx32, cortex_m3->dcb_dhcsr, cortex_m3->nvic_icsr); retval = cortex_m3_debug_entry(target); if (retval != ERROR_OK) return retval; target_call_event_callbacks(target, TARGET_EVENT_HALTED); LOG_DEBUG("target stepped dcb_dhcsr = 0x%" PRIx32 " nvic_icsr = 0x%" PRIx32, cortex_m3->dcb_dhcsr, cortex_m3->nvic_icsr); return ERROR_OK; } static int cortex_m3_assert_reset(struct target *target) { struct cortex_m3_common *cortex_m3 = target_to_cm3(target); struct adiv5_dap *swjdp = cortex_m3->armv7m.arm.dap; enum cortex_m3_soft_reset_config reset_config = cortex_m3->soft_reset_config; LOG_DEBUG("target->state: %s", target_state_name(target)); enum reset_types jtag_reset_config = jtag_get_reset_config(); if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT)) { /* allow scripts to override the reset event */ target_handle_event(target, TARGET_EVENT_RESET_ASSERT); register_cache_invalidate(cortex_m3->armv7m.arm.core_cache); target->state = TARGET_RESET; return ERROR_OK; } /* some cores support connecting while srst is asserted * use that mode is it has been configured */ bool srst_asserted = false; if (jtag_reset_config & RESET_SRST_NO_GATING) { adapter_assert_reset(); srst_asserted = true; } /* Enable debug requests */ int retval; retval = mem_ap_read_atomic_u32(swjdp, DCB_DHCSR, &cortex_m3->dcb_dhcsr); if (retval != ERROR_OK) return retval; if (!(cortex_m3->dcb_dhcsr & C_DEBUGEN)) { retval = mem_ap_write_u32(swjdp, DCB_DHCSR, DBGKEY | C_DEBUGEN); if (retval != ERROR_OK) return retval; } /* If the processor is sleeping in a WFI or WFE instruction, the * C_HALT bit must be asserted to regain control */ if (cortex_m3->dcb_dhcsr & S_SLEEP) { retval = mem_ap_write_u32(swjdp, DCB_DHCSR, DBGKEY | C_HALT | C_DEBUGEN); if (retval != ERROR_OK) return retval; } retval = mem_ap_write_u32(swjdp, DCB_DCRDR, 0); if (retval != ERROR_OK) return retval; if (!target->reset_halt) { /* Set/Clear C_MASKINTS in a separate operation */ if (cortex_m3->dcb_dhcsr & C_MASKINTS) { retval = mem_ap_write_atomic_u32(swjdp, DCB_DHCSR, DBGKEY | C_DEBUGEN | C_HALT); if (retval != ERROR_OK) return retval; } /* clear any debug flags before resuming */ cortex_m3_clear_halt(target); /* clear C_HALT in dhcsr reg */ cortex_m3_write_debug_halt_mask(target, 0, C_HALT); } else { /* Halt in debug on reset; endreset_event() restores DEMCR. * * REVISIT catching BUSERR presumably helps to defend against * bad vector table entries. Should this include MMERR or * other flags too? */ retval = mem_ap_write_atomic_u32(swjdp, DCB_DEMCR, TRCENA | VC_HARDERR | VC_BUSERR | VC_CORERESET); if (retval != ERROR_OK) return retval; } if (jtag_reset_config & RESET_HAS_SRST) { /* default to asserting srst */ if (!srst_asserted) adapter_assert_reset(); } else { /* Use a standard Cortex-M3 software reset mechanism. * We default to using VECRESET as it is supported on all current cores. * This has the disadvantage of not resetting the peripherals, so a * reset-init event handler is needed to perform any peripheral resets. */ retval = mem_ap_write_atomic_u32(swjdp, NVIC_AIRCR, AIRCR_VECTKEY | ((reset_config == CORTEX_M3_RESET_SYSRESETREQ) ? AIRCR_SYSRESETREQ : AIRCR_VECTRESET)); if (retval != ERROR_OK) return retval; LOG_DEBUG("Using Cortex-M3 %s", (reset_config == CORTEX_M3_RESET_SYSRESETREQ) ? "SYSRESETREQ" : "VECTRESET"); if (reset_config == CORTEX_M3_RESET_VECTRESET) { LOG_WARNING("Only resetting the Cortex-M3 core, use a reset-init event " "handler to reset any peripherals or configure hardware srst support."); } { /* I do not know why this is necessary, but it * fixes strange effects (step/resume cause NMI * after reset) on LM3S6918 -- Michael Schwingen */ uint32_t tmp; retval = mem_ap_read_atomic_u32(swjdp, NVIC_AIRCR, &tmp); if (retval != ERROR_OK) return retval; } } target->state = TARGET_RESET; jtag_add_sleep(50000); register_cache_invalidate(cortex_m3->armv7m.arm.core_cache); if (target->reset_halt) { retval = target_halt(target); if (retval != ERROR_OK) return retval; } return ERROR_OK; } static int cortex_m3_deassert_reset(struct target *target) { LOG_DEBUG("target->state: %s", target_state_name(target)); /* deassert reset lines */ adapter_deassert_reset(); return ERROR_OK; } int cortex_m3_set_breakpoint(struct target *target, struct breakpoint *breakpoint) { int retval; int fp_num = 0; uint32_t hilo; struct cortex_m3_common *cortex_m3 = target_to_cm3(target); struct cortex_m3_fp_comparator *comparator_list = cortex_m3->fp_comparator_list; if (breakpoint->set) { LOG_WARNING("breakpoint (BPID: %d) already set", breakpoint->unique_id); return ERROR_OK; } if (cortex_m3->auto_bp_type) breakpoint->type = BKPT_TYPE_BY_ADDR(breakpoint->address); if (breakpoint->type == BKPT_HARD) { while (comparator_list[fp_num].used && (fp_num < cortex_m3->fp_num_code)) fp_num++; if (fp_num >= cortex_m3->fp_num_code) { LOG_ERROR("Can not find free FPB Comparator!"); return ERROR_FAIL; } breakpoint->set = fp_num + 1; hilo = (breakpoint->address & 0x2) ? FPCR_REPLACE_BKPT_HIGH : FPCR_REPLACE_BKPT_LOW; comparator_list[fp_num].used = 1; comparator_list[fp_num].fpcr_value = (breakpoint->address & 0x1FFFFFFC) | hilo | 1; target_write_u32(target, comparator_list[fp_num].fpcr_address, comparator_list[fp_num].fpcr_value); LOG_DEBUG("fpc_num %i fpcr_value 0x%" PRIx32 "", fp_num, comparator_list[fp_num].fpcr_value); if (!cortex_m3->fpb_enabled) { LOG_DEBUG("FPB wasn't enabled, do it now"); target_write_u32(target, FP_CTRL, 3); } } else if (breakpoint->type == BKPT_SOFT) { uint8_t code[4]; /* NOTE: on ARMv6-M and ARMv7-M, BKPT(0xab) is used for * semihosting; don't use that. Otherwise the BKPT * parameter is arbitrary. */ buf_set_u32(code, 0, 32, ARMV5_T_BKPT(0x11)); retval = target_read_memory(target, breakpoint->address & 0xFFFFFFFE, breakpoint->length, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; retval = target_write_memory(target, breakpoint->address & 0xFFFFFFFE, breakpoint->length, 1, code); if (retval != ERROR_OK) return retval; breakpoint->set = true; } LOG_DEBUG("BPID: %d, Type: %d, Address: 0x%08" PRIx32 " Length: %d (set=%d)", breakpoint->unique_id, (int)(breakpoint->type), breakpoint->address, breakpoint->length, breakpoint->set); return ERROR_OK; } int cortex_m3_unset_breakpoint(struct target *target, struct breakpoint *breakpoint) { int retval; struct cortex_m3_common *cortex_m3 = target_to_cm3(target); struct cortex_m3_fp_comparator *comparator_list = cortex_m3->fp_comparator_list; if (!breakpoint->set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } LOG_DEBUG("BPID: %d, Type: %d, Address: 0x%08" PRIx32 " Length: %d (set=%d)", breakpoint->unique_id, (int)(breakpoint->type), breakpoint->address, breakpoint->length, breakpoint->set); if (breakpoint->type == BKPT_HARD) { int fp_num = breakpoint->set - 1; if ((fp_num < 0) || (fp_num >= cortex_m3->fp_num_code)) { LOG_DEBUG("Invalid FP Comparator number in breakpoint"); return ERROR_OK; } comparator_list[fp_num].used = 0; comparator_list[fp_num].fpcr_value = 0; target_write_u32(target, comparator_list[fp_num].fpcr_address, comparator_list[fp_num].fpcr_value); } else { /* restore original instruction (kept in target endianness) */ if (breakpoint->length == 4) { retval = target_write_memory(target, breakpoint->address & 0xFFFFFFFE, 4, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; } else { retval = target_write_memory(target, breakpoint->address & 0xFFFFFFFE, 2, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; } } breakpoint->set = false; return ERROR_OK; } int cortex_m3_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct cortex_m3_common *cortex_m3 = target_to_cm3(target); if (cortex_m3->auto_bp_type) { breakpoint->type = BKPT_TYPE_BY_ADDR(breakpoint->address); #ifdef ARMV7_GDB_HACKS if (breakpoint->length != 2) { /* XXX Hack: Replace all breakpoints with length != 2 with * a hardware breakpoint. */ breakpoint->type = BKPT_HARD; breakpoint->length = 2; } #endif } if (breakpoint->type != BKPT_TYPE_BY_ADDR(breakpoint->address)) { if (breakpoint->type == BKPT_HARD) { LOG_INFO("flash patch comparator requested outside code memory region"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if (breakpoint->type == BKPT_SOFT) { LOG_INFO("soft breakpoint requested in code (flash) memory region"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } if ((breakpoint->type == BKPT_HARD) && (cortex_m3->fp_code_available < 1)) { LOG_INFO("no flash patch comparator unit available for hardware breakpoint"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if ((breakpoint->length != 2)) { LOG_INFO("only breakpoints of two bytes length supported"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if (breakpoint->type == BKPT_HARD) cortex_m3->fp_code_available--; return cortex_m3_set_breakpoint(target, breakpoint); } int cortex_m3_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct cortex_m3_common *cortex_m3 = target_to_cm3(target); /* REVISIT why check? FBP can be updated with core running ... */ if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (cortex_m3->auto_bp_type) breakpoint->type = BKPT_TYPE_BY_ADDR(breakpoint->address); if (breakpoint->set) cortex_m3_unset_breakpoint(target, breakpoint); if (breakpoint->type == BKPT_HARD) cortex_m3->fp_code_available++; return ERROR_OK; } int cortex_m3_set_watchpoint(struct target *target, struct watchpoint *watchpoint) { int dwt_num = 0; uint32_t mask, temp; struct cortex_m3_common *cortex_m3 = target_to_cm3(target); /* watchpoint params were validated earlier */ mask = 0; temp = watchpoint->length; while (temp) { temp >>= 1; mask++; } mask--; /* REVISIT Don't fully trust these "not used" records ... users * may set up breakpoints by hand, e.g. dual-address data value * watchpoint using comparator #1; comparator #0 matching cycle * count; send data trace info through ITM and TPIU; etc */ struct cortex_m3_dwt_comparator *comparator; for (comparator = cortex_m3->dwt_comparator_list; comparator->used && dwt_num < cortex_m3->dwt_num_comp; comparator++, dwt_num++) continue; if (dwt_num >= cortex_m3->dwt_num_comp) { LOG_ERROR("Can not find free DWT Comparator"); return ERROR_FAIL; } comparator->used = 1; watchpoint->set = dwt_num + 1; comparator->comp = watchpoint->address; target_write_u32(target, comparator->dwt_comparator_address + 0, comparator->comp); comparator->mask = mask; target_write_u32(target, comparator->dwt_comparator_address + 4, comparator->mask); switch (watchpoint->rw) { case WPT_READ: comparator->function = 5; break; case WPT_WRITE: comparator->function = 6; break; case WPT_ACCESS: comparator->function = 7; break; } target_write_u32(target, comparator->dwt_comparator_address + 8, comparator->function); LOG_DEBUG("Watchpoint (ID %d) DWT%d 0x%08x 0x%x 0x%05x", watchpoint->unique_id, dwt_num, (unsigned) comparator->comp, (unsigned) comparator->mask, (unsigned) comparator->function); return ERROR_OK; } int cortex_m3_unset_watchpoint(struct target *target, struct watchpoint *watchpoint) { struct cortex_m3_common *cortex_m3 = target_to_cm3(target); struct cortex_m3_dwt_comparator *comparator; int dwt_num; if (!watchpoint->set) { LOG_WARNING("watchpoint (wpid: %d) not set", watchpoint->unique_id); return ERROR_OK; } dwt_num = watchpoint->set - 1; LOG_DEBUG("Watchpoint (ID %d) DWT%d address: 0x%08x clear", watchpoint->unique_id, dwt_num, (unsigned) watchpoint->address); if ((dwt_num < 0) || (dwt_num >= cortex_m3->dwt_num_comp)) { LOG_DEBUG("Invalid DWT Comparator number in watchpoint"); return ERROR_OK; } comparator = cortex_m3->dwt_comparator_list + dwt_num; comparator->used = 0; comparator->function = 0; target_write_u32(target, comparator->dwt_comparator_address + 8, comparator->function); watchpoint->set = false; return ERROR_OK; } int cortex_m3_add_watchpoint(struct target *target, struct watchpoint *watchpoint) { struct cortex_m3_common *cortex_m3 = target_to_cm3(target); if (cortex_m3->dwt_comp_available < 1) { LOG_DEBUG("no comparators?"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* hardware doesn't support data value masking */ if (watchpoint->mask != ~(uint32_t)0) { LOG_DEBUG("watchpoint value masks not supported"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* hardware allows address masks of up to 32K */ unsigned mask; for (mask = 0; mask < 16; mask++) { if ((1u << mask) == watchpoint->length) break; } if (mask == 16) { LOG_DEBUG("unsupported watchpoint length"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if (watchpoint->address & ((1 << mask) - 1)) { LOG_DEBUG("watchpoint address is unaligned"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } /* Caller doesn't seem to be able to describe watching for data * values of zero; that flags "no value". * * REVISIT This DWT may well be able to watch for specific data * values. Requires comparator #1 to set DATAVMATCH and match * the data, and another comparator (DATAVADDR0) matching addr. */ if (watchpoint->value) { LOG_DEBUG("data value watchpoint not YET supported"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } cortex_m3->dwt_comp_available--; LOG_DEBUG("dwt_comp_available: %d", cortex_m3->dwt_comp_available); return ERROR_OK; } int cortex_m3_remove_watchpoint(struct target *target, struct watchpoint *watchpoint) { struct cortex_m3_common *cortex_m3 = target_to_cm3(target); /* REVISIT why check? DWT can be updated with core running ... */ if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (watchpoint->set) cortex_m3_unset_watchpoint(target, watchpoint); cortex_m3->dwt_comp_available++; LOG_DEBUG("dwt_comp_available: %d", cortex_m3->dwt_comp_available); return ERROR_OK; } void cortex_m3_enable_watchpoints(struct target *target) { struct watchpoint *watchpoint = target->watchpoints; /* set any pending watchpoints */ while (watchpoint) { if (!watchpoint->set) cortex_m3_set_watchpoint(target, watchpoint); watchpoint = watchpoint->next; } } static int cortex_m3_load_core_reg_u32(struct target *target, uint32_t num, uint32_t *value) { int retval; struct armv7m_common *armv7m = target_to_armv7m(target); struct adiv5_dap *swjdp = armv7m->arm.dap; /* NOTE: we "know" here that the register identifiers used * in the v7m header match the Cortex-M3 Debug Core Register * Selector values for R0..R15, xPSR, MSP, and PSP. */ switch (num) { case 0 ... 18: /* read a normal core register */ retval = cortexm3_dap_read_coreregister_u32(swjdp, value, num); if (retval != ERROR_OK) { LOG_ERROR("JTAG failure %i", retval); return ERROR_JTAG_DEVICE_ERROR; } LOG_DEBUG("load from core reg %i value 0x%" PRIx32 "", (int)num, *value); break; case ARMV7M_PRIMASK: case ARMV7M_BASEPRI: case ARMV7M_FAULTMASK: case ARMV7M_CONTROL: /* Cortex-M3 packages these four registers as bitfields * in one Debug Core register. So say r0 and r2 docs; * it was removed from r1 docs, but still works. */ cortexm3_dap_read_coreregister_u32(swjdp, value, 20); switch (num) { case ARMV7M_PRIMASK: *value = buf_get_u32((uint8_t *)value, 0, 1); break; case ARMV7M_BASEPRI: *value = buf_get_u32((uint8_t *)value, 8, 8); break; case ARMV7M_FAULTMASK: *value = buf_get_u32((uint8_t *)value, 16, 1); break; case ARMV7M_CONTROL: *value = buf_get_u32((uint8_t *)value, 24, 2); break; } LOG_DEBUG("load from special reg %i value 0x%" PRIx32 "", (int)num, *value); break; default: return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; } static int cortex_m3_store_core_reg_u32(struct target *target, uint32_t num, uint32_t value) { int retval; uint32_t reg; struct armv7m_common *armv7m = target_to_armv7m(target); struct adiv5_dap *swjdp = armv7m->arm.dap; #ifdef ARMV7_GDB_HACKS /* If the LR register is being modified, make sure it will put us * in "thumb" mode, or an INVSTATE exception will occur. This is a * hack to deal with the fact that gdb will sometimes "forge" * return addresses, and doesn't set the LSB correctly (i.e., when * printing expressions containing function calls, it sets LR = 0.) * Valid exception return codes have bit 0 set too. */ if (num == ARMV7M_R14) value |= 0x01; #endif /* NOTE: we "know" here that the register identifiers used * in the v7m header match the Cortex-M3 Debug Core Register * Selector values for R0..R15, xPSR, MSP, and PSP. */ switch (num) { case 0 ... 18: retval = cortexm3_dap_write_coreregister_u32(swjdp, value, num); if (retval != ERROR_OK) { struct reg *r; LOG_ERROR("JTAG failure"); r = armv7m->arm.core_cache->reg_list + num; r->dirty = r->valid; return ERROR_JTAG_DEVICE_ERROR; } LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", (int)num, value); break; case ARMV7M_PRIMASK: case ARMV7M_BASEPRI: case ARMV7M_FAULTMASK: case ARMV7M_CONTROL: /* Cortex-M3 packages these four registers as bitfields * in one Debug Core register. So say r0 and r2 docs; * it was removed from r1 docs, but still works. */ cortexm3_dap_read_coreregister_u32(swjdp, ®, 20); switch (num) { case ARMV7M_PRIMASK: buf_set_u32((uint8_t *)®, 0, 1, value); break; case ARMV7M_BASEPRI: buf_set_u32((uint8_t *)®, 8, 8, value); break; case ARMV7M_FAULTMASK: buf_set_u32((uint8_t *)®, 16, 1, value); break; case ARMV7M_CONTROL: buf_set_u32((uint8_t *)®, 24, 2, value); break; } cortexm3_dap_write_coreregister_u32(swjdp, reg, 20); LOG_DEBUG("write special reg %i value 0x%" PRIx32 " ", (int)num, value); break; default: return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; } static int cortex_m3_read_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct armv7m_common *armv7m = target_to_armv7m(target); struct adiv5_dap *swjdp = armv7m->arm.dap; int retval = ERROR_COMMAND_SYNTAX_ERROR; if (armv7m->arm.is_armv6m) { /* armv6m does not handle unaligned memory access */ if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) return ERROR_TARGET_UNALIGNED_ACCESS; } /* cortex_m3 handles unaligned memory access */ if (count && buffer) { switch (size) { case 4: retval = mem_ap_read_buf_u32(swjdp, buffer, 4 * count, address, true); break; case 2: retval = mem_ap_read_buf_u16(swjdp, buffer, 2 * count, address); break; case 1: retval = mem_ap_read_buf_u8(swjdp, buffer, count, address); break; } } return retval; } static int cortex_m3_write_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct armv7m_common *armv7m = target_to_armv7m(target); struct adiv5_dap *swjdp = armv7m->arm.dap; int retval = ERROR_COMMAND_SYNTAX_ERROR; if (armv7m->arm.is_armv6m) { /* armv6m does not handle unaligned memory access */ if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) return ERROR_TARGET_UNALIGNED_ACCESS; } if (count && buffer) { switch (size) { case 4: retval = mem_ap_write_buf_u32(swjdp, buffer, 4 * count, address, true); break; case 2: retval = mem_ap_write_buf_u16(swjdp, buffer, 2 * count, address); break; case 1: retval = mem_ap_write_buf_u8(swjdp, buffer, count, address); break; } } return retval; } static int cortex_m3_init_target(struct command_context *cmd_ctx, struct target *target) { armv7m_build_reg_cache(target); return ERROR_OK; } /* REVISIT cache valid/dirty bits are unmaintained. We could set "valid" * on r/w if the core is not running, and clear on resume or reset ... or * at least, in a post_restore_context() method. */ struct dwt_reg_state { struct target *target; uint32_t addr; uint32_t value; /* scratch/cache */ }; static int cortex_m3_dwt_get_reg(struct reg *reg) { struct dwt_reg_state *state = reg->arch_info; return target_read_u32(state->target, state->addr, &state->value); } static int cortex_m3_dwt_set_reg(struct reg *reg, uint8_t *buf) { struct dwt_reg_state *state = reg->arch_info; return target_write_u32(state->target, state->addr, buf_get_u32(buf, 0, reg->size)); } struct dwt_reg { uint32_t addr; char *name; unsigned size; }; static struct dwt_reg dwt_base_regs[] = { { DWT_CTRL, "dwt_ctrl", 32, }, /* NOTE that Erratum 532314 (fixed r2p0) affects CYCCNT: it wrongly * increments while the core is asleep. */ { DWT_CYCCNT, "dwt_cyccnt", 32, }, /* plus some 8 bit counters, useful for profiling with TPIU */ }; static struct dwt_reg dwt_comp[] = { #define DWT_COMPARATOR(i) \ { DWT_COMP0 + 0x10 * (i), "dwt_" #i "_comp", 32, }, \ { DWT_MASK0 + 0x10 * (i), "dwt_" #i "_mask", 4, }, \ { DWT_FUNCTION0 + 0x10 * (i), "dwt_" #i "_function", 32, } DWT_COMPARATOR(0), DWT_COMPARATOR(1), DWT_COMPARATOR(2), DWT_COMPARATOR(3), #undef DWT_COMPARATOR }; static const struct reg_arch_type dwt_reg_type = { .get = cortex_m3_dwt_get_reg, .set = cortex_m3_dwt_set_reg, }; static void cortex_m3_dwt_addreg(struct target *t, struct reg *r, struct dwt_reg *d) { struct dwt_reg_state *state; state = calloc(1, sizeof *state); if (!state) return; state->addr = d->addr; state->target = t; r->name = d->name; r->size = d->size; r->value = &state->value; r->arch_info = state; r->type = &dwt_reg_type; } void cortex_m3_dwt_setup(struct cortex_m3_common *cm3, struct target *target) { uint32_t dwtcr; struct reg_cache *cache; struct cortex_m3_dwt_comparator *comparator; int reg, i; target_read_u32(target, DWT_CTRL, &dwtcr); if (!dwtcr) { LOG_DEBUG("no DWT"); return; } cm3->dwt_num_comp = (dwtcr >> 28) & 0xF; cm3->dwt_comp_available = cm3->dwt_num_comp; cm3->dwt_comparator_list = calloc(cm3->dwt_num_comp, sizeof(struct cortex_m3_dwt_comparator)); if (!cm3->dwt_comparator_list) { fail0: cm3->dwt_num_comp = 0; LOG_ERROR("out of mem"); return; } cache = calloc(1, sizeof *cache); if (!cache) { fail1: free(cm3->dwt_comparator_list); goto fail0; } cache->name = "cortex-m3 dwt registers"; cache->num_regs = 2 + cm3->dwt_num_comp * 3; cache->reg_list = calloc(cache->num_regs, sizeof *cache->reg_list); if (!cache->reg_list) { free(cache); goto fail1; } for (reg = 0; reg < 2; reg++) cortex_m3_dwt_addreg(target, cache->reg_list + reg, dwt_base_regs + reg); comparator = cm3->dwt_comparator_list; for (i = 0; i < cm3->dwt_num_comp; i++, comparator++) { int j; comparator->dwt_comparator_address = DWT_COMP0 + 0x10 * i; for (j = 0; j < 3; j++, reg++) cortex_m3_dwt_addreg(target, cache->reg_list + reg, dwt_comp + 3 * i + j); /* make sure we clear any watchpoints enabled on the target */ target_write_u32(target, comparator->dwt_comparator_address + 8, 0); } *register_get_last_cache_p(&target->reg_cache) = cache; cm3->dwt_cache = cache; LOG_DEBUG("DWT dwtcr 0x%" PRIx32 ", comp %d, watch%s", dwtcr, cm3->dwt_num_comp, (dwtcr & (0xf << 24)) ? " only" : "/trigger"); /* REVISIT: if num_comp > 1, check whether comparator #1 can * implement single-address data value watchpoints ... so we * won't need to check it later, when asked to set one up. */ } #define MVFR0 0xe000ef40 #define MVFR1 0xe000ef44 #define MVFR0_DEFAULT_M4 0x10110021 #define MVFR1_DEFAULT_M4 0x11000011 int cortex_m3_examine(struct target *target) { int retval; uint32_t cpuid, fpcr, mvfr0, mvfr1; int i; struct cortex_m3_common *cortex_m3 = target_to_cm3(target); struct adiv5_dap *swjdp = cortex_m3->armv7m.arm.dap; struct armv7m_common *armv7m = target_to_armv7m(target); /* stlink shares the examine handler but does not support * all its calls */ if (!armv7m->stlink) { retval = ahbap_debugport_init(swjdp); if (retval != ERROR_OK) return retval; } if (!target_was_examined(target)) { target_set_examined(target); /* Read from Device Identification Registers */ retval = target_read_u32(target, CPUID, &cpuid); if (retval != ERROR_OK) return retval; /* Get CPU Type */ i = (cpuid >> 4) & 0xf; LOG_DEBUG("Cortex-M%d r%" PRId8 "p%" PRId8 " processor detected", i, (uint8_t)((cpuid >> 20) & 0xf), (uint8_t)((cpuid >> 0) & 0xf)); LOG_DEBUG("cpuid: 0x%8.8" PRIx32 "", cpuid); /* test for floating point feature on cortex-m4 */ if (i == 4) { target_read_u32(target, MVFR0, &mvfr0); target_read_u32(target, MVFR1, &mvfr1); if ((mvfr0 == MVFR0_DEFAULT_M4) && (mvfr1 == MVFR1_DEFAULT_M4)) { LOG_DEBUG("Cortex-M%d floating point feature FPv4_SP found", i); armv7m->fp_feature = FPv4_SP; } } else if (i == 0) { /* Cortex-M0 does not support unaligned memory access */ armv7m->arm.is_armv6m = true; } if (i == 4 || i == 3) { /* Cortex-M3/M4 has 4096 bytes autoincrement range */ armv7m->dap.tar_autoincr_block = (1 << 12); } /* NOTE: FPB and DWT are both optional. */ /* Setup FPB */ target_read_u32(target, FP_CTRL, &fpcr); cortex_m3->auto_bp_type = 1; cortex_m3->fp_num_code = ((fpcr >> 8) & 0x70) | ((fpcr >> 4) & 0xF); /* bits *[14:12] *and [7:4] **/ cortex_m3->fp_num_lit = (fpcr >> 8) & 0xF; cortex_m3->fp_code_available = cortex_m3->fp_num_code; cortex_m3->fp_comparator_list = calloc( cortex_m3->fp_num_code + cortex_m3->fp_num_lit, sizeof(struct cortex_m3_fp_comparator)); cortex_m3->fpb_enabled = fpcr & 1; for (i = 0; i < cortex_m3->fp_num_code + cortex_m3->fp_num_lit; i++) { cortex_m3->fp_comparator_list[i].type = (i < cortex_m3->fp_num_code) ? FPCR_CODE : FPCR_LITERAL; cortex_m3->fp_comparator_list[i].fpcr_address = FP_COMP0 + 4 * i; /* make sure we clear any breakpoints enabled on the target */ target_write_u32(target, cortex_m3->fp_comparator_list[i].fpcr_address, 0); } LOG_DEBUG("FPB fpcr 0x%" PRIx32 ", numcode %i, numlit %i", fpcr, cortex_m3->fp_num_code, cortex_m3->fp_num_lit); /* Setup DWT */ cortex_m3_dwt_setup(cortex_m3, target); /* These hardware breakpoints only work for code in flash! */ LOG_INFO("%s: hardware has %d breakpoints, %d watchpoints", target_name(target), cortex_m3->fp_num_code, cortex_m3->dwt_num_comp); } return ERROR_OK; } static int cortex_m3_dcc_read(struct adiv5_dap *swjdp, uint8_t *value, uint8_t *ctrl) { uint16_t dcrdr; int retval; mem_ap_read_buf_u16(swjdp, (uint8_t *)&dcrdr, 1, DCB_DCRDR); *ctrl = (uint8_t)dcrdr; *value = (uint8_t)(dcrdr >> 8); LOG_DEBUG("data 0x%x ctrl 0x%x", *value, *ctrl); /* write ack back to software dcc register * signify we have read data */ if (dcrdr & (1 << 0)) { dcrdr = 0; retval = mem_ap_write_buf_u16(swjdp, (uint8_t *)&dcrdr, 1, DCB_DCRDR); if (retval != ERROR_OK) return retval; } return ERROR_OK; } static int cortex_m3_target_request_data(struct target *target, uint32_t size, uint8_t *buffer) { struct armv7m_common *armv7m = target_to_armv7m(target); struct adiv5_dap *swjdp = armv7m->arm.dap; uint8_t data; uint8_t ctrl; uint32_t i; for (i = 0; i < (size * 4); i++) { cortex_m3_dcc_read(swjdp, &data, &ctrl); buffer[i] = data; } return ERROR_OK; } static int cortex_m3_handle_target_request(void *priv) { struct target *target = priv; if (!target_was_examined(target)) return ERROR_OK; struct armv7m_common *armv7m = target_to_armv7m(target); struct adiv5_dap *swjdp = armv7m->arm.dap; if (!target->dbg_msg_enabled) return ERROR_OK; if (target->state == TARGET_RUNNING) { uint8_t data; uint8_t ctrl; cortex_m3_dcc_read(swjdp, &data, &ctrl); /* check if we have data */ if (ctrl & (1 << 0)) { uint32_t request; /* we assume target is quick enough */ request = data; cortex_m3_dcc_read(swjdp, &data, &ctrl); request |= (data << 8); cortex_m3_dcc_read(swjdp, &data, &ctrl); request |= (data << 16); cortex_m3_dcc_read(swjdp, &data, &ctrl); request |= (data << 24); target_request(target, request); } } return ERROR_OK; } static int cortex_m3_init_arch_info(struct target *target, struct cortex_m3_common *cortex_m3, struct jtag_tap *tap) { int retval; struct armv7m_common *armv7m = &cortex_m3->armv7m; armv7m_init_arch_info(target, armv7m); /* prepare JTAG information for the new target */ cortex_m3->jtag_info.tap = tap; cortex_m3->jtag_info.scann_size = 4; /* default reset mode is to use srst if fitted * if not it will use CORTEX_M3_RESET_VECTRESET */ cortex_m3->soft_reset_config = CORTEX_M3_RESET_VECTRESET; armv7m->arm.dap = &armv7m->dap; /* Leave (only) generic DAP stuff for debugport_init(); */ armv7m->dap.jtag_info = &cortex_m3->jtag_info; armv7m->dap.memaccess_tck = 8; /* Cortex-M3/M4 has 4096 bytes autoincrement range * but set a safe default to 1024 to support Cortex-M0 * this will be changed in cortex_m3_examine if a M3/M4 is detected */ armv7m->dap.tar_autoincr_block = (1 << 10); /* register arch-specific functions */ armv7m->examine_debug_reason = cortex_m3_examine_debug_reason; armv7m->post_debug_entry = NULL; armv7m->pre_restore_context = NULL; armv7m->load_core_reg_u32 = cortex_m3_load_core_reg_u32; armv7m->store_core_reg_u32 = cortex_m3_store_core_reg_u32; target_register_timer_callback(cortex_m3_handle_target_request, 1, 1, target); retval = arm_jtag_setup_connection(&cortex_m3->jtag_info); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int cortex_m3_target_create(struct target *target, Jim_Interp *interp) { struct cortex_m3_common *cortex_m3 = calloc(1, sizeof(struct cortex_m3_common)); cortex_m3->common_magic = CORTEX_M3_COMMON_MAGIC; cortex_m3_init_arch_info(target, cortex_m3, target->tap); return ERROR_OK; } /*--------------------------------------------------------------------------*/ static int cortex_m3_verify_pointer(struct command_context *cmd_ctx, struct cortex_m3_common *cm3) { if (cm3->common_magic != CORTEX_M3_COMMON_MAGIC) { command_print(cmd_ctx, "target is not a Cortex-M3"); return ERROR_TARGET_INVALID; } return ERROR_OK; } /* * Only stuff below this line should need to verify that its target * is a Cortex-M3. Everything else should have indirected through the * cortexm3_target structure, which is only used with CM3 targets. */ static const struct { char name[10]; unsigned mask; } vec_ids[] = { { "hard_err", VC_HARDERR, }, { "int_err", VC_INTERR, }, { "bus_err", VC_BUSERR, }, { "state_err", VC_STATERR, }, { "chk_err", VC_CHKERR, }, { "nocp_err", VC_NOCPERR, }, { "mm_err", VC_MMERR, }, { "reset", VC_CORERESET, }, }; COMMAND_HANDLER(handle_cortex_m3_vector_catch_command) { struct target *target = get_current_target(CMD_CTX); struct cortex_m3_common *cortex_m3 = target_to_cm3(target); struct armv7m_common *armv7m = &cortex_m3->armv7m; struct adiv5_dap *swjdp = armv7m->arm.dap; uint32_t demcr = 0; int retval; retval = cortex_m3_verify_pointer(CMD_CTX, cortex_m3); if (retval != ERROR_OK) return retval; retval = mem_ap_read_atomic_u32(swjdp, DCB_DEMCR, &demcr); if (retval != ERROR_OK) return retval; if (CMD_ARGC > 0) { unsigned catch = 0; if (CMD_ARGC == 1) { if (strcmp(CMD_ARGV[0], "all") == 0) { catch = VC_HARDERR | VC_INTERR | VC_BUSERR | VC_STATERR | VC_CHKERR | VC_NOCPERR | VC_MMERR | VC_CORERESET; goto write; } else if (strcmp(CMD_ARGV[0], "none") == 0) goto write; } while (CMD_ARGC-- > 0) { unsigned i; for (i = 0; i < ARRAY_SIZE(vec_ids); i++) { if (strcmp(CMD_ARGV[CMD_ARGC], vec_ids[i].name) != 0) continue; catch |= vec_ids[i].mask; break; } if (i == ARRAY_SIZE(vec_ids)) { LOG_ERROR("No CM3 vector '%s'", CMD_ARGV[CMD_ARGC]); return ERROR_COMMAND_SYNTAX_ERROR; } } write: /* For now, armv7m->demcr only stores vector catch flags. */ armv7m->demcr = catch; demcr &= ~0xffff; demcr |= catch; /* write, but don't assume it stuck (why not??) */ retval = mem_ap_write_u32(swjdp, DCB_DEMCR, demcr); if (retval != ERROR_OK) return retval; retval = mem_ap_read_atomic_u32(swjdp, DCB_DEMCR, &demcr); if (retval != ERROR_OK) return retval; /* FIXME be sure to clear DEMCR on clean server shutdown. * Otherwise the vector catch hardware could fire when there's * no debugger hooked up, causing much confusion... */ } for (unsigned i = 0; i < ARRAY_SIZE(vec_ids); i++) { command_print(CMD_CTX, "%9s: %s", vec_ids[i].name, (demcr & vec_ids[i].mask) ? "catch" : "ignore"); } return ERROR_OK; } COMMAND_HANDLER(handle_cortex_m3_mask_interrupts_command) { struct target *target = get_current_target(CMD_CTX); struct cortex_m3_common *cortex_m3 = target_to_cm3(target); int retval; static const Jim_Nvp nvp_maskisr_modes[] = { { .name = "auto", .value = CORTEX_M3_ISRMASK_AUTO }, { .name = "off", .value = CORTEX_M3_ISRMASK_OFF }, { .name = "on", .value = CORTEX_M3_ISRMASK_ON }, { .name = NULL, .value = -1 }, }; const Jim_Nvp *n; retval = cortex_m3_verify_pointer(CMD_CTX, cortex_m3); if (retval != ERROR_OK) return retval; if (target->state != TARGET_HALTED) { command_print(CMD_CTX, "target must be stopped for \"%s\" command", CMD_NAME); return ERROR_OK; } if (CMD_ARGC > 0) { n = Jim_Nvp_name2value_simple(nvp_maskisr_modes, CMD_ARGV[0]); if (n->name == NULL) return ERROR_COMMAND_SYNTAX_ERROR; cortex_m3->isrmasking_mode = n->value; if (cortex_m3->isrmasking_mode == CORTEX_M3_ISRMASK_ON) cortex_m3_write_debug_halt_mask(target, C_HALT | C_MASKINTS, 0); else cortex_m3_write_debug_halt_mask(target, C_HALT, C_MASKINTS); } n = Jim_Nvp_value2name_simple(nvp_maskisr_modes, cortex_m3->isrmasking_mode); command_print(CMD_CTX, "cortex_m3 interrupt mask %s", n->name); return ERROR_OK; } COMMAND_HANDLER(handle_cortex_m3_reset_config_command) { struct target *target = get_current_target(CMD_CTX); struct cortex_m3_common *cortex_m3 = target_to_cm3(target); int retval; char *reset_config; retval = cortex_m3_verify_pointer(CMD_CTX, cortex_m3); if (retval != ERROR_OK) return retval; if (CMD_ARGC > 0) { if (strcmp(*CMD_ARGV, "sysresetreq") == 0) cortex_m3->soft_reset_config = CORTEX_M3_RESET_SYSRESETREQ; else if (strcmp(*CMD_ARGV, "vectreset") == 0) cortex_m3->soft_reset_config = CORTEX_M3_RESET_VECTRESET; } switch (cortex_m3->soft_reset_config) { case CORTEX_M3_RESET_SYSRESETREQ: reset_config = "sysresetreq"; break; case CORTEX_M3_RESET_VECTRESET: reset_config = "vectreset"; break; default: reset_config = "unknown"; break; } command_print(CMD_CTX, "cortex_m3 reset_config %s", reset_config); return ERROR_OK; } static const struct command_registration cortex_m3_exec_command_handlers[] = { { .name = "maskisr", .handler = handle_cortex_m3_mask_interrupts_command, .mode = COMMAND_EXEC, .help = "mask cortex_m3 interrupts", .usage = "['auto'|'on'|'off']", }, { .name = "vector_catch", .handler = handle_cortex_m3_vector_catch_command, .mode = COMMAND_EXEC, .help = "configure hardware vectors to trigger debug entry", .usage = "['all'|'none'|('bus_err'|'chk_err'|...)*]", }, { .name = "reset_config", .handler = handle_cortex_m3_reset_config_command, .mode = COMMAND_ANY, .help = "configure software reset handling", .usage = "['srst'|'sysresetreq'|'vectreset']", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration cortex_m3_command_handlers[] = { { .chain = armv7m_command_handlers, }, { .name = "cortex_m", .mode = COMMAND_EXEC, .help = "Cortex-M command group", .usage = "", .chain = cortex_m3_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct target_type cortexm3_target = { .name = "cortex_m", .deprecated_name = "cortex_m3", .poll = cortex_m3_poll, .arch_state = armv7m_arch_state, .target_request_data = cortex_m3_target_request_data, .halt = cortex_m3_halt, .resume = cortex_m3_resume, .step = cortex_m3_step, .assert_reset = cortex_m3_assert_reset, .deassert_reset = cortex_m3_deassert_reset, .soft_reset_halt = cortex_m3_soft_reset_halt, .get_gdb_reg_list = armv7m_get_gdb_reg_list, .read_memory = cortex_m3_read_memory, .write_memory = cortex_m3_write_memory, .checksum_memory = armv7m_checksum_memory, .blank_check_memory = armv7m_blank_check_memory, .run_algorithm = armv7m_run_algorithm, .start_algorithm = armv7m_start_algorithm, .wait_algorithm = armv7m_wait_algorithm, .add_breakpoint = cortex_m3_add_breakpoint, .remove_breakpoint = cortex_m3_remove_breakpoint, .add_watchpoint = cortex_m3_add_watchpoint, .remove_watchpoint = cortex_m3_remove_watchpoint, .commands = cortex_m3_command_handlers, .target_create = cortex_m3_target_create, .init_target = cortex_m3_init_target, .examine = cortex_m3_examine, }; openocd-0.7.0/src/target/armv7a.c0000644000175000001440000005612312137151331013504 00000000000000/*************************************************************************** * Copyright (C) 2009 by David Brownell * * * * Copyright (C) ST-Ericsson SA 2011 michel.jaouen@stericsson.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "armv7a.h" #include "arm_disassembler.h" #include "register.h" #include #include #include #include #include #include "arm_opcodes.h" #include "target.h" #include "target_type.h" static void armv7a_show_fault_registers(struct target *target) { uint32_t dfsr, ifsr, dfar, ifar; struct armv7a_common *armv7a = target_to_armv7a(target); struct arm_dpm *dpm = armv7a->arm.dpm; int retval; retval = dpm->prepare(dpm); if (retval != ERROR_OK) return; /* ARMV4_5_MRC(cpnum, op1, r0, CRn, CRm, op2) */ /* c5/c0 - {data, instruction} fault status registers */ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 0, 0, 5, 0, 0), &dfsr); if (retval != ERROR_OK) goto done; retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 0, 0, 5, 0, 1), &ifsr); if (retval != ERROR_OK) goto done; /* c6/c0 - {data, instruction} fault address registers */ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 0, 0, 6, 0, 0), &dfar); if (retval != ERROR_OK) goto done; retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 0, 0, 6, 0, 2), &ifar); if (retval != ERROR_OK) goto done; LOG_USER("Data fault registers DFSR: %8.8" PRIx32 ", DFAR: %8.8" PRIx32, dfsr, dfar); LOG_USER("Instruction fault registers IFSR: %8.8" PRIx32 ", IFAR: %8.8" PRIx32, ifsr, ifar); done: /* (void) */ dpm->finish(dpm); } static int armv7a_read_ttbcr(struct target *target) { struct armv7a_common *armv7a = target_to_armv7a(target); struct arm_dpm *dpm = armv7a->arm.dpm; uint32_t ttbcr; int retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; /* MRC p15,0,,c2,c0,2 ; Read CP15 Translation Table Base Control Register*/ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 0, 0, 2, 0, 2), &ttbcr); if (retval != ERROR_OK) goto done; armv7a->armv7a_mmu.ttbr1_used = ((ttbcr & 0x7) != 0) ? 1 : 0; armv7a->armv7a_mmu.ttbr0_mask = 7 << (32 - ((ttbcr & 0x7))); #if 0 LOG_INFO("ttb1 %s ,ttb0_mask %x", armv7a->armv7a_mmu.ttbr1_used ? "used" : "not used", armv7a->armv7a_mmu.ttbr0_mask); #endif if (armv7a->armv7a_mmu.ttbr1_used == 1) { LOG_INFO("SVC access above %x", (0xffffffff & armv7a->armv7a_mmu.ttbr0_mask)); armv7a->armv7a_mmu.os_border = 0xffffffff & armv7a->armv7a_mmu.ttbr0_mask; } else { /* fix me , default is hard coded LINUX border */ armv7a->armv7a_mmu.os_border = 0xc0000000; } done: dpm->finish(dpm); return retval; } /* method adapted to cortex A : reused arm v4 v5 method*/ int armv7a_mmu_translate_va(struct target *target, uint32_t va, uint32_t *val) { uint32_t first_lvl_descriptor = 0x0; uint32_t second_lvl_descriptor = 0x0; int retval; struct armv7a_common *armv7a = target_to_armv7a(target); struct arm_dpm *dpm = armv7a->arm.dpm; uint32_t ttb = 0; /* default ttb0 */ if (armv7a->armv7a_mmu.ttbr1_used == -1) armv7a_read_ttbcr(target); if ((armv7a->armv7a_mmu.ttbr1_used) && (va > (0xffffffff & armv7a->armv7a_mmu.ttbr0_mask))) { /* select ttb 1 */ ttb = 1; } retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; /* MRC p15,0,,c2,c0,ttb */ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 0, 0, 2, 0, ttb), &ttb); if (retval != ERROR_OK) return retval; retval = armv7a->armv7a_mmu.read_physical_memory(target, (ttb & 0xffffc000) | ((va & 0xfff00000) >> 18), 4, 1, (uint8_t *)&first_lvl_descriptor); if (retval != ERROR_OK) return retval; first_lvl_descriptor = target_buffer_get_u32(target, (uint8_t *) &first_lvl_descriptor); /* reuse armv4_5 piece of code, specific armv7a changes may come later */ LOG_DEBUG("1st lvl desc: %8.8" PRIx32 "", first_lvl_descriptor); if ((first_lvl_descriptor & 0x3) == 0) { LOG_ERROR("Address translation failure"); return ERROR_TARGET_TRANSLATION_FAULT; } if ((first_lvl_descriptor & 0x3) == 2) { /* section descriptor */ *val = (first_lvl_descriptor & 0xfff00000) | (va & 0x000fffff); return ERROR_OK; } if ((first_lvl_descriptor & 0x3) == 1) { /* coarse page table */ retval = armv7a->armv7a_mmu.read_physical_memory(target, (first_lvl_descriptor & 0xfffffc00) | ((va & 0x000ff000) >> 10), 4, 1, (uint8_t *)&second_lvl_descriptor); if (retval != ERROR_OK) return retval; } else if ((first_lvl_descriptor & 0x3) == 3) { /* fine page table */ retval = armv7a->armv7a_mmu.read_physical_memory(target, (first_lvl_descriptor & 0xfffff000) | ((va & 0x000ffc00) >> 8), 4, 1, (uint8_t *)&second_lvl_descriptor); if (retval != ERROR_OK) return retval; } second_lvl_descriptor = target_buffer_get_u32(target, (uint8_t *) &second_lvl_descriptor); LOG_DEBUG("2nd lvl desc: %8.8" PRIx32 "", second_lvl_descriptor); if ((second_lvl_descriptor & 0x3) == 0) { LOG_ERROR("Address translation failure"); return ERROR_TARGET_TRANSLATION_FAULT; } if ((second_lvl_descriptor & 0x3) == 1) { /* large page descriptor */ *val = (second_lvl_descriptor & 0xffff0000) | (va & 0x0000ffff); return ERROR_OK; } if ((second_lvl_descriptor & 0x3) == 2) { /* small page descriptor */ *val = (second_lvl_descriptor & 0xfffff000) | (va & 0x00000fff); return ERROR_OK; } if ((second_lvl_descriptor & 0x3) == 3) { *val = (second_lvl_descriptor & 0xfffffc00) | (va & 0x000003ff); return ERROR_OK; } /* should not happen */ LOG_ERROR("Address translation failure"); return ERROR_TARGET_TRANSLATION_FAULT; done: return retval; } /* V7 method VA TO PA */ int armv7a_mmu_translate_va_pa(struct target *target, uint32_t va, uint32_t *val, int meminfo) { int retval = ERROR_FAIL; struct armv7a_common *armv7a = target_to_armv7a(target); struct arm_dpm *dpm = armv7a->arm.dpm; uint32_t virt = va & ~0xfff; uint32_t NOS, NS, INNER, OUTER; *val = 0xdeadbeef; retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; /* mmu must be enable in order to get a correct translation * use VA to PA CP15 register for conversion */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 7, 8, 0), virt); if (retval != ERROR_OK) goto done; retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 0, 0, 7, 4, 0), val); /* decode memory attribute */ NOS = (*val >> 10) & 1; /* Not Outer shareable */ NS = (*val >> 9) & 1; /* Non secure */ INNER = (*val >> 4) & 0x7; OUTER = (*val >> 2) & 0x3; if (retval != ERROR_OK) goto done; *val = (*val & ~0xfff) + (va & 0xfff); if (*val == va) LOG_WARNING("virt = phys : MMU disable !!"); if (meminfo) { LOG_INFO("%x : %x %s outer shareable %s secured", va, *val, NOS == 1 ? "not" : " ", NS == 1 ? "not" : ""); switch (OUTER) { case 0: LOG_INFO("outer: Non-Cacheable"); break; case 1: LOG_INFO("outer: Write-Back, Write-Allocate"); break; case 2: LOG_INFO("outer: Write-Through, No Write-Allocate"); break; case 3: LOG_INFO("outer: Write-Back, no Write-Allocate"); break; } switch (INNER) { case 0: LOG_INFO("inner: Non-Cacheable"); break; case 1: LOG_INFO("inner: Strongly-ordered"); break; case 3: LOG_INFO("inner: Device"); break; case 5: LOG_INFO("inner: Write-Back, Write-Allocate"); break; case 6: LOG_INFO("inner: Write-Through"); break; case 7: LOG_INFO("inner: Write-Back, no Write-Allocate"); default: LOG_INFO("inner: %x ???", INNER); } } done: dpm->finish(dpm); return retval; } static int armv7a_handle_inner_cache_info_command(struct command_context *cmd_ctx, struct armv7a_cache_common *armv7a_cache) { if (armv7a_cache->ctype == -1) { command_print(cmd_ctx, "cache not yet identified"); return ERROR_OK; } command_print(cmd_ctx, "D-Cache: linelen %i, associativity %i, nsets %i, cachesize %d KBytes", armv7a_cache->d_u_size.linelen, armv7a_cache->d_u_size.associativity, armv7a_cache->d_u_size.nsets, armv7a_cache->d_u_size.cachesize); command_print(cmd_ctx, "I-Cache: linelen %i, associativity %i, nsets %i, cachesize %d KBytes", armv7a_cache->i_size.linelen, armv7a_cache->i_size.associativity, armv7a_cache->i_size.nsets, armv7a_cache->i_size.cachesize); return ERROR_OK; } static int _armv7a_flush_all_data(struct target *target) { struct armv7a_common *armv7a = target_to_armv7a(target); struct arm_dpm *dpm = armv7a->arm.dpm; struct armv7a_cachesize *d_u_size = &(armv7a->armv7a_mmu.armv7a_cache.d_u_size); int32_t c_way, c_index = d_u_size->index; int retval; /* check that cache data is on at target halt */ if (!armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled) { LOG_INFO("flushed not performed :cache not on at target halt"); return ERROR_OK; } retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; do { c_way = d_u_size->way; do { uint32_t value = (c_index << d_u_size->index_shift) | (c_way << d_u_size->way_shift); /* DCCISW */ /* LOG_INFO ("%d %d %x",c_way,c_index,value); */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 7, 14, 2), value); if (retval != ERROR_OK) goto done; c_way -= 1; } while (c_way >= 0); c_index -= 1; } while (c_index >= 0); return retval; done: LOG_ERROR("flushed failed"); dpm->finish(dpm); return retval; } static int armv7a_flush_all_data(struct target *target) { int retval = ERROR_FAIL; /* check that armv7a_cache is correctly identify */ struct armv7a_common *armv7a = target_to_armv7a(target); if (armv7a->armv7a_mmu.armv7a_cache.ctype == -1) { LOG_ERROR("trying to flush un-identified cache"); return retval; } if (target->smp) { /* look if all the other target have been flushed in order to flush level * 2 */ struct target_list *head; struct target *curr; head = target->head; while (head != (struct target_list *)NULL) { curr = head->target; if (curr->state == TARGET_HALTED) { LOG_INFO("Wait flushing data l1 on core %d", curr->coreid); retval = _armv7a_flush_all_data(curr); } head = head->next; } } else retval = _armv7a_flush_all_data(target); return retval; } /* L2 is not specific to armv7a a specific file is needed */ static int armv7a_l2x_flush_all_data(struct target *target) { #define L2X0_CLEAN_INV_WAY 0x7FC int retval = ERROR_FAIL; struct armv7a_common *armv7a = target_to_armv7a(target); struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *) (armv7a->armv7a_mmu.armv7a_cache.l2_cache); uint32_t base = l2x_cache->base; uint32_t l2_way = l2x_cache->way; uint32_t l2_way_val = (1 << l2_way) - 1; retval = armv7a_flush_all_data(target); if (retval != ERROR_OK) return retval; retval = target->type->write_phys_memory(target, (uint32_t)(base+(uint32_t)L2X0_CLEAN_INV_WAY), (uint32_t)4, (uint32_t)1, (uint8_t *)&l2_way_val); return retval; } static int armv7a_handle_l2x_cache_info_command(struct command_context *cmd_ctx, struct armv7a_cache_common *armv7a_cache) { struct armv7a_l2x_cache *l2x_cache = (struct armv7a_l2x_cache *) (armv7a_cache->l2_cache); if (armv7a_cache->ctype == -1) { command_print(cmd_ctx, "cache not yet identified"); return ERROR_OK; } command_print(cmd_ctx, "L1 D-Cache: linelen %i, associativity %i, nsets %i, cachesize %d KBytes", armv7a_cache->d_u_size.linelen, armv7a_cache->d_u_size.associativity, armv7a_cache->d_u_size.nsets, armv7a_cache->d_u_size.cachesize); command_print(cmd_ctx, "L1 I-Cache: linelen %i, associativity %i, nsets %i, cachesize %d KBytes", armv7a_cache->i_size.linelen, armv7a_cache->i_size.associativity, armv7a_cache->i_size.nsets, armv7a_cache->i_size.cachesize); command_print(cmd_ctx, "L2 unified cache Base Address 0x%x, %d ways", l2x_cache->base, l2x_cache->way); return ERROR_OK; } static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t way) { struct armv7a_l2x_cache *l2x_cache; struct target_list *head = target->head; struct target *curr; struct armv7a_common *armv7a = target_to_armv7a(target); l2x_cache = calloc(1, sizeof(struct armv7a_l2x_cache)); l2x_cache->base = base; l2x_cache->way = way; /*LOG_INFO("cache l2 initialized base %x way %d", l2x_cache->base,l2x_cache->way);*/ if (armv7a->armv7a_mmu.armv7a_cache.l2_cache) LOG_INFO("cache l2 already initialized\n"); armv7a->armv7a_mmu.armv7a_cache.l2_cache = (void *) l2x_cache; /* initialize l1 / l2x cache function */ armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache = armv7a_l2x_flush_all_data; armv7a->armv7a_mmu.armv7a_cache.display_cache_info = armv7a_handle_l2x_cache_info_command; /* initialize all target in this cluster (smp target) * l2 cache must be configured after smp declaration */ while (head != (struct target_list *)NULL) { curr = head->target; if (curr != target) { armv7a = target_to_armv7a(curr); if (armv7a->armv7a_mmu.armv7a_cache.l2_cache) LOG_ERROR("smp target : cache l2 already initialized\n"); armv7a->armv7a_mmu.armv7a_cache.l2_cache = (void *) l2x_cache; armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache = armv7a_l2x_flush_all_data; armv7a->armv7a_mmu.armv7a_cache.display_cache_info = armv7a_handle_l2x_cache_info_command; } head = head->next; } return JIM_OK; } COMMAND_HANDLER(handle_cache_l2x) { struct target *target = get_current_target(CMD_CTX); uint32_t base, way; switch (CMD_ARGC) { case 0: return ERROR_COMMAND_SYNTAX_ERROR; break; case 2: /* command_print(CMD_CTX, "%s %s", CMD_ARGV[0], CMD_ARGV[1]); */ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], base); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], way); /* AP address is in bits 31:24 of DP_SELECT */ armv7a_l2x_cache_init(target, base, way); break; default: return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; } int armv7a_handle_cache_info_command(struct command_context *cmd_ctx, struct armv7a_cache_common *armv7a_cache) { if (armv7a_cache->ctype == -1) { command_print(cmd_ctx, "cache not yet identified"); return ERROR_OK; } if (armv7a_cache->display_cache_info) armv7a_cache->display_cache_info(cmd_ctx, armv7a_cache); return ERROR_OK; } /* retrieve core id cluster id */ static int armv7a_read_mpidr(struct target *target) { int retval = ERROR_FAIL; struct armv7a_common *armv7a = target_to_armv7a(target); struct arm_dpm *dpm = armv7a->arm.dpm; uint32_t mpidr; retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; /* MRC p15,0,,c0,c0,5; read Multiprocessor ID register*/ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 0, 0, 0, 0, 5), &mpidr); if (retval != ERROR_OK) goto done; if (mpidr & 1<<31) { armv7a->multi_processor_system = (mpidr >> 30) & 1; armv7a->cluster_id = (mpidr >> 8) & 0xf; armv7a->cpu_id = mpidr & 0x3; LOG_INFO("%s cluster %x core %x %s", target_name(target), armv7a->cluster_id, armv7a->cpu_id, armv7a->multi_processor_system == 0 ? "multi core" : "mono core"); } else LOG_ERROR("mpdir not in multiprocessor format"); done: dpm->finish(dpm); return retval; } int armv7a_identify_cache(struct target *target) { /* read cache descriptor */ int retval = ERROR_FAIL; struct armv7a_common *armv7a = target_to_armv7a(target); struct arm_dpm *dpm = armv7a->arm.dpm; uint32_t cache_selected, clidr; uint32_t cache_i_reg, cache_d_reg; struct armv7a_cache_common *cache = &(armv7a->armv7a_mmu.armv7a_cache); if (!armv7a->is_armv7r) armv7a_read_ttbcr(target); retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; /* retrieve CLIDR * mrc p15, 1, r0, c0, c0, 1 @ read clidr */ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 1, 0, 0, 0, 1), &clidr); if (retval != ERROR_OK) goto done; clidr = (clidr & 0x7000000) >> 23; LOG_INFO("number of cache level %d", clidr / 2); if ((clidr / 2) > 1) { /* FIXME not supported present in cortex A8 and later */ /* in cortex A7, A15 */ LOG_ERROR("cache l2 present :not supported"); } /* retrieve selected cache * MRC p15, 2,, c0, c0, 0; Read CSSELR */ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 2, 0, 0, 0, 0), &cache_selected); if (retval != ERROR_OK) goto done; retval = armv7a->arm.mrc(target, 15, 2, 0, /* op1, op2 */ 0, 0, /* CRn, CRm */ &cache_selected); if (retval != ERROR_OK) goto done; /* select instruction cache * MCR p15, 2,, c0, c0, 0; Write CSSELR * [0] : 1 instruction cache selection , 0 data cache selection */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MRC(15, 2, 0, 0, 0, 0), 1); if (retval != ERROR_OK) goto done; /* read CCSIDR * MRC P15,1,,C0, C0,0 ;on cortex A9 read CCSIDR * [2:0] line size 001 eight word per line * [27:13] NumSet 0x7f 16KB, 0xff 32Kbytes, 0x1ff 64Kbytes */ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 1, 0, 0, 0, 0), &cache_i_reg); if (retval != ERROR_OK) goto done; /* select data cache*/ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MRC(15, 2, 0, 0, 0, 0), 0); if (retval != ERROR_OK) goto done; retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 1, 0, 0, 0, 0), &cache_d_reg); if (retval != ERROR_OK) goto done; /* restore selected cache */ dpm->instr_write_data_r0(dpm, ARMV4_5_MRC(15, 2, 0, 0, 0, 0), cache_selected); if (retval != ERROR_OK) goto done; dpm->finish(dpm); /* put fake type */ cache->d_u_size.linelen = 16 << (cache_d_reg & 0x7); cache->d_u_size.cachesize = (((cache_d_reg >> 13) & 0x7fff)+1)/8; cache->d_u_size.nsets = (cache_d_reg >> 13) & 0x7fff; cache->d_u_size.associativity = ((cache_d_reg >> 3) & 0x3ff) + 1; /* compute info for set way operation on cache */ cache->d_u_size.index_shift = (cache_d_reg & 0x7) + 4; cache->d_u_size.index = (cache_d_reg >> 13) & 0x7fff; cache->d_u_size.way = ((cache_d_reg >> 3) & 0x3ff); cache->d_u_size.way_shift = cache->d_u_size.way + 1; { int i = 0; while (((cache->d_u_size.way_shift >> i) & 1) != 1) i++; cache->d_u_size.way_shift = 32-i; } #if 0 LOG_INFO("data cache index %d << %d, way %d << %d", cache->d_u_size.index, cache->d_u_size.index_shift, cache->d_u_size.way, cache->d_u_size.way_shift); LOG_INFO("data cache %d bytes %d KBytes asso %d ways", cache->d_u_size.linelen, cache->d_u_size.cachesize, cache->d_u_size.associativity); #endif cache->i_size.linelen = 16 << (cache_i_reg & 0x7); cache->i_size.associativity = ((cache_i_reg >> 3) & 0x3ff) + 1; cache->i_size.nsets = (cache_i_reg >> 13) & 0x7fff; cache->i_size.cachesize = (((cache_i_reg >> 13) & 0x7fff)+1)/8; /* compute info for set way operation on cache */ cache->i_size.index_shift = (cache_i_reg & 0x7) + 4; cache->i_size.index = (cache_i_reg >> 13) & 0x7fff; cache->i_size.way = ((cache_i_reg >> 3) & 0x3ff); cache->i_size.way_shift = cache->i_size.way + 1; { int i = 0; while (((cache->i_size.way_shift >> i) & 1) != 1) i++; cache->i_size.way_shift = 32-i; } #if 0 LOG_INFO("instruction cache index %d << %d, way %d << %d", cache->i_size.index, cache->i_size.index_shift, cache->i_size.way, cache->i_size.way_shift); LOG_INFO("instruction cache %d bytes %d KBytes asso %d ways", cache->i_size.linelen, cache->i_size.cachesize, cache->i_size.associativity); #endif /* if no l2 cache initialize l1 data cache flush function function */ if (armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache == NULL) { armv7a->armv7a_mmu.armv7a_cache.display_cache_info = armv7a_handle_inner_cache_info_command; armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache = armv7a_flush_all_data; } armv7a->armv7a_mmu.armv7a_cache.ctype = 0; done: dpm->finish(dpm); armv7a_read_mpidr(target); return retval; } int armv7a_init_arch_info(struct target *target, struct armv7a_common *armv7a) { struct arm *arm = &armv7a->arm; arm->arch_info = armv7a; target->arch_info = &armv7a->arm; /* target is useful in all function arm v4 5 compatible */ armv7a->arm.target = target; armv7a->arm.common_magic = ARM_COMMON_MAGIC; armv7a->common_magic = ARMV7_COMMON_MAGIC; armv7a->armv7a_mmu.armv7a_cache.l2_cache = NULL; armv7a->armv7a_mmu.armv7a_cache.ctype = -1; armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache = NULL; armv7a->armv7a_mmu.armv7a_cache.display_cache_info = NULL; return ERROR_OK; } int armv7a_arch_state(struct target *target) { static const char *state[] = { "disabled", "enabled" }; struct armv7a_common *armv7a = target_to_armv7a(target); struct arm *arm = &armv7a->arm; if (armv7a->common_magic != ARMV7_COMMON_MAGIC) { LOG_ERROR("BUG: called for a non-ARMv7A target"); return ERROR_COMMAND_SYNTAX_ERROR; } arm_arch_state(target); if (armv7a->is_armv7r) { LOG_USER("D-Cache: %s, I-Cache: %s", state[armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled], state[armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled]); } else { LOG_USER("MMU: %s, D-Cache: %s, I-Cache: %s", state[armv7a->armv7a_mmu.mmu_enabled], state[armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled], state[armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled]); } if (arm->core_mode == ARM_MODE_ABT) armv7a_show_fault_registers(target); if (target->debug_reason == DBG_REASON_WATCHPOINT) LOG_USER("Watchpoint triggered at PC %#08x", (unsigned) armv7a->dpm.wp_pc); return ERROR_OK; } static const struct command_registration l2_cache_commands[] = { { .name = "l2x", .handler = handle_cache_l2x, .mode = COMMAND_EXEC, .help = "configure l2x cache " "", .usage = "[base_addr] [number_of_way]", }, COMMAND_REGISTRATION_DONE }; const struct command_registration l2x_cache_command_handlers[] = { { .name = "cache_config", .mode = COMMAND_EXEC, .help = "cache configuation for a target", .usage = "", .chain = l2_cache_commands, }, COMMAND_REGISTRATION_DONE }; const struct command_registration armv7a_command_handlers[] = { { .chain = dap_command_handlers, }, { .chain = l2x_cache_command_handlers, }, COMMAND_REGISTRATION_DONE }; openocd-0.7.0/src/target/arm946e.h0000644000175000001440000000507112134336410013477 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2010 by Drasko DRASKOVIC * * drasko.draskovic@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef ARM946E_H #define ARM946E_H #include "arm9tdmi.h" #define ARM946E_COMMON_MAGIC 0x20f920f9 struct arm946e_common { struct arm7_9_common arm7_9_common; int common_magic; uint32_t cp15_control_reg; uint32_t cp15_cache_info; }; static inline struct arm946e_common *target_to_arm946(struct target *target) { return container_of(target->arch_info, struct arm946e_common, arm7_9_common.arm); } int arm946e_init_arch_info(struct target *target, struct arm946e_common *arm946e, struct jtag_tap *tap); int arm946e_write_cp15(struct target *target, int reg_addr, uint32_t value); extern const struct command_registration arm946e_command_handlers[]; #endif /* ARM946E_H */ openocd-0.7.0/src/target/avr32_mem.c0000644000175000001440000001671212134336410014102 00000000000000/*************************************************************************** * Copyright (C) 2010 by Oleksandr Tymoshenko * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "target.h" #include "jtag/jtag.h" #include "avr32_jtag.h" #include "avr32_mem.h" int avr32_jtag_read_memory32(struct avr32_jtag *jtag_info, uint32_t addr, int count, uint32_t *buffer) { int i, retval; uint32_t data; for (i = 0; i < count; i++) { retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED, addr + i*4, &data); if (retval != ERROR_OK) return retval; /* XXX: Assume AVR32 is BE */ buffer[i] = be_to_h_u32((uint8_t *)&data); } return ERROR_OK; } int avr32_jtag_read_memory16(struct avr32_jtag *jtag_info, uint32_t addr, int count, uint16_t *buffer) { int i, retval; uint32_t data; i = 0; /* any unaligned half-words? */ if (addr & 3) { retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED, addr + i*2, &data); if (retval != ERROR_OK) return retval; /* XXX: Assume AVR32 is BE */ data = be_to_h_u32((uint8_t *)&data); buffer[i] = (data >> 16) & 0xffff; i++; } /* read all complete words */ for (; i < (count & ~1); i += 2) { retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED, addr + i*2, &data); if (retval != ERROR_OK) return retval; /* XXX: Assume AVR32 is BE */ data = be_to_h_u32((uint8_t *)&data); buffer[i] = data & 0xffff; buffer[i+1] = (data >> 16) & 0xffff; } /* last halfword */ if (i < count) { retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED, addr + i*2, &data); if (retval != ERROR_OK) return retval; /* XXX: Assume AVR32 is BE */ data = be_to_h_u32((uint8_t *)&data); buffer[i] = data & 0xffff; } return ERROR_OK; } int avr32_jtag_read_memory8(struct avr32_jtag *jtag_info, uint32_t addr, int count, uint8_t *buffer) { int i, j, retval; uint8_t data[4]; i = 0; /* Do we have non-aligned bytes? */ if (addr & 3) { retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED, addr + i, (uint32_t *)(void *)data); if (retval != ERROR_OK) return retval; for (j = addr & 3; (j < 4) && (i < count); j++, i++) buffer[i] = data[3-j]; } /* read all complete words */ for (; i < (count & ~3); i += 4) { retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED, addr + i, (uint32_t *)(void *)data); if (retval != ERROR_OK) return retval; for (j = 0; j < 4; j++) buffer[i+j] = data[3-j]; } /* remaining bytes */ if (i < count) { retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED, addr + i, (uint32_t *)(void *)data); if (retval != ERROR_OK) return retval; for (j = 0; i + j < count; j++) buffer[i+j] = data[3-j]; } return ERROR_OK; } int avr32_jtag_write_memory32(struct avr32_jtag *jtag_info, uint32_t addr, int count, const uint32_t *buffer) { int i, retval; uint32_t data; for (i = 0; i < count; i++) { /* XXX: Assume AVR32 is BE */ h_u32_to_be((uint8_t *)&data, buffer[i]); retval = avr32_jtag_mwa_write(jtag_info, SLAVE_HSB_UNCACHED, addr + i*4, data); if (retval != ERROR_OK) return retval; } return ERROR_OK; } int avr32_jtag_write_memory16(struct avr32_jtag *jtag_info, uint32_t addr, int count, const uint16_t *buffer) { int i, retval; uint32_t data; uint32_t data_out; i = 0; /* * Do we have any non-aligned half-words? */ if (addr & 3) { /* * mwa_read will read whole world, no nead to fiddle * with address. It will be truncated in set_addr */ retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED, addr, &data); if (retval != ERROR_OK) return retval; data = be_to_h_u32((uint8_t *)&data); data = (buffer[i] << 16) | (data & 0xffff); h_u32_to_be((uint8_t *)&data_out, data); retval = avr32_jtag_mwa_write(jtag_info, SLAVE_HSB_UNCACHED, addr, data_out); if (retval != ERROR_OK) return retval; i++; } /* write all complete words */ for (; i < (count & ~1); i += 2) { /* XXX: Assume AVR32 is BE */ data = (buffer[i+1] << 16) | buffer[i]; h_u32_to_be((uint8_t *)&data_out, data); retval = avr32_jtag_mwa_write(jtag_info, SLAVE_HSB_UNCACHED, addr + i*2, data_out); if (retval != ERROR_OK) return retval; } /* last halfword */ if (i < count) { retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED, addr + i*2, &data); if (retval != ERROR_OK) return retval; data = be_to_h_u32((uint8_t *)&data); data &= ~0xffff; data |= buffer[i]; h_u32_to_be((uint8_t *)&data_out, data); retval = avr32_jtag_mwa_write(jtag_info, SLAVE_HSB_UNCACHED, addr + i*2, data_out); if (retval != ERROR_OK) return retval; } return ERROR_OK; } int avr32_jtag_write_memory8(struct avr32_jtag *jtag_info, uint32_t addr, int count, const uint8_t *buffer) { int i, j, retval; uint32_t data; uint32_t data_out; i = 0; /* * Do we have any non-aligned bytes? */ if (addr & 3) { /* * mwa_read will read whole world, no nead to fiddle * with address. It will be truncated in set_addr */ retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED, addr, &data); if (retval != ERROR_OK) return retval; data = be_to_h_u32((uint8_t *)&data); for (j = addr & 3; (j < 4) && (i < count); j++, i++) { data &= ~(0xff << j*8); data |= (buffer[i] << j*8); } h_u32_to_be((uint8_t *)&data_out, data); retval = avr32_jtag_mwa_write(jtag_info, SLAVE_HSB_UNCACHED, addr, data_out); if (retval != ERROR_OK) return retval; } /* write all complete words */ for (; i < (count & ~3); i += 4) { data = 0; for (j = 0; j < 4; j++) data |= (buffer[j+i] << j*8); h_u32_to_be((uint8_t *)&data_out, data); retval = avr32_jtag_mwa_write(jtag_info, SLAVE_HSB_UNCACHED, addr + i, data_out); if (retval != ERROR_OK) return retval; } /* * Write trailing bytes */ if (i < count) { retval = avr32_jtag_mwa_read(jtag_info, SLAVE_HSB_UNCACHED, addr + i, &data); if (retval != ERROR_OK) return retval; data = be_to_h_u32((uint8_t *)&data); for (j = 0; i < count; j++, i++) { data &= ~(0xff << j*8); data |= (buffer[j+i] << j*8); } h_u32_to_be((uint8_t *)&data_out, data); retval = avr32_jtag_mwa_write(jtag_info, SLAVE_HSB_UNCACHED, addr+i, data_out); if (retval != ERROR_OK) return retval; } return ERROR_OK; } openocd-0.7.0/src/target/arm_simulator.h0000644000175000001440000000430612134336410015166 00000000000000/*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef ARM_SIMULATOR_H #define ARM_SIMULATOR_H struct target; struct arm_sim_interface { void *user_data; uint32_t (*get_reg)(struct arm_sim_interface *sim, int reg); void (*set_reg)(struct arm_sim_interface *sim, int reg, uint32_t value); uint32_t (*get_reg_mode)(struct arm_sim_interface *sim, int reg); void (*set_reg_mode)(struct arm_sim_interface *sim, int reg, uint32_t value); uint32_t (*get_cpsr)(struct arm_sim_interface *sim, int pos, int bits); enum arm_state (*get_state)(struct arm_sim_interface *sim); void (*set_state)(struct arm_sim_interface *sim, enum arm_state mode); enum arm_mode (*get_mode)(struct arm_sim_interface *sim); }; /* armv4_5 version */ int arm_simulate_step(struct target *target, uint32_t *dry_run_pc); #endif /* ARM_SIMULATOR_H */ openocd-0.7.0/src/target/oocd_trace.c0000644000175000001440000003023612134336410014406 00000000000000/*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm.h" #include "etm.h" #include "oocd_trace.h" /* * This is "proof of concept" code, for prototype hardware: * https://lists.berlios.de/pipermail/openocd-development/2007-September/000336.html */ static int oocd_trace_read_reg(struct oocd_trace *oocd_trace, int reg, uint32_t *value) { size_t bytes_written, bytes_read, bytes_to_read; uint8_t cmd; cmd = 0x10 | (reg & 0x7); bytes_written = write(oocd_trace->tty_fd, &cmd, 1); bytes_to_read = 4; while (bytes_to_read > 0) { bytes_read = read(oocd_trace->tty_fd, ((uint8_t *)value) + 4 - bytes_to_read, bytes_to_read); bytes_to_read -= bytes_read; } LOG_DEBUG("reg #%i: 0x%8.8x", reg, *value); return ERROR_OK; } static int oocd_trace_write_reg(struct oocd_trace *oocd_trace, int reg, uint32_t value) { size_t bytes_written; uint8_t data[5]; data[0] = 0x18 | (reg & 0x7); data[1] = value & 0xff; data[2] = (value & 0xff00) >> 8; data[3] = (value & 0xff0000) >> 16; data[4] = (value & 0xff000000) >> 24; bytes_written = write(oocd_trace->tty_fd, data, 5); LOG_DEBUG("reg #%i: 0x%8.8x", reg, value); return ERROR_OK; } static int oocd_trace_read_memory(struct oocd_trace *oocd_trace, uint8_t *data, uint32_t address, uint32_t size) { size_t bytes_written, bytes_to_read; ssize_t bytes_read; uint8_t cmd; oocd_trace_write_reg(oocd_trace, OOCD_TRACE_ADDRESS, address); oocd_trace_write_reg(oocd_trace, OOCD_TRACE_SDRAM_COUNTER, size); cmd = 0x20; bytes_written = write(oocd_trace->tty_fd, &cmd, 1); bytes_to_read = size * 16; while (bytes_to_read > 0) { bytes_read = read(oocd_trace->tty_fd, ((uint8_t *)data) + (size * 16) - bytes_to_read, bytes_to_read); if (bytes_read < 0) LOG_DEBUG("read() returned %zi (%s)", bytes_read, strerror(errno)); else bytes_to_read -= bytes_read; } return ERROR_OK; } static int oocd_trace_init(struct etm_context *etm_ctx) { uint8_t trash[256]; struct oocd_trace *oocd_trace = etm_ctx->capture_driver_priv; size_t bytes_read; oocd_trace->tty_fd = open(oocd_trace->tty, O_RDWR | O_NOCTTY | O_NONBLOCK); if (oocd_trace->tty_fd < 0) { LOG_ERROR("can't open tty"); return ERROR_ETM_CAPTURE_INIT_FAILED; } /* clear input & output buffers, then switch to "blocking mode" */ tcflush(oocd_trace->tty_fd, TCOFLUSH); tcflush(oocd_trace->tty_fd, TCIFLUSH); fcntl(oocd_trace->tty_fd, F_SETFL, fcntl(oocd_trace->tty_fd, F_GETFL) & ~O_NONBLOCK); tcgetattr(oocd_trace->tty_fd, &oocd_trace->oldtio); /* save current port settings */ bzero(&oocd_trace->newtio, sizeof(oocd_trace->newtio)); oocd_trace->newtio.c_cflag = CS8 | CLOCAL | CREAD | B2500000; oocd_trace->newtio.c_iflag = IGNPAR | IGNBRK | IXON | IXOFF; oocd_trace->newtio.c_oflag = 0; /* set input mode (non-canonical, no echo,...) */ oocd_trace->newtio.c_lflag = 0; cfmakeraw(&oocd_trace->newtio); oocd_trace->newtio.c_cc[VTIME] = 1; /* inter-character timer used */ oocd_trace->newtio.c_cc[VMIN] = 0; /* blocking read until 0 chars received */ tcflush(oocd_trace->tty_fd, TCIFLUSH); tcsetattr(oocd_trace->tty_fd, TCSANOW, &oocd_trace->newtio); /* occasionally one bogus character is left in the input buffer * read up any leftover characters to ensure communication is in sync */ do { bytes_read = read(oocd_trace->tty_fd, trash, sizeof(trash)); if (bytes_read) LOG_DEBUG("%zi bytes read", bytes_read); } while (bytes_read > 0); return ERROR_OK; } static trace_status_t oocd_trace_status(struct etm_context *etm_ctx) { struct oocd_trace *oocd_trace = etm_ctx->capture_driver_priv; uint32_t status; oocd_trace_read_reg(oocd_trace, OOCD_TRACE_STATUS, &status); /* if tracing is currently idle, return this information */ if (etm_ctx->capture_status == TRACE_IDLE) return etm_ctx->capture_status; else if (etm_ctx->capture_status & TRACE_RUNNING) { /* check Full bit to identify an overflow */ if (status & 0x4) etm_ctx->capture_status |= TRACE_OVERFLOWED; /* check Triggered bit to identify trigger condition */ if (status & 0x2) etm_ctx->capture_status |= TRACE_TRIGGERED; if (status & 0x1) { etm_ctx->capture_status &= ~TRACE_RUNNING; etm_ctx->capture_status |= TRACE_COMPLETED; } } return etm_ctx->capture_status; } static int oocd_trace_read_trace(struct etm_context *etm_ctx) { struct oocd_trace *oocd_trace = etm_ctx->capture_driver_priv; uint32_t status, address; uint32_t first_frame = 0x0; uint32_t num_frames = 1048576; uint8_t *trace_data; uint32_t i; oocd_trace_read_reg(oocd_trace, OOCD_TRACE_STATUS, &status); oocd_trace_read_reg(oocd_trace, OOCD_TRACE_ADDRESS, &address); /* check if we overflowed, and adjust first frame of the trace accordingly * if we didn't overflow, read only up to the frame that would be written next, * i.e. don't read invalid entries */ if (status & 0x4) first_frame = address; else num_frames = address; /* read data into temporary array for unpacking * one frame from OpenOCD + trace corresponds to 16 trace cycles */ trace_data = malloc(sizeof(uint8_t) * num_frames * 16); oocd_trace_read_memory(oocd_trace, trace_data, first_frame, num_frames); if (etm_ctx->trace_depth > 0) free(etm_ctx->trace_data); etm_ctx->trace_depth = num_frames * 16; etm_ctx->trace_data = malloc(sizeof(struct etmv1_trace_data) * etm_ctx->trace_depth); for (i = 0; i < num_frames * 16; i++) { etm_ctx->trace_data[i].pipestat = (trace_data[i] & 0x7); etm_ctx->trace_data[i].packet = (trace_data[i] & 0x78) >> 3; etm_ctx->trace_data[i].flags = 0; if ((trace_data[i] & 0x80) >> 7) etm_ctx->trace_data[i].flags |= ETMV1_TRACESYNC_CYCLE; if (etm_ctx->trace_data[i].pipestat == STAT_TR) { etm_ctx->trace_data[i].pipestat = etm_ctx->trace_data[i].packet & 0x7; etm_ctx->trace_data[i].flags |= ETMV1_TRIGGER_CYCLE; } } free(trace_data); return ERROR_OK; } static int oocd_trace_start_capture(struct etm_context *etm_ctx) { struct oocd_trace *oocd_trace = etm_ctx->capture_driver_priv; uint32_t control = 0x1; /* 0x1: enabled */ uint32_t trigger_count; if (((etm_ctx->control & ETM_PORT_MODE_MASK) != ETM_PORT_NORMAL) || ((etm_ctx->control & ETM_PORT_WIDTH_MASK) != ETM_PORT_4BIT)) { LOG_DEBUG("OpenOCD + trace only supports normal 4-bit ETM mode"); return ERROR_ETM_PORTMODE_NOT_SUPPORTED; } if ((etm_ctx->control & ETM_PORT_CLOCK_MASK) == ETM_PORT_HALF_CLOCK) control |= 0x2; /* half rate clock, capture at twice the clock rate */ /* OpenOCD + trace holds up to 16 million samples, * but trigger counts is set in multiples of 16 */ trigger_count = (1048576 * /* trigger_percent */ 50) / 100; /* capturing always starts at address zero */ oocd_trace_write_reg(oocd_trace, OOCD_TRACE_ADDRESS, 0x0); oocd_trace_write_reg(oocd_trace, OOCD_TRACE_TRIGGER_COUNTER, trigger_count); oocd_trace_write_reg(oocd_trace, OOCD_TRACE_CONTROL, control); /* we're starting a new trace, initialize capture status */ etm_ctx->capture_status = TRACE_RUNNING; return ERROR_OK; } static int oocd_trace_stop_capture(struct etm_context *etm_ctx) { struct oocd_trace *oocd_trace = etm_ctx->capture_driver_priv; /* trace stopped, just clear running flag, but preserve others */ etm_ctx->capture_status &= ~TRACE_RUNNING; oocd_trace_write_reg(oocd_trace, OOCD_TRACE_CONTROL, 0x0); return ERROR_OK; } COMMAND_HANDLER(handle_oocd_trace_config_command) { struct target *target; struct arm *arm; if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; target = get_current_target(CMD_CTX); arm = target_to_arm(target); if (!is_arm(arm)) { command_print(CMD_CTX, "current target isn't an ARM"); return ERROR_FAIL; } if (arm->etm) { struct oocd_trace *oocd_trace = malloc(sizeof(struct oocd_trace)); arm->etm->capture_driver_priv = oocd_trace; oocd_trace->etm_ctx = arm->etm; /* copy name of TTY device used to communicate with OpenOCD + trace */ oocd_trace->tty = strndup(CMD_ARGV[1], 256); } else LOG_ERROR("target has no ETM defined, OpenOCD + trace left unconfigured"); return ERROR_OK; } COMMAND_HANDLER(handle_oocd_trace_status_command) { struct target *target; struct arm *arm; struct oocd_trace *oocd_trace; uint32_t status; target = get_current_target(CMD_CTX); arm = target_to_arm(target); if (!is_arm(arm)) { command_print(CMD_CTX, "current target isn't an ARM"); return ERROR_FAIL; } if (!arm->etm) { command_print(CMD_CTX, "current target doesn't have an ETM configured"); return ERROR_FAIL; } if (strcmp(arm->etm->capture_driver->name, "oocd_trace") != 0) { command_print(CMD_CTX, "current target's ETM capture driver isn't 'oocd_trace'"); return ERROR_FAIL; } oocd_trace = (struct oocd_trace *)arm->etm->capture_driver_priv; oocd_trace_read_reg(oocd_trace, OOCD_TRACE_STATUS, &status); if (status & 0x8) command_print(CMD_CTX, "trace clock locked"); else command_print(CMD_CTX, "no trace clock"); return ERROR_OK; } COMMAND_HANDLER(handle_oocd_trace_resync_command) { struct target *target; struct arm *arm; struct oocd_trace *oocd_trace; size_t bytes_written; uint8_t cmd_array[1]; target = get_current_target(CMD_CTX); arm = target_to_arm(target); if (!is_arm(arm)) { command_print(CMD_CTX, "current target isn't an ARM"); return ERROR_FAIL; } if (!arm->etm) { command_print(CMD_CTX, "current target doesn't have an ETM configured"); return ERROR_FAIL; } if (strcmp(arm->etm->capture_driver->name, "oocd_trace") != 0) { command_print(CMD_CTX, "current target's ETM capture driver isn't 'oocd_trace'"); return ERROR_FAIL; } oocd_trace = (struct oocd_trace *)arm->etm->capture_driver_priv; cmd_array[0] = 0xf0; bytes_written = write(oocd_trace->tty_fd, cmd_array, 1); command_print(CMD_CTX, "requesting traceclock resync"); LOG_DEBUG("resyncing traceclk pll"); return ERROR_OK; } static const struct command_registration oocd_trace_all_command_handlers[] = { { .name = "config", .handler = handle_oocd_trace_config_command, .mode = COMMAND_CONFIG, .usage = " ", }, { .name = "status", .handler = handle_oocd_trace_status_command, .mode = COMMAND_EXEC, .usage = "", .help = "display OpenOCD + trace status", }, { .name = "resync", .handler = handle_oocd_trace_resync_command, .mode = COMMAND_EXEC, .usage = "", .help = "resync OpenOCD + trace capture clock", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration oocd_trace_command_handlers[] = { { .name = "oocd_trace", .mode = COMMAND_ANY, .help = "OpenOCD trace capture driver command group", .usage = "", .chain = oocd_trace_all_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct etm_capture_driver oocd_trace_capture_driver = { .name = "oocd_trace", .commands = oocd_trace_command_handlers, .init = oocd_trace_init, .status = oocd_trace_status, .start_capture = oocd_trace_start_capture, .stop_capture = oocd_trace_stop_capture, .read_trace = oocd_trace_read_trace, }; openocd-0.7.0/src/target/fa526.c0000644000175000001440000003365412134336410013136 00000000000000/*************************************************************************** * Copyright (C) 2009 by Paulius Zaleckas * * paulius.zaleckas@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /* * FA526 is very similar to ARM920T with following differences: * * - execution pipeline is 6 steps * - Unified TLB * - has Branch Target Buffer * - does not support reading of I/D cache contents */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm920t.h" #include "target_type.h" #include "arm_opcodes.h" static void fa526_change_to_arm(struct target *target, uint32_t *r0, uint32_t *pc) { LOG_ERROR("%s: there is no Thumb state on FA526", __func__); } static void fa526_read_core_regs(struct target *target, uint32_t mask, uint32_t *core_regs[16]) { int i; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* STMIA r0-15, [r0] at debug speed * register values will start to appear on 4th DCLK */ arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0); /* fetch NOP, STM in DECODE stage */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, STM in SHIFT stage */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, STM in EXECUTE stage (1st cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); for (i = 0; i <= 15; i++) { if (mask & (1 << i)) /* nothing fetched, STM in MEMORY (i'th cycle) */ arm9tdmi_clock_data_in(jtag_info, core_regs[i]); } } static void fa526_read_core_regs_target_buffer(struct target *target, uint32_t mask, void *buffer, int size) { int i; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; int be = (target->endianness == TARGET_BIG_ENDIAN) ? 1 : 0; uint32_t *buf_u32 = buffer; uint16_t *buf_u16 = buffer; uint8_t *buf_u8 = buffer; /* STMIA r0-15, [r0] at debug speed * register values will start to appear on 4th DCLK */ arm9tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0); /* fetch NOP, STM in DECODE stage */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, STM in SHIFT stage */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, STM in EXECUTE stage (1st cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); for (i = 0; i <= 15; i++) { if (mask & (1 << i)) /* nothing fetched, STM in MEMORY (i'th cycle) */ switch (size) { case 4: arm9tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be); break; case 2: arm9tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be); break; case 1: arm9tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be); break; } } } static void fa526_read_xpsr(struct target *target, uint32_t *xpsr, int spsr) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* MRS r0, cpsr */ arm9tdmi_clock_out(jtag_info, ARMV4_5_MRS(0, spsr & 1), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* STR r0, [r15] */ arm9tdmi_clock_out(jtag_info, ARMV4_5_STR(0, 15), 0, NULL, 0); /* fetch NOP, STR in DECODE stage */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, STR in SHIFT stage */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, STR in EXECUTE stage (1st cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* nothing fetched, STR in MEMORY */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, xpsr, 0); } static void fa526_write_xpsr(struct target *target, uint32_t xpsr, int spsr) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; LOG_DEBUG("xpsr: %8.8" PRIx32 ", spsr: %i", xpsr, spsr); /* MSR1 fetched */ arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr & 0xff, 0, 1, spsr), 0, NULL, 0); /* MSR2 fetched, MSR1 in DECODE */ arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff00) >> 8, 0xc, 2, spsr), 0, NULL, 0); /* MSR3 fetched, MSR1 in SHIFT, MSR2 in DECODE */ arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff0000) >> 16, 0x8, 4, spsr), 0, NULL, 0); /* MSR4 fetched, MSR1 in EXECUTE (1), MSR2 in SHIFT, MSR3 in DECODE */ arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff000000) >> 24, 0x4, 8, spsr), 0, NULL, 0); /* nothing fetched, MSR1 in EXECUTE (2) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* nothing fetched, MSR1 in EXECUTE (3) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* nothing fetched, MSR2 in EXECUTE (1), MSR3 in SHIFT, MSR4 in DECODE */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* nothing fetched, MSR2 in EXECUTE (2) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* nothing fetched, MSR2 in EXECUTE (3) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* NOP fetched, MSR3 in EXECUTE (1), MSR4 in SHIFT */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* nothing fetched, MSR3 in EXECUTE (2) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* nothing fetched, MSR3 in EXECUTE (3) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* NOP fetched, MSR4 in EXECUTE (1) */ /* last MSR writes flags, which takes only one cycle */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); } static void fa526_write_xpsr_im8(struct target *target, uint8_t xpsr_im, int rot, int spsr) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; LOG_DEBUG("xpsr_im: %2.2x, rot: %i, spsr: %i", xpsr_im, rot, spsr); /* MSR fetched */ arm9tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr_im, rot, 1, spsr), 0, NULL, 0); /* NOP fetched, MSR in DECODE */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* NOP fetched, MSR in SHIFT */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* NOP fetched, MSR in EXECUTE (1) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* rot == 4 writes flags, which takes only one cycle */ if (rot != 4) { /* nothing fetched, MSR in EXECUTE (2) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* nothing fetched, MSR in EXECUTE (3) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); } } static void fa526_write_core_regs(struct target *target, uint32_t mask, uint32_t core_regs[16]) { int i; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* LDMIA r0-15, [r0] at debug speed * register values will start to appear on 4th DCLK */ arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 0), 0, NULL, 0); /* fetch NOP, LDM in DECODE stage */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, LDM in SHIFT stage */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); for (i = 0; i <= 15; i++) { if (mask & (1 << i)) /* nothing fetched, LDM still in EXECUTE (1 + i cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, core_regs[i], NULL, 0); } arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); } static void fa526_write_pc(struct target *target, uint32_t pc) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* LDMIA r0-15, [r0] at debug speed * register values will start to appear on 4th DCLK */ arm9tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x8000, 0, 0), 0, NULL, 0); /* fetch NOP, LDM in DECODE stage */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, LDM in SHIFT stage */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* nothing fetched, LDM in EXECUTE stage (2nd cycle) (output data) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, pc, NULL, 0); /* nothing fetched, LDM in EXECUTE stage (3rd cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, LDM in EXECUTE stage (4th cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); /* fetch NOP, LDM in EXECUTE stage (5th cycle) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 0); } static void fa526_branch_resume_thumb(struct target *target) { LOG_ERROR("%s: there is no Thumb state on FA526", __func__); } static int fa526_init_arch_info_2(struct target *target, struct arm7_9_common *arm7_9, struct jtag_tap *tap) { /* prepare JTAG information for the new target */ arm7_9->jtag_info.tap = tap; arm7_9->jtag_info.scann_size = 5; /* register arch-specific functions */ arm7_9->examine_debug_reason = arm9tdmi_examine_debug_reason; arm7_9->change_to_arm = fa526_change_to_arm; arm7_9->read_core_regs = fa526_read_core_regs; arm7_9->read_core_regs_target_buffer = fa526_read_core_regs_target_buffer; arm7_9->read_xpsr = fa526_read_xpsr; arm7_9->write_xpsr = fa526_write_xpsr; arm7_9->write_xpsr_im8 = fa526_write_xpsr_im8; arm7_9->write_core_regs = fa526_write_core_regs; arm7_9->load_word_regs = arm9tdmi_load_word_regs; arm7_9->load_hword_reg = arm9tdmi_load_hword_reg; arm7_9->load_byte_reg = arm9tdmi_load_byte_reg; arm7_9->store_word_regs = arm9tdmi_store_word_regs; arm7_9->store_hword_reg = arm9tdmi_store_hword_reg; arm7_9->store_byte_reg = arm9tdmi_store_byte_reg; arm7_9->write_pc = fa526_write_pc; arm7_9->branch_resume = arm9tdmi_branch_resume; arm7_9->branch_resume_thumb = fa526_branch_resume_thumb; arm7_9->enable_single_step = arm9tdmi_enable_single_step; arm7_9->disable_single_step = arm9tdmi_disable_single_step; arm7_9->post_debug_entry = NULL; arm7_9->pre_restore_context = NULL; /* initialize arch-specific breakpoint handling */ arm7_9->arm_bkpt = 0xdeeedeee; arm7_9->thumb_bkpt = 0xdeee; arm7_9->dbgreq_adjust_pc = 3; arm7_9_init_arch_info(target, arm7_9); /* override use of DBGRQ, this is safe on ARM9TDMI */ arm7_9->use_dbgrq = 1; /* all ARM9s have the vector catch register */ arm7_9->has_vector_catch = 1; return ERROR_OK; } static int fa526_init_arch_info(struct target *target, struct arm920t_common *arm920t, struct jtag_tap *tap) { struct arm7_9_common *arm7_9 = &arm920t->arm7_9_common; /* initialize arm7/arm9 specific info (including armv4_5) */ fa526_init_arch_info_2(target, arm7_9, tap); arm920t->common_magic = ARM920T_COMMON_MAGIC; arm7_9->post_debug_entry = arm920t_post_debug_entry; arm7_9->pre_restore_context = arm920t_pre_restore_context; arm920t->armv4_5_mmu.armv4_5_cache.ctype = -1; arm920t->armv4_5_mmu.get_ttb = arm920t_get_ttb; arm920t->armv4_5_mmu.read_memory = arm7_9_read_memory; arm920t->armv4_5_mmu.write_memory = arm7_9_write_memory; arm920t->armv4_5_mmu.disable_mmu_caches = arm920t_disable_mmu_caches; arm920t->armv4_5_mmu.enable_mmu_caches = arm920t_enable_mmu_caches; arm920t->armv4_5_mmu.has_tiny_pages = 1; arm920t->armv4_5_mmu.mmu_enabled = 0; /* disabling linefills leads to lockups, so keep them enabled for now * this doesn't affect correctness, but might affect timing issues, if * important data is evicted from the cache during the debug session * */ arm920t->preserve_cache = 0; /* override hw single-step capability from ARM9TDMI */ arm7_9->has_single_step = 1; return ERROR_OK; } static int fa526_target_create(struct target *target, Jim_Interp *interp) { struct arm920t_common *arm920t = calloc(1, sizeof(struct arm920t_common)); return fa526_init_arch_info(target, arm920t, target->tap); } /** Holds methods for FA526 targets. */ struct target_type fa526_target = { .name = "fa526", .poll = arm7_9_poll, .arch_state = arm920t_arch_state, .target_request_data = arm7_9_target_request_data, .halt = arm7_9_halt, .resume = arm7_9_resume, .step = arm7_9_step, .assert_reset = arm7_9_assert_reset, .deassert_reset = arm7_9_deassert_reset, .soft_reset_halt = arm920t_soft_reset_halt, .get_gdb_reg_list = arm_get_gdb_reg_list, .read_memory = arm920t_read_memory, .write_memory = arm920t_write_memory, .bulk_write_memory = arm7_9_bulk_write_memory, .checksum_memory = arm_checksum_memory, .blank_check_memory = arm_blank_check_memory, .run_algorithm = armv4_5_run_algorithm, .add_breakpoint = arm7_9_add_breakpoint, .remove_breakpoint = arm7_9_remove_breakpoint, .add_watchpoint = arm7_9_add_watchpoint, .remove_watchpoint = arm7_9_remove_watchpoint, .commands = arm920t_command_handlers, .target_create = fa526_target_create, .init_target = arm9tdmi_init_target, .examine = arm7_9_examine, .check_reset = arm7_9_check_reset, }; openocd-0.7.0/src/target/arm966e.h0000644000175000001440000000446412134336410013506 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef ARM966E_H #define ARM966E_H #include "arm9tdmi.h" #define ARM966E_COMMON_MAGIC 0x20f920f9 struct arm966e_common { struct arm7_9_common arm7_9_common; int common_magic; uint32_t cp15_control_reg; }; static inline struct arm966e_common * target_to_arm966(struct target *target) { return container_of(target->arch_info, struct arm966e_common, arm7_9_common.arm); } int arm966e_init_arch_info(struct target *target, struct arm966e_common *arm966e, struct jtag_tap *tap); int arm966e_write_cp15(struct target *target, int reg_addr, uint32_t value); extern const struct command_registration arm966e_command_handlers[]; #endif /* ARM966E_H */ openocd-0.7.0/src/target/trace.h0000644000175000001440000000454212134336410013410 00000000000000/*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef TRACE_H #define TRACE_H struct target; struct command_context; struct trace_point { uint32_t address; uint64_t hit_counter; }; struct trace { uint32_t num_trace_points; uint32_t trace_points_size; struct trace_point *trace_points; uint32_t trace_history_size; uint32_t *trace_history; uint32_t trace_history_pos; int trace_history_overflowed; }; /** * \todo This enum is one of the few things in this file related * to *hardware* tracing ... split such "real" tracing out from * the contrib/libdcc support. */ typedef enum trace_status { TRACE_IDLE = 0x0, TRACE_RUNNING = 0x1, TRACE_TRIGGERED = 0x2, TRACE_COMPLETED = 0x4, TRACE_OVERFLOWED = 0x8, } trace_status_t; int trace_point(struct target *target, uint32_t number); int trace_register_commands(struct command_context *cmd_ctx); #define ERROR_TRACE_IMAGE_UNAVAILABLE (-1500) #define ERROR_TRACE_INSTRUCTION_UNAVAILABLE (-1501) #endif /* TRACE_H */ openocd-0.7.0/src/target/target_request.h0000644000175000001440000000521512134336410015346 00000000000000/*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef TARGET_REQUEST_H #define TARGET_REQUEST_H struct target; struct command_context; typedef enum target_req_cmd { TARGET_REQ_TRACEMSG, TARGET_REQ_DEBUGMSG, TARGET_REQ_DEBUGCHAR, /* TARGET_REQ_SEMIHOSTING, */ } target_req_cmd_t; struct debug_msg_receiver { struct command_context *cmd_ctx; struct debug_msg_receiver *next; }; int target_request(struct target *target, uint32_t request); int delete_debug_msg_receiver(struct command_context *cmd_ctx, struct target *target); int target_request_register_commands(struct command_context *cmd_ctx); /** * Read and clear the flag as to whether we got a message. * * This is used to implement the back-off algorithm on * sleeping in idle mode. */ bool target_got_message(void); #endif /* TARGET_REQUEST_H */ openocd-0.7.0/src/target/testee.c0000644000175000001440000000453612134336410013601 00000000000000/*************************************************************************** * Copyright (C) 2009 Zachary T Welch * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "target.h" #include "target_type.h" #include "hello.h" static const struct command_registration testee_command_handlers[] = { { .name = "testee", .mode = COMMAND_ANY, .help = "testee target commands", .chain = hello_command_handlers, }, COMMAND_REGISTRATION_DONE }; static int testee_init(struct command_context *cmd_ctx, struct target *target) { return ERROR_OK; } static int testee_poll(struct target *target) { return ERROR_OK; } static int testee_halt(struct target *target) { return ERROR_OK; } static int testee_reset_assert(struct target *target) { return ERROR_OK; } static int testee_reset_deassert(struct target *target) { return ERROR_OK; } struct target_type testee_target = { .name = "testee", .commands = testee_command_handlers, .init_target = &testee_init, .poll = &testee_poll, .halt = &testee_halt, .assert_reset = &testee_reset_assert, .deassert_reset = &testee_reset_deassert, }; openocd-0.7.0/src/target/avr32_ap7k.h0000644000175000001440000000354612134336410014174 00000000000000/*************************************************************************** * Copyright (C) 2010 by Oleksandr Tymoshenko * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef AVR32_AP7K #define AVR32_AP7K struct target; #define AP7k_COMMON_MAGIC 0x4150374b struct avr32_ap7k_common { int common_magic; struct avr32_jtag jtag; struct reg_cache *core_cache; uint32_t core_regs[AVR32NUMCOREREGS]; }; static inline struct avr32_ap7k_common * target_to_ap7k(struct target *target) { return (struct avr32_ap7k_common *)target->arch_info; } struct avr32_core_reg { uint32_t num; struct target *target; struct avr32_ap7k_common *avr32_common; }; #endif /*AVR32_AP7K*/ openocd-0.7.0/src/target/mips32.h0000644000175000001440000002274712134336410013436 00000000000000/*************************************************************************** * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2008 by David T.L. Wong * * * * Copyright (C) 2011 by Drasko DRASKOVIC * * drasko.draskovic@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef MIPS32_H #define MIPS32_H #include "target.h" #include "mips32_pracc.h" #define MIPS32_COMMON_MAGIC 0xB320B320 /** * Memory segments (32bit kernel mode addresses) * These are the traditional names used in the 32-bit universe. */ #define KUSEG 0x00000000 #define KSEG0 0x80000000 #define KSEG1 0xa0000000 #define KSEG2 0xc0000000 #define KSEG3 0xe0000000 /** Returns the kernel segment base of a given address */ #define KSEGX(a) ((a) & 0xe0000000) /** CP0 CONFIG regites fields */ #define MIPS32_CONFIG0_KU_SHIFT 25 #define MIPS32_CONFIG0_KU_MASK (0x7 << MIPS32_CONFIG0_KU_SHIFT) #define MIPS32_CONFIG0_K0_SHIFT 0 #define MIPS32_CONFIG0_K0_MASK (0x7 << MIPS32_CONFIG0_K0_SHIFT) #define MIPS32_CONFIG0_K23_SHIFT 28 #define MIPS32_CONFIG0_K23_MASK (0x7 << MIPS32_CONFIG0_K23_SHIFT) #define MIPS32_CONFIG0_AR_SHIFT 10 #define MIPS32_CONFIG0_AR_MASK (0x7 << MIPS32_CONFIG0_AR_SHIFT) #define MIPS32_CONFIG1_DL_SHIFT 10 #define MIPS32_CONFIG1_DL_MASK (0x7 << MIPS32_CONFIG1_DL_SHIFT) #define MIPS32_ARCH_REL1 0x0 #define MIPS32_ARCH_REL2 0x1 /* offsets into mips32 core register cache */ enum { MIPS32_PC = 37, MIPS32NUMCOREREGS }; enum mips32_isa_mode { MIPS32_ISA_MIPS32 = 0, MIPS32_ISA_MIPS16E = 1, }; struct mips32_comparator { int used; uint32_t bp_value; uint32_t reg_address; }; struct mips32_common { uint32_t common_magic; void *arch_info; struct reg_cache *core_cache; struct mips_ejtag ejtag_info; uint32_t core_regs[MIPS32NUMCOREREGS]; enum mips32_isa_mode isa_mode; /* working area for fastdata access */ struct working_area *fast_data_area; int bp_scanned; int num_inst_bpoints; int num_data_bpoints; int num_inst_bpoints_avail; int num_data_bpoints_avail; struct mips32_comparator *inst_break_list; struct mips32_comparator *data_break_list; /* register cache to processor synchronization */ int (*read_core_reg)(struct target *target, int num); int (*write_core_reg)(struct target *target, int num); }; static inline struct mips32_common * target_to_mips32(struct target *target) { return target->arch_info; } struct mips32_core_reg { uint32_t num; struct target *target; struct mips32_common *mips32_common; }; struct mips32_algorithm { int common_magic; enum mips32_isa_mode isa_mode; }; #define MIPS32_OP_ADDIU 0x21 #define MIPS32_OP_ANDI 0x0C #define MIPS32_OP_BEQ 0x04 #define MIPS32_OP_BGTZ 0x07 #define MIPS32_OP_BNE 0x05 #define MIPS32_OP_ADDI 0x08 #define MIPS32_OP_AND 0x24 #define MIPS32_OP_CACHE 0x2F #define MIPS32_OP_COP0 0x10 #define MIPS32_OP_JR 0x08 #define MIPS32_OP_LUI 0x0F #define MIPS32_OP_LW 0x23 #define MIPS32_OP_LBU 0x24 #define MIPS32_OP_LHU 0x25 #define MIPS32_OP_MFHI 0x10 #define MIPS32_OP_MTHI 0x11 #define MIPS32_OP_MFLO 0x12 #define MIPS32_OP_MTLO 0x13 #define MIPS32_OP_RDHWR 0x3B #define MIPS32_OP_SB 0x28 #define MIPS32_OP_SH 0x29 #define MIPS32_OP_SW 0x2B #define MIPS32_OP_ORI 0x0D #define MIPS32_OP_XORI 0x0E #define MIPS32_OP_XOR 0x26 #define MIPS32_OP_SLTU 0x2B #define MIPS32_OP_SRL 0x03 #define MIPS32_OP_SYNCI 0x1F #define MIPS32_OP_REGIMM 0x01 #define MIPS32_OP_SDBBP 0x3F #define MIPS32_OP_SPECIAL 0x00 #define MIPS32_OP_SPECIAL2 0x07 #define MIPS32_OP_SPECIAL3 0x1F #define MIPS32_COP0_MF 0x00 #define MIPS32_COP0_MT 0x04 #define MIPS32_R_INST(opcode, rs, rt, rd, shamt, funct) \ (((opcode) << 26) | ((rs) << 21) | ((rt) << 16) | ((rd) << 11) | ((shamt) << 6) | (funct)) #define MIPS32_I_INST(opcode, rs, rt, immd) \ (((opcode) << 26) | ((rs) << 21) | ((rt) << 16) | (immd)) #define MIPS32_J_INST(opcode, addr) (((opcode) << 26) | (addr)) #define MIPS32_NOP 0 #define MIPS32_ADDI(tar, src, val) MIPS32_I_INST(MIPS32_OP_ADDI, src, tar, val) #define MIPS32_ADDU(dst, src, tar) MIPS32_R_INST(MIPS32_OP_SPECIAL, src, tar, dst, 0, MIPS32_OP_ADDIU) #define MIPS32_AND(reg, off, val) MIPS32_R_INST(0, off, val, reg, 0, MIPS32_OP_AND) #define MIPS32_ANDI(tar, src, val) MIPS32_I_INST(MIPS32_OP_ANDI, src, tar, val) #define MIPS32_B(off) MIPS32_BEQ(0, 0, off) #define MIPS32_BEQ(src, tar, off) MIPS32_I_INST(MIPS32_OP_BEQ, src, tar, off) #define MIPS32_BGTZ(reg, off) MIPS32_I_INST(MIPS32_OP_BGTZ, reg, 0, off) #define MIPS32_BNE(src, tar, off) MIPS32_I_INST(MIPS32_OP_BNE, src, tar, off) #define MIPS32_CACHE(op, off, base) MIPS32_I_INST(MIPS32_OP_CACHE, base, op, off) #define MIPS32_JR(reg) MIPS32_R_INST(0, reg, 0, 0, 0, MIPS32_OP_JR) #define MIPS32_MFC0(gpr, cpr, sel) MIPS32_R_INST(MIPS32_OP_COP0, MIPS32_COP0_MF, gpr, cpr, 0, sel) #define MIPS32_MTC0(gpr, cpr, sel) MIPS32_R_INST(MIPS32_OP_COP0, MIPS32_COP0_MT, gpr, cpr, 0, sel) #define MIPS32_LBU(reg, off, base) MIPS32_I_INST(MIPS32_OP_LBU, base, reg, off) #define MIPS32_LHU(reg, off, base) MIPS32_I_INST(MIPS32_OP_LHU, base, reg, off) #define MIPS32_LUI(reg, val) MIPS32_I_INST(MIPS32_OP_LUI, 0, reg, val) #define MIPS32_LW(reg, off, base) MIPS32_I_INST(MIPS32_OP_LW, base, reg, off) #define MIPS32_MFLO(reg) MIPS32_R_INST(0, 0, 0, reg, 0, MIPS32_OP_MFLO) #define MIPS32_MFHI(reg) MIPS32_R_INST(0, 0, 0, reg, 0, MIPS32_OP_MFHI) #define MIPS32_MTLO(reg) MIPS32_R_INST(0, reg, 0, 0, 0, MIPS32_OP_MTLO) #define MIPS32_MTHI(reg) MIPS32_R_INST(0, reg, 0, 0, 0, MIPS32_OP_MTHI) #define MIPS32_ORI(tar, src, val) MIPS32_I_INST(MIPS32_OP_ORI, src, tar, val) #define MIPS32_XORI(tar, src, val) MIPS32_I_INST(MIPS32_OP_XORI, src, tar, val) #define MIPS32_RDHWR(tar, dst) MIPS32_R_INST(MIPS32_OP_SPECIAL3, 0, tar, dst, 0, MIPS32_OP_RDHWR) #define MIPS32_SB(reg, off, base) MIPS32_I_INST(MIPS32_OP_SB, base, reg, off) #define MIPS32_SH(reg, off, base) MIPS32_I_INST(MIPS32_OP_SH, base, reg, off) #define MIPS32_SW(reg, off, base) MIPS32_I_INST(MIPS32_OP_SW, base, reg, off) #define MIPS32_XOR(reg, val1, val2) MIPS32_R_INST(0, val1, val2, reg, 0, MIPS32_OP_XOR) #define MIPS32_SRL(reg, src, off) MIPS32_R_INST(0, 0, src, reg, off, MIPS32_OP_SRL) #define MIPS32_SLTU(dst, src, tar) MIPS32_R_INST(MIPS32_OP_SPECIAL, src, tar, dst, 0, MIPS32_OP_SLTU) #define MIPS32_SYNCI(off, base) MIPS32_I_INST(MIPS32_OP_REGIMM, base, MIPS32_OP_SYNCI, off) #define MIPS32_SYNC 0xF #define MIPS32_SYNCI_STEP 0x1 /* reg num od address step size to be used with synci instruction */ /** * Cache operations definietions * Operation field is 5 bits long : * 1) bits 1..0 hold cache type * 2) bits 4..2 hold operation code */ #define MIPS32_CACHE_D_HIT_WRITEBACK ((0x1 << 0) | (0x6 << 2)) #define MIPS32_CACHE_I_HIT_INVALIDATE ((0x0 << 0) | (0x4 << 2)) /* ejtag specific instructions */ #define MIPS32_DRET 0x4200001F #define MIPS32_SDBBP 0x7000003F /* MIPS32_J_INST(MIPS32_OP_SPECIAL2, MIPS32_OP_SDBBP) */ #define MIPS16_SDBBP 0xE801 extern const struct command_registration mips32_command_handlers[]; int mips32_arch_state(struct target *target); int mips32_init_arch_info(struct target *target, struct mips32_common *mips32, struct jtag_tap *tap); int mips32_restore_context(struct target *target); int mips32_save_context(struct target *target); struct reg_cache *mips32_build_reg_cache(struct target *target); int mips32_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, uint32_t entry_point, uint32_t exit_point, int timeout_ms, void *arch_info); int mips32_configure_break_unit(struct target *target); int mips32_enable_interrupts(struct target *target, int enable); int mips32_examine(struct target *target); int mips32_register_commands(struct command_context *cmd_ctx); int mips32_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size); int mips32_checksum_memory(struct target *target, uint32_t address, uint32_t count, uint32_t *checksum); int mips32_blank_check_memory(struct target *target, uint32_t address, uint32_t count, uint32_t *blank); #endif /*MIPS32_H*/ openocd-0.7.0/src/target/xscale/0000755000175000001440000000000012141414412013470 500000000000000openocd-0.7.0/src/target/xscale/debug_handler.bin0000755000175000001440000000307012134336410016673 00000000000000ÞîÑâÑ ãÞ îþîýÿÿjîþîýÿÿjîî ápë ánë álë ájë áhë áfë ádëOábëOá ÀãÀ€ãâQãÀã€ã=ê\ëPã9 PãZ Pã{ PムPã‹ !Pã“ "Pã› $P㣠0Pã 1Pã+ @PãÄ APãí PPã§ QP㬠RP㬠SP㬠`Pã› aPã  bPã ×ÿÿê4ëðiá2ëp á0ë` á.ëP á,ë@ á*ë0 á(ë  á&ë á$ëþîýÿÿZîîð^âëpáð!á áâþîýÿÿjŽîþîýÿÿjžîþîýÿÿj®îþîýÿÿj¾îþîýÿÿjÎîþîýÿÿjÞîþîýÿÿjîîQã Oáþîýÿÿjîð!á áŸÿÿêüëpáð!á áâþîýÿÿZŽîþîýÿÿZžîþîýÿÿZ®îþîýÿÿZ¾îþîýÿÿZÎîþîýÿÿZÞîþîýÿÿZîîQã þîýÿÿZîðiáð!á á|ÿÿêÙë  á×ë áÒäšîÏëQâúÿÿrÿÿêÏë  áÍë á²ÒàšîÅëQâúÿÿhÿÿêÅë  áÃë á’äšî»ëQâúÿÿ^ÿÿê»ë  á¹ë á·ëÂäšîQâúÿÿTÿÿê±ë  á¯ë á­ë²ÂàšîQâúÿÿJÿÿê§ë  á¥ë á£ë‚äšîQâúÿÿ@ÿÿêî Àã î<ÿÿê™ë ã²î €âQâûÿÿ5ÿÿêî3ÿÿêî1ÿÿêî áðOâ-ÿÿê€ëâ€ñàî#ê0î!êîê0îêîêîêîêîêîêîêîêî êî êî êîêîêîêîêîÿÿÿêSëøþÿêUë áSë âñ‚àîñþÿê0îïþÿêîíþÿê0îëþÿêîéþÿêîçþÿêîåþÿêîãþÿê îáþÿêîßþÿêîÝþÿêîÛþÿêîÙþÿêî×þÿêîÕþÿê îÓþÿê îÑþÿê îÏþÿê îÍþÿê ãî$ëQâûÿÿî ëîëÃþÿê ãîQâüÿÿ¾þÿêëðiáëp áë` áëP áë@ áë0 áë  á ë á ëþîýÿÿZîîÞîÐãÞ îð^âþÿÿêþîýÿÿjîð áþîýÿÿZîð áopenocd-0.7.0/src/target/algorithm.c0000644000175000001440000000426312134336410014273 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "algorithm.h" #include void init_mem_param(struct mem_param *param, uint32_t address, uint32_t size, enum param_direction direction) { param->address = address; param->size = size; param->value = malloc(size); param->direction = direction; } void destroy_mem_param(struct mem_param *param) { free(param->value); param->value = NULL; } void init_reg_param(struct reg_param *param, char *reg_name, uint32_t size, enum param_direction direction) { param->reg_name = reg_name; param->size = size; param->value = malloc(DIV_ROUND_UP(size, 8)); param->direction = direction; } void destroy_reg_param(struct reg_param *param) { free(param->value); param->value = NULL; } openocd-0.7.0/src/target/etm.h0000644000175000001440000001750512134336410013102 00000000000000/*************************************************************************** * Copyright (C) 2005, 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007 by Vincent Palatin * * vincent.palatin_openocd@m4x.org * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef ETM_H #define ETM_H #include "trace.h" #include "arm_jtag.h" struct image; /* ETM registers (JTAG protocol) */ enum { ETM_CTRL = 0x00, ETM_CONFIG = 0x01, ETM_TRIG_EVENT = 0x02, ETM_ASIC_CTRL = 0x03, ETM_STATUS = 0x04, ETM_SYS_CONFIG = 0x05, ETM_TRACE_RESOURCE_CTRL = 0x06, ETM_TRACE_EN_CTRL2 = 0x07, ETM_TRACE_EN_EVENT = 0x08, ETM_TRACE_EN_CTRL1 = 0x09, /* optional FIFOFULL */ ETM_FIFOFULL_REGION = 0x0a, ETM_FIFOFULL_LEVEL = 0x0b, /* viewdata support */ ETM_VIEWDATA_EVENT = 0x0c, ETM_VIEWDATA_CTRL1 = 0x0d, ETM_VIEWDATA_CTRL2 = 0x0e, /* optional */ ETM_VIEWDATA_CTRL3 = 0x0f, /* N pairs of ADDR_{COMPARATOR,ACCESS} registers */ ETM_ADDR_COMPARATOR_VALUE = 0x10, ETM_ADDR_ACCESS_TYPE = 0x20, /* N pairs of DATA_COMPARATOR_{VALUE,MASK} registers */ ETM_DATA_COMPARATOR_VALUE = 0x30, ETM_DATA_COMPARATOR_MASK = 0x40, /* N quads of COUNTER_{RELOAD_{VALUE,EVENT},ENABLE,VALUE} registers */ ETM_COUNTER_RELOAD_VALUE = 0x50, ETM_COUNTER_ENABLE = 0x54, ETM_COUNTER_RELOAD_EVENT = 0x58, ETM_COUNTER_VALUE = 0x5c, /* 6 sequencer event transitions */ ETM_SEQUENCER_EVENT = 0x60, ETM_SEQUENCER_STATE = 0x67, /* N triggered outputs */ ETM_EXTERNAL_OUTPUT = 0x68, /* N task contexts */ ETM_CONTEXTID_COMPARATOR_VALUE = 0x6c, ETM_CONTEXTID_COMPARATOR_MASK = 0x6f, ETM_ID = 0x79, }; struct etm_reg { uint32_t value; const struct etm_reg_info *reg_info; struct arm_jtag *jtag_info; }; /* Subset of ETM_CTRL bit assignments. Many of these * control the configuration of trace output, which * hooks up either to ETB or to an external device. * * NOTE that these have evolved since the ~v1.3 defns ... */ enum { ETM_CTRL_POWERDOWN = (1 << 0), ETM_CTRL_MONITOR_CPRT = (1 << 1), /* bits 3:2 == trace type */ ETM_CTRL_TRACE_DATA = (1 << 2), ETM_CTRL_TRACE_ADDR = (2 << 2), ETM_CTRL_TRACE_MASK = (3 << 2), /* Port width (bits 21 and 6:4) */ ETM_PORT_4BIT = 0x00, ETM_PORT_8BIT = 0x10, ETM_PORT_16BIT = 0x20, ETM_PORT_24BIT = 0x30, ETM_PORT_32BIT = 0x40, ETM_PORT_48BIT = 0x50, ETM_PORT_64BIT = 0x60, ETM_PORT_1BIT = 0x00 | (1 << 21), ETM_PORT_2BIT = 0x10 | (1 << 21), ETM_PORT_WIDTH_MASK = 0x70 | (1 << 21), ETM_CTRL_FIFOFULL_STALL = (1 << 7), ETM_CTRL_BRANCH_OUTPUT = (1 << 8), ETM_CTRL_DBGRQ = (1 << 9), ETM_CTRL_ETM_PROG = (1 << 10), ETM_CTRL_ETMEN = (1 << 11), ETM_CTRL_CYCLE_ACCURATE = (1 << 12), /* Clocking modes -- up to v2.1, bit 13 */ ETM_PORT_FULL_CLOCK = (0 << 13), ETM_PORT_HALF_CLOCK = (1 << 13), ETM_PORT_CLOCK_MASK = (1 << 13), /* bits 15:14 == context ID size used in tracing */ ETM_CTRL_CONTEXTID_NONE = (0 << 14), ETM_CTRL_CONTEXTID_8 = (1 << 14), ETM_CTRL_CONTEXTID_16 = (2 << 14), ETM_CTRL_CONTEXTID_32 = (3 << 14), ETM_CTRL_CONTEXTID_MASK = (3 << 14), /* Port modes -- bits 17:16, tied to clocking mode */ ETM_PORT_NORMAL = (0 << 16), ETM_PORT_MUXED = (1 << 16), ETM_PORT_DEMUXED = (2 << 16), ETM_PORT_MODE_MASK = (3 << 16), /* bits 31:18 defined in v3.0 and later (e.g. ARM11+) */ }; /* forward-declare ETM context */ struct etm_context; struct etm_capture_driver { const char *name; const struct command_registration *commands; int (*init)(struct etm_context *etm_ctx); trace_status_t (*status)(struct etm_context *etm_ctx); int (*read_trace)(struct etm_context *etm_ctx); int (*start_capture)(struct etm_context *etm_ctx); int (*stop_capture)(struct etm_context *etm_ctx); }; enum { ETMV1_TRACESYNC_CYCLE = 0x1, ETMV1_TRIGGER_CYCLE = 0x2, }; struct etmv1_trace_data { uint8_t pipestat; /* bits 0-2 pipeline status */ uint16_t packet; /* packet data (4, 8 or 16 bit) */ int flags; /* ETMV1_TRACESYNC_CYCLE, ETMV1_TRIGGER_CYCLE */ }; /* describe a trace context * if support for ETMv2 or ETMv3 is to be implemented, * this will have to be split into version independent elements * and a version specific part */ struct etm_context { struct target *target; /* target this ETM is connected to */ struct reg_cache *reg_cache; /* ETM register cache */ struct etm_capture_driver *capture_driver; /* driver used to access ETM data */ void *capture_driver_priv; /* capture driver private data */ trace_status_t capture_status; /* current state of capture run */ struct etmv1_trace_data *trace_data; /* trace data */ uint32_t trace_depth; /* number of cycles to be analyzed, 0 if no data available */ uint32_t control; /* shadow of ETM_CTRL */ int /*arm_state*/ core_state; /* current core state */ struct image *image; /* source for target opcodes */ uint32_t pipe_index; /* current trace cycle */ uint32_t data_index; /* cycle holding next data packet */ bool data_half; /* port half on a 16 bit port */ bool pc_ok; /* full PC has been acquired */ bool ptr_ok; /* whether last_ptr is valid */ uint8_t bcd_vers; /* e.g. 0x13 == ETMv1.3 */ uint32_t config; /* cache of ETM_CONFIG value */ uint32_t id; /* cache of ETM_ID value, or 0 */ uint32_t current_pc; /* current program counter */ uint32_t last_branch; /* last branch address output */ uint32_t last_branch_reason; /* type of last branch encountered */ uint32_t last_ptr; /* address of the last data access */ uint32_t last_instruction; /* index of last executed (to calc timings) */ }; /* PIPESTAT values */ typedef enum { STAT_IE = 0x0, STAT_ID = 0x1, STAT_IN = 0x2, STAT_WT = 0x3, STAT_BE = 0x4, STAT_BD = 0x5, STAT_TR = 0x6, STAT_TD = 0x7 } etmv1_pipestat_t; /* branch reason values */ typedef enum { BR_NORMAL = 0x0, /* Normal PC change : periodic synchro (ETMv1.1) */ BR_ENABLE = 0x1, /* Trace has been enabled */ BR_RESTART = 0x2, /* Trace restarted after a FIFO overflow */ BR_NODEBUG = 0x3, /* ARM has exited for debug state */ BR_PERIOD = 0x4, /* Peridioc synchronization point (ETM >= v1.2)*/ BR_RSVD5 = 0x5, /* reserved */ BR_RSVD6 = 0x6, /* reserved */ BR_RSVD7 = 0x7, /* reserved */ } etmv1_branch_reason_t; struct reg_cache *etm_build_reg_cache(struct target *target, struct arm_jtag *jtag_info, struct etm_context *etm_ctx); int etm_setup(struct target *target); extern const struct command_registration etm_command_handlers[]; #define ERROR_ETM_INVALID_DRIVER (-1300) #define ERROR_ETM_PORTMODE_NOT_SUPPORTED (-1301) #define ERROR_ETM_CAPTURE_INIT_FAILED (-1302) #define ERROR_ETM_ANALYSIS_FAILED (-1303) #endif /* ETM_H */ openocd-0.7.0/src/target/adi_v5_jtag.c0000644000175000001440000003640212137151331014461 00000000000000/*************************************************************************** * Copyright (C) 2006 by Magnus Lundin * lundin@mlu.mine.nu * * Copyright (C) 2008 by Spencer Oliver * spen@spen-soft.co.uk * * Copyright (C) 2009 by Oyvind Harboe * oyvind.harboe@zylin.com * * Copyright (C) 2009-2010 by David Brownell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 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. ***************************************************************************/ /** * @file * This file implements JTAG transport support for cores implementing the ARM Debug Interface version 5 (ADIv5). */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm.h" #include "arm_adi_v5.h" #include /* JTAG instructions/registers for JTAG-DP and SWJ-DP */ #define JTAG_DP_ABORT 0x8 #define JTAG_DP_DPACC 0xA #define JTAG_DP_APACC 0xB #define JTAG_DP_IDCODE 0xE /* three-bit ACK values for DPACC and APACC reads */ #define JTAG_ACK_OK_FAULT 0x2 #define JTAG_ACK_WAIT 0x1 static int jtag_ap_q_abort(struct adiv5_dap *dap, uint8_t *ack); /*************************************************************************** * * DPACC and APACC scanchain access through JTAG-DP (or SWJ-DP) * ***************************************************************************/ /** * Scan DPACC or APACC using target ordered uint8_t buffers. No endianness * conversions are performed. See section 4.4.3 of the ADIv5 spec, which * discusses operations which access these registers. * * Note that only one scan is performed. If RnW is set, a separate scan * will be needed to collect the data which was read; the "invalue" collects * the posted result of a preceding operation, not the current one. * * @param dap the DAP * @param instr JTAG_DP_APACC (AP access) or JTAG_DP_DPACC (DP access) * @param reg_addr two significant bits; A[3:2]; for APACC access, the * SELECT register has more addressing bits. * @param RnW false iff outvalue will be written to the DP or AP * @param outvalue points to a 32-bit (little-endian) integer * @param invalue NULL, or points to a 32-bit (little-endian) integer * @param ack points to where the three bit JTAG_ACK_* code will be stored */ static int adi_jtag_dp_scan(struct adiv5_dap *dap, uint8_t instr, uint8_t reg_addr, uint8_t RnW, uint8_t *outvalue, uint8_t *invalue, uint8_t *ack) { struct arm_jtag *jtag_info = dap->jtag_info; struct scan_field fields[2]; uint8_t out_addr_buf; int retval; retval = arm_jtag_set_instr(jtag_info, instr, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; /* Scan out a read or write operation using some DP or AP register. * For APACC access with any sticky error flag set, this is discarded. */ fields[0].num_bits = 3; buf_set_u32(&out_addr_buf, 0, 3, ((reg_addr >> 1) & 0x6) | (RnW & 0x1)); fields[0].out_value = &out_addr_buf; fields[0].in_value = ack; /* NOTE: if we receive JTAG_ACK_WAIT, the previous operation did not * complete; data we write is discarded, data we read is unpredictable. * When overrun detect is active, STICKYORUN is set. */ fields[1].num_bits = 32; fields[1].out_value = outvalue; fields[1].in_value = invalue; jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_IDLE); /* Add specified number of tck clocks after starting memory bus * access, giving the hardware time to complete the access. * They provide more time for the (MEM) AP to complete the read ... * See "Minimum Response Time" for JTAG-DP, in the ADIv5 spec. */ if ((instr == JTAG_DP_APACC) && ((reg_addr == AP_REG_DRW) || ((reg_addr & 0xF0) == AP_REG_BD0)) && (dap->memaccess_tck != 0)) jtag_add_runtest(dap->memaccess_tck, TAP_IDLE); return ERROR_OK; } /** * Scan DPACC or APACC out and in from host ordered uint32_t buffers. * This is exactly like adi_jtag_dp_scan(), except that endianness * conversions are performed (so the types of invalue and outvalue * must be different). */ static int adi_jtag_dp_scan_u32(struct adiv5_dap *dap, uint8_t instr, uint8_t reg_addr, uint8_t RnW, uint32_t outvalue, uint32_t *invalue, uint8_t *ack) { uint8_t out_value_buf[4]; int retval; buf_set_u32(out_value_buf, 0, 32, outvalue); retval = adi_jtag_dp_scan(dap, instr, reg_addr, RnW, out_value_buf, (uint8_t *)invalue, ack); if (retval != ERROR_OK) return retval; if (invalue) jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t) invalue); return retval; } /** * Utility to write AP registers. */ static inline int adi_jtag_ap_write_check(struct adiv5_dap *dap, uint8_t reg_addr, uint8_t *outvalue) { return adi_jtag_dp_scan(dap, JTAG_DP_APACC, reg_addr, DPAP_WRITE, outvalue, NULL, NULL); } static int adi_jtag_scan_inout_check_u32(struct adiv5_dap *dap, uint8_t instr, uint8_t reg_addr, uint8_t RnW, uint32_t outvalue, uint32_t *invalue) { int retval; /* Issue the read or write */ retval = adi_jtag_dp_scan_u32(dap, instr, reg_addr, RnW, outvalue, NULL, NULL); if (retval != ERROR_OK) return retval; /* For reads, collect posted value; RDBUFF has no other effect. * Assumes read gets acked with OK/FAULT, and CTRL_STAT says "OK". */ if ((RnW == DPAP_READ) && (invalue != NULL)) retval = adi_jtag_dp_scan_u32(dap, JTAG_DP_DPACC, DP_RDBUFF, DPAP_READ, 0, invalue, &dap->ack); return retval; } static int jtagdp_transaction_endcheck(struct adiv5_dap *dap) { int retval; uint32_t ctrlstat; /* too expensive to call keep_alive() here */ /* Here be dragons! * * It is easy to be in a JTAG clock range where the target * is not operating in a stable fashion. This happens * for a few reasons: * * - the user may construct a simple test case to try to see * if a higher JTAG clock works to eke out more performance. * This simple case may pass, but more complex situations can * fail. * * - The mostly works JTAG clock rate and the complete failure * JTAG clock rate may be as much as 2-4x apart. This seems * to be especially true on RC oscillator driven parts. * * So: even if calling adi_jtag_scan_inout_check_u32() multiple * times here seems to "make things better here", it is just * hiding problems with too high a JTAG clock. * * Note that even if some parts have RCLK/RTCK, that doesn't * mean that RCLK/RTCK is the *correct* rate to run the JTAG * interface at, i.e. RCLK/RTCK rates can be "too high", especially * before the RC oscillator phase is not yet complete. */ /* Post CTRL/STAT read; discard any previous posted read value * but collect its ACK status. */ retval = adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC, DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; dap->ack = dap->ack & 0x7; /* common code path avoids calling timeval_ms() */ if (dap->ack != JTAG_ACK_OK_FAULT) { long long then = timeval_ms(); while (dap->ack != JTAG_ACK_OK_FAULT) { if (dap->ack == JTAG_ACK_WAIT) { if ((timeval_ms()-then) > 1000) { LOG_WARNING("Timeout (1000ms) waiting " "for ACK=OK/FAULT " "in JTAG-DP transaction - aborting"); uint8_t ack; int abort_ret = jtag_ap_q_abort(dap, &ack); if (abort_ret != 0) LOG_WARNING("Abort failed : return=%d ack=%d", abort_ret, ack); return ERROR_JTAG_DEVICE_ERROR; } } else { LOG_WARNING("Invalid ACK %#x " "in JTAG-DP transaction", dap->ack); return ERROR_JTAG_DEVICE_ERROR; } retval = adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC, DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; dap->ack = dap->ack & 0x7; } } /* REVISIT also STICKYCMP, for pushed comparisons (nyet used) */ /* Check for STICKYERR and STICKYORUN */ if (ctrlstat & (SSTICKYORUN | SSTICKYERR)) { LOG_DEBUG("jtag-dp: CTRL/STAT error, 0x%" PRIx32, ctrlstat); /* Check power to debug regions */ if ((ctrlstat & 0xf0000000) != 0xf0000000) { retval = ahbap_debugport_init(dap); if (retval != ERROR_OK) return retval; } else { uint32_t mem_ap_csw, mem_ap_tar; /* Maybe print information about last intended * MEM-AP access; but not if autoincrementing. * *Real* CSW and TAR values are always shown. */ if (dap->ap_tar_value != (uint32_t) -1) LOG_DEBUG("MEM-AP Cached values: " "ap_bank 0x%" PRIx32 ", ap_csw 0x%" PRIx32 ", ap_tar 0x%" PRIx32, dap->ap_bank_value, dap->ap_csw_value, dap->ap_tar_value); if (ctrlstat & SSTICKYORUN) LOG_ERROR("JTAG-DP OVERRUN - check clock, " "memaccess, or reduce jtag speed"); if (ctrlstat & SSTICKYERR) LOG_ERROR("JTAG-DP STICKY ERROR"); /* Clear Sticky Error Bits */ retval = adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC, DP_CTRL_STAT, DPAP_WRITE, dap->dp_ctrl_stat | SSTICKYORUN | SSTICKYERR, NULL); if (retval != ERROR_OK) return retval; retval = adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC, DP_CTRL_STAT, DPAP_READ, 0, &ctrlstat); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; LOG_DEBUG("jtag-dp: CTRL/STAT 0x%" PRIx32, ctrlstat); retval = dap_queue_ap_read(dap, AP_REG_CSW, &mem_ap_csw); if (retval != ERROR_OK) return retval; retval = dap_queue_ap_read(dap, AP_REG_TAR, &mem_ap_tar); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; LOG_ERROR("MEM_AP_CSW 0x%" PRIx32 ", MEM_AP_TAR 0x%" PRIx32, mem_ap_csw, mem_ap_tar); } retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; return ERROR_JTAG_DEVICE_ERROR; } return ERROR_OK; } /*--------------------------------------------------------------------------*/ static int jtag_idcode_q_read(struct adiv5_dap *dap, uint8_t *ack, uint32_t *data) { struct arm_jtag *jtag_info = dap->jtag_info; int retval; struct scan_field fields[1]; /* This is a standard JTAG operation -- no DAP tweakage */ retval = arm_jtag_set_instr(jtag_info, JTAG_DP_IDCODE, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 32; fields[0].out_value = NULL; fields[0].in_value = (void *) data; jtag_add_dr_scan(jtag_info->tap, 1, fields, TAP_IDLE); jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t) data); return ERROR_OK; } static int jtag_dp_q_read(struct adiv5_dap *dap, unsigned reg, uint32_t *data) { return adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC, reg, DPAP_READ, 0, data); } static int jtag_dp_q_write(struct adiv5_dap *dap, unsigned reg, uint32_t data) { return adi_jtag_scan_inout_check_u32(dap, JTAG_DP_DPACC, reg, DPAP_WRITE, data, NULL); } /** Select the AP register bank matching bits 7:4 of reg. */ static int jtag_ap_q_bankselect(struct adiv5_dap *dap, unsigned reg) { uint32_t select_ap_bank = reg & 0x000000F0; if (select_ap_bank == dap->ap_bank_value) return ERROR_OK; dap->ap_bank_value = select_ap_bank; select_ap_bank |= dap->ap_current; return jtag_dp_q_write(dap, DP_SELECT, select_ap_bank); } static int jtag_ap_q_read(struct adiv5_dap *dap, unsigned reg, uint32_t *data) { int retval = jtag_ap_q_bankselect(dap, reg); if (retval != ERROR_OK) return retval; return adi_jtag_scan_inout_check_u32(dap, JTAG_DP_APACC, reg, DPAP_READ, 0, data); } static int jtag_ap_q_write(struct adiv5_dap *dap, unsigned reg, uint32_t data) { uint8_t out_value_buf[4]; int retval = jtag_ap_q_bankselect(dap, reg); if (retval != ERROR_OK) return retval; buf_set_u32(out_value_buf, 0, 32, data); return adi_jtag_ap_write_check(dap, reg, out_value_buf); } static int jtag_ap_q_read_block(struct adiv5_dap *dap, unsigned reg, uint32_t blocksize, uint8_t *buffer) { uint32_t readcount; int retval = ERROR_OK; /* Scan out first read */ retval = adi_jtag_dp_scan(dap, JTAG_DP_APACC, reg, DPAP_READ, 0, NULL, NULL); if (retval != ERROR_OK) return retval; for (readcount = 0; readcount < blocksize - 1; readcount++) { /* Scan out next read; scan in posted value for the * previous one. Assumes read is acked "OK/FAULT", * and CTRL_STAT says that meant "OK". */ retval = adi_jtag_dp_scan(dap, JTAG_DP_APACC, reg, DPAP_READ, 0, buffer + 4 * readcount, &dap->ack); if (retval != ERROR_OK) return retval; } /* Scan in last posted value; RDBUFF has no other effect, * assuming ack is OK/FAULT and CTRL_STAT says "OK". */ retval = adi_jtag_dp_scan(dap, JTAG_DP_DPACC, DP_RDBUFF, DPAP_READ, 0, buffer + 4 * readcount, &dap->ack); return retval; } static int jtag_ap_q_abort(struct adiv5_dap *dap, uint8_t *ack) { /* for JTAG, this is the only valid ABORT register operation */ return adi_jtag_dp_scan_u32(dap, JTAG_DP_ABORT, 0, DPAP_WRITE, 1, NULL, ack); } static int jtag_dp_run(struct adiv5_dap *dap) { return jtagdp_transaction_endcheck(dap); } /* FIXME don't export ... just initialize as * part of DAP setup */ const struct dap_ops jtag_dp_ops = { .queue_idcode_read = jtag_idcode_q_read, .queue_dp_read = jtag_dp_q_read, .queue_dp_write = jtag_dp_q_write, .queue_ap_read = jtag_ap_q_read, .queue_ap_write = jtag_ap_q_write, .queue_ap_read_block = jtag_ap_q_read_block, .queue_ap_abort = jtag_ap_q_abort, .run = jtag_dp_run, }; static const uint8_t swd2jtag_bitseq[] = { /* More than 50 TCK/SWCLK cycles with TMS/SWDIO high, * putting both JTAG and SWD logic into reset state. */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* Switching equence disables SWD and enables JTAG * NOTE: bits in the DP's IDCODE can expose the need for * the old/deprecated sequence (0xae 0xde). */ 0x3c, 0xe7, /* At least 50 TCK/SWCLK cycles with TMS/SWDIO high, * putting both JTAG and SWD logic into reset state. * NOTE: some docs say "at least 5". */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }; /** Put the debug link into JTAG mode, if the target supports it. * The link's initial mode may be either SWD or JTAG. * * @param target Enters JTAG mode (if possible). * * Note that targets implemented with SW-DP do not support JTAG, and * that some targets which could otherwise support it may have been * configured to disable JTAG signaling * * @return ERROR_OK or else a fault code. */ int dap_to_jtag(struct target *target) { int retval; LOG_DEBUG("Enter JTAG mode"); /* REVISIT it's nasty to need to make calls to a "jtag" * subsystem if the link isn't in JTAG mode... */ retval = jtag_add_tms_seq(8 * sizeof(swd2jtag_bitseq), swd2jtag_bitseq, TAP_RESET); if (retval == ERROR_OK) retval = jtag_execute_queue(); /* REVISIT set up the DAP's ops vector for JTAG mode. */ return retval; } openocd-0.7.0/src/target/cortex_a.c0000644000175000001440000024647712137175623014142 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2006 by Magnus Lundin * * lundin@mlu.mine.nu * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2009 by Dirk Behme * * dirk.behme@gmail.com - copy from cortex_m3 * * * * Copyright (C) 2010 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) ST-Ericsson SA 2011 * * michel.jaouen@stericsson.com : smp minimum support * * * * Copyright (C) Broadcom 2012 * * ehunter@broadcom.com : Cortex R4 support * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * * * * Cortex-A8(tm) TRM, ARM DDI 0344H * * Cortex-A9(tm) TRM, ARM DDI 0407F * * Cortex-A4(tm) TRM, ARM DDI 0363E * * * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "breakpoints.h" #include "cortex_a.h" #include "register.h" #include "target_request.h" #include "target_type.h" #include "arm_opcodes.h" #include static int cortex_a8_poll(struct target *target); static int cortex_a8_debug_entry(struct target *target); static int cortex_a8_restore_context(struct target *target, bool bpwp); static int cortex_a8_set_breakpoint(struct target *target, struct breakpoint *breakpoint, uint8_t matchmode); static int cortex_a8_set_context_breakpoint(struct target *target, struct breakpoint *breakpoint, uint8_t matchmode); static int cortex_a8_set_hybrid_breakpoint(struct target *target, struct breakpoint *breakpoint); static int cortex_a8_unset_breakpoint(struct target *target, struct breakpoint *breakpoint); static int cortex_a8_dap_read_coreregister_u32(struct target *target, uint32_t *value, int regnum); static int cortex_a8_dap_write_coreregister_u32(struct target *target, uint32_t value, int regnum); static int cortex_a8_mmu(struct target *target, int *enabled); static int cortex_a8_virt2phys(struct target *target, uint32_t virt, uint32_t *phys); static int cortex_a8_read_apb_ab_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer); /* restore cp15_control_reg at resume */ static int cortex_a8_restore_cp15_control_reg(struct target *target) { int retval = ERROR_OK; struct cortex_a8_common *cortex_a8 = target_to_cortex_a8(target); struct armv7a_common *armv7a = target_to_armv7a(target); if (cortex_a8->cp15_control_reg != cortex_a8->cp15_control_reg_curr) { cortex_a8->cp15_control_reg_curr = cortex_a8->cp15_control_reg; /* LOG_INFO("cp15_control_reg: %8.8" PRIx32, cortex_a8->cp15_control_reg); */ retval = armv7a->arm.mcr(target, 15, 0, 0, /* op1, op2 */ 1, 0, /* CRn, CRm */ cortex_a8->cp15_control_reg); } return retval; } /* check address before cortex_a8_apb read write access with mmu on * remove apb predictible data abort */ static int cortex_a8_check_address(struct target *target, uint32_t address) { struct armv7a_common *armv7a = target_to_armv7a(target); struct cortex_a8_common *cortex_a8 = target_to_cortex_a8(target); uint32_t os_border = armv7a->armv7a_mmu.os_border; if ((address < os_border) && (armv7a->arm.core_mode == ARM_MODE_SVC)) { LOG_ERROR("%x access in userspace and target in supervisor", address); return ERROR_FAIL; } if ((address >= os_border) && (cortex_a8->curr_mode != ARM_MODE_SVC)) { dpm_modeswitch(&armv7a->dpm, ARM_MODE_SVC); cortex_a8->curr_mode = ARM_MODE_SVC; LOG_INFO("%x access in kernel space and target not in supervisor", address); return ERROR_OK; } if ((address < os_border) && (cortex_a8->curr_mode == ARM_MODE_SVC)) { dpm_modeswitch(&armv7a->dpm, ARM_MODE_ANY); cortex_a8->curr_mode = ARM_MODE_ANY; } return ERROR_OK; } /* modify cp15_control_reg in order to enable or disable mmu for : * - virt2phys address conversion * - read or write memory in phys or virt address */ static int cortex_a8_mmu_modify(struct target *target, int enable) { struct cortex_a8_common *cortex_a8 = target_to_cortex_a8(target); struct armv7a_common *armv7a = target_to_armv7a(target); int retval = ERROR_OK; if (enable) { /* if mmu enabled at target stop and mmu not enable */ if (!(cortex_a8->cp15_control_reg & 0x1U)) { LOG_ERROR("trying to enable mmu on target stopped with mmu disable"); return ERROR_FAIL; } if (!(cortex_a8->cp15_control_reg_curr & 0x1U)) { cortex_a8->cp15_control_reg_curr |= 0x1U; retval = armv7a->arm.mcr(target, 15, 0, 0, /* op1, op2 */ 1, 0, /* CRn, CRm */ cortex_a8->cp15_control_reg_curr); } } else { if (cortex_a8->cp15_control_reg_curr & 0x4U) { /* data cache is active */ cortex_a8->cp15_control_reg_curr &= ~0x4U; /* flush data cache armv7 function to be called */ if (armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache) armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache(target); } if ((cortex_a8->cp15_control_reg_curr & 0x1U)) { cortex_a8->cp15_control_reg_curr &= ~0x1U; retval = armv7a->arm.mcr(target, 15, 0, 0, /* op1, op2 */ 1, 0, /* CRn, CRm */ cortex_a8->cp15_control_reg_curr); } } return retval; } /* * Cortex-A8 Basic debug access, very low level assumes state is saved */ static int cortex_a8_init_debug_access(struct target *target) { struct armv7a_common *armv7a = target_to_armv7a(target); struct adiv5_dap *swjdp = armv7a->arm.dap; int retval; uint32_t dummy; LOG_DEBUG(" "); /* Unlocking the debug registers for modification * The debugport might be uninitialised so try twice */ retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_LOCKACCESS, 0xC5ACCE55); if (retval != ERROR_OK) { /* try again */ retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_LOCKACCESS, 0xC5ACCE55); if (retval == ERROR_OK) LOG_USER( "Locking debug access failed on first, but succeeded on second try."); } if (retval != ERROR_OK) return retval; /* Clear Sticky Power Down status Bit in PRSR to enable access to the registers in the Core Power Domain */ retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_PRSR, &dummy); if (retval != ERROR_OK) return retval; /* Enabling of instruction execution in debug mode is done in debug_entry code */ /* Resync breakpoint registers */ /* Since this is likely called from init or reset, update target state information*/ return cortex_a8_poll(target); } /* To reduce needless round-trips, pass in a pointer to the current * DSCR value. Initialize it to zero if you just need to know the * value on return from this function; or DSCR_INSTR_COMP if you * happen to know that no instruction is pending. */ static int cortex_a8_exec_opcode(struct target *target, uint32_t opcode, uint32_t *dscr_p) { uint32_t dscr; int retval; struct armv7a_common *armv7a = target_to_armv7a(target); struct adiv5_dap *swjdp = armv7a->arm.dap; dscr = dscr_p ? *dscr_p : 0; LOG_DEBUG("exec opcode 0x%08" PRIx32, opcode); /* Wait for InstrCompl bit to be set */ long long then = timeval_ms(); while ((dscr & DSCR_INSTR_COMP) == 0) { retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); if (retval != ERROR_OK) { LOG_ERROR("Could not read DSCR register, opcode = 0x%08" PRIx32, opcode); return retval; } if (timeval_ms() > then + 1000) { LOG_ERROR("Timeout waiting for cortex_a8_exec_opcode"); return ERROR_FAIL; } } retval = mem_ap_sel_write_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_ITR, opcode); if (retval != ERROR_OK) return retval; then = timeval_ms(); do { retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); if (retval != ERROR_OK) { LOG_ERROR("Could not read DSCR register"); return retval; } if (timeval_ms() > then + 1000) { LOG_ERROR("Timeout waiting for cortex_a8_exec_opcode"); return ERROR_FAIL; } } while ((dscr & DSCR_INSTR_COMP) == 0); /* Wait for InstrCompl bit to be set */ if (dscr_p) *dscr_p = dscr; return retval; } /************************************************************************** Read core register with very few exec_opcode, fast but needs work_area. This can cause problems with MMU active. **************************************************************************/ static int cortex_a8_read_regs_through_mem(struct target *target, uint32_t address, uint32_t *regfile) { int retval = ERROR_OK; struct armv7a_common *armv7a = target_to_armv7a(target); struct adiv5_dap *swjdp = armv7a->arm.dap; retval = cortex_a8_dap_read_coreregister_u32(target, regfile, 0); if (retval != ERROR_OK) return retval; retval = cortex_a8_dap_write_coreregister_u32(target, address, 0); if (retval != ERROR_OK) return retval; retval = cortex_a8_exec_opcode(target, ARMV4_5_STMIA(0, 0xFFFE, 0, 0), NULL); if (retval != ERROR_OK) return retval; retval = mem_ap_sel_read_buf_u32(swjdp, armv7a->memory_ap, (uint8_t *)(®file[1]), 4*15, address); return retval; } static int cortex_a8_dap_read_coreregister_u32(struct target *target, uint32_t *value, int regnum) { int retval = ERROR_OK; uint8_t reg = regnum&0xFF; uint32_t dscr = 0; struct armv7a_common *armv7a = target_to_armv7a(target); struct adiv5_dap *swjdp = armv7a->arm.dap; if (reg > 17) return retval; if (reg < 15) { /* Rn to DCCTX, "MCR p14, 0, Rn, c0, c5, 0" 0xEE00nE15 */ retval = cortex_a8_exec_opcode(target, ARMV4_5_MCR(14, 0, reg, 0, 5, 0), &dscr); if (retval != ERROR_OK) return retval; } else if (reg == 15) { /* "MOV r0, r15"; then move r0 to DCCTX */ retval = cortex_a8_exec_opcode(target, 0xE1A0000F, &dscr); if (retval != ERROR_OK) return retval; retval = cortex_a8_exec_opcode(target, ARMV4_5_MCR(14, 0, 0, 0, 5, 0), &dscr); if (retval != ERROR_OK) return retval; } else { /* "MRS r0, CPSR" or "MRS r0, SPSR" * then move r0 to DCCTX */ retval = cortex_a8_exec_opcode(target, ARMV4_5_MRS(0, reg & 1), &dscr); if (retval != ERROR_OK) return retval; retval = cortex_a8_exec_opcode(target, ARMV4_5_MCR(14, 0, 0, 0, 5, 0), &dscr); if (retval != ERROR_OK) return retval; } /* Wait for DTRRXfull then read DTRRTX */ long long then = timeval_ms(); while ((dscr & DSCR_DTR_TX_FULL) == 0) { retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); if (retval != ERROR_OK) return retval; if (timeval_ms() > then + 1000) { LOG_ERROR("Timeout waiting for cortex_a8_exec_opcode"); return ERROR_FAIL; } } retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DTRTX, value); LOG_DEBUG("read DCC 0x%08" PRIx32, *value); return retval; } static int cortex_a8_dap_write_coreregister_u32(struct target *target, uint32_t value, int regnum) { int retval = ERROR_OK; uint8_t Rd = regnum&0xFF; uint32_t dscr; struct armv7a_common *armv7a = target_to_armv7a(target); struct adiv5_dap *swjdp = armv7a->arm.dap; LOG_DEBUG("register %i, value 0x%08" PRIx32, regnum, value); /* Check that DCCRX is not full */ retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); if (retval != ERROR_OK) return retval; if (dscr & DSCR_DTR_RX_FULL) { LOG_ERROR("DSCR_DTR_RX_FULL, dscr 0x%08" PRIx32, dscr); /* Clear DCCRX with MRC(p14, 0, Rd, c0, c5, 0), opcode 0xEE100E15 */ retval = cortex_a8_exec_opcode(target, ARMV4_5_MRC(14, 0, 0, 0, 5, 0), &dscr); if (retval != ERROR_OK) return retval; } if (Rd > 17) return retval; /* Write DTRRX ... sets DSCR.DTRRXfull but exec_opcode() won't care */ LOG_DEBUG("write DCC 0x%08" PRIx32, value); retval = mem_ap_sel_write_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DTRRX, value); if (retval != ERROR_OK) return retval; if (Rd < 15) { /* DCCRX to Rn, "MRC p14, 0, Rn, c0, c5, 0", 0xEE10nE15 */ retval = cortex_a8_exec_opcode(target, ARMV4_5_MRC(14, 0, Rd, 0, 5, 0), &dscr); if (retval != ERROR_OK) return retval; } else if (Rd == 15) { /* DCCRX to R0, "MRC p14, 0, R0, c0, c5, 0", 0xEE100E15 * then "mov r15, r0" */ retval = cortex_a8_exec_opcode(target, ARMV4_5_MRC(14, 0, 0, 0, 5, 0), &dscr); if (retval != ERROR_OK) return retval; retval = cortex_a8_exec_opcode(target, 0xE1A0F000, &dscr); if (retval != ERROR_OK) return retval; } else { /* DCCRX to R0, "MRC p14, 0, R0, c0, c5, 0", 0xEE100E15 * then "MSR CPSR_cxsf, r0" or "MSR SPSR_cxsf, r0" (all fields) */ retval = cortex_a8_exec_opcode(target, ARMV4_5_MRC(14, 0, 0, 0, 5, 0), &dscr); if (retval != ERROR_OK) return retval; retval = cortex_a8_exec_opcode(target, ARMV4_5_MSR_GP(0, 0xF, Rd & 1), &dscr); if (retval != ERROR_OK) return retval; /* "Prefetch flush" after modifying execution status in CPSR */ if (Rd == 16) { retval = cortex_a8_exec_opcode(target, ARMV4_5_MCR(15, 0, 0, 7, 5, 4), &dscr); if (retval != ERROR_OK) return retval; } } return retval; } /* Write to memory mapped registers directly with no cache or mmu handling */ static int cortex_a8_dap_write_memap_register_u32(struct target *target, uint32_t address, uint32_t value) { int retval; struct armv7a_common *armv7a = target_to_armv7a(target); struct adiv5_dap *swjdp = armv7a->arm.dap; retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, address, value); return retval; } /* * Cortex-A8 implementation of Debug Programmer's Model * * NOTE the invariant: these routines return with DSCR_INSTR_COMP set, * so there's no need to poll for it before executing an instruction. * * NOTE that in several of these cases the "stall" mode might be useful. * It'd let us queue a few operations together... prepare/finish might * be the places to enable/disable that mode. */ static inline struct cortex_a8_common *dpm_to_a8(struct arm_dpm *dpm) { return container_of(dpm, struct cortex_a8_common, armv7a_common.dpm); } static int cortex_a8_write_dcc(struct cortex_a8_common *a8, uint32_t data) { LOG_DEBUG("write DCC 0x%08" PRIx32, data); return mem_ap_sel_write_u32(a8->armv7a_common.arm.dap, a8->armv7a_common.debug_ap, a8->armv7a_common.debug_base + CPUDBG_DTRRX, data); } static int cortex_a8_read_dcc(struct cortex_a8_common *a8, uint32_t *data, uint32_t *dscr_p) { struct adiv5_dap *swjdp = a8->armv7a_common.arm.dap; uint32_t dscr = DSCR_INSTR_COMP; int retval; if (dscr_p) dscr = *dscr_p; /* Wait for DTRRXfull */ long long then = timeval_ms(); while ((dscr & DSCR_DTR_TX_FULL) == 0) { retval = mem_ap_sel_read_atomic_u32(swjdp, a8->armv7a_common.debug_ap, a8->armv7a_common.debug_base + CPUDBG_DSCR, &dscr); if (retval != ERROR_OK) return retval; if (timeval_ms() > then + 1000) { LOG_ERROR("Timeout waiting for read dcc"); return ERROR_FAIL; } } retval = mem_ap_sel_read_atomic_u32(swjdp, a8->armv7a_common.debug_ap, a8->armv7a_common.debug_base + CPUDBG_DTRTX, data); if (retval != ERROR_OK) return retval; /* LOG_DEBUG("read DCC 0x%08" PRIx32, *data); */ if (dscr_p) *dscr_p = dscr; return retval; } static int cortex_a8_dpm_prepare(struct arm_dpm *dpm) { struct cortex_a8_common *a8 = dpm_to_a8(dpm); struct adiv5_dap *swjdp = a8->armv7a_common.arm.dap; uint32_t dscr; int retval; /* set up invariant: INSTR_COMP is set after ever DPM operation */ long long then = timeval_ms(); for (;; ) { retval = mem_ap_sel_read_atomic_u32(swjdp, a8->armv7a_common.debug_ap, a8->armv7a_common.debug_base + CPUDBG_DSCR, &dscr); if (retval != ERROR_OK) return retval; if ((dscr & DSCR_INSTR_COMP) != 0) break; if (timeval_ms() > then + 1000) { LOG_ERROR("Timeout waiting for dpm prepare"); return ERROR_FAIL; } } /* this "should never happen" ... */ if (dscr & DSCR_DTR_RX_FULL) { LOG_ERROR("DSCR_DTR_RX_FULL, dscr 0x%08" PRIx32, dscr); /* Clear DCCRX */ retval = cortex_a8_exec_opcode( a8->armv7a_common.arm.target, ARMV4_5_MRC(14, 0, 0, 0, 5, 0), &dscr); if (retval != ERROR_OK) return retval; } return retval; } static int cortex_a8_dpm_finish(struct arm_dpm *dpm) { /* REVISIT what could be done here? */ return ERROR_OK; } static int cortex_a8_instr_write_data_dcc(struct arm_dpm *dpm, uint32_t opcode, uint32_t data) { struct cortex_a8_common *a8 = dpm_to_a8(dpm); int retval; uint32_t dscr = DSCR_INSTR_COMP; retval = cortex_a8_write_dcc(a8, data); if (retval != ERROR_OK) return retval; return cortex_a8_exec_opcode( a8->armv7a_common.arm.target, opcode, &dscr); } static int cortex_a8_instr_write_data_r0(struct arm_dpm *dpm, uint32_t opcode, uint32_t data) { struct cortex_a8_common *a8 = dpm_to_a8(dpm); uint32_t dscr = DSCR_INSTR_COMP; int retval; retval = cortex_a8_write_dcc(a8, data); if (retval != ERROR_OK) return retval; /* DCCRX to R0, "MCR p14, 0, R0, c0, c5, 0", 0xEE000E15 */ retval = cortex_a8_exec_opcode( a8->armv7a_common.arm.target, ARMV4_5_MRC(14, 0, 0, 0, 5, 0), &dscr); if (retval != ERROR_OK) return retval; /* then the opcode, taking data from R0 */ retval = cortex_a8_exec_opcode( a8->armv7a_common.arm.target, opcode, &dscr); return retval; } static int cortex_a8_instr_cpsr_sync(struct arm_dpm *dpm) { struct target *target = dpm->arm->target; uint32_t dscr = DSCR_INSTR_COMP; /* "Prefetch flush" after modifying execution status in CPSR */ return cortex_a8_exec_opcode(target, ARMV4_5_MCR(15, 0, 0, 7, 5, 4), &dscr); } static int cortex_a8_instr_read_data_dcc(struct arm_dpm *dpm, uint32_t opcode, uint32_t *data) { struct cortex_a8_common *a8 = dpm_to_a8(dpm); int retval; uint32_t dscr = DSCR_INSTR_COMP; /* the opcode, writing data to DCC */ retval = cortex_a8_exec_opcode( a8->armv7a_common.arm.target, opcode, &dscr); if (retval != ERROR_OK) return retval; return cortex_a8_read_dcc(a8, data, &dscr); } static int cortex_a8_instr_read_data_r0(struct arm_dpm *dpm, uint32_t opcode, uint32_t *data) { struct cortex_a8_common *a8 = dpm_to_a8(dpm); uint32_t dscr = DSCR_INSTR_COMP; int retval; /* the opcode, writing data to R0 */ retval = cortex_a8_exec_opcode( a8->armv7a_common.arm.target, opcode, &dscr); if (retval != ERROR_OK) return retval; /* write R0 to DCC */ retval = cortex_a8_exec_opcode( a8->armv7a_common.arm.target, ARMV4_5_MCR(14, 0, 0, 0, 5, 0), &dscr); if (retval != ERROR_OK) return retval; return cortex_a8_read_dcc(a8, data, &dscr); } static int cortex_a8_bpwp_enable(struct arm_dpm *dpm, unsigned index_t, uint32_t addr, uint32_t control) { struct cortex_a8_common *a8 = dpm_to_a8(dpm); uint32_t vr = a8->armv7a_common.debug_base; uint32_t cr = a8->armv7a_common.debug_base; int retval; switch (index_t) { case 0 ... 15: /* breakpoints */ vr += CPUDBG_BVR_BASE; cr += CPUDBG_BCR_BASE; break; case 16 ... 31: /* watchpoints */ vr += CPUDBG_WVR_BASE; cr += CPUDBG_WCR_BASE; index_t -= 16; break; default: return ERROR_FAIL; } vr += 4 * index_t; cr += 4 * index_t; LOG_DEBUG("A8: bpwp enable, vr %08x cr %08x", (unsigned) vr, (unsigned) cr); retval = cortex_a8_dap_write_memap_register_u32(dpm->arm->target, vr, addr); if (retval != ERROR_OK) return retval; retval = cortex_a8_dap_write_memap_register_u32(dpm->arm->target, cr, control); return retval; } static int cortex_a8_bpwp_disable(struct arm_dpm *dpm, unsigned index_t) { struct cortex_a8_common *a8 = dpm_to_a8(dpm); uint32_t cr; switch (index_t) { case 0 ... 15: cr = a8->armv7a_common.debug_base + CPUDBG_BCR_BASE; break; case 16 ... 31: cr = a8->armv7a_common.debug_base + CPUDBG_WCR_BASE; index_t -= 16; break; default: return ERROR_FAIL; } cr += 4 * index_t; LOG_DEBUG("A8: bpwp disable, cr %08x", (unsigned) cr); /* clear control register */ return cortex_a8_dap_write_memap_register_u32(dpm->arm->target, cr, 0); } static int cortex_a8_dpm_setup(struct cortex_a8_common *a8, uint32_t didr) { struct arm_dpm *dpm = &a8->armv7a_common.dpm; int retval; dpm->arm = &a8->armv7a_common.arm; dpm->didr = didr; dpm->prepare = cortex_a8_dpm_prepare; dpm->finish = cortex_a8_dpm_finish; dpm->instr_write_data_dcc = cortex_a8_instr_write_data_dcc; dpm->instr_write_data_r0 = cortex_a8_instr_write_data_r0; dpm->instr_cpsr_sync = cortex_a8_instr_cpsr_sync; dpm->instr_read_data_dcc = cortex_a8_instr_read_data_dcc; dpm->instr_read_data_r0 = cortex_a8_instr_read_data_r0; dpm->bpwp_enable = cortex_a8_bpwp_enable; dpm->bpwp_disable = cortex_a8_bpwp_disable; retval = arm_dpm_setup(dpm); if (retval == ERROR_OK) retval = arm_dpm_initialize(dpm); return retval; } static struct target *get_cortex_a8(struct target *target, int32_t coreid) { struct target_list *head; struct target *curr; head = target->head; while (head != (struct target_list *)NULL) { curr = head->target; if ((curr->coreid == coreid) && (curr->state == TARGET_HALTED)) return curr; head = head->next; } return target; } static int cortex_a8_halt(struct target *target); static int cortex_a8_halt_smp(struct target *target) { int retval = 0; struct target_list *head; struct target *curr; head = target->head; while (head != (struct target_list *)NULL) { curr = head->target; if ((curr != target) && (curr->state != TARGET_HALTED)) retval += cortex_a8_halt(curr); head = head->next; } return retval; } static int update_halt_gdb(struct target *target) { int retval = 0; if (target->gdb_service->core[0] == -1) { target->gdb_service->target = target; target->gdb_service->core[0] = target->coreid; retval += cortex_a8_halt_smp(target); } return retval; } /* * Cortex-A8 Run control */ static int cortex_a8_poll(struct target *target) { int retval = ERROR_OK; uint32_t dscr; struct cortex_a8_common *cortex_a8 = target_to_cortex_a8(target); struct armv7a_common *armv7a = &cortex_a8->armv7a_common; struct adiv5_dap *swjdp = armv7a->arm.dap; enum target_state prev_target_state = target->state; /* toggle to another core is done by gdb as follow */ /* maint packet J core_id */ /* continue */ /* the next polling trigger an halt event sent to gdb */ if ((target->state == TARGET_HALTED) && (target->smp) && (target->gdb_service) && (target->gdb_service->target == NULL)) { target->gdb_service->target = get_cortex_a8(target, target->gdb_service->core[1]); target_call_event_callbacks(target, TARGET_EVENT_HALTED); return retval; } retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); if (retval != ERROR_OK) return retval; cortex_a8->cpudbg_dscr = dscr; if (DSCR_RUN_MODE(dscr) == (DSCR_CORE_HALTED | DSCR_CORE_RESTARTED)) { if (prev_target_state != TARGET_HALTED) { /* We have a halting debug event */ LOG_DEBUG("Target halted"); target->state = TARGET_HALTED; if ((prev_target_state == TARGET_RUNNING) || (prev_target_state == TARGET_UNKNOWN) || (prev_target_state == TARGET_RESET)) { retval = cortex_a8_debug_entry(target); if (retval != ERROR_OK) return retval; if (target->smp) { retval = update_halt_gdb(target); if (retval != ERROR_OK) return retval; } target_call_event_callbacks(target, TARGET_EVENT_HALTED); } if (prev_target_state == TARGET_DEBUG_RUNNING) { LOG_DEBUG(" "); retval = cortex_a8_debug_entry(target); if (retval != ERROR_OK) return retval; if (target->smp) { retval = update_halt_gdb(target); if (retval != ERROR_OK) return retval; } target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); } } } else if (DSCR_RUN_MODE(dscr) == DSCR_CORE_RESTARTED) target->state = TARGET_RUNNING; else { LOG_DEBUG("Unknown target state dscr = 0x%08" PRIx32, dscr); target->state = TARGET_UNKNOWN; } return retval; } static int cortex_a8_halt(struct target *target) { int retval = ERROR_OK; uint32_t dscr; struct armv7a_common *armv7a = target_to_armv7a(target); struct adiv5_dap *swjdp = armv7a->arm.dap; /* * Tell the core to be halted by writing DRCR with 0x1 * and then wait for the core to be halted. */ retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DRCR, DRCR_HALT); if (retval != ERROR_OK) return retval; /* * enter halting debug mode */ retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); if (retval != ERROR_OK) return retval; retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, dscr | DSCR_HALT_DBG_MODE); if (retval != ERROR_OK) return retval; long long then = timeval_ms(); for (;; ) { retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); if (retval != ERROR_OK) return retval; if ((dscr & DSCR_CORE_HALTED) != 0) break; if (timeval_ms() > then + 1000) { LOG_ERROR("Timeout waiting for halt"); return ERROR_FAIL; } } target->debug_reason = DBG_REASON_DBGRQ; return ERROR_OK; } static int cortex_a8_internal_restore(struct target *target, int current, uint32_t *address, int handle_breakpoints, int debug_execution) { struct armv7a_common *armv7a = target_to_armv7a(target); struct arm *arm = &armv7a->arm; int retval; uint32_t resume_pc; if (!debug_execution) target_free_all_working_areas(target); #if 0 if (debug_execution) { /* Disable interrupts */ /* We disable interrupts in the PRIMASK register instead of * masking with C_MASKINTS, * This is probably the same issue as Cortex-M3 Errata 377493: * C_MASKINTS in parallel with disabled interrupts can cause * local faults to not be taken. */ buf_set_u32(armv7m->core_cache->reg_list[ARMV7M_PRIMASK].value, 0, 32, 1); armv7m->core_cache->reg_list[ARMV7M_PRIMASK].dirty = 1; armv7m->core_cache->reg_list[ARMV7M_PRIMASK].valid = 1; /* Make sure we are in Thumb mode */ buf_set_u32(armv7m->core_cache->reg_list[ARMV7M_xPSR].value, 0, 32, buf_get_u32(armv7m->core_cache->reg_list[ARMV7M_xPSR].value, 0, 32) | (1 << 24)); armv7m->core_cache->reg_list[ARMV7M_xPSR].dirty = 1; armv7m->core_cache->reg_list[ARMV7M_xPSR].valid = 1; } #endif /* current = 1: continue on current pc, otherwise continue at
*/ resume_pc = buf_get_u32(arm->pc->value, 0, 32); if (!current) resume_pc = *address; else *address = resume_pc; /* Make sure that the Armv7 gdb thumb fixups does not * kill the return address */ switch (arm->core_state) { case ARM_STATE_ARM: resume_pc &= 0xFFFFFFFC; break; case ARM_STATE_THUMB: case ARM_STATE_THUMB_EE: /* When the return address is loaded into PC * bit 0 must be 1 to stay in Thumb state */ resume_pc |= 0x1; break; case ARM_STATE_JAZELLE: LOG_ERROR("How do I resume into Jazelle state??"); return ERROR_FAIL; } LOG_DEBUG("resume pc = 0x%08" PRIx32, resume_pc); buf_set_u32(arm->pc->value, 0, 32, resume_pc); arm->pc->dirty = 1; arm->pc->valid = 1; /* restore dpm_mode at system halt */ dpm_modeswitch(&armv7a->dpm, ARM_MODE_ANY); /* called it now before restoring context because it uses cpu * register r0 for restoring cp15 control register */ retval = cortex_a8_restore_cp15_control_reg(target); if (retval != ERROR_OK) return retval; retval = cortex_a8_restore_context(target, handle_breakpoints); if (retval != ERROR_OK) return retval; target->debug_reason = DBG_REASON_NOTHALTED; target->state = TARGET_RUNNING; /* registers are now invalid */ register_cache_invalidate(arm->core_cache); #if 0 /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) { /* Single step past breakpoint at current address */ breakpoint = breakpoint_find(target, resume_pc); if (breakpoint) { LOG_DEBUG("unset breakpoint at 0x%8.8x", breakpoint->address); cortex_m3_unset_breakpoint(target, breakpoint); cortex_m3_single_step_core(target); cortex_m3_set_breakpoint(target, breakpoint); } } #endif return retval; } static int cortex_a8_internal_restart(struct target *target) { struct armv7a_common *armv7a = target_to_armv7a(target); struct arm *arm = &armv7a->arm; struct adiv5_dap *swjdp = arm->dap; int retval; uint32_t dscr; /* * * Restart core and wait for it to be started. Clear ITRen and sticky * * exception flags: see ARMv7 ARM, C5.9. * * REVISIT: for single stepping, we probably want to * disable IRQs by default, with optional override... */ retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); if (retval != ERROR_OK) return retval; if ((dscr & DSCR_INSTR_COMP) == 0) LOG_ERROR("DSCR InstrCompl must be set before leaving debug!"); retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, dscr & ~DSCR_ITR_EN); if (retval != ERROR_OK) return retval; retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DRCR, DRCR_RESTART | DRCR_CLEAR_EXCEPTIONS); if (retval != ERROR_OK) return retval; long long then = timeval_ms(); for (;; ) { retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); if (retval != ERROR_OK) return retval; if ((dscr & DSCR_CORE_RESTARTED) != 0) break; if (timeval_ms() > then + 1000) { LOG_ERROR("Timeout waiting for resume"); return ERROR_FAIL; } } target->debug_reason = DBG_REASON_NOTHALTED; target->state = TARGET_RUNNING; /* registers are now invalid */ register_cache_invalidate(arm->core_cache); return ERROR_OK; } static int cortex_a8_restore_smp(struct target *target, int handle_breakpoints) { int retval = 0; struct target_list *head; struct target *curr; uint32_t address; head = target->head; while (head != (struct target_list *)NULL) { curr = head->target; if ((curr != target) && (curr->state != TARGET_RUNNING)) { /* resume current address , not in step mode */ retval += cortex_a8_internal_restore(curr, 1, &address, handle_breakpoints, 0); retval += cortex_a8_internal_restart(curr); } head = head->next; } return retval; } static int cortex_a8_resume(struct target *target, int current, uint32_t address, int handle_breakpoints, int debug_execution) { int retval = 0; /* dummy resume for smp toggle in order to reduce gdb impact */ if ((target->smp) && (target->gdb_service->core[1] != -1)) { /* simulate a start and halt of target */ target->gdb_service->target = NULL; target->gdb_service->core[0] = target->gdb_service->core[1]; /* fake resume at next poll we play the target core[1], see poll*/ target_call_event_callbacks(target, TARGET_EVENT_RESUMED); return 0; } cortex_a8_internal_restore(target, current, &address, handle_breakpoints, debug_execution); if (target->smp) { target->gdb_service->core[0] = -1; retval = cortex_a8_restore_smp(target, handle_breakpoints); if (retval != ERROR_OK) return retval; } cortex_a8_internal_restart(target); if (!debug_execution) { target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); LOG_DEBUG("target resumed at 0x%" PRIx32, address); } else { target->state = TARGET_DEBUG_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); LOG_DEBUG("target debug resumed at 0x%" PRIx32, address); } return ERROR_OK; } static int cortex_a8_debug_entry(struct target *target) { int i; uint32_t regfile[16], cpsr, dscr; int retval = ERROR_OK; struct working_area *regfile_working_area = NULL; struct cortex_a8_common *cortex_a8 = target_to_cortex_a8(target); struct armv7a_common *armv7a = target_to_armv7a(target); struct arm *arm = &armv7a->arm; struct adiv5_dap *swjdp = armv7a->arm.dap; struct reg *reg; LOG_DEBUG("dscr = 0x%08" PRIx32, cortex_a8->cpudbg_dscr); /* REVISIT surely we should not re-read DSCR !! */ retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); if (retval != ERROR_OK) return retval; /* REVISIT see A8 TRM 12.11.4 steps 2..3 -- make sure that any * imprecise data aborts get discarded by issuing a Data * Synchronization Barrier: ARMV4_5_MCR(15, 0, 0, 7, 10, 4). */ /* Enable the ITR execution once we are in debug mode */ dscr |= DSCR_ITR_EN; retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, dscr); if (retval != ERROR_OK) return retval; /* Examine debug reason */ arm_dpm_report_dscr(&armv7a->dpm, cortex_a8->cpudbg_dscr); /* save address of instruction that triggered the watchpoint? */ if (target->debug_reason == DBG_REASON_WATCHPOINT) { uint32_t wfar; retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_WFAR, &wfar); if (retval != ERROR_OK) return retval; arm_dpm_report_wfar(&armv7a->dpm, wfar); } /* REVISIT fast_reg_read is never set ... */ /* Examine target state and mode */ if (cortex_a8->fast_reg_read) target_alloc_working_area(target, 64, ®file_working_area); /* First load register acessible through core debug port*/ if (!regfile_working_area) retval = arm_dpm_read_current_registers(&armv7a->dpm); else { retval = cortex_a8_read_regs_through_mem(target, regfile_working_area->address, regfile); target_free_working_area(target, regfile_working_area); if (retval != ERROR_OK) return retval; /* read Current PSR */ retval = cortex_a8_dap_read_coreregister_u32(target, &cpsr, 16); /* store current cpsr */ if (retval != ERROR_OK) return retval; LOG_DEBUG("cpsr: %8.8" PRIx32, cpsr); arm_set_cpsr(arm, cpsr); /* update cache */ for (i = 0; i <= ARM_PC; i++) { reg = arm_reg_current(arm, i); buf_set_u32(reg->value, 0, 32, regfile[i]); reg->valid = 1; reg->dirty = 0; } /* Fixup PC Resume Address */ if (cpsr & (1 << 5)) { /* T bit set for Thumb or ThumbEE state */ regfile[ARM_PC] -= 4; } else { /* ARM state */ regfile[ARM_PC] -= 8; } reg = arm->pc; buf_set_u32(reg->value, 0, 32, regfile[ARM_PC]); reg->dirty = reg->valid; } #if 0 /* TODO, Move this */ uint32_t cp15_control_register, cp15_cacr, cp15_nacr; cortex_a8_read_cp(target, &cp15_control_register, 15, 0, 1, 0, 0); LOG_DEBUG("cp15_control_register = 0x%08x", cp15_control_register); cortex_a8_read_cp(target, &cp15_cacr, 15, 0, 1, 0, 2); LOG_DEBUG("cp15 Coprocessor Access Control Register = 0x%08x", cp15_cacr); cortex_a8_read_cp(target, &cp15_nacr, 15, 0, 1, 1, 2); LOG_DEBUG("cp15 Nonsecure Access Control Register = 0x%08x", cp15_nacr); #endif /* Are we in an exception handler */ /* armv4_5->exception_number = 0; */ if (armv7a->post_debug_entry) { retval = armv7a->post_debug_entry(target); if (retval != ERROR_OK) return retval; } return retval; } static int cortex_a8_post_debug_entry(struct target *target) { struct cortex_a8_common *cortex_a8 = target_to_cortex_a8(target); struct armv7a_common *armv7a = &cortex_a8->armv7a_common; int retval; /* MRC p15,0,,c1,c0,0 ; Read CP15 System Control Register */ retval = armv7a->arm.mrc(target, 15, 0, 0, /* op1, op2 */ 1, 0, /* CRn, CRm */ &cortex_a8->cp15_control_reg); if (retval != ERROR_OK) return retval; LOG_DEBUG("cp15_control_reg: %8.8" PRIx32, cortex_a8->cp15_control_reg); cortex_a8->cp15_control_reg_curr = cortex_a8->cp15_control_reg; if (armv7a->armv7a_mmu.armv7a_cache.ctype == -1) armv7a_identify_cache(target); if (armv7a->is_armv7r) { armv7a->armv7a_mmu.mmu_enabled = 0; } else { armv7a->armv7a_mmu.mmu_enabled = (cortex_a8->cp15_control_reg & 0x1U) ? 1 : 0; } armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled = (cortex_a8->cp15_control_reg & 0x4U) ? 1 : 0; armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled = (cortex_a8->cp15_control_reg & 0x1000U) ? 1 : 0; cortex_a8->curr_mode = armv7a->arm.core_mode; return ERROR_OK; } static int cortex_a8_step(struct target *target, int current, uint32_t address, int handle_breakpoints) { struct armv7a_common *armv7a = target_to_armv7a(target); struct arm *arm = &armv7a->arm; struct breakpoint *breakpoint = NULL; struct breakpoint stepbreakpoint; struct reg *r; int retval; if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* current = 1: continue on current pc, otherwise continue at
*/ r = arm->pc; if (!current) buf_set_u32(r->value, 0, 32, address); else address = buf_get_u32(r->value, 0, 32); /* The front-end may request us not to handle breakpoints. * But since Cortex-A8 uses breakpoint for single step, * we MUST handle breakpoints. */ handle_breakpoints = 1; if (handle_breakpoints) { breakpoint = breakpoint_find(target, address); if (breakpoint) cortex_a8_unset_breakpoint(target, breakpoint); } /* Setup single step breakpoint */ stepbreakpoint.address = address; stepbreakpoint.length = (arm->core_state == ARM_STATE_THUMB) ? 2 : 4; stepbreakpoint.type = BKPT_HARD; stepbreakpoint.set = 0; /* Break on IVA mismatch */ cortex_a8_set_breakpoint(target, &stepbreakpoint, 0x04); target->debug_reason = DBG_REASON_SINGLESTEP; retval = cortex_a8_resume(target, 1, address, 0, 0); if (retval != ERROR_OK) return retval; long long then = timeval_ms(); while (target->state != TARGET_HALTED) { retval = cortex_a8_poll(target); if (retval != ERROR_OK) return retval; if (timeval_ms() > then + 1000) { LOG_ERROR("timeout waiting for target halt"); return ERROR_FAIL; } } cortex_a8_unset_breakpoint(target, &stepbreakpoint); target->debug_reason = DBG_REASON_BREAKPOINT; if (breakpoint) cortex_a8_set_breakpoint(target, breakpoint, 0); if (target->state != TARGET_HALTED) LOG_DEBUG("target stepped"); return ERROR_OK; } static int cortex_a8_restore_context(struct target *target, bool bpwp) { struct armv7a_common *armv7a = target_to_armv7a(target); LOG_DEBUG(" "); if (armv7a->pre_restore_context) armv7a->pre_restore_context(target); return arm_dpm_write_dirty_registers(&armv7a->dpm, bpwp); } /* * Cortex-A8 Breakpoint and watchpoint functions */ /* Setup hardware Breakpoint Register Pair */ static int cortex_a8_set_breakpoint(struct target *target, struct breakpoint *breakpoint, uint8_t matchmode) { int retval; int brp_i = 0; uint32_t control; uint8_t byte_addr_select = 0x0F; struct cortex_a8_common *cortex_a8 = target_to_cortex_a8(target); struct armv7a_common *armv7a = &cortex_a8->armv7a_common; struct cortex_a8_brp *brp_list = cortex_a8->brp_list; if (breakpoint->set) { LOG_WARNING("breakpoint already set"); return ERROR_OK; } if (breakpoint->type == BKPT_HARD) { while (brp_list[brp_i].used && (brp_i < cortex_a8->brp_num)) brp_i++; if (brp_i >= cortex_a8->brp_num) { LOG_ERROR("ERROR Can not find free Breakpoint Register Pair"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } breakpoint->set = brp_i + 1; if (breakpoint->length == 2) byte_addr_select = (3 << (breakpoint->address & 0x02)); control = ((matchmode & 0x7) << 20) | (byte_addr_select << 5) | (3 << 1) | 1; brp_list[brp_i].used = 1; brp_list[brp_i].value = (breakpoint->address & 0xFFFFFFFC); brp_list[brp_i].control = control; retval = cortex_a8_dap_write_memap_register_u32(target, armv7a->debug_base + CPUDBG_BVR_BASE + 4 * brp_list[brp_i].BRPn, brp_list[brp_i].value); if (retval != ERROR_OK) return retval; retval = cortex_a8_dap_write_memap_register_u32(target, armv7a->debug_base + CPUDBG_BCR_BASE + 4 * brp_list[brp_i].BRPn, brp_list[brp_i].control); if (retval != ERROR_OK) return retval; LOG_DEBUG("brp %i control 0x%0" PRIx32 " value 0x%0" PRIx32, brp_i, brp_list[brp_i].control, brp_list[brp_i].value); } else if (breakpoint->type == BKPT_SOFT) { uint8_t code[4]; if (breakpoint->length == 2) buf_set_u32(code, 0, 32, ARMV5_T_BKPT(0x11)); else buf_set_u32(code, 0, 32, ARMV5_BKPT(0x11)); retval = target_read_memory(target, breakpoint->address & 0xFFFFFFFE, breakpoint->length, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; retval = target_write_memory(target, breakpoint->address & 0xFFFFFFFE, breakpoint->length, 1, code); if (retval != ERROR_OK) return retval; breakpoint->set = 0x11; /* Any nice value but 0 */ } return ERROR_OK; } static int cortex_a8_set_context_breakpoint(struct target *target, struct breakpoint *breakpoint, uint8_t matchmode) { int retval = ERROR_FAIL; int brp_i = 0; uint32_t control; uint8_t byte_addr_select = 0x0F; struct cortex_a8_common *cortex_a8 = target_to_cortex_a8(target); struct armv7a_common *armv7a = &cortex_a8->armv7a_common; struct cortex_a8_brp *brp_list = cortex_a8->brp_list; if (breakpoint->set) { LOG_WARNING("breakpoint already set"); return retval; } /*check available context BRPs*/ while ((brp_list[brp_i].used || (brp_list[brp_i].type != BRP_CONTEXT)) && (brp_i < cortex_a8->brp_num)) brp_i++; if (brp_i >= cortex_a8->brp_num) { LOG_ERROR("ERROR Can not find free Breakpoint Register Pair"); return ERROR_FAIL; } breakpoint->set = brp_i + 1; control = ((matchmode & 0x7) << 20) | (byte_addr_select << 5) | (3 << 1) | 1; brp_list[brp_i].used = 1; brp_list[brp_i].value = (breakpoint->asid); brp_list[brp_i].control = control; retval = cortex_a8_dap_write_memap_register_u32(target, armv7a->debug_base + CPUDBG_BVR_BASE + 4 * brp_list[brp_i].BRPn, brp_list[brp_i].value); if (retval != ERROR_OK) return retval; retval = cortex_a8_dap_write_memap_register_u32(target, armv7a->debug_base + CPUDBG_BCR_BASE + 4 * brp_list[brp_i].BRPn, brp_list[brp_i].control); if (retval != ERROR_OK) return retval; LOG_DEBUG("brp %i control 0x%0" PRIx32 " value 0x%0" PRIx32, brp_i, brp_list[brp_i].control, brp_list[brp_i].value); return ERROR_OK; } static int cortex_a8_set_hybrid_breakpoint(struct target *target, struct breakpoint *breakpoint) { int retval = ERROR_FAIL; int brp_1 = 0; /* holds the contextID pair */ int brp_2 = 0; /* holds the IVA pair */ uint32_t control_CTX, control_IVA; uint8_t CTX_byte_addr_select = 0x0F; uint8_t IVA_byte_addr_select = 0x0F; uint8_t CTX_machmode = 0x03; uint8_t IVA_machmode = 0x01; struct cortex_a8_common *cortex_a8 = target_to_cortex_a8(target); struct armv7a_common *armv7a = &cortex_a8->armv7a_common; struct cortex_a8_brp *brp_list = cortex_a8->brp_list; if (breakpoint->set) { LOG_WARNING("breakpoint already set"); return retval; } /*check available context BRPs*/ while ((brp_list[brp_1].used || (brp_list[brp_1].type != BRP_CONTEXT)) && (brp_1 < cortex_a8->brp_num)) brp_1++; printf("brp(CTX) found num: %d\n", brp_1); if (brp_1 >= cortex_a8->brp_num) { LOG_ERROR("ERROR Can not find free Breakpoint Register Pair"); return ERROR_FAIL; } while ((brp_list[brp_2].used || (brp_list[brp_2].type != BRP_NORMAL)) && (brp_2 < cortex_a8->brp_num)) brp_2++; printf("brp(IVA) found num: %d\n", brp_2); if (brp_2 >= cortex_a8->brp_num) { LOG_ERROR("ERROR Can not find free Breakpoint Register Pair"); return ERROR_FAIL; } breakpoint->set = brp_1 + 1; breakpoint->linked_BRP = brp_2; control_CTX = ((CTX_machmode & 0x7) << 20) | (brp_2 << 16) | (0 << 14) | (CTX_byte_addr_select << 5) | (3 << 1) | 1; brp_list[brp_1].used = 1; brp_list[brp_1].value = (breakpoint->asid); brp_list[brp_1].control = control_CTX; retval = cortex_a8_dap_write_memap_register_u32(target, armv7a->debug_base + CPUDBG_BVR_BASE + 4 * brp_list[brp_1].BRPn, brp_list[brp_1].value); if (retval != ERROR_OK) return retval; retval = cortex_a8_dap_write_memap_register_u32(target, armv7a->debug_base + CPUDBG_BCR_BASE + 4 * brp_list[brp_1].BRPn, brp_list[brp_1].control); if (retval != ERROR_OK) return retval; control_IVA = ((IVA_machmode & 0x7) << 20) | (brp_1 << 16) | (IVA_byte_addr_select << 5) | (3 << 1) | 1; brp_list[brp_2].used = 1; brp_list[brp_2].value = (breakpoint->address & 0xFFFFFFFC); brp_list[brp_2].control = control_IVA; retval = cortex_a8_dap_write_memap_register_u32(target, armv7a->debug_base + CPUDBG_BVR_BASE + 4 * brp_list[brp_2].BRPn, brp_list[brp_2].value); if (retval != ERROR_OK) return retval; retval = cortex_a8_dap_write_memap_register_u32(target, armv7a->debug_base + CPUDBG_BCR_BASE + 4 * brp_list[brp_2].BRPn, brp_list[brp_2].control); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int cortex_a8_unset_breakpoint(struct target *target, struct breakpoint *breakpoint) { int retval; struct cortex_a8_common *cortex_a8 = target_to_cortex_a8(target); struct armv7a_common *armv7a = &cortex_a8->armv7a_common; struct cortex_a8_brp *brp_list = cortex_a8->brp_list; if (!breakpoint->set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } if (breakpoint->type == BKPT_HARD) { if ((breakpoint->address != 0) && (breakpoint->asid != 0)) { int brp_i = breakpoint->set - 1; int brp_j = breakpoint->linked_BRP; if ((brp_i < 0) || (brp_i >= cortex_a8->brp_num)) { LOG_DEBUG("Invalid BRP number in breakpoint"); return ERROR_OK; } LOG_DEBUG("rbp %i control 0x%0" PRIx32 " value 0x%0" PRIx32, brp_i, brp_list[brp_i].control, brp_list[brp_i].value); brp_list[brp_i].used = 0; brp_list[brp_i].value = 0; brp_list[brp_i].control = 0; retval = cortex_a8_dap_write_memap_register_u32(target, armv7a->debug_base + CPUDBG_BCR_BASE + 4 * brp_list[brp_i].BRPn, brp_list[brp_i].control); if (retval != ERROR_OK) return retval; retval = cortex_a8_dap_write_memap_register_u32(target, armv7a->debug_base + CPUDBG_BVR_BASE + 4 * brp_list[brp_i].BRPn, brp_list[brp_i].value); if (retval != ERROR_OK) return retval; if ((brp_j < 0) || (brp_j >= cortex_a8->brp_num)) { LOG_DEBUG("Invalid BRP number in breakpoint"); return ERROR_OK; } LOG_DEBUG("rbp %i control 0x%0" PRIx32 " value 0x%0" PRIx32, brp_j, brp_list[brp_j].control, brp_list[brp_j].value); brp_list[brp_j].used = 0; brp_list[brp_j].value = 0; brp_list[brp_j].control = 0; retval = cortex_a8_dap_write_memap_register_u32(target, armv7a->debug_base + CPUDBG_BCR_BASE + 4 * brp_list[brp_j].BRPn, brp_list[brp_j].control); if (retval != ERROR_OK) return retval; retval = cortex_a8_dap_write_memap_register_u32(target, armv7a->debug_base + CPUDBG_BVR_BASE + 4 * brp_list[brp_j].BRPn, brp_list[brp_j].value); if (retval != ERROR_OK) return retval; breakpoint->linked_BRP = 0; breakpoint->set = 0; return ERROR_OK; } else { int brp_i = breakpoint->set - 1; if ((brp_i < 0) || (brp_i >= cortex_a8->brp_num)) { LOG_DEBUG("Invalid BRP number in breakpoint"); return ERROR_OK; } LOG_DEBUG("rbp %i control 0x%0" PRIx32 " value 0x%0" PRIx32, brp_i, brp_list[brp_i].control, brp_list[brp_i].value); brp_list[brp_i].used = 0; brp_list[brp_i].value = 0; brp_list[brp_i].control = 0; retval = cortex_a8_dap_write_memap_register_u32(target, armv7a->debug_base + CPUDBG_BCR_BASE + 4 * brp_list[brp_i].BRPn, brp_list[brp_i].control); if (retval != ERROR_OK) return retval; retval = cortex_a8_dap_write_memap_register_u32(target, armv7a->debug_base + CPUDBG_BVR_BASE + 4 * brp_list[brp_i].BRPn, brp_list[brp_i].value); if (retval != ERROR_OK) return retval; breakpoint->set = 0; return ERROR_OK; } } else { /* restore original instruction (kept in target endianness) */ if (breakpoint->length == 4) { retval = target_write_memory(target, breakpoint->address & 0xFFFFFFFE, 4, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; } else { retval = target_write_memory(target, breakpoint->address & 0xFFFFFFFE, 2, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; } } breakpoint->set = 0; return ERROR_OK; } static int cortex_a8_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct cortex_a8_common *cortex_a8 = target_to_cortex_a8(target); if ((breakpoint->type == BKPT_HARD) && (cortex_a8->brp_num_available < 1)) { LOG_INFO("no hardware breakpoint available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if (breakpoint->type == BKPT_HARD) cortex_a8->brp_num_available--; return cortex_a8_set_breakpoint(target, breakpoint, 0x00); /* Exact match */ } static int cortex_a8_add_context_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct cortex_a8_common *cortex_a8 = target_to_cortex_a8(target); if ((breakpoint->type == BKPT_HARD) && (cortex_a8->brp_num_available < 1)) { LOG_INFO("no hardware breakpoint available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if (breakpoint->type == BKPT_HARD) cortex_a8->brp_num_available--; return cortex_a8_set_context_breakpoint(target, breakpoint, 0x02); /* asid match */ } static int cortex_a8_add_hybrid_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct cortex_a8_common *cortex_a8 = target_to_cortex_a8(target); if ((breakpoint->type == BKPT_HARD) && (cortex_a8->brp_num_available < 1)) { LOG_INFO("no hardware breakpoint available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if (breakpoint->type == BKPT_HARD) cortex_a8->brp_num_available--; return cortex_a8_set_hybrid_breakpoint(target, breakpoint); /* ??? */ } static int cortex_a8_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct cortex_a8_common *cortex_a8 = target_to_cortex_a8(target); #if 0 /* It is perfectly possible to remove breakpoints while the target is running */ if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } #endif if (breakpoint->set) { cortex_a8_unset_breakpoint(target, breakpoint); if (breakpoint->type == BKPT_HARD) cortex_a8->brp_num_available++; } return ERROR_OK; } /* * Cortex-A8 Reset functions */ static int cortex_a8_assert_reset(struct target *target) { struct armv7a_common *armv7a = target_to_armv7a(target); LOG_DEBUG(" "); /* FIXME when halt is requested, make it work somehow... */ /* Issue some kind of warm reset. */ if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT)) target_handle_event(target, TARGET_EVENT_RESET_ASSERT); else if (jtag_get_reset_config() & RESET_HAS_SRST) { /* REVISIT handle "pulls" cases, if there's * hardware that needs them to work. */ jtag_add_reset(0, 1); } else { LOG_ERROR("%s: how to reset?", target_name(target)); return ERROR_FAIL; } /* registers are now invalid */ register_cache_invalidate(armv7a->arm.core_cache); target->state = TARGET_RESET; return ERROR_OK; } static int cortex_a8_deassert_reset(struct target *target) { int retval; LOG_DEBUG(" "); /* be certain SRST is off */ jtag_add_reset(0, 0); retval = cortex_a8_poll(target); if (retval != ERROR_OK) return retval; if (target->reset_halt) { if (target->state != TARGET_HALTED) { LOG_WARNING("%s: ran after reset and before halt ...", target_name(target)); retval = target_halt(target); if (retval != ERROR_OK) return retval; } } return ERROR_OK; } static int cortex_a8_write_apb_ab_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { /* write memory through APB-AP */ int retval = ERROR_COMMAND_SYNTAX_ERROR; struct armv7a_common *armv7a = target_to_armv7a(target); struct arm *arm = &armv7a->arm; struct adiv5_dap *swjdp = armv7a->arm.dap; int total_bytes = count * size; int total_u32; int start_byte = address & 0x3; int end_byte = (address + total_bytes) & 0x3; struct reg *reg; uint32_t dscr; uint8_t *tmp_buff = NULL; if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } total_u32 = DIV_ROUND_UP((address & 3) + total_bytes, 4); /* Mark register R0 as dirty, as it will be used * for transferring the data. * It will be restored automatically when exiting * debug mode */ reg = arm_reg_current(arm, 0); reg->dirty = true; /* clear any abort */ retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DRCR, 1<<2); if (retval != ERROR_OK) return retval; /* This algorithm comes from either : * Cortex-A8 TRM Example 12-25 * Cortex-R4 TRM Example 11-26 * (slight differences) */ /* The algorithm only copies 32 bit words, so the buffer * should be expanded to include the words at either end. * The first and last words will be read first to avoid * corruption if needed. */ tmp_buff = (uint8_t *) malloc(total_u32 << 2); if ((start_byte != 0) && (total_u32 > 1)) { /* First bytes not aligned - read the 32 bit word to avoid corrupting * the other bytes in the word. */ retval = cortex_a8_read_apb_ab_memory(target, (address & ~0x3), 4, 1, tmp_buff); if (retval != ERROR_OK) goto error_free_buff_w; } /* If end of write is not aligned, or the write is less than 4 bytes */ if ((end_byte != 0) || ((total_u32 == 1) && (total_bytes != 4))) { /* Read the last word to avoid corruption during 32 bit write */ int mem_offset = (total_u32-1) << 4; retval = cortex_a8_read_apb_ab_memory(target, (address & ~0x3) + mem_offset, 4, 1, &tmp_buff[mem_offset]); if (retval != ERROR_OK) goto error_free_buff_w; } /* Copy the write buffer over the top of the temporary buffer */ memcpy(&tmp_buff[start_byte], buffer, total_bytes); /* We now have a 32 bit aligned buffer that can be written */ /* Read DSCR */ retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); if (retval != ERROR_OK) goto error_free_buff_w; /* Set DTR mode to Fast (2) */ dscr = (dscr & ~DSCR_EXT_DCC_MASK) | DSCR_EXT_DCC_FAST_MODE; retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, dscr); if (retval != ERROR_OK) goto error_free_buff_w; /* Copy the destination address into R0 */ /* - pend an instruction MRC p14, 0, R0, c5, c0 */ retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_ITR, ARMV4_5_MRC(14, 0, 0, 0, 5, 0)); if (retval != ERROR_OK) goto error_unset_dtr_w; /* Write address into DTRRX, which triggers previous instruction */ retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DTRRX, address & (~0x3)); if (retval != ERROR_OK) goto error_unset_dtr_w; /* Write the data transfer instruction into the ITR * (STC p14, c5, [R0], 4) */ retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_ITR, ARMV4_5_STC(0, 1, 0, 1, 14, 5, 0, 4)); if (retval != ERROR_OK) goto error_unset_dtr_w; /* Do the write */ retval = mem_ap_sel_write_buf_u32_noincr(swjdp, armv7a->debug_ap, tmp_buff, (total_u32)<<2, armv7a->debug_base + CPUDBG_DTRRX); if (retval != ERROR_OK) goto error_unset_dtr_w; /* Switch DTR mode back to non-blocking (0) */ dscr = (dscr & ~DSCR_EXT_DCC_MASK) | DSCR_EXT_DCC_NON_BLOCKING; retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, dscr); if (retval != ERROR_OK) goto error_unset_dtr_w; /* Check for sticky abort flags in the DSCR */ retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); if (retval != ERROR_OK) goto error_free_buff_w; if (dscr & (DSCR_STICKY_ABORT_PRECISE | DSCR_STICKY_ABORT_IMPRECISE)) { /* Abort occurred - clear it and exit */ LOG_ERROR("abort occurred - dscr = 0x%08x", dscr); mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DRCR, 1<<2); goto error_free_buff_w; } /* Done */ free(tmp_buff); return ERROR_OK; error_unset_dtr_w: /* Unset DTR mode */ mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); dscr = (dscr & ~DSCR_EXT_DCC_MASK) | DSCR_EXT_DCC_NON_BLOCKING; mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, dscr); error_free_buff_w: LOG_ERROR("error"); free(tmp_buff); return ERROR_FAIL; } static int cortex_a8_read_apb_ab_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) { /* read memory through APB-AP */ int retval = ERROR_COMMAND_SYNTAX_ERROR; struct armv7a_common *armv7a = target_to_armv7a(target); struct adiv5_dap *swjdp = armv7a->arm.dap; struct arm *arm = &armv7a->arm; int total_bytes = count * size; int total_u32; int start_byte = address & 0x3; struct reg *reg; uint32_t dscr; char *tmp_buff = NULL; uint32_t buff32[2]; if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } total_u32 = DIV_ROUND_UP((address & 3) + total_bytes, 4); /* Mark register R0 as dirty, as it will be used * for transferring the data. * It will be restored automatically when exiting * debug mode */ reg = arm_reg_current(arm, 0); reg->dirty = true; /* clear any abort */ retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DRCR, 1<<2); if (retval != ERROR_OK) return retval; /* Read DSCR */ retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); /* This algorithm comes from either : * Cortex-A8 TRM Example 12-24 * Cortex-R4 TRM Example 11-25 * (slight differences) */ /* Set DTR access mode to stall mode b01 */ dscr = (dscr & ~DSCR_EXT_DCC_MASK) | DSCR_EXT_DCC_STALL_MODE; retval += mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, dscr); /* Write R0 with value 'address' using write procedure for stall mode */ /* - Write the address for read access into DTRRX */ retval += mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DTRRX, address & ~0x3); /* - Copy value from DTRRX to R0 using instruction mrc p14, 0, r0, c5, c0 */ cortex_a8_exec_opcode(target, ARMV4_5_MRC(14, 0, 0, 0, 5, 0), &dscr); /* Write the data transfer instruction (ldc p14, c5, [r0],4) * and the DTR mode setting to fast mode * in one combined write (since they are adjacent registers) */ buff32[0] = ARMV4_5_LDC(0, 1, 0, 1, 14, 5, 0, 4); dscr = (dscr & ~DSCR_EXT_DCC_MASK) | DSCR_EXT_DCC_FAST_MODE; buff32[1] = dscr; /* group the 2 access CPUDBG_ITR 0x84 and CPUDBG_DSCR 0x88 */ retval += mem_ap_sel_write_buf_u32(swjdp, armv7a->debug_ap, (uint8_t *)buff32, 8, armv7a->debug_base + CPUDBG_ITR); if (retval != ERROR_OK) goto error_unset_dtr_r; /* Due to offset word alignment, the buffer may not have space * to read the full first and last int32 words, * hence, malloc space to read into, then copy and align into the buffer. */ tmp_buff = (char *) malloc(total_u32<<2); /* The last word needs to be handled separately - read all other words in one go. */ if (total_u32 > 1) { /* Read the data - Each read of the DTRTX register causes the instruction to be reissued * Abort flags are sticky, so can be read at end of transactions * * This data is read in aligned to 32 bit boundary, hence may need shifting later. */ retval = mem_ap_sel_read_buf_u32_noincr(swjdp, armv7a->debug_ap, (uint8_t *)tmp_buff, (total_u32-1)<<2, armv7a->debug_base + CPUDBG_DTRTX); if (retval != ERROR_OK) goto error_unset_dtr_r; } /* set DTR access mode back to non blocking b00 */ dscr = (dscr & ~DSCR_EXT_DCC_MASK) | DSCR_EXT_DCC_NON_BLOCKING; retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, dscr); if (retval != ERROR_OK) goto error_free_buff_r; /* Wait for the final read instruction to finish */ do { retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); if (retval != ERROR_OK) goto error_free_buff_r; } while ((dscr & DSCR_INSTR_COMP) == 0); /* Check for sticky abort flags in the DSCR */ retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); if (retval != ERROR_OK) goto error_free_buff_r; if (dscr & (DSCR_STICKY_ABORT_PRECISE | DSCR_STICKY_ABORT_IMPRECISE)) { /* Abort occurred - clear it and exit */ LOG_ERROR("abort occurred - dscr = 0x%08x", dscr); mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DRCR, 1<<2); goto error_free_buff_r; } /* Read the last word */ retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DTRTX, (uint32_t *)&tmp_buff[(total_u32-1)<<2]); if (retval != ERROR_OK) goto error_free_buff_r; /* Copy and align the data into the output buffer */ memcpy(buffer, &tmp_buff[start_byte], total_bytes); free(tmp_buff); /* Done */ return ERROR_OK; error_unset_dtr_r: /* Unset DTR mode */ mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); dscr = (dscr & ~DSCR_EXT_DCC_MASK) | DSCR_EXT_DCC_NON_BLOCKING; mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, dscr); error_free_buff_r: LOG_ERROR("error"); free(tmp_buff); return ERROR_FAIL; } /* * Cortex-A8 Memory access * * This is same Cortex M3 but we must also use the correct * ap number for every access. */ static int cortex_a8_read_phys_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct armv7a_common *armv7a = target_to_armv7a(target); struct adiv5_dap *swjdp = armv7a->arm.dap; int retval = ERROR_COMMAND_SYNTAX_ERROR; uint8_t apsel = swjdp->apsel; LOG_DEBUG("Reading memory at real address 0x%x; size %d; count %d", address, size, count); if (count && buffer) { if (armv7a->memory_ap_available && (apsel == armv7a->memory_ap)) { /* read memory through AHB-AP */ switch (size) { case 4: retval = mem_ap_sel_read_buf_u32(swjdp, armv7a->memory_ap, buffer, 4 * count, address); break; case 2: retval = mem_ap_sel_read_buf_u16(swjdp, armv7a->memory_ap, buffer, 2 * count, address); break; case 1: retval = mem_ap_sel_read_buf_u8(swjdp, armv7a->memory_ap, buffer, count, address); break; } } else { /* read memory through APB-AP */ if (!armv7a->is_armv7r) { /* disable mmu */ retval = cortex_a8_mmu_modify(target, 0); if (retval != ERROR_OK) return retval; } retval = cortex_a8_read_apb_ab_memory(target, address, size, count, buffer); } } return retval; } static int cortex_a8_read_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) { int enabled = 0; uint32_t virt, phys; int retval; struct armv7a_common *armv7a = target_to_armv7a(target); struct adiv5_dap *swjdp = armv7a->arm.dap; uint8_t apsel = swjdp->apsel; /* cortex_a8 handles unaligned memory access */ LOG_DEBUG("Reading memory at address 0x%x; size %d; count %d", address, size, count); if (armv7a->memory_ap_available && (apsel == armv7a->memory_ap)) { if (!armv7a->is_armv7r) { retval = cortex_a8_mmu(target, &enabled); if (retval != ERROR_OK) return retval; if (enabled) { virt = address; retval = cortex_a8_virt2phys(target, virt, &phys); if (retval != ERROR_OK) return retval; LOG_DEBUG("Reading at virtual address. Translating v:0x%x to r:0x%x", virt, phys); address = phys; } } retval = cortex_a8_read_phys_memory(target, address, size, count, buffer); } else { if (!armv7a->is_armv7r) { retval = cortex_a8_check_address(target, address); if (retval != ERROR_OK) return retval; /* enable mmu */ retval = cortex_a8_mmu_modify(target, 1); if (retval != ERROR_OK) return retval; } retval = cortex_a8_read_apb_ab_memory(target, address, size, count, buffer); } return retval; } static int cortex_a8_write_phys_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct armv7a_common *armv7a = target_to_armv7a(target); struct adiv5_dap *swjdp = armv7a->arm.dap; int retval = ERROR_COMMAND_SYNTAX_ERROR; uint8_t apsel = swjdp->apsel; LOG_DEBUG("Writing memory to real address 0x%x; size %d; count %d", address, size, count); if (count && buffer) { if (armv7a->memory_ap_available && (apsel == armv7a->memory_ap)) { /* write memory through AHB-AP */ switch (size) { case 4: retval = mem_ap_sel_write_buf_u32(swjdp, armv7a->memory_ap, buffer, 4 * count, address); break; case 2: retval = mem_ap_sel_write_buf_u16(swjdp, armv7a->memory_ap, buffer, 2 * count, address); break; case 1: retval = mem_ap_sel_write_buf_u8(swjdp, armv7a->memory_ap, buffer, count, address); break; } } else { /* write memory through APB-AP */ if (!armv7a->is_armv7r) { retval = cortex_a8_mmu_modify(target, 0); if (retval != ERROR_OK) return retval; } return cortex_a8_write_apb_ab_memory(target, address, size, count, buffer); } } /* REVISIT this op is generic ARMv7-A/R stuff */ if (retval == ERROR_OK && target->state == TARGET_HALTED) { struct arm_dpm *dpm = armv7a->arm.dpm; retval = dpm->prepare(dpm); if (retval != ERROR_OK) return retval; /* The Cache handling will NOT work with MMU active, the * wrong addresses will be invalidated! * * For both ICache and DCache, walk all cache lines in the * address range. Cortex-A8 has fixed 64 byte line length. * * REVISIT per ARMv7, these may trigger watchpoints ... */ /* invalidate I-Cache */ if (armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled) { /* ICIMVAU - Invalidate Cache single entry * with MVA to PoU * MCR p15, 0, r0, c7, c5, 1 */ for (uint32_t cacheline = address; cacheline < address + size * count; cacheline += 64) { retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 7, 5, 1), cacheline); if (retval != ERROR_OK) return retval; } } /* invalidate D-Cache */ if (armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled) { /* DCIMVAC - Invalidate data Cache line * with MVA to PoC * MCR p15, 0, r0, c7, c6, 1 */ for (uint32_t cacheline = address; cacheline < address + size * count; cacheline += 64) { retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 7, 6, 1), cacheline); if (retval != ERROR_OK) return retval; } } /* (void) */ dpm->finish(dpm); } return retval; } static int cortex_a8_write_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { int enabled = 0; uint32_t virt, phys; int retval; struct armv7a_common *armv7a = target_to_armv7a(target); struct adiv5_dap *swjdp = armv7a->arm.dap; uint8_t apsel = swjdp->apsel; /* cortex_a8 handles unaligned memory access */ LOG_DEBUG("Writing memory at address 0x%x; size %d; count %d", address, size, count); if (armv7a->memory_ap_available && (apsel == armv7a->memory_ap)) { LOG_DEBUG("Writing memory to address 0x%x; size %d; count %d", address, size, count); if (!armv7a->is_armv7r) { retval = cortex_a8_mmu(target, &enabled); if (retval != ERROR_OK) return retval; if (enabled) { virt = address; retval = cortex_a8_virt2phys(target, virt, &phys); if (retval != ERROR_OK) return retval; LOG_DEBUG("Writing to virtual address. Translating v:0x%x to r:0x%x", virt, phys); address = phys; } } retval = cortex_a8_write_phys_memory(target, address, size, count, buffer); } else { if (!armv7a->is_armv7r) { retval = cortex_a8_check_address(target, address); if (retval != ERROR_OK) return retval; /* enable mmu */ retval = cortex_a8_mmu_modify(target, 1); if (retval != ERROR_OK) return retval; } retval = cortex_a8_write_apb_ab_memory(target, address, size, count, buffer); } return retval; } static int cortex_a8_handle_target_request(void *priv) { struct target *target = priv; struct armv7a_common *armv7a = target_to_armv7a(target); struct adiv5_dap *swjdp = armv7a->arm.dap; int retval; if (!target_was_examined(target)) return ERROR_OK; if (!target->dbg_msg_enabled) return ERROR_OK; if (target->state == TARGET_RUNNING) { uint32_t request; uint32_t dscr; retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); /* check if we have data */ while ((dscr & DSCR_DTR_TX_FULL) && (retval == ERROR_OK)) { retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DTRTX, &request); if (retval == ERROR_OK) { target_request(target, request); retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); } } } return ERROR_OK; } /* * Cortex-A8 target information and configuration */ static int cortex_a8_examine_first(struct target *target) { struct cortex_a8_common *cortex_a8 = target_to_cortex_a8(target); struct armv7a_common *armv7a = &cortex_a8->armv7a_common; struct adiv5_dap *swjdp = armv7a->arm.dap; int i; int retval = ERROR_OK; uint32_t didr, ctypr, ttypr, cpuid; /* We do one extra read to ensure DAP is configured, * we call ahbap_debugport_init(swjdp) instead */ retval = ahbap_debugport_init(swjdp); if (retval != ERROR_OK) return retval; /* Search for the APB-AB - it is needed for access to debug registers */ retval = dap_find_ap(swjdp, AP_TYPE_APB_AP, &armv7a->debug_ap); if (retval != ERROR_OK) { LOG_ERROR("Could not find APB-AP for debug access"); return retval; } /* Search for the AHB-AB */ retval = dap_find_ap(swjdp, AP_TYPE_AHB_AP, &armv7a->memory_ap); if (retval != ERROR_OK) { /* AHB-AP not found - use APB-AP */ LOG_DEBUG("Could not find AHB-AP - using APB-AP for memory access"); armv7a->memory_ap_available = false; } else { armv7a->memory_ap_available = true; } if (!target->dbgbase_set) { uint32_t dbgbase; /* Get ROM Table base */ uint32_t apid; retval = dap_get_debugbase(swjdp, 1, &dbgbase, &apid); if (retval != ERROR_OK) return retval; /* Lookup 0x15 -- Processor DAP */ retval = dap_lookup_cs_component(swjdp, 1, dbgbase, 0x15, &armv7a->debug_base); if (retval != ERROR_OK) return retval; } else armv7a->debug_base = target->dbgbase; retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_CPUID, &cpuid); if (retval != ERROR_OK) return retval; retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_CPUID, &cpuid); if (retval != ERROR_OK) { LOG_DEBUG("Examine %s failed", "CPUID"); return retval; } retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_CTYPR, &ctypr); if (retval != ERROR_OK) { LOG_DEBUG("Examine %s failed", "CTYPR"); return retval; } retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_TTYPR, &ttypr); if (retval != ERROR_OK) { LOG_DEBUG("Examine %s failed", "TTYPR"); return retval; } retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, armv7a->debug_base + CPUDBG_DIDR, &didr); if (retval != ERROR_OK) { LOG_DEBUG("Examine %s failed", "DIDR"); return retval; } LOG_DEBUG("cpuid = 0x%08" PRIx32, cpuid); LOG_DEBUG("ctypr = 0x%08" PRIx32, ctypr); LOG_DEBUG("ttypr = 0x%08" PRIx32, ttypr); LOG_DEBUG("didr = 0x%08" PRIx32, didr); armv7a->arm.core_type = ARM_MODE_MON; retval = cortex_a8_dpm_setup(cortex_a8, didr); if (retval != ERROR_OK) return retval; /* Setup Breakpoint Register Pairs */ cortex_a8->brp_num = ((didr >> 24) & 0x0F) + 1; cortex_a8->brp_num_context = ((didr >> 20) & 0x0F) + 1; cortex_a8->brp_num_available = cortex_a8->brp_num; cortex_a8->brp_list = calloc(cortex_a8->brp_num, sizeof(struct cortex_a8_brp)); /* cortex_a8->brb_enabled = ????; */ for (i = 0; i < cortex_a8->brp_num; i++) { cortex_a8->brp_list[i].used = 0; if (i < (cortex_a8->brp_num-cortex_a8->brp_num_context)) cortex_a8->brp_list[i].type = BRP_NORMAL; else cortex_a8->brp_list[i].type = BRP_CONTEXT; cortex_a8->brp_list[i].value = 0; cortex_a8->brp_list[i].control = 0; cortex_a8->brp_list[i].BRPn = i; } LOG_DEBUG("Configured %i hw breakpoints", cortex_a8->brp_num); target_set_examined(target); return ERROR_OK; } static int cortex_a8_examine(struct target *target) { int retval = ERROR_OK; /* don't re-probe hardware after each reset */ if (!target_was_examined(target)) retval = cortex_a8_examine_first(target); /* Configure core debug access */ if (retval == ERROR_OK) retval = cortex_a8_init_debug_access(target); return retval; } /* * Cortex-A8 target creation and initialization */ static int cortex_a8_init_target(struct command_context *cmd_ctx, struct target *target) { /* examine_first() does a bunch of this */ return ERROR_OK; } static int cortex_a8_init_arch_info(struct target *target, struct cortex_a8_common *cortex_a8, struct jtag_tap *tap) { struct armv7a_common *armv7a = &cortex_a8->armv7a_common; struct adiv5_dap *dap = &armv7a->dap; armv7a->arm.dap = dap; /* Setup struct cortex_a8_common */ cortex_a8->common_magic = CORTEX_A8_COMMON_MAGIC; /* tap has no dap initialized */ if (!tap->dap) { armv7a->arm.dap = dap; /* Setup struct cortex_a8_common */ /* prepare JTAG information for the new target */ cortex_a8->jtag_info.tap = tap; cortex_a8->jtag_info.scann_size = 4; /* Leave (only) generic DAP stuff for debugport_init() */ dap->jtag_info = &cortex_a8->jtag_info; /* Number of bits for tar autoincrement, impl. dep. at least 10 */ dap->tar_autoincr_block = (1 << 10); dap->memaccess_tck = 80; tap->dap = dap; } else armv7a->arm.dap = tap->dap; cortex_a8->fast_reg_read = 0; /* register arch-specific functions */ armv7a->examine_debug_reason = NULL; armv7a->post_debug_entry = cortex_a8_post_debug_entry; armv7a->pre_restore_context = NULL; armv7a->armv7a_mmu.read_physical_memory = cortex_a8_read_phys_memory; /* arm7_9->handle_target_request = cortex_a8_handle_target_request; */ /* REVISIT v7a setup should be in a v7a-specific routine */ armv7a_init_arch_info(target, armv7a); target_register_timer_callback(cortex_a8_handle_target_request, 1, 1, target); return ERROR_OK; } static int cortex_a8_target_create(struct target *target, Jim_Interp *interp) { struct cortex_a8_common *cortex_a8 = calloc(1, sizeof(struct cortex_a8_common)); cortex_a8->armv7a_common.is_armv7r = false; return cortex_a8_init_arch_info(target, cortex_a8, target->tap); } static int cortex_r4_target_create(struct target *target, Jim_Interp *interp) { struct cortex_a8_common *cortex_a8 = calloc(1, sizeof(struct cortex_a8_common)); cortex_a8->armv7a_common.is_armv7r = true; return cortex_a8_init_arch_info(target, cortex_a8, target->tap); } static int cortex_a8_mmu(struct target *target, int *enabled) { if (target->state != TARGET_HALTED) { LOG_ERROR("%s: target not halted", __func__); return ERROR_TARGET_INVALID; } *enabled = target_to_cortex_a8(target)->armv7a_common.armv7a_mmu.mmu_enabled; return ERROR_OK; } static int cortex_a8_virt2phys(struct target *target, uint32_t virt, uint32_t *phys) { int retval = ERROR_FAIL; struct armv7a_common *armv7a = target_to_armv7a(target); struct adiv5_dap *swjdp = armv7a->arm.dap; uint8_t apsel = swjdp->apsel; if (armv7a->memory_ap_available && (apsel == armv7a->memory_ap)) { uint32_t ret; retval = armv7a_mmu_translate_va(target, virt, &ret); if (retval != ERROR_OK) goto done; *phys = ret; } else {/* use this method if armv7a->memory_ap not selected * mmu must be enable in order to get a correct translation */ retval = cortex_a8_mmu_modify(target, 1); if (retval != ERROR_OK) goto done; retval = armv7a_mmu_translate_va_pa(target, virt, phys, 1); } done: return retval; } COMMAND_HANDLER(cortex_a8_handle_cache_info_command) { struct target *target = get_current_target(CMD_CTX); struct armv7a_common *armv7a = target_to_armv7a(target); return armv7a_handle_cache_info_command(CMD_CTX, &armv7a->armv7a_mmu.armv7a_cache); } COMMAND_HANDLER(cortex_a8_handle_dbginit_command) { struct target *target = get_current_target(CMD_CTX); if (!target_was_examined(target)) { LOG_ERROR("target not examined yet"); return ERROR_FAIL; } return cortex_a8_init_debug_access(target); } COMMAND_HANDLER(cortex_a8_handle_smp_off_command) { struct target *target = get_current_target(CMD_CTX); /* check target is an smp target */ struct target_list *head; struct target *curr; head = target->head; target->smp = 0; if (head != (struct target_list *)NULL) { while (head != (struct target_list *)NULL) { curr = head->target; curr->smp = 0; head = head->next; } /* fixes the target display to the debugger */ target->gdb_service->target = target; } return ERROR_OK; } COMMAND_HANDLER(cortex_a8_handle_smp_on_command) { struct target *target = get_current_target(CMD_CTX); struct target_list *head; struct target *curr; head = target->head; if (head != (struct target_list *)NULL) { target->smp = 1; while (head != (struct target_list *)NULL) { curr = head->target; curr->smp = 1; head = head->next; } } return ERROR_OK; } COMMAND_HANDLER(cortex_a8_handle_smp_gdb_command) { struct target *target = get_current_target(CMD_CTX); int retval = ERROR_OK; struct target_list *head; head = target->head; if (head != (struct target_list *)NULL) { if (CMD_ARGC == 1) { int coreid = 0; COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], coreid); if (ERROR_OK != retval) return retval; target->gdb_service->core[1] = coreid; } command_print(CMD_CTX, "gdb coreid %d -> %d", target->gdb_service->core[0] , target->gdb_service->core[1]); } return ERROR_OK; } static const struct command_registration cortex_a8_exec_command_handlers[] = { { .name = "cache_info", .handler = cortex_a8_handle_cache_info_command, .mode = COMMAND_EXEC, .help = "display information about target caches", .usage = "", }, { .name = "dbginit", .handler = cortex_a8_handle_dbginit_command, .mode = COMMAND_EXEC, .help = "Initialize core debug", .usage = "", }, { .name = "smp_off", .handler = cortex_a8_handle_smp_off_command, .mode = COMMAND_EXEC, .help = "Stop smp handling", .usage = "",}, { .name = "smp_on", .handler = cortex_a8_handle_smp_on_command, .mode = COMMAND_EXEC, .help = "Restart smp handling", .usage = "", }, { .name = "smp_gdb", .handler = cortex_a8_handle_smp_gdb_command, .mode = COMMAND_EXEC, .help = "display/fix current core played to gdb", .usage = "", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration cortex_a8_command_handlers[] = { { .chain = arm_command_handlers, }, { .chain = armv7a_command_handlers, }, { .name = "cortex_a", .mode = COMMAND_ANY, .help = "Cortex-A command group", .usage = "", .chain = cortex_a8_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct target_type cortexa8_target = { .name = "cortex_a8", .poll = cortex_a8_poll, .arch_state = armv7a_arch_state, .target_request_data = NULL, .halt = cortex_a8_halt, .resume = cortex_a8_resume, .step = cortex_a8_step, .assert_reset = cortex_a8_assert_reset, .deassert_reset = cortex_a8_deassert_reset, .soft_reset_halt = NULL, /* REVISIT allow exporting VFP3 registers ... */ .get_gdb_reg_list = arm_get_gdb_reg_list, .read_memory = cortex_a8_read_memory, .write_memory = cortex_a8_write_memory, .checksum_memory = arm_checksum_memory, .blank_check_memory = arm_blank_check_memory, .run_algorithm = armv4_5_run_algorithm, .add_breakpoint = cortex_a8_add_breakpoint, .add_context_breakpoint = cortex_a8_add_context_breakpoint, .add_hybrid_breakpoint = cortex_a8_add_hybrid_breakpoint, .remove_breakpoint = cortex_a8_remove_breakpoint, .add_watchpoint = NULL, .remove_watchpoint = NULL, .commands = cortex_a8_command_handlers, .target_create = cortex_a8_target_create, .init_target = cortex_a8_init_target, .examine = cortex_a8_examine, .read_phys_memory = cortex_a8_read_phys_memory, .write_phys_memory = cortex_a8_write_phys_memory, .mmu = cortex_a8_mmu, .virt2phys = cortex_a8_virt2phys, }; static const struct command_registration cortex_r4_exec_command_handlers[] = { { .name = "cache_info", .handler = cortex_a8_handle_cache_info_command, .mode = COMMAND_EXEC, .help = "display information about target caches", .usage = "", }, { .name = "dbginit", .handler = cortex_a8_handle_dbginit_command, .mode = COMMAND_EXEC, .help = "Initialize core debug", .usage = "", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration cortex_r4_command_handlers[] = { { .chain = arm_command_handlers, }, { .chain = armv7a_command_handlers, }, { .name = "cortex_r4", .mode = COMMAND_ANY, .help = "Cortex-R4 command group", .usage = "", .chain = cortex_r4_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct target_type cortexr4_target = { .name = "cortex_r4", .poll = cortex_a8_poll, .arch_state = armv7a_arch_state, .target_request_data = NULL, .halt = cortex_a8_halt, .resume = cortex_a8_resume, .step = cortex_a8_step, .assert_reset = cortex_a8_assert_reset, .deassert_reset = cortex_a8_deassert_reset, .soft_reset_halt = NULL, /* REVISIT allow exporting VFP3 registers ... */ .get_gdb_reg_list = arm_get_gdb_reg_list, .read_memory = cortex_a8_read_memory, .write_memory = cortex_a8_write_memory, .checksum_memory = arm_checksum_memory, .blank_check_memory = arm_blank_check_memory, .run_algorithm = armv4_5_run_algorithm, .add_breakpoint = cortex_a8_add_breakpoint, .add_context_breakpoint = cortex_a8_add_context_breakpoint, .add_hybrid_breakpoint = cortex_a8_add_hybrid_breakpoint, .remove_breakpoint = cortex_a8_remove_breakpoint, .add_watchpoint = NULL, .remove_watchpoint = NULL, .commands = cortex_r4_command_handlers, .target_create = cortex_r4_target_create, .init_target = cortex_a8_init_target, .examine = cortex_a8_examine, }; openocd-0.7.0/src/target/register.c0000644000175000001440000000652412134336410014133 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "register.h" #include /** * @file * Holds utilities to work with register caches. * * OpenOCD uses machine registers internally, and exposes them by name * to Tcl scripts. Sets of related registers are grouped into caches. * For example, a CPU core will expose a set of registers, and there * may be separate registers associated with debug or trace modules. */ struct reg *register_get_by_name(struct reg_cache *first, const char *name, bool search_all) { unsigned i; struct reg_cache *cache = first; while (cache) { for (i = 0; i < cache->num_regs; i++) { if (strcmp(cache->reg_list[i].name, name) == 0) return &(cache->reg_list[i]); } if (search_all) cache = cache->next; else break; } return NULL; } struct reg_cache **register_get_last_cache_p(struct reg_cache **first) { struct reg_cache **cache_p = first; if (*cache_p) while (*cache_p) cache_p = &((*cache_p)->next); else return first; return cache_p; } /** Marks the contents of the register cache as invalid (and clean). */ void register_cache_invalidate(struct reg_cache *cache) { struct reg *reg = cache->reg_list; for (unsigned n = cache->num_regs; n != 0; n--, reg++) { reg->valid = 0; reg->dirty = 0; } } static int register_get_dummy_core_reg(struct reg *reg) { return ERROR_OK; } static int register_set_dummy_core_reg(struct reg *reg, uint8_t *buf) { reg->dirty = 1; reg->valid = 1; return ERROR_OK; } static const struct reg_arch_type dummy_type = { .get = register_get_dummy_core_reg, .set = register_set_dummy_core_reg, }; void register_init_dummy(struct reg *reg) { reg->type = &dummy_type; } openocd-0.7.0/src/target/avrt.h0000644000175000001440000000345212134336410013265 00000000000000/*************************************************************************** * Copyright (C) 2009 by Simon Qian * * SimonQian@SimonQian.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef AVRT_H #define AVRT_H #include struct mcu_jtag { struct jtag_tap *tap; }; struct avr_common { struct mcu_jtag jtag_info; }; int mcu_execute_queue(void); int avr_jtag_sendinstr(struct jtag_tap *tap, uint8_t *ir_in, uint8_t ir_out); int avr_jtag_senddat(struct jtag_tap *tap, uint32_t *dr_in, uint32_t dr_out, int len); #endif /* AVRT_H */ openocd-0.7.0/src/target/avr32_jtag.h0000644000175000001440000000730512134336410014254 00000000000000/*************************************************************************** * Copyright (C) 2010 by Oleksandr Tymoshenko * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef AVR32_JTAG #define AVR32_JTAG #define AVR32NUMCOREREGS 17 /* tap instructions */ #define AVR32_INST_IDCODE 0x01 #define AVR32_INST_NEXUS_ACCESS 0x10 #define AVR32_INST_MW_ACCESS 0x11 #define AVR32_INST_MB_ACCESS 0x12 #define SLAVE_OCD 0x01 #define SLAVE_HSB_CACHED 0x04 #define SLAVE_HSB_UNCACHED 0x05 /* * Registers */ #define AVR32_OCDREG_DID 0x00 #define AVR32_OCDREG_DC 0x02 #define OCDREG_DC_SS (1 << 8) #define OCDREG_DC_DBR (1 << 12) #define OCDREG_DC_DBE (1 << 13) #define OCDREG_DC_SQA (1 << 22) #define OCDREG_DC_RES (1 << 30) #define OCDREG_DC_ABORT (1 << 31) #define AVR32_OCDREG_DS 0x04 #define OCDREG_DS_SSS (1 << 0) #define OCDREG_DS_SWB (1 << 1) #define OCDREG_DS_HWB (1 << 2) #define OCDREG_DS_STP (1 << 4) #define OCDREG_DS_DBS (1 << 5) #define OCDREG_DS_BP_SHIFT 8 #define OCDREG_DS_BP_MASK 0xff #define OCDREG_DS_INC (1 << 24) #define OCDREG_DS_BOZ (1 << 25) #define OCDREG_DS_DBA (1 << 26) #define OCDREG_DS_EXB (1 << 27) #define OCDREG_DS_NTBF (1 << 28) #define AVR32_OCDREG_DINST 0x41 #define AVR32_OCDREG_DPC 0x42 #define AVR32_OCDREG_DCCPU 0x44 #define AVR32_OCDREG_DCEMU 0x45 #define AVR32_OCDREG_DCSR 0x46 #define OCDREG_DCSR_CPUD (1 << 0) #define OCDREG_DCSR_EMUD (1 << 1) /* * Direction bit */ #define MODE_WRITE 0x00 #define MODE_READ 0x01 /* * Some instructions */ #define RETD 0xd703d623 #define MTDR(dreg, reg) (0xe7b00044 | ((reg) << 16) | dreg) #define MFDR(reg, dreg) (0xe5b00044 | ((reg) << 16) | dreg) #define MTSR(sysreg, reg) (0xe3b00002 | ((reg) << 16) | sysreg) #define MFSR(reg, sysreg) (0xe1b00002 | ((reg) << 16) | sysreg) struct avr32_jtag { struct jtag_tap *tap; uint32_t dpc; /* Debug PC value */ }; int avr32_jtag_nexus_read(struct avr32_jtag *jtag_info, uint32_t addr, uint32_t *value); int avr32_jtag_nexus_write(struct avr32_jtag *jtag_info, uint32_t addr, uint32_t value); int avr32_jtag_mwa_read(struct avr32_jtag *jtag_info, int slave, uint32_t addr, uint32_t *value); int avr32_jtag_mwa_write(struct avr32_jtag *jtag_info, int slave, uint32_t addr, uint32_t value); int avr32_ocd_setbits(struct avr32_jtag *jtag, int reg, uint32_t bits); int avr32_ocd_clearbits(struct avr32_jtag *jtag, int reg, uint32_t bits); int avr32_jtag_exec(struct avr32_jtag *jtag_info, uint32_t inst); #endif /* AVR32_JTAG */ openocd-0.7.0/src/target/mips32_dmaacc.h0000644000175000001440000000445312134336410014720 00000000000000/*************************************************************************** * Copyright (C) 2008 by John McCarthy * * jgmcc@magma.ca * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2008 by David T.L. Wong * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef MIPS32_DMAACC_H #define MIPS32_DMAACC_H #include "mips_ejtag.h" #define EJTAG_CTRL_DMA_BYTE 0x00000000 #define EJTAG_CTRL_DMA_HALFWORD 0x00000080 #define EJTAG_CTRL_DMA_WORD 0x00000100 #define EJTAG_CTRL_DMA_TRIPLEBYTE 0x00000180 #define RETRY_ATTEMPTS 0 int mips32_dmaacc_read_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, void *buf); int mips32_dmaacc_write_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, void *buf); #endif openocd-0.7.0/src/target/arm_semihosting.c0000644000175000001440000003606612134336410015503 00000000000000/*************************************************************************** * Copyright (C) 2009 by Marvell Technology Group Ltd. * * Written by Nicolas Pitre * * * * Copyright (C) 2010 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /** * @file * Hold ARM semihosting support. * * Semihosting enables code running on an ARM target to use the I/O * facilities on the host computer. The target application must be linked * against a library that forwards operation requests by using the SVC * instruction trapped at the Supervisor Call vector by the debugger. * Details can be found in chapter 8 of DUI0203I_rvct_developer_guide.pdf * from ARM Ltd. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm.h" #include "armv4_5.h" #include "arm7_9_common.h" #include "armv7m.h" #include "cortex_m.h" #include "register.h" #include "arm_semihosting.h" #include #include #include static int open_modeflags[12] = { O_RDONLY, O_RDONLY | O_BINARY, O_RDWR, O_RDWR | O_BINARY, O_WRONLY | O_CREAT | O_TRUNC, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, O_RDWR | O_CREAT | O_TRUNC, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, O_WRONLY | O_CREAT | O_APPEND, O_WRONLY | O_CREAT | O_APPEND | O_BINARY, O_RDWR | O_CREAT | O_APPEND, O_RDWR | O_CREAT | O_APPEND | O_BINARY }; static int do_semihosting(struct target *target) { struct arm *arm = target_to_arm(target); uint32_t r0 = buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32); uint32_t r1 = buf_get_u32(arm->core_cache->reg_list[1].value, 0, 32); uint8_t params[16]; int retval, result; /* * TODO: lots of security issues are not considered yet, such as: * - no validation on target provided file descriptors * - no safety checks on opened/deleted/renamed file paths * Beware the target app you use this support with. * * TODO: explore mapping requests to GDB's "File-I/O Remote * Protocol Extension" ... when GDB is active. */ switch (r0) { case 0x01: /* SYS_OPEN */ retval = target_read_memory(target, r1, 4, 3, params); if (retval != ERROR_OK) return retval; else { uint32_t a = target_buffer_get_u32(target, params+0); uint32_t m = target_buffer_get_u32(target, params+4); uint32_t l = target_buffer_get_u32(target, params+8); if (l <= 255 && m <= 11) { uint8_t fn[256]; retval = target_read_memory(target, a, 1, l, fn); if (retval != ERROR_OK) return retval; fn[l] = 0; if (strcmp((char *)fn, ":tt") == 0) { if (m < 4) result = dup(STDIN_FILENO); else result = dup(STDOUT_FILENO); } else { /* cygwin requires the permission setting * otherwise it will fail to reopen a previously * written file */ result = open((char *)fn, open_modeflags[m], 0644); } arm->semihosting_errno = errno; } else { result = -1; arm->semihosting_errno = EINVAL; } } break; case 0x02: /* SYS_CLOSE */ retval = target_read_memory(target, r1, 4, 1, params); if (retval != ERROR_OK) return retval; else { int fd = target_buffer_get_u32(target, params+0); result = close(fd); arm->semihosting_errno = errno; } break; case 0x03: /* SYS_WRITEC */ { unsigned char c; retval = target_read_memory(target, r1, 1, 1, &c); if (retval != ERROR_OK) return retval; putchar(c); result = 0; } break; case 0x04: /* SYS_WRITE0 */ do { unsigned char c; retval = target_read_memory(target, r1++, 1, 1, &c); if (retval != ERROR_OK) return retval; if (!c) break; putchar(c); } while (1); result = 0; break; case 0x05: /* SYS_WRITE */ retval = target_read_memory(target, r1, 4, 3, params); if (retval != ERROR_OK) return retval; else { int fd = target_buffer_get_u32(target, params+0); uint32_t a = target_buffer_get_u32(target, params+4); size_t l = target_buffer_get_u32(target, params+8); uint8_t *buf = malloc(l); if (!buf) { result = -1; arm->semihosting_errno = ENOMEM; } else { retval = target_read_buffer(target, a, l, buf); if (retval != ERROR_OK) { free(buf); return retval; } result = write(fd, buf, l); arm->semihosting_errno = errno; if (result >= 0) result = l - result; free(buf); } } break; case 0x06: /* SYS_READ */ retval = target_read_memory(target, r1, 4, 3, params); if (retval != ERROR_OK) return retval; else { int fd = target_buffer_get_u32(target, params+0); uint32_t a = target_buffer_get_u32(target, params+4); ssize_t l = target_buffer_get_u32(target, params+8); uint8_t *buf = malloc(l); if (!buf) { result = -1; arm->semihosting_errno = ENOMEM; } else { result = read(fd, buf, l); arm->semihosting_errno = errno; if (result >= 0) { retval = target_write_buffer(target, a, result, buf); if (retval != ERROR_OK) { free(buf); return retval; } result = l - result; } free(buf); } } break; case 0x07: /* SYS_READC */ result = getchar(); break; case 0x08: /* SYS_ISERROR */ retval = target_read_memory(target, r1, 4, 1, params); if (retval != ERROR_OK) return retval; result = (target_buffer_get_u32(target, params+0) != 0); break; case 0x09: /* SYS_ISTTY */ retval = target_read_memory(target, r1, 4, 1, params); if (retval != ERROR_OK) return retval; result = isatty(target_buffer_get_u32(target, params+0)); break; case 0x0a: /* SYS_SEEK */ retval = target_read_memory(target, r1, 4, 2, params); if (retval != ERROR_OK) return retval; else { int fd = target_buffer_get_u32(target, params+0); off_t pos = target_buffer_get_u32(target, params+4); result = lseek(fd, pos, SEEK_SET); arm->semihosting_errno = errno; if (result == pos) result = 0; } break; case 0x0c: /* SYS_FLEN */ retval = target_read_memory(target, r1, 4, 1, params); if (retval != ERROR_OK) return retval; else { int fd = target_buffer_get_u32(target, params+0); struct stat buf; result = fstat(fd, &buf); if (result == -1) { arm->semihosting_errno = errno; result = -1; break; } result = buf.st_size; } break; case 0x0e: /* SYS_REMOVE */ retval = target_read_memory(target, r1, 4, 2, params); if (retval != ERROR_OK) return retval; else { uint32_t a = target_buffer_get_u32(target, params+0); uint32_t l = target_buffer_get_u32(target, params+4); if (l <= 255) { uint8_t fn[256]; retval = target_read_memory(target, a, 1, l, fn); if (retval != ERROR_OK) return retval; fn[l] = 0; result = remove((char *)fn); arm->semihosting_errno = errno; } else { result = -1; arm->semihosting_errno = EINVAL; } } break; case 0x0f: /* SYS_RENAME */ retval = target_read_memory(target, r1, 4, 4, params); if (retval != ERROR_OK) return retval; else { uint32_t a1 = target_buffer_get_u32(target, params+0); uint32_t l1 = target_buffer_get_u32(target, params+4); uint32_t a2 = target_buffer_get_u32(target, params+8); uint32_t l2 = target_buffer_get_u32(target, params+12); if (l1 <= 255 && l2 <= 255) { uint8_t fn1[256], fn2[256]; retval = target_read_memory(target, a1, 1, l1, fn1); if (retval != ERROR_OK) return retval; retval = target_read_memory(target, a2, 1, l2, fn2); if (retval != ERROR_OK) return retval; fn1[l1] = 0; fn2[l2] = 0; result = rename((char *)fn1, (char *)fn2); arm->semihosting_errno = errno; } else { result = -1; arm->semihosting_errno = EINVAL; } } break; case 0x11: /* SYS_TIME */ result = time(NULL); break; case 0x13: /* SYS_ERRNO */ result = arm->semihosting_errno; break; case 0x15: /* SYS_GET_CMDLINE */ retval = target_read_memory(target, r1, 4, 2, params); if (retval != ERROR_OK) return retval; else { uint32_t a = target_buffer_get_u32(target, params+0); uint32_t l = target_buffer_get_u32(target, params+4); char *arg = "foobar"; uint32_t s = strlen(arg) + 1; if (l < s) result = -1; else { retval = target_write_buffer(target, a, s, (void *)arg); if (retval != ERROR_OK) return retval; result = 0; } } break; case 0x16: /* SYS_HEAPINFO */ retval = target_read_memory(target, r1, 4, 1, params); if (retval != ERROR_OK) return retval; else { uint32_t a = target_buffer_get_u32(target, params+0); /* tell the remote we have no idea */ memset(params, 0, 4*4); retval = target_write_memory(target, a, 4, 4, params); if (retval != ERROR_OK) return retval; result = 0; } break; case 0x18: /* angel_SWIreason_ReportException */ switch (r1) { case 0x20026: /* ADP_Stopped_ApplicationExit */ fprintf(stderr, "semihosting: *** application exited ***\n"); break; case 0x20000: /* ADP_Stopped_BranchThroughZero */ case 0x20001: /* ADP_Stopped_UndefinedInstr */ case 0x20002: /* ADP_Stopped_SoftwareInterrupt */ case 0x20003: /* ADP_Stopped_PrefetchAbort */ case 0x20004: /* ADP_Stopped_DataAbort */ case 0x20005: /* ADP_Stopped_AddressException */ case 0x20006: /* ADP_Stopped_IRQ */ case 0x20007: /* ADP_Stopped_FIQ */ case 0x20020: /* ADP_Stopped_BreakPoint */ case 0x20021: /* ADP_Stopped_WatchPoint */ case 0x20022: /* ADP_Stopped_StepComplete */ case 0x20023: /* ADP_Stopped_RunTimeErrorUnknown */ case 0x20024: /* ADP_Stopped_InternalError */ case 0x20025: /* ADP_Stopped_UserInterruption */ case 0x20027: /* ADP_Stopped_StackOverflow */ case 0x20028: /* ADP_Stopped_DivisionByZero */ case 0x20029: /* ADP_Stopped_OSSpecific */ default: fprintf(stderr, "semihosting: exception %#x\n", (unsigned) r1); } return target_call_event_callbacks(target, TARGET_EVENT_HALTED); case 0x0d: /* SYS_TMPNAM */ case 0x10: /* SYS_CLOCK */ case 0x12: /* SYS_SYSTEM */ case 0x17: /* angel_SWIreason_EnterSVC */ case 0x30: /* SYS_ELAPSED */ case 0x31: /* SYS_TICKFREQ */ default: fprintf(stderr, "semihosting: unsupported call %#x\n", (unsigned) r0); result = -1; arm->semihosting_errno = ENOTSUP; } /* resume execution to the original mode */ /* REVISIT this looks wrong ... ARM11 and Cortex-A8 * should work this way at least sometimes. */ if (is_arm7_9(target_to_arm7_9(target))) { uint32_t spsr; /* return value in R0 */ buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, result); arm->core_cache->reg_list[0].dirty = 1; /* LR --> PC */ buf_set_u32(arm->core_cache->reg_list[15].value, 0, 32, buf_get_u32(arm_reg_current(arm, 14)->value, 0, 32)); arm->core_cache->reg_list[15].dirty = 1; /* saved PSR --> current PSR */ spsr = buf_get_u32(arm->spsr->value, 0, 32); /* REVISIT should this be arm_set_cpsr(arm, spsr) * instead of a partially unrolled version? */ buf_set_u32(arm->cpsr->value, 0, 32, spsr); arm->cpsr->dirty = 1; arm->core_mode = spsr & 0x1f; if (spsr & 0x20) arm->core_state = ARM_STATE_THUMB; } else { /* resume execution, this will be pc+2 to skip over the * bkpt instruction */ /* return result in R0 */ buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, result); arm->core_cache->reg_list[0].dirty = 1; } return target_resume(target, 1, 0, 0, 0); } /** * Checks for and processes an ARM semihosting request. This is meant * to be called when the target is stopped due to a debug mode entry. * If the value 0 is returned then there was nothing to process. A non-zero * return value signifies that a request was processed and the target resumed, * or an error was encountered, in which case the caller must return * immediately. * * @param target Pointer to the ARM target to process. This target must * not represent an ARMv6-M or ARMv7-M processor. * @param retval Pointer to a location where the return code will be stored * @return non-zero value if a request was processed or an error encountered */ int arm_semihosting(struct target *target, int *retval) { struct arm *arm = target_to_arm(target); uint32_t pc, lr, spsr; struct reg *r; if (!arm->is_semihosting) return 0; if (is_arm7_9(target_to_arm7_9(target))) { if (arm->core_mode != ARM_MODE_SVC) return 0; /* Check for PC == 0x00000008 or 0xffff0008: Supervisor Call vector. */ r = arm->pc; pc = buf_get_u32(r->value, 0, 32); if (pc != 0x00000008 && pc != 0xffff0008) return 0; r = arm_reg_current(arm, 14); lr = buf_get_u32(r->value, 0, 32); /* Core-specific code should make sure SPSR is retrieved * when the above checks pass... */ if (!arm->spsr->valid) { LOG_ERROR("SPSR not valid!"); *retval = ERROR_FAIL; return 1; } spsr = buf_get_u32(arm->spsr->value, 0, 32); /* check instruction that triggered this trap */ if (spsr & (1 << 5)) { /* was in Thumb (or ThumbEE) mode */ uint8_t insn_buf[2]; uint16_t insn; *retval = target_read_memory(target, lr-2, 2, 1, insn_buf); if (*retval != ERROR_OK) return 1; insn = target_buffer_get_u16(target, insn_buf); /* SVC 0xab */ if (insn != 0xDFAB) return 0; } else if (spsr & (1 << 24)) { /* was in Jazelle mode */ return 0; } else { /* was in ARM mode */ uint8_t insn_buf[4]; uint32_t insn; *retval = target_read_memory(target, lr-4, 4, 1, insn_buf); if (*retval != ERROR_OK) return 1; insn = target_buffer_get_u32(target, insn_buf); /* SVC 0x123456 */ if (insn != 0xEF123456) return 0; } } else if (is_armv7m(target_to_armv7m(target))) { uint16_t insn; if (target->debug_reason != DBG_REASON_BREAKPOINT) return 0; r = arm->pc; pc = buf_get_u32(r->value, 0, 32); pc &= ~1; *retval = target_read_u16(target, pc, &insn); if (*retval != ERROR_OK) return 1; /* bkpt 0xAB */ if (insn != 0xBEAB) return 0; } else { LOG_ERROR("Unsupported semi-hosting Target"); return 0; } *retval = do_semihosting(target); return 1; } openocd-0.7.0/src/target/arm11.c0000644000175000001440000010770112137151331013227 00000000000000/*************************************************************************** * Copyright (C) 2008 digenius technology GmbH. * * Michael Bruck * * * * Copyright (C) 2008,2009 Oyvind Harboe oyvind.harboe@zylin.com * * * * Copyright (C) 2008 Georg Acher * * * * Copyright (C) 2009 David Brownell * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "etm.h" #include "breakpoints.h" #include "arm11_dbgtap.h" #include "arm_simulator.h" #include #include "target_type.h" #include "algorithm.h" #include "register.h" #include "arm_opcodes.h" #if 0 #define _DEBUG_INSTRUCTION_EXECUTION_ #endif static int arm11_step(struct target *target, int current, uint32_t address, int handle_breakpoints); /** Check and if necessary take control of the system * * \param arm11 Target state variable. */ static int arm11_check_init(struct arm11_common *arm11) { CHECK_RETVAL(arm11_read_DSCR(arm11)); if (!(arm11->dscr & DSCR_HALT_DBG_MODE)) { LOG_DEBUG("DSCR %08x", (unsigned) arm11->dscr); LOG_DEBUG("Bringing target into debug mode"); arm11->dscr |= DSCR_HALT_DBG_MODE; CHECK_RETVAL(arm11_write_DSCR(arm11, arm11->dscr)); /* add further reset initialization here */ arm11->simulate_reset_on_next_halt = true; if (arm11->dscr & DSCR_CORE_HALTED) { /** \todo TODO: this needs further scrutiny because * arm11_debug_entry() never gets called. (WHY NOT?) * As a result we don't read the actual register states from * the target. */ arm11->arm.target->state = TARGET_HALTED; arm_dpm_report_dscr(arm11->arm.dpm, arm11->dscr); } else { arm11->arm.target->state = TARGET_RUNNING; arm11->arm.target->debug_reason = DBG_REASON_NOTHALTED; } CHECK_RETVAL(arm11_sc7_clear_vbw(arm11)); } return ERROR_OK; } /** * Save processor state. This is called after a HALT instruction * succeeds, and on other occasions the processor enters debug mode * (breakpoint, watchpoint, etc). Caller has updated arm11->dscr. */ static int arm11_debug_entry(struct arm11_common *arm11) { int retval; arm11->arm.target->state = TARGET_HALTED; arm_dpm_report_dscr(arm11->arm.dpm, arm11->dscr); /* REVISIT entire cache should already be invalid !!! */ register_cache_invalidate(arm11->arm.core_cache); /* See e.g. ARM1136 TRM, "14.8.4 Entering Debug state" */ /* maybe save wDTR (pending DCC write to debug SW, e.g. libdcc) */ arm11->is_wdtr_saved = !!(arm11->dscr & DSCR_DTR_TX_FULL); if (arm11->is_wdtr_saved) { arm11_add_debug_SCAN_N(arm11, 0x05, ARM11_TAP_DEFAULT); arm11_add_IR(arm11, ARM11_INTEST, ARM11_TAP_DEFAULT); struct scan_field chain5_fields[3]; arm11_setup_field(arm11, 32, NULL, &arm11->saved_wdtr, chain5_fields + 0); arm11_setup_field(arm11, 1, NULL, NULL, chain5_fields + 1); arm11_setup_field(arm11, 1, NULL, NULL, chain5_fields + 2); arm11_add_dr_scan_vc(arm11->arm.target->tap, ARRAY_SIZE( chain5_fields), chain5_fields, TAP_DRPAUSE); } /* DSCR: set the Execute ARM instruction enable bit. * * ARM1176 spec says this is needed only for wDTR/rDTR's "ITR mode", * but not to issue ITRs(?). The ARMv7 arch spec says it's required * for executing instructions via ITR. */ CHECK_RETVAL(arm11_write_DSCR(arm11, DSCR_ITR_EN | arm11->dscr)); /* From the spec: Before executing any instruction in debug state you have to drain the write buffer. This ensures that no imprecise Data Aborts can return at a later point:*/ /** \todo TODO: Test drain write buffer. */ #if 0 while (1) { /* MRC p14,0,R0,c5,c10,0 */ /* arm11_run_instr_no_data1(arm11, / *0xee150e1a* /0xe320f000); */ /* mcr 15, 0, r0, cr7, cr10, {4} */ arm11_run_instr_no_data1(arm11, 0xee070f9a); uint32_t dscr = arm11_read_DSCR(arm11); LOG_DEBUG("DRAIN, DSCR %08x", dscr); if (dscr & ARM11_DSCR_STICKY_IMPRECISE_DATA_ABORT) { arm11_run_instr_no_data1(arm11, 0xe320f000); dscr = arm11_read_DSCR(arm11); LOG_DEBUG("DRAIN, DSCR %08x (DONE)", dscr); break; } } #endif /* Save registers. * * NOTE: ARM1136 TRM suggests saving just R0 here now, then * CPSR and PC after the rDTR stuff. We do it all at once. */ retval = arm_dpm_read_current_registers(&arm11->dpm); if (retval != ERROR_OK) LOG_ERROR("DPM REG READ -- fail"); retval = arm11_run_instr_data_prepare(arm11); if (retval != ERROR_OK) return retval; /* maybe save rDTR (pending DCC read from debug SW, e.g. libdcc) */ arm11->is_rdtr_saved = !!(arm11->dscr & DSCR_DTR_RX_FULL); if (arm11->is_rdtr_saved) { /* MRC p14,0,R0,c0,c5,0 (move rDTR -> r0 (-> wDTR -> local var)) */ retval = arm11_run_instr_data_from_core_via_r0(arm11, 0xEE100E15, &arm11->saved_rdtr); if (retval != ERROR_OK) return retval; } /* REVISIT Now that we've saved core state, there's may also * be MMU and cache state to care about ... */ if (arm11->simulate_reset_on_next_halt) { arm11->simulate_reset_on_next_halt = false; LOG_DEBUG("Reset c1 Control Register"); /* Write 0 (reset value) to Control register 0 to disable MMU/Cache etc. */ /* MCR p15,0,R0,c1,c0,0 */ retval = arm11_run_instr_data_to_core_via_r0(arm11, 0xee010f10, 0); if (retval != ERROR_OK) return retval; } if (arm11->arm.target->debug_reason == DBG_REASON_WATCHPOINT) { uint32_t wfar; /* MRC p15, 0, , c6, c0, 1 ; Read WFAR */ retval = arm11_run_instr_data_from_core_via_r0(arm11, ARMV4_5_MRC(15, 0, 0, 6, 0, 1), &wfar); if (retval != ERROR_OK) return retval; arm_dpm_report_wfar(arm11->arm.dpm, wfar); } retval = arm11_run_instr_data_finish(arm11); if (retval != ERROR_OK) return retval; return ERROR_OK; } /** * Restore processor state. This is called in preparation for * the RESTART function. */ static int arm11_leave_debug_state(struct arm11_common *arm11, bool bpwp) { int retval; /* See e.g. ARM1136 TRM, "14.8.5 Leaving Debug state" */ /* NOTE: the ARM1136 TRM suggests restoring all registers * except R0/PC/CPSR right now. Instead, we do them all * at once, just a bit later on. */ /* REVISIT once we start caring about MMU and cache state, * address it here ... */ /* spec says clear wDTR and rDTR; we assume they are clear as otherwise our programming would be sloppy */ { CHECK_RETVAL(arm11_read_DSCR(arm11)); if (arm11->dscr & (DSCR_DTR_RX_FULL | DSCR_DTR_TX_FULL)) { /* The wDTR/rDTR two registers that are used to send/receive data to/from the core in tandem with corresponding instruction codes that are written into the core. The RDTR FULL/WDTR FULL flag indicates that the registers hold data that was written by one side (CPU or JTAG) and not read out by the other side. */ LOG_ERROR("wDTR/rDTR inconsistent (DSCR %08x)", (unsigned) arm11->dscr); return ERROR_FAIL; } } /* maybe restore original wDTR */ if (arm11->is_wdtr_saved) { retval = arm11_run_instr_data_prepare(arm11); if (retval != ERROR_OK) return retval; /* MCR p14,0,R0,c0,c5,0 */ retval = arm11_run_instr_data_to_core_via_r0(arm11, 0xee000e15, arm11->saved_wdtr); if (retval != ERROR_OK) return retval; retval = arm11_run_instr_data_finish(arm11); if (retval != ERROR_OK) return retval; } /* restore CPSR, PC, and R0 ... after flushing any modified * registers. */ CHECK_RETVAL(arm_dpm_write_dirty_registers(&arm11->dpm, bpwp)); CHECK_RETVAL(arm11_bpwp_flush(arm11)); register_cache_invalidate(arm11->arm.core_cache); /* restore DSCR */ CHECK_RETVAL(arm11_write_DSCR(arm11, arm11->dscr)); /* maybe restore rDTR */ if (arm11->is_rdtr_saved) { arm11_add_debug_SCAN_N(arm11, 0x05, ARM11_TAP_DEFAULT); arm11_add_IR(arm11, ARM11_EXTEST, ARM11_TAP_DEFAULT); struct scan_field chain5_fields[3]; uint8_t Ready = 0; /* ignored */ uint8_t Valid = 0; /* ignored */ arm11_setup_field(arm11, 32, &arm11->saved_rdtr, NULL, chain5_fields + 0); arm11_setup_field(arm11, 1, &Ready, NULL, chain5_fields + 1); arm11_setup_field(arm11, 1, &Valid, NULL, chain5_fields + 2); arm11_add_dr_scan_vc(arm11->arm.target->tap, ARRAY_SIZE( chain5_fields), chain5_fields, TAP_DRPAUSE); } /* now processor is ready to RESTART */ return ERROR_OK; } /* poll current target status */ static int arm11_poll(struct target *target) { int retval; struct arm11_common *arm11 = target_to_arm11(target); CHECK_RETVAL(arm11_check_init(arm11)); if (arm11->dscr & DSCR_CORE_HALTED) { if (target->state != TARGET_HALTED) { enum target_state old_state = target->state; LOG_DEBUG("enter TARGET_HALTED"); retval = arm11_debug_entry(arm11); if (retval != ERROR_OK) return retval; target_call_event_callbacks(target, (old_state == TARGET_DEBUG_RUNNING) ? TARGET_EVENT_DEBUG_HALTED : TARGET_EVENT_HALTED); } } else { if (target->state != TARGET_RUNNING && target->state != TARGET_DEBUG_RUNNING) { LOG_DEBUG("enter TARGET_RUNNING"); target->state = TARGET_RUNNING; target->debug_reason = DBG_REASON_NOTHALTED; } } return ERROR_OK; } /* architecture specific status reply */ static int arm11_arch_state(struct target *target) { struct arm11_common *arm11 = target_to_arm11(target); int retval; retval = arm_arch_state(target); /* REVISIT also display ARM11-specific MMU and cache status ... */ if (target->debug_reason == DBG_REASON_WATCHPOINT) LOG_USER("Watchpoint triggered at PC %#08x", (unsigned) arm11->dpm.wp_pc); return retval; } /* target request support */ static int arm11_target_request_data(struct target *target, uint32_t size, uint8_t *buffer) { LOG_WARNING("Not implemented: %s", __func__); return ERROR_FAIL; } /* target execution control */ static int arm11_halt(struct target *target) { struct arm11_common *arm11 = target_to_arm11(target); LOG_DEBUG("target->state: %s", target_state_name(target)); if (target->state == TARGET_UNKNOWN) arm11->simulate_reset_on_next_halt = true; if (target->state == TARGET_HALTED) { LOG_DEBUG("target was already halted"); return ERROR_OK; } arm11_add_IR(arm11, ARM11_HALT, TAP_IDLE); CHECK_RETVAL(jtag_execute_queue()); int i = 0; while (1) { CHECK_RETVAL(arm11_read_DSCR(arm11)); if (arm11->dscr & DSCR_CORE_HALTED) break; long long then = 0; if (i == 1000) then = timeval_ms(); if (i >= 1000) { if ((timeval_ms()-then) > 1000) { LOG_WARNING("Timeout (1000ms) waiting for instructions to complete"); return ERROR_FAIL; } } i++; } enum target_state old_state = target->state; CHECK_RETVAL(arm11_debug_entry(arm11)); CHECK_RETVAL( target_call_event_callbacks(target, old_state == TARGET_DEBUG_RUNNING ? TARGET_EVENT_DEBUG_HALTED : TARGET_EVENT_HALTED)); return ERROR_OK; } static uint32_t arm11_nextpc(struct arm11_common *arm11, int current, uint32_t address) { void *value = arm11->arm.pc->value; if (!current) buf_set_u32(value, 0, 32, address); else address = buf_get_u32(value, 0, 32); return address; } static int arm11_resume(struct target *target, int current, uint32_t address, int handle_breakpoints, int debug_execution) { /* LOG_DEBUG("current %d address %08x handle_breakpoints %d debug_execution %d", */ /* current, address, handle_breakpoints, debug_execution); */ struct arm11_common *arm11 = target_to_arm11(target); LOG_DEBUG("target->state: %s", target_state_name(target)); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } address = arm11_nextpc(arm11, current, address); LOG_DEBUG("RESUME PC %08" PRIx32 "%s", address, !current ? "!" : ""); /* clear breakpoints/watchpoints and VCR*/ CHECK_RETVAL(arm11_sc7_clear_vbw(arm11)); if (!debug_execution) target_free_all_working_areas(target); /* Should we skip over breakpoints matching the PC? */ if (handle_breakpoints) { struct breakpoint *bp; for (bp = target->breakpoints; bp; bp = bp->next) { if (bp->address == address) { LOG_DEBUG("must step over %08" PRIx32 "", bp->address); arm11_step(target, 1, 0, 0); break; } } } /* activate all breakpoints */ if (true) { struct breakpoint *bp; unsigned brp_num = 0; for (bp = target->breakpoints; bp; bp = bp->next) { struct arm11_sc7_action brp[2]; brp[0].write = 1; brp[0].address = ARM11_SC7_BVR0 + brp_num; brp[0].value = bp->address; brp[1].write = 1; brp[1].address = ARM11_SC7_BCR0 + brp_num; brp[1].value = 0x1 | (3 << 1) | (0x0F << 5) | (0 << 14) | (0 << 16) | (0 << 20) | (0 << 21); CHECK_RETVAL(arm11_sc7_run(arm11, brp, ARRAY_SIZE(brp))); LOG_DEBUG("Add BP %d at %08" PRIx32, brp_num, bp->address); brp_num++; } if (arm11->vcr) CHECK_RETVAL(arm11_sc7_set_vcr(arm11, arm11->vcr)); } /* activate all watchpoints and breakpoints */ CHECK_RETVAL(arm11_leave_debug_state(arm11, true)); arm11_add_IR(arm11, ARM11_RESTART, TAP_IDLE); CHECK_RETVAL(jtag_execute_queue()); int i = 0; while (1) { CHECK_RETVAL(arm11_read_DSCR(arm11)); LOG_DEBUG("DSCR %08x", (unsigned) arm11->dscr); if (arm11->dscr & DSCR_CORE_RESTARTED) break; long long then = 0; if (i == 1000) then = timeval_ms(); if (i >= 1000) { if ((timeval_ms()-then) > 1000) { LOG_WARNING("Timeout (1000ms) waiting for instructions to complete"); return ERROR_FAIL; } } i++; } target->debug_reason = DBG_REASON_NOTHALTED; if (!debug_execution) target->state = TARGET_RUNNING; else target->state = TARGET_DEBUG_RUNNING; CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_RESUMED)); return ERROR_OK; } static int arm11_step(struct target *target, int current, uint32_t address, int handle_breakpoints) { LOG_DEBUG("target->state: %s", target_state_name(target)); if (target->state != TARGET_HALTED) { LOG_WARNING("target was not halted"); return ERROR_TARGET_NOT_HALTED; } struct arm11_common *arm11 = target_to_arm11(target); address = arm11_nextpc(arm11, current, address); LOG_DEBUG("STEP PC %08" PRIx32 "%s", address, !current ? "!" : ""); /** \todo TODO: Thumb not supported here */ uint32_t next_instruction; CHECK_RETVAL(arm11_read_memory_word(arm11, address, &next_instruction)); /* skip over BKPT */ if ((next_instruction & 0xFFF00070) == 0xe1200070) { address = arm11_nextpc(arm11, 0, address + 4); LOG_DEBUG("Skipping BKPT %08" PRIx32, address); } /* skip over Wait for interrupt / Standby * mcr 15, 0, r?, cr7, cr0, {4} */ else if ((next_instruction & 0xFFFF0FFF) == 0xee070f90) { address = arm11_nextpc(arm11, 0, address + 4); LOG_DEBUG("Skipping WFI %08" PRIx32, address); } /* ignore B to self */ else if ((next_instruction & 0xFEFFFFFF) == 0xeafffffe) LOG_DEBUG("Not stepping jump to self"); else { /** \todo TODO: check if break-/watchpoints make any sense at all in combination * with this. */ /** \todo TODO: check if disabling IRQs might be a good idea here. Alternatively * the VCR might be something worth looking into. */ /* Set up breakpoint for stepping */ struct arm11_sc7_action brp[2]; brp[0].write = 1; brp[0].address = ARM11_SC7_BVR0; brp[1].write = 1; brp[1].address = ARM11_SC7_BCR0; if (arm11->hardware_step) { /* Hardware single stepping ("instruction address * mismatch") is used if enabled. It's not quite * exactly "run one instruction"; "branch to here" * loops won't break, neither will some other cases, * but it's probably the best default. * * Hardware single stepping isn't supported on v6 * debug modules. ARM1176 and v7 can support it... * * FIXME Thumb stepping likely needs to use 0x03 * or 0xc0 byte masks, not 0x0f. */ brp[0].value = address; brp[1].value = 0x1 | (3 << 1) | (0x0F << 5) | (0 << 14) | (0 << 16) | (0 << 20) | (2 << 21); } else { /* Sets a breakpoint on the next PC, as calculated * by instruction set simulation. * * REVISIT stepping Thumb on ARM1156 requires Thumb2 * support from the simulator. */ uint32_t next_pc; int retval; retval = arm_simulate_step(target, &next_pc); if (retval != ERROR_OK) return retval; brp[0].value = next_pc; brp[1].value = 0x1 | (3 << 1) | (0x0F << 5) | (0 << 14) | (0 << 16) | (0 << 20) | (0 << 21); } CHECK_RETVAL(arm11_sc7_run(arm11, brp, ARRAY_SIZE(brp))); /* resume */ if (arm11->step_irq_enable) /* this disable should be redundant ... */ arm11->dscr &= ~DSCR_INT_DIS; else arm11->dscr |= DSCR_INT_DIS; CHECK_RETVAL(arm11_leave_debug_state(arm11, handle_breakpoints)); arm11_add_IR(arm11, ARM11_RESTART, TAP_IDLE); CHECK_RETVAL(jtag_execute_queue()); /* wait for halt */ int i = 0; while (1) { const uint32_t mask = DSCR_CORE_RESTARTED | DSCR_CORE_HALTED; CHECK_RETVAL(arm11_read_DSCR(arm11)); LOG_DEBUG("DSCR %08x e", (unsigned) arm11->dscr); if ((arm11->dscr & mask) == mask) break; long long then = 0; if (i == 1000) then = timeval_ms(); if (i >= 1000) { if ((timeval_ms()-then) > 1000) { LOG_WARNING( "Timeout (1000ms) waiting for instructions to complete"); return ERROR_FAIL; } } i++; } /* clear breakpoint */ CHECK_RETVAL(arm11_sc7_clear_vbw(arm11)); /* save state */ CHECK_RETVAL(arm11_debug_entry(arm11)); /* restore default state */ arm11->dscr &= ~DSCR_INT_DIS; } target->debug_reason = DBG_REASON_SINGLESTEP; CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_HALTED)); return ERROR_OK; } static int arm11_assert_reset(struct target *target) { struct arm11_common *arm11 = target_to_arm11(target); /* optionally catch reset vector */ if (target->reset_halt && !(arm11->vcr & 1)) CHECK_RETVAL(arm11_sc7_set_vcr(arm11, arm11->vcr | 1)); /* Issue some kind of warm reset. */ if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT)) target_handle_event(target, TARGET_EVENT_RESET_ASSERT); else if (jtag_get_reset_config() & RESET_HAS_SRST) { /* REVISIT handle "pulls" cases, if there's * hardware that needs them to work. */ jtag_add_reset(0, 1); } else { LOG_ERROR("%s: how to reset?", target_name(target)); return ERROR_FAIL; } /* registers are now invalid */ register_cache_invalidate(arm11->arm.core_cache); target->state = TARGET_RESET; return ERROR_OK; } /* * - There is another bug in the arm11 core. (iMX31 specific again?) * When you generate an access to external logic (for example DDR * controller via AHB bus) and that block is not configured (perhaps * it is still held in reset), that transaction will never complete. * This will hang arm11 core but it will also hang JTAG controller. * Nothing short of srst assertion will bring it out of this. */ static int arm11_deassert_reset(struct target *target) { struct arm11_common *arm11 = target_to_arm11(target); int retval; /* be certain SRST is off */ jtag_add_reset(0, 0); /* WORKAROUND i.MX31 problems: SRST goofs the TAP, and resets * at least DSCR. OMAP24xx doesn't show that problem, though * SRST-only reset seems to be problematic for other reasons. * (Secure boot sequences being one likelihood!) */ jtag_add_tlr(); CHECK_RETVAL(arm11_poll(target)); if (target->reset_halt) { if (target->state != TARGET_HALTED) { LOG_WARNING("%s: ran after reset and before halt ...", target_name(target)); retval = target_halt(target); if (retval != ERROR_OK) return retval; } } /* maybe restore vector catch config */ if (target->reset_halt && !(arm11->vcr & 1)) CHECK_RETVAL(arm11_sc7_set_vcr(arm11, arm11->vcr)); return ERROR_OK; } static int arm11_soft_reset_halt(struct target *target) { LOG_WARNING("Not implemented: %s", __func__); return ERROR_FAIL; } /* target memory access * size: 1 = byte (8bit), 2 = half-word (16bit), 4 = word (32bit) * count: number of items of * * arm11_config_memrw_no_increment - in the future we may want to be able * to read/write a range of data to a "port". a "port" is an action on * read memory address for some peripheral. */ static int arm11_read_memory_inner(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer, bool arm11_config_memrw_no_increment) { /** \todo TODO: check if buffer cast to uint32_t* and uint16_t* might cause alignment *problems */ int retval; if (target->state != TARGET_HALTED) { LOG_WARNING("target was not halted"); return ERROR_TARGET_NOT_HALTED; } LOG_DEBUG("ADDR %08" PRIx32 " SIZE %08" PRIx32 " COUNT %08" PRIx32 "", address, size, count); struct arm11_common *arm11 = target_to_arm11(target); retval = arm11_run_instr_data_prepare(arm11); if (retval != ERROR_OK) return retval; /* MRC p14,0,r0,c0,c5,0 */ retval = arm11_run_instr_data_to_core1(arm11, 0xee100e15, address); if (retval != ERROR_OK) return retval; switch (size) { case 1: arm11->arm.core_cache->reg_list[1].dirty = true; for (size_t i = 0; i < count; i++) { /* ldrb r1, [r0], #1 */ /* ldrb r1, [r0] */ CHECK_RETVAL(arm11_run_instr_no_data1(arm11, !arm11_config_memrw_no_increment ? 0xe4d01001 : 0xe5d01000)); uint32_t res; /* MCR p14,0,R1,c0,c5,0 */ CHECK_RETVAL(arm11_run_instr_data_from_core(arm11, 0xEE001E15, &res, 1)); *buffer++ = res; } break; case 2: { arm11->arm.core_cache->reg_list[1].dirty = true; for (size_t i = 0; i < count; i++) { /* ldrh r1, [r0], #2 */ CHECK_RETVAL(arm11_run_instr_no_data1(arm11, !arm11_config_memrw_no_increment ? 0xe0d010b2 : 0xe1d010b0)); uint32_t res; /* MCR p14,0,R1,c0,c5,0 */ CHECK_RETVAL(arm11_run_instr_data_from_core(arm11, 0xEE001E15, &res, 1)); uint16_t svalue = res; memcpy(buffer + i * sizeof(uint16_t), &svalue, sizeof(uint16_t)); } break; } case 4: { uint32_t instr = !arm11_config_memrw_no_increment ? 0xecb05e01 : 0xed905e00; /** \todo TODO: buffer cast to uint32_t* causes alignment warnings */ uint32_t *words = (uint32_t *)(void *)buffer; /* LDC p14,c5,[R0],#4 */ /* LDC p14,c5,[R0] */ CHECK_RETVAL(arm11_run_instr_data_from_core(arm11, instr, words, count)); break; } } return arm11_run_instr_data_finish(arm11); } static int arm11_read_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) { return arm11_read_memory_inner(target, address, size, count, buffer, false); } /* * no_increment - in the future we may want to be able * to read/write a range of data to a "port". a "port" is an action on * read memory address for some peripheral. */ static int arm11_write_memory_inner(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer, bool no_increment) { int retval; if (target->state != TARGET_HALTED) { LOG_WARNING("target was not halted"); return ERROR_TARGET_NOT_HALTED; } LOG_DEBUG("ADDR %08" PRIx32 " SIZE %08" PRIx32 " COUNT %08" PRIx32 "", address, size, count); struct arm11_common *arm11 = target_to_arm11(target); retval = arm11_run_instr_data_prepare(arm11); if (retval != ERROR_OK) return retval; /* load r0 with buffer address * MRC p14,0,r0,c0,c5,0 */ retval = arm11_run_instr_data_to_core1(arm11, 0xee100e15, address); if (retval != ERROR_OK) return retval; /* burst writes are not used for single words as those may well be * reset init script writes. * * The other advantage is that as burst writes are default, we'll * now exercise both burst and non-burst code paths with the * default settings, increasing code coverage. */ bool burst = arm11->memwrite_burst && (count > 1); switch (size) { case 1: { arm11->arm.core_cache->reg_list[1].dirty = true; for (size_t i = 0; i < count; i++) { /* load r1 from DCC with byte data */ /* MRC p14,0,r1,c0,c5,0 */ retval = arm11_run_instr_data_to_core1(arm11, 0xee101e15, *buffer++); if (retval != ERROR_OK) return retval; /* write r1 to memory */ /* strb r1, [r0], #1 */ /* strb r1, [r0] */ retval = arm11_run_instr_no_data1(arm11, !no_increment ? 0xe4c01001 : 0xe5c01000); if (retval != ERROR_OK) return retval; } break; } case 2: { arm11->arm.core_cache->reg_list[1].dirty = true; for (size_t i = 0; i < count; i++) { uint16_t value; memcpy(&value, buffer + i * sizeof(uint16_t), sizeof(uint16_t)); /* load r1 from DCC with halfword data */ /* MRC p14,0,r1,c0,c5,0 */ retval = arm11_run_instr_data_to_core1(arm11, 0xee101e15, value); if (retval != ERROR_OK) return retval; /* write r1 to memory */ /* strh r1, [r0], #2 */ /* strh r1, [r0] */ retval = arm11_run_instr_no_data1(arm11, !no_increment ? 0xe0c010b2 : 0xe1c010b0); if (retval != ERROR_OK) return retval; } break; } case 4: { /* stream word data through DCC directly to memory */ /* increment: STC p14,c5,[R0],#4 */ /* no increment: STC p14,c5,[R0]*/ uint32_t instr = !no_increment ? 0xeca05e01 : 0xed805e00; /** \todo TODO: buffer cast to uint32_t* causes alignment warnings */ uint32_t *words = (uint32_t *)(void *)buffer; /* "burst" here just means trusting each instruction executes * fully before we run the next one: per-word roundtrips, to * check the Ready flag, are not used. */ if (!burst) retval = arm11_run_instr_data_to_core(arm11, instr, words, count); else retval = arm11_run_instr_data_to_core_noack(arm11, instr, words, count); if (retval != ERROR_OK) return retval; break; } } /* r0 verification */ if (!no_increment) { uint32_t r0; /* MCR p14,0,R0,c0,c5,0 */ retval = arm11_run_instr_data_from_core(arm11, 0xEE000E15, &r0, 1); if (retval != ERROR_OK) return retval; if (address + size * count != r0) { LOG_ERROR("Data transfer failed. Expected end " "address 0x%08x, got 0x%08x", (unsigned) (address + size * count), (unsigned) r0); if (burst) LOG_ERROR( "use 'arm11 memwrite burst disable' to disable fast burst mode"); if (arm11->memwrite_error_fatal) return ERROR_FAIL; } } return arm11_run_instr_data_finish(arm11); } static int arm11_write_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { /* pointer increment matters only for multi-unit writes ... * not e.g. to a "reset the chip" controller. */ return arm11_write_memory_inner(target, address, size, count, buffer, count == 1); } /* target break-/watchpoint control * rw: 0 = write, 1 = read, 2 = access */ static int arm11_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct arm11_common *arm11 = target_to_arm11(target); #if 0 if (breakpoint->type == BKPT_SOFT) { LOG_INFO("sw breakpoint requested, but software breakpoints not enabled"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } #endif if (!arm11->free_brps) { LOG_DEBUG("no breakpoint unit available for hardware breakpoint"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if (breakpoint->length != 4) { LOG_DEBUG("only breakpoints of four bytes length supported"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } arm11->free_brps--; return ERROR_OK; } static int arm11_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct arm11_common *arm11 = target_to_arm11(target); arm11->free_brps++; return ERROR_OK; } static int arm11_target_create(struct target *target, Jim_Interp *interp) { struct arm11_common *arm11; if (target->tap == NULL) return ERROR_FAIL; if (target->tap->ir_length != 5) { LOG_ERROR("'target arm11' expects IR LENGTH = 5"); return ERROR_COMMAND_SYNTAX_ERROR; } arm11 = calloc(1, sizeof *arm11); if (!arm11) return ERROR_FAIL; arm11->arm.core_type = ARM_MODE_ANY; arm_init_arch_info(target, &arm11->arm); arm11->jtag_info.tap = target->tap; arm11->jtag_info.scann_size = 5; arm11->jtag_info.scann_instr = ARM11_SCAN_N; arm11->jtag_info.cur_scan_chain = ~0; /* invalid/unknown */ arm11->jtag_info.intest_instr = ARM11_INTEST; arm11->memwrite_burst = true; arm11->memwrite_error_fatal = true; return ERROR_OK; } static int arm11_init_target(struct command_context *cmd_ctx, struct target *target) { /* Initialize anything we can set up without talking to the target */ return ERROR_OK; } /* talk to the target and set things up */ static int arm11_examine(struct target *target) { int retval; char *type; struct arm11_common *arm11 = target_to_arm11(target); uint32_t didr, device_id; uint8_t implementor; /* FIXME split into do-first-time and do-every-time logic ... */ /* check IDCODE */ arm11_add_IR(arm11, ARM11_IDCODE, ARM11_TAP_DEFAULT); struct scan_field idcode_field; arm11_setup_field(arm11, 32, NULL, &device_id, &idcode_field); arm11_add_dr_scan_vc(arm11->arm.target->tap, 1, &idcode_field, TAP_DRPAUSE); /* check DIDR */ arm11_add_debug_SCAN_N(arm11, 0x00, ARM11_TAP_DEFAULT); arm11_add_IR(arm11, ARM11_INTEST, ARM11_TAP_DEFAULT); struct scan_field chain0_fields[2]; arm11_setup_field(arm11, 32, NULL, &didr, chain0_fields + 0); arm11_setup_field(arm11, 8, NULL, &implementor, chain0_fields + 1); arm11_add_dr_scan_vc(arm11->arm.target->tap, ARRAY_SIZE( chain0_fields), chain0_fields, TAP_IDLE); CHECK_RETVAL(jtag_execute_queue()); /* assume the manufacturer id is ok; check the part # */ switch ((device_id >> 12) & 0xFFFF) { case 0x7B36: type = "ARM1136"; break; case 0x7B37: type = "ARM11 MPCore"; break; case 0x7B56: type = "ARM1156"; break; case 0x7B76: arm11->arm.core_type = ARM_MODE_MON; /* NOTE: could default arm11->hardware_step to true */ type = "ARM1176"; break; default: LOG_ERROR("unexpected ARM11 ID code"); return ERROR_FAIL; } LOG_INFO("found %s", type); /* unlikely this could ever fail, but ... */ switch ((didr >> 16) & 0x0F) { case ARM11_DEBUG_V6: case ARM11_DEBUG_V61: /* supports security extensions */ break; default: LOG_ERROR("Only ARM v6 and v6.1 debug supported."); return ERROR_FAIL; } arm11->brp = ((didr >> 24) & 0x0F) + 1; /** \todo TODO: reserve one brp slot if we allow breakpoints during step */ arm11->free_brps = arm11->brp; LOG_DEBUG("IDCODE %08" PRIx32 " IMPLEMENTOR %02x DIDR %08" PRIx32, device_id, implementor, didr); /* as a side-effect this reads DSCR and thus * clears the ARM11_DSCR_STICKY_PRECISE_DATA_ABORT / Sticky Precise Data Abort Flag * as suggested by the spec. */ retval = arm11_check_init(arm11); if (retval != ERROR_OK) return retval; /* Build register cache "late", after target_init(), since we * want to know if this core supports Secure Monitor mode. */ if (!target_was_examined(target)) CHECK_RETVAL(arm11_dpm_init(arm11, didr)); /* ETM on ARM11 still uses original scanchain 6 access mode */ if (arm11->arm.etm && !target_was_examined(target)) { *register_get_last_cache_p(&target->reg_cache) = etm_build_reg_cache(target, &arm11->jtag_info, arm11->arm.etm); CHECK_RETVAL(etm_setup(target)); } target_set_examined(target); return ERROR_OK; } #define ARM11_BOOL_WRAPPER(name, print_name) \ COMMAND_HANDLER(arm11_handle_bool_ ## name) \ { \ struct target *target = get_current_target(CMD_CTX); \ struct arm11_common *arm11 = target_to_arm11(target); \ \ return CALL_COMMAND_HANDLER(handle_command_parse_bool, \ &arm11->name, print_name); \ } ARM11_BOOL_WRAPPER(memwrite_burst, "memory write burst mode") ARM11_BOOL_WRAPPER(memwrite_error_fatal, "fatal error mode for memory writes") ARM11_BOOL_WRAPPER(step_irq_enable, "IRQs while stepping") ARM11_BOOL_WRAPPER(hardware_step, "hardware single step") /* REVISIT handle the VCR bits like other ARMs: use symbols for * input and output values. */ COMMAND_HANDLER(arm11_handle_vcr) { struct target *target = get_current_target(CMD_CTX); struct arm11_common *arm11 = target_to_arm11(target); switch (CMD_ARGC) { case 0: break; case 1: COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], arm11->vcr); break; default: return ERROR_COMMAND_SYNTAX_ERROR; } LOG_INFO("VCR 0x%08" PRIx32 "", arm11->vcr); return ERROR_OK; } static const struct command_registration arm11_mw_command_handlers[] = { { .name = "burst", .handler = arm11_handle_bool_memwrite_burst, .mode = COMMAND_ANY, .help = "Display or modify flag controlling potentially " "risky fast burst mode (default: enabled)", .usage = "['enable'|'disable']", }, { .name = "error_fatal", .handler = arm11_handle_bool_memwrite_error_fatal, .mode = COMMAND_ANY, .help = "Display or modify flag controlling transfer " "termination on transfer errors" " (default: enabled)", .usage = "['enable'|'disable']", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration arm11_any_command_handlers[] = { { /* "hardware_step" is only here to check if the default * simulate + breakpoint implementation is broken. * TEMPORARY! NOT DOCUMENTED! */ .name = "hardware_step", .handler = arm11_handle_bool_hardware_step, .mode = COMMAND_ANY, .help = "DEBUG ONLY - Hardware single stepping" " (default: disabled)", .usage = "['enable'|'disable']", }, { .name = "memwrite", .mode = COMMAND_ANY, .help = "memwrite command group", .usage = "", .chain = arm11_mw_command_handlers, }, { .name = "step_irq_enable", .handler = arm11_handle_bool_step_irq_enable, .mode = COMMAND_ANY, .help = "Display or modify flag controlling interrupt " "enable while stepping (default: disabled)", .usage = "['enable'|'disable']", }, { .name = "vcr", .handler = arm11_handle_vcr, .mode = COMMAND_ANY, .help = "Display or modify Vector Catch Register", .usage = "[value]", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration arm11_command_handlers[] = { { .chain = arm_command_handlers, }, { .chain = etm_command_handlers, }, { .name = "arm11", .mode = COMMAND_ANY, .help = "ARM11 command group", .usage = "", .chain = arm11_any_command_handlers, }, COMMAND_REGISTRATION_DONE }; /** Holds methods for ARM11xx targets. */ struct target_type arm11_target = { .name = "arm11", .poll = arm11_poll, .arch_state = arm11_arch_state, .target_request_data = arm11_target_request_data, .halt = arm11_halt, .resume = arm11_resume, .step = arm11_step, .assert_reset = arm11_assert_reset, .deassert_reset = arm11_deassert_reset, .soft_reset_halt = arm11_soft_reset_halt, .get_gdb_reg_list = arm_get_gdb_reg_list, .read_memory = arm11_read_memory, .write_memory = arm11_write_memory, .checksum_memory = arm_checksum_memory, .blank_check_memory = arm_blank_check_memory, .add_breakpoint = arm11_add_breakpoint, .remove_breakpoint = arm11_remove_breakpoint, .run_algorithm = armv4_5_run_algorithm, .commands = arm11_command_handlers, .target_create = arm11_target_create, .init_target = arm11_init_target, .examine = arm11_examine, }; openocd-0.7.0/src/target/avrt.c0000644000175000001440000001474012134336410013262 00000000000000/*************************************************************************** * Copyright (C) 2009 by Simon Qian * * SimonQian@SimonQian.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "avrt.h" #include "target.h" #include "target_type.h" #define AVR_JTAG_INS_LEN 4 /* forward declarations */ static int avr_target_create(struct target *target, Jim_Interp *interp); static int avr_init_target(struct command_context *cmd_ctx, struct target *target); static int avr_arch_state(struct target *target); static int avr_poll(struct target *target); static int avr_halt(struct target *target); static int avr_resume(struct target *target, int current, uint32_t address, int handle_breakpoints, int debug_execution); static int avr_step(struct target *target, int current, uint32_t address, int handle_breakpoints); static int avr_assert_reset(struct target *target); static int avr_deassert_reset(struct target *target); static int avr_soft_reset_halt(struct target *target); /* IR and DR functions */ static int mcu_write_ir(struct jtag_tap *tap, uint8_t *ir_in, uint8_t *ir_out, int ir_len, int rti); static int mcu_write_dr(struct jtag_tap *tap, uint8_t *dr_in, uint8_t *dr_out, int dr_len, int rti); static int mcu_write_ir_u8(struct jtag_tap *tap, uint8_t *ir_in, uint8_t ir_out, int ir_len, int rti); static int mcu_write_dr_u32(struct jtag_tap *tap, uint32_t *ir_in, uint32_t ir_out, int dr_len, int rti); struct target_type avr_target = { .name = "avr", .poll = avr_poll, .arch_state = avr_arch_state, .target_request_data = NULL, .halt = avr_halt, .resume = avr_resume, .step = avr_step, .assert_reset = avr_assert_reset, .deassert_reset = avr_deassert_reset, .soft_reset_halt = avr_soft_reset_halt, /* .get_gdb_reg_list = avr_get_gdb_reg_list, .read_memory = avr_read_memory, .write_memory = avr_write_memory, .bulk_write_memory = avr_bulk_write_memory, .checksum_memory = avr_checksum_memory, .blank_check_memory = avr_blank_check_memory, .run_algorithm = avr_run_algorithm, .add_breakpoint = avr_add_breakpoint, .remove_breakpoint = avr_remove_breakpoint, .add_watchpoint = avr_add_watchpoint, .remove_watchpoint = avr_remove_watchpoint, */ .target_create = avr_target_create, .init_target = avr_init_target, }; static int avr_target_create(struct target *target, Jim_Interp *interp) { struct avr_common *avr = calloc(1, sizeof(struct avr_common)); avr->jtag_info.tap = target->tap; target->arch_info = avr; return ERROR_OK; } static int avr_init_target(struct command_context *cmd_ctx, struct target *target) { LOG_DEBUG("%s", __func__); return ERROR_OK; } static int avr_arch_state(struct target *target) { LOG_DEBUG("%s", __func__); return ERROR_OK; } static int avr_poll(struct target *target) { if ((target->state == TARGET_RUNNING) || (target->state == TARGET_DEBUG_RUNNING)) target->state = TARGET_HALTED; LOG_DEBUG("%s", __func__); return ERROR_OK; } static int avr_halt(struct target *target) { LOG_DEBUG("%s", __func__); return ERROR_OK; } static int avr_resume(struct target *target, int current, uint32_t address, int handle_breakpoints, int debug_execution) { LOG_DEBUG("%s", __func__); return ERROR_OK; } static int avr_step(struct target *target, int current, uint32_t address, int handle_breakpoints) { LOG_DEBUG("%s", __func__); return ERROR_OK; } static int avr_assert_reset(struct target *target) { target->state = TARGET_RESET; LOG_DEBUG("%s", __func__); return ERROR_OK; } static int avr_deassert_reset(struct target *target) { target->state = TARGET_RUNNING; LOG_DEBUG("%s", __func__); return ERROR_OK; } static int avr_soft_reset_halt(struct target *target) { LOG_DEBUG("%s", __func__); return ERROR_OK; } int avr_jtag_senddat(struct jtag_tap *tap, uint32_t* dr_in, uint32_t dr_out, int len) { return mcu_write_dr_u32(tap, dr_in, dr_out, len, 1); } int avr_jtag_sendinstr(struct jtag_tap *tap, uint8_t *ir_in, uint8_t ir_out) { return mcu_write_ir_u8(tap, ir_in, ir_out, AVR_JTAG_INS_LEN, 1); } /* IR and DR functions */ static int mcu_write_ir(struct jtag_tap *tap, uint8_t *ir_in, uint8_t *ir_out, int ir_len, int rti) { if (NULL == tap) { LOG_ERROR("invalid tap"); return ERROR_FAIL; } if (ir_len != tap->ir_length) { LOG_ERROR("invalid ir_len"); return ERROR_FAIL; } { jtag_add_plain_ir_scan(tap->ir_length, ir_out, ir_in, TAP_IDLE); } return ERROR_OK; } static int mcu_write_dr(struct jtag_tap *tap, uint8_t *dr_in, uint8_t *dr_out, int dr_len, int rti) { if (NULL == tap) { LOG_ERROR("invalid tap"); return ERROR_FAIL; } { jtag_add_plain_dr_scan(dr_len, dr_out, dr_in, TAP_IDLE); } return ERROR_OK; } static int mcu_write_ir_u8(struct jtag_tap *tap, uint8_t *ir_in, uint8_t ir_out, int ir_len, int rti) { if (ir_len > 8) { LOG_ERROR("ir_len overflow, maxium is 8"); return ERROR_FAIL; } mcu_write_ir(tap, ir_in, &ir_out, ir_len, rti); return ERROR_OK; } static int mcu_write_dr_u32(struct jtag_tap *tap, uint32_t *dr_in, uint32_t dr_out, int dr_len, int rti) { if (dr_len > 32) { LOG_ERROR("dr_len overflow, maxium is 32"); return ERROR_FAIL; } mcu_write_dr(tap, (uint8_t *)dr_in, (uint8_t *)&dr_out, dr_len, rti); return ERROR_OK; } int mcu_execute_queue(void) { return jtag_execute_queue(); } openocd-0.7.0/src/target/avr32_jtag.c0000644000175000001440000002175012134336410014247 00000000000000/*************************************************************************** * Copyright (C) 2010 by Oleksandr Tymoshenko * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "target.h" #include "jtag/jtag.h" #include "avr32_jtag.h" static int avr32_jtag_set_instr(struct avr32_jtag *jtag_info, int new_instr) { struct jtag_tap *tap; int busy = 0; tap = jtag_info->tap; if (tap == NULL) return ERROR_FAIL; if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != (uint32_t)new_instr) { do { struct scan_field field; uint8_t t[4]; uint8_t ret[4]; field.num_bits = tap->ir_length; field.out_value = t; buf_set_u32(t, 0, field.num_bits, new_instr); field.in_value = ret; jtag_add_ir_scan(tap, &field, TAP_IDLE); if (jtag_execute_queue() != ERROR_OK) { LOG_ERROR("%s: setting address failed", __func__); return ERROR_FAIL; } busy = buf_get_u32(ret, 2, 1); } while (busy); /* check for busy bit */ } return ERROR_OK; } int avr32_jtag_nexus_set_address(struct avr32_jtag *jtag_info, uint32_t addr, int mode) { struct scan_field fields[2]; uint8_t addr_buf[4]; uint8_t busy_buf[4]; int busy; memset(fields, 0, sizeof(fields)); do { memset(addr_buf, 0, sizeof(addr_buf)); memset(busy_buf, 0, sizeof(busy_buf)); buf_set_u32(addr_buf, 0, 1, mode); buf_set_u32(addr_buf, 1, 7, addr); fields[0].num_bits = 26; fields[0].in_value = NULL; fields[0].out_value = NULL; fields[1].num_bits = 8; fields[1].in_value = busy_buf; fields[1].out_value = addr_buf; jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_IDLE); if (jtag_execute_queue() != ERROR_OK) { LOG_ERROR("%s: setting address failed", __func__); return ERROR_FAIL; } busy = buf_get_u32(busy_buf, 6, 1); } while (busy); return ERROR_OK; } int avr32_jtag_nexus_read_data(struct avr32_jtag *jtag_info, uint32_t *pdata) { struct scan_field fields[2]; uint8_t data_buf[4]; uint8_t busy_buf[4]; int busy; do { memset(data_buf, 0, sizeof(data_buf)); memset(busy_buf, 0, sizeof(busy_buf)); fields[0].num_bits = 32; fields[0].out_value = NULL; fields[0].in_value = data_buf; fields[1].num_bits = 2; fields[1].in_value = busy_buf; fields[1].out_value = NULL; jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_IDLE); if (jtag_execute_queue() != ERROR_OK) { LOG_ERROR("%s: reading data failed", __func__); return ERROR_FAIL; } busy = buf_get_u32(busy_buf, 0, 1); } while (busy); *pdata = buf_get_u32(data_buf, 0, 32); return ERROR_OK; } int avr32_jtag_nexus_write_data(struct avr32_jtag *jtag_info, uint32_t data) { struct scan_field fields[2]; uint8_t data_buf[4]; uint8_t busy_buf[4]; uint8_t dummy_buf[4]; int busy; do { memset(data_buf, 0, sizeof(data_buf)); memset(busy_buf, 0, sizeof(busy_buf)); memset(dummy_buf, 0, sizeof(dummy_buf)); fields[0].num_bits = 2; fields[0].in_value = busy_buf; fields[0].out_value = dummy_buf; buf_set_u32(data_buf, 0, 32, data); fields[1].num_bits = 32; fields[1].in_value = NULL; fields[1].out_value = data_buf; jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_IDLE); if (jtag_execute_queue() != ERROR_OK) { LOG_ERROR("%s: reading data failed", __func__); return ERROR_FAIL; } busy = buf_get_u32(busy_buf, 0, 0); } while (busy); return ERROR_OK; } int avr32_jtag_nexus_read(struct avr32_jtag *jtag_info, uint32_t addr, uint32_t *value) { avr32_jtag_set_instr(jtag_info, AVR32_INST_NEXUS_ACCESS); avr32_jtag_nexus_set_address(jtag_info, addr, MODE_READ); avr32_jtag_nexus_read_data(jtag_info, value); return ERROR_OK; } int avr32_jtag_nexus_write(struct avr32_jtag *jtag_info, uint32_t addr, uint32_t value) { avr32_jtag_set_instr(jtag_info, AVR32_INST_NEXUS_ACCESS); avr32_jtag_nexus_set_address(jtag_info, addr, MODE_WRITE); avr32_jtag_nexus_write_data(jtag_info, value); return ERROR_OK; } int avr32_jtag_mwa_set_address(struct avr32_jtag *jtag_info, int slave, uint32_t addr, int mode) { struct scan_field fields[2]; uint8_t addr_buf[4]; uint8_t slave_buf[4]; uint8_t busy_buf[4]; int busy; memset(fields, 0, sizeof(fields)); do { memset(addr_buf, 0, sizeof(addr_buf)); memset(busy_buf, 0, sizeof(busy_buf)); memset(slave_buf, 0, sizeof(slave_buf)); buf_set_u32(slave_buf, 0, 4, slave); buf_set_u32(addr_buf, 0, 1, mode); buf_set_u32(addr_buf, 1, 30, addr >> 2); fields[0].num_bits = 31; fields[0].in_value = NULL; fields[0].out_value = addr_buf; fields[1].num_bits = 4; fields[1].in_value = busy_buf; fields[1].out_value = slave_buf; jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_IDLE); if (jtag_execute_queue() != ERROR_OK) { LOG_ERROR("%s: setting address failed", __func__); return ERROR_FAIL; } busy = buf_get_u32(busy_buf, 1, 1); } while (busy); return ERROR_OK; } int avr32_jtag_mwa_read_data(struct avr32_jtag *jtag_info, uint32_t *pdata) { struct scan_field fields[2]; uint8_t data_buf[4]; uint8_t busy_buf[4]; int busy; do { memset(data_buf, 0, sizeof(data_buf)); memset(busy_buf, 0, sizeof(busy_buf)); fields[0].num_bits = 32; fields[0].out_value = NULL; fields[0].in_value = data_buf; fields[1].num_bits = 3; fields[1].in_value = busy_buf; fields[1].out_value = NULL; jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_IDLE); if (jtag_execute_queue() != ERROR_OK) { LOG_ERROR("%s: reading data failed", __func__); return ERROR_FAIL; } busy = buf_get_u32(busy_buf, 0, 1); } while (busy); *pdata = buf_get_u32(data_buf, 0, 32); return ERROR_OK; } int avr32_jtag_mwa_write_data(struct avr32_jtag *jtag_info, uint32_t data) { struct scan_field fields[2]; uint8_t data_buf[4]; uint8_t busy_buf[4]; uint8_t zero_buf[4]; int busy; do { memset(data_buf, 0, sizeof(data_buf)); memset(busy_buf, 0, sizeof(busy_buf)); memset(zero_buf, 0, sizeof(zero_buf)); buf_set_u32(data_buf, 0, 32, data); fields[0].num_bits = 3; fields[0].in_value = busy_buf; fields[0].out_value = zero_buf; fields[1].num_bits = 32; fields[1].out_value = data_buf; fields[1].in_value = NULL; jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_IDLE); if (jtag_execute_queue() != ERROR_OK) { LOG_ERROR("%s: reading data failed", __func__); return ERROR_FAIL; } busy = buf_get_u32(busy_buf, 0, 1); } while (busy); return ERROR_OK; } int avr32_jtag_mwa_read(struct avr32_jtag *jtag_info, int slave, uint32_t addr, uint32_t *value) { avr32_jtag_set_instr(jtag_info, AVR32_INST_MW_ACCESS); avr32_jtag_mwa_set_address(jtag_info, slave, addr, MODE_READ); avr32_jtag_mwa_read_data(jtag_info, value); return ERROR_OK; } int avr32_jtag_mwa_write(struct avr32_jtag *jtag_info, int slave, uint32_t addr, uint32_t value) { avr32_jtag_set_instr(jtag_info, AVR32_INST_MW_ACCESS); avr32_jtag_mwa_set_address(jtag_info, slave, addr, MODE_WRITE); avr32_jtag_mwa_write_data(jtag_info, value); return ERROR_OK; } int avr32_jtag_exec(struct avr32_jtag *jtag_info, uint32_t inst) { int retval; uint32_t ds; retval = avr32_jtag_nexus_write(jtag_info, AVR32_OCDREG_DINST, inst); if (retval != ERROR_OK) return retval; do { retval = avr32_jtag_nexus_read(jtag_info, AVR32_OCDREG_DS, &ds); if (retval != ERROR_OK) return retval; } while ((ds & OCDREG_DS_DBA) && !(ds & OCDREG_DS_INC)); return ERROR_OK; } int avr32_ocd_setbits(struct avr32_jtag *jtag, int reg, uint32_t bits) { uint32_t value; int res; res = avr32_jtag_nexus_read(jtag, reg, &value); if (res) return res; value |= bits; res = avr32_jtag_nexus_write(jtag, reg, value); if (res) return res; return ERROR_OK; } int avr32_ocd_clearbits(struct avr32_jtag *jtag, int reg, uint32_t bits) { uint32_t value; int res; res = avr32_jtag_nexus_read(jtag, reg, &value); if (res) return res; value &= ~bits; res = avr32_jtag_nexus_write(jtag, reg, value); if (res) return res; return ERROR_OK; } openocd-0.7.0/src/target/oocd_trace.h0000644000175000001440000000412312134336410014407 00000000000000/*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef OOCD_TRACE_H #define OOCD_TRACE_H #include /* registers */ enum { OOCD_TRACE_ID = 0x7, OOCD_TRACE_ADDRESS = 0x0, OOCD_TRACE_TRIGGER_COUNTER = 0x01, OOCD_TRACE_CONTROL = 0x2, OOCD_TRACE_STATUS = 0x3, OOCD_TRACE_SDRAM_COUNTER = 0x4, }; /* commands */ enum { OOCD_TRACE_NOP = 0x0, OOCD_TRACE_READ_REG = 0x10, OOCD_TRACE_WRITE_REG = 0x18, OOCD_TRACE_READ_RAM = 0x20, /* OOCD_TRACE_WRITE_RAM = 0x28, */ OOCD_TRACE_RESYNC = 0xf0, }; struct oocd_trace { struct etm_context *etm_ctx; char *tty; int tty_fd; struct termios oldtio, newtio; }; extern struct etm_capture_driver oocd_trace_capture_driver; #endif /* OOCD_TRACE_TRACE_H */ openocd-0.7.0/src/target/arm7tdmi.c0000644000175000001440000005701712134336410014036 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm7tdmi.h" #include "target_type.h" #include "register.h" #include "arm_opcodes.h" /* * For information about ARM7TDMI, see ARM DDI 0210C (r4p1) * or ARM DDI 0029G (r3). "Debug In Depth", Appendix B, * covers JTAG support. */ #if 0 #define _DEBUG_INSTRUCTION_EXECUTION_ #endif static int arm7tdmi_examine_debug_reason(struct target *target) { int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); /* only check the debug reason if we don't know it already */ if ((target->debug_reason != DBG_REASON_DBGRQ) && (target->debug_reason != DBG_REASON_SINGLESTEP)) { struct scan_field fields[2]; uint8_t databus[4]; uint8_t breakpoint; fields[0].num_bits = 1; fields[0].out_value = NULL; fields[0].in_value = &breakpoint; fields[1].num_bits = 32; fields[1].out_value = NULL; fields[1].in_value = databus; retval = arm_jtag_scann(&arm7_9->jtag_info, 0x1, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(&arm7_9->jtag_info, arm7_9->jtag_info.intest_instr, NULL, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; jtag_add_dr_scan(arm7_9->jtag_info.tap, 2, fields, TAP_DRPAUSE); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; fields[0].in_value = NULL; fields[0].out_value = &breakpoint; fields[1].in_value = NULL; fields[1].out_value = databus; jtag_add_dr_scan(arm7_9->jtag_info.tap, 2, fields, TAP_DRPAUSE); if (breakpoint & 1) target->debug_reason = DBG_REASON_WATCHPOINT; else target->debug_reason = DBG_REASON_BREAKPOINT; } return ERROR_OK; } static const int arm7tdmi_num_bits[] = {1, 32}; static inline int arm7tdmi_clock_out_inner(struct arm_jtag *jtag_info, uint32_t out, int breakpoint) { uint32_t values[2] = {breakpoint, flip_u32(out, 32)}; jtag_add_dr_out(jtag_info->tap, 2, arm7tdmi_num_bits, values, TAP_DRPAUSE); jtag_add_runtest(0, TAP_DRPAUSE); return ERROR_OK; } /* put an instruction in the ARM7TDMI pipeline or write the data bus, * and optionally read data * * FIXME remove the unused "deprecated" parameter */ static inline int arm7tdmi_clock_out(struct arm_jtag *jtag_info, uint32_t out, uint32_t *deprecated, int breakpoint) { int retval; retval = arm_jtag_scann(jtag_info, 0x1, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; return arm7tdmi_clock_out_inner(jtag_info, out, breakpoint); } /* clock the target, reading the databus */ static int arm7tdmi_clock_data_in(struct arm_jtag *jtag_info, uint32_t *in) { int retval = ERROR_OK; struct scan_field fields[2]; retval = arm_jtag_scann(jtag_info, 0x1, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 1; fields[0].out_value = NULL; fields[0].in_value = NULL; fields[1].num_bits = 32; fields[1].out_value = NULL; fields[1].in_value = (uint8_t *)in; jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_DRPAUSE); jtag_add_callback(arm7flip32, (jtag_callback_data_t)in); jtag_add_runtest(0, TAP_DRPAUSE); #ifdef _DEBUG_INSTRUCTION_EXECUTION_ retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (in) LOG_DEBUG("in: 0x%8.8x", *in); else LOG_ERROR("BUG: called with in == NULL"); #endif return ERROR_OK; } /* clock the target, and read the databus * the *in pointer points to a buffer where elements of 'size' bytes * are stored in big (be == 1) or little (be == 0) endianness */ static int arm7tdmi_clock_data_in_endianness(struct arm_jtag *jtag_info, void *in, int size, int be) { int retval = ERROR_OK; struct scan_field fields[3]; retval = arm_jtag_scann(jtag_info, 0x1, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 1; fields[0].out_value = NULL; fields[0].in_value = NULL; if (size == 4) { fields[1].num_bits = 32; fields[1].out_value = NULL; fields[1].in_value = in; } else { /* Discard irrelevant bits of the scan, making sure we don't write more * than size bytes to in */ fields[1].num_bits = 32 - size * 8; fields[1].out_value = NULL; fields[1].in_value = NULL; fields[2].num_bits = size * 8; fields[2].out_value = NULL; fields[2].in_value = in; } jtag_add_dr_scan(jtag_info->tap, size == 4 ? 2 : 3, fields, TAP_DRPAUSE); jtag_add_callback4(arm7_9_endianness_callback, (jtag_callback_data_t)in, (jtag_callback_data_t)size, (jtag_callback_data_t)be, (jtag_callback_data_t)1); jtag_add_runtest(0, TAP_DRPAUSE); #ifdef _DEBUG_INSTRUCTION_EXECUTION_ { retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (in) LOG_DEBUG("in: 0x%8.8x", *(uint32_t *)in); else LOG_ERROR("BUG: called with in == NULL"); } #endif return ERROR_OK; } static void arm7tdmi_change_to_arm(struct target *target, uint32_t *r0, uint32_t *pc) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* save r0 before using it and put system in ARM state * to allow common handling of ARM and THUMB debugging */ /* fetch STR r0, [r0] */ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), NULL, 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); /* nothing fetched, STR r0, [r0] in Execute (2) */ arm7tdmi_clock_data_in(jtag_info, r0); /* MOV r0, r15 fetched, STR in Decode */ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_MOV(0, 15), NULL, 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), NULL, 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); /* nothing fetched, STR r0, [r0] in Execute (2) */ arm7tdmi_clock_data_in(jtag_info, pc); /* use pc-relative LDR to clear r0[1:0] (for switch to ARM mode) */ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), NULL, 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); /* nothing fetched, data for LDR r0, [PC, #0] */ arm7tdmi_clock_out(jtag_info, 0x0, NULL, 0); /* nothing fetched, data from previous cycle is written to register */ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); /* fetch BX */ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_BX(0), NULL, 0); /* NOP fetched, BX in Decode, MOV in Execute */ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); /* NOP fetched, BX in Execute (1) */ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); jtag_execute_queue(); /* fix program counter: * MOV r0, r15 was the 4th instruction (+6) * reading PC in Thumb state gives address of instruction + 4 */ *pc -= 0xa; } /* FIX!!! is this a potential performance bottleneck w.r.t. requiring too many * roundtrips when jtag_execute_queue() has a large overhead(e.g. for USB)s? * * The solution is to arrange for a large out/in scan in this loop and * and convert data afterwards. */ static void arm7tdmi_read_core_regs(struct target *target, uint32_t mask, uint32_t *core_regs[16]) { int i; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* STMIA r0-15, [r0] at debug speed * register values will start to appear on 4th DCLK */ arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), NULL, 0); /* fetch NOP, STM in DECODE stage */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); /* fetch NOP, STM in EXECUTE stage (1st cycle) */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); for (i = 0; i <= 15; i++) { if (mask & (1 << i)) /* nothing fetched, STM still in EXECUTE (1 + i cycle) */ arm7tdmi_clock_data_in(jtag_info, core_regs[i]); } } static void arm7tdmi_read_core_regs_target_buffer(struct target *target, uint32_t mask, void *buffer, int size) { int i; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; int be = (target->endianness == TARGET_BIG_ENDIAN) ? 1 : 0; uint32_t *buf_u32 = buffer; uint16_t *buf_u16 = buffer; uint8_t *buf_u8 = buffer; /* STMIA r0-15, [r0] at debug speed * register values will start to appear on 4th DCLK */ arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask & 0xffff, 0, 0), NULL, 0); /* fetch NOP, STM in DECODE stage */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); /* fetch NOP, STM in EXECUTE stage (1st cycle) */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); for (i = 0; i <= 15; i++) { /* nothing fetched, STM still in EXECUTE (1 + i cycle), read databus */ if (mask & (1 << i)) { switch (size) { case 4: arm7tdmi_clock_data_in_endianness(jtag_info, buf_u32++, 4, be); break; case 2: arm7tdmi_clock_data_in_endianness(jtag_info, buf_u16++, 2, be); break; case 1: arm7tdmi_clock_data_in_endianness(jtag_info, buf_u8++, 1, be); break; } } } } static void arm7tdmi_read_xpsr(struct target *target, uint32_t *xpsr, int spsr) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* MRS r0, cpsr */ arm7tdmi_clock_out(jtag_info, ARMV4_5_MRS(0, spsr & 1), NULL, 0); /* STR r0, [r15] */ arm7tdmi_clock_out(jtag_info, ARMV4_5_STR(0, 15), NULL, 0); /* fetch NOP, STR in DECODE stage */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); /* fetch NOP, STR in EXECUTE stage (1st cycle) */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); /* nothing fetched, STR still in EXECUTE (2nd cycle) */ arm7tdmi_clock_data_in(jtag_info, xpsr); } static void arm7tdmi_write_xpsr(struct target *target, uint32_t xpsr, int spsr) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; LOG_DEBUG("xpsr: %8.8" PRIx32 ", spsr: %i", xpsr, spsr); /* MSR1 fetched */ arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr & 0xff, 0, 1, spsr), NULL, 0); /* MSR2 fetched, MSR1 in DECODE */ arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff00) >> 8, 0xc, 2, spsr), NULL, 0); /* MSR3 fetched, MSR1 in EXECUTE (1), MSR2 in DECODE */ arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff0000) >> 16, 0x8, 4, spsr), NULL, 0); /* nothing fetched, MSR1 in EXECUTE (2) */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); /* MSR4 fetched, MSR2 in EXECUTE (1), MSR3 in DECODE */ arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM((xpsr & 0xff000000) >> 24, 0x4, 8, spsr), NULL, 0); /* nothing fetched, MSR2 in EXECUTE (2) */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); /* NOP fetched, MSR3 in EXECUTE (1), MSR4 in DECODE */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); /* nothing fetched, MSR3 in EXECUTE (2) */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); /* NOP fetched, MSR4 in EXECUTE (1) */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); /* nothing fetched, MSR4 in EXECUTE (2) */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); } static void arm7tdmi_write_xpsr_im8(struct target *target, uint8_t xpsr_im, int rot, int spsr) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; LOG_DEBUG("xpsr_im: %2.2x, rot: %i, spsr: %i", xpsr_im, rot, spsr); /* MSR fetched */ arm7tdmi_clock_out(jtag_info, ARMV4_5_MSR_IM(xpsr_im, rot, 1, spsr), NULL, 0); /* NOP fetched, MSR in DECODE */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); /* NOP fetched, MSR in EXECUTE (1) */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); /* nothing fetched, MSR in EXECUTE (2) */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); } static void arm7tdmi_write_core_regs(struct target *target, uint32_t mask, uint32_t core_regs[16]) { int i; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* LDMIA r0-15, [r0] at debug speed * register values will start to appear on 4th DCLK */ arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 0), NULL, 0); /* fetch NOP, LDM in DECODE stage */ arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0); /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0); for (i = 0; i <= 15; i++) { if (mask & (1 << i)) /* nothing fetched, LDM still in EXECUTE (1 + i cycle) */ arm7tdmi_clock_out_inner(jtag_info, core_regs[i], 0); } arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0); } static void arm7tdmi_load_word_regs(struct target *target, uint32_t mask) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* put system-speed load-multiple into the pipeline */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, mask & 0xffff, 0, 1), NULL, 0); } static void arm7tdmi_load_hword_reg(struct target *target, int num) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* put system-speed load half-word into the pipeline */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); arm7tdmi_clock_out(jtag_info, ARMV4_5_LDRH_IP(num, 0), NULL, 0); } static void arm7tdmi_load_byte_reg(struct target *target, int num) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* put system-speed load byte into the pipeline */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); arm7tdmi_clock_out(jtag_info, ARMV4_5_LDRB_IP(num, 0), NULL, 0); } static void arm7tdmi_store_word_regs(struct target *target, uint32_t mask) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* put system-speed store-multiple into the pipeline */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); arm7tdmi_clock_out(jtag_info, ARMV4_5_STMIA(0, mask, 0, 1), NULL, 0); } static void arm7tdmi_store_hword_reg(struct target *target, int num) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* put system-speed store half-word into the pipeline */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); arm7tdmi_clock_out(jtag_info, ARMV4_5_STRH_IP(num, 0), NULL, 0); } static void arm7tdmi_store_byte_reg(struct target *target, int num) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* put system-speed store byte into the pipeline */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); arm7tdmi_clock_out(jtag_info, ARMV4_5_STRB_IP(num, 0), NULL, 0); } static void arm7tdmi_write_pc(struct target *target, uint32_t pc) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* LDMIA r0-15, [r0] at debug speed * register values will start to appear on 4th DCLK */ arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x8000, 0, 0), NULL, 0); /* fetch NOP, LDM in DECODE stage */ arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0); /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0); /* nothing fetched, LDM in EXECUTE stage (1st cycle) load register */ arm7tdmi_clock_out_inner(jtag_info, pc, 0); /* nothing fetched, LDM in EXECUTE stage (2nd cycle) load register */ arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0); /* nothing fetched, LDM in EXECUTE stage (3rd cycle) load register */ arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0); /* fetch NOP, LDM in EXECUTE stage (4th cycle) */ arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0); /* fetch NOP, LDM in EXECUTE stage (5th cycle) */ arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_NOP, 0); } static void arm7tdmi_branch_resume(struct target *target) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 1); arm7tdmi_clock_out_inner(jtag_info, ARMV4_5_B(0xfffffa, 0), 0); } static void arm7tdmi_branch_resume_thumb(struct target *target) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; struct arm_jtag *jtag_info = &arm7_9->jtag_info; struct reg *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; LOG_DEBUG("-"); /* LDMIA r0, [r0] at debug speed * register values will start to appear on 4th DCLK */ arm7tdmi_clock_out(jtag_info, ARMV4_5_LDMIA(0, 0x1, 0, 0), NULL, 0); /* fetch NOP, LDM in DECODE stage */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); /* fetch NOP, LDM in EXECUTE stage (1st cycle) */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); /* nothing fetched, LDM in EXECUTE stage (2nd cycle) */ arm7tdmi_clock_out(jtag_info, buf_get_u32(arm->pc->value, 0, 32) | 1, NULL, 0); /* nothing fetched, LDM in EXECUTE stage (3rd cycle) */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); /* Branch and eXchange */ arm7tdmi_clock_out(jtag_info, ARMV4_5_BX(0), NULL, 0); embeddedice_read_reg(dbg_stat); /* fetch NOP, BX in DECODE stage */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); /* target is now in Thumb state */ embeddedice_read_reg(dbg_stat); /* fetch NOP, BX in EXECUTE stage (1st cycle) */ arm7tdmi_clock_out(jtag_info, ARMV4_5_NOP, NULL, 0); /* target is now in Thumb state */ embeddedice_read_reg(dbg_stat); /* load r0 value */ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), NULL, 0); /* fetch NOP, LDR in Decode */ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); /* fetch NOP, LDR in Execute */ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); /* nothing fetched, LDR in EXECUTE stage (2nd cycle) */ arm7tdmi_clock_out(jtag_info, buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32), NULL, 0); /* nothing fetched, LDR in EXECUTE stage (3rd cycle) */ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); embeddedice_read_reg(dbg_stat); arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 1); arm7tdmi_clock_out(jtag_info, ARMV4_5_T_B(0x7f8), NULL, 0); } static void arm7tdmi_build_reg_cache(struct target *target) { struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); struct arm *arm = target_to_arm(target); (*cache_p) = arm_build_reg_cache(target, arm); } int arm7tdmi_init_target(struct command_context *cmd_ctx, struct target *target) { arm7tdmi_build_reg_cache(target); return ERROR_OK; } int arm7tdmi_init_arch_info(struct target *target, struct arm7_9_common *arm7_9, struct jtag_tap *tap) { /* prepare JTAG information for the new target */ arm7_9->jtag_info.tap = tap; arm7_9->jtag_info.scann_size = 4; /* register arch-specific functions */ arm7_9->examine_debug_reason = arm7tdmi_examine_debug_reason; arm7_9->change_to_arm = arm7tdmi_change_to_arm; arm7_9->read_core_regs = arm7tdmi_read_core_regs; arm7_9->read_core_regs_target_buffer = arm7tdmi_read_core_regs_target_buffer; arm7_9->read_xpsr = arm7tdmi_read_xpsr; arm7_9->write_xpsr = arm7tdmi_write_xpsr; arm7_9->write_xpsr_im8 = arm7tdmi_write_xpsr_im8; arm7_9->write_core_regs = arm7tdmi_write_core_regs; arm7_9->load_word_regs = arm7tdmi_load_word_regs; arm7_9->load_hword_reg = arm7tdmi_load_hword_reg; arm7_9->load_byte_reg = arm7tdmi_load_byte_reg; arm7_9->store_word_regs = arm7tdmi_store_word_regs; arm7_9->store_hword_reg = arm7tdmi_store_hword_reg; arm7_9->store_byte_reg = arm7tdmi_store_byte_reg; arm7_9->write_pc = arm7tdmi_write_pc; arm7_9->branch_resume = arm7tdmi_branch_resume; arm7_9->branch_resume_thumb = arm7tdmi_branch_resume_thumb; arm7_9->enable_single_step = arm7_9_enable_eice_step; arm7_9->disable_single_step = arm7_9_disable_eice_step; arm7_9->post_debug_entry = NULL; arm7_9->pre_restore_context = NULL; /* initialize arch-specific breakpoint handling */ arm7_9->arm_bkpt = 0xdeeedeee; arm7_9->thumb_bkpt = 0xdeee; arm7_9->dbgreq_adjust_pc = 2; arm7_9_init_arch_info(target, arm7_9); return ERROR_OK; } static int arm7tdmi_target_create(struct target *target, Jim_Interp *interp) { struct arm7_9_common *arm7_9; arm7_9 = calloc(1, sizeof(struct arm7_9_common)); arm7tdmi_init_arch_info(target, arm7_9, target->tap); arm7_9->arm.is_armv4 = true; return ERROR_OK; } /** Holds methods for ARM7TDMI targets. */ struct target_type arm7tdmi_target = { .name = "arm7tdmi", .poll = arm7_9_poll, .arch_state = arm_arch_state, .target_request_data = arm7_9_target_request_data, .halt = arm7_9_halt, .resume = arm7_9_resume, .step = arm7_9_step, .assert_reset = arm7_9_assert_reset, .deassert_reset = arm7_9_deassert_reset, .soft_reset_halt = arm7_9_soft_reset_halt, .get_gdb_reg_list = arm_get_gdb_reg_list, .read_memory = arm7_9_read_memory, .write_memory = arm7_9_write_memory, .bulk_write_memory = arm7_9_bulk_write_memory, .checksum_memory = arm_checksum_memory, .blank_check_memory = arm_blank_check_memory, .run_algorithm = armv4_5_run_algorithm, .add_breakpoint = arm7_9_add_breakpoint, .remove_breakpoint = arm7_9_remove_breakpoint, .add_watchpoint = arm7_9_add_watchpoint, .remove_watchpoint = arm7_9_remove_watchpoint, .commands = arm7_9_command_handlers, .target_create = arm7tdmi_target_create, .init_target = arm7tdmi_init_target, .examine = arm7_9_examine, .check_reset = arm7_9_check_reset, }; openocd-0.7.0/src/target/arm7_9_common.c0000644000175000001440000025533312137151331014761 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2008 by Hongtao Zheng * * hontor@126.com * * * * Copyright (C) 2009 by David Brownell * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "breakpoints.h" #include "embeddedice.h" #include "target_request.h" #include "etm.h" #include #include "arm_simulator.h" #include "arm_semihosting.h" #include "algorithm.h" #include "register.h" #include "armv4_5.h" /** * @file * Hold common code supporting the ARM7 and ARM9 core generations. * * While the ARM core implementations evolved substantially during these * two generations, they look quite similar from the JTAG perspective. * Both have similar debug facilities, based on the same two scan chains * providing access to the core and to an EmbeddedICE module. Both can * support similar ETM and ETB modules, for tracing. And both expose * what could be viewed as "ARM Classic", with multiple processor modes, * shadowed registers, and support for the Thumb instruction set. * * Processor differences include things like presence or absence of MMU * and cache, pipeline sizes, use of a modified Harvard Architecure * (with separate instruction and data busses from the CPU), support * for cpu clock gating during idle, and more. */ static int arm7_9_debug_entry(struct target *target); /** * Clear watchpoints for an ARM7/9 target. * * @param arm7_9 Pointer to the common struct for an ARM7/9 target * @return JTAG error status after executing queue */ static int arm7_9_clear_watchpoints(struct arm7_9_common *arm7_9) { LOG_DEBUG("-"); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], 0x0); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE], 0x0); arm7_9->sw_breakpoint_count = 0; arm7_9->sw_breakpoints_added = 0; arm7_9->wp0_used = 0; arm7_9->wp1_used = arm7_9->wp1_used_default; arm7_9->wp_available = arm7_9->wp_available_max; return jtag_execute_queue(); } /** * Assign a watchpoint to one of the two available hardware comparators in an * ARM7 or ARM9 target. * * @param arm7_9 Pointer to the common struct for an ARM7/9 target * @param breakpoint Pointer to the breakpoint to be used as a watchpoint */ static void arm7_9_assign_wp(struct arm7_9_common *arm7_9, struct breakpoint *breakpoint) { if (!arm7_9->wp0_used) { arm7_9->wp0_used = 1; breakpoint->set = 1; arm7_9->wp_available--; } else if (!arm7_9->wp1_used) { arm7_9->wp1_used = 1; breakpoint->set = 2; arm7_9->wp_available--; } else LOG_ERROR("BUG: no hardware comparator available"); LOG_DEBUG("BPID: %d (0x%08" PRIx32 ") using hw wp: %d", breakpoint->unique_id, breakpoint->address, breakpoint->set); } /** * Setup an ARM7/9 target's embedded ICE registers for software breakpoints. * * @param arm7_9 Pointer to common struct for ARM7/9 targets * @return Error codes if there is a problem finding a watchpoint or the result * of executing the JTAG queue */ static int arm7_9_set_software_breakpoints(struct arm7_9_common *arm7_9) { if (arm7_9->sw_breakpoints_added) return ERROR_OK; if (arm7_9->wp_available < 1) { LOG_WARNING("can't enable sw breakpoints with no watchpoint unit available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } arm7_9->wp_available--; /* pick a breakpoint unit */ if (!arm7_9->wp0_used) { arm7_9->sw_breakpoints_added = 1; arm7_9->wp0_used = 3; } else if (!arm7_9->wp1_used) { arm7_9->sw_breakpoints_added = 2; arm7_9->wp1_used = 3; } else { LOG_ERROR("BUG: both watchpoints used, but wp_available >= 1"); return ERROR_FAIL; } if (arm7_9->sw_breakpoints_added == 1) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_VALUE], arm7_9->arm_bkpt); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK], 0x0); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK], 0xffffffffu); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK], ~EICE_W_CTRL_nOPC & 0xff); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], EICE_W_CTRL_ENABLE); } else if (arm7_9->sw_breakpoints_added == 2) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_DATA_VALUE], arm7_9->arm_bkpt); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_DATA_MASK], 0x0); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_MASK], 0xffffffffu); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_MASK], ~EICE_W_CTRL_nOPC & 0xff); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE], EICE_W_CTRL_ENABLE); } else { LOG_ERROR("BUG: both watchpoints used, but wp_available >= 1"); return ERROR_FAIL; } LOG_DEBUG("SW BP using hw wp: %d", arm7_9->sw_breakpoints_added); return jtag_execute_queue(); } /** * Setup the common pieces for an ARM7/9 target after reset or on startup. * * @param target Pointer to an ARM7/9 target to setup * @return Result of clearing the watchpoints on the target */ static int arm7_9_setup(struct target *target) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); return arm7_9_clear_watchpoints(arm7_9); } /** * Set either a hardware or software breakpoint on an ARM7/9 target. The * breakpoint is set up even if it is already set. Some actions, e.g. reset, * might have erased the values in Embedded ICE. * * @param target Pointer to the target device to set the breakpoints on * @param breakpoint Pointer to the breakpoint to be set * @return For hardware breakpoints, this is the result of executing the JTAG * queue. For software breakpoints, this will be the status of the * required memory reads and writes */ static int arm7_9_set_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); int retval = ERROR_OK; LOG_DEBUG("BPID: %d, Address: 0x%08" PRIx32 ", Type: %d", breakpoint->unique_id, breakpoint->address, breakpoint->type); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (breakpoint->type == BKPT_HARD) { /* either an ARM (4 byte) or Thumb (2 byte) breakpoint */ uint32_t mask = (breakpoint->length == 4) ? 0x3u : 0x1u; /* reassign a hw breakpoint */ if (breakpoint->set == 0) arm7_9_assign_wp(arm7_9, breakpoint); if (breakpoint->set == 1) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_VALUE], breakpoint->address); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK], mask); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK], 0xffffffffu); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK], ~EICE_W_CTRL_nOPC & 0xff); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], EICE_W_CTRL_ENABLE); } else if (breakpoint->set == 2) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_VALUE], breakpoint->address); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_MASK], mask); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_DATA_MASK], 0xffffffffu); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_MASK], ~EICE_W_CTRL_nOPC & 0xff); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE], EICE_W_CTRL_ENABLE); } else { LOG_ERROR("BUG: no hardware comparator available"); return ERROR_OK; } retval = jtag_execute_queue(); } else if (breakpoint->type == BKPT_SOFT) { /* did we already set this breakpoint? */ if (breakpoint->set) return ERROR_OK; if (breakpoint->length == 4) { uint32_t verify = 0xffffffff; /* keep the original instruction in target endianness */ retval = target_read_memory(target, breakpoint->address, 4, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; /* write the breakpoint instruction in target * endianness (arm7_9->arm_bkpt is host endian) */ retval = target_write_u32(target, breakpoint->address, arm7_9->arm_bkpt); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, breakpoint->address, &verify); if (retval != ERROR_OK) return retval; if (verify != arm7_9->arm_bkpt) { LOG_ERROR("Unable to set 32 bit software breakpoint at address %08" PRIx32 " - check that memory is read/writable", breakpoint->address); return ERROR_OK; } } else { uint16_t verify = 0xffff; /* keep the original instruction in target endianness */ retval = target_read_memory(target, breakpoint->address, 2, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; /* write the breakpoint instruction in target * endianness (arm7_9->thumb_bkpt is host endian) */ retval = target_write_u16(target, breakpoint->address, arm7_9->thumb_bkpt); if (retval != ERROR_OK) return retval; retval = target_read_u16(target, breakpoint->address, &verify); if (retval != ERROR_OK) return retval; if (verify != arm7_9->thumb_bkpt) { LOG_ERROR("Unable to set thumb software breakpoint at address %08" PRIx32 " - check that memory is read/writable", breakpoint->address); return ERROR_OK; } } retval = arm7_9_set_software_breakpoints(arm7_9); if (retval != ERROR_OK) return retval; arm7_9->sw_breakpoint_count++; breakpoint->set = 1; } return retval; } /** * Unsets an existing breakpoint on an ARM7/9 target. If it is a hardware * breakpoint, the watchpoint used will be freed and the Embedded ICE registers * will be updated. Otherwise, the software breakpoint will be restored to its * original instruction if it hasn't already been modified. * * @param target Pointer to ARM7/9 target to unset the breakpoint from * @param breakpoint Pointer to breakpoint to be unset * @return For hardware breakpoints, this is the result of executing the JTAG * queue. For software breakpoints, this will be the status of the * required memory reads and writes */ static int arm7_9_unset_breakpoint(struct target *target, struct breakpoint *breakpoint) { int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); LOG_DEBUG("BPID: %d, Address: 0x%08" PRIx32, breakpoint->unique_id, breakpoint->address); if (!breakpoint->set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } if (breakpoint->type == BKPT_HARD) { LOG_DEBUG("BPID: %d Releasing hw wp: %d", breakpoint->unique_id, breakpoint->set); if (breakpoint->set == 1) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], 0x0); arm7_9->wp0_used = 0; arm7_9->wp_available++; } else if (breakpoint->set == 2) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE], 0x0); arm7_9->wp1_used = 0; arm7_9->wp_available++; } retval = jtag_execute_queue(); breakpoint->set = 0; } else { /* restore original instruction (kept in target endianness) */ if (breakpoint->length == 4) { uint32_t current_instr; /* check that user program as not modified breakpoint instruction */ retval = target_read_memory(target, breakpoint->address, 4, 1, (uint8_t *)¤t_instr); if (retval != ERROR_OK) return retval; current_instr = target_buffer_get_u32(target, (uint8_t *)¤t_instr); if (current_instr == arm7_9->arm_bkpt) { retval = target_write_memory(target, breakpoint->address, 4, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; } } else { uint16_t current_instr; /* check that user program as not modified breakpoint instruction */ retval = target_read_memory(target, breakpoint->address, 2, 1, (uint8_t *)¤t_instr); if (retval != ERROR_OK) return retval; current_instr = target_buffer_get_u16(target, (uint8_t *)¤t_instr); if (current_instr == arm7_9->thumb_bkpt) retval = target_write_memory(target, breakpoint->address, 2, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; } if (--arm7_9->sw_breakpoint_count == 0) { /* We have removed the last sw breakpoint, clear the hw breakpoint we used *to implement it */ if (arm7_9->sw_breakpoints_added == 1) embeddedice_set_reg(&arm7_9->eice_cache->reg_list[ EICE_W0_CONTROL_VALUE], 0); else if (arm7_9->sw_breakpoints_added == 2) embeddedice_set_reg(&arm7_9->eice_cache->reg_list[ EICE_W1_CONTROL_VALUE], 0); } breakpoint->set = 0; } return retval; } /** * Add a breakpoint to an ARM7/9 target. This makes sure that there are no * dangling breakpoints and that the desired breakpoint can be added. * * @param target Pointer to the target ARM7/9 device to add a breakpoint to * @param breakpoint Pointer to the breakpoint to be added * @return An error status if there is a problem adding the breakpoint or the * result of setting the breakpoint */ int arm7_9_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); if (arm7_9->breakpoint_count == 0) { /* make sure we don't have any dangling breakpoints. This is vital upon * GDB connect/disconnect */ arm7_9_clear_watchpoints(arm7_9); } if ((breakpoint->type == BKPT_HARD) && (arm7_9->wp_available < 1)) { LOG_INFO("no watchpoint unit available for hardware breakpoint"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if ((breakpoint->length != 2) && (breakpoint->length != 4)) { LOG_INFO("only breakpoints of two (Thumb) or four (ARM) bytes length supported"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if (breakpoint->type == BKPT_HARD) arm7_9_assign_wp(arm7_9, breakpoint); arm7_9->breakpoint_count++; return arm7_9_set_breakpoint(target, breakpoint); } /** * Removes a breakpoint from an ARM7/9 target. This will make sure there are no * dangling breakpoints and updates available watchpoints if it is a hardware * breakpoint. * * @param target Pointer to the target to have a breakpoint removed * @param breakpoint Pointer to the breakpoint to be removed * @return Error status if there was a problem unsetting the breakpoint or the * watchpoints could not be cleared */ int arm7_9_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); retval = arm7_9_unset_breakpoint(target, breakpoint); if (retval != ERROR_OK) return retval; if (breakpoint->type == BKPT_HARD) arm7_9->wp_available++; arm7_9->breakpoint_count--; if (arm7_9->breakpoint_count == 0) { /* make sure we don't have any dangling breakpoints */ retval = arm7_9_clear_watchpoints(arm7_9); if (retval != ERROR_OK) return retval; } return ERROR_OK; } /** * Sets a watchpoint for an ARM7/9 target in one of the watchpoint units. It is * considered a bug to call this function when there are no available watchpoint * units. * * @param target Pointer to an ARM7/9 target to set a watchpoint on * @param watchpoint Pointer to the watchpoint to be set * @return Error status if watchpoint set fails or the result of executing the * JTAG queue */ static int arm7_9_set_watchpoint(struct target *target, struct watchpoint *watchpoint) { int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); int rw_mask = 1; uint32_t mask; mask = watchpoint->length - 1; if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (watchpoint->rw == WPT_ACCESS) rw_mask = 0; else rw_mask = 1; if (!arm7_9->wp0_used) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_VALUE], watchpoint->address); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK], mask); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK], watchpoint->mask); if (watchpoint->mask != 0xffffffffu) embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_VALUE], watchpoint->value); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK], 0xff & ~EICE_W_CTRL_nOPC & ~rw_mask); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], EICE_W_CTRL_ENABLE | EICE_W_CTRL_nOPC | (watchpoint->rw & 1)); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; watchpoint->set = 1; arm7_9->wp0_used = 2; } else if (!arm7_9->wp1_used) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_VALUE], watchpoint->address); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_MASK], mask); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_DATA_MASK], watchpoint->mask); if (watchpoint->mask != 0xffffffffu) embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_DATA_VALUE], watchpoint->value); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_MASK], 0xff & ~EICE_W_CTRL_nOPC & ~rw_mask); embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE], EICE_W_CTRL_ENABLE | EICE_W_CTRL_nOPC | (watchpoint->rw & 1)); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; watchpoint->set = 2; arm7_9->wp1_used = 2; } else { LOG_ERROR("BUG: no hardware comparator available"); return ERROR_OK; } return ERROR_OK; } /** * Unset an existing watchpoint and clear the used watchpoint unit. * * @param target Pointer to the target to have the watchpoint removed * @param watchpoint Pointer to the watchpoint to be removed * @return Error status while trying to unset the watchpoint or the result of * executing the JTAG queue */ static int arm7_9_unset_watchpoint(struct target *target, struct watchpoint *watchpoint) { int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!watchpoint->set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } if (watchpoint->set == 1) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], 0x0); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; arm7_9->wp0_used = 0; } else if (watchpoint->set == 2) { embeddedice_set_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE], 0x0); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; arm7_9->wp1_used = 0; } watchpoint->set = 0; return ERROR_OK; } /** * Add a watchpoint to an ARM7/9 target. If there are no watchpoint units * available, an error response is returned. * * @param target Pointer to the ARM7/9 target to add a watchpoint to * @param watchpoint Pointer to the watchpoint to be added * @return Error status while trying to add the watchpoint */ int arm7_9_add_watchpoint(struct target *target, struct watchpoint *watchpoint) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); if (arm7_9->wp_available < 1) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; if ((watchpoint->length != 1) && (watchpoint->length != 2) && (watchpoint->length != 4)) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; arm7_9->wp_available--; return ERROR_OK; } /** * Remove a watchpoint from an ARM7/9 target. The watchpoint will be unset and * the used watchpoint unit will be reopened. * * @param target Pointer to the target to remove a watchpoint from * @param watchpoint Pointer to the watchpoint to be removed * @return Result of trying to unset the watchpoint */ int arm7_9_remove_watchpoint(struct target *target, struct watchpoint *watchpoint) { int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); if (watchpoint->set) { retval = arm7_9_unset_watchpoint(target, watchpoint); if (retval != ERROR_OK) return retval; } arm7_9->wp_available++; return ERROR_OK; } /** * Restarts the target by sending a RESTART instruction and moving the JTAG * state to IDLE. This includes a timeout waiting for DBGACK and SYSCOMP to be * asserted by the processor. * * @param target Pointer to target to issue commands to * @return Error status if there is a timeout or a problem while executing the * JTAG queue */ int arm7_9_execute_sys_speed(struct target *target) { int retval; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; struct reg *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; /* set RESTART instruction */ if (arm7_9->need_bypass_before_restart) { arm7_9->need_bypass_before_restart = 0; retval = arm_jtag_set_instr(jtag_info, 0xf, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; } retval = arm_jtag_set_instr(jtag_info, 0x4, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; long long then = timeval_ms(); int timeout; while (!(timeout = ((timeval_ms()-then) > 1000))) { /* read debug status register */ embeddedice_read_reg(dbg_stat); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if ((buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_DBGACK, 1)) && (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_SYSCOMP, 1))) break; if (debug_level >= 3) alive_sleep(100); else keep_alive(); } if (timeout) { LOG_ERROR("timeout waiting for SYSCOMP & DBGACK, last DBG_STATUS: %" PRIx32 "", buf_get_u32(dbg_stat->value, 0, dbg_stat->size)); return ERROR_TARGET_TIMEOUT; } return ERROR_OK; } /** * Restarts the target by sending a RESTART instruction and moving the JTAG * state to IDLE. This validates that DBGACK and SYSCOMP are set without * waiting until they are. * * @param target Pointer to the target to issue commands to * @return Always ERROR_OK */ static int arm7_9_execute_fast_sys_speed(struct target *target) { static int set; static uint8_t check_value[4], check_mask[4]; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; struct reg *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; int retval; /* set RESTART instruction */ if (arm7_9->need_bypass_before_restart) { arm7_9->need_bypass_before_restart = 0; retval = arm_jtag_set_instr(jtag_info, 0xf, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; } retval = arm_jtag_set_instr(jtag_info, 0x4, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; if (!set) { /* check for DBGACK and SYSCOMP set (others don't care) */ /* NB! These are constants that must be available until after next jtag_execute() and * we evaluate the values upon first execution in lieu of setting up these constants * during early setup. * */ buf_set_u32(check_value, 0, 32, 0x9); buf_set_u32(check_mask, 0, 32, 0x9); set = 1; } /* read debug status register */ embeddedice_read_reg_w_check(dbg_stat, check_value, check_mask); return ERROR_OK; } /** * Get some data from the ARM7/9 target. * * @param target Pointer to the ARM7/9 target to read data from * @param size The number of 32bit words to be read * @param buffer Pointer to the buffer that will hold the data * @return The result of receiving data from the Embedded ICE unit */ int arm7_9_target_request_data(struct target *target, uint32_t size, uint8_t *buffer) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; uint32_t *data; int retval = ERROR_OK; uint32_t i; data = malloc(size * (sizeof(uint32_t))); retval = embeddedice_receive(jtag_info, data, size); /* return the 32-bit ints in the 8-bit array */ for (i = 0; i < size; i++) h_u32_to_le(buffer + (i * 4), data[i]); free(data); return retval; } /** * Handles requests to an ARM7/9 target. If debug messaging is enabled, the * target is running and the DCC control register has the W bit high, this will * execute the request on the target. * * @param priv Void pointer expected to be a struct target pointer * @return ERROR_OK unless there are issues with the JTAG queue or when reading * from the Embedded ICE unit */ static int arm7_9_handle_target_request(void *priv) { int retval = ERROR_OK; struct target *target = priv; if (!target_was_examined(target)) return ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; struct reg *dcc_control = &arm7_9->eice_cache->reg_list[EICE_COMMS_CTRL]; if (!target->dbg_msg_enabled) return ERROR_OK; if (target->state == TARGET_RUNNING) { /* read DCC control register */ embeddedice_read_reg(dcc_control); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; /* check W bit */ if (buf_get_u32(dcc_control->value, 1, 1) == 1) { uint32_t request; retval = embeddedice_receive(jtag_info, &request, 1); if (retval != ERROR_OK) return retval; retval = target_request(target, request); if (retval != ERROR_OK) return retval; } } return ERROR_OK; } /** * Polls an ARM7/9 target for its current status. If DBGACK is set, the target * is manipulated to the right halted state based on its current state. This is * what happens: * * * * * * * * *
State Action
TARGET_RUNNING | TARGET_RESET Enters debug mode. If TARGET_RESET, pc may be checked
TARGET_UNKNOWN Warning is logged
TARGET_DEBUG_RUNNING Enters debug mode
TARGET_HALTED Nothing
* * If the target does not end up in the halted state, a warning is produced. If * DBGACK is cleared, then the target is expected to either be running or * running in debug. * * @param target Pointer to the ARM7/9 target to poll * @return ERROR_OK or an error status if a command fails */ int arm7_9_poll(struct target *target) { int retval; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct reg *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; /* read debug status register */ embeddedice_read_reg(dbg_stat); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_DBGACK, 1)) { /* LOG_DEBUG("DBGACK set, dbg_state->value: 0x%x", buf_get_u32(dbg_stat->value, 0, *32));*/ if (target->state == TARGET_UNKNOWN) { /* Starting OpenOCD with target in debug-halt */ target->state = TARGET_RUNNING; LOG_DEBUG("DBGACK already set during server startup."); } if ((target->state == TARGET_RUNNING) || (target->state == TARGET_RESET)) { target->state = TARGET_HALTED; retval = arm7_9_debug_entry(target); if (retval != ERROR_OK) return retval; if (arm_semihosting(target, &retval) != 0) return retval; retval = target_call_event_callbacks(target, TARGET_EVENT_HALTED); if (retval != ERROR_OK) return retval; } if (target->state == TARGET_DEBUG_RUNNING) { target->state = TARGET_HALTED; retval = arm7_9_debug_entry(target); if (retval != ERROR_OK) return retval; retval = target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); if (retval != ERROR_OK) return retval; } if (target->state != TARGET_HALTED) LOG_WARNING( "DBGACK set, but the target did not end up in the halted state %d", target->state); } else { if (target->state != TARGET_DEBUG_RUNNING) target->state = TARGET_RUNNING; } return ERROR_OK; } /** * Asserts the reset (SRST) on an ARM7/9 target. Some -S targets (ARM966E-S in * the STR912 isn't affected, ARM926EJ-S in the LPC3180 and AT91SAM9260 is * affected) completely stop the JTAG clock while the core is held in reset * (SRST). It isn't possible to program the halt condition once reset is * asserted, hence a hook that allows the target to set up its reset-halt * condition is setup prior to asserting reset. * * @param target Pointer to an ARM7/9 target to assert reset on * @return ERROR_FAIL if the JTAG device does not have SRST, otherwise ERROR_OK */ int arm7_9_assert_reset(struct target *target) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); enum reset_types jtag_reset_config = jtag_get_reset_config(); bool use_event = false; LOG_DEBUG("target->state: %s", target_state_name(target)); if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT)) use_event = true; else if (!(jtag_reset_config & RESET_HAS_SRST)) { LOG_ERROR("%s: how to reset?", target_name(target)); return ERROR_FAIL; } /* At this point trst has been asserted/deasserted once. We would * like to program EmbeddedICE while SRST is asserted, instead of * depending on SRST to leave that module alone. However, many CPUs * gate the JTAG clock while SRST is asserted; or JTAG may need * clock stability guarantees (adaptive clocking might help). * * So we assume JTAG access during SRST is off the menu unless it's * been specifically enabled. */ bool srst_asserted = false; if (!use_event && !(jtag_reset_config & RESET_SRST_PULLS_TRST) && (jtag_reset_config & RESET_SRST_NO_GATING)) { jtag_add_reset(0, 1); srst_asserted = true; } if (target->reset_halt) { /* * For targets that don't support communication while SRST is * asserted, we need to set up the reset vector catch first. * * When we use TRST+SRST and that's equivalent to a power-up * reset, these settings may well be reset anyway; so setting * them here won't matter. */ if (arm7_9->has_vector_catch) { /* program vector catch register to catch reset */ embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_VEC_CATCH], 0x1); /* extra runtest added as issues were found with * certain ARM9 cores (maybe more) - AT91SAM9260 * and STR9 */ jtag_add_runtest(1, TAP_IDLE); } else { /* program watchpoint unit to match on reset vector * address */ embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_VALUE], 0x0); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK], 0x3); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK], 0xffffffff); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], EICE_W_CTRL_ENABLE); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK], ~EICE_W_CTRL_nOPC & 0xff); } } if (use_event) target_handle_event(target, TARGET_EVENT_RESET_ASSERT); else { /* If we use SRST ... we'd like to issue just SRST, but the * board or chip may be set up so we have to assert TRST as * well. On some chips that combination is equivalent to a * power-up reset, and generally clobbers EICE state. */ if (jtag_reset_config & RESET_SRST_PULLS_TRST) jtag_add_reset(1, 1); else if (!srst_asserted) jtag_add_reset(0, 1); jtag_add_sleep(50000); } target->state = TARGET_RESET; register_cache_invalidate(arm7_9->arm.core_cache); /* REVISIT why isn't standard debug entry logic sufficient?? */ if (target->reset_halt && (!(jtag_reset_config & RESET_SRST_PULLS_TRST) || use_event)) { /* debug entry was prepared above */ target->debug_reason = DBG_REASON_DBGRQ; } return ERROR_OK; } /** * Deassert the reset (SRST) signal on an ARM7/9 target. If SRST pulls TRST * and the target is being reset into a halt, a warning will be triggered * because it is not possible to reset into a halted mode in this case. The * target is halted using the target's functions. * * @param target Pointer to the target to have the reset deasserted * @return ERROR_OK or an error from polling or halting the target */ int arm7_9_deassert_reset(struct target *target) { int retval = ERROR_OK; LOG_DEBUG("target->state: %s", target_state_name(target)); /* deassert reset lines */ jtag_add_reset(0, 0); /* In case polling is disabled, we need to examine the * target and poll here for this target to work correctly. * * Otherwise, e.g. halt will fail afterwards with bogus * error messages as halt will believe that reset is * still in effect. */ retval = target_examine_one(target); if (retval != ERROR_OK) return retval; retval = target_poll(target); if (retval != ERROR_OK) return retval; enum reset_types jtag_reset_config = jtag_get_reset_config(); if (target->reset_halt && (jtag_reset_config & RESET_SRST_PULLS_TRST) != 0) { LOG_WARNING( "srst pulls trst - can not reset into halted mode. Issuing halt after reset."); retval = target_halt(target); if (retval != ERROR_OK) return retval; } return retval; } /** * Clears the halt condition for an ARM7/9 target. If it isn't coming out of * reset and if DBGRQ is used, it is progammed to be deasserted. If the reset * vector catch was used, it is restored. Otherwise, the control value is * restored and the watchpoint unit is restored if it was in use. * * @param target Pointer to the ARM7/9 target to have halt cleared * @return Always ERROR_OK */ static int arm7_9_clear_halt(struct target *target) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct reg *dbg_ctrl = &arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]; /* we used DBGRQ only if we didn't come out of reset */ if (!arm7_9->debug_entry_from_reset && arm7_9->use_dbgrq) { /* program EmbeddedICE Debug Control Register to deassert DBGRQ */ buf_set_u32(dbg_ctrl->value, EICE_DBG_CONTROL_DBGRQ, 1, 0); embeddedice_store_reg(dbg_ctrl); } else { if (arm7_9->debug_entry_from_reset && arm7_9->has_vector_catch) { /* if we came out of reset, and vector catch is supported, we used * vector catch to enter debug state * restore the register in that case */ embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_VEC_CATCH]); } else { /* restore registers if watchpoint unit 0 was in use */ if (arm7_9->wp0_used) { if (arm7_9->debug_entry_from_reset) embeddedice_store_reg(&arm7_9->eice_cache->reg_list[ EICE_W0_ADDR_VALUE]); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[ EICE_W0_ADDR_MASK]); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[ EICE_W0_DATA_MASK]); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[ EICE_W0_CONTROL_MASK]); } /* control value always has to be restored, as it was either disabled, * or enabled with possibly different bits */ embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE]); } } return ERROR_OK; } /** * Issue a software reset and halt to an ARM7/9 target. The target is halted * and then there is a wait until the processor shows the halt. This wait can * timeout and results in an error being returned. The software reset involves * clearing the halt, updating the debug control register, changing to ARM mode, * reset of the program counter, and reset of all of the registers. * * @param target Pointer to the ARM7/9 target to be reset and halted by software * @return Error status if any of the commands fail, otherwise ERROR_OK */ int arm7_9_soft_reset_halt(struct target *target) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; struct reg *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; struct reg *dbg_ctrl = &arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]; int i; int retval; /* FIX!!! replace some of this code with tcl commands * * halt # the halt command is synchronous * armv4_5 core_state arm * */ retval = target_halt(target); if (retval != ERROR_OK) return retval; long long then = timeval_ms(); int timeout; while (!(timeout = ((timeval_ms()-then) > 1000))) { if (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_DBGACK, 1) != 0) break; embeddedice_read_reg(dbg_stat); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (debug_level >= 3) alive_sleep(100); else keep_alive(); } if (timeout) { LOG_ERROR("Failed to halt CPU after 1 sec"); return ERROR_TARGET_TIMEOUT; } target->state = TARGET_HALTED; /* program EmbeddedICE Debug Control Register to assert DBGACK and INTDIS * ensure that DBGRQ is cleared */ buf_set_u32(dbg_ctrl->value, EICE_DBG_CONTROL_DBGACK, 1, 1); buf_set_u32(dbg_ctrl->value, EICE_DBG_CONTROL_DBGRQ, 1, 0); buf_set_u32(dbg_ctrl->value, EICE_DBG_CONTROL_INTDIS, 1, 1); embeddedice_store_reg(dbg_ctrl); retval = arm7_9_clear_halt(target); if (retval != ERROR_OK) return retval; /* if the target is in Thumb state, change to ARM state */ if (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_ITBIT, 1)) { uint32_t r0_thumb, pc_thumb; LOG_DEBUG("target entered debug from Thumb state, changing to ARM"); /* Entered debug from Thumb mode */ arm->core_state = ARM_STATE_THUMB; arm7_9->change_to_arm(target, &r0_thumb, &pc_thumb); } /* REVISIT likewise for bit 5 -- switch Jazelle-to-ARM */ /* all register content is now invalid */ register_cache_invalidate(arm->core_cache); /* SVC, ARM state, IRQ and FIQ disabled */ uint32_t cpsr; cpsr = buf_get_u32(arm->cpsr->value, 0, 32); cpsr &= ~0xff; cpsr |= 0xd3; arm_set_cpsr(arm, cpsr); arm->cpsr->dirty = 1; /* start fetching from 0x0 */ buf_set_u32(arm->pc->value, 0, 32, 0x0); arm->pc->dirty = 1; arm->pc->valid = 1; /* reset registers */ for (i = 0; i <= 14; i++) { struct reg *r = arm_reg_current(arm, i); buf_set_u32(r->value, 0, 32, 0xffffffff); r->dirty = 1; r->valid = 1; } retval = target_call_event_callbacks(target, TARGET_EVENT_HALTED); if (retval != ERROR_OK) return retval; return ERROR_OK; } /** * Halt an ARM7/9 target. This is accomplished by either asserting the DBGRQ * line or by programming a watchpoint to trigger on any address. It is * considered a bug to call this function while the target is in the * TARGET_RESET state. * * @param target Pointer to the ARM7/9 target to be halted * @return Always ERROR_OK */ int arm7_9_halt(struct target *target) { if (target->state == TARGET_RESET) { LOG_ERROR( "BUG: arm7/9 does not support halt during reset. This is handled in arm7_9_assert_reset()"); return ERROR_OK; } struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct reg *dbg_ctrl = &arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]; LOG_DEBUG("target->state: %s", target_state_name(target)); if (target->state == TARGET_HALTED) { LOG_DEBUG("target was already halted"); return ERROR_OK; } if (target->state == TARGET_UNKNOWN) LOG_WARNING("target was in unknown state when halt was requested"); if (arm7_9->use_dbgrq) { /* program EmbeddedICE Debug Control Register to assert DBGRQ */ if (arm7_9->set_special_dbgrq) arm7_9->set_special_dbgrq(target); else { buf_set_u32(dbg_ctrl->value, EICE_DBG_CONTROL_DBGRQ, 1, 1); embeddedice_store_reg(dbg_ctrl); } } else { /* program watchpoint unit to match on any address */ embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK], 0xffffffff); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK], 0xffffffff); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], EICE_W_CTRL_ENABLE); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK], ~EICE_W_CTRL_nOPC & 0xff); } target->debug_reason = DBG_REASON_DBGRQ; return ERROR_OK; } /** * Handle an ARM7/9 target's entry into debug mode. The halt is cleared on the * ARM. The JTAG queue is then executed and the reason for debug entry is * examined. Once done, the target is verified to be halted and the processor * is forced into ARM mode. The core registers are saved for the current core * mode and the program counter (register 15) is updated as needed. The core * registers and CPSR and SPSR are saved for restoration later. * * @param target Pointer to target that is entering debug mode * @return Error code if anything fails, otherwise ERROR_OK */ static int arm7_9_debug_entry(struct target *target) { int i; uint32_t context[16]; uint32_t *context_p[16]; uint32_t r0_thumb, pc_thumb; uint32_t cpsr, cpsr_mask = 0; int retval; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; struct reg *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; struct reg *dbg_ctrl = &arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]; #ifdef _DEBUG_ARM7_9_ LOG_DEBUG("-"); #endif /* program EmbeddedICE Debug Control Register to assert DBGACK and INTDIS * ensure that DBGRQ is cleared */ buf_set_u32(dbg_ctrl->value, EICE_DBG_CONTROL_DBGACK, 1, 1); buf_set_u32(dbg_ctrl->value, EICE_DBG_CONTROL_DBGRQ, 1, 0); buf_set_u32(dbg_ctrl->value, EICE_DBG_CONTROL_INTDIS, 1, 1); embeddedice_store_reg(dbg_ctrl); retval = arm7_9_clear_halt(target); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; retval = arm7_9->examine_debug_reason(target); if (retval != ERROR_OK) return retval; if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* if the target is in Thumb state, change to ARM state */ if (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_ITBIT, 1)) { LOG_DEBUG("target entered debug from Thumb state"); /* Entered debug from Thumb mode */ arm->core_state = ARM_STATE_THUMB; cpsr_mask = 1 << 5; arm7_9->change_to_arm(target, &r0_thumb, &pc_thumb); LOG_DEBUG("r0_thumb: 0x%8.8" PRIx32 ", pc_thumb: 0x%8.8" PRIx32, r0_thumb, pc_thumb); } else if (buf_get_u32(dbg_stat->value, 5, 1)) { /* \todo Get some vaguely correct handling of Jazelle, if * anyone ever uses it and full info becomes available. * See ARM9EJS TRM B.7.1 for how to switch J->ARM; and * B.7.3 for the reverse. That'd be the bare minimum... */ LOG_DEBUG("target entered debug from Jazelle state"); arm->core_state = ARM_STATE_JAZELLE; cpsr_mask = 1 << 24; LOG_ERROR("Jazelle debug entry -- BROKEN!"); } else { LOG_DEBUG("target entered debug from ARM state"); /* Entered debug from ARM mode */ arm->core_state = ARM_STATE_ARM; } for (i = 0; i < 16; i++) context_p[i] = &context[i]; /* save core registers (r0 - r15 of current core mode) */ arm7_9->read_core_regs(target, 0xffff, context_p); arm7_9->read_xpsr(target, &cpsr, 0); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; /* Sync our CPSR copy with J or T bits EICE reported, but * which we then erased by putting the core into ARM mode. */ arm_set_cpsr(arm, cpsr | cpsr_mask); if (!is_arm_mode(arm->core_mode)) { target->state = TARGET_UNKNOWN; LOG_ERROR("cpsr contains invalid mode value - communication failure"); return ERROR_TARGET_FAILURE; } LOG_DEBUG("target entered debug state in %s mode", arm_mode_name(arm->core_mode)); if (arm->core_state == ARM_STATE_THUMB) { LOG_DEBUG("thumb state, applying fixups"); context[0] = r0_thumb; context[15] = pc_thumb; } else if (arm->core_state == ARM_STATE_ARM) { /* adjust value stored by STM */ context[15] -= 3 * 4; } if ((target->debug_reason != DBG_REASON_DBGRQ) || (!arm7_9->use_dbgrq)) context[15] -= 3 * ((arm->core_state == ARM_STATE_ARM) ? 4 : 2); else context[15] -= arm7_9->dbgreq_adjust_pc * ((arm->core_state == ARM_STATE_ARM) ? 4 : 2); for (i = 0; i <= 15; i++) { struct reg *r = arm_reg_current(arm, i); LOG_DEBUG("r%i: 0x%8.8" PRIx32 "", i, context[i]); buf_set_u32(r->value, 0, 32, context[i]); /* r0 and r15 (pc) have to be restored later */ r->dirty = (i == 0) || (i == 15); r->valid = 1; } LOG_DEBUG("entered debug state at PC 0x%" PRIx32 "", context[15]); /* exceptions other than USR & SYS have a saved program status register */ if (arm->spsr) { uint32_t spsr; arm7_9->read_xpsr(target, &spsr, 1); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; buf_set_u32(arm->spsr->value, 0, 32, spsr); arm->spsr->dirty = 0; arm->spsr->valid = 1; } retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (arm7_9->post_debug_entry) { retval = arm7_9->post_debug_entry(target); if (retval != ERROR_OK) return retval; } return ERROR_OK; } /** * Validate the full context for an ARM7/9 target in all processor modes. If * there are any invalid registers for the target, they will all be read. This * includes the PSR. * * @param target Pointer to the ARM7/9 target to capture the full context from * @return Error if the target is not halted, has an invalid core mode, or if * the JTAG queue fails to execute */ static int arm7_9_full_context(struct target *target) { int i; int retval; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; LOG_DEBUG("-"); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!is_arm_mode(arm->core_mode)) { LOG_ERROR("not a valid arm core mode - communication failure?"); return ERROR_FAIL; } /* iterate through processor modes (User, FIQ, IRQ, SVC, ABT, UND) * SYS shares registers with User, so we don't touch SYS */ for (i = 0; i < 6; i++) { uint32_t mask = 0; uint32_t *reg_p[16]; int j; int valid = 1; /* check if there are invalid registers in the current mode */ for (j = 0; j <= 16; j++) { if (ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode(i), j).valid == 0) valid = 0; } if (!valid) { uint32_t tmp_cpsr; /* change processor mode (and mask T bit) */ tmp_cpsr = buf_get_u32(arm->cpsr->value, 0, 8) & 0xe0; tmp_cpsr |= armv4_5_number_to_mode(i); tmp_cpsr &= ~0x20; arm7_9->write_xpsr_im8(target, tmp_cpsr & 0xff, 0, 0); for (j = 0; j < 15; j++) { if (ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode(i), j).valid == 0) { reg_p[j] = (uint32_t *)ARMV4_5_CORE_REG_MODE( arm->core_cache, armv4_5_number_to_mode(i), j).value; mask |= 1 << j; ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode(i), j).valid = 1; ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode(i), j).dirty = 0; } } /* if only the PSR is invalid, mask is all zeroes */ if (mask) arm7_9->read_core_regs(target, mask, reg_p); /* check if the PSR has to be read */ if (ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode(i), 16).valid == 0) { arm7_9->read_xpsr(target, (uint32_t *)ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode(i), 16).value, 1); ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode(i), 16).valid = 1; ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode(i), 16).dirty = 0; } } } /* restore processor mode (mask T bit) */ arm7_9->write_xpsr_im8(target, buf_get_u32(arm->cpsr->value, 0, 8) & ~0x20, 0, 0); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; return ERROR_OK; } /** * Restore the processor context on an ARM7/9 target. The full processor * context is analyzed to see if any of the registers are dirty on this end, but * have a valid new value. If this is the case, the processor is changed to the * appropriate mode and the new register values are written out to the * processor. If there happens to be a dirty register with an invalid value, an * error will be logged. * * @param target Pointer to the ARM7/9 target to have its context restored * @return Error status if the target is not halted or the core mode in the * armv4_5 struct is invalid. */ static int arm7_9_restore_context(struct target *target) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; struct reg *reg; enum arm_mode current_mode = arm->core_mode; int i, j; int dirty; int mode_change; LOG_DEBUG("-"); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (arm7_9->pre_restore_context) arm7_9->pre_restore_context(target); if (!is_arm_mode(arm->core_mode)) { LOG_ERROR("not a valid arm core mode - communication failure?"); return ERROR_FAIL; } /* iterate through processor modes (User, FIQ, IRQ, SVC, ABT, UND) * SYS shares registers with User, so we don't touch SYS */ for (i = 0; i < 6; i++) { LOG_DEBUG("examining %s mode", arm_mode_name(arm->core_mode)); dirty = 0; mode_change = 0; /* check if there are dirty registers in the current mode */ for (j = 0; j <= 16; j++) { reg = &ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode(i), j); if (reg->dirty == 1) { if (reg->valid == 1) { dirty = 1; LOG_DEBUG("examining dirty reg: %s", reg->name); struct arm_reg *reg_arch_info; reg_arch_info = reg->arch_info; if ((reg_arch_info->mode != ARM_MODE_ANY) && (reg_arch_info->mode != current_mode) && !((reg_arch_info->mode == ARM_MODE_USR) && (arm->core_mode == ARM_MODE_SYS)) && !((reg_arch_info->mode == ARM_MODE_SYS) && (arm->core_mode == ARM_MODE_USR))) { mode_change = 1; LOG_DEBUG("require mode change"); } } else LOG_ERROR("BUG: dirty register '%s', but no valid data", reg->name); } } if (dirty) { uint32_t mask = 0x0; int num_regs = 0; uint32_t regs[16]; if (mode_change) { uint32_t tmp_cpsr; /* change processor mode (mask T bit) */ tmp_cpsr = buf_get_u32(arm->cpsr->value, 0, 8) & 0xe0; tmp_cpsr |= armv4_5_number_to_mode(i); tmp_cpsr &= ~0x20; arm7_9->write_xpsr_im8(target, tmp_cpsr & 0xff, 0, 0); current_mode = armv4_5_number_to_mode(i); } for (j = 0; j <= 14; j++) { reg = &ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode(i), j); if (reg->dirty == 1) { regs[j] = buf_get_u32(reg->value, 0, 32); mask |= 1 << j; num_regs++; reg->dirty = 0; reg->valid = 1; LOG_DEBUG("writing register %i mode %s " "with value 0x%8.8" PRIx32, j, arm_mode_name(arm->core_mode), regs[j]); } } if (mask) arm7_9->write_core_regs(target, mask, regs); reg = &ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode( i), 16); struct arm_reg *reg_arch_info; reg_arch_info = reg->arch_info; if ((reg->dirty) && (reg_arch_info->mode != ARM_MODE_ANY)) { LOG_DEBUG("writing SPSR of mode %i with value 0x%8.8" PRIx32 "", i, buf_get_u32(reg->value, 0, 32)); arm7_9->write_xpsr(target, buf_get_u32(reg->value, 0, 32), 1); } } } if (!arm->cpsr->dirty && (arm->core_mode != current_mode)) { /* restore processor mode (mask T bit) */ uint32_t tmp_cpsr; tmp_cpsr = buf_get_u32(arm->cpsr->value, 0, 8) & 0xE0; tmp_cpsr |= armv4_5_number_to_mode(i); tmp_cpsr &= ~0x20; LOG_DEBUG("writing lower 8 bit of cpsr with value 0x%2.2x", (unsigned)(tmp_cpsr)); arm7_9->write_xpsr_im8(target, tmp_cpsr & 0xff, 0, 0); } else if (arm->cpsr->dirty) { /* CPSR has been changed, full restore necessary (mask T bit) */ LOG_DEBUG("writing cpsr with value 0x%8.8" PRIx32, buf_get_u32(arm->cpsr->value, 0, 32)); arm7_9->write_xpsr(target, buf_get_u32(arm->cpsr->value, 0, 32) & ~0x20, 0); arm->cpsr->dirty = 0; arm->cpsr->valid = 1; } /* restore PC */ LOG_DEBUG("writing PC with value 0x%8.8" PRIx32, buf_get_u32(arm->pc->value, 0, 32)); arm7_9->write_pc(target, buf_get_u32(arm->pc->value, 0, 32)); arm->pc->dirty = 0; return ERROR_OK; } /** * Restart the core of an ARM7/9 target. A RESTART command is sent to the * instruction register and the JTAG state is set to TAP_IDLE causing a core * restart. * * @param target Pointer to the ARM7/9 target to be restarted * @return Result of executing the JTAG queue */ static int arm7_9_restart_core(struct target *target) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; int retval; /* set RESTART instruction */ if (arm7_9->need_bypass_before_restart) { arm7_9->need_bypass_before_restart = 0; retval = arm_jtag_set_instr(jtag_info, 0xf, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; } retval = arm_jtag_set_instr(jtag_info, 0x4, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; jtag_add_runtest(1, TAP_IDLE); return jtag_execute_queue(); } /** * Enable the watchpoints on an ARM7/9 target. The target's watchpoints are * iterated through and are set on the target if they aren't already set. * * @param target Pointer to the ARM7/9 target to enable watchpoints on */ static void arm7_9_enable_watchpoints(struct target *target) { struct watchpoint *watchpoint = target->watchpoints; while (watchpoint) { if (watchpoint->set == 0) arm7_9_set_watchpoint(target, watchpoint); watchpoint = watchpoint->next; } } /** * Enable the breakpoints on an ARM7/9 target. The target's breakpoints are * iterated through and are set on the target. * * @param target Pointer to the ARM7/9 target to enable breakpoints on */ static void arm7_9_enable_breakpoints(struct target *target) { struct breakpoint *breakpoint = target->breakpoints; /* set any pending breakpoints */ while (breakpoint) { arm7_9_set_breakpoint(target, breakpoint); breakpoint = breakpoint->next; } } int arm7_9_resume(struct target *target, int current, uint32_t address, int handle_breakpoints, int debug_execution) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; struct reg *dbg_ctrl = &arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]; int err, retval = ERROR_OK; LOG_DEBUG("-"); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!debug_execution) target_free_all_working_areas(target); /* current = 1: continue on current pc, otherwise continue at
*/ if (!current) buf_set_u32(arm->pc->value, 0, 32, address); uint32_t current_pc; current_pc = buf_get_u32(arm->pc->value, 0, 32); /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) { struct breakpoint *breakpoint; breakpoint = breakpoint_find(target, buf_get_u32(arm->pc->value, 0, 32)); if (breakpoint != NULL) { LOG_DEBUG("unset breakpoint at 0x%8.8" PRIx32 " (id: %d)", breakpoint->address, breakpoint->unique_id); retval = arm7_9_unset_breakpoint(target, breakpoint); if (retval != ERROR_OK) return retval; /* calculate PC of next instruction */ uint32_t next_pc; retval = arm_simulate_step(target, &next_pc); if (retval != ERROR_OK) { uint32_t current_opcode; target_read_u32(target, current_pc, ¤t_opcode); LOG_ERROR( "Couldn't calculate PC of next instruction, current opcode was 0x%8.8" PRIx32 "", current_opcode); return retval; } LOG_DEBUG("enable single-step"); arm7_9->enable_single_step(target, next_pc); target->debug_reason = DBG_REASON_SINGLESTEP; retval = arm7_9_restore_context(target); if (retval != ERROR_OK) return retval; if (arm->core_state == ARM_STATE_ARM) arm7_9->branch_resume(target); else if (arm->core_state == ARM_STATE_THUMB) arm7_9->branch_resume_thumb(target); else { LOG_ERROR("unhandled core state"); return ERROR_FAIL; } buf_set_u32(dbg_ctrl->value, EICE_DBG_CONTROL_DBGACK, 1, 0); embeddedice_write_reg(dbg_ctrl, buf_get_u32(dbg_ctrl->value, 0, dbg_ctrl->size)); err = arm7_9_execute_sys_speed(target); LOG_DEBUG("disable single-step"); arm7_9->disable_single_step(target); if (err != ERROR_OK) { retval = arm7_9_set_breakpoint(target, breakpoint); if (retval != ERROR_OK) return retval; target->state = TARGET_UNKNOWN; return err; } retval = arm7_9_debug_entry(target); if (retval != ERROR_OK) return retval; LOG_DEBUG("new PC after step: 0x%8.8" PRIx32, buf_get_u32(arm->pc->value, 0, 32)); LOG_DEBUG("set breakpoint at 0x%8.8" PRIx32 "", breakpoint->address); retval = arm7_9_set_breakpoint(target, breakpoint); if (retval != ERROR_OK) return retval; } } /* enable any pending breakpoints and watchpoints */ arm7_9_enable_breakpoints(target); arm7_9_enable_watchpoints(target); retval = arm7_9_restore_context(target); if (retval != ERROR_OK) return retval; if (arm->core_state == ARM_STATE_ARM) arm7_9->branch_resume(target); else if (arm->core_state == ARM_STATE_THUMB) arm7_9->branch_resume_thumb(target); else { LOG_ERROR("unhandled core state"); return ERROR_FAIL; } /* deassert DBGACK and INTDIS */ buf_set_u32(dbg_ctrl->value, EICE_DBG_CONTROL_DBGACK, 1, 0); /* INTDIS only when we really resume, not during debug execution */ if (!debug_execution) buf_set_u32(dbg_ctrl->value, EICE_DBG_CONTROL_INTDIS, 1, 0); embeddedice_write_reg(dbg_ctrl, buf_get_u32(dbg_ctrl->value, 0, dbg_ctrl->size)); retval = arm7_9_restart_core(target); if (retval != ERROR_OK) return retval; target->debug_reason = DBG_REASON_NOTHALTED; if (!debug_execution) { /* registers are now invalid */ register_cache_invalidate(arm->core_cache); target->state = TARGET_RUNNING; retval = target_call_event_callbacks(target, TARGET_EVENT_RESUMED); if (retval != ERROR_OK) return retval; } else { target->state = TARGET_DEBUG_RUNNING; retval = target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); if (retval != ERROR_OK) return retval; } LOG_DEBUG("target resumed"); return ERROR_OK; } void arm7_9_enable_eice_step(struct target *target, uint32_t next_pc) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; uint32_t current_pc; current_pc = buf_get_u32(arm->pc->value, 0, 32); if (next_pc != current_pc) { /* setup an inverse breakpoint on the current PC * - comparator 1 matches the current address * - rangeout from comparator 1 is connected to comparator 0 rangein * - comparator 0 matches any address, as long as rangein is low */ embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK], 0xffffffff); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK], 0xffffffff); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], EICE_W_CTRL_ENABLE); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK], ~(EICE_W_CTRL_RANGE | EICE_W_CTRL_nOPC) & 0xff); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_VALUE], current_pc); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_MASK], 0); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W1_DATA_MASK], 0xffffffff); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE], 0x0); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_MASK], ~EICE_W_CTRL_nOPC & 0xff); } else { embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK], 0xffffffff); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK], 0xffffffff); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE], 0x0); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK], 0xff); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_VALUE], next_pc); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_MASK], 0); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W1_DATA_MASK], 0xffffffff); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE], EICE_W_CTRL_ENABLE); embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_MASK], ~EICE_W_CTRL_nOPC & 0xff); } } void arm7_9_disable_eice_step(struct target *target) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W0_ADDR_MASK]); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W0_DATA_MASK]); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_VALUE]); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W0_CONTROL_MASK]); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_VALUE]); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W1_ADDR_MASK]); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W1_DATA_MASK]); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_MASK]); embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE]); } int arm7_9_step(struct target *target, int current, uint32_t address, int handle_breakpoints) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; struct breakpoint *breakpoint = NULL; int err, retval; if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* current = 1: continue on current pc, otherwise continue at
*/ if (!current) buf_set_u32(arm->pc->value, 0, 32, address); uint32_t current_pc = buf_get_u32(arm->pc->value, 0, 32); /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) breakpoint = breakpoint_find(target, current_pc); if (breakpoint != NULL) { retval = arm7_9_unset_breakpoint(target, breakpoint); if (retval != ERROR_OK) return retval; } target->debug_reason = DBG_REASON_SINGLESTEP; /* calculate PC of next instruction */ uint32_t next_pc; retval = arm_simulate_step(target, &next_pc); if (retval != ERROR_OK) { uint32_t current_opcode; target_read_u32(target, current_pc, ¤t_opcode); LOG_ERROR( "Couldn't calculate PC of next instruction, current opcode was 0x%8.8" PRIx32 "", current_opcode); return retval; } retval = arm7_9_restore_context(target); if (retval != ERROR_OK) return retval; arm7_9->enable_single_step(target, next_pc); if (arm->core_state == ARM_STATE_ARM) arm7_9->branch_resume(target); else if (arm->core_state == ARM_STATE_THUMB) arm7_9->branch_resume_thumb(target); else { LOG_ERROR("unhandled core state"); return ERROR_FAIL; } retval = target_call_event_callbacks(target, TARGET_EVENT_RESUMED); if (retval != ERROR_OK) return retval; err = arm7_9_execute_sys_speed(target); arm7_9->disable_single_step(target); /* registers are now invalid */ register_cache_invalidate(arm->core_cache); if (err != ERROR_OK) target->state = TARGET_UNKNOWN; else { retval = arm7_9_debug_entry(target); if (retval != ERROR_OK) return retval; retval = target_call_event_callbacks(target, TARGET_EVENT_HALTED); if (retval != ERROR_OK) return retval; LOG_DEBUG("target stepped"); } if (breakpoint) { retval = arm7_9_set_breakpoint(target, breakpoint); if (retval != ERROR_OK) return retval; } return err; } static int arm7_9_read_core_reg(struct target *target, struct reg *r, int num, enum arm_mode mode) { uint32_t *reg_p[16]; int retval; struct arm_reg *areg = r->arch_info; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; if (!is_arm_mode(arm->core_mode)) return ERROR_FAIL; if ((num < 0) || (num > 16)) return ERROR_COMMAND_SYNTAX_ERROR; if ((mode != ARM_MODE_ANY) && (mode != arm->core_mode) && (areg->mode != ARM_MODE_ANY)) { uint32_t tmp_cpsr; /* change processor mode (mask T bit) */ tmp_cpsr = buf_get_u32(arm->cpsr->value, 0, 8) & 0xE0; tmp_cpsr |= mode; tmp_cpsr &= ~0x20; arm7_9->write_xpsr_im8(target, tmp_cpsr & 0xff, 0, 0); } uint32_t value = 0; if ((num >= 0) && (num <= 15)) { /* read a normal core register */ reg_p[num] = &value; arm7_9->read_core_regs(target, 1 << num, reg_p); } else { /* read a program status register * if the register mode is MODE_ANY, we read the cpsr, otherwise a spsr */ arm7_9->read_xpsr(target, &value, areg->mode != ARM_MODE_ANY); } retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; r->valid = 1; r->dirty = 0; buf_set_u32(r->value, 0, 32, value); if ((mode != ARM_MODE_ANY) && (mode != arm->core_mode) && (areg->mode != ARM_MODE_ANY)) { /* restore processor mode (mask T bit) */ arm7_9->write_xpsr_im8(target, buf_get_u32(arm->cpsr->value, 0, 8) & ~0x20, 0, 0); } return ERROR_OK; } static int arm7_9_write_core_reg(struct target *target, struct reg *r, int num, enum arm_mode mode, uint32_t value) { uint32_t reg[16]; struct arm_reg *areg = r->arch_info; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; if (!is_arm_mode(arm->core_mode)) return ERROR_FAIL; if ((num < 0) || (num > 16)) return ERROR_COMMAND_SYNTAX_ERROR; if ((mode != ARM_MODE_ANY) && (mode != arm->core_mode) && (areg->mode != ARM_MODE_ANY)) { uint32_t tmp_cpsr; /* change processor mode (mask T bit) */ tmp_cpsr = buf_get_u32(arm->cpsr->value, 0, 8) & 0xE0; tmp_cpsr |= mode; tmp_cpsr &= ~0x20; arm7_9->write_xpsr_im8(target, tmp_cpsr & 0xff, 0, 0); } if ((num >= 0) && (num <= 15)) { /* write a normal core register */ reg[num] = value; arm7_9->write_core_regs(target, 1 << num, reg); } else { /* write a program status register * if the register mode is MODE_ANY, we write the cpsr, otherwise a spsr */ int spsr = (areg->mode != ARM_MODE_ANY); /* if we're writing the CPSR, mask the T bit */ if (!spsr) value &= ~0x20; arm7_9->write_xpsr(target, value, spsr); } r->valid = 1; r->dirty = 0; if ((mode != ARM_MODE_ANY) && (mode != arm->core_mode) && (areg->mode != ARM_MODE_ANY)) { /* restore processor mode (mask T bit) */ arm7_9->write_xpsr_im8(target, buf_get_u32(arm->cpsr->value, 0, 8) & ~0x20, 0, 0); } return jtag_execute_queue(); } int arm7_9_read_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; uint32_t reg[16]; uint32_t num_accesses = 0; int thisrun_accesses; int i; uint32_t cpsr; int retval; int last_reg = 0; LOG_DEBUG("address: 0x%8.8" PRIx32 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", address, size, count); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* sanitize arguments */ if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer)) return ERROR_COMMAND_SYNTAX_ERROR; if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) return ERROR_TARGET_UNALIGNED_ACCESS; /* load the base register with the address of the first word */ reg[0] = address; arm7_9->write_core_regs(target, 0x1, reg); int j = 0; switch (size) { case 4: while (num_accesses < count) { uint32_t reg_list; thisrun_accesses = ((count - num_accesses) >= 14) ? 14 : (count - num_accesses); reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe; if (last_reg <= thisrun_accesses) last_reg = thisrun_accesses; arm7_9->load_word_regs(target, reg_list); /* fast memory reads are only safe when the target is running * from a sufficiently high clock (32 kHz is usually too slow) */ if (arm7_9->fast_memory_access) retval = arm7_9_execute_fast_sys_speed(target); else retval = arm7_9_execute_sys_speed(target); if (retval != ERROR_OK) return retval; arm7_9->read_core_regs_target_buffer(target, reg_list, buffer, 4); /* advance buffer, count number of accesses */ buffer += thisrun_accesses * 4; num_accesses += thisrun_accesses; if ((j++%1024) == 0) keep_alive(); } break; case 2: while (num_accesses < count) { uint32_t reg_list; thisrun_accesses = ((count - num_accesses) >= 14) ? 14 : (count - num_accesses); reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe; for (i = 1; i <= thisrun_accesses; i++) { if (i > last_reg) last_reg = i; arm7_9->load_hword_reg(target, i); /* fast memory reads are only safe when the target is running * from a sufficiently high clock (32 kHz is usually too slow) */ if (arm7_9->fast_memory_access) retval = arm7_9_execute_fast_sys_speed(target); else retval = arm7_9_execute_sys_speed(target); if (retval != ERROR_OK) return retval; } arm7_9->read_core_regs_target_buffer(target, reg_list, buffer, 2); /* advance buffer, count number of accesses */ buffer += thisrun_accesses * 2; num_accesses += thisrun_accesses; if ((j++%1024) == 0) keep_alive(); } break; case 1: while (num_accesses < count) { uint32_t reg_list; thisrun_accesses = ((count - num_accesses) >= 14) ? 14 : (count - num_accesses); reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe; for (i = 1; i <= thisrun_accesses; i++) { if (i > last_reg) last_reg = i; arm7_9->load_byte_reg(target, i); /* fast memory reads are only safe when the target is running * from a sufficiently high clock (32 kHz is usually too slow) */ if (arm7_9->fast_memory_access) retval = arm7_9_execute_fast_sys_speed(target); else retval = arm7_9_execute_sys_speed(target); if (retval != ERROR_OK) return retval; } arm7_9->read_core_regs_target_buffer(target, reg_list, buffer, 1); /* advance buffer, count number of accesses */ buffer += thisrun_accesses * 1; num_accesses += thisrun_accesses; if ((j++%1024) == 0) keep_alive(); } break; } if (!is_arm_mode(arm->core_mode)) return ERROR_FAIL; for (i = 0; i <= last_reg; i++) { struct reg *r = arm_reg_current(arm, i); r->dirty = r->valid; } arm7_9->read_xpsr(target, &cpsr, 0); retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("JTAG error while reading cpsr"); return ERROR_TARGET_DATA_ABORT; } if (((cpsr & 0x1f) == ARM_MODE_ABT) && (arm->core_mode != ARM_MODE_ABT)) { LOG_WARNING( "memory read caused data abort (address: 0x%8.8" PRIx32 ", size: 0x%" PRIx32 ", count: 0x%" PRIx32 ")", address, size, count); arm7_9->write_xpsr_im8(target, buf_get_u32(arm->cpsr->value, 0, 8) & ~0x20, 0, 0); return ERROR_TARGET_DATA_ABORT; } return ERROR_OK; } int arm7_9_write_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; struct reg *dbg_ctrl = &arm7_9->eice_cache->reg_list[EICE_DBG_CTRL]; uint32_t reg[16]; uint32_t num_accesses = 0; int thisrun_accesses; int i; uint32_t cpsr; int retval; int last_reg = 0; #ifdef _DEBUG_ARM7_9_ LOG_DEBUG("address: 0x%8.8x, size: 0x%8.8x, count: 0x%8.8x", address, size, count); #endif if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* sanitize arguments */ if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer)) return ERROR_COMMAND_SYNTAX_ERROR; if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) return ERROR_TARGET_UNALIGNED_ACCESS; /* load the base register with the address of the first word */ reg[0] = address; arm7_9->write_core_regs(target, 0x1, reg); /* Clear DBGACK, to make sure memory fetches work as expected */ buf_set_u32(dbg_ctrl->value, EICE_DBG_CONTROL_DBGACK, 1, 0); embeddedice_store_reg(dbg_ctrl); switch (size) { case 4: while (num_accesses < count) { uint32_t reg_list; thisrun_accesses = ((count - num_accesses) >= 14) ? 14 : (count - num_accesses); reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe; for (i = 1; i <= thisrun_accesses; i++) { if (i > last_reg) last_reg = i; reg[i] = target_buffer_get_u32(target, buffer); buffer += 4; } arm7_9->write_core_regs(target, reg_list, reg); arm7_9->store_word_regs(target, reg_list); /* fast memory writes are only safe when the target is running * from a sufficiently high clock (32 kHz is usually too slow) */ if (arm7_9->fast_memory_access) retval = arm7_9_execute_fast_sys_speed(target); else { retval = arm7_9_execute_sys_speed(target); /* * if memory writes are made when the clock is running slow * (i.e. 32 kHz) which is necessary in some scripts to reconfigure * processor operations after a "reset halt" or "reset init", * need to immediately stroke the keep alive or will end up with * gdb "keep alive not sent error message" problem. */ keep_alive(); } if (retval != ERROR_OK) return retval; num_accesses += thisrun_accesses; } break; case 2: while (num_accesses < count) { uint32_t reg_list; thisrun_accesses = ((count - num_accesses) >= 14) ? 14 : (count - num_accesses); reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe; for (i = 1; i <= thisrun_accesses; i++) { if (i > last_reg) last_reg = i; reg[i] = target_buffer_get_u16(target, buffer) & 0xffff; buffer += 2; } arm7_9->write_core_regs(target, reg_list, reg); for (i = 1; i <= thisrun_accesses; i++) { arm7_9->store_hword_reg(target, i); /* fast memory writes are only safe when the target is running * from a sufficiently high clock (32 kHz is usually too slow) */ if (arm7_9->fast_memory_access) retval = arm7_9_execute_fast_sys_speed(target); else { retval = arm7_9_execute_sys_speed(target); /* * if memory writes are made when the clock is running slow * (i.e. 32 kHz) which is necessary in some scripts to reconfigure * processor operations after a "reset halt" or "reset init", * need to immediately stroke the keep alive or will end up with * gdb "keep alive not sent error message" problem. */ keep_alive(); } if (retval != ERROR_OK) return retval; } num_accesses += thisrun_accesses; } break; case 1: while (num_accesses < count) { uint32_t reg_list; thisrun_accesses = ((count - num_accesses) >= 14) ? 14 : (count - num_accesses); reg_list = (0xffff >> (15 - thisrun_accesses)) & 0xfffe; for (i = 1; i <= thisrun_accesses; i++) { if (i > last_reg) last_reg = i; reg[i] = *buffer++ & 0xff; } arm7_9->write_core_regs(target, reg_list, reg); for (i = 1; i <= thisrun_accesses; i++) { arm7_9->store_byte_reg(target, i); /* fast memory writes are only safe when the target is running * from a sufficiently high clock (32 kHz is usually too slow) */ if (arm7_9->fast_memory_access) retval = arm7_9_execute_fast_sys_speed(target); else { retval = arm7_9_execute_sys_speed(target); /* * if memory writes are made when the clock is running slow * (i.e. 32 kHz) which is necessary in some scripts to reconfigure * processor operations after a "reset halt" or "reset init", * need to immediately stroke the keep alive or will end up with * gdb "keep alive not sent error message" problem. */ keep_alive(); } if (retval != ERROR_OK) return retval; } num_accesses += thisrun_accesses; } break; } /* Re-Set DBGACK */ buf_set_u32(dbg_ctrl->value, EICE_DBG_CONTROL_DBGACK, 1, 1); embeddedice_store_reg(dbg_ctrl); if (!is_arm_mode(arm->core_mode)) return ERROR_FAIL; for (i = 0; i <= last_reg; i++) { struct reg *r = arm_reg_current(arm, i); r->dirty = r->valid; } arm7_9->read_xpsr(target, &cpsr, 0); retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("JTAG error while reading cpsr"); return ERROR_TARGET_DATA_ABORT; } if (((cpsr & 0x1f) == ARM_MODE_ABT) && (arm->core_mode != ARM_MODE_ABT)) { LOG_WARNING( "memory write caused data abort (address: 0x%8.8" PRIx32 ", size: 0x%" PRIx32 ", count: 0x%" PRIx32 ")", address, size, count); arm7_9->write_xpsr_im8(target, buf_get_u32(arm->cpsr->value, 0, 8) & ~0x20, 0, 0); return ERROR_TARGET_DATA_ABORT; } return ERROR_OK; } static int dcc_count; static const uint8_t *dcc_buffer; static int arm7_9_dcc_completion(struct target *target, uint32_t exit_point, int timeout_ms, void *arch_info) { int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); retval = target_wait_state(target, TARGET_DEBUG_RUNNING, 500); if (retval != ERROR_OK) return retval; int little = target->endianness == TARGET_LITTLE_ENDIAN; int count = dcc_count; const uint8_t *buffer = dcc_buffer; if (count > 2) { /* Handle first & last using standard embeddedice_write_reg and the middle ones w/the * core function repeated. */ embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_COMMS_DATA], fast_target_buffer_get_u32(buffer, little)); buffer += 4; struct embeddedice_reg *ice_reg = arm7_9->eice_cache->reg_list[EICE_COMMS_DATA].arch_info; uint8_t reg_addr = ice_reg->addr & 0x1f; struct jtag_tap *tap; tap = ice_reg->jtag_info->tap; embeddedice_write_dcc(tap, reg_addr, buffer, little, count-2); buffer += (count-2)*4; embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_COMMS_DATA], fast_target_buffer_get_u32(buffer, little)); } else { int i; for (i = 0; i < count; i++) { embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_COMMS_DATA], fast_target_buffer_get_u32(buffer, little)); buffer += 4; } } retval = target_halt(target); if (retval != ERROR_OK) return retval; return target_wait_state(target, TARGET_HALTED, 500); } static const uint32_t dcc_code[] = { /* r0 == input, points to memory buffer * r1 == scratch */ /* spin until DCC control (c0) reports data arrived */ 0xee101e10, /* w: mrc p14, #0, r1, c0, c0 */ 0xe3110001, /* tst r1, #1 */ 0x0afffffc, /* bne w */ /* read word from DCC (c1), write to memory */ 0xee111e10, /* mrc p14, #0, r1, c1, c0 */ 0xe4801004, /* str r1, [r0], #4 */ /* repeat */ 0xeafffff9 /* b w */ }; int arm7_9_bulk_write_memory(struct target *target, uint32_t address, uint32_t count, const uint8_t *buffer) { int retval; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); int i; if (!arm7_9->dcc_downloads) return target_write_memory(target, address, 4, count, buffer); /* regrab previously allocated working_area, or allocate a new one */ if (!arm7_9->dcc_working_area) { uint8_t dcc_code_buf[6 * 4]; /* make sure we have a working area */ if (target_alloc_working_area(target, 24, &arm7_9->dcc_working_area) != ERROR_OK) { LOG_INFO("no working area available, falling back to memory writes"); return target_write_memory(target, address, 4, count, buffer); } /* copy target instructions to target endianness */ for (i = 0; i < 6; i++) target_buffer_set_u32(target, dcc_code_buf + i*4, dcc_code[i]); /* write DCC code to working area */ retval = target_write_memory(target, arm7_9->dcc_working_area->address, 4, 6, dcc_code_buf); if (retval != ERROR_OK) return retval; } struct arm_algorithm arm_algo; struct reg_param reg_params[1]; arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); dcc_count = count; dcc_buffer = buffer; retval = armv4_5_run_algorithm_inner(target, 0, NULL, 1, reg_params, arm7_9->dcc_working_area->address, arm7_9->dcc_working_area->address + 6*4, 20*1000, &arm_algo, arm7_9_dcc_completion); if (retval == ERROR_OK) { uint32_t endaddress = buf_get_u32(reg_params[0].value, 0, 32); if (endaddress != (address + count*4)) { LOG_ERROR( "DCC write failed, expected end address 0x%08" PRIx32 " got 0x%0" PRIx32 "", (address + count*4), endaddress); retval = ERROR_FAIL; } } destroy_reg_param(®_params[0]); return retval; } /** * Perform per-target setup that requires JTAG access. */ int arm7_9_examine(struct target *target) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); int retval; if (!target_was_examined(target)) { struct reg_cache *t, **cache_p; t = embeddedice_build_reg_cache(target, arm7_9); if (t == NULL) return ERROR_FAIL; cache_p = register_get_last_cache_p(&target->reg_cache); (*cache_p) = t; arm7_9->eice_cache = (*cache_p); if (arm7_9->arm.etm) (*cache_p)->next = etm_build_reg_cache(target, &arm7_9->jtag_info, arm7_9->arm.etm); target_set_examined(target); } retval = embeddedice_setup(target); if (retval == ERROR_OK) retval = arm7_9_setup(target); if (retval == ERROR_OK && arm7_9->arm.etm) retval = etm_setup(target); return retval; } int arm7_9_check_reset(struct target *target) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); if (get_target_reset_nag() && !arm7_9->dcc_downloads) LOG_WARNING( "NOTE! DCC downloads have not been enabled, defaulting to slow memory writes. Type 'help dcc'."); if (get_target_reset_nag() && (target->working_area_size == 0)) LOG_WARNING("NOTE! Severe performance degradation without working memory enabled."); if (get_target_reset_nag() && !arm7_9->fast_memory_access) LOG_WARNING( "NOTE! Severe performance degradation without fast memory access enabled. Type 'help fast'."); return ERROR_OK; } int arm7_9_endianness_callback(jtag_callback_data_t pu8_in, jtag_callback_data_t i_size, jtag_callback_data_t i_be, jtag_callback_data_t i_flip) { uint8_t *in = (uint8_t *)pu8_in; int size = (int)i_size; int be = (int)i_be; int flip = (int)i_flip; uint32_t readback; switch (size) { case 4: readback = le_to_h_u32(in); if (flip) readback = flip_u32(readback, 32); if (be) h_u32_to_be(in, readback); else h_u32_to_le(in, readback); break; case 2: readback = le_to_h_u16(in); if (flip) readback = flip_u32(readback, 16); if (be) h_u16_to_be(in, readback & 0xffff); else h_u16_to_le(in, readback & 0xffff); break; case 1: readback = *in; if (flip) readback = flip_u32(readback, 8); *in = readback & 0xff; break; } return ERROR_OK; } COMMAND_HANDLER(handle_arm7_9_dbgrq_command) { struct target *target = get_current_target(CMD_CTX); struct arm7_9_common *arm7_9 = target_to_arm7_9(target); if (!is_arm7_9(arm7_9)) { command_print(CMD_CTX, "current target isn't an ARM7/ARM9 target"); return ERROR_TARGET_INVALID; } if (CMD_ARGC > 0) COMMAND_PARSE_ENABLE(CMD_ARGV[0], arm7_9->use_dbgrq); command_print(CMD_CTX, "use of EmbeddedICE dbgrq instead of breakpoint for target halt %s", (arm7_9->use_dbgrq) ? "enabled" : "disabled"); return ERROR_OK; } COMMAND_HANDLER(handle_arm7_9_fast_memory_access_command) { struct target *target = get_current_target(CMD_CTX); struct arm7_9_common *arm7_9 = target_to_arm7_9(target); if (!is_arm7_9(arm7_9)) { command_print(CMD_CTX, "current target isn't an ARM7/ARM9 target"); return ERROR_TARGET_INVALID; } if (CMD_ARGC > 0) COMMAND_PARSE_ENABLE(CMD_ARGV[0], arm7_9->fast_memory_access); command_print(CMD_CTX, "fast memory access is %s", (arm7_9->fast_memory_access) ? "enabled" : "disabled"); return ERROR_OK; } COMMAND_HANDLER(handle_arm7_9_dcc_downloads_command) { struct target *target = get_current_target(CMD_CTX); struct arm7_9_common *arm7_9 = target_to_arm7_9(target); if (!is_arm7_9(arm7_9)) { command_print(CMD_CTX, "current target isn't an ARM7/ARM9 target"); return ERROR_TARGET_INVALID; } if (CMD_ARGC > 0) COMMAND_PARSE_ENABLE(CMD_ARGV[0], arm7_9->dcc_downloads); command_print(CMD_CTX, "dcc downloads are %s", (arm7_9->dcc_downloads) ? "enabled" : "disabled"); return ERROR_OK; } static int arm7_9_setup_semihosting(struct target *target, int enable) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); if (!is_arm7_9(arm7_9)) { LOG_USER("current target isn't an ARM7/ARM9 target"); return ERROR_TARGET_INVALID; } if (arm7_9->has_vector_catch) { struct reg *vector_catch = &arm7_9->eice_cache ->reg_list[EICE_VEC_CATCH]; if (!vector_catch->valid) embeddedice_read_reg(vector_catch); buf_set_u32(vector_catch->value, 2, 1, enable); embeddedice_store_reg(vector_catch); } else { /* TODO: allow optional high vectors and/or BKPT_HARD */ if (enable) breakpoint_add(target, 8, 4, BKPT_SOFT); else breakpoint_remove(target, 8); } return ERROR_OK; } int arm7_9_init_arch_info(struct target *target, struct arm7_9_common *arm7_9) { int retval = ERROR_OK; struct arm *arm = &arm7_9->arm; arm7_9->common_magic = ARM7_9_COMMON_MAGIC; retval = arm_jtag_setup_connection(&arm7_9->jtag_info); if (retval != ERROR_OK) return retval; /* caller must have allocated via calloc(), so everything's zeroed */ arm7_9->wp_available_max = 2; arm7_9->fast_memory_access = false; arm7_9->dcc_downloads = false; arm->arch_info = arm7_9; arm->core_type = ARM_MODE_ANY; arm->read_core_reg = arm7_9_read_core_reg; arm->write_core_reg = arm7_9_write_core_reg; arm->full_context = arm7_9_full_context; arm->setup_semihosting = arm7_9_setup_semihosting; retval = arm_init_arch_info(target, arm); if (retval != ERROR_OK) return retval; return target_register_timer_callback(arm7_9_handle_target_request, 1, 1, target); } static const struct command_registration arm7_9_any_command_handlers[] = { { "dbgrq", .handler = handle_arm7_9_dbgrq_command, .mode = COMMAND_ANY, .usage = "['enable'|'disable']", .help = "use EmbeddedICE dbgrq instead of breakpoint " "for target halt requests", }, { "fast_memory_access", .handler = handle_arm7_9_fast_memory_access_command, .mode = COMMAND_ANY, .usage = "['enable'|'disable']", .help = "use fast memory accesses instead of slower " "but potentially safer accesses", }, { "dcc_downloads", .handler = handle_arm7_9_dcc_downloads_command, .mode = COMMAND_ANY, .usage = "['enable'|'disable']", .help = "use DCC downloads for larger memory writes", }, COMMAND_REGISTRATION_DONE }; const struct command_registration arm7_9_command_handlers[] = { { .chain = arm_command_handlers, }, { .chain = etm_command_handlers, }, { .name = "arm7_9", .mode = COMMAND_ANY, .help = "arm7/9 specific commands", .usage = "", .chain = arm7_9_any_command_handlers, }, COMMAND_REGISTRATION_DONE }; openocd-0.7.0/src/target/dsp563xx_once.c0000644000175000001440000001747312134336410014724 00000000000000/*************************************************************************** * Copyright (C) 2009 by Mathias Kuester * * mkdorg@users.sourceforge.net * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "target.h" #include "target_type.h" #include "register.h" #include "dsp563xx.h" #include "dsp563xx_once.h" #define JTAG_STATUS_STATIC_MASK 0x03 #define JTAG_STATUS_STATIC_VALUE 0x01 #define JTAG_STATUS_NORMAL 0x01 #define JTAG_STATUS_STOPWAIT 0x05 #define JTAG_STATUS_BUSY 0x09 #define JTAG_STATUS_DEBUG 0x0d #define JTAG_INSTR_EXTEST 0x00 #define JTAG_INSTR_SAMPLE_PRELOAD 0x01 #define JTAG_INSTR_IDCODE 0x02 #define JTAG_INSTR_HIZ 0x04 #define JTAG_INSTR_CLAMP 0x05 #define JTAG_INSTR_ENABLE_ONCE 0x06 #define JTAG_INSTR_DEBUG_REQUEST 0x07 #define JTAG_INSTR_BYPASS 0x0F /** */ static inline int dsp563xx_write_dr(struct jtag_tap *tap, uint8_t * dr_in, uint8_t * dr_out, int dr_len, int rti) { jtag_add_plain_dr_scan(dr_len, dr_out, dr_in, TAP_IDLE); return ERROR_OK; } /** */ static inline int dsp563xx_write_dr_u8(struct jtag_tap *tap, uint8_t * dr_in, uint8_t dr_out, int dr_len, int rti) { return dsp563xx_write_dr(tap, dr_in, &dr_out, dr_len, rti); } /** */ static inline int dsp563xx_write_dr_u32(struct jtag_tap *tap, uint32_t * dr_in, uint32_t dr_out, int dr_len, int rti) { return dsp563xx_write_dr(tap, (uint8_t *) dr_in, (uint8_t *) &dr_out, dr_len, rti); } /** single word instruction */ static inline int dsp563xx_once_ir_exec(struct jtag_tap *tap, int flush, uint8_t instr, uint8_t rw, uint8_t go, uint8_t ex) { int err; err = dsp563xx_write_dr_u8(tap, 0, instr | (ex << 5) | (go << 6) | (rw << 7), 8, 0); if (err != ERROR_OK) return err; if (flush) err = jtag_execute_queue(); return err; } /* IR and DR functions */ static inline int dsp563xx_write_ir(struct jtag_tap *tap, uint8_t * ir_in, uint8_t * ir_out, int ir_len, int rti) { jtag_add_plain_ir_scan(tap->ir_length, ir_out, ir_in, TAP_IDLE); return ERROR_OK; } static inline int dsp563xx_write_ir_u8(struct jtag_tap *tap, uint8_t * ir_in, uint8_t ir_out, int ir_len, int rti) { return dsp563xx_write_ir(tap, ir_in, &ir_out, ir_len, rti); } static inline int dsp563xx_jtag_sendinstr(struct jtag_tap *tap, uint8_t * ir_in, uint8_t ir_out) { return dsp563xx_write_ir_u8(tap, ir_in, ir_out, tap->ir_length, 1); } /** */ int dsp563xx_once_target_status(struct jtag_tap *tap) { int err; uint8_t jtag_status; err = dsp563xx_jtag_sendinstr(tap, &jtag_status, JTAG_INSTR_ENABLE_ONCE); if (err != ERROR_OK) return TARGET_UNKNOWN; err = jtag_execute_queue(); if (err != ERROR_OK) return TARGET_UNKNOWN; /* verify correct static status pattern */ if ((jtag_status & JTAG_STATUS_STATIC_MASK) != JTAG_STATUS_STATIC_VALUE) return TARGET_UNKNOWN; if (jtag_status != JTAG_STATUS_DEBUG) return TARGET_RUNNING; return TARGET_HALTED; } /** */ int dsp563xx_once_request_debug(struct jtag_tap *tap, int reset_state) { int err; uint8_t ir_in = 0, pattern = 0; uint32_t retry = 0; /* in reset state we only get a ACK * from the interface */ if (reset_state) pattern = 1; else pattern = JTAG_STATUS_DEBUG; /* wait until we get the ack */ while (ir_in != pattern) { err = dsp563xx_jtag_sendinstr(tap, &ir_in, JTAG_INSTR_DEBUG_REQUEST); if (err != ERROR_OK) return err; err = jtag_execute_queue(); if (err != ERROR_OK) return err; LOG_DEBUG("debug request: %02X", ir_in); if (retry++ == 100) return ERROR_TARGET_FAILURE; } /* we cant enable the once in reset state */ if (pattern == 1) return ERROR_OK; /* try to enable once */ retry = 0; ir_in = 0; while (ir_in != pattern) { err = dsp563xx_jtag_sendinstr(tap, &ir_in, JTAG_INSTR_ENABLE_ONCE); if (err != ERROR_OK) return err; err = jtag_execute_queue(); if (err != ERROR_OK) return err; LOG_DEBUG("enable once: %02X", ir_in); if (retry++ == 100) { LOG_DEBUG("error"); return ERROR_TARGET_FAILURE; } } if (ir_in != JTAG_STATUS_DEBUG) return ERROR_TARGET_FAILURE; return ERROR_OK; } /** once read registers */ int dsp563xx_once_read_register(struct jtag_tap *tap, int flush, struct once_reg *regs, int len) { int i; int err = ERROR_OK; for (i = 0; i < len; i++) { err = dsp563xx_once_reg_read_ex(tap, flush, regs[i].addr, regs[i].len, ®s[i].reg); if (err != ERROR_OK) return err; } if (flush) err = jtag_execute_queue(); return err; } /** once read register with register len */ int dsp563xx_once_reg_read_ex(struct jtag_tap *tap, int flush, uint8_t reg, uint8_t len, uint32_t * data) { int err; err = dsp563xx_once_ir_exec(tap, 1, reg, 1, 0, 0); if (err != ERROR_OK) return err; err = dsp563xx_write_dr_u32(tap, data, 0x00, len, 0); if (err != ERROR_OK) return err; if (flush) err = jtag_execute_queue(); return err; } /** once read register */ int dsp563xx_once_reg_read(struct jtag_tap *tap, int flush, uint8_t reg, uint32_t * data) { int err; err = dsp563xx_once_ir_exec(tap, flush, reg, 1, 0, 0); if (err != ERROR_OK) return err; err = dsp563xx_write_dr_u32(tap, data, 0x00, 24, 0); if (err != ERROR_OK) return err; if (flush) err = jtag_execute_queue(); return err; } /** once write register */ int dsp563xx_once_reg_write(struct jtag_tap *tap, int flush, uint8_t reg, uint32_t data) { int err; err = dsp563xx_once_ir_exec(tap, flush, reg, 0, 0, 0); if (err != ERROR_OK) return err; err = dsp563xx_write_dr_u32(tap, 0x00, data, 24, 0); if (err != ERROR_OK) return err; if (flush) err = jtag_execute_queue(); return err; } /** single word instruction */ int dsp563xx_once_execute_sw_ir(struct jtag_tap *tap, int flush, uint32_t opcode) { int err; err = dsp563xx_once_ir_exec(tap, flush, DSP563XX_ONCE_OPDBR, 0, 1, 0); if (err != ERROR_OK) return err; err = dsp563xx_write_dr_u32(tap, 0, opcode, 24, 0); if (err != ERROR_OK) return err; if (flush) err = jtag_execute_queue(); return err; } /** double word instruction */ int dsp563xx_once_execute_dw_ir(struct jtag_tap *tap, int flush, uint32_t opcode, uint32_t operand) { int err; err = dsp563xx_once_ir_exec(tap, flush, DSP563XX_ONCE_OPDBR, 0, 0, 0); if (err != ERROR_OK) return err; err = dsp563xx_write_dr_u32(tap, 0, opcode, 24, 0); if (err != ERROR_OK) return err; if (flush) { err = jtag_execute_queue(); if (err != ERROR_OK) return err; } err = dsp563xx_once_ir_exec(tap, flush, DSP563XX_ONCE_OPDBR, 0, 1, 0); if (err != ERROR_OK) return err; err = dsp563xx_write_dr_u32(tap, 0, operand, 24, 0); if (err != ERROR_OK) return err; if (flush) { err = jtag_execute_queue(); if (err != ERROR_OK) return err; } return ERROR_OK; } openocd-0.7.0/src/target/arm926ejs.c0000644000175000001440000006051112134336410014025 00000000000000/*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008,2009 by Øyvind Harboe * * oyvind.harboe@zylin.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm926ejs.h" #include #include "target_type.h" #include "register.h" #include "arm_opcodes.h" /* * The ARM926 is built around the ARM9EJ-S core, and most JTAG docs * are in the ARM9EJ-S Technical Reference Manual (ARM DDI 0222B) not * the ARM926 manual (ARM DDI 0198E). The scan chains are: * * 1 ... core debugging * 2 ... EmbeddedICE * 3 ... external boundary scan (SoC-specific, unused here) * 6 ... ETM * 15 ... coprocessor 15 */ #if 0 #define _DEBUG_INSTRUCTION_EXECUTION_ #endif #define ARM926EJS_CP15_ADDR(opcode_1, opcode_2, CRn, CRm) ((opcode_1 << 11) | (opcode_2 << 8) | (CRn << 4) | (CRm << 0)) static int arm926ejs_cp15_read(struct target *target, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t *value) { int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; uint32_t address = ARM926EJS_CP15_ADDR(op1, op2, CRn, CRm); struct scan_field fields[4]; uint8_t address_buf[2] = {0, 0}; uint8_t nr_w_buf = 0; uint8_t access_t = 1; buf_set_u32(address_buf, 0, 14, address); retval = arm_jtag_scann(jtag_info, 0xf, TAP_IDLE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 32; fields[0].out_value = NULL; fields[0].in_value = (uint8_t *)value; fields[1].num_bits = 1; fields[1].out_value = &access_t; fields[1].in_value = &access_t; fields[2].num_bits = 14; fields[2].out_value = address_buf; fields[2].in_value = NULL; fields[3].num_bits = 1; fields[3].out_value = &nr_w_buf; fields[3].in_value = NULL; jtag_add_dr_scan(jtag_info->tap, 4, fields, TAP_IDLE); long long then = timeval_ms(); for (;;) { /* rescan with NOP, to wait for the access to complete */ access_t = 0; nr_w_buf = 0; jtag_add_dr_scan(jtag_info->tap, 4, fields, TAP_IDLE); jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t)value); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (buf_get_u32(&access_t, 0, 1) == 1) break; /* 10ms timeout */ if ((timeval_ms()-then) > 10) { LOG_ERROR("cp15 read operation timed out"); return ERROR_FAIL; } } #ifdef _DEBUG_INSTRUCTION_EXECUTION_ LOG_DEBUG("addr: 0x%x value: %8.8x", address, *value); #endif retval = arm_jtag_set_instr(jtag_info, 0xc, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int arm926ejs_mrc(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t *value) { if (cpnum != 15) { LOG_ERROR("Only cp15 is supported"); return ERROR_FAIL; } return arm926ejs_cp15_read(target, op1, op2, CRn, CRm, value); } static int arm926ejs_cp15_write(struct target *target, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t value) { int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; uint32_t address = ARM926EJS_CP15_ADDR(op1, op2, CRn, CRm); struct scan_field fields[4]; uint8_t value_buf[4]; uint8_t address_buf[2] = {0, 0}; uint8_t nr_w_buf = 1; uint8_t access_t = 1; buf_set_u32(address_buf, 0, 14, address); buf_set_u32(value_buf, 0, 32, value); retval = arm_jtag_scann(jtag_info, 0xf, TAP_IDLE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 32; fields[0].out_value = value_buf; fields[0].in_value = NULL; fields[1].num_bits = 1; fields[1].out_value = &access_t; fields[1].in_value = &access_t; fields[2].num_bits = 14; fields[2].out_value = address_buf; fields[2].in_value = NULL; fields[3].num_bits = 1; fields[3].out_value = &nr_w_buf; fields[3].in_value = NULL; jtag_add_dr_scan(jtag_info->tap, 4, fields, TAP_IDLE); long long then = timeval_ms(); for (;;) { /* rescan with NOP, to wait for the access to complete */ access_t = 0; nr_w_buf = 0; jtag_add_dr_scan(jtag_info->tap, 4, fields, TAP_IDLE); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (buf_get_u32(&access_t, 0, 1) == 1) break; /* 10ms timeout */ if ((timeval_ms()-then) > 10) { LOG_ERROR("cp15 write operation timed out"); return ERROR_FAIL; } } #ifdef _DEBUG_INSTRUCTION_EXECUTION_ LOG_DEBUG("addr: 0x%x value: %8.8x", address, value); #endif retval = arm_jtag_set_instr(jtag_info, 0xf, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int arm926ejs_mcr(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t value) { if (cpnum != 15) { LOG_ERROR("Only cp15 is supported"); return ERROR_FAIL; } return arm926ejs_cp15_write(target, op1, op2, CRn, CRm, value); } static int arm926ejs_examine_debug_reason(struct target *target) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct reg *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; int debug_reason; int retval; embeddedice_read_reg(dbg_stat); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; /* Method-Of-Entry (MOE) field */ debug_reason = buf_get_u32(dbg_stat->value, 6, 4); switch (debug_reason) { case 0: LOG_DEBUG("no *NEW* debug entry (?missed one?)"); /* ... since last restart or debug reset ... */ target->debug_reason = DBG_REASON_DBGRQ; break; case 1: LOG_DEBUG("breakpoint from EICE unit 0"); target->debug_reason = DBG_REASON_BREAKPOINT; break; case 2: LOG_DEBUG("breakpoint from EICE unit 1"); target->debug_reason = DBG_REASON_BREAKPOINT; break; case 3: LOG_DEBUG("soft breakpoint (BKPT instruction)"); target->debug_reason = DBG_REASON_BREAKPOINT; break; case 4: LOG_DEBUG("vector catch breakpoint"); target->debug_reason = DBG_REASON_BREAKPOINT; break; case 5: LOG_DEBUG("external breakpoint"); target->debug_reason = DBG_REASON_BREAKPOINT; break; case 6: LOG_DEBUG("watchpoint from EICE unit 0"); target->debug_reason = DBG_REASON_WATCHPOINT; break; case 7: LOG_DEBUG("watchpoint from EICE unit 1"); target->debug_reason = DBG_REASON_WATCHPOINT; break; case 8: LOG_DEBUG("external watchpoint"); target->debug_reason = DBG_REASON_WATCHPOINT; break; case 9: LOG_DEBUG("internal debug request"); target->debug_reason = DBG_REASON_DBGRQ; break; case 10: LOG_DEBUG("external debug request"); target->debug_reason = DBG_REASON_DBGRQ; break; case 11: LOG_DEBUG("debug re-entry from system speed access"); /* This is normal when connecting to something that's * already halted, or in some related code paths, but * otherwise is surprising (and presumably wrong). */ switch (target->debug_reason) { case DBG_REASON_DBGRQ: break; default: LOG_ERROR("unexpected -- debug re-entry"); /* FALLTHROUGH */ case DBG_REASON_UNDEFINED: target->debug_reason = DBG_REASON_DBGRQ; break; } break; case 12: /* FIX!!!! here be dragons!!! We need to fail here so * the target will interpreted as halted but we won't * try to talk to it right now... a resume + halt seems * to sync things up again. Please send an email to * openocd development mailing list if you have hardware * to donate to look into this problem.... */ LOG_WARNING("WARNING: mystery debug reason MOE = 0xc. Try issuing a resume + halt."); target->debug_reason = DBG_REASON_DBGRQ; break; default: LOG_WARNING("WARNING: unknown debug reason: 0x%x", debug_reason); /* Oh agony! should we interpret this as a halt request or * that the target stopped on it's own accord? */ target->debug_reason = DBG_REASON_DBGRQ; /* if we fail here, we won't talk to the target and it will * be reported to be in the halted state */ break; } return ERROR_OK; } static int arm926ejs_get_ttb(struct target *target, uint32_t *result) { struct arm926ejs_common *arm926ejs = target_to_arm926(target); int retval; uint32_t ttb = 0x0; retval = arm926ejs->read_cp15(target, 0, 0, 2, 0, &ttb); if (retval != ERROR_OK) return retval; *result = ttb; return ERROR_OK; } static int arm926ejs_disable_mmu_caches(struct target *target, int mmu, int d_u_cache, int i_cache) { struct arm926ejs_common *arm926ejs = target_to_arm926(target); uint32_t cp15_control; int retval; /* read cp15 control register */ retval = arm926ejs->read_cp15(target, 0, 0, 1, 0, &cp15_control); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (mmu) { /* invalidate TLB */ retval = arm926ejs->write_cp15(target, 0, 0, 8, 7, 0x0); if (retval != ERROR_OK) return retval; cp15_control &= ~0x1U; } if (d_u_cache) { uint32_t debug_override; /* read-modify-write CP15 debug override register * to enable "test and clean all" */ retval = arm926ejs->read_cp15(target, 0, 0, 15, 0, &debug_override); if (retval != ERROR_OK) return retval; debug_override |= 0x80000; retval = arm926ejs->write_cp15(target, 0, 0, 15, 0, debug_override); if (retval != ERROR_OK) return retval; /* clean and invalidate DCache */ retval = arm926ejs->write_cp15(target, 0, 0, 7, 5, 0x0); if (retval != ERROR_OK) return retval; /* write CP15 debug override register * to disable "test and clean all" */ debug_override &= ~0x80000; retval = arm926ejs->write_cp15(target, 0, 0, 15, 0, debug_override); if (retval != ERROR_OK) return retval; cp15_control &= ~0x4U; } if (i_cache) { /* invalidate ICache */ retval = arm926ejs->write_cp15(target, 0, 0, 7, 5, 0x0); if (retval != ERROR_OK) return retval; cp15_control &= ~0x1000U; } retval = arm926ejs->write_cp15(target, 0, 0, 1, 0, cp15_control); return retval; } static int arm926ejs_enable_mmu_caches(struct target *target, int mmu, int d_u_cache, int i_cache) { struct arm926ejs_common *arm926ejs = target_to_arm926(target); uint32_t cp15_control; int retval; /* read cp15 control register */ retval = arm926ejs->read_cp15(target, 0, 0, 1, 0, &cp15_control); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (mmu) cp15_control |= 0x1U; if (d_u_cache) cp15_control |= 0x4U; if (i_cache) cp15_control |= 0x1000U; retval = arm926ejs->write_cp15(target, 0, 0, 1, 0, cp15_control); return retval; } static int arm926ejs_post_debug_entry(struct target *target) { struct arm926ejs_common *arm926ejs = target_to_arm926(target); int retval; /* examine cp15 control reg */ retval = arm926ejs->read_cp15(target, 0, 0, 1, 0, &arm926ejs->cp15_control_reg); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; LOG_DEBUG("cp15_control_reg: %8.8" PRIx32 "", arm926ejs->cp15_control_reg); if (arm926ejs->armv4_5_mmu.armv4_5_cache.ctype == -1) { uint32_t cache_type_reg; /* identify caches */ retval = arm926ejs->read_cp15(target, 0, 1, 0, 0, &cache_type_reg); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; armv4_5_identify_cache(cache_type_reg, &arm926ejs->armv4_5_mmu.armv4_5_cache); } arm926ejs->armv4_5_mmu.mmu_enabled = (arm926ejs->cp15_control_reg & 0x1U) ? 1 : 0; arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (arm926ejs->cp15_control_reg & 0x4U) ? 1 : 0; arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled = (arm926ejs->cp15_control_reg & 0x1000U) ? 1 : 0; /* save i/d fault status and address register */ retval = arm926ejs->read_cp15(target, 0, 0, 5, 0, &arm926ejs->d_fsr); if (retval != ERROR_OK) return retval; retval = arm926ejs->read_cp15(target, 0, 1, 5, 0, &arm926ejs->i_fsr); if (retval != ERROR_OK) return retval; retval = arm926ejs->read_cp15(target, 0, 0, 6, 0, &arm926ejs->d_far); if (retval != ERROR_OK) return retval; LOG_DEBUG("D FSR: 0x%8.8" PRIx32 ", D FAR: 0x%8.8" PRIx32 ", I FSR: 0x%8.8" PRIx32 "", arm926ejs->d_fsr, arm926ejs->d_far, arm926ejs->i_fsr); uint32_t cache_dbg_ctrl; /* read-modify-write CP15 cache debug control register * to disable I/D-cache linefills and force WT */ retval = arm926ejs->read_cp15(target, 7, 0, 15, 0, &cache_dbg_ctrl); if (retval != ERROR_OK) return retval; cache_dbg_ctrl |= 0x7; retval = arm926ejs->write_cp15(target, 7, 0, 15, 0, cache_dbg_ctrl); return retval; } static void arm926ejs_pre_restore_context(struct target *target) { struct arm926ejs_common *arm926ejs = target_to_arm926(target); /* restore i/d fault status and address register */ arm926ejs->write_cp15(target, 0, 0, 5, 0, arm926ejs->d_fsr); arm926ejs->write_cp15(target, 0, 1, 5, 0, arm926ejs->i_fsr); arm926ejs->write_cp15(target, 0, 0, 6, 0, arm926ejs->d_far); uint32_t cache_dbg_ctrl; /* read-modify-write CP15 cache debug control register * to reenable I/D-cache linefills and disable WT */ arm926ejs->read_cp15(target, 7, 0, 15, 0, &cache_dbg_ctrl); cache_dbg_ctrl &= ~0x7; arm926ejs->write_cp15(target, 7, 0, 15, 0, cache_dbg_ctrl); } static const char arm926_not[] = "target is not an ARM926"; static int arm926ejs_verify_pointer(struct command_context *cmd_ctx, struct arm926ejs_common *arm926) { if (arm926->common_magic != ARM926EJS_COMMON_MAGIC) { command_print(cmd_ctx, arm926_not); return ERROR_TARGET_INVALID; } return ERROR_OK; } /** Logs summary of ARM926 state for a halted target. */ int arm926ejs_arch_state(struct target *target) { static const char *state[] = { "disabled", "enabled" }; struct arm926ejs_common *arm926ejs = target_to_arm926(target); if (arm926ejs->common_magic != ARM926EJS_COMMON_MAGIC) { LOG_ERROR("BUG: %s", arm926_not); return ERROR_TARGET_INVALID; } arm_arch_state(target); LOG_USER("MMU: %s, D-Cache: %s, I-Cache: %s", state[arm926ejs->armv4_5_mmu.mmu_enabled], state[arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled], state[arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled]); return ERROR_OK; } int arm926ejs_soft_reset_halt(struct target *target) { int retval = ERROR_OK; struct arm926ejs_common *arm926ejs = target_to_arm926(target); struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; struct reg *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; retval = target_halt(target); if (retval != ERROR_OK) return retval; long long then = timeval_ms(); int timeout; while (!(timeout = ((timeval_ms()-then) > 1000))) { if (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_DBGACK, 1) == 0) { embeddedice_read_reg(dbg_stat); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; } else break; if (debug_level >= 1) { /* do not eat all CPU, time out after 1 se*/ alive_sleep(100); } else keep_alive(); } if (timeout) { LOG_ERROR("Failed to halt CPU after 1 sec"); return ERROR_TARGET_TIMEOUT; } target->state = TARGET_HALTED; /* SVC, ARM state, IRQ and FIQ disabled */ uint32_t cpsr; cpsr = buf_get_u32(arm->cpsr->value, 0, 32); cpsr &= ~0xff; cpsr |= 0xd3; arm_set_cpsr(arm, cpsr); arm->cpsr->dirty = 1; /* start fetching from 0x0 */ buf_set_u32(arm->pc->value, 0, 32, 0x0); arm->pc->dirty = 1; arm->pc->valid = 1; retval = arm926ejs_disable_mmu_caches(target, 1, 1, 1); if (retval != ERROR_OK) return retval; arm926ejs->armv4_5_mmu.mmu_enabled = 0; arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0; arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0; return target_call_event_callbacks(target, TARGET_EVENT_HALTED); } /** Writes a buffer, in the specified word size, with current MMU settings. */ int arm926ejs_write_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { int retval; struct arm926ejs_common *arm926ejs = target_to_arm926(target); /* FIX!!!! this should be cleaned up and made much more general. The * plan is to write up and test on arm926ejs specifically and * then generalize and clean up afterwards. * * * Also it should be moved to the callbacks that handle breakpoints * specifically and not the generic memory write fn's. See XScale code. **/ if (arm926ejs->armv4_5_mmu.mmu_enabled && (count == 1) && ((size == 2) || (size == 4))) { /* special case the handling of single word writes to bypass MMU * to allow implementation of breakpoints in memory marked read only * by MMU */ if (arm926ejs->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled) { /* flush and invalidate data cache * * MCR p15,0,p,c7,c10,1 - clean cache line using virtual address * */ retval = arm926ejs->write_cp15(target, 0, 1, 7, 10, address&~0x3); if (retval != ERROR_OK) return retval; } uint32_t pa; retval = target->type->virt2phys(target, address, &pa); if (retval != ERROR_OK) return retval; /* write directly to physical memory bypassing any read only MMU bits, etc. */ retval = armv4_5_mmu_write_physical(target, &arm926ejs->armv4_5_mmu, pa, size, count, buffer); if (retval != ERROR_OK) return retval; } else { retval = arm7_9_write_memory(target, address, size, count, buffer); if (retval != ERROR_OK) return retval; } /* If ICache is enabled, we have to invalidate affected ICache lines * the DCache is forced to write-through, so we don't have to clean it here */ if (arm926ejs->armv4_5_mmu.armv4_5_cache.i_cache_enabled) { if (count <= 1) { /* invalidate ICache single entry with MVA */ arm926ejs->write_cp15(target, 0, 1, 7, 5, address); } else { /* invalidate ICache */ arm926ejs->write_cp15(target, 0, 0, 7, 5, address); } } return retval; } static int arm926ejs_write_phys_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct arm926ejs_common *arm926ejs = target_to_arm926(target); return armv4_5_mmu_write_physical(target, &arm926ejs->armv4_5_mmu, address, size, count, buffer); } static int arm926ejs_read_phys_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct arm926ejs_common *arm926ejs = target_to_arm926(target); return armv4_5_mmu_read_physical(target, &arm926ejs->armv4_5_mmu, address, size, count, buffer); } int arm926ejs_init_arch_info(struct target *target, struct arm926ejs_common *arm926ejs, struct jtag_tap *tap) { struct arm7_9_common *arm7_9 = &arm926ejs->arm7_9_common; arm7_9->arm.mrc = arm926ejs_mrc; arm7_9->arm.mcr = arm926ejs_mcr; /* initialize arm7/arm9 specific info (including armv4_5) */ arm9tdmi_init_arch_info(target, arm7_9, tap); arm926ejs->common_magic = ARM926EJS_COMMON_MAGIC; arm7_9->post_debug_entry = arm926ejs_post_debug_entry; arm7_9->pre_restore_context = arm926ejs_pre_restore_context; arm926ejs->read_cp15 = arm926ejs_cp15_read; arm926ejs->write_cp15 = arm926ejs_cp15_write; arm926ejs->armv4_5_mmu.armv4_5_cache.ctype = -1; arm926ejs->armv4_5_mmu.get_ttb = arm926ejs_get_ttb; arm926ejs->armv4_5_mmu.read_memory = arm7_9_read_memory; arm926ejs->armv4_5_mmu.write_memory = arm7_9_write_memory; arm926ejs->armv4_5_mmu.disable_mmu_caches = arm926ejs_disable_mmu_caches; arm926ejs->armv4_5_mmu.enable_mmu_caches = arm926ejs_enable_mmu_caches; arm926ejs->armv4_5_mmu.has_tiny_pages = 1; arm926ejs->armv4_5_mmu.mmu_enabled = 0; arm7_9->examine_debug_reason = arm926ejs_examine_debug_reason; /* The ARM926EJ-S implements the ARMv5TE architecture which * has the BKPT instruction, so we don't have to use a watchpoint comparator */ arm7_9->arm_bkpt = ARMV5_BKPT(0x0); arm7_9->thumb_bkpt = ARMV5_T_BKPT(0x0) & 0xffff; return ERROR_OK; } static int arm926ejs_target_create(struct target *target, Jim_Interp *interp) { struct arm926ejs_common *arm926ejs = calloc(1, sizeof(struct arm926ejs_common)); /* ARM9EJ-S core always reports 0x1 in Capture-IR */ target->tap->ir_capture_mask = 0x0f; return arm926ejs_init_arch_info(target, arm926ejs, target->tap); } COMMAND_HANDLER(arm926ejs_handle_cache_info_command) { int retval; struct target *target = get_current_target(CMD_CTX); struct arm926ejs_common *arm926ejs = target_to_arm926(target); retval = arm926ejs_verify_pointer(CMD_CTX, arm926ejs); if (retval != ERROR_OK) return retval; return armv4_5_handle_cache_info_command(CMD_CTX, &arm926ejs->armv4_5_mmu.armv4_5_cache); } static int arm926ejs_virt2phys(struct target *target, uint32_t virtual, uint32_t *physical) { uint32_t cb; struct arm926ejs_common *arm926ejs = target_to_arm926(target); uint32_t ret; int retval = armv4_5_mmu_translate_va(target, &arm926ejs->armv4_5_mmu, virtual, &cb, &ret); if (retval != ERROR_OK) return retval; *physical = ret; return ERROR_OK; } static int arm926ejs_mmu(struct target *target, int *enabled) { struct arm926ejs_common *arm926ejs = target_to_arm926(target); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_INVALID; } *enabled = arm926ejs->armv4_5_mmu.mmu_enabled; return ERROR_OK; } static const struct command_registration arm926ejs_exec_command_handlers[] = { { .name = "cache_info", .handler = arm926ejs_handle_cache_info_command, .mode = COMMAND_EXEC, .usage = "", .help = "display information about target caches", }, COMMAND_REGISTRATION_DONE }; const struct command_registration arm926ejs_command_handlers[] = { { .chain = arm9tdmi_command_handlers, }, { .name = "arm926ejs", .mode = COMMAND_ANY, .help = "arm926ejs command group", .usage = "", .chain = arm926ejs_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; /** Holds methods for ARM926 targets. */ struct target_type arm926ejs_target = { .name = "arm926ejs", .poll = arm7_9_poll, .arch_state = arm926ejs_arch_state, .target_request_data = arm7_9_target_request_data, .halt = arm7_9_halt, .resume = arm7_9_resume, .step = arm7_9_step, .assert_reset = arm7_9_assert_reset, .deassert_reset = arm7_9_deassert_reset, .soft_reset_halt = arm926ejs_soft_reset_halt, .get_gdb_reg_list = arm_get_gdb_reg_list, .read_memory = arm7_9_read_memory, .write_memory = arm926ejs_write_memory, .bulk_write_memory = arm7_9_bulk_write_memory, .checksum_memory = arm_checksum_memory, .blank_check_memory = arm_blank_check_memory, .run_algorithm = armv4_5_run_algorithm, .add_breakpoint = arm7_9_add_breakpoint, .remove_breakpoint = arm7_9_remove_breakpoint, .add_watchpoint = arm7_9_add_watchpoint, .remove_watchpoint = arm7_9_remove_watchpoint, .commands = arm926ejs_command_handlers, .target_create = arm926ejs_target_create, .init_target = arm9tdmi_init_target, .examine = arm7_9_examine, .check_reset = arm7_9_check_reset, .virt2phys = arm926ejs_virt2phys, .mmu = arm926ejs_mmu, .read_phys_memory = arm926ejs_read_phys_memory, .write_phys_memory = arm926ejs_write_phys_memory, }; openocd-0.7.0/src/target/dsp563xx.h0000644000175000001440000000444212134336410013715 00000000000000/*************************************************************************** * Copyright (C) 2009-2011 by Mathias Kuester * * mkdorg@users.sourceforge.net * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef DSP563XX_H #define DSP563XX_H #include #include #define DSP563XX_NUMCOREREGS 54 #define DSP563XX_NUMONCEREGS 25 struct mcu_jtag { struct jtag_tap *tap; }; struct dsp563xx_common { struct mcu_jtag jtag_info; struct reg_cache *core_cache; uint32_t core_regs[DSP563XX_NUMCOREREGS]; struct once_reg once_regs[DSP563XX_NUMONCEREGS]; /* register cache to processor synchronization */ int (*read_core_reg) (struct target *target, int num); int (*write_core_reg) (struct target *target, int num); }; struct dsp563xx_core_reg { uint32_t num; const char *name; uint32_t size; uint8_t eame; uint32_t instr_mask; struct target *target; struct dsp563xx_common *dsp563xx_common; }; static inline struct dsp563xx_common *target_to_dsp563xx(struct target *target) { return target->arch_info; } #endif /* DSP563XX_H */ openocd-0.7.0/src/target/armv7a.h0000644000175000001440000001232112137151331013501 00000000000000/*************************************************************************** * Copyright (C) 2009 by David Brownell * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef ARMV7A_H #define ARMV7A_H #include "arm_adi_v5.h" #include "arm.h" #include "armv4_5_mmu.h" #include "armv4_5_cache.h" #include "arm_dpm.h" enum { ARM_PC = 15, ARM_CPSR = 16 }; #define ARMV7_COMMON_MAGIC 0x0A450999 /* VA to PA translation operations opc2 values*/ #define V2PCWPR 0 #define V2PCWPW 1 #define V2PCWUR 2 #define V2PCWUW 3 #define V2POWPR 4 #define V2POWPW 5 #define V2POWUR 6 #define V2POWUW 7 /* L210/L220 cache controller support */ struct armv7a_l2x_cache { uint32_t base; uint32_t way; }; struct armv7a_cachesize { uint32_t level_num; /* cache dimensionning */ uint32_t linelen; uint32_t associativity; uint32_t nsets; uint32_t cachesize; /* info for set way operation on cache */ uint32_t index; uint32_t index_shift; uint32_t way; uint32_t way_shift; }; struct armv7a_cache_common { int ctype; struct armv7a_cachesize d_u_size; /* data cache */ struct armv7a_cachesize i_size; /* instruction cache */ int i_cache_enabled; int d_u_cache_enabled; /* l2 external unified cache if some */ void *l2_cache; int (*flush_all_data_cache)(struct target *target); int (*display_cache_info)(struct command_context *cmd_ctx, struct armv7a_cache_common *armv7a_cache); }; struct armv7a_mmu_common { /* following field mmu working way */ int32_t ttbr1_used; /* -1 not initialized, 0 no ttbr1 1 ttbr1 used and */ uint32_t ttbr0_mask;/* masked to be used */ uint32_t os_border; int (*read_physical_memory)(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer); struct armv7a_cache_common armv7a_cache; uint32_t mmu_enabled; }; struct armv7a_common { struct arm arm; int common_magic; struct reg_cache *core_cache; struct adiv5_dap dap; /* Core Debug Unit */ struct arm_dpm dpm; uint32_t debug_base; uint8_t debug_ap; uint8_t memory_ap; bool memory_ap_available; /* mdir */ uint8_t multi_processor_system; uint8_t cluster_id; uint8_t cpu_id; bool is_armv7r; /* cache specific to V7 Memory Management Unit compatible with v4_5*/ struct armv7a_mmu_common armv7a_mmu; int (*examine_debug_reason)(struct target *target); int (*post_debug_entry)(struct target *target); void (*pre_restore_context)(struct target *target); }; static inline struct armv7a_common * target_to_armv7a(struct target *target) { return container_of(target->arch_info, struct armv7a_common, arm); } /* register offsets from armv7a.debug_base */ /* See ARMv7a arch spec section C10.2 */ #define CPUDBG_DIDR 0x000 /* See ARMv7a arch spec section C10.3 */ #define CPUDBG_WFAR 0x018 /* PCSR at 0x084 -or- 0x0a0 -or- both ... based on flags in DIDR */ #define CPUDBG_DSCR 0x088 #define CPUDBG_DRCR 0x090 #define CPUDBG_PRCR 0x310 #define CPUDBG_PRSR 0x314 /* See ARMv7a arch spec section C10.4 */ #define CPUDBG_DTRRX 0x080 #define CPUDBG_ITR 0x084 #define CPUDBG_DTRTX 0x08c /* See ARMv7a arch spec section C10.5 */ #define CPUDBG_BVR_BASE 0x100 #define CPUDBG_BCR_BASE 0x140 #define CPUDBG_WVR_BASE 0x180 #define CPUDBG_WCR_BASE 0x1C0 #define CPUDBG_VCR 0x01C /* See ARMv7a arch spec section C10.6 */ #define CPUDBG_OSLAR 0x300 #define CPUDBG_OSLSR 0x304 #define CPUDBG_OSSRR 0x308 #define CPUDBG_ECR 0x024 /* See ARMv7a arch spec section C10.7 */ #define CPUDBG_DSCCR 0x028 /* See ARMv7a arch spec section C10.8 */ #define CPUDBG_AUTHSTATUS 0xFB8 int armv7a_arch_state(struct target *target); int armv7a_identify_cache(struct target *target); int armv7a_init_arch_info(struct target *target, struct armv7a_common *armv7a); int armv7a_mmu_translate_va_pa(struct target *target, uint32_t va, uint32_t *val, int meminfo); int armv7a_mmu_translate_va(struct target *target, uint32_t va, uint32_t *val); int armv7a_handle_cache_info_command(struct command_context *cmd_ctx, struct armv7a_cache_common *armv7a_cache); extern const struct command_registration armv7a_command_handlers[]; #endif /* ARMV4_5_H */ openocd-0.7.0/src/target/arm920t.c0000644000175000001440000013565712134336410013517 00000000000000 /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm920t.h" #include #include "target_type.h" #include "register.h" #include "arm_opcodes.h" /* * For information about the ARM920T, see ARM DDI 0151C especially * Chapter 9 about debug support, which shows how to manipulate each * of the different scan chains: * * 0 ... ARM920 signals, e.g. to rest of SOC (unused here) * 1 ... debugging; watchpoint and breakpoint status, etc; also * MMU and cache access in conjunction with scan chain 15 * 2 ... EmbeddedICE * 3 ... external boundary scan (SoC-specific, unused here) * 4 ... access to cache tag RAM * 6 ... ETM9 * 15 ... access coprocessor 15, "physical" or "interpreted" modes * "interpreted" works with a few actual MRC/MCR instructions * "physical" provides register-like behaviors. Section 9.6.7 * covers these details. * * The ARM922T is similar, but with smaller caches (8K each, vs 16K). */ #if 0 #define _DEBUG_INSTRUCTION_EXECUTION_ #endif /* Table 9-8 shows scan chain 15 format during physical access mode, using a * dedicated 6-bit address space (encoded in bits 33:38). Writes use one * JTAG scan, while reads use two. * * Table 9-9 lists the thirteen registers which support physical access. * ARM920T_CP15_PHYS_ADDR() constructs the 6-bit reg_addr parameter passed * to arm920t_read_cp15_physical() and arm920t_write_cp15_physical(). * * x == bit[38] * y == bits[37:34] * z == bit[33] */ #define ARM920T_CP15_PHYS_ADDR(x, y, z) ((x << 5) | (y << 1) << (z)) /* Registers supporting physical Read access (from table 9-9) */ #define CP15PHYS_CACHETYPE ARM920T_CP15_PHYS_ADDR(0, 0x0, 1) #define CP15PHYS_ICACHE_IDX ARM920T_CP15_PHYS_ADDR(1, 0xd, 1) #define CP15PHYS_DCACHE_IDX ARM920T_CP15_PHYS_ADDR(1, 0xe, 1) /* NOTE: several more registers support only physical read access */ /* Registers supporting physical Read/Write access (from table 9-9) */ #define CP15PHYS_CTRL ARM920T_CP15_PHYS_ADDR(0, 0x1, 0) #define CP15PHYS_PID ARM920T_CP15_PHYS_ADDR(0, 0xd, 0) #define CP15PHYS_TESTSTATE ARM920T_CP15_PHYS_ADDR(0, 0xf, 0) #define CP15PHYS_ICACHE ARM920T_CP15_PHYS_ADDR(1, 0x1, 1) #define CP15PHYS_DCACHE ARM920T_CP15_PHYS_ADDR(1, 0x2, 1) static int arm920t_read_cp15_physical(struct target *target, int reg_addr, uint32_t *value) { struct arm920t_common *arm920t = target_to_arm920(target); struct arm_jtag *jtag_info; struct scan_field fields[4]; uint8_t access_type_buf = 1; uint8_t reg_addr_buf = reg_addr & 0x3f; uint8_t nr_w_buf = 0; int retval; jtag_info = &arm920t->arm7_9_common.jtag_info; retval = arm_jtag_scann(jtag_info, 0xf, TAP_IDLE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 1; fields[0].out_value = &access_type_buf; fields[0].in_value = NULL; fields[1].num_bits = 32; fields[1].out_value = NULL; fields[1].in_value = NULL; fields[2].num_bits = 6; fields[2].out_value = ®_addr_buf; fields[2].in_value = NULL; fields[3].num_bits = 1; fields[3].out_value = &nr_w_buf; fields[3].in_value = NULL; jtag_add_dr_scan(jtag_info->tap, 4, fields, TAP_IDLE); fields[1].in_value = (uint8_t *)value; jtag_add_dr_scan(jtag_info->tap, 4, fields, TAP_IDLE); jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t)value); #ifdef _DEBUG_INSTRUCTION_EXECUTION_ jtag_execute_queue(); LOG_DEBUG("addr: 0x%x value: %8.8x", reg_addr, *value); #endif return ERROR_OK; } static int arm920t_write_cp15_physical(struct target *target, int reg_addr, uint32_t value) { struct arm920t_common *arm920t = target_to_arm920(target); struct arm_jtag *jtag_info; struct scan_field fields[4]; uint8_t access_type_buf = 1; uint8_t reg_addr_buf = reg_addr & 0x3f; uint8_t nr_w_buf = 1; uint8_t value_buf[4]; int retval; jtag_info = &arm920t->arm7_9_common.jtag_info; buf_set_u32(value_buf, 0, 32, value); retval = arm_jtag_scann(jtag_info, 0xf, TAP_IDLE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 1; fields[0].out_value = &access_type_buf; fields[0].in_value = NULL; fields[1].num_bits = 32; fields[1].out_value = value_buf; fields[1].in_value = NULL; fields[2].num_bits = 6; fields[2].out_value = ®_addr_buf; fields[2].in_value = NULL; fields[3].num_bits = 1; fields[3].out_value = &nr_w_buf; fields[3].in_value = NULL; jtag_add_dr_scan(jtag_info->tap, 4, fields, TAP_IDLE); #ifdef _DEBUG_INSTRUCTION_EXECUTION_ LOG_DEBUG("addr: 0x%x value: %8.8x", reg_addr, value); #endif return ERROR_OK; } /* See table 9-10 for scan chain 15 format during interpreted access mode. * If the TESTSTATE register is set for interpreted access, certain CP15 * MRC and MCR instructions may be executed through scan chain 15. * * Tables 9-11, 9-12, and 9-13 show which MRC and MCR instructions can be * executed using scan chain 15 interpreted mode. */ static int arm920t_execute_cp15(struct target *target, uint32_t cp15_opcode, uint32_t arm_opcode) { int retval; struct arm920t_common *arm920t = target_to_arm920(target); struct arm_jtag *jtag_info; struct scan_field fields[4]; uint8_t access_type_buf = 0; /* interpreted access */ uint8_t reg_addr_buf = 0x0; uint8_t nr_w_buf = 0; uint8_t cp15_opcode_buf[4]; jtag_info = &arm920t->arm7_9_common.jtag_info; retval = arm_jtag_scann(jtag_info, 0xf, TAP_IDLE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; buf_set_u32(cp15_opcode_buf, 0, 32, cp15_opcode); fields[0].num_bits = 1; fields[0].out_value = &access_type_buf; fields[0].in_value = NULL; fields[1].num_bits = 32; fields[1].out_value = cp15_opcode_buf; fields[1].in_value = NULL; fields[2].num_bits = 6; fields[2].out_value = ®_addr_buf; fields[2].in_value = NULL; fields[3].num_bits = 1; fields[3].out_value = &nr_w_buf; fields[3].in_value = NULL; jtag_add_dr_scan(jtag_info->tap, 4, fields, TAP_IDLE); arm9tdmi_clock_out(jtag_info, arm_opcode, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_NOP, 0, NULL, 1); retval = arm7_9_execute_sys_speed(target); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("failed executing JTAG queue"); return retval; } return ERROR_OK; } static int arm920t_read_cp15_interpreted(struct target *target, uint32_t cp15_opcode, uint32_t address, uint32_t *value) { struct arm *arm = target_to_arm(target); uint32_t *regs_p[1]; uint32_t regs[2]; uint32_t cp15c15 = 0x0; struct reg *r = arm->core_cache->reg_list; /* load address into R1 */ regs[1] = address; arm9tdmi_write_core_regs(target, 0x2, regs); /* read-modify-write CP15 test state register * to enable interpreted access mode */ arm920t_read_cp15_physical(target, CP15PHYS_TESTSTATE, &cp15c15); jtag_execute_queue(); cp15c15 |= 1; /* set interpret mode */ arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* execute CP15 instruction and ARM load (reading from coprocessor) */ arm920t_execute_cp15(target, cp15_opcode, ARMV4_5_LDR(0, 1)); /* disable interpreted access mode */ cp15c15 &= ~1U; /* clear interpret mode */ arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* retrieve value from R0 */ regs_p[0] = value; arm9tdmi_read_core_regs(target, 0x1, regs_p); jtag_execute_queue(); #ifdef _DEBUG_INSTRUCTION_EXECUTION_ LOG_DEBUG("cp15_opcode: %8.8x, address: %8.8x, value: %8.8x", cp15_opcode, address, *value); #endif if (!is_arm_mode(arm->core_mode)) { LOG_ERROR("not a valid arm core mode - communication failure?"); return ERROR_FAIL; } r[0].dirty = 1; r[1].dirty = 1; return ERROR_OK; } static int arm920t_write_cp15_interpreted(struct target *target, uint32_t cp15_opcode, uint32_t value, uint32_t address) { uint32_t cp15c15 = 0x0; struct arm *arm = target_to_arm(target); uint32_t regs[2]; struct reg *r = arm->core_cache->reg_list; /* load value, address into R0, R1 */ regs[0] = value; regs[1] = address; arm9tdmi_write_core_regs(target, 0x3, regs); /* read-modify-write CP15 test state register * to enable interpreted access mode */ arm920t_read_cp15_physical(target, CP15PHYS_TESTSTATE, &cp15c15); jtag_execute_queue(); cp15c15 |= 1; /* set interpret mode */ arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* execute CP15 instruction and ARM store (writing to coprocessor) */ arm920t_execute_cp15(target, cp15_opcode, ARMV4_5_STR(0, 1)); /* disable interpreted access mode */ cp15c15 &= ~1U; /* set interpret mode */ arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); #ifdef _DEBUG_INSTRUCTION_EXECUTION_ LOG_DEBUG("cp15_opcode: %8.8x, value: %8.8x, address: %8.8x", cp15_opcode, value, address); #endif if (!is_arm_mode(arm->core_mode)) { LOG_ERROR("not a valid arm core mode - communication failure?"); return ERROR_FAIL; } r[0].dirty = 1; r[1].dirty = 1; return ERROR_OK; } /* EXPORTED to FA256 */ int arm920t_get_ttb(struct target *target, uint32_t *result) { int retval; uint32_t ttb = 0x0; retval = arm920t_read_cp15_interpreted(target, /* FIXME use opcode macro */ 0xeebf0f51, 0x0, &ttb); if (retval != ERROR_OK) return retval; *result = ttb; return ERROR_OK; } /* EXPORTED to FA256 */ int arm920t_disable_mmu_caches(struct target *target, int mmu, int d_u_cache, int i_cache) { uint32_t cp15_control; int retval; /* read cp15 control register */ retval = arm920t_read_cp15_physical(target, CP15PHYS_CTRL, &cp15_control); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (mmu) cp15_control &= ~0x1U; if (d_u_cache) cp15_control &= ~0x4U; if (i_cache) cp15_control &= ~0x1000U; retval = arm920t_write_cp15_physical(target, CP15PHYS_CTRL, cp15_control); return retval; } /* EXPORTED to FA256 */ int arm920t_enable_mmu_caches(struct target *target, int mmu, int d_u_cache, int i_cache) { uint32_t cp15_control; int retval; /* read cp15 control register */ retval = arm920t_read_cp15_physical(target, CP15PHYS_CTRL, &cp15_control); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (mmu) cp15_control |= 0x1U; if (d_u_cache) cp15_control |= 0x4U; if (i_cache) cp15_control |= 0x1000U; retval = arm920t_write_cp15_physical(target, CP15PHYS_CTRL, cp15_control); return retval; } /* EXPORTED to FA256 */ int arm920t_post_debug_entry(struct target *target) { uint32_t cp15c15; struct arm920t_common *arm920t = target_to_arm920(target); int retval; /* examine cp15 control reg */ retval = arm920t_read_cp15_physical(target, CP15PHYS_CTRL, &arm920t->cp15_control_reg); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; LOG_DEBUG("cp15_control_reg: %8.8" PRIx32, arm920t->cp15_control_reg); if (arm920t->armv4_5_mmu.armv4_5_cache.ctype == -1) { uint32_t cache_type_reg; /* identify caches */ retval = arm920t_read_cp15_physical(target, CP15PHYS_CACHETYPE, &cache_type_reg); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; armv4_5_identify_cache(cache_type_reg, &arm920t->armv4_5_mmu.armv4_5_cache); } arm920t->armv4_5_mmu.mmu_enabled = (arm920t->cp15_control_reg & 0x1U) ? 1 : 0; arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (arm920t->cp15_control_reg & 0x4U) ? 1 : 0; arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = (arm920t->cp15_control_reg & 0x1000U) ? 1 : 0; /* save i/d fault status and address register * FIXME use opcode macros */ retval = arm920t_read_cp15_interpreted(target, 0xee150f10, 0x0, &arm920t->d_fsr); if (retval != ERROR_OK) return retval; retval = arm920t_read_cp15_interpreted(target, 0xee150f30, 0x0, &arm920t->i_fsr); if (retval != ERROR_OK) return retval; retval = arm920t_read_cp15_interpreted(target, 0xee160f10, 0x0, &arm920t->d_far); if (retval != ERROR_OK) return retval; retval = arm920t_read_cp15_interpreted(target, 0xee160f30, 0x0, &arm920t->i_far); if (retval != ERROR_OK) return retval; LOG_DEBUG("D FSR: 0x%8.8" PRIx32 ", D FAR: 0x%8.8" PRIx32 ", I FSR: 0x%8.8" PRIx32 ", I FAR: 0x%8.8" PRIx32, arm920t->d_fsr, arm920t->d_far, arm920t->i_fsr, arm920t->i_far); if (arm920t->preserve_cache) { /* read-modify-write CP15 test state register * to disable I/D-cache linefills */ retval = arm920t_read_cp15_physical(target, CP15PHYS_TESTSTATE, &cp15c15); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; cp15c15 |= 0x600; retval = arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); if (retval != ERROR_OK) return retval; } return ERROR_OK; } /* EXPORTED to FA256 */ void arm920t_pre_restore_context(struct target *target) { uint32_t cp15c15; struct arm920t_common *arm920t = target_to_arm920(target); /* restore i/d fault status and address register */ arm920t_write_cp15_interpreted(target, 0xee050f10, arm920t->d_fsr, 0x0); arm920t_write_cp15_interpreted(target, 0xee050f30, arm920t->i_fsr, 0x0); arm920t_write_cp15_interpreted(target, 0xee060f10, arm920t->d_far, 0x0); arm920t_write_cp15_interpreted(target, 0xee060f30, arm920t->i_far, 0x0); /* read-modify-write CP15 test state register * to reenable I/D-cache linefills */ if (arm920t->preserve_cache) { arm920t_read_cp15_physical(target, CP15PHYS_TESTSTATE, &cp15c15); jtag_execute_queue(); cp15c15 &= ~0x600U; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); } } static const char arm920_not[] = "target is not an ARM920"; static int arm920t_verify_pointer(struct command_context *cmd_ctx, struct arm920t_common *arm920t) { if (arm920t->common_magic != ARM920T_COMMON_MAGIC) { command_print(cmd_ctx, arm920_not); return ERROR_TARGET_INVALID; } return ERROR_OK; } /** Logs summary of ARM920 state for a halted target. */ int arm920t_arch_state(struct target *target) { static const char *state[] = { "disabled", "enabled" }; struct arm920t_common *arm920t = target_to_arm920(target); if (arm920t->common_magic != ARM920T_COMMON_MAGIC) { LOG_ERROR("BUG: %s", arm920_not); return ERROR_TARGET_INVALID; } arm_arch_state(target); LOG_USER("MMU: %s, D-Cache: %s, I-Cache: %s", state[arm920t->armv4_5_mmu.mmu_enabled], state[arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled], state[arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled]); return ERROR_OK; } static int arm920_mmu(struct target *target, int *enabled) { if (target->state != TARGET_HALTED) { LOG_ERROR("%s: target not halted", __func__); return ERROR_TARGET_INVALID; } *enabled = target_to_arm920(target)->armv4_5_mmu.mmu_enabled; return ERROR_OK; } static int arm920_virt2phys(struct target *target, uint32_t virt, uint32_t *phys) { uint32_t cb; struct arm920t_common *arm920t = target_to_arm920(target); uint32_t ret; int retval = armv4_5_mmu_translate_va(target, &arm920t->armv4_5_mmu, virt, &cb, &ret); if (retval != ERROR_OK) return retval; *phys = ret; return ERROR_OK; } /** Reads a buffer, in the specified word size, with current MMU settings. */ int arm920t_read_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) { int retval; retval = arm7_9_read_memory(target, address, size, count, buffer); return retval; } static int arm920t_read_phys_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct arm920t_common *arm920t = target_to_arm920(target); return armv4_5_mmu_read_physical(target, &arm920t->armv4_5_mmu, address, size, count, buffer); } static int arm920t_write_phys_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct arm920t_common *arm920t = target_to_arm920(target); return armv4_5_mmu_write_physical(target, &arm920t->armv4_5_mmu, address, size, count, buffer); } /** Writes a buffer, in the specified word size, with current MMU settings. */ int arm920t_write_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { int retval; const uint32_t cache_mask = ~0x1f; /* cache line size : 32 byte */ struct arm920t_common *arm920t = target_to_arm920(target); /* FIX!!!! this should be cleaned up and made much more general. The * plan is to write up and test on arm920t specifically and * then generalize and clean up afterwards. * * Also it should be moved to the callbacks that handle breakpoints * specifically and not the generic memory write fn's. See XScale code. */ if (arm920t->armv4_5_mmu.mmu_enabled && (count == 1) && ((size == 2) || (size == 4))) { /* special case the handling of single word writes to * bypass MMU, to allow implementation of breakpoints * in memory marked read only * by MMU */ uint32_t cb; uint32_t pa; /* * We need physical address and cb */ retval = armv4_5_mmu_translate_va(target, &arm920t->armv4_5_mmu, address, &cb, &pa); if (retval != ERROR_OK) return retval; if (arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled) { if (cb & 0x1) { LOG_DEBUG("D-Cache buffered, " "drain write buffer"); /* * Buffered ? * Drain write buffer - MCR p15,0,Rd,c7,c10,4 */ retval = arm920t_write_cp15_interpreted(target, ARMV4_5_MCR(15, 0, 0, 7, 10, 4), 0x0, 0); if (retval != ERROR_OK) return retval; } if (cb == 0x3) { /* * Write back memory ? -> clean cache * * There is no way to clean cache lines using * cp15 scan chain, so copy the full cache * line from cache to physical memory. */ uint8_t data[32]; LOG_DEBUG("D-Cache in 'write back' mode, " "flush cache line"); retval = target_read_memory(target, address & cache_mask, 1, sizeof(data), &data[0]); if (retval != ERROR_OK) return retval; retval = armv4_5_mmu_write_physical(target, &arm920t->armv4_5_mmu, pa & cache_mask, 1, sizeof(data), &data[0]); if (retval != ERROR_OK) return retval; } /* Cached ? */ if (cb & 0x2) { /* * Cached ? -> Invalidate data cache using MVA * * MCR p15,0,Rd,c7,c6,1 */ LOG_DEBUG("D-Cache enabled, " "invalidate cache line"); retval = arm920t_write_cp15_interpreted(target, ARMV4_5_MCR(15, 0, 0, 7, 6, 1), 0x0, address & cache_mask); if (retval != ERROR_OK) return retval; } } /* write directly to physical memory, * bypassing any read only MMU bits, etc. */ retval = armv4_5_mmu_write_physical(target, &arm920t->armv4_5_mmu, pa, size, count, buffer); if (retval != ERROR_OK) return retval; } else { retval = arm7_9_write_memory(target, address, size, count, buffer); if (retval != ERROR_OK) return retval; } /* If ICache is enabled, we have to invalidate affected ICache lines * the DCache is forced to write-through, * so we don't have to clean it here */ if (arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled) { if (count <= 1) { /* invalidate ICache single entry with MVA * mcr 15, 0, r0, cr7, cr5, {1} */ LOG_DEBUG("I-Cache enabled, " "invalidating affected I-Cache line"); retval = arm920t_write_cp15_interpreted(target, ARMV4_5_MCR(15, 0, 0, 7, 5, 1), 0x0, address & cache_mask); if (retval != ERROR_OK) return retval; } else { /* invalidate ICache * mcr 15, 0, r0, cr7, cr5, {0} */ retval = arm920t_write_cp15_interpreted(target, ARMV4_5_MCR(15, 0, 0, 7, 5, 0), 0x0, 0x0); if (retval != ERROR_OK) return retval; } } return ERROR_OK; } /* EXPORTED to FA256 */ int arm920t_soft_reset_halt(struct target *target) { int retval = ERROR_OK; struct arm920t_common *arm920t = target_to_arm920(target); struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; struct reg *dbg_stat = &arm7_9->eice_cache->reg_list[EICE_DBG_STAT]; retval = target_halt(target); if (retval != ERROR_OK) return retval; long long then = timeval_ms(); int timeout; while (!(timeout = ((timeval_ms()-then) > 1000))) { if (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_DBGACK, 1) == 0) { embeddedice_read_reg(dbg_stat); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; } else break; if (debug_level >= 3) { /* do not eat all CPU, time out after 1 se*/ alive_sleep(100); } else keep_alive(); } if (timeout) { LOG_ERROR("Failed to halt CPU after 1 sec"); return ERROR_TARGET_TIMEOUT; } target->state = TARGET_HALTED; /* SVC, ARM state, IRQ and FIQ disabled */ uint32_t cpsr; cpsr = buf_get_u32(arm->cpsr->value, 0, 32); cpsr &= ~0xff; cpsr |= 0xd3; arm_set_cpsr(arm, cpsr); arm->cpsr->dirty = 1; /* start fetching from 0x0 */ buf_set_u32(arm->pc->value, 0, 32, 0x0); arm->pc->dirty = 1; arm->pc->valid = 1; arm920t_disable_mmu_caches(target, 1, 1, 1); arm920t->armv4_5_mmu.mmu_enabled = 0; arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0; arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0; return target_call_event_callbacks(target, TARGET_EVENT_HALTED); } /* FIXME remove forward decls */ static int arm920t_mrc(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t *value); static int arm920t_mcr(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t value); static int arm920t_init_arch_info(struct target *target, struct arm920t_common *arm920t, struct jtag_tap *tap) { struct arm7_9_common *arm7_9 = &arm920t->arm7_9_common; arm7_9->arm.mrc = arm920t_mrc; arm7_9->arm.mcr = arm920t_mcr; /* initialize arm7/arm9 specific info (including armv4_5) */ arm9tdmi_init_arch_info(target, arm7_9, tap); arm920t->common_magic = ARM920T_COMMON_MAGIC; arm7_9->post_debug_entry = arm920t_post_debug_entry; arm7_9->pre_restore_context = arm920t_pre_restore_context; arm920t->armv4_5_mmu.armv4_5_cache.ctype = -1; arm920t->armv4_5_mmu.get_ttb = arm920t_get_ttb; arm920t->armv4_5_mmu.read_memory = arm7_9_read_memory; arm920t->armv4_5_mmu.write_memory = arm7_9_write_memory; arm920t->armv4_5_mmu.disable_mmu_caches = arm920t_disable_mmu_caches; arm920t->armv4_5_mmu.enable_mmu_caches = arm920t_enable_mmu_caches; arm920t->armv4_5_mmu.has_tiny_pages = 1; arm920t->armv4_5_mmu.mmu_enabled = 0; /* disabling linefills leads to lockups, so keep them enabled for now * this doesn't affect correctness, but might affect timing issues, if * important data is evicted from the cache during the debug session * */ arm920t->preserve_cache = 0; /* override hw single-step capability from ARM9TDMI */ arm7_9->has_single_step = 1; return ERROR_OK; } static int arm920t_target_create(struct target *target, Jim_Interp *interp) { struct arm920t_common *arm920t; arm920t = calloc(1, sizeof(struct arm920t_common)); return arm920t_init_arch_info(target, arm920t, target->tap); } COMMAND_HANDLER(arm920t_handle_read_cache_command) { int retval = ERROR_OK; struct target *target = get_current_target(CMD_CTX); struct arm920t_common *arm920t = target_to_arm920(target); struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; uint32_t cp15c15; uint32_t cp15_ctrl, cp15_ctrl_saved; uint32_t regs[16]; uint32_t *regs_p[16]; uint32_t C15_C_D_Ind, C15_C_I_Ind; int i; FILE *output; int segment, index_t; struct reg *r; retval = arm920t_verify_pointer(CMD_CTX, arm920t); if (retval != ERROR_OK) return retval; if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; output = fopen(CMD_ARGV[0], "w"); if (output == NULL) { LOG_DEBUG("error opening cache content file"); return ERROR_OK; } for (i = 0; i < 16; i++) regs_p[i] = ®s[i]; /* disable MMU and Caches */ arm920t_read_cp15_physical(target, CP15PHYS_CTRL, &cp15_ctrl); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; cp15_ctrl_saved = cp15_ctrl; cp15_ctrl &= ~(ARMV4_5_MMU_ENABLED | ARMV4_5_D_U_CACHE_ENABLED | ARMV4_5_I_CACHE_ENABLED); arm920t_write_cp15_physical(target, CP15PHYS_CTRL, cp15_ctrl); /* read CP15 test state register */ arm920t_read_cp15_physical(target, CP15PHYS_TESTSTATE, &cp15c15); jtag_execute_queue(); /* read DCache content */ fprintf(output, "DCache:\n"); /* go through segments 0 to nsets (8 on ARM920T, 4 on ARM922T) */ for (segment = 0; segment < arm920t->armv4_5_mmu.armv4_5_cache.d_u_size.nsets; segment++) { fprintf(output, "\nsegment: %i\n----------", segment); /* Ra: r0 = SBZ(31:8):segment(7:5):SBZ(4:0) */ regs[0] = 0x0 | (segment << 5); arm9tdmi_write_core_regs(target, 0x1, regs); /* set interpret mode */ cp15c15 |= 0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* D CAM Read, loads current victim into C15.C.D.Ind */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 2, 0, 15, 6, 2), ARMV4_5_LDR(1, 0)); /* read current victim */ arm920t_read_cp15_physical(target, CP15PHYS_DCACHE_IDX, &C15_C_D_Ind); /* clear interpret mode */ cp15c15 &= ~0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); for (index_t = 0; index_t < 64; index_t++) { /* Ra: * r0 = index(31:26):SBZ(25:8):segment(7:5):SBZ(4:0) */ regs[0] = 0x0 | (segment << 5) | (index_t << 26); arm9tdmi_write_core_regs(target, 0x1, regs); /* set interpret mode */ cp15c15 |= 0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* Write DCache victim */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 0, 0, 9, 1, 0), ARMV4_5_LDR(1, 0)); /* Read D RAM */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 2, 0, 15, 10, 2), ARMV4_5_LDMIA(0, 0x1fe, 0, 0)); /* Read D CAM */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 2, 0, 15, 6, 2), ARMV4_5_LDR(9, 0)); /* clear interpret mode */ cp15c15 &= ~0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* read D RAM and CAM content */ arm9tdmi_read_core_regs(target, 0x3fe, regs_p); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; /* mask LFSR[6] */ regs[9] &= 0xfffffffe; fprintf(output, "\nsegment: %i, index: %i, CAM: 0x%8.8" PRIx32 ", content (%s):\n", segment, index_t, regs[9], (regs[9] & 0x10) ? "valid" : "invalid"); for (i = 1; i < 9; i++) { fprintf(output, "%i: 0x%8.8" PRIx32 "\n", i-1, regs[i]); } } /* Ra: r0 = index(31:26):SBZ(25:8):segment(7:5):SBZ(4:0) */ regs[0] = 0x0 | (segment << 5) | (C15_C_D_Ind << 26); arm9tdmi_write_core_regs(target, 0x1, regs); /* set interpret mode */ cp15c15 |= 0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* Write DCache victim */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 0, 0, 9, 1, 0), ARMV4_5_LDR(1, 0)); /* clear interpret mode */ cp15c15 &= ~0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); } /* read ICache content */ fprintf(output, "ICache:\n"); /* go through segments 0 to nsets (8 on ARM920T, 4 on ARM922T) */ for (segment = 0; segment < arm920t->armv4_5_mmu.armv4_5_cache.d_u_size.nsets; segment++) { fprintf(output, "segment: %i\n----------", segment); /* Ra: r0 = SBZ(31:8):segment(7:5):SBZ(4:0) */ regs[0] = 0x0 | (segment << 5); arm9tdmi_write_core_regs(target, 0x1, regs); /* set interpret mode */ cp15c15 |= 0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* I CAM Read, loads current victim into C15.C.I.Ind */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 2, 0, 15, 5, 2), ARMV4_5_LDR(1, 0)); /* read current victim */ arm920t_read_cp15_physical(target, CP15PHYS_ICACHE_IDX, &C15_C_I_Ind); /* clear interpret mode */ cp15c15 &= ~0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); for (index_t = 0; index_t < 64; index_t++) { /* Ra: * r0 = index(31:26):SBZ(25:8):segment(7:5):SBZ(4:0) */ regs[0] = 0x0 | (segment << 5) | (index_t << 26); arm9tdmi_write_core_regs(target, 0x1, regs); /* set interpret mode */ cp15c15 |= 0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* Write ICache victim */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 0, 0, 9, 1, 1), ARMV4_5_LDR(1, 0)); /* Read I RAM */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 2, 0, 15, 9, 2), ARMV4_5_LDMIA(0, 0x1fe, 0, 0)); /* Read I CAM */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 2, 0, 15, 5, 2), ARMV4_5_LDR(9, 0)); /* clear interpret mode */ cp15c15 &= ~0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* read I RAM and CAM content */ arm9tdmi_read_core_regs(target, 0x3fe, regs_p); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; /* mask LFSR[6] */ regs[9] &= 0xfffffffe; fprintf(output, "\nsegment: %i, index: %i, " "CAM: 0x%8.8" PRIx32 ", content (%s):\n", segment, index_t, regs[9], (regs[9] & 0x10) ? "valid" : "invalid"); for (i = 1; i < 9; i++) { fprintf(output, "%i: 0x%8.8" PRIx32 "\n", i-1, regs[i]); } } /* Ra: r0 = index(31:26):SBZ(25:8):segment(7:5):SBZ(4:0) */ regs[0] = 0x0 | (segment << 5) | (C15_C_D_Ind << 26); arm9tdmi_write_core_regs(target, 0x1, regs); /* set interpret mode */ cp15c15 |= 0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* Write ICache victim */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 0, 0, 9, 1, 1), ARMV4_5_LDR(1, 0)); /* clear interpret mode */ cp15c15 &= ~0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); } /* restore CP15 MMU and Cache settings */ arm920t_write_cp15_physical(target, CP15PHYS_CTRL, cp15_ctrl_saved); command_print(CMD_CTX, "cache content successfully output to %s", CMD_ARGV[0]); fclose(output); if (!is_arm_mode(arm->core_mode)) { LOG_ERROR("not a valid arm core mode - communication failure?"); return ERROR_FAIL; } /* force writeback of the valid data */ r = arm->core_cache->reg_list; r[0].dirty = r[0].valid; r[1].dirty = r[1].valid; r[2].dirty = r[2].valid; r[3].dirty = r[3].valid; r[4].dirty = r[4].valid; r[5].dirty = r[5].valid; r[6].dirty = r[6].valid; r[7].dirty = r[7].valid; r = arm_reg_current(arm, 8); r->dirty = r->valid; r = arm_reg_current(arm, 9); r->dirty = r->valid; return ERROR_OK; } COMMAND_HANDLER(arm920t_handle_read_mmu_command) { int retval = ERROR_OK; struct target *target = get_current_target(CMD_CTX); struct arm920t_common *arm920t = target_to_arm920(target); struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; uint32_t cp15c15; uint32_t cp15_ctrl, cp15_ctrl_saved; uint32_t regs[16]; uint32_t *regs_p[16]; int i; FILE *output; uint32_t Dlockdown, Ilockdown; struct arm920t_tlb_entry d_tlb[64], i_tlb[64]; int victim; struct reg *r; retval = arm920t_verify_pointer(CMD_CTX, arm920t); if (retval != ERROR_OK) return retval; if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; output = fopen(CMD_ARGV[0], "w"); if (output == NULL) { LOG_DEBUG("error opening mmu content file"); return ERROR_OK; } for (i = 0; i < 16; i++) regs_p[i] = ®s[i]; /* disable MMU and Caches */ arm920t_read_cp15_physical(target, CP15PHYS_CTRL, &cp15_ctrl); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; cp15_ctrl_saved = cp15_ctrl; cp15_ctrl &= ~(ARMV4_5_MMU_ENABLED | ARMV4_5_D_U_CACHE_ENABLED | ARMV4_5_I_CACHE_ENABLED); arm920t_write_cp15_physical(target, CP15PHYS_CTRL, cp15_ctrl); /* read CP15 test state register */ arm920t_read_cp15_physical(target, CP15PHYS_TESTSTATE, &cp15c15); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; /* prepare reading D TLB content * */ /* set interpret mode */ cp15c15 |= 0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* Read D TLB lockdown */ arm920t_execute_cp15(target, ARMV4_5_MRC(15, 0, 0, 10, 0, 0), ARMV4_5_LDR(1, 0)); /* clear interpret mode */ cp15c15 &= ~0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* read D TLB lockdown stored to r1 */ arm9tdmi_read_core_regs(target, 0x2, regs_p); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; Dlockdown = regs[1]; for (victim = 0; victim < 64; victim += 8) { /* new lockdown value: base[31:26]:victim[25:20]:SBZ[19:1]:p[0] * base remains unchanged, victim goes through entries 0 to 63 */ regs[1] = (Dlockdown & 0xfc000000) | (victim << 20); arm9tdmi_write_core_regs(target, 0x2, regs); /* set interpret mode */ cp15c15 |= 0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* Write D TLB lockdown */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 0, 0, 10, 0, 0), ARMV4_5_STR(1, 0)); /* Read D TLB CAM */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 4, 0, 15, 6, 4), ARMV4_5_LDMIA(0, 0x3fc, 0, 0)); /* clear interpret mode */ cp15c15 &= ~0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* read D TLB CAM content stored to r2-r9 */ arm9tdmi_read_core_regs(target, 0x3fc, regs_p); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; for (i = 0; i < 8; i++) d_tlb[victim + i].cam = regs[i + 2]; } for (victim = 0; victim < 64; victim++) { /* new lockdown value: base[31:26]:victim[25:20]:SBZ[19:1]:p[0] * base remains unchanged, victim goes through entries 0 to 63 */ regs[1] = (Dlockdown & 0xfc000000) | (victim << 20); arm9tdmi_write_core_regs(target, 0x2, regs); /* set interpret mode */ cp15c15 |= 0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* Write D TLB lockdown */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 0, 0, 10, 0, 0), ARMV4_5_STR(1, 0)); /* Read D TLB RAM1 */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 4, 0, 15, 10, 4), ARMV4_5_LDR(2, 0)); /* Read D TLB RAM2 */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 4, 0, 15, 2, 5), ARMV4_5_LDR(3, 0)); /* clear interpret mode */ cp15c15 &= ~0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* read D TLB RAM content stored to r2 and r3 */ arm9tdmi_read_core_regs(target, 0xc, regs_p); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; d_tlb[victim].ram1 = regs[2]; d_tlb[victim].ram2 = regs[3]; } /* restore D TLB lockdown */ regs[1] = Dlockdown; arm9tdmi_write_core_regs(target, 0x2, regs); /* Write D TLB lockdown */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 0, 0, 10, 0, 0), ARMV4_5_STR(1, 0)); /* prepare reading I TLB content * */ /* set interpret mode */ cp15c15 |= 0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* Read I TLB lockdown */ arm920t_execute_cp15(target, ARMV4_5_MRC(15, 0, 0, 10, 0, 1), ARMV4_5_LDR(1, 0)); /* clear interpret mode */ cp15c15 &= ~0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* read I TLB lockdown stored to r1 */ arm9tdmi_read_core_regs(target, 0x2, regs_p); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; Ilockdown = regs[1]; for (victim = 0; victim < 64; victim += 8) { /* new lockdown value: base[31:26]:victim[25:20]:SBZ[19:1]:p[0] * base remains unchanged, victim goes through entries 0 to 63 */ regs[1] = (Ilockdown & 0xfc000000) | (victim << 20); arm9tdmi_write_core_regs(target, 0x2, regs); /* set interpret mode */ cp15c15 |= 0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* Write I TLB lockdown */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 0, 0, 10, 0, 1), ARMV4_5_STR(1, 0)); /* Read I TLB CAM */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 4, 0, 15, 5, 4), ARMV4_5_LDMIA(0, 0x3fc, 0, 0)); /* clear interpret mode */ cp15c15 &= ~0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* read I TLB CAM content stored to r2-r9 */ arm9tdmi_read_core_regs(target, 0x3fc, regs_p); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; for (i = 0; i < 8; i++) i_tlb[i + victim].cam = regs[i + 2]; } for (victim = 0; victim < 64; victim++) { /* new lockdown value: base[31:26]:victim[25:20]:SBZ[19:1]:p[0] * base remains unchanged, victim goes through entries 0 to 63 */ regs[1] = (Dlockdown & 0xfc000000) | (victim << 20); arm9tdmi_write_core_regs(target, 0x2, regs); /* set interpret mode */ cp15c15 |= 0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* Write I TLB lockdown */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 0, 0, 10, 0, 1), ARMV4_5_STR(1, 0)); /* Read I TLB RAM1 */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 4, 0, 15, 9, 4), ARMV4_5_LDR(2, 0)); /* Read I TLB RAM2 */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 4, 0, 15, 1, 5), ARMV4_5_LDR(3, 0)); /* clear interpret mode */ cp15c15 &= ~0x1; arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* read I TLB RAM content stored to r2 and r3 */ arm9tdmi_read_core_regs(target, 0xc, regs_p); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; i_tlb[victim].ram1 = regs[2]; i_tlb[victim].ram2 = regs[3]; } /* restore I TLB lockdown */ regs[1] = Ilockdown; arm9tdmi_write_core_regs(target, 0x2, regs); /* Write I TLB lockdown */ arm920t_execute_cp15(target, ARMV4_5_MCR(15, 0, 0, 10, 0, 1), ARMV4_5_STR(1, 0)); /* restore CP15 MMU and Cache settings */ arm920t_write_cp15_physical(target, CP15PHYS_CTRL, cp15_ctrl_saved); /* output data to file */ fprintf(output, "D TLB content:\n"); for (i = 0; i < 64; i++) { fprintf(output, "%i: 0x%8.8" PRIx32 " 0x%8.8" PRIx32 " 0x%8.8" PRIx32 " %s\n", i, d_tlb[i].cam, d_tlb[i].ram1, d_tlb[i].ram2, (d_tlb[i].cam & 0x20) ? "(valid)" : "(invalid)"); } fprintf(output, "\n\nI TLB content:\n"); for (i = 0; i < 64; i++) { fprintf(output, "%i: 0x%8.8" PRIx32 " 0x%8.8" PRIx32 " 0x%8.8" PRIx32 " %s\n", i, i_tlb[i].cam, i_tlb[i].ram1, i_tlb[i].ram2, (i_tlb[i].cam & 0x20) ? "(valid)" : "(invalid)"); } command_print(CMD_CTX, "mmu content successfully output to %s", CMD_ARGV[0]); fclose(output); if (!is_arm_mode(arm->core_mode)) { LOG_ERROR("not a valid arm core mode - communication failure?"); return ERROR_FAIL; } /* force writeback of the valid data */ r = arm->core_cache->reg_list; r[0].dirty = r[0].valid; r[1].dirty = r[1].valid; r[2].dirty = r[2].valid; r[3].dirty = r[3].valid; r[4].dirty = r[4].valid; r[5].dirty = r[5].valid; r[6].dirty = r[6].valid; r[7].dirty = r[7].valid; r = arm_reg_current(arm, 8); r->dirty = r->valid; r = arm_reg_current(arm, 9); r->dirty = r->valid; return ERROR_OK; } COMMAND_HANDLER(arm920t_handle_cp15_command) { int retval; struct target *target = get_current_target(CMD_CTX); struct arm920t_common *arm920t = target_to_arm920(target); retval = arm920t_verify_pointer(CMD_CTX, arm920t); if (retval != ERROR_OK) return retval; if (target->state != TARGET_HALTED) { command_print(CMD_CTX, "target must be stopped for " "\"%s\" command", CMD_NAME); return ERROR_OK; } /* one argument, read a register. * two arguments, write it. */ if (CMD_ARGC >= 1) { int address; COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], address); if (CMD_ARGC == 1) { uint32_t value; retval = arm920t_read_cp15_physical(target, address, &value); if (retval != ERROR_OK) { command_print(CMD_CTX, "couldn't access reg %i", address); return ERROR_OK; } retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; command_print(CMD_CTX, "%i: %8.8" PRIx32, address, value); } else if (CMD_ARGC == 2) { uint32_t value; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); retval = arm920t_write_cp15_physical(target, address, value); if (retval != ERROR_OK) { command_print(CMD_CTX, "couldn't access reg %i", address); /* REVISIT why lie? "return retval"? */ return ERROR_OK; } command_print(CMD_CTX, "%i: %8.8" PRIx32, address, value); } } return ERROR_OK; } COMMAND_HANDLER(arm920t_handle_cp15i_command) { int retval; struct target *target = get_current_target(CMD_CTX); struct arm920t_common *arm920t = target_to_arm920(target); retval = arm920t_verify_pointer(CMD_CTX, arm920t); if (retval != ERROR_OK) return retval; if (target->state != TARGET_HALTED) { command_print(CMD_CTX, "target must be stopped for " "\"%s\" command", CMD_NAME); return ERROR_OK; } /* one argument, read a register. * two arguments, write it. */ if (CMD_ARGC >= 1) { uint32_t opcode; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], opcode); if (CMD_ARGC == 1) { uint32_t value; retval = arm920t_read_cp15_interpreted(target, opcode, 0x0, &value); if (retval != ERROR_OK) { command_print(CMD_CTX, "couldn't execute %8.8" PRIx32, opcode); /* REVISIT why lie? "return retval"? */ return ERROR_OK; } command_print(CMD_CTX, "%8.8" PRIx32 ": %8.8" PRIx32, opcode, value); } else if (CMD_ARGC == 2) { uint32_t value; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); retval = arm920t_write_cp15_interpreted(target, opcode, value, 0); if (retval != ERROR_OK) { command_print(CMD_CTX, "couldn't execute %8.8" PRIx32, opcode); /* REVISIT why lie? "return retval"? */ return ERROR_OK; } command_print(CMD_CTX, "%8.8" PRIx32 ": %8.8" PRIx32, opcode, value); } else if (CMD_ARGC == 3) { uint32_t value; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); uint32_t address; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], address); retval = arm920t_write_cp15_interpreted(target, opcode, value, address); if (retval != ERROR_OK) { command_print(CMD_CTX, "couldn't execute %8.8" PRIx32, opcode); /* REVISIT why lie? "return retval"? */ return ERROR_OK; } command_print(CMD_CTX, "%8.8" PRIx32 ": %8.8" PRIx32 " %8.8" PRIx32, opcode, value, address); } } else return ERROR_COMMAND_SYNTAX_ERROR; return ERROR_OK; } COMMAND_HANDLER(arm920t_handle_cache_info_command) { int retval; struct target *target = get_current_target(CMD_CTX); struct arm920t_common *arm920t = target_to_arm920(target); retval = arm920t_verify_pointer(CMD_CTX, arm920t); if (retval != ERROR_OK) return retval; return armv4_5_handle_cache_info_command(CMD_CTX, &arm920t->armv4_5_mmu.armv4_5_cache); } static int arm920t_mrc(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t *value) { if (cpnum != 15) { LOG_ERROR("Only cp15 is supported"); return ERROR_FAIL; } /* read "to" r0 */ return arm920t_read_cp15_interpreted(target, ARMV4_5_MRC(cpnum, op1, 0, CRn, CRm, op2), 0, value); } static int arm920t_mcr(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t value) { if (cpnum != 15) { LOG_ERROR("Only cp15 is supported"); return ERROR_FAIL; } /* write "from" r0 */ return arm920t_write_cp15_interpreted(target, ARMV4_5_MCR(cpnum, op1, 0, CRn, CRm, op2), 0, value); } static const struct command_registration arm920t_exec_command_handlers[] = { { .name = "cp15", .handler = arm920t_handle_cp15_command, .mode = COMMAND_EXEC, .help = "display/modify cp15 register", .usage = "regnum [value]", }, { .name = "cp15i", .handler = arm920t_handle_cp15i_command, .mode = COMMAND_EXEC, /* prefer using less error-prone "arm mcr" or "arm mrc" */ .help = "display/modify cp15 register using ARM opcode" " (DEPRECATED)", .usage = "instruction [value [address]]", }, { .name = "cache_info", .handler = arm920t_handle_cache_info_command, .mode = COMMAND_EXEC, .usage = "", .help = "display information about target caches", }, { .name = "read_cache", .handler = arm920t_handle_read_cache_command, .mode = COMMAND_EXEC, .help = "dump I/D cache content to file", .usage = "filename", }, { .name = "read_mmu", .handler = arm920t_handle_read_mmu_command, .mode = COMMAND_EXEC, .help = "dump I/D mmu content to file", .usage = "filename", }, COMMAND_REGISTRATION_DONE }; const struct command_registration arm920t_command_handlers[] = { { .chain = arm9tdmi_command_handlers, }, { .name = "arm920t", .mode = COMMAND_ANY, .help = "arm920t command group", .usage = "", .chain = arm920t_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; /** Holds methods for ARM920 targets. */ struct target_type arm920t_target = { .name = "arm920t", .poll = arm7_9_poll, .arch_state = arm920t_arch_state, .target_request_data = arm7_9_target_request_data, .halt = arm7_9_halt, .resume = arm7_9_resume, .step = arm7_9_step, .assert_reset = arm7_9_assert_reset, .deassert_reset = arm7_9_deassert_reset, .soft_reset_halt = arm920t_soft_reset_halt, .get_gdb_reg_list = arm_get_gdb_reg_list, .read_memory = arm920t_read_memory, .write_memory = arm920t_write_memory, .read_phys_memory = arm920t_read_phys_memory, .write_phys_memory = arm920t_write_phys_memory, .mmu = arm920_mmu, .virt2phys = arm920_virt2phys, .bulk_write_memory = arm7_9_bulk_write_memory, .checksum_memory = arm_checksum_memory, .blank_check_memory = arm_blank_check_memory, .run_algorithm = armv4_5_run_algorithm, .add_breakpoint = arm7_9_add_breakpoint, .remove_breakpoint = arm7_9_remove_breakpoint, .add_watchpoint = arm7_9_add_watchpoint, .remove_watchpoint = arm7_9_remove_watchpoint, .commands = arm920t_command_handlers, .target_create = arm920t_target_create, .init_target = arm9tdmi_init_target, .examine = arm7_9_examine, .check_reset = arm7_9_check_reset, }; openocd-0.7.0/src/target/avr32_regs.c0000644000175000001440000000656512134336410014271 00000000000000/*************************************************************************** * Copyright (C) 2010 by Oleksandr Tymoshenko * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "target.h" #include "jtag/jtag.h" #include "avr32_jtag.h" #include "avr32_regs.h" static int avr32_jtag_read_reg(struct avr32_jtag *jtag_info, int reg, uint32_t *val) { int retval; uint32_t dcsr; retval = avr32_jtag_exec(jtag_info, MTDR(AVR32_OCDREG_DCCPU, reg)); if (retval != ERROR_OK) return retval; do { retval = avr32_jtag_nexus_read(jtag_info, AVR32_OCDREG_DCSR, &dcsr); if (retval != ERROR_OK) return retval; } while (!(dcsr & OCDREG_DCSR_CPUD)); retval = avr32_jtag_nexus_read(jtag_info, AVR32_OCDREG_DCCPU, val); return retval; } static int avr32_jtag_write_reg(struct avr32_jtag *jtag_info, int reg, uint32_t val) { int retval; uint32_t dcsr; /* Restore Status reg */ retval = avr32_jtag_nexus_write(jtag_info, AVR32_OCDREG_DCEMU, val); if (retval != ERROR_OK) return retval; retval = avr32_jtag_exec(jtag_info, MFDR(reg, AVR32_OCDREG_DCEMU)); if (retval != ERROR_OK) return retval; do { retval = avr32_jtag_nexus_read(jtag_info, AVR32_OCDREG_DCSR, &dcsr); } while (!(dcsr & OCDREG_DCSR_EMUD) && (retval == ERROR_OK)); return retval; } int avr32_jtag_read_regs(struct avr32_jtag *jtag_info, uint32_t *regs) { int i, retval; /* read core registers */ for (i = 0; i < AVR32NUMCOREREGS - 1; i++) avr32_jtag_read_reg(jtag_info, i, regs + i); /* read status register */ retval = avr32_jtag_exec(jtag_info, MFSR(0, 0)); if (retval != ERROR_OK) return retval; retval = avr32_jtag_read_reg(jtag_info, 0, regs + AVR32_REG_SR); return retval; } int avr32_jtag_write_regs(struct avr32_jtag *jtag_info, uint32_t *regs) { int i, retval; retval = avr32_jtag_write_reg(jtag_info, 0, regs[AVR32_REG_SR]); if (retval != ERROR_OK) return retval; /* Restore Status reg */ retval = avr32_jtag_exec(jtag_info, MTSR(0, 0)); if (retval != ERROR_OK) return retval; /* * And now the rest of registers */ for (i = 0; i < AVR32NUMCOREREGS - 1; i++) avr32_jtag_write_reg(jtag_info, i, regs[i]); return ERROR_OK; } openocd-0.7.0/src/target/mips_ejtag.h0000644000175000001440000001355012137151331014433 00000000000000/*************************************************************************** * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2008 by David T.L. Wong * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef MIPS_EJTAG #define MIPS_EJTAG #include /* tap instructions */ #define EJTAG_INST_IDCODE 0x01 #define EJTAG_INST_IMPCODE 0x03 #define EJTAG_INST_ADDRESS 0x08 #define EJTAG_INST_DATA 0x09 #define EJTAG_INST_CONTROL 0x0A #define EJTAG_INST_ALL 0x0B #define EJTAG_INST_EJTAGBOOT 0x0C #define EJTAG_INST_NORMALBOOT 0x0D #define EJTAG_INST_FASTDATA 0x0E #define EJTAG_INST_TCBCONTROLA 0x10 #define EJTAG_INST_TCBCONTROLB 0x11 #define EJTAG_INST_TCBDATA 0x12 #define EJTAG_INST_BYPASS 0xFF /* microchip PIC32MX specific instructions */ #define MTAP_SW_MTAP 0x04 #define MTAP_SW_ETAP 0x05 #define MTAP_COMMAND 0x07 /* microchip specific cmds */ #define MCHP_ASERT_RST 0xd1 #define MCHP_DE_ASSERT_RST 0xd0 #define MCHP_ERASE 0xfc #define MCHP_STATUS 0x00 /* ejtag control register bits ECR */ #define EJTAG_CTRL_TOF (1 << 1) #define EJTAG_CTRL_TIF (1 << 2) #define EJTAG_CTRL_BRKST (1 << 3) #define EJTAG_CTRL_DLOCK (1 << 5) #define EJTAG_CTRL_DRWN (1 << 9) #define EJTAG_CTRL_DERR (1 << 10) #define EJTAG_CTRL_DSTRT (1 << 11) #define EJTAG_CTRL_JTAGBRK (1 << 12) #define EJTAG_CTRL_SETDEV (1 << 14) #define EJTAG_CTRL_PROBEN (1 << 15) #define EJTAG_CTRL_PRRST (1 << 16) #define EJTAG_CTRL_DMAACC (1 << 17) #define EJTAG_CTRL_PRACC (1 << 18) #define EJTAG_CTRL_PRNW (1 << 19) #define EJTAG_CTRL_PERRST (1 << 20) #define EJTAG_CTRL_SYNC (1 << 23) #define EJTAG_CTRL_DNM (1 << 28) #define EJTAG_CTRL_ROCC (1 << 31) /* Debug Register (CP0 Register 23, Select 0) */ #define EJTAG_DEBUG_DSS (1 << 0) #define EJTAG_DEBUG_DBP (1 << 1) #define EJTAG_DEBUG_DDBL (1 << 2) #define EJTAG_DEBUG_DDBS (1 << 3) #define EJTAG_DEBUG_DIB (1 << 4) #define EJTAG_DEBUG_DINT (1 << 5) #define EJTAG_DEBUG_OFFLINE (1 << 7) #define EJTAG_DEBUG_SST (1 << 8) #define EJTAG_DEBUG_NOSST (1 << 9) #define EJTAG_DEBUG_DDBLIMPR (1 << 18) #define EJTAG_DEBUG_DDBSIMPR (1 << 19) #define EJTAG_DEBUG_IEXI (1 << 20) #define EJTAG_DEBUG_DBUSEP (1 << 21) #define EJTAG_DEBUG_CACHEEP (1 << 22) #define EJTAG_DEBUG_MCHECKP (1 << 23) #define EJTAG_DEBUG_IBUSEP (1 << 24) #define EJTAG_DEBUG_COUNTDM (1 << 25) #define EJTAG_DEBUG_HALT (1 << 26) #define EJTAG_DEBUG_DOZE (1 << 27) #define EJTAG_DEBUG_LSNM (1 << 28) #define EJTAG_DEBUG_NODCR (1 << 29) #define EJTAG_DEBUG_DM (1 << 30) #define EJTAG_DEBUG_DBD (1 << 31) /* implementaion register bits */ #define EJTAG_IMP_R3K (1 << 28) #define EJTAG_IMP_DINT (1 << 24) #define EJTAG_IMP_NODMA (1 << 14) #define EJTAG_IMP_MIPS16 (1 << 16) #define EJTAG_DCR_MIPS64 (1 << 0) /* Debug Control Register DCR */ #define EJTAG_DCR 0xFF300000 #define EJTAG_DCR_ENM (1 << 29) #define EJTAG_DCR_DB (1 << 17) #define EJTAG_DCR_IB (1 << 16) #define EJTAG_DCR_INTE (1 << 4) /* breakpoint support */ #define EJTAG_IBS 0xFF301000 #define EJTAG_IBA1 0xFF301100 #define EJTAG_DBS 0xFF302000 #define EJTAG_DBA1 0xFF302100 #define EJTAG_DBCn_NOSB (1 << 13) #define EJTAG_DBCn_NOLB (1 << 12) #define EJTAG_DBCn_BLM_MASK 0xff #define EJTAG_DBCn_BLM_SHIFT 4 #define EJTAG_DBCn_BE (1 << 0) struct mips_ejtag { struct jtag_tap *tap; uint32_t impcode; uint32_t idcode; uint32_t ejtag_ctrl; int fast_access_save; uint32_t reg8; uint32_t reg9; unsigned scan_delay; int mode; }; void mips_ejtag_set_instr(struct mips_ejtag *ejtag_info, int new_instr); int mips_ejtag_enter_debug(struct mips_ejtag *ejtag_info); int mips_ejtag_exit_debug(struct mips_ejtag *ejtag_info); int mips_ejtag_get_idcode(struct mips_ejtag *ejtag_info, uint32_t *idcode); void mips_ejtag_add_scan_96(struct mips_ejtag *ejtag_info, uint32_t ctrl, uint32_t data, uint8_t *in_scan_buf); void mips_ejtag_drscan_32_out(struct mips_ejtag *ejtag_info, uint32_t data); int mips_ejtag_drscan_32(struct mips_ejtag *ejtag_info, uint32_t *data); void mips_ejtag_drscan_8_out(struct mips_ejtag *ejtag_info, uint8_t data); int mips_ejtag_drscan_8(struct mips_ejtag *ejtag_info, uint32_t *data); int mips_ejtag_fastdata_scan(struct mips_ejtag *ejtag_info, int write_t, uint32_t *data); int mips_ejtag_init(struct mips_ejtag *ejtag_info); int mips_ejtag_config_step(struct mips_ejtag *ejtag_info, int enable_step); static inline void mips_le_to_h_u32(jtag_callback_data_t arg) { uint8_t *in = (uint8_t *)arg; *((uint32_t *)arg) = le_to_h_u32(in); } #endif /* MIPS_EJTAG */ openocd-0.7.0/src/target/mips32_pracc.h0000644000175000001440000001174412137151331014601 00000000000000/*************************************************************************** * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2008 by David T.L. Wong * * * * Copyright (C) 2011 by Drasko DRASKOVIC * * drasko.draskovic@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef MIPS32_PRACC_H #define MIPS32_PRACC_H #include #include #define MIPS32_PRACC_FASTDATA_AREA 0xFF200000 #define MIPS32_PRACC_BASE_ADDR 0xFF200000 #define MIPS32_PRACC_FASTDATA_SIZE 16 #define MIPS32_PRACC_TEXT 0xFF200200 #define MIPS32_PRACC_STACK 0xFF204000 #define MIPS32_PRACC_PARAM_IN 0xFF201000 #define MIPS32_PRACC_PARAM_IN_SIZE 0x1000 #define MIPS32_PRACC_PARAM_OUT (MIPS32_PRACC_PARAM_IN + MIPS32_PRACC_PARAM_IN_SIZE) #define MIPS32_PRACC_PARAM_OUT_SIZE 0x1000 #define PRACC_UPPER_BASE_ADDR (MIPS32_PRACC_BASE_ADDR >> 16) #define PRACC_TEXT_OFFSET (MIPS32_PRACC_TEXT - MIPS32_PRACC_BASE_ADDR) #define PRACC_IN_OFFSET (MIPS32_PRACC_PARAM_IN - MIPS32_PRACC_BASE_ADDR) #define PRACC_OUT_OFFSET (MIPS32_PRACC_PARAM_OUT - MIPS32_PRACC_BASE_ADDR) #define PRACC_STACK_OFFSET (MIPS32_PRACC_STACK - MIPS32_PRACC_BASE_ADDR) #define MIPS32_FASTDATA_HANDLER_SIZE 0x80 #define UPPER16(uint32_t) (uint32_t >> 16) #define LOWER16(uint32_t) (uint32_t & 0xFFFF) #define NEG16(v) (((~(v)) + 1) & 0xFFFF) /*#define NEG18(v) (((~(v)) + 1) & 0x3FFFF)*/ struct pracc_queue_info { int retval; const int max_code; int code_count; int store_count; uint32_t *pracc_list; /* Code and store addresses */ }; void pracc_queue_init(struct pracc_queue_info *ctx); void pracc_add(struct pracc_queue_info *ctx, uint32_t addr, uint32_t instr); void pracc_queue_free(struct pracc_queue_info *ctx); int mips32_pracc_queue_exec(struct mips_ejtag *ejtag_info, struct pracc_queue_info *ctx, uint32_t *buf); int mips32_pracc_read_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, void *buf); int mips32_pracc_write_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, void *buf); int mips32_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, struct working_area *source, int write_t, uint32_t addr, int count, uint32_t *buf); int mips32_pracc_read_regs(struct mips_ejtag *ejtag_info, uint32_t *regs); int mips32_pracc_write_regs(struct mips_ejtag *ejtag_info, uint32_t *regs); int mips32_pracc_exec(struct mips_ejtag *ejtag_info, int code_len, const uint32_t *code, int num_param_in, uint32_t *param_in, int num_param_out, uint32_t *param_out, int cycle); /** * \b mips32_cp0_read * * Simulates mfc0 ASM instruction (Move From C0), * i.e. implements copro C0 Register read. * * @param[in] ejtag_info * @param[in] val Storage to hold read value * @param[in] cp0_reg Number of copro C0 register we want to read * @param[in] cp0_sel Select for the given C0 register * * @return ERROR_OK on Sucess, ERROR_FAIL otherwise */ int mips32_cp0_read(struct mips_ejtag *ejtag_info, uint32_t *val, uint32_t cp0_reg, uint32_t cp0_sel); /** * \b mips32_cp0_write * * Simulates mtc0 ASM instruction (Move To C0), * i.e. implements copro C0 Register read. * * @param[in] ejtag_info * @param[in] val Value to be written * @param[in] cp0_reg Number of copro C0 register we want to write to * @param[in] cp0_sel Select for the given C0 register * * @return ERROR_OK on Sucess, ERROR_FAIL otherwise */ int mips32_cp0_write(struct mips_ejtag *ejtag_info, uint32_t val, uint32_t cp0_reg, uint32_t cp0_sel); #endif openocd-0.7.0/src/target/arm_semihosting.h0000644000175000001440000000305712134336410015502 00000000000000/*************************************************************************** * Copyright (C) 2009 by Marvell Technology Group Ltd. * * Written by Nicolas Pitre * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef ARM_SEMIHOSTING_H #define ARM_SEMIHOSTING_H int arm_semihosting(struct target *target, int *retval); #endif openocd-0.7.0/src/target/armv4_5_mmu.h0000644000175000001440000000530712134336410014445 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef ARMV4_5_MMU_H #define ARMV4_5_MMU_H #include "armv4_5_cache.h" struct target; struct armv4_5_mmu_common { int (*get_ttb)(struct target *target, uint32_t *result); int (*read_memory)(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer); int (*write_memory)(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer); int (*disable_mmu_caches)(struct target *target, int mmu, int d_u_cache, int i_cache); int (*enable_mmu_caches)(struct target *target, int mmu, int d_u_cache, int i_cache); struct armv4_5_cache_common armv4_5_cache; int has_tiny_pages; int mmu_enabled; }; int armv4_5_mmu_translate_va(struct target *target, struct armv4_5_mmu_common *armv4_5_mmu, uint32_t va, uint32_t *cb, uint32_t *val); int armv4_5_mmu_read_physical(struct target *target, struct armv4_5_mmu_common *armv4_5_mmu, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer); int armv4_5_mmu_write_physical(struct target *target, struct armv4_5_mmu_common *armv4_5_mmu, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer); enum { ARMV4_5_MMU_ENABLED = 0x1, ARMV4_5_ALIGNMENT_CHECK = 0x2, ARMV4_5_MMU_S_BIT = 0x100, ARMV4_5_MMU_R_BIT = 0x200 }; #endif /* ARMV4_5_MMU_H */ openocd-0.7.0/src/target/etm.c0000644000175000001440000016120212134336410013067 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm.h" #include "etm.h" #include "etb.h" #include "image.h" #include "arm_disassembler.h" #include "register.h" #include "etm_dummy.h" #if BUILD_OOCD_TRACE == 1 #include "oocd_trace.h" #endif /* * ARM "Embedded Trace Macrocell" (ETM) support -- direct JTAG access. * * ETM modules collect instruction and/or data trace information, compress * it, and transfer it to a debugging host through either a (buffered) trace * port (often a 38-pin Mictor connector) or an Embedded Trace Buffer (ETB). * * There are several generations of these modules. Original versions have * JTAG access through a dedicated scan chain. Recent versions have added * access via coprocessor instructions, memory addressing, and the ARM Debug * Interface v5 (ADIv5); and phased out direct JTAG access. * * This code supports up to the ETMv1.3 architecture, as seen in ETM9 and * most common ARM9 systems. Note: "CoreSight ETM9" implements ETMv3.2, * implying non-JTAG connectivity options. * * Relevant documentation includes: * ARM DDI 0157G ... ETM9 (r2p2) Technical Reference Manual * ARM DDI 0315B ... CoreSight ETM9 (r0p1) Technical Reference Manual * ARM IHI 0014O ... Embedded Trace Macrocell, Architecture Specification */ enum { RO, /* read/only */ WO, /* write/only */ RW, /* read/write */ }; struct etm_reg_info { uint8_t addr; uint8_t size; /* low-N of 32 bits */ uint8_t mode; /* RO, WO, RW */ uint8_t bcd_vers; /* 1.0, 2.0, etc */ char *name; }; /* * Registers 0..0x7f are JTAG-addressable using scanchain 6. * (Or on some processors, through coprocessor operations.) * Newer versions of ETM make some W/O registers R/W, and * provide definitions for some previously-unused bits. */ /* core registers used to version/configure the ETM */ static const struct etm_reg_info etm_core[] = { /* NOTE: we "know" the order here ... */ { ETM_CONFIG, 32, RO, 0x10, "ETM_config", }, { ETM_ID, 32, RO, 0x20, "ETM_id", }, }; /* basic registers that are always there given the right ETM version */ static const struct etm_reg_info etm_basic[] = { /* ETM Trace Registers */ { ETM_CTRL, 32, RW, 0x10, "ETM_ctrl", }, { ETM_TRIG_EVENT, 17, WO, 0x10, "ETM_trig_event", }, { ETM_ASIC_CTRL, 8, WO, 0x10, "ETM_asic_ctrl", }, { ETM_STATUS, 3, RO, 0x11, "ETM_status", }, { ETM_SYS_CONFIG, 9, RO, 0x12, "ETM_sys_config", }, /* TraceEnable configuration */ { ETM_TRACE_RESOURCE_CTRL, 32, WO, 0x12, "ETM_trace_resource_ctrl", }, { ETM_TRACE_EN_CTRL2, 16, WO, 0x12, "ETM_trace_en_ctrl2", }, { ETM_TRACE_EN_EVENT, 17, WO, 0x10, "ETM_trace_en_event", }, { ETM_TRACE_EN_CTRL1, 26, WO, 0x10, "ETM_trace_en_ctrl1", }, /* ViewData configuration (data trace) */ { ETM_VIEWDATA_EVENT, 17, WO, 0x10, "ETM_viewdata_event", }, { ETM_VIEWDATA_CTRL1, 32, WO, 0x10, "ETM_viewdata_ctrl1", }, { ETM_VIEWDATA_CTRL2, 32, WO, 0x10, "ETM_viewdata_ctrl2", }, { ETM_VIEWDATA_CTRL3, 17, WO, 0x10, "ETM_viewdata_ctrl3", }, /* REVISIT exclude VIEWDATA_CTRL2 when it's not there */ { 0x78, 12, WO, 0x20, "ETM_sync_freq", }, { 0x7a, 22, RO, 0x31, "ETM_config_code_ext", }, { 0x7b, 32, WO, 0x31, "ETM_ext_input_select", }, { 0x7c, 32, WO, 0x34, "ETM_trace_start_stop", }, { 0x7d, 8, WO, 0x34, "ETM_behavior_control", }, }; static const struct etm_reg_info etm_fifofull[] = { /* FIFOFULL configuration */ { ETM_FIFOFULL_REGION, 25, WO, 0x10, "ETM_fifofull_region", }, { ETM_FIFOFULL_LEVEL, 8, WO, 0x10, "ETM_fifofull_level", }, }; static const struct etm_reg_info etm_addr_comp[] = { /* Address comparator register pairs */ #define ADDR_COMPARATOR(i) \ { ETM_ADDR_COMPARATOR_VALUE + (i) - 1, 32, WO, 0x10, \ "ETM_addr_" #i "_comparator_value", }, \ { ETM_ADDR_ACCESS_TYPE + (i) - 1, 7, WO, 0x10, \ "ETM_addr_" #i "_access_type", } ADDR_COMPARATOR(1), ADDR_COMPARATOR(2), ADDR_COMPARATOR(3), ADDR_COMPARATOR(4), ADDR_COMPARATOR(5), ADDR_COMPARATOR(6), ADDR_COMPARATOR(7), ADDR_COMPARATOR(8), ADDR_COMPARATOR(9), ADDR_COMPARATOR(10), ADDR_COMPARATOR(11), ADDR_COMPARATOR(12), ADDR_COMPARATOR(13), ADDR_COMPARATOR(14), ADDR_COMPARATOR(15), ADDR_COMPARATOR(16), #undef ADDR_COMPARATOR }; static const struct etm_reg_info etm_data_comp[] = { /* Data Value Comparators (NOTE: odd addresses are reserved) */ #define DATA_COMPARATOR(i) \ { ETM_DATA_COMPARATOR_VALUE + 2*(i) - 1, 32, WO, 0x10, \ "ETM_data_" #i "_comparator_value", }, \ { ETM_DATA_COMPARATOR_MASK + 2*(i) - 1, 32, WO, 0x10, \ "ETM_data_" #i "_comparator_mask", } DATA_COMPARATOR(1), DATA_COMPARATOR(2), DATA_COMPARATOR(3), DATA_COMPARATOR(4), DATA_COMPARATOR(5), DATA_COMPARATOR(6), DATA_COMPARATOR(7), DATA_COMPARATOR(8), #undef DATA_COMPARATOR }; static const struct etm_reg_info etm_counters[] = { #define ETM_COUNTER(i) \ { ETM_COUNTER_RELOAD_VALUE + (i) - 1, 16, WO, 0x10, \ "ETM_counter_" #i "_reload_value", }, \ { ETM_COUNTER_ENABLE + (i) - 1, 18, WO, 0x10, \ "ETM_counter_" #i "_enable", }, \ { ETM_COUNTER_RELOAD_EVENT + (i) - 1, 17, WO, 0x10, \ "ETM_counter_" #i "_reload_event", }, \ { ETM_COUNTER_VALUE + (i) - 1, 16, RO, 0x10, \ "ETM_counter_" #i "_value", } ETM_COUNTER(1), ETM_COUNTER(2), ETM_COUNTER(3), ETM_COUNTER(4), #undef ETM_COUNTER }; static const struct etm_reg_info etm_sequencer[] = { #define ETM_SEQ(i) \ { ETM_SEQUENCER_EVENT + (i), 17, WO, 0x10, \ "ETM_sequencer_event" #i, } ETM_SEQ(0), /* 1->2 */ ETM_SEQ(1), /* 2->1 */ ETM_SEQ(2), /* 2->3 */ ETM_SEQ(3), /* 3->1 */ ETM_SEQ(4), /* 3->2 */ ETM_SEQ(5), /* 1->3 */ #undef ETM_SEQ /* 0x66 reserved */ { ETM_SEQUENCER_STATE, 2, RO, 0x10, "ETM_sequencer_state", }, }; static const struct etm_reg_info etm_outputs[] = { #define ETM_OUTPUT(i) \ { ETM_EXTERNAL_OUTPUT + (i) - 1, 17, WO, 0x10, \ "ETM_external_output" #i, } ETM_OUTPUT(1), ETM_OUTPUT(2), ETM_OUTPUT(3), ETM_OUTPUT(4), #undef ETM_OUTPUT }; #if 0 /* registers from 0x6c..0x7f were added after ETMv1.3 */ /* Context ID Comparators */ { 0x6c, 32, RO, 0x20, "ETM_contextid_comparator_value1", } { 0x6d, 32, RO, 0x20, "ETM_contextid_comparator_value2", } { 0x6e, 32, RO, 0x20, "ETM_contextid_comparator_value3", } { 0x6f, 32, RO, 0x20, "ETM_contextid_comparator_mask", } #endif static int etm_get_reg(struct reg *reg); static int etm_read_reg_w_check(struct reg *reg, uint8_t *check_value, uint8_t *check_mask); static int etm_register_user_commands(struct command_context *cmd_ctx); static int etm_set_reg_w_exec(struct reg *reg, uint8_t *buf); static int etm_write_reg(struct reg *reg, uint32_t value); static const struct reg_arch_type etm_scan6_type = { .get = etm_get_reg, .set = etm_set_reg_w_exec, }; /* Look up register by ID ... most ETM instances only * support a subset of the possible registers. */ static struct reg *etm_reg_lookup(struct etm_context *etm_ctx, unsigned id) { struct reg_cache *cache = etm_ctx->reg_cache; unsigned i; for (i = 0; i < cache->num_regs; i++) { struct etm_reg *reg = cache->reg_list[i].arch_info; if (reg->reg_info->addr == id) return &cache->reg_list[i]; } /* caller asking for nonexistent register is a bug! * REVISIT say which of the N targets was involved */ LOG_ERROR("ETM: register 0x%02x not available", id); return NULL; } static void etm_reg_add(unsigned bcd_vers, struct arm_jtag *jtag_info, struct reg_cache *cache, struct etm_reg *ereg, const struct etm_reg_info *r, unsigned nreg) { struct reg *reg = cache->reg_list; reg += cache->num_regs; ereg += cache->num_regs; /* add up to "nreg" registers from "r", if supported by this * version of the ETM, to the specified cache. */ for (; nreg--; r++) { /* this ETM may be too old to have some registers */ if (r->bcd_vers > bcd_vers) continue; reg->name = r->name; reg->size = r->size; reg->value = &ereg->value; reg->arch_info = ereg; reg->type = &etm_scan6_type; reg++; cache->num_regs++; ereg->reg_info = r; ereg->jtag_info = jtag_info; ereg++; } } struct reg_cache *etm_build_reg_cache(struct target *target, struct arm_jtag *jtag_info, struct etm_context *etm_ctx) { struct reg_cache *reg_cache = malloc(sizeof(struct reg_cache)); struct reg *reg_list = NULL; struct etm_reg *arch_info = NULL; unsigned bcd_vers, config; /* the actual registers are kept in two arrays */ reg_list = calloc(128, sizeof(struct reg)); arch_info = calloc(128, sizeof(struct etm_reg)); /* fill in values for the reg cache */ reg_cache->name = "etm registers"; reg_cache->next = NULL; reg_cache->reg_list = reg_list; reg_cache->num_regs = 0; /* add ETM_CONFIG, then parse its values to see * which other registers exist in this ETM */ etm_reg_add(0x10, jtag_info, reg_cache, arch_info, etm_core, 1); etm_get_reg(reg_list); etm_ctx->config = buf_get_u32((void *)&arch_info->value, 0, 32); config = etm_ctx->config; /* figure ETM version then add base registers */ if (config & (1 << 31)) { LOG_WARNING("ETMv2+ support is incomplete"); /* REVISIT more registers may exist; they may now be * readable; more register bits have defined meanings; * don't presume trace start/stop support is present; * and include any context ID comparator registers. */ etm_reg_add(0x20, jtag_info, reg_cache, arch_info, etm_core + 1, 1); etm_get_reg(reg_list + 1); etm_ctx->id = buf_get_u32( (void *)&arch_info[1].value, 0, 32); LOG_DEBUG("ETM ID: %08x", (unsigned) etm_ctx->id); bcd_vers = 0x10 + (((etm_ctx->id) >> 4) & 0xff); } else { switch (config >> 28) { case 7: case 5: case 3: bcd_vers = 0x13; break; case 4: case 2: bcd_vers = 0x12; break; case 1: bcd_vers = 0x11; break; case 0: bcd_vers = 0x10; break; default: LOG_WARNING("Bad ETMv1 protocol %d", config >> 28); goto fail; } } etm_ctx->bcd_vers = bcd_vers; LOG_INFO("ETM v%d.%d", bcd_vers >> 4, bcd_vers & 0xf); etm_reg_add(bcd_vers, jtag_info, reg_cache, arch_info, etm_basic, ARRAY_SIZE(etm_basic)); /* address and data comparators; counters; outputs */ etm_reg_add(bcd_vers, jtag_info, reg_cache, arch_info, etm_addr_comp, 4 * (0x0f & (config >> 0))); etm_reg_add(bcd_vers, jtag_info, reg_cache, arch_info, etm_data_comp, 2 * (0x0f & (config >> 4))); etm_reg_add(bcd_vers, jtag_info, reg_cache, arch_info, etm_counters, 4 * (0x07 & (config >> 13))); etm_reg_add(bcd_vers, jtag_info, reg_cache, arch_info, etm_outputs, (0x07 & (config >> 20))); /* FIFOFULL presence is optional * REVISIT for ETMv1.2 and later, don't bother adding this * unless ETM_SYS_CONFIG says it's also *supported* ... */ if (config & (1 << 23)) etm_reg_add(bcd_vers, jtag_info, reg_cache, arch_info, etm_fifofull, ARRAY_SIZE(etm_fifofull)); /* sequencer is optional (for state-dependant triggering) */ if (config & (1 << 16)) etm_reg_add(bcd_vers, jtag_info, reg_cache, arch_info, etm_sequencer, ARRAY_SIZE(etm_sequencer)); /* REVISIT could realloc and likely save half the memory * in the two chunks we allocated... */ /* the ETM might have an ETB connected */ if (strcmp(etm_ctx->capture_driver->name, "etb") == 0) { struct etb *etb = etm_ctx->capture_driver_priv; if (!etb) { LOG_ERROR("etb selected as etm capture driver, but no ETB configured"); goto fail; } reg_cache->next = etb_build_reg_cache(etb); etb->reg_cache = reg_cache->next; } etm_ctx->reg_cache = reg_cache; return reg_cache; fail: free(reg_cache); free(reg_list); free(arch_info); return NULL; } static int etm_read_reg(struct reg *reg) { return etm_read_reg_w_check(reg, NULL, NULL); } static int etm_store_reg(struct reg *reg) { return etm_write_reg(reg, buf_get_u32(reg->value, 0, reg->size)); } int etm_setup(struct target *target) { int retval; uint32_t etm_ctrl_value; struct arm *arm = target_to_arm(target); struct etm_context *etm_ctx = arm->etm; struct reg *etm_ctrl_reg; etm_ctrl_reg = etm_reg_lookup(etm_ctx, ETM_CTRL); if (!etm_ctrl_reg) return ERROR_OK; /* initialize some ETM control register settings */ etm_get_reg(etm_ctrl_reg); etm_ctrl_value = buf_get_u32(etm_ctrl_reg->value, 0, 32); /* clear the ETM powerdown bit (0) */ etm_ctrl_value &= ~ETM_CTRL_POWERDOWN; /* configure port width (21,6:4), mode (13,17:16) and * for older modules clocking (13) */ etm_ctrl_value = (etm_ctrl_value & ~ETM_PORT_WIDTH_MASK & ~ETM_PORT_MODE_MASK & ~ETM_CTRL_DBGRQ & ~ETM_PORT_CLOCK_MASK) | etm_ctx->control; buf_set_u32(etm_ctrl_reg->value, 0, 32, etm_ctrl_value); etm_store_reg(etm_ctrl_reg); etm_ctx->control = etm_ctrl_value; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; /* REVISIT for ETMv3.0 and later, read ETM_sys_config to * verify that those width and mode settings are OK ... */ retval = etm_ctx->capture_driver->init(etm_ctx); if (retval != ERROR_OK) { LOG_ERROR("ETM capture driver initialization failed"); return retval; } return ERROR_OK; } static int etm_get_reg(struct reg *reg) { int retval; retval = etm_read_reg(reg); if (retval != ERROR_OK) { LOG_ERROR("BUG: error scheduling etm register read"); return retval; } retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("register read failed"); return retval; } return ERROR_OK; } static int etm_read_reg_w_check(struct reg *reg, uint8_t *check_value, uint8_t *check_mask) { struct etm_reg *etm_reg = reg->arch_info; const struct etm_reg_info *r = etm_reg->reg_info; uint8_t reg_addr = r->addr & 0x7f; struct scan_field fields[3]; int retval; if (etm_reg->reg_info->mode == WO) { LOG_ERROR("BUG: can't read write-only register %s", r->name); return ERROR_COMMAND_SYNTAX_ERROR; } LOG_DEBUG("%s (%u)", r->name, reg_addr); retval = arm_jtag_scann(etm_reg->jtag_info, 0x6, TAP_IDLE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(etm_reg->jtag_info, etm_reg->jtag_info->intest_instr, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 32; fields[0].out_value = reg->value; fields[0].in_value = NULL; fields[0].check_value = NULL; fields[0].check_mask = NULL; fields[1].num_bits = 7; uint8_t temp1; fields[1].out_value = &temp1; buf_set_u32(&temp1, 0, 7, reg_addr); fields[1].in_value = NULL; fields[1].check_value = NULL; fields[1].check_mask = NULL; fields[2].num_bits = 1; uint8_t temp2; fields[2].out_value = &temp2; buf_set_u32(&temp2, 0, 1, 0); fields[2].in_value = NULL; fields[2].check_value = NULL; fields[2].check_mask = NULL; jtag_add_dr_scan(etm_reg->jtag_info->tap, 3, fields, TAP_IDLE); fields[0].in_value = reg->value; fields[0].check_value = check_value; fields[0].check_mask = check_mask; jtag_add_dr_scan_check(etm_reg->jtag_info->tap, 3, fields, TAP_IDLE); return ERROR_OK; } static int etm_set_reg(struct reg *reg, uint32_t value) { int retval = etm_write_reg(reg, value); if (retval != ERROR_OK) { LOG_ERROR("BUG: error scheduling etm register write"); return retval; } buf_set_u32(reg->value, 0, reg->size, value); reg->valid = 1; reg->dirty = 0; return ERROR_OK; } static int etm_set_reg_w_exec(struct reg *reg, uint8_t *buf) { int retval; etm_set_reg(reg, buf_get_u32(buf, 0, reg->size)); retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("register write failed"); return retval; } return ERROR_OK; } static int etm_write_reg(struct reg *reg, uint32_t value) { struct etm_reg *etm_reg = reg->arch_info; const struct etm_reg_info *r = etm_reg->reg_info; uint8_t reg_addr = r->addr & 0x7f; struct scan_field fields[3]; int retval; if (etm_reg->reg_info->mode == RO) { LOG_ERROR("BUG: can't write read--only register %s", r->name); return ERROR_COMMAND_SYNTAX_ERROR; } LOG_DEBUG("%s (%u): 0x%8.8" PRIx32 "", r->name, reg_addr, value); retval = arm_jtag_scann(etm_reg->jtag_info, 0x6, TAP_IDLE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(etm_reg->jtag_info, etm_reg->jtag_info->intest_instr, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 32; uint8_t tmp1[4]; fields[0].out_value = tmp1; buf_set_u32(tmp1, 0, 32, value); fields[0].in_value = NULL; fields[1].num_bits = 7; uint8_t tmp2; fields[1].out_value = &tmp2; buf_set_u32(&tmp2, 0, 7, reg_addr); fields[1].in_value = NULL; fields[2].num_bits = 1; uint8_t tmp3; fields[2].out_value = &tmp3; buf_set_u32(&tmp3, 0, 1, 1); fields[2].in_value = NULL; jtag_add_dr_scan(etm_reg->jtag_info->tap, 3, fields, TAP_IDLE); return ERROR_OK; } /* ETM trace analysis functionality */ static struct etm_capture_driver *etm_capture_drivers[] = { &etb_capture_driver, &etm_dummy_capture_driver, #if BUILD_OOCD_TRACE == 1 &oocd_trace_capture_driver, #endif NULL }; static int etm_read_instruction(struct etm_context *ctx, struct arm_instruction *instruction) { int i; int section = -1; size_t size_read; uint32_t opcode; int retval; if (!ctx->image) return ERROR_TRACE_IMAGE_UNAVAILABLE; /* search for the section the current instruction belongs to */ for (i = 0; i < ctx->image->num_sections; i++) { if ((ctx->image->sections[i].base_address <= ctx->current_pc) && (ctx->image->sections[i].base_address + ctx->image->sections[i].size > ctx->current_pc)) { section = i; break; } } if (section == -1) { /* current instruction couldn't be found in the image */ return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; } if (ctx->core_state == ARM_STATE_ARM) { uint8_t buf[4]; retval = image_read_section(ctx->image, section, ctx->current_pc - ctx->image->sections[section].base_address, 4, buf, &size_read); if (retval != ERROR_OK) { LOG_ERROR("error while reading instruction"); return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; } opcode = target_buffer_get_u32(ctx->target, buf); arm_evaluate_opcode(opcode, ctx->current_pc, instruction); } else if (ctx->core_state == ARM_STATE_THUMB) { uint8_t buf[2]; retval = image_read_section(ctx->image, section, ctx->current_pc - ctx->image->sections[section].base_address, 2, buf, &size_read); if (retval != ERROR_OK) { LOG_ERROR("error while reading instruction"); return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; } opcode = target_buffer_get_u16(ctx->target, buf); thumb_evaluate_opcode(opcode, ctx->current_pc, instruction); } else if (ctx->core_state == ARM_STATE_JAZELLE) { LOG_ERROR("BUG: tracing of jazelle code not supported"); return ERROR_FAIL; } else { LOG_ERROR("BUG: unknown core state encountered"); return ERROR_FAIL; } return ERROR_OK; } static int etmv1_next_packet(struct etm_context *ctx, uint8_t *packet, int apo) { while (ctx->data_index < ctx->trace_depth) { /* if the caller specified an address packet offset, skip until the * we reach the n-th cycle marked with tracesync */ if (apo > 0) { if (ctx->trace_data[ctx->data_index].flags & ETMV1_TRACESYNC_CYCLE) apo--; if (apo > 0) { ctx->data_index++; ctx->data_half = 0; } continue; } /* no tracedata output during a TD cycle * or in a trigger cycle */ if ((ctx->trace_data[ctx->data_index].pipestat == STAT_TD) || (ctx->trace_data[ctx->data_index].flags & ETMV1_TRIGGER_CYCLE)) { ctx->data_index++; ctx->data_half = 0; continue; } /* FIXME there are more port widths than these... */ if ((ctx->control & ETM_PORT_WIDTH_MASK) == ETM_PORT_16BIT) { if (ctx->data_half == 0) { *packet = ctx->trace_data[ctx->data_index].packet & 0xff; ctx->data_half = 1; } else { *packet = (ctx->trace_data[ctx->data_index].packet & 0xff00) >> 8; ctx->data_half = 0; ctx->data_index++; } } else if ((ctx->control & ETM_PORT_WIDTH_MASK) == ETM_PORT_8BIT) { *packet = ctx->trace_data[ctx->data_index].packet & 0xff; ctx->data_index++; } else { /* on a 4-bit port, a packet will be output during two consecutive cycles */ if (ctx->data_index > (ctx->trace_depth - 2)) return -1; *packet = ctx->trace_data[ctx->data_index].packet & 0xf; *packet |= (ctx->trace_data[ctx->data_index + 1].packet & 0xf) << 4; ctx->data_index += 2; } return 0; } return -1; } static int etmv1_branch_address(struct etm_context *ctx) { int retval; uint8_t packet; int shift = 0; int apo; uint32_t i; /* quit analysis if less than two cycles are left in the trace * because we can't extract the APO */ if (ctx->data_index > (ctx->trace_depth - 2)) return -1; /* a BE could be output during an APO cycle, skip the current * and continue with the new one */ if (ctx->trace_data[ctx->pipe_index + 1].pipestat & 0x4) return 1; if (ctx->trace_data[ctx->pipe_index + 2].pipestat & 0x4) return 2; /* address packet offset encoded in the next two cycles' pipestat bits */ apo = ctx->trace_data[ctx->pipe_index + 1].pipestat & 0x3; apo |= (ctx->trace_data[ctx->pipe_index + 2].pipestat & 0x3) << 2; /* count number of tracesync cycles between current pipe_index and data_index * i.e. the number of tracesyncs that data_index already passed by * to subtract them from the APO */ for (i = ctx->pipe_index; i < ctx->data_index; i++) { if (ctx->trace_data[ctx->pipe_index + 1].pipestat & ETMV1_TRACESYNC_CYCLE) apo--; } /* extract up to four 7-bit packets */ do { retval = etmv1_next_packet(ctx, &packet, (shift == 0) ? apo + 1 : 0); if (retval != 0) return -1; ctx->last_branch &= ~(0x7f << shift); ctx->last_branch |= (packet & 0x7f) << shift; shift += 7; } while ((packet & 0x80) && (shift < 28)); /* one last packet holding 4 bits of the address, plus the branch reason code */ if ((shift == 28) && (packet & 0x80)) { retval = etmv1_next_packet(ctx, &packet, 0); if (retval != 0) return -1; ctx->last_branch &= 0x0fffffff; ctx->last_branch |= (packet & 0x0f) << 28; ctx->last_branch_reason = (packet & 0x70) >> 4; shift += 4; } else ctx->last_branch_reason = 0; if (shift == 32) ctx->pc_ok = 1; /* if a full address was output, we might have branched into Jazelle state */ if ((shift == 32) && (packet & 0x80)) ctx->core_state = ARM_STATE_JAZELLE; else { /* if we didn't branch into Jazelle state, the current processor state is * encoded in bit 0 of the branch target address */ if (ctx->last_branch & 0x1) { ctx->core_state = ARM_STATE_THUMB; ctx->last_branch &= ~0x1; } else { ctx->core_state = ARM_STATE_ARM; ctx->last_branch &= ~0x3; } } return 0; } static int etmv1_data(struct etm_context *ctx, int size, uint32_t *data) { int j; uint8_t buf[4]; int retval; for (j = 0; j < size; j++) { retval = etmv1_next_packet(ctx, &buf[j], 0); if (retval != 0) return -1; } if (size == 8) { LOG_ERROR("TODO: add support for 64-bit values"); return -1; } else if (size == 4) *data = target_buffer_get_u32(ctx->target, buf); else if (size == 2) *data = target_buffer_get_u16(ctx->target, buf); else if (size == 1) *data = buf[0]; else return -1; return 0; } static int etmv1_analyze_trace(struct etm_context *ctx, struct command_context *cmd_ctx) { int retval; struct arm_instruction instruction; /* read the trace data if it wasn't read already */ if (ctx->trace_depth == 0) ctx->capture_driver->read_trace(ctx); if (ctx->trace_depth == 0) { command_print(cmd_ctx, "Trace is empty."); return ERROR_OK; } /* start at the beginning of the captured trace */ ctx->pipe_index = 0; ctx->data_index = 0; ctx->data_half = 0; /* neither the PC nor the data pointer are valid */ ctx->pc_ok = 0; ctx->ptr_ok = 0; while (ctx->pipe_index < ctx->trace_depth) { uint8_t pipestat = ctx->trace_data[ctx->pipe_index].pipestat; uint32_t next_pc = ctx->current_pc; uint32_t old_data_index = ctx->data_index; uint32_t old_data_half = ctx->data_half; uint32_t old_index = ctx->pipe_index; uint32_t last_instruction = ctx->last_instruction; uint32_t cycles = 0; int current_pc_ok = ctx->pc_ok; if (ctx->trace_data[ctx->pipe_index].flags & ETMV1_TRIGGER_CYCLE) command_print(cmd_ctx, "--- trigger ---"); /* instructions execute in IE/D or BE/D cycles */ if ((pipestat == STAT_IE) || (pipestat == STAT_ID)) ctx->last_instruction = ctx->pipe_index; /* if we don't have a valid pc skip until we reach an indirect branch */ if ((!ctx->pc_ok) && (pipestat != STAT_BE)) { ctx->pipe_index++; continue; } /* any indirect branch could have interrupted instruction flow * - the branch reason code could indicate a trace discontinuity * - a branch to the exception vectors indicates an exception */ if ((pipestat == STAT_BE) || (pipestat == STAT_BD)) { /* backup current data index, to be able to consume the branch address * before examining data address and values */ old_data_index = ctx->data_index; old_data_half = ctx->data_half; ctx->last_instruction = ctx->pipe_index; retval = etmv1_branch_address(ctx); if (retval != 0) { /* negative return value from etmv1_branch_address means we ran out of packets, * quit analysing the trace */ if (retval < 0) break; /* a positive return values means the current branch was abandoned, * and a new branch was encountered in cycle ctx->pipe_index + retval; */ LOG_WARNING( "abandoned branch encountered, correctnes of analysis uncertain"); ctx->pipe_index += retval; continue; } /* skip over APO cycles */ ctx->pipe_index += 2; switch (ctx->last_branch_reason) { case 0x0: /* normal PC change */ next_pc = ctx->last_branch; break; case 0x1: /* tracing enabled */ command_print(cmd_ctx, "--- tracing enabled at 0x%8.8" PRIx32 " ---", ctx->last_branch); ctx->current_pc = ctx->last_branch; ctx->pipe_index++; continue; break; case 0x2: /* trace restarted after FIFO overflow */ command_print(cmd_ctx, "--- trace restarted after FIFO overflow at 0x%8.8" PRIx32 " ---", ctx->last_branch); ctx->current_pc = ctx->last_branch; ctx->pipe_index++; continue; break; case 0x3: /* exit from debug state */ command_print(cmd_ctx, "--- exit from debug state at 0x%8.8" PRIx32 " ---", ctx->last_branch); ctx->current_pc = ctx->last_branch; ctx->pipe_index++; continue; break; case 0x4: /* periodic synchronization point */ next_pc = ctx->last_branch; /* if we had no valid PC prior to this synchronization point, * we have to move on with the next trace cycle */ if (!current_pc_ok) { command_print(cmd_ctx, "--- periodic synchronization point at 0x%8.8" PRIx32 " ---", next_pc); ctx->current_pc = next_pc; ctx->pipe_index++; continue; } break; default: /* reserved */ LOG_ERROR( "BUG: branch reason code 0x%" PRIx32 " is reserved", ctx->last_branch_reason); return ERROR_FAIL; } /* if we got here the branch was a normal PC change * (or a periodic synchronization point, which means the same for that matter) * if we didn't accquire a complete PC continue with the next cycle */ if (!ctx->pc_ok) continue; /* indirect branch to the exception vector means an exception occured */ if ((ctx->last_branch <= 0x20) || ((ctx->last_branch >= 0xffff0000) && (ctx->last_branch <= 0xffff0020))) { if ((ctx->last_branch & 0xff) == 0x10) command_print(cmd_ctx, "data abort"); else { command_print(cmd_ctx, "exception vector 0x%2.2" PRIx32 "", ctx->last_branch); ctx->current_pc = ctx->last_branch; ctx->pipe_index++; continue; } } } /* an instruction was executed (or not, depending on the condition flags) * retrieve it from the image for displaying */ if (ctx->pc_ok && (pipestat != STAT_WT) && (pipestat != STAT_TD) && !(((pipestat == STAT_BE) || (pipestat == STAT_BD)) && ((ctx->last_branch_reason != 0x0) && (ctx->last_branch_reason != 0x4)))) { retval = etm_read_instruction(ctx, &instruction); if (retval != ERROR_OK) { /* can't continue tracing with no image available */ if (retval == ERROR_TRACE_IMAGE_UNAVAILABLE) return retval; else if (retval == ERROR_TRACE_INSTRUCTION_UNAVAILABLE) { /* TODO: handle incomplete images * for now we just quit the analsysis*/ return retval; } } cycles = old_index - last_instruction; } if ((pipestat == STAT_ID) || (pipestat == STAT_BD)) { uint32_t new_data_index = ctx->data_index; uint32_t new_data_half = ctx->data_half; /* in case of a branch with data, the branch target address was consumed before * we temporarily go back to the saved data index */ if (pipestat == STAT_BD) { ctx->data_index = old_data_index; ctx->data_half = old_data_half; } if (ctx->control & ETM_CTRL_TRACE_ADDR) { uint8_t packet; int shift = 0; do { retval = etmv1_next_packet(ctx, &packet, 0); if (retval != 0) return ERROR_ETM_ANALYSIS_FAILED; ctx->last_ptr &= ~(0x7f << shift); ctx->last_ptr |= (packet & 0x7f) << shift; shift += 7; } while ((packet & 0x80) && (shift < 32)); if (shift >= 32) ctx->ptr_ok = 1; if (ctx->ptr_ok) command_print(cmd_ctx, "address: 0x%8.8" PRIx32 "", ctx->last_ptr); } if (ctx->control & ETM_CTRL_TRACE_DATA) { if ((instruction.type == ARM_LDM) || (instruction.type == ARM_STM)) { int i; for (i = 0; i < 16; i++) { if (instruction.info.load_store_multiple. register_list & (1 << i)) { uint32_t data; if (etmv1_data(ctx, 4, &data) != 0) return ERROR_ETM_ANALYSIS_FAILED; command_print(cmd_ctx, "data: 0x%8.8" PRIx32 "", data); } } } else if ((instruction.type >= ARM_LDR) && (instruction.type <= ARM_STRH)) { uint32_t data; if (etmv1_data(ctx, arm_access_size(&instruction), &data) != 0) return ERROR_ETM_ANALYSIS_FAILED; command_print(cmd_ctx, "data: 0x%8.8" PRIx32 "", data); } } /* restore data index after consuming BD address and data */ if (pipestat == STAT_BD) { ctx->data_index = new_data_index; ctx->data_half = new_data_half; } } /* adjust PC */ if ((pipestat == STAT_IE) || (pipestat == STAT_ID)) { if (((instruction.type == ARM_B) || (instruction.type == ARM_BL) || (instruction.type == ARM_BLX)) && (instruction.info.b_bl_bx_blx.target_address != 0xffffffff)) next_pc = instruction.info.b_bl_bx_blx.target_address; else next_pc += (ctx->core_state == ARM_STATE_ARM) ? 4 : 2; } else if (pipestat == STAT_IN) next_pc += (ctx->core_state == ARM_STATE_ARM) ? 4 : 2; if ((pipestat != STAT_TD) && (pipestat != STAT_WT)) { char cycles_text[32] = ""; /* if the trace was captured with cycle accurate tracing enabled, * output the number of cycles since the last executed instruction */ if (ctx->control & ETM_CTRL_CYCLE_ACCURATE) { snprintf(cycles_text, 32, " (%i %s)", (int)cycles, (cycles == 1) ? "cycle" : "cycles"); } command_print(cmd_ctx, "%s%s%s", instruction.text, (pipestat == STAT_IN) ? " (not executed)" : "", cycles_text); ctx->current_pc = next_pc; /* packets for an instruction don't start on or before the preceding * functional pipestat (i.e. other than WT or TD) */ if (ctx->data_index <= ctx->pipe_index) { ctx->data_index = ctx->pipe_index + 1; ctx->data_half = 0; } } ctx->pipe_index += 1; } return ERROR_OK; } static COMMAND_HELPER(handle_etm_tracemode_command_update, uint32_t *mode) { uint32_t tracemode; /* what parts of data access are traced? */ if (strcmp(CMD_ARGV[0], "none") == 0) tracemode = 0; else if (strcmp(CMD_ARGV[0], "data") == 0) tracemode = ETM_CTRL_TRACE_DATA; else if (strcmp(CMD_ARGV[0], "address") == 0) tracemode = ETM_CTRL_TRACE_ADDR; else if (strcmp(CMD_ARGV[0], "all") == 0) tracemode = ETM_CTRL_TRACE_DATA | ETM_CTRL_TRACE_ADDR; else { command_print(CMD_CTX, "invalid option '%s'", CMD_ARGV[0]); return ERROR_COMMAND_SYNTAX_ERROR; } uint8_t context_id; COMMAND_PARSE_NUMBER(u8, CMD_ARGV[1], context_id); switch (context_id) { case 0: tracemode |= ETM_CTRL_CONTEXTID_NONE; break; case 8: tracemode |= ETM_CTRL_CONTEXTID_8; break; case 16: tracemode |= ETM_CTRL_CONTEXTID_16; break; case 32: tracemode |= ETM_CTRL_CONTEXTID_32; break; default: command_print(CMD_CTX, "invalid option '%s'", CMD_ARGV[1]); return ERROR_COMMAND_SYNTAX_ERROR; } bool etmv1_cycle_accurate; COMMAND_PARSE_ENABLE(CMD_ARGV[2], etmv1_cycle_accurate); if (etmv1_cycle_accurate) tracemode |= ETM_CTRL_CYCLE_ACCURATE; bool etmv1_branch_output; COMMAND_PARSE_ENABLE(CMD_ARGV[3], etmv1_branch_output); if (etmv1_branch_output) tracemode |= ETM_CTRL_BRANCH_OUTPUT; /* IGNORED: * - CPRT tracing (coprocessor register transfers) * - debug request (causes debug entry on trigger) * - stall on FIFOFULL (preventing tracedata lossage) */ *mode = tracemode; return ERROR_OK; } COMMAND_HANDLER(handle_etm_tracemode_command) { struct target *target = get_current_target(CMD_CTX); struct arm *arm = target_to_arm(target); struct etm_context *etm; if (!is_arm(arm)) { command_print(CMD_CTX, "ETM: current target isn't an ARM"); return ERROR_FAIL; } etm = arm->etm; if (!etm) { command_print(CMD_CTX, "current target doesn't have an ETM configured"); return ERROR_FAIL; } uint32_t tracemode = etm->control; switch (CMD_ARGC) { case 0: break; case 4: CALL_COMMAND_HANDLER(handle_etm_tracemode_command_update, &tracemode); break; default: return ERROR_COMMAND_SYNTAX_ERROR; } /** * todo: fail if parameters were invalid for this hardware, * or couldn't be written; display actual hardware state... */ command_print(CMD_CTX, "current tracemode configuration:"); switch (tracemode & ETM_CTRL_TRACE_MASK) { default: command_print(CMD_CTX, "data tracing: none"); break; case ETM_CTRL_TRACE_DATA: command_print(CMD_CTX, "data tracing: data only"); break; case ETM_CTRL_TRACE_ADDR: command_print(CMD_CTX, "data tracing: address only"); break; case ETM_CTRL_TRACE_DATA | ETM_CTRL_TRACE_ADDR: command_print(CMD_CTX, "data tracing: address and data"); break; } switch (tracemode & ETM_CTRL_CONTEXTID_MASK) { case ETM_CTRL_CONTEXTID_NONE: command_print(CMD_CTX, "contextid tracing: none"); break; case ETM_CTRL_CONTEXTID_8: command_print(CMD_CTX, "contextid tracing: 8 bit"); break; case ETM_CTRL_CONTEXTID_16: command_print(CMD_CTX, "contextid tracing: 16 bit"); break; case ETM_CTRL_CONTEXTID_32: command_print(CMD_CTX, "contextid tracing: 32 bit"); break; } if (tracemode & ETM_CTRL_CYCLE_ACCURATE) command_print(CMD_CTX, "cycle-accurate tracing enabled"); else command_print(CMD_CTX, "cycle-accurate tracing disabled"); if (tracemode & ETM_CTRL_BRANCH_OUTPUT) command_print(CMD_CTX, "full branch address output enabled"); else command_print(CMD_CTX, "full branch address output disabled"); #define TRACEMODE_MASK ( \ ETM_CTRL_CONTEXTID_MASK \ | ETM_CTRL_BRANCH_OUTPUT \ | ETM_CTRL_CYCLE_ACCURATE \ | ETM_CTRL_TRACE_MASK \ ) /* only update ETM_CTRL register if tracemode changed */ if ((etm->control & TRACEMODE_MASK) != tracemode) { struct reg *etm_ctrl_reg; etm_ctrl_reg = etm_reg_lookup(etm, ETM_CTRL); if (!etm_ctrl_reg) return ERROR_FAIL; etm->control &= ~TRACEMODE_MASK; etm->control |= tracemode & TRACEMODE_MASK; buf_set_u32(etm_ctrl_reg->value, 0, 32, etm->control); etm_store_reg(etm_ctrl_reg); /* invalidate old trace data */ etm->capture_status = TRACE_IDLE; if (etm->trace_depth > 0) { free(etm->trace_data); etm->trace_data = NULL; } etm->trace_depth = 0; } #undef TRACEMODE_MASK return ERROR_OK; } COMMAND_HANDLER(handle_etm_config_command) { struct target *target; struct arm *arm; uint32_t portmode = 0x0; struct etm_context *etm_ctx; int i; if (CMD_ARGC != 5) return ERROR_COMMAND_SYNTAX_ERROR; target = get_target(CMD_ARGV[0]); if (!target) { LOG_ERROR("target '%s' not defined", CMD_ARGV[0]); return ERROR_FAIL; } arm = target_to_arm(target); if (!is_arm(arm)) { command_print(CMD_CTX, "target '%s' is '%s'; not an ARM", target_name(target), target_type_name(target)); return ERROR_FAIL; } /* FIXME for ETMv3.0 and above -- and we don't yet know what ETM * version we'll be using!! -- so we can't know how to validate * params yet. "etm config" should likely be *AFTER* hookup... * * - Many more widths might be supported ... and we can easily * check whether our setting "took". * * - The "clock" and "mode" bits are interpreted differently. * See ARM IHI 0014O table 2-17 for the old behavior, and * table 2-18 for the new. With ETB it's best to specify * "normal full" ... */ uint8_t port_width; COMMAND_PARSE_NUMBER(u8, CMD_ARGV[1], port_width); switch (port_width) { /* before ETMv3.0 */ case 4: portmode |= ETM_PORT_4BIT; break; case 8: portmode |= ETM_PORT_8BIT; break; case 16: portmode |= ETM_PORT_16BIT; break; /* ETMv3.0 and later*/ case 24: portmode |= ETM_PORT_24BIT; break; case 32: portmode |= ETM_PORT_32BIT; break; case 48: portmode |= ETM_PORT_48BIT; break; case 64: portmode |= ETM_PORT_64BIT; break; case 1: portmode |= ETM_PORT_1BIT; break; case 2: portmode |= ETM_PORT_2BIT; break; default: command_print(CMD_CTX, "unsupported ETM port width '%s'", CMD_ARGV[1]); return ERROR_FAIL; } if (strcmp("normal", CMD_ARGV[2]) == 0) portmode |= ETM_PORT_NORMAL; else if (strcmp("multiplexed", CMD_ARGV[2]) == 0) portmode |= ETM_PORT_MUXED; else if (strcmp("demultiplexed", CMD_ARGV[2]) == 0) portmode |= ETM_PORT_DEMUXED; else { command_print(CMD_CTX, "unsupported ETM port mode '%s', must be 'normal', 'multiplexed' or 'demultiplexed'", CMD_ARGV[2]); return ERROR_FAIL; } if (strcmp("half", CMD_ARGV[3]) == 0) portmode |= ETM_PORT_HALF_CLOCK; else if (strcmp("full", CMD_ARGV[3]) == 0) portmode |= ETM_PORT_FULL_CLOCK; else { command_print(CMD_CTX, "unsupported ETM port clocking '%s', must be 'full' or 'half'", CMD_ARGV[3]); return ERROR_FAIL; } etm_ctx = calloc(1, sizeof(struct etm_context)); if (!etm_ctx) { LOG_DEBUG("out of memory"); return ERROR_FAIL; } for (i = 0; etm_capture_drivers[i]; i++) { if (strcmp(CMD_ARGV[4], etm_capture_drivers[i]->name) == 0) { int retval = register_commands(CMD_CTX, NULL, etm_capture_drivers[i]->commands); if (ERROR_OK != retval) { free(etm_ctx); return retval; } etm_ctx->capture_driver = etm_capture_drivers[i]; break; } } if (!etm_capture_drivers[i]) { /* no supported capture driver found, don't register an ETM */ free(etm_ctx); LOG_ERROR("trace capture driver '%s' not found", CMD_ARGV[4]); return ERROR_FAIL; } etm_ctx->target = target; etm_ctx->trace_data = NULL; etm_ctx->control = portmode; etm_ctx->core_state = ARM_STATE_ARM; arm->etm = etm_ctx; return etm_register_user_commands(CMD_CTX); } COMMAND_HANDLER(handle_etm_info_command) { struct target *target; struct arm *arm; struct etm_context *etm; struct reg *etm_sys_config_reg; int max_port_size; uint32_t config; target = get_current_target(CMD_CTX); arm = target_to_arm(target); if (!is_arm(arm)) { command_print(CMD_CTX, "ETM: current target isn't an ARM"); return ERROR_FAIL; } etm = arm->etm; if (!etm) { command_print(CMD_CTX, "current target doesn't have an ETM configured"); return ERROR_FAIL; } command_print(CMD_CTX, "ETM v%d.%d", etm->bcd_vers >> 4, etm->bcd_vers & 0xf); command_print(CMD_CTX, "pairs of address comparators: %i", (int) (etm->config >> 0) & 0x0f); command_print(CMD_CTX, "data comparators: %i", (int) (etm->config >> 4) & 0x0f); command_print(CMD_CTX, "memory map decoders: %i", (int) (etm->config >> 8) & 0x1f); command_print(CMD_CTX, "number of counters: %i", (int) (etm->config >> 13) & 0x07); command_print(CMD_CTX, "sequencer %spresent", (int) (etm->config & (1 << 16)) ? "" : "not "); command_print(CMD_CTX, "number of ext. inputs: %i", (int) (etm->config >> 17) & 0x07); command_print(CMD_CTX, "number of ext. outputs: %i", (int) (etm->config >> 20) & 0x07); command_print(CMD_CTX, "FIFO full %spresent", (int) (etm->config & (1 << 23)) ? "" : "not "); if (etm->bcd_vers < 0x20) command_print(CMD_CTX, "protocol version: %i", (int) (etm->config >> 28) & 0x07); else { command_print(CMD_CTX, "coprocessor and memory access %ssupported", (etm->config & (1 << 26)) ? "" : "not "); command_print(CMD_CTX, "trace start/stop %spresent", (etm->config & (1 << 26)) ? "" : "not "); command_print(CMD_CTX, "number of context comparators: %i", (int) (etm->config >> 24) & 0x03); } /* SYS_CONFIG isn't present before ETMv1.2 */ etm_sys_config_reg = etm_reg_lookup(etm, ETM_SYS_CONFIG); if (!etm_sys_config_reg) return ERROR_OK; etm_get_reg(etm_sys_config_reg); config = buf_get_u32(etm_sys_config_reg->value, 0, 32); LOG_DEBUG("ETM SYS CONFIG %08x", (unsigned) config); max_port_size = config & 0x7; if (etm->bcd_vers >= 0x30) max_port_size |= (config >> 6) & 0x08; switch (max_port_size) { /* before ETMv3.0 */ case 0: max_port_size = 4; break; case 1: max_port_size = 8; break; case 2: max_port_size = 16; break; /* ETMv3.0 and later*/ case 3: max_port_size = 24; break; case 4: max_port_size = 32; break; case 5: max_port_size = 48; break; case 6: max_port_size = 64; break; case 8: max_port_size = 1; break; case 9: max_port_size = 2; break; default: LOG_ERROR("Illegal max_port_size"); return ERROR_FAIL; } command_print(CMD_CTX, "max. port size: %i", max_port_size); if (etm->bcd_vers < 0x30) { command_print(CMD_CTX, "half-rate clocking %ssupported", (config & (1 << 3)) ? "" : "not "); command_print(CMD_CTX, "full-rate clocking %ssupported", (config & (1 << 4)) ? "" : "not "); command_print(CMD_CTX, "normal trace format %ssupported", (config & (1 << 5)) ? "" : "not "); command_print(CMD_CTX, "multiplex trace format %ssupported", (config & (1 << 6)) ? "" : "not "); command_print(CMD_CTX, "demultiplex trace format %ssupported", (config & (1 << 7)) ? "" : "not "); } else { /* REVISIT show which size and format are selected ... */ command_print(CMD_CTX, "current port size %ssupported", (config & (1 << 10)) ? "" : "not "); command_print(CMD_CTX, "current trace format %ssupported", (config & (1 << 11)) ? "" : "not "); } if (etm->bcd_vers >= 0x21) command_print(CMD_CTX, "fetch comparisons %ssupported", (config & (1 << 17)) ? "not " : ""); command_print(CMD_CTX, "FIFO full %ssupported", (config & (1 << 8)) ? "" : "not "); return ERROR_OK; } COMMAND_HANDLER(handle_etm_status_command) { struct target *target; struct arm *arm; struct etm_context *etm; trace_status_t trace_status; target = get_current_target(CMD_CTX); arm = target_to_arm(target); if (!is_arm(arm)) { command_print(CMD_CTX, "ETM: current target isn't an ARM"); return ERROR_FAIL; } etm = arm->etm; if (!etm) { command_print(CMD_CTX, "current target doesn't have an ETM configured"); return ERROR_FAIL; } /* ETM status */ if (etm->bcd_vers >= 0x11) { struct reg *reg; reg = etm_reg_lookup(etm, ETM_STATUS); if (!reg) return ERROR_FAIL; if (etm_get_reg(reg) == ERROR_OK) { unsigned s = buf_get_u32(reg->value, 0, reg->size); command_print(CMD_CTX, "etm: %s%s%s%s", /* bit(1) == progbit */ (etm->bcd_vers >= 0x12) ? ((s & (1 << 1)) ? "disabled" : "enabled") : "?", ((s & (1 << 3)) && etm->bcd_vers >= 0x31) ? " triggered" : "", ((s & (1 << 2)) && etm->bcd_vers >= 0x12) ? " start/stop" : "", ((s & (1 << 0)) && etm->bcd_vers >= 0x11) ? " untraced-overflow" : ""); } /* else ignore and try showing trace port status */ } /* Trace Port Driver status */ trace_status = etm->capture_driver->status(etm); if (trace_status == TRACE_IDLE) command_print(CMD_CTX, "%s: idle", etm->capture_driver->name); else { static char *completed = " completed"; static char *running = " is running"; static char *overflowed = ", overflowed"; static char *triggered = ", triggered"; command_print(CMD_CTX, "%s: trace collection%s%s%s", etm->capture_driver->name, (trace_status & TRACE_RUNNING) ? running : completed, (trace_status & TRACE_OVERFLOWED) ? overflowed : "", (trace_status & TRACE_TRIGGERED) ? triggered : ""); if (etm->trace_depth > 0) { command_print(CMD_CTX, "%i frames of trace data read", (int)(etm->trace_depth)); } } return ERROR_OK; } COMMAND_HANDLER(handle_etm_image_command) { struct target *target; struct arm *arm; struct etm_context *etm_ctx; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; target = get_current_target(CMD_CTX); arm = target_to_arm(target); if (!is_arm(arm)) { command_print(CMD_CTX, "ETM: current target isn't an ARM"); return ERROR_FAIL; } etm_ctx = arm->etm; if (!etm_ctx) { command_print(CMD_CTX, "current target doesn't have an ETM configured"); return ERROR_FAIL; } if (etm_ctx->image) { image_close(etm_ctx->image); free(etm_ctx->image); command_print(CMD_CTX, "previously loaded image found and closed"); } etm_ctx->image = malloc(sizeof(struct image)); etm_ctx->image->base_address_set = 0; etm_ctx->image->start_address_set = 0; /* a base address isn't always necessary, default to 0x0 (i.e. don't relocate) */ if (CMD_ARGC >= 2) { etm_ctx->image->base_address_set = 1; COMMAND_PARSE_NUMBER(llong, CMD_ARGV[1], etm_ctx->image->base_address); } else etm_ctx->image->base_address_set = 0; if (image_open(etm_ctx->image, CMD_ARGV[0], (CMD_ARGC >= 3) ? CMD_ARGV[2] : NULL) != ERROR_OK) { free(etm_ctx->image); etm_ctx->image = NULL; return ERROR_FAIL; } return ERROR_OK; } COMMAND_HANDLER(handle_etm_dump_command) { struct fileio file; struct target *target; struct arm *arm; struct etm_context *etm_ctx; uint32_t i; if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; target = get_current_target(CMD_CTX); arm = target_to_arm(target); if (!is_arm(arm)) { command_print(CMD_CTX, "ETM: current target isn't an ARM"); return ERROR_FAIL; } etm_ctx = arm->etm; if (!etm_ctx) { command_print(CMD_CTX, "current target doesn't have an ETM configured"); return ERROR_FAIL; } if (etm_ctx->capture_driver->status == TRACE_IDLE) { command_print(CMD_CTX, "trace capture wasn't enabled, no trace data captured"); return ERROR_OK; } if (etm_ctx->capture_driver->status(etm_ctx) & TRACE_RUNNING) { /* TODO: if on-the-fly capture is to be supported, this needs to be changed */ command_print(CMD_CTX, "trace capture not completed"); return ERROR_FAIL; } /* read the trace data if it wasn't read already */ if (etm_ctx->trace_depth == 0) etm_ctx->capture_driver->read_trace(etm_ctx); if (fileio_open(&file, CMD_ARGV[0], FILEIO_WRITE, FILEIO_BINARY) != ERROR_OK) return ERROR_FAIL; fileio_write_u32(&file, etm_ctx->capture_status); fileio_write_u32(&file, etm_ctx->control); fileio_write_u32(&file, etm_ctx->trace_depth); for (i = 0; i < etm_ctx->trace_depth; i++) { fileio_write_u32(&file, etm_ctx->trace_data[i].pipestat); fileio_write_u32(&file, etm_ctx->trace_data[i].packet); fileio_write_u32(&file, etm_ctx->trace_data[i].flags); } fileio_close(&file); return ERROR_OK; } COMMAND_HANDLER(handle_etm_load_command) { struct fileio file; struct target *target; struct arm *arm; struct etm_context *etm_ctx; uint32_t i; if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; target = get_current_target(CMD_CTX); arm = target_to_arm(target); if (!is_arm(arm)) { command_print(CMD_CTX, "ETM: current target isn't an ARM"); return ERROR_FAIL; } etm_ctx = arm->etm; if (!etm_ctx) { command_print(CMD_CTX, "current target doesn't have an ETM configured"); return ERROR_FAIL; } if (etm_ctx->capture_driver->status(etm_ctx) & TRACE_RUNNING) { command_print(CMD_CTX, "trace capture running, stop first"); return ERROR_FAIL; } if (fileio_open(&file, CMD_ARGV[0], FILEIO_READ, FILEIO_BINARY) != ERROR_OK) return ERROR_FAIL; int filesize; int retval = fileio_size(&file, &filesize); if (retval != ERROR_OK) { fileio_close(&file); return retval; } if (filesize % 4) { command_print(CMD_CTX, "size isn't a multiple of 4, no valid trace data"); fileio_close(&file); return ERROR_FAIL; } if (etm_ctx->trace_depth > 0) { free(etm_ctx->trace_data); etm_ctx->trace_data = NULL; } { uint32_t tmp; fileio_read_u32(&file, &tmp); etm_ctx->capture_status = tmp; fileio_read_u32(&file, &tmp); etm_ctx->control = tmp; fileio_read_u32(&file, &etm_ctx->trace_depth); } etm_ctx->trace_data = malloc(sizeof(struct etmv1_trace_data) * etm_ctx->trace_depth); if (etm_ctx->trace_data == NULL) { command_print(CMD_CTX, "not enough memory to perform operation"); fileio_close(&file); return ERROR_FAIL; } for (i = 0; i < etm_ctx->trace_depth; i++) { uint32_t pipestat, packet, flags; fileio_read_u32(&file, &pipestat); fileio_read_u32(&file, &packet); fileio_read_u32(&file, &flags); etm_ctx->trace_data[i].pipestat = pipestat & 0xff; etm_ctx->trace_data[i].packet = packet & 0xffff; etm_ctx->trace_data[i].flags = flags; } fileio_close(&file); return ERROR_OK; } COMMAND_HANDLER(handle_etm_start_command) { struct target *target; struct arm *arm; struct etm_context *etm_ctx; struct reg *etm_ctrl_reg; target = get_current_target(CMD_CTX); arm = target_to_arm(target); if (!is_arm(arm)) { command_print(CMD_CTX, "ETM: current target isn't an ARM"); return ERROR_FAIL; } etm_ctx = arm->etm; if (!etm_ctx) { command_print(CMD_CTX, "current target doesn't have an ETM configured"); return ERROR_FAIL; } /* invalidate old tracing data */ etm_ctx->capture_status = TRACE_IDLE; if (etm_ctx->trace_depth > 0) { free(etm_ctx->trace_data); etm_ctx->trace_data = NULL; } etm_ctx->trace_depth = 0; etm_ctrl_reg = etm_reg_lookup(etm_ctx, ETM_CTRL); if (!etm_ctrl_reg) return ERROR_FAIL; etm_get_reg(etm_ctrl_reg); /* Clear programming bit (10), set port selection bit (11) */ buf_set_u32(etm_ctrl_reg->value, 10, 2, 0x2); etm_store_reg(etm_ctrl_reg); jtag_execute_queue(); etm_ctx->capture_driver->start_capture(etm_ctx); return ERROR_OK; } COMMAND_HANDLER(handle_etm_stop_command) { struct target *target; struct arm *arm; struct etm_context *etm_ctx; struct reg *etm_ctrl_reg; target = get_current_target(CMD_CTX); arm = target_to_arm(target); if (!is_arm(arm)) { command_print(CMD_CTX, "ETM: current target isn't an ARM"); return ERROR_FAIL; } etm_ctx = arm->etm; if (!etm_ctx) { command_print(CMD_CTX, "current target doesn't have an ETM configured"); return ERROR_FAIL; } etm_ctrl_reg = etm_reg_lookup(etm_ctx, ETM_CTRL); if (!etm_ctrl_reg) return ERROR_FAIL; etm_get_reg(etm_ctrl_reg); /* Set programming bit (10), clear port selection bit (11) */ buf_set_u32(etm_ctrl_reg->value, 10, 2, 0x1); etm_store_reg(etm_ctrl_reg); jtag_execute_queue(); etm_ctx->capture_driver->stop_capture(etm_ctx); return ERROR_OK; } COMMAND_HANDLER(handle_etm_trigger_debug_command) { struct target *target; struct arm *arm; struct etm_context *etm; target = get_current_target(CMD_CTX); arm = target_to_arm(target); if (!is_arm(arm)) { command_print(CMD_CTX, "ETM: %s isn't an ARM", target_name(target)); return ERROR_FAIL; } etm = arm->etm; if (!etm) { command_print(CMD_CTX, "ETM: no ETM configured for %s", target_name(target)); return ERROR_FAIL; } if (CMD_ARGC == 1) { struct reg *etm_ctrl_reg; bool dbgrq; etm_ctrl_reg = etm_reg_lookup(etm, ETM_CTRL); if (!etm_ctrl_reg) return ERROR_FAIL; COMMAND_PARSE_ENABLE(CMD_ARGV[0], dbgrq); if (dbgrq) etm->control |= ETM_CTRL_DBGRQ; else etm->control &= ~ETM_CTRL_DBGRQ; /* etm->control will be written to hardware * the next time an "etm start" is issued. */ buf_set_u32(etm_ctrl_reg->value, 0, 32, etm->control); } command_print(CMD_CTX, "ETM: %s debug halt", (etm->control & ETM_CTRL_DBGRQ) ? "triggers" : "does not trigger"); return ERROR_OK; } COMMAND_HANDLER(handle_etm_analyze_command) { struct target *target; struct arm *arm; struct etm_context *etm_ctx; int retval; target = get_current_target(CMD_CTX); arm = target_to_arm(target); if (!is_arm(arm)) { command_print(CMD_CTX, "ETM: current target isn't an ARM"); return ERROR_FAIL; } etm_ctx = arm->etm; if (!etm_ctx) { command_print(CMD_CTX, "current target doesn't have an ETM configured"); return ERROR_FAIL; } retval = etmv1_analyze_trace(etm_ctx, CMD_CTX); if (retval != ERROR_OK) { /* FIX! error should be reported inside etmv1_analyze_trace() */ switch (retval) { case ERROR_ETM_ANALYSIS_FAILED: command_print(CMD_CTX, "further analysis failed (corrupted trace data or just end of data"); break; case ERROR_TRACE_INSTRUCTION_UNAVAILABLE: command_print(CMD_CTX, "no instruction for current address available, analysis aborted"); break; case ERROR_TRACE_IMAGE_UNAVAILABLE: command_print(CMD_CTX, "no image available for trace analysis"); break; default: command_print(CMD_CTX, "unknown error"); } } return retval; } static const struct command_registration etm_config_command_handlers[] = { { /* NOTE: with ADIv5, ETMs are accessed by DAP operations, * possibly over SWD, not JTAG scanchain 6 of 'target'. * * Also, these parameters don't match ETM v3+ modules... */ .name = "config", .handler = handle_etm_config_command, .mode = COMMAND_CONFIG, .help = "Set up ETM output port.", .usage = "target port_width port_mode clocking capture_driver", }, COMMAND_REGISTRATION_DONE }; const struct command_registration etm_command_handlers[] = { { .name = "etm", .mode = COMMAND_ANY, .help = "Emebdded Trace Macrocell command group", .usage = "", .chain = etm_config_command_handlers, }, COMMAND_REGISTRATION_DONE }; static const struct command_registration etm_exec_command_handlers[] = { { .name = "tracemode", .handler = handle_etm_tracemode_command, .mode = COMMAND_EXEC, .help = "configure/display trace mode", .usage = "('none'|'data'|'address'|'all') " "context_id_bits " "['enable'|'disable'] " "['enable'|'disable']", }, { .name = "info", .handler = handle_etm_info_command, .mode = COMMAND_EXEC, .usage = "", .help = "display info about the current target's ETM", }, { .name = "status", .handler = handle_etm_status_command, .mode = COMMAND_EXEC, .usage = "", .help = "display current target's ETM status", }, { .name = "start", .handler = handle_etm_start_command, .mode = COMMAND_EXEC, .usage = "", .help = "start ETM trace collection", }, { .name = "stop", .handler = handle_etm_stop_command, .mode = COMMAND_EXEC, .usage = "", .help = "stop ETM trace collection", }, { .name = "trigger_debug", .handler = handle_etm_trigger_debug_command, .mode = COMMAND_EXEC, .help = "enable/disable debug entry on trigger", .usage = "['enable'|'disable']", }, { .name = "analyze", .handler = handle_etm_analyze_command, .mode = COMMAND_EXEC, .usage = "", .help = "analyze collected ETM trace", }, { .name = "image", .handler = handle_etm_image_command, .mode = COMMAND_EXEC, .help = "load image from file with optional offset", .usage = " [base address] [type]", }, { .name = "dump", .handler = handle_etm_dump_command, .mode = COMMAND_EXEC, .help = "dump captured trace data to file", .usage = "filename", }, { .name = "load", .handler = handle_etm_load_command, .mode = COMMAND_EXEC, .usage = "", .help = "load trace data for analysis ", }, COMMAND_REGISTRATION_DONE }; static int etm_register_user_commands(struct command_context *cmd_ctx) { struct command *etm_cmd = command_find_in_context(cmd_ctx, "etm"); return register_commands(cmd_ctx, etm_cmd, etm_exec_command_handlers); } openocd-0.7.0/src/target/arm_disassembler.h0000644000175000001440000001074312134336410015626 00000000000000/*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef ARM_DISASSEMBLER_H #define ARM_DISASSEMBLER_H enum arm_instruction_type { ARM_UNKNOWN_INSTUCTION, /* Branch instructions */ ARM_B, ARM_BL, ARM_BX, ARM_BLX, /* Data processing instructions */ ARM_AND, ARM_EOR, ARM_SUB, ARM_RSB, ARM_ADD, ARM_ADC, ARM_SBC, ARM_RSC, ARM_TST, ARM_TEQ, ARM_CMP, ARM_CMN, ARM_ORR, ARM_MOV, ARM_BIC, ARM_MVN, /* Load/store instructions */ ARM_LDR, ARM_LDRB, ARM_LDRT, ARM_LDRBT, ARM_LDRH, ARM_LDRSB, ARM_LDRSH, ARM_LDM, ARM_STR, ARM_STRB, ARM_STRT, ARM_STRBT, ARM_STRH, ARM_STM, /* Status register access instructions */ ARM_MRS, ARM_MSR, /* Multiply instructions */ ARM_MUL, ARM_MLA, ARM_SMULL, ARM_SMLAL, ARM_UMULL, ARM_UMLAL, /* Miscellaneous instructions */ ARM_CLZ, /* Exception generating instructions */ ARM_BKPT, ARM_SWI, /* Coprocessor instructions */ ARM_CDP, ARM_LDC, ARM_STC, ARM_MCR, ARM_MRC, /* Semaphore instructions */ ARM_SWP, ARM_SWPB, /* Enhanced DSP extensions */ ARM_MCRR, ARM_MRRC, ARM_PLD, ARM_QADD, ARM_QDADD, ARM_QSUB, ARM_QDSUB, ARM_SMLAxy, ARM_SMLALxy, ARM_SMLAWy, ARM_SMULxy, ARM_SMULWy, ARM_LDRD, ARM_STRD, ARM_UNDEFINED_INSTRUCTION = 0xffffffff, }; struct arm_b_bl_bx_blx_instr { int reg_operand; uint32_t target_address; }; union arm_shifter_operand { struct { uint32_t immediate; } immediate; struct { uint8_t Rm; uint8_t shift; /* 0: LSL, 1: LSR, 2: ASR, 3: ROR, 4: RRX */ uint8_t shift_imm; } immediate_shift; struct { uint8_t Rm; uint8_t shift; uint8_t Rs; } register_shift; }; struct arm_data_proc_instr { int variant; /* 0: immediate, 1: immediate_shift, 2: register_shift */ uint8_t S; uint8_t Rn; uint8_t Rd; union arm_shifter_operand shifter_operand; }; struct arm_load_store_instr { uint8_t Rd; uint8_t Rn; uint8_t U; int index_mode; /* 0: offset, 1: pre-indexed, 2: post-indexed */ int offset_mode; /* 0: immediate, 1: (scaled) register */ union { uint32_t offset; struct { uint8_t Rm; uint8_t shift; /* 0: LSL, 1: LSR, 2: ASR, 3: ROR, 4: RRX */ uint8_t shift_imm; } reg; } offset; }; struct arm_load_store_multiple_instr { uint8_t Rn; uint32_t register_list; uint8_t addressing_mode; /* 0: IA, 1: IB, 2: DA, 3: DB */ uint8_t S; uint8_t W; }; struct arm_instruction { enum arm_instruction_type type; char text[128]; uint32_t opcode; /* return value ... Thumb-2 sizes vary */ unsigned instruction_size; union { struct arm_b_bl_bx_blx_instr b_bl_bx_blx; struct arm_data_proc_instr data_proc; struct arm_load_store_instr load_store; struct arm_load_store_multiple_instr load_store_multiple; } info; }; int arm_evaluate_opcode(uint32_t opcode, uint32_t address, struct arm_instruction *instruction); int thumb_evaluate_opcode(uint16_t opcode, uint32_t address, struct arm_instruction *instruction); int thumb2_opcode(struct target *target, uint32_t address, struct arm_instruction *instruction); int arm_access_size(struct arm_instruction *instruction); #define COND(opcode) (arm_condition_strings[(opcode & 0xf0000000) >> 28]) #endif /* ARM_DISASSEMBLER_H */ openocd-0.7.0/src/target/armv4_5_mmu.c0000644000175000001440000001340612134336410014437 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "target.h" #include "armv4_5_mmu.h" int armv4_5_mmu_translate_va(struct target *target, struct armv4_5_mmu_common *armv4_5_mmu, uint32_t va, uint32_t *cb, uint32_t *val) { uint32_t first_lvl_descriptor = 0x0; uint32_t second_lvl_descriptor = 0x0; uint32_t ttb; int retval; retval = armv4_5_mmu->get_ttb(target, &ttb); if (retval != ERROR_OK) return retval; retval = armv4_5_mmu_read_physical(target, armv4_5_mmu, (ttb & 0xffffc000) | ((va & 0xfff00000) >> 18), 4, 1, (uint8_t *)&first_lvl_descriptor); if (retval != ERROR_OK) return retval; first_lvl_descriptor = target_buffer_get_u32(target, (uint8_t *)&first_lvl_descriptor); LOG_DEBUG("1st lvl desc: %8.8" PRIx32 "", first_lvl_descriptor); if ((first_lvl_descriptor & 0x3) == 0) { LOG_ERROR("Address translation failure"); return ERROR_TARGET_TRANSLATION_FAULT; } if (!armv4_5_mmu->has_tiny_pages && ((first_lvl_descriptor & 0x3) == 3)) { LOG_ERROR("Address translation failure"); return ERROR_TARGET_TRANSLATION_FAULT; } if ((first_lvl_descriptor & 0x3) == 2) { /* section descriptor */ *cb = (first_lvl_descriptor & 0xc) >> 2; *val = (first_lvl_descriptor & 0xfff00000) | (va & 0x000fffff); return ERROR_OK; } if ((first_lvl_descriptor & 0x3) == 1) { /* coarse page table */ retval = armv4_5_mmu_read_physical(target, armv4_5_mmu, (first_lvl_descriptor & 0xfffffc00) | ((va & 0x000ff000) >> 10), 4, 1, (uint8_t *)&second_lvl_descriptor); if (retval != ERROR_OK) return retval; } else if ((first_lvl_descriptor & 0x3) == 3) { /* fine page table */ retval = armv4_5_mmu_read_physical(target, armv4_5_mmu, (first_lvl_descriptor & 0xfffff000) | ((va & 0x000ffc00) >> 8), 4, 1, (uint8_t *)&second_lvl_descriptor); if (retval != ERROR_OK) return retval; } second_lvl_descriptor = target_buffer_get_u32(target, (uint8_t *)&second_lvl_descriptor); LOG_DEBUG("2nd lvl desc: %8.8" PRIx32 "", second_lvl_descriptor); if ((second_lvl_descriptor & 0x3) == 0) { LOG_ERROR("Address translation failure"); return ERROR_TARGET_TRANSLATION_FAULT; } /* cacheable/bufferable is always specified in bits 3-2 */ *cb = (second_lvl_descriptor & 0xc) >> 2; if ((second_lvl_descriptor & 0x3) == 1) { /* large page descriptor */ *val = (second_lvl_descriptor & 0xffff0000) | (va & 0x0000ffff); return ERROR_OK; } if ((second_lvl_descriptor & 0x3) == 2) { /* small page descriptor */ *val = (second_lvl_descriptor & 0xfffff000) | (va & 0x00000fff); return ERROR_OK; } if ((second_lvl_descriptor & 0x3) == 3) { /* tiny page descriptor */ *val = (second_lvl_descriptor & 0xfffffc00) | (va & 0x000003ff); return ERROR_OK; } /* should not happen */ LOG_ERROR("Address translation failure"); return ERROR_TARGET_TRANSLATION_FAULT; } int armv4_5_mmu_read_physical(struct target *target, struct armv4_5_mmu_common *armv4_5_mmu, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) { int retval; if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; /* disable MMU and data (or unified) cache */ retval = armv4_5_mmu->disable_mmu_caches(target, 1, 1, 0); if (retval != ERROR_OK) return retval; retval = armv4_5_mmu->read_memory(target, address, size, count, buffer); if (retval != ERROR_OK) return retval; /* reenable MMU / cache */ retval = armv4_5_mmu->enable_mmu_caches(target, armv4_5_mmu->mmu_enabled, armv4_5_mmu->armv4_5_cache.d_u_cache_enabled, armv4_5_mmu->armv4_5_cache.i_cache_enabled); if (retval != ERROR_OK) return retval; return retval; } int armv4_5_mmu_write_physical(struct target *target, struct armv4_5_mmu_common *armv4_5_mmu, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { int retval; if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; /* disable MMU and data (or unified) cache */ retval = armv4_5_mmu->disable_mmu_caches(target, 1, 1, 0); if (retval != ERROR_OK) return retval; retval = armv4_5_mmu->write_memory(target, address, size, count, buffer); if (retval != ERROR_OK) return retval; /* reenable MMU / cache */ retval = armv4_5_mmu->enable_mmu_caches(target, armv4_5_mmu->mmu_enabled, armv4_5_mmu->armv4_5_cache.d_u_cache_enabled, armv4_5_mmu->armv4_5_cache.i_cache_enabled); if (retval != ERROR_OK) return retval; return retval; } openocd-0.7.0/src/target/etb.c0000644000175000001440000004624712134336410013067 00000000000000/*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm.h" #include "etm.h" #include "etb.h" #include "register.h" static char *etb_reg_list[] = { "ETB_identification", "ETB_ram_depth", "ETB_ram_width", "ETB_status", "ETB_ram_data", "ETB_ram_read_pointer", "ETB_ram_write_pointer", "ETB_trigger_counter", "ETB_control", }; static int etb_get_reg(struct reg *reg); static int etb_set_instr(struct etb *etb, uint32_t new_instr) { struct jtag_tap *tap; tap = etb->tap; if (tap == NULL) return ERROR_FAIL; if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != new_instr) { struct scan_field field; field.num_bits = tap->ir_length; void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1); field.out_value = t; buf_set_u32(t, 0, field.num_bits, new_instr); field.in_value = NULL; jtag_add_ir_scan(tap, &field, TAP_IDLE); free(t); } return ERROR_OK; } static int etb_scann(struct etb *etb, uint32_t new_scan_chain) { if (etb->cur_scan_chain != new_scan_chain) { struct scan_field field; field.num_bits = 5; void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1); field.out_value = t; buf_set_u32(t, 0, field.num_bits, new_scan_chain); field.in_value = NULL; /* select INTEST instruction */ etb_set_instr(etb, 0x2); jtag_add_dr_scan(etb->tap, 1, &field, TAP_IDLE); etb->cur_scan_chain = new_scan_chain; free(t); } return ERROR_OK; } static int etb_read_reg_w_check(struct reg *, uint8_t *, uint8_t *); static int etb_set_reg_w_exec(struct reg *, uint8_t *); static int etb_read_reg(struct reg *reg) { return etb_read_reg_w_check(reg, NULL, NULL); } static int etb_get_reg(struct reg *reg) { int retval; retval = etb_read_reg(reg); if (retval != ERROR_OK) { LOG_ERROR("BUG: error scheduling ETB register read"); return retval; } retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("ETB register read failed"); return retval; } return ERROR_OK; } static const struct reg_arch_type etb_reg_type = { .get = etb_get_reg, .set = etb_set_reg_w_exec, }; struct reg_cache *etb_build_reg_cache(struct etb *etb) { struct reg_cache *reg_cache = malloc(sizeof(struct reg_cache)); struct reg *reg_list = NULL; struct etb_reg *arch_info = NULL; int num_regs = 9; int i; /* the actual registers are kept in two arrays */ reg_list = calloc(num_regs, sizeof(struct reg)); arch_info = calloc(num_regs, sizeof(struct etb_reg)); /* fill in values for the reg cache */ reg_cache->name = "etb registers"; reg_cache->next = NULL; reg_cache->reg_list = reg_list; reg_cache->num_regs = num_regs; /* set up registers */ for (i = 0; i < num_regs; i++) { reg_list[i].name = etb_reg_list[i]; reg_list[i].size = 32; reg_list[i].dirty = 0; reg_list[i].valid = 0; reg_list[i].value = calloc(1, 4); reg_list[i].arch_info = &arch_info[i]; reg_list[i].type = &etb_reg_type; reg_list[i].size = 32; arch_info[i].addr = i; arch_info[i].etb = etb; } return reg_cache; } static void etb_getbuf(jtag_callback_data_t arg) { uint8_t *in = (uint8_t *)arg; *((uint32_t *)arg) = buf_get_u32(in, 0, 32); } static int etb_read_ram(struct etb *etb, uint32_t *data, int num_frames) { struct scan_field fields[3]; int i; etb_scann(etb, 0x0); etb_set_instr(etb, 0xc); fields[0].num_bits = 32; fields[0].out_value = NULL; fields[0].in_value = NULL; fields[1].num_bits = 7; uint8_t temp1; fields[1].out_value = &temp1; buf_set_u32(&temp1, 0, 7, 4); fields[1].in_value = NULL; fields[2].num_bits = 1; uint8_t temp2; fields[2].out_value = &temp2; buf_set_u32(&temp2, 0, 1, 0); fields[2].in_value = NULL; jtag_add_dr_scan(etb->tap, 3, fields, TAP_IDLE); for (i = 0; i < num_frames; i++) { /* ensure nR/W reamins set to read */ buf_set_u32(&temp2, 0, 1, 0); /* address remains set to 0x4 (RAM data) until we read the last frame */ if (i < num_frames - 1) buf_set_u32(&temp1, 0, 7, 4); else buf_set_u32(&temp1, 0, 7, 0); fields[0].in_value = (uint8_t *)(data + i); jtag_add_dr_scan(etb->tap, 3, fields, TAP_IDLE); jtag_add_callback(etb_getbuf, (jtag_callback_data_t)(data + i)); } jtag_execute_queue(); return ERROR_OK; } static int etb_read_reg_w_check(struct reg *reg, uint8_t *check_value, uint8_t *check_mask) { struct etb_reg *etb_reg = reg->arch_info; uint8_t reg_addr = etb_reg->addr & 0x7f; struct scan_field fields[3]; LOG_DEBUG("%i", (int)(etb_reg->addr)); etb_scann(etb_reg->etb, 0x0); etb_set_instr(etb_reg->etb, 0xc); fields[0].num_bits = 32; fields[0].out_value = reg->value; fields[0].in_value = NULL; fields[0].check_value = NULL; fields[0].check_mask = NULL; fields[1].num_bits = 7; uint8_t temp1; fields[1].out_value = &temp1; buf_set_u32(&temp1, 0, 7, reg_addr); fields[1].in_value = NULL; fields[1].check_value = NULL; fields[1].check_mask = NULL; fields[2].num_bits = 1; uint8_t temp2; fields[2].out_value = &temp2; buf_set_u32(&temp2, 0, 1, 0); fields[2].in_value = NULL; fields[2].check_value = NULL; fields[2].check_mask = NULL; jtag_add_dr_scan(etb_reg->etb->tap, 3, fields, TAP_IDLE); /* read the identification register in the second run, to make sure we * don't read the ETB data register twice, skipping every second entry */ buf_set_u32(&temp1, 0, 7, 0x0); fields[0].in_value = reg->value; fields[0].check_value = check_value; fields[0].check_mask = check_mask; jtag_add_dr_scan_check(etb_reg->etb->tap, 3, fields, TAP_IDLE); return ERROR_OK; } static int etb_write_reg(struct reg *, uint32_t); static int etb_set_reg(struct reg *reg, uint32_t value) { int retval; retval = etb_write_reg(reg, value); if (retval != ERROR_OK) { LOG_ERROR("BUG: error scheduling ETB register write"); return retval; } buf_set_u32(reg->value, 0, reg->size, value); reg->valid = 1; reg->dirty = 0; return ERROR_OK; } static int etb_set_reg_w_exec(struct reg *reg, uint8_t *buf) { int retval; etb_set_reg(reg, buf_get_u32(buf, 0, reg->size)); retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("ETB: register write failed"); return retval; } return ERROR_OK; } static int etb_write_reg(struct reg *reg, uint32_t value) { struct etb_reg *etb_reg = reg->arch_info; uint8_t reg_addr = etb_reg->addr & 0x7f; struct scan_field fields[3]; LOG_DEBUG("%i: 0x%8.8" PRIx32 "", (int)(etb_reg->addr), value); etb_scann(etb_reg->etb, 0x0); etb_set_instr(etb_reg->etb, 0xc); fields[0].num_bits = 32; uint8_t temp0[4]; fields[0].out_value = temp0; buf_set_u32(&temp0, 0, 32, value); fields[0].in_value = NULL; fields[1].num_bits = 7; uint8_t temp1; fields[1].out_value = &temp1; buf_set_u32(&temp1, 0, 7, reg_addr); fields[1].in_value = NULL; fields[2].num_bits = 1; uint8_t temp2; fields[2].out_value = &temp2; buf_set_u32(&temp2, 0, 1, 1); fields[2].in_value = NULL; jtag_add_dr_scan(etb_reg->etb->tap, 3, fields, TAP_IDLE); return ERROR_OK; } COMMAND_HANDLER(handle_etb_config_command) { struct target *target; struct jtag_tap *tap; struct arm *arm; if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; target = get_target(CMD_ARGV[0]); if (!target) { LOG_ERROR("ETB: target '%s' not defined", CMD_ARGV[0]); return ERROR_FAIL; } arm = target_to_arm(target); if (!is_arm(arm)) { command_print(CMD_CTX, "ETB: '%s' isn't an ARM", CMD_ARGV[0]); return ERROR_FAIL; } tap = jtag_tap_by_string(CMD_ARGV[1]); if (tap == NULL) { command_print(CMD_CTX, "ETB: TAP %s does not exist", CMD_ARGV[1]); return ERROR_FAIL; } if (arm->etm) { struct etb *etb = malloc(sizeof(struct etb)); arm->etm->capture_driver_priv = etb; etb->tap = tap; etb->cur_scan_chain = 0xffffffff; etb->reg_cache = NULL; etb->ram_width = 0; etb->ram_depth = 0; } else { LOG_ERROR("ETM: target has no ETM defined, ETB left unconfigured"); return ERROR_FAIL; } return ERROR_OK; } COMMAND_HANDLER(handle_etb_trigger_percent_command) { struct target *target; struct arm *arm; struct etm_context *etm; struct etb *etb; target = get_current_target(CMD_CTX); arm = target_to_arm(target); if (!is_arm(arm)) { command_print(CMD_CTX, "ETB: current target isn't an ARM"); return ERROR_FAIL; } etm = arm->etm; if (!etm) { command_print(CMD_CTX, "ETB: target has no ETM configured"); return ERROR_FAIL; } if (etm->capture_driver != &etb_capture_driver) { command_print(CMD_CTX, "ETB: target not using ETB"); return ERROR_FAIL; } etb = arm->etm->capture_driver_priv; if (CMD_ARGC > 0) { uint32_t new_value; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], new_value); if ((new_value < 2) || (new_value > 100)) command_print(CMD_CTX, "valid percentages are 2%% to 100%%"); else etb->trigger_percent = (unsigned) new_value; } command_print(CMD_CTX, "%d percent of tracebuffer fills after trigger", etb->trigger_percent); return ERROR_OK; } static const struct command_registration etb_config_command_handlers[] = { { /* NOTE: with ADIv5, ETBs are accessed using DAP operations, * possibly over SWD, not through separate TAPs... */ .name = "config", .handler = handle_etb_config_command, .mode = COMMAND_CONFIG, .help = "Associate ETB with target and JTAG TAP.", .usage = "target tap", }, { .name = "trigger_percent", .handler = handle_etb_trigger_percent_command, .mode = COMMAND_EXEC, .help = "Set percent of trace buffer to be filled " "after the trigger occurs (2..100).", .usage = "[percent]", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration etb_command_handlers[] = { { .name = "etb", .mode = COMMAND_ANY, .help = "Emebdded Trace Buffer command group", .chain = etb_config_command_handlers, }, COMMAND_REGISTRATION_DONE }; static int etb_init(struct etm_context *etm_ctx) { struct etb *etb = etm_ctx->capture_driver_priv; etb->etm_ctx = etm_ctx; /* identify ETB RAM depth and width */ etb_read_reg(&etb->reg_cache->reg_list[ETB_RAM_DEPTH]); etb_read_reg(&etb->reg_cache->reg_list[ETB_RAM_WIDTH]); jtag_execute_queue(); etb->ram_depth = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_DEPTH].value, 0, 32); etb->ram_width = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WIDTH].value, 0, 32); etb->trigger_percent = 50; return ERROR_OK; } static trace_status_t etb_status(struct etm_context *etm_ctx) { struct etb *etb = etm_ctx->capture_driver_priv; struct reg *control = &etb->reg_cache->reg_list[ETB_CTRL]; struct reg *status = &etb->reg_cache->reg_list[ETB_STATUS]; trace_status_t retval = 0; int etb_timeout = 100; etb->etm_ctx = etm_ctx; /* read control and status registers */ etb_read_reg(control); etb_read_reg(status); jtag_execute_queue(); /* See if it's (still) active */ retval = buf_get_u32(control->value, 0, 1) ? TRACE_RUNNING : TRACE_IDLE; /* check Full bit to identify wraparound/overflow */ if (buf_get_u32(status->value, 0, 1) == 1) retval |= TRACE_OVERFLOWED; /* check Triggered bit to identify trigger condition */ if (buf_get_u32(status->value, 1, 1) == 1) retval |= TRACE_TRIGGERED; /* check AcqComp to see if trigger counter dropped to zero */ if (buf_get_u32(status->value, 2, 1) == 1) { /* wait for DFEmpty */ while (etb_timeout-- && buf_get_u32(status->value, 3, 1) == 0) etb_get_reg(status); if (etb_timeout == 0) LOG_ERROR("ETB: DFEmpty won't go high, status 0x%02x", (unsigned) buf_get_u32(status->value, 0, 4)); if (!(etm_ctx->capture_status & TRACE_TRIGGERED)) LOG_WARNING("ETB: trace complete without triggering?"); retval |= TRACE_COMPLETED; } /* NOTE: using a trigger is optional; and at least ETB11 has a mode * where it can ignore the trigger counter. */ /* update recorded state */ etm_ctx->capture_status = retval; return retval; } static int etb_read_trace(struct etm_context *etm_ctx) { struct etb *etb = etm_ctx->capture_driver_priv; int first_frame = 0; int num_frames = etb->ram_depth; uint32_t *trace_data = NULL; int i, j; etb_read_reg(&etb->reg_cache->reg_list[ETB_STATUS]); etb_read_reg(&etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER]); jtag_execute_queue(); /* check if we overflowed, and adjust first frame of the trace accordingly * if we didn't overflow, read only up to the frame that would be written next, * i.e. don't read invalid entries */ if (buf_get_u32(etb->reg_cache->reg_list[ETB_STATUS].value, 0, 1)) first_frame = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER].value, 0, 32); else num_frames = buf_get_u32(etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER].value, 0, 32); etb_write_reg(&etb->reg_cache->reg_list[ETB_RAM_READ_POINTER], first_frame); /* read data into temporary array for unpacking */ trace_data = malloc(sizeof(uint32_t) * num_frames); etb_read_ram(etb, trace_data, num_frames); if (etm_ctx->trace_depth > 0) free(etm_ctx->trace_data); if ((etm_ctx->control & ETM_PORT_WIDTH_MASK) == ETM_PORT_4BIT) etm_ctx->trace_depth = num_frames * 3; else if ((etm_ctx->control & ETM_PORT_WIDTH_MASK) == ETM_PORT_8BIT) etm_ctx->trace_depth = num_frames * 2; else etm_ctx->trace_depth = num_frames; etm_ctx->trace_data = malloc(sizeof(struct etmv1_trace_data) * etm_ctx->trace_depth); for (i = 0, j = 0; i < num_frames; i++) { if ((etm_ctx->control & ETM_PORT_WIDTH_MASK) == ETM_PORT_4BIT) { /* trace word j */ etm_ctx->trace_data[j].pipestat = trace_data[i] & 0x7; etm_ctx->trace_data[j].packet = (trace_data[i] & 0x78) >> 3; etm_ctx->trace_data[j].flags = 0; if ((trace_data[i] & 0x80) >> 7) etm_ctx->trace_data[j].flags |= ETMV1_TRACESYNC_CYCLE; if (etm_ctx->trace_data[j].pipestat == STAT_TR) { etm_ctx->trace_data[j].pipestat = etm_ctx->trace_data[j].packet & 0x7; etm_ctx->trace_data[j].flags |= ETMV1_TRIGGER_CYCLE; } /* trace word j + 1 */ etm_ctx->trace_data[j + 1].pipestat = (trace_data[i] & 0x100) >> 8; etm_ctx->trace_data[j + 1].packet = (trace_data[i] & 0x7800) >> 11; etm_ctx->trace_data[j + 1].flags = 0; if ((trace_data[i] & 0x8000) >> 15) etm_ctx->trace_data[j + 1].flags |= ETMV1_TRACESYNC_CYCLE; if (etm_ctx->trace_data[j + 1].pipestat == STAT_TR) { etm_ctx->trace_data[j + 1].pipestat = etm_ctx->trace_data[j + 1].packet & 0x7; etm_ctx->trace_data[j + 1].flags |= ETMV1_TRIGGER_CYCLE; } /* trace word j + 2 */ etm_ctx->trace_data[j + 2].pipestat = (trace_data[i] & 0x10000) >> 16; etm_ctx->trace_data[j + 2].packet = (trace_data[i] & 0x780000) >> 19; etm_ctx->trace_data[j + 2].flags = 0; if ((trace_data[i] & 0x800000) >> 23) etm_ctx->trace_data[j + 2].flags |= ETMV1_TRACESYNC_CYCLE; if (etm_ctx->trace_data[j + 2].pipestat == STAT_TR) { etm_ctx->trace_data[j + 2].pipestat = etm_ctx->trace_data[j + 2].packet & 0x7; etm_ctx->trace_data[j + 2].flags |= ETMV1_TRIGGER_CYCLE; } j += 3; } else if ((etm_ctx->control & ETM_PORT_WIDTH_MASK) == ETM_PORT_8BIT) { /* trace word j */ etm_ctx->trace_data[j].pipestat = trace_data[i] & 0x7; etm_ctx->trace_data[j].packet = (trace_data[i] & 0x7f8) >> 3; etm_ctx->trace_data[j].flags = 0; if ((trace_data[i] & 0x800) >> 11) etm_ctx->trace_data[j].flags |= ETMV1_TRACESYNC_CYCLE; if (etm_ctx->trace_data[j].pipestat == STAT_TR) { etm_ctx->trace_data[j].pipestat = etm_ctx->trace_data[j].packet & 0x7; etm_ctx->trace_data[j].flags |= ETMV1_TRIGGER_CYCLE; } /* trace word j + 1 */ etm_ctx->trace_data[j + 1].pipestat = (trace_data[i] & 0x7000) >> 12; etm_ctx->trace_data[j + 1].packet = (trace_data[i] & 0x7f8000) >> 15; etm_ctx->trace_data[j + 1].flags = 0; if ((trace_data[i] & 0x800000) >> 23) etm_ctx->trace_data[j + 1].flags |= ETMV1_TRACESYNC_CYCLE; if (etm_ctx->trace_data[j + 1].pipestat == STAT_TR) { etm_ctx->trace_data[j + 1].pipestat = etm_ctx->trace_data[j + 1].packet & 0x7; etm_ctx->trace_data[j + 1].flags |= ETMV1_TRIGGER_CYCLE; } j += 2; } else { /* trace word j */ etm_ctx->trace_data[j].pipestat = trace_data[i] & 0x7; etm_ctx->trace_data[j].packet = (trace_data[i] & 0x7fff8) >> 3; etm_ctx->trace_data[j].flags = 0; if ((trace_data[i] & 0x80000) >> 19) etm_ctx->trace_data[j].flags |= ETMV1_TRACESYNC_CYCLE; if (etm_ctx->trace_data[j].pipestat == STAT_TR) { etm_ctx->trace_data[j].pipestat = etm_ctx->trace_data[j].packet & 0x7; etm_ctx->trace_data[j].flags |= ETMV1_TRIGGER_CYCLE; } j += 1; } } free(trace_data); return ERROR_OK; } static int etb_start_capture(struct etm_context *etm_ctx) { struct etb *etb = etm_ctx->capture_driver_priv; uint32_t etb_ctrl_value = 0x1; uint32_t trigger_count; if ((etm_ctx->control & ETM_PORT_MODE_MASK) == ETM_PORT_DEMUXED) { if ((etm_ctx->control & ETM_PORT_WIDTH_MASK) != ETM_PORT_8BIT) { LOG_ERROR("ETB can't run in demultiplexed mode with a 4 or 16 bit port"); return ERROR_ETM_PORTMODE_NOT_SUPPORTED; } etb_ctrl_value |= 0x2; } if ((etm_ctx->control & ETM_PORT_MODE_MASK) == ETM_PORT_MUXED) { LOG_ERROR("ETB: can't run in multiplexed mode"); return ERROR_ETM_PORTMODE_NOT_SUPPORTED; } trigger_count = (etb->ram_depth * etb->trigger_percent) / 100; etb_write_reg(&etb->reg_cache->reg_list[ETB_TRIGGER_COUNTER], trigger_count); etb_write_reg(&etb->reg_cache->reg_list[ETB_RAM_WRITE_POINTER], 0x0); etb_write_reg(&etb->reg_cache->reg_list[ETB_CTRL], etb_ctrl_value); jtag_execute_queue(); /* we're starting a new trace, initialize capture status */ etm_ctx->capture_status = TRACE_RUNNING; return ERROR_OK; } static int etb_stop_capture(struct etm_context *etm_ctx) { struct etb *etb = etm_ctx->capture_driver_priv; struct reg *etb_ctrl_reg = &etb->reg_cache->reg_list[ETB_CTRL]; etb_write_reg(etb_ctrl_reg, 0x0); jtag_execute_queue(); /* trace stopped, just clear running flag, but preserve others */ etm_ctx->capture_status &= ~TRACE_RUNNING; return ERROR_OK; } struct etm_capture_driver etb_capture_driver = { .name = "etb", .commands = etb_command_handlers, .init = etb_init, .status = etb_status, .start_capture = etb_start_capture, .stop_capture = etb_stop_capture, .read_trace = etb_read_trace, }; openocd-0.7.0/src/target/arm_dpm.c0000644000175000001440000006132612134336410013727 00000000000000/* * Copyright (C) 2009 by David Brownell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 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. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm.h" #include "arm_dpm.h" #include #include "register.h" #include "breakpoints.h" #include "target_type.h" #include "arm_opcodes.h" /** * @file * Implements various ARM DPM operations using architectural debug registers. * These routines layer over core-specific communication methods to cope with * implementation differences between cores like ARM1136 and Cortex-A8. * * The "Debug Programmers' Model" (DPM) for ARMv6 and ARMv7 is defined by * Part C (Debug Architecture) of the ARM Architecture Reference Manual, * ARMv7-A and ARMv7-R edition (ARM DDI 0406B). In OpenOCD, DPM operations * are abstracted through internal programming interfaces to share code and * to minimize needless differences in debug behavior between cores. */ /*----------------------------------------------------------------------*/ /* * Coprocessor support */ /* Read coprocessor */ static int dpm_mrc(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t *value) { struct arm *arm = target_to_arm(target); struct arm_dpm *dpm = arm->dpm; int retval; retval = dpm->prepare(dpm); if (retval != ERROR_OK) return retval; LOG_DEBUG("MRC p%d, %d, r0, c%d, c%d, %d", cpnum, (int) op1, (int) CRn, (int) CRm, (int) op2); /* read coprocessor register into R0; return via DCC */ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(cpnum, op1, 0, CRn, CRm, op2), value); /* (void) */ dpm->finish(dpm); return retval; } static int dpm_mcr(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t value) { struct arm *arm = target_to_arm(target); struct arm_dpm *dpm = arm->dpm; int retval; retval = dpm->prepare(dpm); if (retval != ERROR_OK) return retval; LOG_DEBUG("MCR p%d, %d, r0, c%d, c%d, %d", cpnum, (int) op1, (int) CRn, (int) CRm, (int) op2); /* read DCC into r0; then write coprocessor register from R0 */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(cpnum, op1, 0, CRn, CRm, op2), value); /* (void) */ dpm->finish(dpm); return retval; } /*----------------------------------------------------------------------*/ /* * Register access utilities */ /* Toggles between recorded core mode (USR, SVC, etc) and a temporary one. * Routines *must* restore the original mode before returning!! */ int dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode) { int retval; uint32_t cpsr; /* restore previous mode */ if (mode == ARM_MODE_ANY) cpsr = buf_get_u32(dpm->arm->cpsr->value, 0, 32); /* else force to the specified mode */ else cpsr = mode; retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MSR_GP(0, 0xf, 0), cpsr); if (retval != ERROR_OK) return retval; if (dpm->instr_cpsr_sync) retval = dpm->instr_cpsr_sync(dpm); return retval; } /* just read the register -- rely on the core mode being right */ static int dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) { uint32_t value; int retval; switch (regnum) { case 0 ... 14: /* return via DCC: "MCR p14, 0, Rnum, c0, c5, 0" */ retval = dpm->instr_read_data_dcc(dpm, ARMV4_5_MCR(14, 0, regnum, 0, 5, 0), &value); break; case 15:/* PC * "MOV r0, pc"; then return via DCC */ retval = dpm->instr_read_data_r0(dpm, 0xe1a0000f, &value); /* NOTE: this seems like a slightly awkward place to update * this value ... but if the PC gets written (the only way * to change what we compute), the arch spec says subsequent * reads return values which are "unpredictable". So this * is always right except in those broken-by-intent cases. */ switch (dpm->arm->core_state) { case ARM_STATE_ARM: value -= 8; break; case ARM_STATE_THUMB: case ARM_STATE_THUMB_EE: value -= 4; break; case ARM_STATE_JAZELLE: /* core-specific ... ? */ LOG_WARNING("Jazelle PC adjustment unknown"); break; } break; default: /* 16: "MRS r0, CPSR"; then return via DCC * 17: "MRS r0, SPSR"; then return via DCC */ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRS(0, regnum & 1), &value); break; } if (retval == ERROR_OK) { buf_set_u32(r->value, 0, 32, value); r->valid = true; r->dirty = false; LOG_DEBUG("READ: %s, %8.8x", r->name, (unsigned) value); } return retval; } /* just write the register -- rely on the core mode being right */ static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) { int retval; uint32_t value = buf_get_u32(r->value, 0, 32); switch (regnum) { case 0 ... 14: /* load register from DCC: "MRC p14, 0, Rnum, c0, c5, 0" */ retval = dpm->instr_write_data_dcc(dpm, ARMV4_5_MRC(14, 0, regnum, 0, 5, 0), value); break; case 15:/* PC * read r0 from DCC; then "MOV pc, r0" */ retval = dpm->instr_write_data_r0(dpm, 0xe1a0f000, value); break; default: /* 16: read r0 from DCC, then "MSR r0, CPSR_cxsf" * 17: read r0 from DCC, then "MSR r0, SPSR_cxsf" */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MSR_GP(0, 0xf, regnum & 1), value); if (retval != ERROR_OK) return retval; if (regnum == 16 && dpm->instr_cpsr_sync) retval = dpm->instr_cpsr_sync(dpm); break; } if (retval == ERROR_OK) { r->dirty = false; LOG_DEBUG("WRITE: %s, %8.8x", r->name, (unsigned) value); } return retval; } /** * Read basic registers of the the current context: R0 to R15, and CPSR; * sets the core mode (such as USR or IRQ) and state (such as ARM or Thumb). * In normal operation this is called on entry to halting debug state, * possibly after some other operations supporting restore of debug state * or making sure the CPU is fully idle (drain write buffer, etc). */ int arm_dpm_read_current_registers(struct arm_dpm *dpm) { struct arm *arm = dpm->arm; uint32_t cpsr; int retval; struct reg *r; retval = dpm->prepare(dpm); if (retval != ERROR_OK) return retval; /* read R0 first (it's used for scratch), then CPSR */ r = arm->core_cache->reg_list + 0; if (!r->valid) { retval = dpm_read_reg(dpm, r, 0); if (retval != ERROR_OK) goto fail; } r->dirty = true; retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRS(0, 0), &cpsr); if (retval != ERROR_OK) goto fail; /* update core mode and state, plus shadow mapping for R8..R14 */ arm_set_cpsr(arm, cpsr); /* REVISIT we can probably avoid reading R1..R14, saving time... */ for (unsigned i = 1; i < 16; i++) { r = arm_reg_current(arm, i); if (r->valid) continue; retval = dpm_read_reg(dpm, r, i); if (retval != ERROR_OK) goto fail; } /* NOTE: SPSR ignored (if it's even relevant). */ /* REVISIT the debugger can trigger various exceptions. See the * ARMv7A architecture spec, section C5.7, for more info about * what defenses are needed; v6 debug has the most issues. */ fail: /* (void) */ dpm->finish(dpm); return retval; } /* Avoid needless I/O ... leave breakpoints and watchpoints alone * unless they're removed, or need updating because of single-stepping * or running debugger code. */ static int dpm_maybe_update_bpwp(struct arm_dpm *dpm, bool bpwp, struct dpm_bpwp *xp, int *set_p) { int retval = ERROR_OK; bool disable; if (!set_p) { if (!xp->dirty) goto done; xp->dirty = false; /* removed or startup; we must disable it */ disable = true; } else if (bpwp) { if (!xp->dirty) goto done; /* disabled, but we must set it */ xp->dirty = disable = false; *set_p = true; } else { if (!*set_p) goto done; /* set, but we must temporarily disable it */ xp->dirty = disable = true; *set_p = false; } if (disable) retval = dpm->bpwp_disable(dpm, xp->number); else retval = dpm->bpwp_enable(dpm, xp->number, xp->address, xp->control); if (retval != ERROR_OK) LOG_ERROR("%s: can't %s HW %spoint %d", disable ? "disable" : "enable", target_name(dpm->arm->target), (xp->number < 16) ? "break" : "watch", xp->number & 0xf); done: return retval; } static int dpm_add_breakpoint(struct target *target, struct breakpoint *bp); /** * Writes all modified core registers for all processor modes. In normal * operation this is called on exit from halting debug state. * * @param dpm: represents the processor * @param bpwp: true ensures breakpoints and watchpoints are set, * false ensures they are cleared */ int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp) { struct arm *arm = dpm->arm; struct reg_cache *cache = arm->core_cache; int retval; bool did_write; retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; /* If we're managing hardware breakpoints for this core, enable * or disable them as requested. * * REVISIT We don't yet manage them for ANY cores. Eventually * we should be able to assume we handle them; but until then, * cope with the hand-crafted breakpoint code. */ if (arm->target->type->add_breakpoint == dpm_add_breakpoint) { for (unsigned i = 0; i < dpm->nbp; i++) { struct dpm_bp *dbp = dpm->dbp + i; struct breakpoint *bp = dbp->bp; retval = dpm_maybe_update_bpwp(dpm, bpwp, &dbp->bpwp, bp ? &bp->set : NULL); if (retval != ERROR_OK) goto done; } } /* enable/disable watchpoints */ for (unsigned i = 0; i < dpm->nwp; i++) { struct dpm_wp *dwp = dpm->dwp + i; struct watchpoint *wp = dwp->wp; retval = dpm_maybe_update_bpwp(dpm, bpwp, &dwp->bpwp, wp ? &wp->set : NULL); if (retval != ERROR_OK) goto done; } /* NOTE: writes to breakpoint and watchpoint registers might * be queued, and need (efficient/batched) flushing later. */ /* Scan the registers until we find one that's both dirty and * eligible for flushing. Flush that and everything else that * shares the same core mode setting. Typically this won't * actually find anything to do... */ do { enum arm_mode mode = ARM_MODE_ANY; did_write = false; /* check everything except our scratch register R0 */ for (unsigned i = 1; i < cache->num_regs; i++) { struct arm_reg *r; unsigned regnum; /* also skip PC, CPSR, and non-dirty */ if (i == 15) continue; if (arm->cpsr == cache->reg_list + i) continue; if (!cache->reg_list[i].dirty) continue; r = cache->reg_list[i].arch_info; regnum = r->num; /* may need to pick and set a mode */ if (!did_write) { enum arm_mode tmode; did_write = true; mode = tmode = r->mode; /* cope with special cases */ switch (regnum) { case 8 ... 12: /* r8..r12 "anything but FIQ" case; * we "know" core mode is accurate * since we haven't changed it yet */ if (arm->core_mode == ARM_MODE_FIQ && ARM_MODE_ANY != mode) tmode = ARM_MODE_USR; break; case 16: /* SPSR */ regnum++; break; } /* REVISIT error checks */ if (tmode != ARM_MODE_ANY) { retval = dpm_modeswitch(dpm, tmode); if (retval != ERROR_OK) goto done; } } if (r->mode != mode) continue; retval = dpm_write_reg(dpm, &cache->reg_list[i], regnum); if (retval != ERROR_OK) goto done; } } while (did_write); /* Restore original CPSR ... assuming either that we changed it, * or it's dirty. Must write PC to ensure the return address is * defined, and must not write it before CPSR. */ retval = dpm_modeswitch(dpm, ARM_MODE_ANY); if (retval != ERROR_OK) goto done; arm->cpsr->dirty = false; retval = dpm_write_reg(dpm, arm->pc, 15); if (retval != ERROR_OK) goto done; arm->pc->dirty = false; /* flush R0 -- it's *very* dirty by now */ retval = dpm_write_reg(dpm, &cache->reg_list[0], 0); if (retval != ERROR_OK) goto done; cache->reg_list[0].dirty = false; /* (void) */ dpm->finish(dpm); done: return retval; } /* Returns ARM_MODE_ANY or temporary mode to use while reading the * specified register ... works around flakiness from ARM core calls. * Caller already filtered out SPSR access; mode is never MODE_SYS * or MODE_ANY. */ static enum arm_mode dpm_mapmode(struct arm *arm, unsigned num, enum arm_mode mode) { enum arm_mode amode = arm->core_mode; /* don't switch if the mode is already correct */ if (amode == ARM_MODE_SYS) amode = ARM_MODE_USR; if (mode == amode) return ARM_MODE_ANY; switch (num) { /* don't switch for non-shadowed registers (r0..r7, r15/pc, cpsr) */ case 0 ... 7: case 15: case 16: break; /* r8..r12 aren't shadowed for anything except FIQ */ case 8 ... 12: if (mode == ARM_MODE_FIQ) return mode; break; /* r13/sp, and r14/lr are always shadowed */ case 13: case 14: return mode; default: LOG_WARNING("invalid register #%u", num); break; } return ARM_MODE_ANY; } /* * Standard ARM register accessors ... there are three methods * in "struct arm", to support individual read/write and bulk read * of registers. */ static int arm_dpm_read_core_reg(struct target *target, struct reg *r, int regnum, enum arm_mode mode) { struct arm_dpm *dpm = target_to_arm(target)->dpm; int retval; if (regnum < 0 || regnum > 16) return ERROR_COMMAND_SYNTAX_ERROR; if (regnum == 16) { if (mode != ARM_MODE_ANY) regnum = 17; } else mode = dpm_mapmode(dpm->arm, regnum, mode); /* REVISIT what happens if we try to read SPSR in a core mode * which has no such register? */ retval = dpm->prepare(dpm); if (retval != ERROR_OK) return retval; if (mode != ARM_MODE_ANY) { retval = dpm_modeswitch(dpm, mode); if (retval != ERROR_OK) goto fail; } retval = dpm_read_reg(dpm, r, regnum); if (retval != ERROR_OK) goto fail; /* always clean up, regardless of error */ if (mode != ARM_MODE_ANY) /* (void) */ dpm_modeswitch(dpm, ARM_MODE_ANY); fail: /* (void) */ dpm->finish(dpm); return retval; } static int arm_dpm_write_core_reg(struct target *target, struct reg *r, int regnum, enum arm_mode mode, uint32_t value) { struct arm_dpm *dpm = target_to_arm(target)->dpm; int retval; if (regnum < 0 || regnum > 16) return ERROR_COMMAND_SYNTAX_ERROR; if (regnum == 16) { if (mode != ARM_MODE_ANY) regnum = 17; } else mode = dpm_mapmode(dpm->arm, regnum, mode); /* REVISIT what happens if we try to write SPSR in a core mode * which has no such register? */ retval = dpm->prepare(dpm); if (retval != ERROR_OK) return retval; if (mode != ARM_MODE_ANY) { retval = dpm_modeswitch(dpm, mode); if (retval != ERROR_OK) goto fail; } retval = dpm_write_reg(dpm, r, regnum); /* always clean up, regardless of error */ if (mode != ARM_MODE_ANY) /* (void) */ dpm_modeswitch(dpm, ARM_MODE_ANY); fail: /* (void) */ dpm->finish(dpm); return retval; } static int arm_dpm_full_context(struct target *target) { struct arm *arm = target_to_arm(target); struct arm_dpm *dpm = arm->dpm; struct reg_cache *cache = arm->core_cache; int retval; bool did_read; retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; do { enum arm_mode mode = ARM_MODE_ANY; did_read = false; /* We "know" arm_dpm_read_current_registers() was called so * the unmapped registers (R0..R7, PC, AND CPSR) and some * view of R8..R14 are current. We also "know" oddities of * register mapping: special cases for R8..R12 and SPSR. * * Pick some mode with unread registers and read them all. * Repeat until done. */ for (unsigned i = 0; i < cache->num_regs; i++) { struct arm_reg *r; if (cache->reg_list[i].valid) continue; r = cache->reg_list[i].arch_info; /* may need to pick a mode and set CPSR */ if (!did_read) { did_read = true; mode = r->mode; /* For R8..R12 when we've entered debug * state in FIQ mode... patch mode. */ if (mode == ARM_MODE_ANY) mode = ARM_MODE_USR; /* REVISIT error checks */ retval = dpm_modeswitch(dpm, mode); if (retval != ERROR_OK) goto done; } if (r->mode != mode) continue; /* CPSR was read, so "R16" must mean SPSR */ retval = dpm_read_reg(dpm, &cache->reg_list[i], (r->num == 16) ? 17 : r->num); if (retval != ERROR_OK) goto done; } } while (did_read); retval = dpm_modeswitch(dpm, ARM_MODE_ANY); /* (void) */ dpm->finish(dpm); done: return retval; } /*----------------------------------------------------------------------*/ /* * Breakpoint and Watchpoint support. * * Hardware {break,watch}points are usually left active, to minimize * debug entry/exit costs. When they are set or cleared, it's done in * batches. Also, DPM-conformant hardware can update debug registers * regardless of whether the CPU is running or halted ... though that * fact isn't currently leveraged. */ static int dpm_bpwp_setup(struct arm_dpm *dpm, struct dpm_bpwp *xp, uint32_t addr, uint32_t length) { uint32_t control; control = (1 << 0) /* enable */ | (3 << 1); /* both user and privileged access */ /* Match 1, 2, or all 4 byte addresses in this word. * * FIXME: v7 hardware allows lengths up to 2 GB for BP and WP. * Support larger length, when addr is suitably aligned. In * particular, allow watchpoints on 8 byte "double" values. * * REVISIT allow watchpoints on unaligned 2-bit values; and on * v7 hardware, unaligned 4-byte ones too. */ switch (length) { case 1: control |= (1 << (addr & 3)) << 5; break; case 2: /* require 2-byte alignment */ if (!(addr & 1)) { control |= (3 << (addr & 2)) << 5; break; } /* FALL THROUGH */ case 4: /* require 4-byte alignment */ if (!(addr & 3)) { control |= 0xf << 5; break; } /* FALL THROUGH */ default: LOG_ERROR("unsupported {break,watch}point length/alignment"); return ERROR_COMMAND_SYNTAX_ERROR; } /* other shared control bits: * bits 15:14 == 0 ... both secure and nonsecure states (v6.1+ only) * bit 20 == 0 ... not linked to a context ID * bit 28:24 == 0 ... not ignoring N LSBs (v7 only) */ xp->address = addr & ~3; xp->control = control; xp->dirty = true; LOG_DEBUG("BPWP: addr %8.8" PRIx32 ", control %" PRIx32 ", number %d", xp->address, control, xp->number); /* hardware is updated in write_dirty_registers() */ return ERROR_OK; } static int dpm_add_breakpoint(struct target *target, struct breakpoint *bp) { struct arm *arm = target_to_arm(target); struct arm_dpm *dpm = arm->dpm; int retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; if (bp->length < 2) return ERROR_COMMAND_SYNTAX_ERROR; if (!dpm->bpwp_enable) return retval; /* FIXME we need a generic solution for software breakpoints. */ if (bp->type == BKPT_SOFT) LOG_DEBUG("using HW bkpt, not SW..."); for (unsigned i = 0; i < dpm->nbp; i++) { if (!dpm->dbp[i].bp) { retval = dpm_bpwp_setup(dpm, &dpm->dbp[i].bpwp, bp->address, bp->length); if (retval == ERROR_OK) dpm->dbp[i].bp = bp; break; } } return retval; } static int dpm_remove_breakpoint(struct target *target, struct breakpoint *bp) { struct arm *arm = target_to_arm(target); struct arm_dpm *dpm = arm->dpm; int retval = ERROR_COMMAND_SYNTAX_ERROR; for (unsigned i = 0; i < dpm->nbp; i++) { if (dpm->dbp[i].bp == bp) { dpm->dbp[i].bp = NULL; dpm->dbp[i].bpwp.dirty = true; /* hardware is updated in write_dirty_registers() */ retval = ERROR_OK; break; } } return retval; } static int dpm_watchpoint_setup(struct arm_dpm *dpm, unsigned index_t, struct watchpoint *wp) { int retval; struct dpm_wp *dwp = dpm->dwp + index_t; uint32_t control; /* this hardware doesn't support data value matching or masking */ if (wp->value || wp->mask != ~(uint32_t)0) { LOG_DEBUG("watchpoint values and masking not supported"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } retval = dpm_bpwp_setup(dpm, &dwp->bpwp, wp->address, wp->length); if (retval != ERROR_OK) return retval; control = dwp->bpwp.control; switch (wp->rw) { case WPT_READ: control |= 1 << 3; break; case WPT_WRITE: control |= 2 << 3; break; case WPT_ACCESS: control |= 3 << 3; break; } dwp->bpwp.control = control; dpm->dwp[index_t].wp = wp; return retval; } static int dpm_add_watchpoint(struct target *target, struct watchpoint *wp) { struct arm *arm = target_to_arm(target); struct arm_dpm *dpm = arm->dpm; int retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; if (dpm->bpwp_enable) { for (unsigned i = 0; i < dpm->nwp; i++) { if (!dpm->dwp[i].wp) { retval = dpm_watchpoint_setup(dpm, i, wp); break; } } } return retval; } static int dpm_remove_watchpoint(struct target *target, struct watchpoint *wp) { struct arm *arm = target_to_arm(target); struct arm_dpm *dpm = arm->dpm; int retval = ERROR_COMMAND_SYNTAX_ERROR; for (unsigned i = 0; i < dpm->nwp; i++) { if (dpm->dwp[i].wp == wp) { dpm->dwp[i].wp = NULL; dpm->dwp[i].bpwp.dirty = true; /* hardware is updated in write_dirty_registers() */ retval = ERROR_OK; break; } } return retval; } void arm_dpm_report_wfar(struct arm_dpm *dpm, uint32_t addr) { switch (dpm->arm->core_state) { case ARM_STATE_ARM: addr -= 8; break; case ARM_STATE_THUMB: case ARM_STATE_THUMB_EE: addr -= 4; break; case ARM_STATE_JAZELLE: /* ?? */ break; } dpm->wp_pc = addr; } /*----------------------------------------------------------------------*/ /* * Other debug and support utilities */ void arm_dpm_report_dscr(struct arm_dpm *dpm, uint32_t dscr) { struct target *target = dpm->arm->target; dpm->dscr = dscr; /* Examine debug reason */ switch (DSCR_ENTRY(dscr)) { case 6: /* Data abort (v6 only) */ case 7: /* Prefetch abort (v6 only) */ /* FALL THROUGH -- assume a v6 core in abort mode */ case 0: /* HALT request from debugger */ case 4: /* EDBGRQ */ target->debug_reason = DBG_REASON_DBGRQ; break; case 1: /* HW breakpoint */ case 3: /* SW BKPT */ case 5: /* vector catch */ target->debug_reason = DBG_REASON_BREAKPOINT; break; case 2: /* asynch watchpoint */ case 10:/* precise watchpoint */ target->debug_reason = DBG_REASON_WATCHPOINT; break; default: target->debug_reason = DBG_REASON_UNDEFINED; break; } } /*----------------------------------------------------------------------*/ /* * Setup and management support. */ /** * Hooks up this DPM to its associated target; call only once. * Initially this only covers the register cache. * * Oh, and watchpoints. Yeah. */ int arm_dpm_setup(struct arm_dpm *dpm) { struct arm *arm = dpm->arm; struct target *target = arm->target; struct reg_cache *cache; arm->dpm = dpm; /* register access setup */ arm->full_context = arm_dpm_full_context; arm->read_core_reg = arm_dpm_read_core_reg; arm->write_core_reg = arm_dpm_write_core_reg; cache = arm_build_reg_cache(target, arm); if (!cache) return ERROR_FAIL; *register_get_last_cache_p(&target->reg_cache) = cache; /* coprocessor access setup */ arm->mrc = dpm_mrc; arm->mcr = dpm_mcr; /* breakpoint setup -- optional until it works everywhere */ if (!target->type->add_breakpoint) { target->type->add_breakpoint = dpm_add_breakpoint; target->type->remove_breakpoint = dpm_remove_breakpoint; } /* watchpoint setup */ target->type->add_watchpoint = dpm_add_watchpoint; target->type->remove_watchpoint = dpm_remove_watchpoint; /* FIXME add vector catch support */ dpm->nbp = 1 + ((dpm->didr >> 24) & 0xf); dpm->dbp = calloc(dpm->nbp, sizeof *dpm->dbp); dpm->nwp = 1 + ((dpm->didr >> 28) & 0xf); dpm->dwp = calloc(dpm->nwp, sizeof *dpm->dwp); if (!dpm->dbp || !dpm->dwp) { free(dpm->dbp); free(dpm->dwp); return ERROR_FAIL; } LOG_INFO("%s: hardware has %d breakpoints, %d watchpoints", target_name(target), dpm->nbp, dpm->nwp); /* REVISIT ... and some of those breakpoints could match * execution context IDs... */ return ERROR_OK; } /** * Reinitializes DPM state at the beginning of a new debug session * or after a reset which may have affected the debug module. */ int arm_dpm_initialize(struct arm_dpm *dpm) { /* Disable all breakpoints and watchpoints at startup. */ if (dpm->bpwp_disable) { unsigned i; for (i = 0; i < dpm->nbp; i++) { dpm->dbp[i].bpwp.number = i; (void) dpm->bpwp_disable(dpm, i); } for (i = 0; i < dpm->nwp; i++) { dpm->dwp[i].bpwp.number = 16 + i; (void) dpm->bpwp_disable(dpm, 16 + i); } } else LOG_WARNING("%s: can't disable breakpoints and watchpoints", target_name(dpm->arm->target)); return ERROR_OK; } openocd-0.7.0/src/target/avr32_regs.h0000644000175000001440000000353512134336410014270 00000000000000/*************************************************************************** * Copyright (C) 2010 by Oleksandr Tymoshenko * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef AVR32_REGS #define AVR32_REGS enum avr32_reg_nums { AVR32_REG_R0 = 0, AVR32_REG_R1, AVR32_REG_R2, AVR32_REG_R3, AVR32_REG_R4, AVR32_REG_R5, AVR32_REG_R6, AVR32_REG_R7, AVR32_REG_R8, AVR32_REG_R9, AVR32_REG_R10, AVR32_REG_R11, AVR32_REG_R12, AVR32_REG_SP, AVR32_REG_LR, AVR32_REG_PC, AVR32_REG_SR, }; int avr32_jtag_read_regs(struct avr32_jtag *jtag_info, uint32_t *regs); int avr32_jtag_write_regs(struct avr32_jtag *jtag_info, uint32_t *regs); #endif /* AVR32_REGS */ openocd-0.7.0/src/target/mips_m4k.c0000644000175000001440000011765512137151331014042 00000000000000/*************************************************************************** * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2008 by David T.L. Wong * * * * Copyright (C) 2009 by David N. Claffey * * * * Copyright (C) 2011 by Drasko DRASKOVIC * * drasko.draskovic@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "breakpoints.h" #include "mips32.h" #include "mips_m4k.h" #include "mips32_dmaacc.h" #include "target_type.h" #include "register.h" static void mips_m4k_enable_breakpoints(struct target *target); static void mips_m4k_enable_watchpoints(struct target *target); static int mips_m4k_set_breakpoint(struct target *target, struct breakpoint *breakpoint); static int mips_m4k_unset_breakpoint(struct target *target, struct breakpoint *breakpoint); static int mips_m4k_internal_restore(struct target *target, int current, uint32_t address, int handle_breakpoints, int debug_execution); static int mips_m4k_halt(struct target *target); static int mips_m4k_examine_debug_reason(struct target *target) { uint32_t break_status; int retval; if ((target->debug_reason != DBG_REASON_DBGRQ) && (target->debug_reason != DBG_REASON_SINGLESTEP)) { /* get info about inst breakpoint support */ retval = target_read_u32(target, EJTAG_IBS, &break_status); if (retval != ERROR_OK) return retval; if (break_status & 0x1f) { /* we have halted on a breakpoint */ retval = target_write_u32(target, EJTAG_IBS, 0); if (retval != ERROR_OK) return retval; target->debug_reason = DBG_REASON_BREAKPOINT; } /* get info about data breakpoint support */ retval = target_read_u32(target, EJTAG_DBS, &break_status); if (retval != ERROR_OK) return retval; if (break_status & 0x1f) { /* we have halted on a breakpoint */ retval = target_write_u32(target, EJTAG_DBS, 0); if (retval != ERROR_OK) return retval; target->debug_reason = DBG_REASON_WATCHPOINT; } } return ERROR_OK; } static int mips_m4k_debug_entry(struct target *target) { struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; mips32_save_context(target); /* make sure stepping disabled, SSt bit in CP0 debug register cleared */ mips_ejtag_config_step(ejtag_info, 0); /* make sure break unit configured */ mips32_configure_break_unit(target); /* attempt to find halt reason */ mips_m4k_examine_debug_reason(target); /* default to mips32 isa, it will be changed below if required */ mips32->isa_mode = MIPS32_ISA_MIPS32; if (ejtag_info->impcode & EJTAG_IMP_MIPS16) mips32->isa_mode = buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 1); LOG_DEBUG("entered debug state at PC 0x%" PRIx32 ", target->state: %s", buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32), target_state_name(target)); return ERROR_OK; } static struct target *get_mips_m4k(struct target *target, int32_t coreid) { struct target_list *head; struct target *curr; head = target->head; while (head != (struct target_list *)NULL) { curr = head->target; if ((curr->coreid == coreid) && (curr->state == TARGET_HALTED)) return curr; head = head->next; } return target; } static int mips_m4k_halt_smp(struct target *target) { int retval = ERROR_OK; struct target_list *head; struct target *curr; head = target->head; while (head != (struct target_list *)NULL) { int ret = ERROR_OK; curr = head->target; if ((curr != target) && (curr->state != TARGET_HALTED)) ret = mips_m4k_halt(curr); if (ret != ERROR_OK) { LOG_ERROR("halt failed target->coreid: %d", curr->coreid); retval = ret; } head = head->next; } return retval; } static int update_halt_gdb(struct target *target) { int retval = ERROR_OK; if (target->gdb_service->core[0] == -1) { target->gdb_service->target = target; target->gdb_service->core[0] = target->coreid; retval = mips_m4k_halt_smp(target); } return retval; } static int mips_m4k_poll(struct target *target) { int retval = ERROR_OK; struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; uint32_t ejtag_ctrl = ejtag_info->ejtag_ctrl; enum target_state prev_target_state = target->state; /* toggle to another core is done by gdb as follow */ /* maint packet J core_id */ /* continue */ /* the next polling trigger an halt event sent to gdb */ if ((target->state == TARGET_HALTED) && (target->smp) && (target->gdb_service) && (target->gdb_service->target == NULL)) { target->gdb_service->target = get_mips_m4k(target, target->gdb_service->core[1]); target_call_event_callbacks(target, TARGET_EVENT_HALTED); return retval; } /* read ejtag control reg */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); retval = mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); if (retval != ERROR_OK) return retval; /* clear this bit before handling polling * as after reset registers will read zero */ if (ejtag_ctrl & EJTAG_CTRL_ROCC) { /* we have detected a reset, clear flag * otherwise ejtag will not work */ ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_ROCC; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); retval = mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); if (retval != ERROR_OK) return retval; LOG_DEBUG("Reset Detected"); } /* check for processor halted */ if (ejtag_ctrl & EJTAG_CTRL_BRKST) { if ((target->state != TARGET_HALTED) && (target->state != TARGET_DEBUG_RUNNING)) { if (target->state == TARGET_UNKNOWN) LOG_DEBUG("EJTAG_CTRL_BRKST already set during server startup."); /* OpenOCD was was probably started on the board with EJTAG_CTRL_BRKST already set * (maybe put on by HALT-ing the board in the previous session). * * Force enable debug entry for this session. */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_NORMALBOOT); target->state = TARGET_HALTED; retval = mips_m4k_debug_entry(target); if (retval != ERROR_OK) return retval; if (target->smp && ((prev_target_state == TARGET_RUNNING) || (prev_target_state == TARGET_RESET))) { retval = update_halt_gdb(target); if (retval != ERROR_OK) return retval; } target_call_event_callbacks(target, TARGET_EVENT_HALTED); } else if (target->state == TARGET_DEBUG_RUNNING) { target->state = TARGET_HALTED; retval = mips_m4k_debug_entry(target); if (retval != ERROR_OK) return retval; if (target->smp) { retval = update_halt_gdb(target); if (retval != ERROR_OK) return retval; } target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); } } else target->state = TARGET_RUNNING; /* LOG_DEBUG("ctrl = 0x%08X", ejtag_ctrl); */ return ERROR_OK; } static int mips_m4k_halt(struct target *target) { struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; LOG_DEBUG("target->state: %s", target_state_name(target)); if (target->state == TARGET_HALTED) { LOG_DEBUG("target was already halted"); return ERROR_OK; } if (target->state == TARGET_UNKNOWN) LOG_WARNING("target was in unknown state when halt was requested"); if (target->state == TARGET_RESET) { if ((jtag_get_reset_config() & RESET_SRST_PULLS_TRST) && jtag_get_srst()) { LOG_ERROR("can't request a halt while in reset if nSRST pulls nTRST"); return ERROR_TARGET_FAILURE; } else { /* we came here in a reset_halt or reset_init sequence * debug entry was already prepared in mips_m4k_assert_reset() */ target->debug_reason = DBG_REASON_DBGRQ; return ERROR_OK; } } /* break processor */ mips_ejtag_enter_debug(ejtag_info); target->debug_reason = DBG_REASON_DBGRQ; return ERROR_OK; } static int mips_m4k_assert_reset(struct target *target) { struct mips_m4k_common *mips_m4k = target_to_m4k(target); struct mips_ejtag *ejtag_info = &mips_m4k->mips32.ejtag_info; LOG_DEBUG("target->state: %s", target_state_name(target)); enum reset_types jtag_reset_config = jtag_get_reset_config(); /* some cores support connecting while srst is asserted * use that mode is it has been configured */ bool srst_asserted = false; if (!(jtag_reset_config & RESET_SRST_PULLS_TRST) && (jtag_reset_config & RESET_SRST_NO_GATING)) { jtag_add_reset(0, 1); srst_asserted = true; } if (target->reset_halt) { /* use hardware to catch reset */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_EJTAGBOOT); } else mips_ejtag_set_instr(ejtag_info, EJTAG_INST_NORMALBOOT); if (jtag_reset_config & RESET_HAS_SRST) { /* here we should issue a srst only, but we may have to assert trst as well */ if (jtag_reset_config & RESET_SRST_PULLS_TRST) jtag_add_reset(1, 1); else if (!srst_asserted) jtag_add_reset(0, 1); } else { if (mips_m4k->is_pic32mx) { LOG_DEBUG("Using MTAP reset to reset processor..."); /* use microchip specific MTAP reset */ mips_ejtag_set_instr(ejtag_info, MTAP_SW_MTAP); mips_ejtag_set_instr(ejtag_info, MTAP_COMMAND); mips_ejtag_drscan_8_out(ejtag_info, MCHP_ASERT_RST); mips_ejtag_drscan_8_out(ejtag_info, MCHP_DE_ASSERT_RST); mips_ejtag_set_instr(ejtag_info, MTAP_SW_ETAP); } else { /* use ejtag reset - not supported by all cores */ uint32_t ejtag_ctrl = ejtag_info->ejtag_ctrl | EJTAG_CTRL_PRRST | EJTAG_CTRL_PERRST; LOG_DEBUG("Using EJTAG reset (PRRST) to reset processor..."); mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); mips_ejtag_drscan_32_out(ejtag_info, ejtag_ctrl); } } target->state = TARGET_RESET; jtag_add_sleep(50000); register_cache_invalidate(mips_m4k->mips32.core_cache); if (target->reset_halt) { int retval = target_halt(target); if (retval != ERROR_OK) return retval; } return ERROR_OK; } static int mips_m4k_deassert_reset(struct target *target) { LOG_DEBUG("target->state: %s", target_state_name(target)); /* deassert reset lines */ jtag_add_reset(0, 0); return ERROR_OK; } static int mips_m4k_soft_reset_halt(struct target *target) { /* TODO */ return ERROR_OK; } static int mips_m4k_single_step_core(struct target *target) { struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; /* configure single step mode */ mips_ejtag_config_step(ejtag_info, 1); /* disable interrupts while stepping */ mips32_enable_interrupts(target, 0); /* exit debug mode */ mips_ejtag_exit_debug(ejtag_info); mips_m4k_debug_entry(target); return ERROR_OK; } static int mips_m4k_restore_smp(struct target *target, uint32_t address, int handle_breakpoints) { int retval = ERROR_OK; struct target_list *head; struct target *curr; head = target->head; while (head != (struct target_list *)NULL) { int ret = ERROR_OK; curr = head->target; if ((curr != target) && (curr->state != TARGET_RUNNING)) { /* resume current address , not in step mode */ ret = mips_m4k_internal_restore(curr, 1, address, handle_breakpoints, 0); if (ret != ERROR_OK) { LOG_ERROR("target->coreid :%d failed to resume at address :0x%x", curr->coreid, address); retval = ret; } } head = head->next; } return retval; } static int mips_m4k_internal_restore(struct target *target, int current, uint32_t address, int handle_breakpoints, int debug_execution) { struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; struct breakpoint *breakpoint = NULL; uint32_t resume_pc; if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!debug_execution) { target_free_all_working_areas(target); mips_m4k_enable_breakpoints(target); mips_m4k_enable_watchpoints(target); } /* current = 1: continue on current pc, otherwise continue at
*/ if (!current) { buf_set_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32, address); mips32->core_cache->reg_list[MIPS32_PC].dirty = 1; mips32->core_cache->reg_list[MIPS32_PC].valid = 1; } if (ejtag_info->impcode & EJTAG_IMP_MIPS16) buf_set_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 1, mips32->isa_mode); if (!current) resume_pc = address; else resume_pc = buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32); mips32_restore_context(target); /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) { /* Single step past breakpoint at current address */ breakpoint = breakpoint_find(target, resume_pc); if (breakpoint) { LOG_DEBUG("unset breakpoint at 0x%8.8" PRIx32 "", breakpoint->address); mips_m4k_unset_breakpoint(target, breakpoint); mips_m4k_single_step_core(target); mips_m4k_set_breakpoint(target, breakpoint); } } /* enable interrupts if we are running */ mips32_enable_interrupts(target, !debug_execution); /* exit debug mode */ mips_ejtag_exit_debug(ejtag_info); target->debug_reason = DBG_REASON_NOTHALTED; /* registers are now invalid */ register_cache_invalidate(mips32->core_cache); if (!debug_execution) { target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); LOG_DEBUG("target resumed at 0x%" PRIx32 "", resume_pc); } else { target->state = TARGET_DEBUG_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); LOG_DEBUG("target debug resumed at 0x%" PRIx32 "", resume_pc); } return ERROR_OK; } static int mips_m4k_resume(struct target *target, int current, uint32_t address, int handle_breakpoints, int debug_execution) { int retval = ERROR_OK; /* dummy resume for smp toggle in order to reduce gdb impact */ if ((target->smp) && (target->gdb_service->core[1] != -1)) { /* simulate a start and halt of target */ target->gdb_service->target = NULL; target->gdb_service->core[0] = target->gdb_service->core[1]; /* fake resume at next poll we play the target core[1], see poll*/ target_call_event_callbacks(target, TARGET_EVENT_RESUMED); return retval; } retval = mips_m4k_internal_restore(target, current, address, handle_breakpoints, debug_execution); if (retval == ERROR_OK && target->smp) { target->gdb_service->core[0] = -1; retval = mips_m4k_restore_smp(target, address, handle_breakpoints); } return retval; } static int mips_m4k_step(struct target *target, int current, uint32_t address, int handle_breakpoints) { /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; struct breakpoint *breakpoint = NULL; if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* current = 1: continue on current pc, otherwise continue at
*/ if (!current) { buf_set_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32, address); mips32->core_cache->reg_list[MIPS32_PC].dirty = 1; mips32->core_cache->reg_list[MIPS32_PC].valid = 1; } /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) { breakpoint = breakpoint_find(target, buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32)); if (breakpoint) mips_m4k_unset_breakpoint(target, breakpoint); } /* restore context */ mips32_restore_context(target); /* configure single step mode */ mips_ejtag_config_step(ejtag_info, 1); target->debug_reason = DBG_REASON_SINGLESTEP; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); /* disable interrupts while stepping */ mips32_enable_interrupts(target, 0); /* exit debug mode */ mips_ejtag_exit_debug(ejtag_info); /* registers are now invalid */ register_cache_invalidate(mips32->core_cache); LOG_DEBUG("target stepped "); mips_m4k_debug_entry(target); if (breakpoint) mips_m4k_set_breakpoint(target, breakpoint); target_call_event_callbacks(target, TARGET_EVENT_HALTED); return ERROR_OK; } static void mips_m4k_enable_breakpoints(struct target *target) { struct breakpoint *breakpoint = target->breakpoints; /* set any pending breakpoints */ while (breakpoint) { if (breakpoint->set == 0) mips_m4k_set_breakpoint(target, breakpoint); breakpoint = breakpoint->next; } } static int mips_m4k_set_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct mips32_common *mips32 = target_to_mips32(target); struct mips32_comparator *comparator_list = mips32->inst_break_list; int retval; if (breakpoint->set) { LOG_WARNING("breakpoint already set"); return ERROR_OK; } if (breakpoint->type == BKPT_HARD) { int bp_num = 0; while (comparator_list[bp_num].used && (bp_num < mips32->num_inst_bpoints)) bp_num++; if (bp_num >= mips32->num_inst_bpoints) { LOG_ERROR("Can not find free FP Comparator(bpid: %d)", breakpoint->unique_id); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } breakpoint->set = bp_num + 1; comparator_list[bp_num].used = 1; comparator_list[bp_num].bp_value = breakpoint->address; target_write_u32(target, comparator_list[bp_num].reg_address, comparator_list[bp_num].bp_value); target_write_u32(target, comparator_list[bp_num].reg_address + 0x08, 0x00000000); target_write_u32(target, comparator_list[bp_num].reg_address + 0x18, 1); LOG_DEBUG("bpid: %d, bp_num %i bp_value 0x%" PRIx32 "", breakpoint->unique_id, bp_num, comparator_list[bp_num].bp_value); } else if (breakpoint->type == BKPT_SOFT) { LOG_DEBUG("bpid: %d", breakpoint->unique_id); if (breakpoint->length == 4) { uint32_t verify = 0xffffffff; retval = target_read_memory(target, breakpoint->address, breakpoint->length, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, breakpoint->address, MIPS32_SDBBP); if (retval != ERROR_OK) return retval; retval = target_read_u32(target, breakpoint->address, &verify); if (retval != ERROR_OK) return retval; if (verify != MIPS32_SDBBP) { LOG_ERROR("Unable to set 32bit breakpoint at address %08" PRIx32 " - check that memory is read/writable", breakpoint->address); return ERROR_OK; } } else { uint16_t verify = 0xffff; retval = target_read_memory(target, breakpoint->address, breakpoint->length, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; retval = target_write_u16(target, breakpoint->address, MIPS16_SDBBP); if (retval != ERROR_OK) return retval; retval = target_read_u16(target, breakpoint->address, &verify); if (retval != ERROR_OK) return retval; if (verify != MIPS16_SDBBP) { LOG_ERROR("Unable to set 16bit breakpoint at address %08" PRIx32 " - check that memory is read/writable", breakpoint->address); return ERROR_OK; } } breakpoint->set = 20; /* Any nice value but 0 */ } return ERROR_OK; } static int mips_m4k_unset_breakpoint(struct target *target, struct breakpoint *breakpoint) { /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); struct mips32_comparator *comparator_list = mips32->inst_break_list; int retval; if (!breakpoint->set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } if (breakpoint->type == BKPT_HARD) { int bp_num = breakpoint->set - 1; if ((bp_num < 0) || (bp_num >= mips32->num_inst_bpoints)) { LOG_DEBUG("Invalid FP Comparator number in breakpoint (bpid: %d)", breakpoint->unique_id); return ERROR_OK; } LOG_DEBUG("bpid: %d - releasing hw: %d", breakpoint->unique_id, bp_num); comparator_list[bp_num].used = 0; comparator_list[bp_num].bp_value = 0; target_write_u32(target, comparator_list[bp_num].reg_address + 0x18, 0); } else { /* restore original instruction (kept in target endianness) */ LOG_DEBUG("bpid: %d", breakpoint->unique_id); if (breakpoint->length == 4) { uint32_t current_instr; /* check that user program has not modified breakpoint instruction */ retval = target_read_memory(target, breakpoint->address, 4, 1, (uint8_t *)¤t_instr); if (retval != ERROR_OK) return retval; /** * target_read_memory() gets us data in _target_ endianess. * If we want to use this data on the host for comparisons with some macros * we must first transform it to _host_ endianess using target_buffer_get_u32(). */ current_instr = target_buffer_get_u32(target, (uint8_t *)¤t_instr); if (current_instr == MIPS32_SDBBP) { retval = target_write_memory(target, breakpoint->address, 4, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; } } else { uint16_t current_instr; /* check that user program has not modified breakpoint instruction */ retval = target_read_memory(target, breakpoint->address, 2, 1, (uint8_t *)¤t_instr); if (retval != ERROR_OK) return retval; current_instr = target_buffer_get_u16(target, (uint8_t *)¤t_instr); if (current_instr == MIPS16_SDBBP) { retval = target_write_memory(target, breakpoint->address, 2, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; } } } breakpoint->set = 0; return ERROR_OK; } static int mips_m4k_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct mips32_common *mips32 = target_to_mips32(target); if (breakpoint->type == BKPT_HARD) { if (mips32->num_inst_bpoints_avail < 1) { LOG_INFO("no hardware breakpoint available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } mips32->num_inst_bpoints_avail--; } return mips_m4k_set_breakpoint(target, breakpoint); } static int mips_m4k_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (breakpoint->set) mips_m4k_unset_breakpoint(target, breakpoint); if (breakpoint->type == BKPT_HARD) mips32->num_inst_bpoints_avail++; return ERROR_OK; } static int mips_m4k_set_watchpoint(struct target *target, struct watchpoint *watchpoint) { struct mips32_common *mips32 = target_to_mips32(target); struct mips32_comparator *comparator_list = mips32->data_break_list; int wp_num = 0; /* * watchpoint enabled, ignore all byte lanes in value register * and exclude both load and store accesses from watchpoint * condition evaluation */ int enable = EJTAG_DBCn_NOSB | EJTAG_DBCn_NOLB | EJTAG_DBCn_BE | (0xff << EJTAG_DBCn_BLM_SHIFT); if (watchpoint->set) { LOG_WARNING("watchpoint already set"); return ERROR_OK; } while (comparator_list[wp_num].used && (wp_num < mips32->num_data_bpoints)) wp_num++; if (wp_num >= mips32->num_data_bpoints) { LOG_ERROR("Can not find free FP Comparator"); return ERROR_FAIL; } if (watchpoint->length != 4) { LOG_ERROR("Only watchpoints of length 4 are supported"); return ERROR_TARGET_UNALIGNED_ACCESS; } if (watchpoint->address % 4) { LOG_ERROR("Watchpoints address should be word aligned"); return ERROR_TARGET_UNALIGNED_ACCESS; } switch (watchpoint->rw) { case WPT_READ: enable &= ~EJTAG_DBCn_NOLB; break; case WPT_WRITE: enable &= ~EJTAG_DBCn_NOSB; break; case WPT_ACCESS: enable &= ~(EJTAG_DBCn_NOLB | EJTAG_DBCn_NOSB); break; default: LOG_ERROR("BUG: watchpoint->rw neither read, write nor access"); } watchpoint->set = wp_num + 1; comparator_list[wp_num].used = 1; comparator_list[wp_num].bp_value = watchpoint->address; target_write_u32(target, comparator_list[wp_num].reg_address, comparator_list[wp_num].bp_value); target_write_u32(target, comparator_list[wp_num].reg_address + 0x08, 0x00000000); target_write_u32(target, comparator_list[wp_num].reg_address + 0x10, 0x00000000); target_write_u32(target, comparator_list[wp_num].reg_address + 0x18, enable); target_write_u32(target, comparator_list[wp_num].reg_address + 0x20, 0); LOG_DEBUG("wp_num %i bp_value 0x%" PRIx32 "", wp_num, comparator_list[wp_num].bp_value); return ERROR_OK; } static int mips_m4k_unset_watchpoint(struct target *target, struct watchpoint *watchpoint) { /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); struct mips32_comparator *comparator_list = mips32->data_break_list; if (!watchpoint->set) { LOG_WARNING("watchpoint not set"); return ERROR_OK; } int wp_num = watchpoint->set - 1; if ((wp_num < 0) || (wp_num >= mips32->num_data_bpoints)) { LOG_DEBUG("Invalid FP Comparator number in watchpoint"); return ERROR_OK; } comparator_list[wp_num].used = 0; comparator_list[wp_num].bp_value = 0; target_write_u32(target, comparator_list[wp_num].reg_address + 0x18, 0); watchpoint->set = 0; return ERROR_OK; } static int mips_m4k_add_watchpoint(struct target *target, struct watchpoint *watchpoint) { struct mips32_common *mips32 = target_to_mips32(target); if (mips32->num_data_bpoints_avail < 1) { LOG_INFO("no hardware watchpoints available"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } mips32->num_data_bpoints_avail--; mips_m4k_set_watchpoint(target, watchpoint); return ERROR_OK; } static int mips_m4k_remove_watchpoint(struct target *target, struct watchpoint *watchpoint) { /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (watchpoint->set) mips_m4k_unset_watchpoint(target, watchpoint); mips32->num_data_bpoints_avail++; return ERROR_OK; } static void mips_m4k_enable_watchpoints(struct target *target) { struct watchpoint *watchpoint = target->watchpoints; /* set any pending watchpoints */ while (watchpoint) { if (watchpoint->set == 0) mips_m4k_set_watchpoint(target, watchpoint); watchpoint = watchpoint->next; } } static int mips_m4k_read_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; LOG_DEBUG("address: 0x%8.8" PRIx32 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", address, size, count); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* sanitize arguments */ if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer)) return ERROR_COMMAND_SYNTAX_ERROR; if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) return ERROR_TARGET_UNALIGNED_ACCESS; /* since we don't know if buffer is aligned, we allocate new mem that is always aligned */ void *t = NULL; if (size > 1) { t = malloc(count * size * sizeof(uint8_t)); if (t == NULL) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } } else t = buffer; /* if noDMA off, use DMAACC mode for memory read */ int retval; if (ejtag_info->impcode & EJTAG_IMP_NODMA) retval = mips32_pracc_read_mem(ejtag_info, address, size, count, t); else retval = mips32_dmaacc_read_mem(ejtag_info, address, size, count, t); /* mips32_..._read_mem with size 4/2 returns uint32_t/uint16_t in host */ /* endianness, but byte array should represent target endianness */ if (ERROR_OK == retval) { switch (size) { case 4: target_buffer_set_u32_array(target, buffer, count, t); break; case 2: target_buffer_set_u16_array(target, buffer, count, t); break; } } if ((size > 1) && (t != NULL)) free(t); return retval; } static int mips_m4k_write_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; LOG_DEBUG("address: 0x%8.8" PRIx32 ", size: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", address, size, count); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* sanitize arguments */ if (((size != 4) && (size != 2) && (size != 1)) || (count == 0) || !(buffer)) return ERROR_COMMAND_SYNTAX_ERROR; if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u))) return ERROR_TARGET_UNALIGNED_ACCESS; /** correct endianess if we have word or hword access */ void *t = NULL; if (size > 1) { /* mips32_..._write_mem with size 4/2 requires uint32_t/uint16_t in host */ /* endianness, but byte array represents target endianness */ t = malloc(count * size * sizeof(uint8_t)); if (t == NULL) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } switch (size) { case 4: target_buffer_get_u32_array(target, buffer, count, (uint32_t *)t); break; case 2: target_buffer_get_u16_array(target, buffer, count, (uint16_t *)t); break; } buffer = t; } /* if noDMA off, use DMAACC mode for memory write */ int retval; if (ejtag_info->impcode & EJTAG_IMP_NODMA) retval = mips32_pracc_write_mem(ejtag_info, address, size, count, (void *)buffer); else retval = mips32_dmaacc_write_mem(ejtag_info, address, size, count, (void *)buffer); if (t != NULL) free(t); if (ERROR_OK != retval) return retval; return ERROR_OK; } static int mips_m4k_init_target(struct command_context *cmd_ctx, struct target *target) { mips32_build_reg_cache(target); return ERROR_OK; } static int mips_m4k_init_arch_info(struct target *target, struct mips_m4k_common *mips_m4k, struct jtag_tap *tap) { struct mips32_common *mips32 = &mips_m4k->mips32; mips_m4k->common_magic = MIPSM4K_COMMON_MAGIC; /* initialize mips4k specific info */ mips32_init_arch_info(target, mips32, tap); mips32->arch_info = mips_m4k; return ERROR_OK; } static int mips_m4k_target_create(struct target *target, Jim_Interp *interp) { struct mips_m4k_common *mips_m4k = calloc(1, sizeof(struct mips_m4k_common)); mips_m4k_init_arch_info(target, mips_m4k, target->tap); return ERROR_OK; } static int mips_m4k_examine(struct target *target) { int retval; struct mips_m4k_common *mips_m4k = target_to_m4k(target); struct mips_ejtag *ejtag_info = &mips_m4k->mips32.ejtag_info; uint32_t idcode = 0; if (!target_was_examined(target)) { retval = mips_ejtag_get_idcode(ejtag_info, &idcode); if (retval != ERROR_OK) return retval; ejtag_info->idcode = idcode; if (((idcode >> 1) & 0x7FF) == 0x29) { /* we are using a pic32mx so select ejtag port * as it is not selected by default */ mips_ejtag_set_instr(ejtag_info, MTAP_SW_ETAP); LOG_DEBUG("PIC32MX Detected - using EJTAG Interface"); mips_m4k->is_pic32mx = true; } } /* init rest of ejtag interface */ retval = mips_ejtag_init(ejtag_info); if (retval != ERROR_OK) return retval; retval = mips32_examine(target); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int mips_m4k_bulk_write_memory(struct target *target, uint32_t address, uint32_t count, const uint8_t *buffer) { struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; int retval; int write_t = 1; LOG_DEBUG("address: 0x%8.8" PRIx32 ", count: 0x%8.8" PRIx32 "", address, count); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* check alignment */ if (address & 0x3u) return ERROR_TARGET_UNALIGNED_ACCESS; if (mips32->fast_data_area == NULL) { /* Get memory for block write handler * we preserve this area between calls and gain a speed increase * of about 3kb/sec when writing flash * this will be released/nulled by the system when the target is resumed or reset */ retval = target_alloc_working_area(target, MIPS32_FASTDATA_HANDLER_SIZE, &mips32->fast_data_area); if (retval != ERROR_OK) { LOG_WARNING("No working area available, falling back to non-bulk write"); return mips_m4k_write_memory(target, address, 4, count, buffer); } /* reset fastadata state so the algo get reloaded */ ejtag_info->fast_access_save = -1; } /* mips32_pracc_fastdata_xfer requires uint32_t in host endianness, */ /* but byte array represents target endianness */ uint32_t *t = NULL; t = malloc(count * sizeof(uint32_t)); if (t == NULL) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } target_buffer_get_u32_array(target, buffer, count, t); retval = mips32_pracc_fastdata_xfer(ejtag_info, mips32->fast_data_area, write_t, address, count, t); if (t != NULL) free(t); if (retval != ERROR_OK) { /* FASTDATA access failed, try normal memory write */ LOG_DEBUG("Fastdata access Failed, falling back to non-bulk write"); retval = mips_m4k_write_memory(target, address, 4, count, buffer); } return retval; } static int mips_m4k_verify_pointer(struct command_context *cmd_ctx, struct mips_m4k_common *mips_m4k) { if (mips_m4k->common_magic != MIPSM4K_COMMON_MAGIC) { command_print(cmd_ctx, "target is not an MIPS_M4K"); return ERROR_TARGET_INVALID; } return ERROR_OK; } COMMAND_HANDLER(mips_m4k_handle_cp0_command) { int retval; struct target *target = get_current_target(CMD_CTX); struct mips_m4k_common *mips_m4k = target_to_m4k(target); struct mips_ejtag *ejtag_info = &mips_m4k->mips32.ejtag_info; retval = mips_m4k_verify_pointer(CMD_CTX, mips_m4k); if (retval != ERROR_OK) return retval; if (target->state != TARGET_HALTED) { command_print(CMD_CTX, "target must be stopped for \"%s\" command", CMD_NAME); return ERROR_OK; } /* two or more argument, access a single register/select (write if third argument is given) */ if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; else { uint32_t cp0_reg, cp0_sel; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], cp0_reg); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], cp0_sel); if (CMD_ARGC == 2) { uint32_t value; retval = mips32_cp0_read(ejtag_info, &value, cp0_reg, cp0_sel); if (retval != ERROR_OK) { command_print(CMD_CTX, "couldn't access reg %" PRIi32, cp0_reg); return ERROR_OK; } command_print(CMD_CTX, "cp0 reg %" PRIi32 ", select %" PRIi32 ": %8.8" PRIx32, cp0_reg, cp0_sel, value); } else if (CMD_ARGC == 3) { uint32_t value; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], value); retval = mips32_cp0_write(ejtag_info, value, cp0_reg, cp0_sel); if (retval != ERROR_OK) { command_print(CMD_CTX, "couldn't access cp0 reg %" PRIi32 ", select %" PRIi32, cp0_reg, cp0_sel); return ERROR_OK; } command_print(CMD_CTX, "cp0 reg %" PRIi32 ", select %" PRIi32 ": %8.8" PRIx32, cp0_reg, cp0_sel, value); } } return ERROR_OK; } COMMAND_HANDLER(mips_m4k_handle_smp_off_command) { struct target *target = get_current_target(CMD_CTX); /* check target is an smp target */ struct target_list *head; struct target *curr; head = target->head; target->smp = 0; if (head != (struct target_list *)NULL) { while (head != (struct target_list *)NULL) { curr = head->target; curr->smp = 0; head = head->next; } /* fixes the target display to the debugger */ target->gdb_service->target = target; } return ERROR_OK; } COMMAND_HANDLER(mips_m4k_handle_smp_on_command) { struct target *target = get_current_target(CMD_CTX); struct target_list *head; struct target *curr; head = target->head; if (head != (struct target_list *)NULL) { target->smp = 1; while (head != (struct target_list *)NULL) { curr = head->target; curr->smp = 1; head = head->next; } } return ERROR_OK; } COMMAND_HANDLER(mips_m4k_handle_smp_gdb_command) { struct target *target = get_current_target(CMD_CTX); int retval = ERROR_OK; struct target_list *head; head = target->head; if (head != (struct target_list *)NULL) { if (CMD_ARGC == 1) { int coreid = 0; COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], coreid); if (ERROR_OK != retval) return retval; target->gdb_service->core[1] = coreid; } command_print(CMD_CTX, "gdb coreid %d -> %d", target->gdb_service->core[0] , target->gdb_service->core[1]); } return ERROR_OK; } COMMAND_HANDLER(mips_m4k_handle_scan_delay_command) { struct target *target = get_current_target(CMD_CTX); struct mips_m4k_common *mips_m4k = target_to_m4k(target); struct mips_ejtag *ejtag_info = &mips_m4k->mips32.ejtag_info; if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], ejtag_info->scan_delay); else if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; command_print(CMD_CTX, "scan delay: %d nsec", ejtag_info->scan_delay); if (ejtag_info->scan_delay >= 20000000) { ejtag_info->mode = 0; command_print(CMD_CTX, "running in legacy mode"); } else { ejtag_info->mode = 1; command_print(CMD_CTX, "running in fast queued mode"); } return ERROR_OK; } static const struct command_registration mips_m4k_exec_command_handlers[] = { { .name = "cp0", .handler = mips_m4k_handle_cp0_command, .mode = COMMAND_EXEC, .usage = "regnum [value]", .help = "display/modify cp0 register", }, { .name = "smp_off", .handler = mips_m4k_handle_smp_off_command, .mode = COMMAND_EXEC, .help = "Stop smp handling", .usage = "",}, { .name = "smp_on", .handler = mips_m4k_handle_smp_on_command, .mode = COMMAND_EXEC, .help = "Restart smp handling", .usage = "", }, { .name = "smp_gdb", .handler = mips_m4k_handle_smp_gdb_command, .mode = COMMAND_EXEC, .help = "display/fix current core played to gdb", .usage = "", }, { .name = "scan_delay", .handler = mips_m4k_handle_scan_delay_command, .mode = COMMAND_ANY, .help = "display/set scan delay in nano seconds", .usage = "[value]", }, COMMAND_REGISTRATION_DONE }; const struct command_registration mips_m4k_command_handlers[] = { { .chain = mips32_command_handlers, }, { .name = "mips_m4k", .mode = COMMAND_ANY, .help = "mips_m4k command group", .usage = "", .chain = mips_m4k_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct target_type mips_m4k_target = { .name = "mips_m4k", .poll = mips_m4k_poll, .arch_state = mips32_arch_state, .target_request_data = NULL, .halt = mips_m4k_halt, .resume = mips_m4k_resume, .step = mips_m4k_step, .assert_reset = mips_m4k_assert_reset, .deassert_reset = mips_m4k_deassert_reset, .soft_reset_halt = mips_m4k_soft_reset_halt, .get_gdb_reg_list = mips32_get_gdb_reg_list, .read_memory = mips_m4k_read_memory, .write_memory = mips_m4k_write_memory, .bulk_write_memory = mips_m4k_bulk_write_memory, .checksum_memory = mips32_checksum_memory, .blank_check_memory = mips32_blank_check_memory, .run_algorithm = mips32_run_algorithm, .add_breakpoint = mips_m4k_add_breakpoint, .remove_breakpoint = mips_m4k_remove_breakpoint, .add_watchpoint = mips_m4k_add_watchpoint, .remove_watchpoint = mips_m4k_remove_watchpoint, .commands = mips_m4k_command_handlers, .target_create = mips_m4k_target_create, .init_target = mips_m4k_init_target, .examine = mips_m4k_examine, }; openocd-0.7.0/src/target/Makefile.am0000644000175000001440000000503312134336410014171 00000000000000include $(top_srcdir)/common.mk if OOCD_TRACE OOCD_TRACE_FILES = oocd_trace.c else OOCD_TRACE_FILES = endif BIN2C = $(top_builddir)/src/helper/bin2char$(EXEEXT_FOR_BUILD) DEBUG_HANDLER = $(srcdir)/xscale/debug_handler.bin EXTRA_DIST = \ startup.tcl \ $(DEBUG_HANDLER) DEBUG_HEADER = xscale_debug.h BUILT_SOURCES = $(DEBUG_HEADER) CLEANFILES = $(DEBUG_HEADER) $(DEBUG_HEADER): $(BIN2C) $(DEBUG_HANDLER) $(BIN2C) < $(DEBUG_HANDLER) xscale_debug_handler > xscale_debug.h METASOURCES = AUTO noinst_LTLIBRARIES = libtarget.la libtarget_la_SOURCES = \ $(TARGET_CORE_SRC) \ $(ARM_DEBUG_SRC) \ $(ARMV4_5_SRC) \ $(ARMV6_SRC) \ $(ARMV7_SRC) \ $(ARM_MISC_SRC) \ $(AVR32_SRC) \ $(MIPS32_SRC) \ avrt.c \ dsp563xx.c \ dsp563xx_once.c \ dsp5680xx.c \ hla_target.c TARGET_CORE_SRC = \ algorithm.c \ register.c \ image.c \ breakpoints.c \ target.c \ target_request.c \ testee.c \ smp.c ARMV4_5_SRC = \ armv4_5.c \ armv4_5_mmu.c \ armv4_5_cache.c \ $(ARM7_9_SRC) ARM7_9_SRC = \ arm7_9_common.c \ arm7tdmi.c \ arm720t.c \ arm9tdmi.c \ arm920t.c \ arm966e.c \ arm946e.c \ arm926ejs.c \ feroceon.c ARM_MISC_SRC = \ fa526.c \ xscale.c ARMV6_SRC = \ arm11.c \ arm11_dbgtap.c ARMV7_SRC = \ armv7m.c \ cortex_m.c \ armv7a.c \ cortex_a.c ARM_DEBUG_SRC = \ arm_dpm.c \ arm_jtag.c \ arm_disassembler.c \ arm_simulator.c \ arm_semihosting.c \ arm_adi_v5.c \ adi_v5_jtag.c \ adi_v5_swd.c \ embeddedice.c \ trace.c \ etb.c \ etm.c \ $(OOCD_TRACE_FILES) \ etm_dummy.c AVR32_SRC = \ avr32_ap7k.c \ avr32_jtag.c \ avr32_mem.c \ avr32_regs.c MIPS32_SRC = \ mips32.c \ mips_m4k.c \ mips32_pracc.c \ mips32_dmaacc.c \ mips_ejtag.c noinst_HEADERS = \ algorithm.h \ arm.h \ arm_dpm.h \ arm_jtag.h \ arm_adi_v5.h \ arm_disassembler.h \ arm_opcodes.h \ arm_simulator.h \ arm_semihosting.h \ arm7_9_common.h \ arm7tdmi.h \ arm720t.h \ arm9tdmi.h \ arm920t.h \ arm926ejs.h \ arm966e.h \ arm946e.h \ arm11.h \ arm11_dbgtap.h \ armv4_5.h \ armv4_5_mmu.h \ armv4_5_cache.h \ armv7a.h \ armv7m.h \ avrt.h \ dsp563xx.h \ dsp563xx_once.h \ dsp5680xx.h \ breakpoints.h \ cortex_m.h \ cortex_a.h \ embeddedice.h \ etb.h \ etm.h \ etm_dummy.h \ image.h \ mips32.h \ mips_m4k.h \ mips_ejtag.h \ mips32_pracc.h \ mips32_dmaacc.h \ oocd_trace.h \ register.h \ target.h \ target_type.h \ trace.h \ target_request.h \ trace.h \ xscale.h \ smp.h \ avr32_ap7k.h \ avr32_jtag.h \ avr32_mem.h \ avr32_regs.h ocddatadir = $(pkglibdir) nobase_dist_ocddata_DATA = MAINTAINERCLEANFILES = $(srcdir)/Makefile.in openocd-0.7.0/src/target/arm7_9_common.h0000644000175000001440000002007412134336410014756 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2008 by Hongtao Zheng * * hontor@126.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef ARM7_9_COMMON_H #define ARM7_9_COMMON_H #include "arm.h" #include "arm_jtag.h" #define ARM7_9_COMMON_MAGIC 0x0a790a79 /**< */ /** * Structure for items that are common between both ARM7 and ARM9 targets. */ struct arm7_9_common { struct arm arm; uint32_t common_magic; struct arm_jtag jtag_info; /**< JTAG information for target */ struct reg_cache *eice_cache; /**< Embedded ICE register cache */ uint32_t arm_bkpt; /**< ARM breakpoint instruction */ uint16_t thumb_bkpt; /**< Thumb breakpoint instruction */ int sw_breakpoints_added; /**< Specifies which watchpoint software breakpoints are setup on */ int sw_breakpoint_count; /**< keep track of number of software breakpoints we have set */ int breakpoint_count; /**< Current number of set breakpoints */ int wp_available; /**< Current number of available watchpoint units */ int wp_available_max; /**< Maximum number of available watchpoint units */ int wp0_used; /**< Specifies if and how watchpoint unit 0 is used */ int wp1_used; /**< Specifies if and how watchpoint unit 1 is used */ int wp1_used_default; /**< Specifies if and how watchpoint unit 1 is used by default */ int dbgreq_adjust_pc; /**< Amount of PC adjustment caused by a DBGREQ */ bool use_dbgrq; /**< Specifies if DBGRQ should be used to halt the target */ bool need_bypass_before_restart; /**< Specifies if there should be a bypass before a JTAG restart */ bool has_single_step; bool has_monitor_mode; bool has_vector_catch; /**< Specifies if the target has a reset vector catch */ bool debug_entry_from_reset; /**< Specifies if debug entry was from a reset */ bool fast_memory_access; bool dcc_downloads; struct working_area *dcc_working_area; int (*examine_debug_reason)(struct target *target); /**< Function for determining why debug state was entered */ void (*change_to_arm)(struct target *target, uint32_t *r0, uint32_t *pc); /**< Function for changing from Thumb to ARM mode */ void (*read_core_regs)(struct target *target, uint32_t mask, uint32_t *core_regs[16]); /**< Function for reading the core registers */ void (*read_core_regs_target_buffer)(struct target *target, uint32_t mask, void *buffer, int size); void (*read_xpsr)(struct target *target, uint32_t *xpsr, int spsr); /**< Function for reading CPSR or SPSR */ void (*write_xpsr)(struct target *target, uint32_t xpsr, int spsr); /**< Function for writing to CPSR or SPSR */ void (*write_xpsr_im8)(struct target *target, uint8_t xpsr_im, int rot, int spsr); /**< Function for writing an immediate value to CPSR or SPSR */ void (*write_core_regs)(struct target *target, uint32_t mask, uint32_t core_regs[16]); void (*load_word_regs)(struct target *target, uint32_t mask); void (*load_hword_reg)(struct target *target, int num); void (*load_byte_reg)(struct target *target, int num); void (*store_word_regs)(struct target *target, uint32_t mask); void (*store_hword_reg)(struct target *target, int num); void (*store_byte_reg)(struct target *target, int num); void (*write_pc)(struct target *target, uint32_t pc); /**< Function for writing to the program counter */ void (*branch_resume)(struct target *target); void (*branch_resume_thumb)(struct target *target); void (*enable_single_step)(struct target *target, uint32_t next_pc); void (*disable_single_step)(struct target *target); void (*set_special_dbgrq)(struct target *target); /**< Function for setting DBGRQ if the normal way won't work */ int (*post_debug_entry)(struct target *target); /**< Callback function called after entering debug mode */ void (*pre_restore_context)(struct target *target); /**< Callback function called before restoring the processor context */ }; static inline struct arm7_9_common *target_to_arm7_9(struct target *target) { return container_of(target->arch_info, struct arm7_9_common, arm); } static inline bool is_arm7_9(struct arm7_9_common *arm7_9) { return arm7_9->common_magic == ARM7_9_COMMON_MAGIC; } extern const struct command_registration arm7_9_command_handlers[]; int arm7_9_poll(struct target *target); int arm7_9_target_request_data(struct target *target, uint32_t size, uint8_t *buffer); int arm7_9_assert_reset(struct target *target); int arm7_9_deassert_reset(struct target *target); int arm7_9_reset_request_halt(struct target *target); int arm7_9_early_halt(struct target *target); int arm7_9_soft_reset_halt(struct target *target); int arm7_9_halt(struct target *target); int arm7_9_resume(struct target *target, int current, uint32_t address, int handle_breakpoints, int debug_execution); int arm7_9_step(struct target *target, int current, uint32_t address, int handle_breakpoints); int arm7_9_read_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer); int arm7_9_write_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer); int arm7_9_bulk_write_memory(struct target *target, uint32_t address, uint32_t count, const uint8_t *buffer); int arm7_9_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_prams, struct reg_param *reg_param, uint32_t entry_point, void *arch_info); int arm7_9_add_breakpoint(struct target *target, struct breakpoint *breakpoint); int arm7_9_remove_breakpoint(struct target *target, struct breakpoint *breakpoint); int arm7_9_add_watchpoint(struct target *target, struct watchpoint *watchpoint); int arm7_9_remove_watchpoint(struct target *target, struct watchpoint *watchpoint); void arm7_9_enable_eice_step(struct target *target, uint32_t next_pc); void arm7_9_disable_eice_step(struct target *target); int arm7_9_execute_sys_speed(struct target *target); int arm7_9_init_arch_info(struct target *target, struct arm7_9_common *arm7_9); int arm7_9_examine(struct target *target); int arm7_9_check_reset(struct target *target); int arm7_9_endianness_callback(jtag_callback_data_t pu8_in, jtag_callback_data_t i_size, jtag_callback_data_t i_be, jtag_callback_data_t i_flip); #endif /* ARM7_9_COMMON_H */ openocd-0.7.0/src/target/algorithm.h0000644000175000001440000000411712134336410014276 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef ALGORITHM_H #define ALGORITHM_H enum param_direction { PARAM_IN, PARAM_OUT, PARAM_IN_OUT }; struct mem_param { uint32_t address; uint32_t size; uint8_t *value; enum param_direction direction; }; struct reg_param { const char *reg_name; uint32_t size; uint8_t *value; enum param_direction direction; }; void init_mem_param(struct mem_param *param, uint32_t address, uint32_t size, enum param_direction dir); void destroy_mem_param(struct mem_param *param); void init_reg_param(struct reg_param *param, char *reg_name, uint32_t size, enum param_direction dir); void destroy_reg_param(struct reg_param *param); #endif /* ALGORITHM_H */ openocd-0.7.0/src/target/arm920t.h0000644000175000001440000000556512134336410013516 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef ARM920T_H #define ARM920T_H #include "arm9tdmi.h" #include "armv4_5_mmu.h" #define ARM920T_COMMON_MAGIC 0xa920a920 struct arm920t_common { struct arm7_9_common arm7_9_common; uint32_t common_magic; struct armv4_5_mmu_common armv4_5_mmu; uint32_t cp15_control_reg; uint32_t d_fsr; uint32_t i_fsr; uint32_t d_far; uint32_t i_far; int preserve_cache; }; static inline struct arm920t_common *target_to_arm920(struct target *target) { return container_of(target->arch_info, struct arm920t_common, arm7_9_common.arm); } struct arm920t_cache_line { uint32_t cam; uint32_t data[8]; }; struct arm920t_tlb_entry { uint32_t cam; uint32_t ram1; uint32_t ram2; }; int arm920t_arch_state(struct target *target); int arm920t_soft_reset_halt(struct target *target); int arm920t_read_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer); int arm920t_write_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer); int arm920t_post_debug_entry(struct target *target); void arm920t_pre_restore_context(struct target *target); int arm920t_get_ttb(struct target *target, uint32_t *result); int arm920t_disable_mmu_caches(struct target *target, int mmu, int d_u_cache, int i_cache); int arm920t_enable_mmu_caches(struct target *target, int mmu, int d_u_cache, int i_cache); extern const struct command_registration arm920t_command_handlers[]; #endif /* ARM920T_H */ openocd-0.7.0/src/target/xscale.h0000644000175000001440000001151412134336410013566 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef XSCALE_H #define XSCALE_H #include "arm.h" #include "armv4_5_mmu.h" #include "trace.h" #define XSCALE_COMMON_MAGIC 0x58534341 /* These four JTAG instructions are architecturally defined. * Lengths are core-specific; originally 5 bits, later 7. */ #define XSCALE_DBGRX 0x02 #define XSCALE_DBGTX 0x10 #define XSCALE_LDIC 0x07 #define XSCALE_SELDCSR 0x09 /* Possible CPU types */ #define XSCALE_IXP4XX_PXA2XX 0x0 #define XSCALE_PXA3XX 0x4 enum xscale_debug_reason { XSCALE_DBG_REASON_GENERIC, XSCALE_DBG_REASON_RESET, XSCALE_DBG_REASON_TB_FULL, }; enum xscale_trace_entry_type { XSCALE_TRACE_MESSAGE = 0x0, XSCALE_TRACE_ADDRESS = 0x1, }; struct xscale_trace_entry { uint8_t data; enum xscale_trace_entry_type type; }; struct xscale_trace_data { struct xscale_trace_entry *entries; int depth; uint32_t chkpt0; uint32_t chkpt1; uint32_t last_instruction; unsigned int num_checkpoints; struct xscale_trace_data *next; }; enum trace_mode { XSCALE_TRACE_DISABLED, XSCALE_TRACE_FILL, XSCALE_TRACE_WRAP }; struct xscale_trace { struct image *image; /* source for target opcodes */ struct xscale_trace_data *data; /* linked list of collected trace data */ int buffer_fill; /* maximum number of trace runs to read */ int fill_counter; /* running count during trace collection */ enum trace_mode mode; enum arm_state core_state; /* current core state (ARM, Thumb) */ }; struct xscale_common { /* armv4/5 common stuff */ struct arm arm; int common_magic; /* XScale registers (CP15, DBG) */ struct reg_cache *reg_cache; /* current state of the debug handler */ uint32_t handler_address; /* target-endian buffers with exception vectors */ uint32_t low_vectors[8]; uint32_t high_vectors[8]; /* static low vectors */ uint8_t static_low_vectors_set; /* bit field with static vectors set by the user */ uint8_t static_high_vectors_set; /* bit field with static vectors set by the user */ uint32_t static_low_vectors[8]; uint32_t static_high_vectors[8]; /* DCache cleaning */ uint32_t cache_clean_address; /* whether hold_rst and ext_dbg_break should be set */ int hold_rst; int external_debug_break; /* breakpoint / watchpoint handling */ int dbr_available; int dbr0_used; int dbr1_used; int ibcr_available; int ibcr0_used; int ibcr1_used; uint32_t arm_bkpt; uint16_t thumb_bkpt; uint8_t vector_catch; struct xscale_trace trace; int arch_debug_reason; /* MMU/Caches */ struct armv4_5_mmu_common armv4_5_mmu; uint32_t cp15_control_reg; int fast_memory_access; /* CPU variant */ int xscale_variant; }; static inline struct xscale_common * target_to_xscale(struct target *target) { return container_of(target->arch_info, struct xscale_common, arm); } struct xscale_reg { int dbg_handler_number; struct target *target; }; enum { XSCALE_MAINID, /* 0 */ XSCALE_CACHETYPE, XSCALE_CTRL, XSCALE_AUXCTRL, XSCALE_TTB, XSCALE_DAC, XSCALE_FSR, XSCALE_FAR, XSCALE_PID, XSCALE_CPACCESS, XSCALE_IBCR0, /* 10 */ XSCALE_IBCR1, XSCALE_DBR0, XSCALE_DBR1, XSCALE_DBCON, XSCALE_TBREG, XSCALE_CHKPT0, XSCALE_CHKPT1, XSCALE_DCSR, XSCALE_TX, XSCALE_RX, /* 20 */ XSCALE_TXRXCTRL, }; #define ERROR_XSCALE_NO_TRACE_DATA (-700) #endif /* XSCALE_H */ openocd-0.7.0/src/target/target.h0000644000175000001440000005354712137151331013611 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * * * * Copyright (C) ST-Ericsson SA 2011 * * michel.jaouen@stericsson.com : smp minimum support * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef TARGET_H #define TARGET_H struct reg; struct trace; struct command_context; struct breakpoint; struct watchpoint; struct mem_param; struct reg_param; struct target_list; /* * TARGET_UNKNOWN = 0: we don't know anything about the target yet * TARGET_RUNNING = 1: the target is executing user code * TARGET_HALTED = 2: the target is not executing code, and ready to talk to the * debugger. on an xscale it means that the debug handler is executing * TARGET_RESET = 3: the target is being held in reset (only a temporary state, * not sure how this is used with all the recent changes) * TARGET_DEBUG_RUNNING = 4: the target is running, but it is executing code on * behalf of the debugger (e.g. algorithm for flashing) * * also see: target_state_name(); */ enum target_state { TARGET_UNKNOWN = 0, TARGET_RUNNING = 1, TARGET_HALTED = 2, TARGET_RESET = 3, TARGET_DEBUG_RUNNING = 4, }; enum nvp_assert { NVP_DEASSERT, NVP_ASSERT, }; enum target_reset_mode { RESET_UNKNOWN = 0, RESET_RUN = 1, /* reset and let target run */ RESET_HALT = 2, /* reset and halt target out of reset */ RESET_INIT = 3, /* reset and halt target out of reset, then run init script */ }; enum target_debug_reason { DBG_REASON_DBGRQ = 0, DBG_REASON_BREAKPOINT = 1, DBG_REASON_WATCHPOINT = 2, DBG_REASON_WPTANDBKPT = 3, DBG_REASON_SINGLESTEP = 4, DBG_REASON_NOTHALTED = 5, DBG_REASON_UNDEFINED = 6 }; enum target_endianness { TARGET_ENDIAN_UNKNOWN = 0, TARGET_BIG_ENDIAN = 1, TARGET_LITTLE_ENDIAN = 2 }; struct working_area { uint32_t address; uint32_t size; bool free; uint8_t *backup; struct working_area **user; struct working_area *next; }; struct gdb_service { struct target *target; /* field for smp display */ /* element 0 coreid currently displayed ( 1 till n) */ /* element 1 coreid to be displayed at next resume 1 till n 0 means resume * all cores core displayed */ int32_t core[2]; }; /* target back off timer */ struct backoff_timer { int times; int count; }; /* target_type.h contains the full definition of struct target_type */ struct target { struct target_type *type; /* target type definition (name, access functions) */ const char *cmd_name; /* tcl Name of target */ int target_number; /* DO NOT USE! field to be removed in 2010 */ struct jtag_tap *tap; /* where on the jtag chain is this */ int32_t coreid; /* which device on the TAP? */ const char *variant; /* what variant of this chip is it? */ /** * Indicates whether this target has been examined. * * Do @b not access this field directly, use target_was_examined() * or target_set_examined(). */ bool examined; /** * true if the target is currently running a downloaded * "algorithm" instead of arbitrary user code. OpenOCD code * invoking algorithms is trusted to maintain correctness of * any cached state (e.g. for flash status), which arbitrary * code will have no reason to know about. */ bool running_alg; struct target_event_action *event_action; int reset_halt; /* attempt resetting the CPU into the halted mode? */ uint32_t working_area; /* working area (initialised RAM). Evaluated * upon first allocation from virtual/physical address. */ bool working_area_virt_spec; /* virtual address specified? */ uint32_t working_area_virt; /* virtual address */ bool working_area_phys_spec; /* virtual address specified? */ uint32_t working_area_phys; /* physical address */ uint32_t working_area_size; /* size in bytes */ uint32_t backup_working_area; /* whether the content of the working area has to be preserved */ struct working_area *working_areas;/* list of allocated working areas */ enum target_debug_reason debug_reason;/* reason why the target entered debug state */ enum target_endianness endianness; /* target endianness */ /* also see: target_state_name() */ enum target_state state; /* the current backend-state (running, halted, ...) */ struct reg_cache *reg_cache; /* the first register cache of the target (core regs) */ struct breakpoint *breakpoints; /* list of breakpoints */ struct watchpoint *watchpoints; /* list of watchpoints */ struct trace *trace_info; /* generic trace information */ struct debug_msg_receiver *dbgmsg; /* list of debug message receivers */ uint32_t dbg_msg_enabled; /* debug message status */ void *arch_info; /* architecture specific information */ struct target *next; /* next target in list */ int display; /* display async info in telnet session. Do not display * lots of halted/resumed info when stepping in debugger. */ bool halt_issued; /* did we transition to halted state? */ long long halt_issued_time; /* Note time when halt was issued */ bool dbgbase_set; /* By default the debug base is not set */ uint32_t dbgbase; /* Really a Cortex-A specific option, but there is no * system in place to support target specific options * currently. */ struct rtos *rtos; /* Instance of Real Time Operating System support */ bool rtos_auto_detect; /* A flag that indicates that the RTOS has been specified as "auto" * and must be detected when symbols are offered */ struct backoff_timer backoff; int smp; /* add some target attributes for smp support */ struct target_list *head; /* the gdb service is there in case of smp, we have only one gdb server * for all smp target * the target attached to the gdb is changing dynamically by changing * gdb_service->target pointer */ struct gdb_service *gdb_service; }; struct target_list { struct target *target; struct target_list *next; }; /** Returns the instance-specific name of the specified target. */ static inline const char *target_name(struct target *target) { return target->cmd_name; } const char *debug_reason_name(struct target *t); enum target_event { /* allow GDB to do stuff before others handle the halted event, * this is in lieu of defining ordering of invocation of events, * which would be more complicated * * Telling GDB to halt does not mean that the target stopped running, * simply that we're dropping out of GDB's waiting for step or continue. * * This can be useful when e.g. detecting power dropout. */ TARGET_EVENT_GDB_HALT, TARGET_EVENT_HALTED, /* target entered debug state from normal execution or reset */ TARGET_EVENT_RESUMED, /* target resumed to normal execution */ TARGET_EVENT_RESUME_START, TARGET_EVENT_RESUME_END, TARGET_EVENT_GDB_START, /* debugger started execution (step/run) */ TARGET_EVENT_GDB_END, /* debugger stopped execution (step/run) */ TARGET_EVENT_RESET_START, TARGET_EVENT_RESET_ASSERT_PRE, TARGET_EVENT_RESET_ASSERT, /* C code uses this instead of SRST */ TARGET_EVENT_RESET_ASSERT_POST, TARGET_EVENT_RESET_DEASSERT_PRE, TARGET_EVENT_RESET_DEASSERT_POST, TARGET_EVENT_RESET_HALT_PRE, TARGET_EVENT_RESET_HALT_POST, TARGET_EVENT_RESET_WAIT_PRE, TARGET_EVENT_RESET_WAIT_POST, TARGET_EVENT_RESET_INIT, TARGET_EVENT_RESET_END, TARGET_EVENT_DEBUG_HALTED, /* target entered debug state, but was executing on behalf of the debugger */ TARGET_EVENT_DEBUG_RESUMED, /* target resumed to execute on behalf of the debugger */ TARGET_EVENT_EXAMINE_START, TARGET_EVENT_EXAMINE_END, TARGET_EVENT_GDB_ATTACH, TARGET_EVENT_GDB_DETACH, TARGET_EVENT_GDB_FLASH_ERASE_START, TARGET_EVENT_GDB_FLASH_ERASE_END, TARGET_EVENT_GDB_FLASH_WRITE_START, TARGET_EVENT_GDB_FLASH_WRITE_END, }; struct target_event_action { enum target_event event; struct Jim_Interp *interp; struct Jim_Obj *body; int has_percent; struct target_event_action *next; }; bool target_has_event_action(struct target *target, enum target_event event); struct target_event_callback { int (*callback)(struct target *target, enum target_event event, void *priv); void *priv; struct target_event_callback *next; }; struct target_timer_callback { int (*callback)(void *priv); int time_ms; int periodic; struct timeval when; void *priv; struct target_timer_callback *next; }; int target_register_commands(struct command_context *cmd_ctx); int target_examine(void); int target_register_event_callback( int (*callback)(struct target *target, enum target_event event, void *priv), void *priv); int target_unregister_event_callback( int (*callback)(struct target *target, enum target_event event, void *priv), void *priv); /* Poll the status of the target, detect any error conditions and report them. * * Also note that this fn will clear such error conditions, so a subsequent * invocation will then succeed. * * These error conditions can be "sticky" error conditions. E.g. writing * to memory could be implemented as an open loop and if memory writes * fails, then a note is made of it, the error is sticky, but the memory * write loop still runs to completion. This improves performance in the * normal case as there is no need to verify that every single write succeed, * yet it is possible to detect error conditions. */ int target_poll(struct target *target); int target_resume(struct target *target, int current, uint32_t address, int handle_breakpoints, int debug_execution); int target_halt(struct target *target); int target_call_event_callbacks(struct target *target, enum target_event event); /** * The period is very approximate, the callback can happen much more often * or much more rarely than specified */ int target_register_timer_callback(int (*callback)(void *priv), int time_ms, int periodic, void *priv); int target_call_timer_callbacks(void); /** * Invoke this to ensure that e.g. polling timer callbacks happen before * a synchronous command completes. */ int target_call_timer_callbacks_now(void); struct target *get_current_target(struct command_context *cmd_ctx); struct target *get_target(const char *id); /** * Get the target type name. * * This routine is a wrapper for the target->type->name field. * Note that this is not an instance-specific name for his target. */ const char *target_type_name(struct target *target); /** * Examine the specified @a target, letting it perform any * Initialisation that requires JTAG access. * * This routine is a wrapper for target->type->examine. */ int target_examine_one(struct target *target); /** @returns @c true if target_set_examined() has been called. */ static inline bool target_was_examined(struct target *target) { return target->examined; } /** Sets the @c examined flag for the given target. */ /** Use in target->type->examine() after one-time setup is done. */ static inline void target_set_examined(struct target *target) { target->examined = true; } /** * Add the @a breakpoint for @a target. * * This routine is a wrapper for target->type->add_breakpoint. */ int target_add_breakpoint(struct target *target, struct breakpoint *breakpoint); /** * Add the @a ContextID breakpoint for @a target. * * This routine is a wrapper for target->type->add_context_breakpoint. */ int target_add_context_breakpoint(struct target *target, struct breakpoint *breakpoint); /** * Add the @a ContextID & IVA breakpoint for @a target. * * This routine is a wrapper for target->type->add_hybrid_breakpoint. */ int target_add_hybrid_breakpoint(struct target *target, struct breakpoint *breakpoint); /** * Remove the @a breakpoint for @a target. * * This routine is a wrapper for target->type->remove_breakpoint. */ int target_remove_breakpoint(struct target *target, struct breakpoint *breakpoint); /** * Add the @a watchpoint for @a target. * * This routine is a wrapper for target->type->add_watchpoint. */ int target_add_watchpoint(struct target *target, struct watchpoint *watchpoint); /** * Remove the @a watchpoint for @a target. * * This routine is a wrapper for target->type->remove_watchpoint. */ int target_remove_watchpoint(struct target *target, struct watchpoint *watchpoint); /** * Obtain the registers for GDB. * * This routine is a wrapper for target->type->get_gdb_reg_list. */ int target_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size); /** * Step the target. * * This routine is a wrapper for target->type->step. */ int target_step(struct target *target, int current, uint32_t address, int handle_breakpoints); /** * Run an algorithm on the @a target given. * * This routine is a wrapper for target->type->run_algorithm. */ int target_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_param, uint32_t entry_point, uint32_t exit_point, int timeout_ms, void *arch_info); /** * Starts an algorithm in the background on the @a target given. * * This routine is a wrapper for target->type->start_algorithm. */ int target_start_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, uint32_t entry_point, uint32_t exit_point, void *arch_info); /** * Wait for an algorithm on the @a target given. * * This routine is a wrapper for target->type->wait_algorithm. */ int target_wait_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, uint32_t exit_point, int timeout_ms, void *arch_info); /** * This routine is a wrapper for asynchronous algorithms. * */ int target_run_flash_async_algorithm(struct target *target, uint8_t *buffer, uint32_t count, int block_size, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, uint32_t buffer_start, uint32_t buffer_size, uint32_t entry_point, uint32_t exit_point, void *arch_info); /** * Read @a count items of @a size bytes from the memory of @a target at * the @a address given. * * This routine is a wrapper for target->type->read_memory. */ int target_read_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer); int target_read_phys_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer); /** * Write @a count items of @a size bytes to the memory of @a target at * the @a address given. @a address must be aligned to @a size * in target memory. * * The endianness is the same in the host and target memory for this * function. * * \todo TODO: * Really @a buffer should have been defined as "const void *" and * @a buffer should have been aligned to @a size in the host memory. * * This is not enforced via e.g. assert's today and e.g. the * target_write_buffer fn breaks this assumption. * * This routine is wrapper for target->type->write_memory. */ int target_write_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer); int target_write_phys_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer); /* * Write to target memory using the virtual address. * * Note that this fn is used to implement software breakpoints. Targets * can implement support for software breakpoints to memory marked as read * only by making this fn write to ram even if it is read only(MMU or * MPUs). * * It is sufficient to implement for writing a single word(16 or 32 in * ARM32/16 bit case) to write the breakpoint to ram. * * The target should also take care of "other things" to make sure that * software breakpoints can be written using this function. E.g. * when there is a separate instruction and data cache, this fn must * make sure that the instruction cache is synced up to the potential * code change that can happen as a result of the memory write(typically * by invalidating the cache). * * The high level wrapper fn in target.c will break down this memory write * request to multiple write requests to the target driver to e.g. guarantee * that writing 4 bytes to an aligned address happens with a single 32 bit * write operation, thus making this fn suitable to e.g. write to special * peripheral registers which do not support byte operations. */ int target_write_buffer(struct target *target, uint32_t address, uint32_t size, const uint8_t *buffer); int target_read_buffer(struct target *target, uint32_t address, uint32_t size, uint8_t *buffer); int target_checksum_memory(struct target *target, uint32_t address, uint32_t size, uint32_t *crc); int target_blank_check_memory(struct target *target, uint32_t address, uint32_t size, uint32_t *blank); int target_wait_state(struct target *target, enum target_state state, int ms); /** Return the *name* of this targets current state */ const char *target_state_name(struct target *target); /* DANGER!!!!! * * if "area" passed in to target_alloc_working_area() points to a memory * location that goes out of scope (e.g. a pointer on the stack), then * the caller of target_alloc_working_area() is responsible for invoking * target_free_working_area() before "area" goes out of scope. * * target_free_all_working_areas() will NULL out the "area" pointer * upon resuming or resetting the CPU. * */ int target_alloc_working_area(struct target *target, uint32_t size, struct working_area **area); /* Same as target_alloc_working_area, except that no error is logged * when ERROR_TARGET_RESOURCE_NOT_AVAILABLE is returned. * * This allows the calling code to *try* to allocate target memory * and have a fallback to another behaviour(slower?). */ int target_alloc_working_area_try(struct target *target, uint32_t size, struct working_area **area); int target_free_working_area(struct target *target, struct working_area *area); void target_free_all_working_areas(struct target *target); uint32_t target_get_working_area_avail(struct target *target); extern struct target *all_targets; uint32_t target_buffer_get_u32(struct target *target, const uint8_t *buffer); uint32_t target_buffer_get_u24(struct target *target, const uint8_t *buffer); uint16_t target_buffer_get_u16(struct target *target, const uint8_t *buffer); void target_buffer_set_u32(struct target *target, uint8_t *buffer, uint32_t value); void target_buffer_set_u24(struct target *target, uint8_t *buffer, uint32_t value); void target_buffer_set_u16(struct target *target, uint8_t *buffer, uint16_t value); void target_buffer_get_u32_array(struct target *target, const uint8_t *buffer, uint32_t count, uint32_t *dstbuf); void target_buffer_get_u16_array(struct target *target, const uint8_t *buffer, uint32_t count, uint16_t *dstbuf); void target_buffer_set_u32_array(struct target *target, uint8_t *buffer, uint32_t count, uint32_t *srcbuf); void target_buffer_set_u16_array(struct target *target, uint8_t *buffer, uint32_t count, uint16_t *srcbuf); int target_read_u32(struct target *target, uint32_t address, uint32_t *value); int target_read_u16(struct target *target, uint32_t address, uint16_t *value); int target_read_u8(struct target *target, uint32_t address, uint8_t *value); int target_write_u32(struct target *target, uint32_t address, uint32_t value); int target_write_u16(struct target *target, uint32_t address, uint16_t value); int target_write_u8(struct target *target, uint32_t address, uint8_t value); /* Issues USER() statements with target state information */ int target_arch_state(struct target *target); void target_handle_event(struct target *t, enum target_event e); #define ERROR_TARGET_INVALID (-300) #define ERROR_TARGET_INIT_FAILED (-301) #define ERROR_TARGET_TIMEOUT (-302) #define ERROR_TARGET_NOT_HALTED (-304) #define ERROR_TARGET_FAILURE (-305) #define ERROR_TARGET_UNALIGNED_ACCESS (-306) #define ERROR_TARGET_DATA_ABORT (-307) #define ERROR_TARGET_RESOURCE_NOT_AVAILABLE (-308) #define ERROR_TARGET_TRANSLATION_FAULT (-309) #define ERROR_TARGET_NOT_RUNNING (-310) #define ERROR_TARGET_NOT_EXAMINED (-311) extern bool get_target_reset_nag(void); #endif /* TARGET_H */ openocd-0.7.0/src/target/armv4_5.h0000644000175000001440000000535412134336410013571 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2009 by Øyvind Harboe * * oyvind.harboe@zylin.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef ARMV4_5_H #define ARMV4_5_H /* This stuff "knows" that its callers aren't talking * to microcontroller profile (current Cortex-M) parts. * We want to phase it out so core code can be shared. */ /* OBSOLETE, DO NOT USE IN NEW CODE! The "number" of an arm_mode is an * index into the armv4_5_core_reg_map array. Its remaining users are * remnants which could as easily walk * the register cache directly as * use the expensive ARMV4_5_CORE_REG_MODE() macro. */ int arm_mode_to_number(enum arm_mode mode); enum arm_mode armv4_5_number_to_mode(int number); extern const int armv4_5_core_reg_map[8][17]; #define ARMV4_5_CORE_REG_MODE(cache, mode, num) \ (cache->reg_list[armv4_5_core_reg_map[arm_mode_to_number(mode)][num]]) /* offset into armv4_5 core register cache -- OBSOLETE, DO NOT USE! */ enum { ARMV4_5_CPSR = 31, }; #endif /* ARMV4_5_H */ openocd-0.7.0/src/target/arm_adi_v5.h0000644000175000001440000004067512137151331014327 00000000000000/*************************************************************************** * Copyright (C) 2006 by Magnus Lundin * * lundin@mlu.mine.nu * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef ARM_ADI_V5_H #define ARM_ADI_V5_H /** * @file * This defines formats and data structures used to talk to ADIv5 entities. * Those include a DAP, different types of Debug Port (DP), and memory mapped * resources accessed through a MEM-AP. */ #include "arm_jtag.h" /* FIXME remove these JTAG-specific decls when mem_ap_read_buf_u32() * is no longer JTAG-specific */ #define JTAG_DP_DPACC 0xA #define JTAG_DP_APACC 0xB /* three-bit ACK values for SWD access (sent LSB first) */ #define SWD_ACK_OK 0x4 #define SWD_ACK_WAIT 0x2 #define SWD_ACK_FAULT 0x1 #define DPAP_WRITE 0 #define DPAP_READ 1 /* A[3:0] for DP registers; A[1:0] are always zero. * - JTAG accesses all of these via JTAG_DP_DPACC, except for * IDCODE (JTAG_DP_IDCODE) and ABORT (JTAG_DP_ABORT). * - SWD accesses these directly, sometimes needing SELECT.CTRLSEL */ #define DP_IDCODE 0 /* SWD: read */ #define DP_ABORT 0 /* SWD: write */ #define DP_CTRL_STAT 0x4 /* r/w */ #define DP_WCR 0x4 /* SWD: r/w (mux CTRLSEL) */ #define DP_RESEND 0x8 /* SWD: read */ #define DP_SELECT 0x8 /* JTAG: r/w; SWD: write */ #define DP_RDBUFF 0xC /* read-only */ #define WCR_TO_TRN(wcr) (1 + (3 & ((wcr)) >> 8)) /* 1..4 clocks */ #define WCR_TO_PRESCALE(wcr) (7 & ((wcr))) /* impl defined */ /* Fields of the DP's AP ABORT register */ #define DAPABORT (1 << 0) #define STKCMPCLR (1 << 1) /* SWD-only */ #define STKERRCLR (1 << 2) /* SWD-only */ #define WDERRCLR (1 << 3) /* SWD-only */ #define ORUNERRCLR (1 << 4) /* SWD-only */ /* Fields of the DP's CTRL/STAT register */ #define CORUNDETECT (1 << 0) #define SSTICKYORUN (1 << 1) /* 3:2 - transaction mode (e.g. pushed compare) */ #define SSTICKYCMP (1 << 4) #define SSTICKYERR (1 << 5) #define READOK (1 << 6) /* SWD-only */ #define WDATAERR (1 << 7) /* SWD-only */ /* 11:8 - mask lanes for pushed compare or verify ops */ /* 21:12 - transaction counter */ #define CDBGRSTREQ (1 << 26) #define CDBGRSTACK (1 << 27) #define CDBGPWRUPREQ (1 << 28) #define CDBGPWRUPACK (1 << 29) #define CSYSPWRUPREQ (1 << 30) #define CSYSPWRUPACK (1 << 31) /* MEM-AP register addresses */ /* TODO: rename as MEM_AP_REG_* */ #define AP_REG_CSW 0x00 #define AP_REG_TAR 0x04 #define AP_REG_DRW 0x0C #define AP_REG_BD0 0x10 #define AP_REG_BD1 0x14 #define AP_REG_BD2 0x18 #define AP_REG_BD3 0x1C #define AP_REG_CFG 0xF4 /* big endian? */ #define AP_REG_BASE 0xF8 /* Generic AP register address */ #define AP_REG_IDR 0xFC /* Fields of the MEM-AP's CSW register */ #define CSW_8BIT 0 #define CSW_16BIT 1 #define CSW_32BIT 2 #define CSW_ADDRINC_MASK (3 << 4) #define CSW_ADDRINC_OFF 0 #define CSW_ADDRINC_SINGLE (1 << 4) #define CSW_ADDRINC_PACKED (2 << 4) #define CSW_DEVICE_EN (1 << 6) #define CSW_TRIN_PROG (1 << 7) #define CSW_SPIDEN (1 << 23) /* 30:24 - implementation-defined! */ #define CSW_HPROT (1 << 25) /* ? */ #define CSW_MASTER_DEBUG (1 << 29) /* ? */ #define CSW_SPROT (1 << 30) #define CSW_DBGSWENABLE (1 << 31) /** * This represents an ARM Debug Interface (v5) Debug Access Port (DAP). * A DAP has two types of component: one Debug Port (DP), which is a * transport agent; and at least one Access Port (AP), controlling * resource access. Most common is a MEM-AP, for memory access. * * There are two basic DP transports: JTAG, and ARM's low pin-count SWD. * Accordingly, this interface is responsible for hiding the transport * differences so upper layer code can largely ignore them. * * When the chip is implemented with JTAG-DP or SW-DP, the transport is * fixed as JTAG or SWD, respectively. Chips incorporating SWJ-DP permit * a choice made at board design time (by only using the SWD pins), or * as part of setting up a debug session (if all the dual-role JTAG/SWD * signals are available). */ struct adiv5_dap { const struct dap_ops *ops; struct arm_jtag *jtag_info; /* Control config */ uint32_t dp_ctrl_stat; uint32_t apcsw[256]; uint32_t apsel; /** * Cache for DP_SELECT bits identifying the current AP. A DAP may * connect to multiple APs, such as one MEM-AP for general access, * another reserved for accessing debug modules, and a JTAG-DP. * "-1" indicates no cached value. */ uint32_t ap_current; /** * Cache for DP_SELECT bits identifying the current four-word AP * register bank. This caches AP register addresss bits 7:4; JTAG * and SWD access primitves pass address bits 3:2; bits 1:0 are zero. * "-1" indicates no cached value. */ uint32_t ap_bank_value; /** * Cache for (MEM-AP) AP_REG_CSW register value. This is written to * configure an access mode, such as autoincrementing AP_REG_TAR during * word access. "-1" indicates no cached value. */ uint32_t ap_csw_value; /** * Cache for (MEM-AP) AP_REG_TAR register value This is written to * configure the address being read or written * "-1" indicates no cached value. */ uint32_t ap_tar_value; /* information about current pending SWjDP-AHBAP transaction */ uint8_t ack; /** * Configures how many extra tck clocks are added after starting a * MEM-AP access before we try to read its status (and/or result). */ uint32_t memaccess_tck; /* Size of TAR autoincrement block, ARM ADI Specification requires at least 10 bits */ uint32_t tar_autoincr_block; }; /** * Transport-neutral representation of queued DAP transactions, supporting * both JTAG and SWD transports. All submitted transactions are logically * queued, until the queue is executed by run(). Some implementations might * execute transactions as soon as they're submitted, but no status is made * availablue until run(). */ struct dap_ops { /** If the DAP transport isn't SWD, it must be JTAG. Upper level * code may need to care about the difference in some cases. */ bool is_swd; /** Reads the DAP's IDCODe register. */ int (*queue_idcode_read)(struct adiv5_dap *dap, uint8_t *ack, uint32_t *data); /** DP register read. */ int (*queue_dp_read)(struct adiv5_dap *dap, unsigned reg, uint32_t *data); /** DP register write. */ int (*queue_dp_write)(struct adiv5_dap *dap, unsigned reg, uint32_t data); /** AP register read. */ int (*queue_ap_read)(struct adiv5_dap *dap, unsigned reg, uint32_t *data); /** AP register write. */ int (*queue_ap_write)(struct adiv5_dap *dap, unsigned reg, uint32_t data); /** AP read block. */ int (*queue_ap_read_block)(struct adiv5_dap *dap, unsigned reg, uint32_t blocksize, uint8_t *buffer); /** AP operation abort. */ int (*queue_ap_abort)(struct adiv5_dap *dap, uint8_t *ack); /** Executes all queued DAP operations. */ int (*run)(struct adiv5_dap *dap); }; /* * Access Port types */ enum ap_type { AP_TYPE_AHB_AP = 0x01, /* AHB Memory-AP */ AP_TYPE_APB_AP = 0x02, /* APB Memory-AP */ AP_TYPE_JTAG_AP = 0x10 /* JTAG-AP - JTAG master for controlling other JTAG devices */ }; /** * Queue an IDCODE register read. This is primarily useful for SWD * transports, where it is required as part of link initialization. * (For JTAG, this register is read as part of scan chain setup.) * * @param dap The DAP used for reading. * @param ack Pointer to where transaction status will be stored. * @param data Pointer saying where to store the IDCODE value. * * @return ERROR_OK for success, else a fault code. */ static inline int dap_queue_idcode_read(struct adiv5_dap *dap, uint8_t *ack, uint32_t *data) { assert(dap->ops != NULL); return dap->ops->queue_idcode_read(dap, ack, data); } /** * Queue a DP register read. * Note that not all DP registers are readable; also, that JTAG and SWD * have slight differences in DP register support. * * @param dap The DAP used for reading. * @param reg The two-bit number of the DP register being read. * @param data Pointer saying where to store the register's value * (in host endianness). * * @return ERROR_OK for success, else a fault code. */ static inline int dap_queue_dp_read(struct adiv5_dap *dap, unsigned reg, uint32_t *data) { assert(dap->ops != NULL); return dap->ops->queue_dp_read(dap, reg, data); } /** * Queue a DP register write. * Note that not all DP registers are writable; also, that JTAG and SWD * have slight differences in DP register support. * * @param dap The DAP used for writing. * @param reg The two-bit number of the DP register being written. * @param data Value being written (host endianness) * * @return ERROR_OK for success, else a fault code. */ static inline int dap_queue_dp_write(struct adiv5_dap *dap, unsigned reg, uint32_t data) { assert(dap->ops != NULL); return dap->ops->queue_dp_write(dap, reg, data); } /** * Queue an AP register read. * * @param dap The DAP used for reading. * @param reg The number of the AP register being read. * @param data Pointer saying where to store the register's value * (in host endianness). * * @return ERROR_OK for success, else a fault code. */ static inline int dap_queue_ap_read(struct adiv5_dap *dap, unsigned reg, uint32_t *data) { assert(dap->ops != NULL); return dap->ops->queue_ap_read(dap, reg, data); } /** * Queue an AP register write. * * @param dap The DAP used for writing. * @param reg The number of the AP register being written. * @param data Value being written (host endianness) * * @return ERROR_OK for success, else a fault code. */ static inline int dap_queue_ap_write(struct adiv5_dap *dap, unsigned reg, uint32_t data) { assert(dap->ops != NULL); return dap->ops->queue_ap_write(dap, reg, data); } /** * Queue an AP block read. * * @param dap The DAP used for reading. * @param reg The number of the AP register being read. * @param blocksize The number of the AP register being read. * @param buffer Pointer saying where to store the data * (in host endianness). * * @return ERROR_OK for success, else a fault code. */ static inline int dap_queue_ap_read_block(struct adiv5_dap *dap, unsigned reg, unsigned blocksize, uint8_t *buffer) { assert(dap->ops != NULL); return dap->ops->queue_ap_read_block(dap, reg, blocksize, buffer); } /** * Queue an AP abort operation. The current AP transaction is aborted, * including any update of the transaction counter. The AP is left in * an unknown state (so it must be re-initialized). For use only after * the AP has reported WAIT status for an extended period. * * @param dap The DAP used for writing. * @param ack Pointer to where transaction status will be stored. * * @return ERROR_OK for success, else a fault code. */ static inline int dap_queue_ap_abort(struct adiv5_dap *dap, uint8_t *ack) { assert(dap->ops != NULL); return dap->ops->queue_ap_abort(dap, ack); } /** * Perform all queued DAP operations, and clear any errors posted in the * CTRL_STAT register when they are done. Note that if more than one AP * operation will be queued, one of the first operations in the queue * should probably enable CORUNDETECT in the CTRL/STAT register. * * @param dap The DAP used. * * @return ERROR_OK for success, else a fault code. */ static inline int dap_run(struct adiv5_dap *dap) { assert(dap->ops != NULL); return dap->ops->run(dap); } /** Accessor for currently selected DAP-AP number (0..255) */ static inline uint8_t dap_ap_get_select(struct adiv5_dap *swjdp) { return (uint8_t)(swjdp->ap_current >> 24); } /* AP selection applies to future AP transactions */ void dap_ap_select(struct adiv5_dap *dap, uint8_t ap); /* Queued AP transactions */ int dap_setup_accessport(struct adiv5_dap *swjdp, uint32_t csw, uint32_t tar); /* Queued MEM-AP memory mapped single word transfers */ int mem_ap_read_u32(struct adiv5_dap *swjdp, uint32_t address, uint32_t *value); int mem_ap_write_u32(struct adiv5_dap *swjdp, uint32_t address, uint32_t value); /* Synchronous MEM-AP memory mapped single word transfers */ int mem_ap_read_atomic_u32(struct adiv5_dap *swjdp, uint32_t address, uint32_t *value); int mem_ap_write_atomic_u32(struct adiv5_dap *swjdp, uint32_t address, uint32_t value); /* MEM-AP memory mapped bus block transfers */ int mem_ap_read_buf_u8(struct adiv5_dap *swjdp, uint8_t *buffer, int count, uint32_t address); int mem_ap_read_buf_u16(struct adiv5_dap *swjdp, uint8_t *buffer, int count, uint32_t address); int mem_ap_read_buf_u32(struct adiv5_dap *swjdp, uint8_t *buffer, int count, uint32_t address, bool addr_incr); int mem_ap_write_buf_u8(struct adiv5_dap *swjdp, const uint8_t *buffer, int count, uint32_t address); int mem_ap_write_buf_u16(struct adiv5_dap *swjdp, const uint8_t *buffer, int count, uint32_t address); int mem_ap_write_buf_u32(struct adiv5_dap *swjdp, const uint8_t *buffer, int count, uint32_t address, bool addr_incr); /* Queued MEM-AP memory mapped single word transfers with selection of ap */ int mem_ap_sel_read_u32(struct adiv5_dap *swjdp, uint8_t ap, uint32_t address, uint32_t *value); int mem_ap_sel_write_u32(struct adiv5_dap *swjdp, uint8_t ap, uint32_t address, uint32_t value); /* Synchronous MEM-AP memory mapped single word transfers with selection of ap */ int mem_ap_sel_read_atomic_u32(struct adiv5_dap *swjdp, uint8_t ap, uint32_t address, uint32_t *value); int mem_ap_sel_write_atomic_u32(struct adiv5_dap *swjdp, uint8_t ap, uint32_t address, uint32_t value); /* Non incrementing buffer functions for accessing fifos */ int mem_ap_sel_read_buf_u32_noincr(struct adiv5_dap *swjdp, uint8_t ap, uint8_t *buffer, int count, uint32_t address); int mem_ap_sel_write_buf_u32_noincr(struct adiv5_dap *swjdp, uint8_t ap, const uint8_t *buffer, int count, uint32_t address); /* MEM-AP memory mapped bus block transfers with selection of ap */ int mem_ap_sel_read_buf_u8(struct adiv5_dap *swjdp, uint8_t ap, uint8_t *buffer, int count, uint32_t address); int mem_ap_sel_read_buf_u16(struct adiv5_dap *swjdp, uint8_t ap, uint8_t *buffer, int count, uint32_t address); int mem_ap_sel_read_buf_u32(struct adiv5_dap *swjdp, uint8_t ap, uint8_t *buffer, int count, uint32_t address); int mem_ap_sel_write_buf_u8(struct adiv5_dap *swjdp, uint8_t ap, const uint8_t *buffer, int count, uint32_t address); int mem_ap_sel_write_buf_u16(struct adiv5_dap *swjdp, uint8_t ap, const uint8_t *buffer, int count, uint32_t address); int mem_ap_sel_write_buf_u32(struct adiv5_dap *swjdp, uint8_t ap, const uint8_t *buffer, int count, uint32_t address); /* Initialisation of the debug system, power domains and registers */ int ahbap_debugport_init(struct adiv5_dap *swjdp); /* Probe the AP for ROM Table location */ int dap_get_debugbase(struct adiv5_dap *dap, int ap, uint32_t *dbgbase, uint32_t *apid); /* Probe Access Ports to find a particular type */ int dap_find_ap(struct adiv5_dap *dap, enum ap_type type_to_find, uint8_t *ap_num_out); /* Lookup CoreSight component */ int dap_lookup_cs_component(struct adiv5_dap *dap, int ap, uint32_t dbgbase, uint8_t type, uint32_t *addr); struct target; /* Put debug link into SWD mode */ int dap_to_swd(struct target *target); /* Put debug link into JTAG mode */ int dap_to_jtag(struct target *target); extern const struct command_registration dap_command_handlers[]; #endif openocd-0.7.0/src/target/arm966e.c0000644000175000001440000002060612134336410013475 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm966e.h" #include "target_type.h" #include "arm_opcodes.h" #if 0 #define _DEBUG_INSTRUCTION_EXECUTION_ #endif int arm966e_init_arch_info(struct target *target, struct arm966e_common *arm966e, struct jtag_tap *tap) { struct arm7_9_common *arm7_9 = &arm966e->arm7_9_common; /* initialize arm7/arm9 specific info (including armv4_5) */ arm9tdmi_init_arch_info(target, arm7_9, tap); arm966e->common_magic = ARM966E_COMMON_MAGIC; /* The ARM966E-S implements the ARMv5TE architecture which * has the BKPT instruction, so we don't have to use a watchpoint comparator */ arm7_9->arm_bkpt = ARMV5_BKPT(0x0); arm7_9->thumb_bkpt = ARMV5_T_BKPT(0x0) & 0xffff; return ERROR_OK; } static int arm966e_target_create(struct target *target, Jim_Interp *interp) { struct arm966e_common *arm966e = calloc(1, sizeof(struct arm966e_common)); return arm966e_init_arch_info(target, arm966e, target->tap); } static int arm966e_verify_pointer(struct command_context *cmd_ctx, struct arm966e_common *arm966e) { if (arm966e->common_magic != ARM966E_COMMON_MAGIC) { command_print(cmd_ctx, "target is not an ARM966"); return ERROR_TARGET_INVALID; } return ERROR_OK; } /* * REVISIT: The "read_cp15" and "write_cp15" commands could hook up * to eventual mrc() and mcr() routines ... the reg_addr values being * constructed (for CP15 only) from Opcode_1, Opcode_2, and CRn values. * See section 7.3 of the ARM966E-S TRM. */ static int arm966e_read_cp15(struct target *target, int reg_addr, uint32_t *value) { int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; struct scan_field fields[3]; uint8_t reg_addr_buf = reg_addr & 0x3f; uint8_t nr_w_buf = 0; retval = arm_jtag_scann(jtag_info, 0xf, TAP_IDLE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 32; /* REVISIT: table 7-2 shows that bits 31-31 need to be * specified for accessing BIST registers ... */ fields[0].out_value = NULL; fields[0].in_value = NULL; fields[1].num_bits = 6; fields[1].out_value = ®_addr_buf; fields[1].in_value = NULL; fields[2].num_bits = 1; fields[2].out_value = &nr_w_buf; fields[2].in_value = NULL; jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE); fields[1].in_value = (uint8_t *)value; jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE); jtag_add_callback(arm_le_to_h_u32, (jtag_callback_data_t)value); #ifdef _DEBUG_INSTRUCTION_EXECUTION_ retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; LOG_DEBUG("addr: 0x%x value: %8.8x", reg_addr, *value); #endif return ERROR_OK; } /* EXPORTED to str9x (flash) */ int arm966e_write_cp15(struct target *target, int reg_addr, uint32_t value) { int retval = ERROR_OK; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; struct scan_field fields[3]; uint8_t reg_addr_buf = reg_addr & 0x3f; uint8_t nr_w_buf = 1; uint8_t value_buf[4]; buf_set_u32(value_buf, 0, 32, value); retval = arm_jtag_scann(jtag_info, 0xf, TAP_IDLE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_IDLE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 32; fields[0].out_value = value_buf; fields[0].in_value = NULL; fields[1].num_bits = 6; fields[1].out_value = ®_addr_buf; fields[1].in_value = NULL; fields[2].num_bits = 1; fields[2].out_value = &nr_w_buf; fields[2].in_value = NULL; jtag_add_dr_scan(jtag_info->tap, 3, fields, TAP_IDLE); #ifdef _DEBUG_INSTRUCTION_EXECUTION_ LOG_DEBUG("addr: 0x%x value: %8.8x", reg_addr, value); #endif return ERROR_OK; } COMMAND_HANDLER(arm966e_handle_cp15_command) { int retval; struct target *target = get_current_target(CMD_CTX); struct arm966e_common *arm966e = target_to_arm966(target); retval = arm966e_verify_pointer(CMD_CTX, arm966e); if (retval != ERROR_OK) return retval; if (target->state != TARGET_HALTED) { command_print(CMD_CTX, "target must be stopped for \"%s\" command", CMD_NAME); return ERROR_OK; } /* one or more argument, access a single register (write if second argument is given */ if (CMD_ARGC >= 1) { uint32_t address; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); if (CMD_ARGC == 1) { uint32_t value; retval = arm966e_read_cp15(target, address, &value); if (retval != ERROR_OK) { command_print(CMD_CTX, "couldn't access reg %" PRIi32, address); return ERROR_OK; } retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; command_print(CMD_CTX, "%" PRIi32 ": %8.8" PRIx32, address, value); } else if (CMD_ARGC == 2) { uint32_t value; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); retval = arm966e_write_cp15(target, address, value); if (retval != ERROR_OK) { command_print(CMD_CTX, "couldn't access reg %" PRIi32, address); return ERROR_OK; } command_print(CMD_CTX, "%" PRIi32 ": %8.8" PRIx32, address, value); } } return ERROR_OK; } static const struct command_registration arm966e_exec_command_handlers[] = { { .name = "cp15", .handler = arm966e_handle_cp15_command, .mode = COMMAND_EXEC, .usage = "regnum [value]", .help = "display/modify cp15 register", }, COMMAND_REGISTRATION_DONE }; const struct command_registration arm966e_command_handlers[] = { { .chain = arm9tdmi_command_handlers, }, { .name = "arm966e", .mode = COMMAND_ANY, .help = "arm966e command group", .usage = "", .chain = arm966e_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; /** Holds methods for ARM966 targets. */ struct target_type arm966e_target = { .name = "arm966e", .poll = arm7_9_poll, .arch_state = arm_arch_state, .target_request_data = arm7_9_target_request_data, .halt = arm7_9_halt, .resume = arm7_9_resume, .step = arm7_9_step, .assert_reset = arm7_9_assert_reset, .deassert_reset = arm7_9_deassert_reset, .soft_reset_halt = arm7_9_soft_reset_halt, .get_gdb_reg_list = arm_get_gdb_reg_list, .read_memory = arm7_9_read_memory, .write_memory = arm7_9_write_memory, .bulk_write_memory = arm7_9_bulk_write_memory, .checksum_memory = arm_checksum_memory, .blank_check_memory = arm_blank_check_memory, .run_algorithm = armv4_5_run_algorithm, .add_breakpoint = arm7_9_add_breakpoint, .remove_breakpoint = arm7_9_remove_breakpoint, .add_watchpoint = arm7_9_add_watchpoint, .remove_watchpoint = arm7_9_remove_watchpoint, .commands = arm966e_command_handlers, .target_create = arm966e_target_create, .init_target = arm9tdmi_init_target, .examine = arm7_9_examine, .check_reset = arm7_9_check_reset, }; openocd-0.7.0/src/target/mips_ejtag.c0000644000175000001440000002345512137151331014433 00000000000000/*************************************************************************** * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2008 by David T.L. Wong * * * * Copyright (C) 2009 by David N. Claffey * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "mips32.h" #include "mips_ejtag.h" void mips_ejtag_set_instr(struct mips_ejtag *ejtag_info, int new_instr) { struct jtag_tap *tap; tap = ejtag_info->tap; assert(tap != NULL); if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != (uint32_t)new_instr) { struct scan_field field; uint8_t t[4]; field.num_bits = tap->ir_length; field.out_value = t; buf_set_u32(t, 0, field.num_bits, new_instr); field.in_value = NULL; jtag_add_ir_scan(tap, &field, TAP_IDLE); } } int mips_ejtag_get_idcode(struct mips_ejtag *ejtag_info, uint32_t *idcode) { struct scan_field field; uint8_t r[4]; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_IDCODE); field.num_bits = 32; field.out_value = NULL; field.in_value = r; jtag_add_dr_scan(ejtag_info->tap, 1, &field, TAP_IDLE); int retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("register read failed"); return retval; } *idcode = buf_get_u32(field.in_value, 0, 32); return ERROR_OK; } static int mips_ejtag_get_impcode(struct mips_ejtag *ejtag_info, uint32_t *impcode) { struct scan_field field; uint8_t r[4]; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_IMPCODE); field.num_bits = 32; field.out_value = NULL; field.in_value = r; jtag_add_dr_scan(ejtag_info->tap, 1, &field, TAP_IDLE); int retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("register read failed"); return retval; } *impcode = buf_get_u32(field.in_value, 0, 32); return ERROR_OK; } void mips_ejtag_add_scan_96(struct mips_ejtag *ejtag_info, uint32_t ctrl, uint32_t data, uint8_t *in_scan_buf) { assert(ejtag_info->tap != NULL); struct jtag_tap *tap = ejtag_info->tap; struct scan_field field; uint8_t out_scan[12]; /* processor access "all" register 96 bit */ field.num_bits = 96; field.out_value = out_scan; buf_set_u32(out_scan, 0, 32, ctrl); buf_set_u32(out_scan + 4, 0, 32, data); buf_set_u32(out_scan + 8, 0, 32, 0); field.in_value = in_scan_buf; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); keep_alive(); } int mips_ejtag_drscan_32(struct mips_ejtag *ejtag_info, uint32_t *data) { struct jtag_tap *tap; tap = ejtag_info->tap; assert(tap != NULL); struct scan_field field; uint8_t t[4], r[4]; int retval; field.num_bits = 32; field.out_value = t; buf_set_u32(t, 0, field.num_bits, *data); field.in_value = r; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("register read failed"); return retval; } *data = buf_get_u32(field.in_value, 0, 32); keep_alive(); return ERROR_OK; } void mips_ejtag_drscan_32_out(struct mips_ejtag *ejtag_info, uint32_t data) { uint8_t t[4]; struct jtag_tap *tap; tap = ejtag_info->tap; assert(tap != NULL); struct scan_field field; field.num_bits = 32; field.out_value = t; buf_set_u32(t, 0, field.num_bits, data); field.in_value = NULL; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); } int mips_ejtag_drscan_8(struct mips_ejtag *ejtag_info, uint32_t *data) { struct jtag_tap *tap; tap = ejtag_info->tap; assert(tap != NULL); struct scan_field field; uint8_t t[4] = {0, 0, 0, 0}, r[4]; int retval; field.num_bits = 8; field.out_value = t; buf_set_u32(t, 0, field.num_bits, *data); field.in_value = r; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("register read failed"); return retval; } *data = buf_get_u32(field.in_value, 0, 32); return ERROR_OK; } void mips_ejtag_drscan_8_out(struct mips_ejtag *ejtag_info, uint8_t data) { struct jtag_tap *tap; tap = ejtag_info->tap; assert(tap != NULL); struct scan_field field; field.num_bits = 8; field.out_value = &data; field.in_value = NULL; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); } /* Set (to enable) or clear (to disable stepping) the SSt bit (bit 8) in Cp0 Debug reg (reg 23, sel 0) */ int mips_ejtag_config_step(struct mips_ejtag *ejtag_info, int enable_step) { struct pracc_queue_info ctx = {.max_code = 7}; pracc_queue_init(&ctx); if (ctx.retval != ERROR_OK) goto exit; pracc_add(&ctx, 0, MIPS32_MFC0(8, 23, 0)); /* move COP0 Debug to $8 */ pracc_add(&ctx, 0, MIPS32_ORI(8, 8, 0x0100)); /* set SSt bit in debug reg */ if (!enable_step) pracc_add(&ctx, 0, MIPS32_XORI(8, 8, 0x0100)); /* clear SSt bit in debug reg */ pracc_add(&ctx, 0, MIPS32_MTC0(8, 23, 0)); /* move $8 to COP0 Debug */ pracc_add(&ctx, 0, MIPS32_LUI(8, UPPER16(ejtag_info->reg8))); /* restore upper 16 bits of $8 */ pracc_add(&ctx, 0, MIPS32_B(NEG16((ctx.code_count + 1)))); /* jump to start */ pracc_add(&ctx, 0, MIPS32_ORI(8, 8, LOWER16(ejtag_info->reg8))); /* restore lower 16 bits of $8 */ ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL); exit: pracc_queue_free(&ctx); return ctx.retval; } int mips_ejtag_enter_debug(struct mips_ejtag *ejtag_info) { uint32_t ejtag_ctrl; mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL); /* set debug break bit */ ejtag_ctrl = ejtag_info->ejtag_ctrl | EJTAG_CTRL_JTAGBRK; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); /* break bit will be cleared by hardware */ ejtag_ctrl = ejtag_info->ejtag_ctrl; mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl); LOG_DEBUG("ejtag_ctrl: 0x%8.8" PRIx32 "", ejtag_ctrl); if ((ejtag_ctrl & EJTAG_CTRL_BRKST) == 0) { LOG_ERROR("Failed to enter Debug Mode!"); return ERROR_FAIL; } return ERROR_OK; } int mips_ejtag_exit_debug(struct mips_ejtag *ejtag_info) { uint32_t instr = MIPS32_DRET; struct pracc_queue_info ctx = {.max_code = 1, .pracc_list = &instr, .code_count = 1, .store_count = 0}; /* execute our dret instruction */ ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL); /* pic32mx workaround, false pending at low core clock */ jtag_add_sleep(1000); return ctx.retval; } int mips_ejtag_init(struct mips_ejtag *ejtag_info) { uint32_t ejtag_version; int retval; retval = mips_ejtag_get_impcode(ejtag_info, &ejtag_info->impcode); if (retval != ERROR_OK) return retval; LOG_DEBUG("impcode: 0x%8.8" PRIx32 "", ejtag_info->impcode); /* get ejtag version */ ejtag_version = ((ejtag_info->impcode >> 29) & 0x07); switch (ejtag_version) { case 0: LOG_DEBUG("EJTAG: Version 1 or 2.0 Detected"); break; case 1: LOG_DEBUG("EJTAG: Version 2.5 Detected"); break; case 2: LOG_DEBUG("EJTAG: Version 2.6 Detected"); break; case 3: LOG_DEBUG("EJTAG: Version 3.1 Detected"); break; case 4: LOG_DEBUG("EJTAG: Version 4.1 Detected"); break; case 5: LOG_DEBUG("EJTAG: Version 5.1 Detected"); break; default: LOG_DEBUG("EJTAG: Unknown Version Detected"); break; } LOG_DEBUG("EJTAG: features:%s%s%s%s%s%s%s", ejtag_info->impcode & EJTAG_IMP_R3K ? " R3k" : " R4k", ejtag_info->impcode & EJTAG_IMP_DINT ? " DINT" : "", ejtag_info->impcode & (1 << 22) ? " ASID_8" : "", ejtag_info->impcode & (1 << 21) ? " ASID_6" : "", ejtag_info->impcode & EJTAG_IMP_MIPS16 ? " MIPS16" : "", ejtag_info->impcode & EJTAG_IMP_NODMA ? " noDMA" : " DMA", ejtag_info->impcode & EJTAG_DCR_MIPS64 ? " MIPS64" : " MIPS32"); if ((ejtag_info->impcode & EJTAG_IMP_NODMA) == 0) LOG_DEBUG("EJTAG: DMA Access Mode Support Enabled"); /* set initial state for ejtag control reg */ ejtag_info->ejtag_ctrl = EJTAG_CTRL_ROCC | EJTAG_CTRL_PRACC | EJTAG_CTRL_PROBEN | EJTAG_CTRL_SETDEV; ejtag_info->fast_access_save = -1; return ERROR_OK; } int mips_ejtag_fastdata_scan(struct mips_ejtag *ejtag_info, int write_t, uint32_t *data) { struct jtag_tap *tap; tap = ejtag_info->tap; assert(tap != NULL); struct scan_field fields[2]; uint8_t spracc = 0; uint8_t t[4] = {0, 0, 0, 0}; /* fastdata 1-bit register */ fields[0].num_bits = 1; fields[0].out_value = &spracc; fields[0].in_value = NULL; /* processor access data register 32 bit */ fields[1].num_bits = 32; fields[1].out_value = t; if (write_t) { fields[1].in_value = NULL; buf_set_u32(t, 0, 32, *data); } else fields[1].in_value = (void *) data; jtag_add_dr_scan(tap, 2, fields, TAP_IDLE); if (!write_t && data) jtag_add_callback(mips_le_to_h_u32, (jtag_callback_data_t) data); keep_alive(); return ERROR_OK; } openocd-0.7.0/src/target/startup.tcl0000644000175000001440000001063312137175623014357 00000000000000# Defines basic Tcl procs for OpenOCD target module proc new_target_name { } { return [target number [expr [target count] - 1 ]] } global in_process_reset set in_process_reset 0 # Catch reset recursion proc ocd_process_reset { MODE } { global in_process_reset if {$in_process_reset} { set in_process_reset 0 return -code error "'reset' can not be invoked recursively" } set in_process_reset 1 set success [expr [catch {ocd_process_reset_inner $MODE} result]==0] set in_process_reset 0 if {$success} { return $result } else { return -code error $result } } proc ocd_process_reset_inner { MODE } { set targets [target names] # If this target must be halted... set halt -1 if { 0 == [string compare $MODE halt] } { set halt 1 } if { 0 == [string compare $MODE init] } { set halt 1; } if { 0 == [string compare $MODE run ] } { set halt 0; } if { $halt < 0 } { return -code error "Invalid mode: $MODE, must be one of: halt, init, or run"; } # Target event handlers *might* change which TAPs are enabled # or disabled, so we fire all of them. But don't issue any # target "arp_*" commands, which may issue JTAG transactions, # unless we know the underlying TAP is active. # # NOTE: ARP == "Advanced Reset Process" ... "advanced" is # relative to a previous restrictive scheme foreach t $targets { # New event script. $t invoke-event reset-start } # Use TRST or TMS/TCK operations to reset all the tap controllers. # TAP reset events get reported; they might enable some taps. init_reset $MODE # Examine all targets on enabled taps. foreach t $targets { if {[jtag tapisenabled [$t cget -chain-position]]} { $t invoke-event examine-start set err [catch "$t arp_examine"] if { $err == 0 } { $t invoke-event examine-end } } } # Assert SRST, and report the pre/post events. # Note: no target sees SRST before "pre" or after "post". foreach t $targets { $t invoke-event reset-assert-pre } foreach t $targets { # C code needs to know if we expect to 'halt' if {[jtag tapisenabled [$t cget -chain-position]]} { $t arp_reset assert $halt } } foreach t $targets { $t invoke-event reset-assert-post } # Now de-assert SRST, and report the pre/post events. # Note: no target sees !SRST before "pre" or after "post". foreach t $targets { $t invoke-event reset-deassert-pre } foreach t $targets { # Again, de-assert code needs to know if we 'halt' if {[jtag tapisenabled [$t cget -chain-position]]} { $t arp_reset deassert $halt } } foreach t $targets { $t invoke-event reset-deassert-post } # Pass 1 - Now wait for any halt (requested as part of reset # assert/deassert) to happen. Ideally it takes effect without # first executing any instructions. if { $halt } { foreach t $targets { if {[jtag tapisenabled [$t cget -chain-position]] == 0} { continue } # Wait upto 1 second for target to halt. Why 1sec? Cause # the JTAG tap reset signal might be hooked to a slow # resistor/capacitor circuit - and it might take a while # to charge # Catch, but ignore any errors. catch { $t arp_waitstate halted 1000 } # Did we succeed? set s [$t curstate] if { 0 != [string compare $s "halted" ] } { return -code error [format "TARGET: %s - Not halted" $t] } } } #Pass 2 - if needed "init" if { 0 == [string compare init $MODE] } { foreach t $targets { if {[jtag tapisenabled [$t cget -chain-position]] == 0} { continue } set err [catch "$t arp_waitstate halted 5000"] # Did it halt? if { $err == 0 } { $t invoke-event reset-init } } } foreach t $targets { $t invoke-event reset-end } } ######### # Temporary migration aid. May be removed starting in January 2011. proc armv4_5 params { echo "DEPRECATED! use 'arm $params' not 'armv4_5 $params'" arm $params } # Target/chain configuration scripts can either execute commands directly # or define a procedure which is executed once all configuration # scripts have completed. # # By default(classic) the config scripts will set up the target configuration proc init_targets {} { } # Additionally board config scripts can define a procedure init_board that will be executed after init and init_targets proc init_board {} { } # deprecated target name cmds proc cortex_m3 args { echo "DEPRECATED! use 'cortex_m' not 'cortex_m3'" eval cortex_m $args } proc cortex_a8 args { echo "DEPRECATED! use 'cortex_a' not 'cortex_a8'" eval cortex_a $args } openocd-0.7.0/src/target/arm720t.c0000644000175000001440000004101512134336410013475 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2009 by Øyvind Harboe * * oyvind.harboe@zylin.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "arm720t.h" #include #include "target_type.h" #include "register.h" #include "arm_opcodes.h" /* * ARM720 is an ARM7TDMI-S with MMU and ETM7. For information, see * ARM DDI 0229C especially Chapter 9 about debug support. */ #if 0 #define _DEBUG_INSTRUCTION_EXECUTION_ #endif static int arm720t_scan_cp15(struct target *target, uint32_t out, uint32_t *in, int instruction, int clock_arg) { int retval; struct arm720t_common *arm720t = target_to_arm720(target); struct arm_jtag *jtag_info; struct scan_field fields[2]; uint8_t out_buf[4]; uint8_t instruction_buf = instruction; jtag_info = &arm720t->arm7_9_common.jtag_info; buf_set_u32(out_buf, 0, 32, flip_u32(out, 32)); retval = arm_jtag_scann(jtag_info, 0xf, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; retval = arm_jtag_set_instr(jtag_info, jtag_info->intest_instr, NULL, TAP_DRPAUSE); if (retval != ERROR_OK) return retval; fields[0].num_bits = 1; fields[0].out_value = &instruction_buf; fields[0].in_value = NULL; fields[1].num_bits = 32; fields[1].out_value = out_buf; fields[1].in_value = NULL; if (in) { fields[1].in_value = (uint8_t *)in; jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_DRPAUSE); jtag_add_callback(arm7flip32, (jtag_callback_data_t)in); } else jtag_add_dr_scan(jtag_info->tap, 2, fields, TAP_DRPAUSE); if (clock_arg) jtag_add_runtest(0, TAP_DRPAUSE); #ifdef _DEBUG_INSTRUCTION_EXECUTION_ retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (in) LOG_DEBUG("out: %8.8x, in: %8.8x, instruction: %i, clock: %i", out, *in, instruction, clock); else LOG_DEBUG("out: %8.8x, instruction: %i, clock: %i", out, instruction, clock_arg); #else LOG_DEBUG("out: %8.8" PRIx32 ", instruction: %i, clock: %i", out, instruction, clock_arg); #endif return ERROR_OK; } static int arm720t_read_cp15(struct target *target, uint32_t opcode, uint32_t *value) { /* fetch CP15 opcode */ arm720t_scan_cp15(target, opcode, NULL, 1, 1); /* "DECODE" stage */ arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 1); /* "EXECUTE" stage (1) */ arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 0); arm720t_scan_cp15(target, 0x0, NULL, 0, 1); /* "EXECUTE" stage (2) */ arm720t_scan_cp15(target, 0x0, NULL, 0, 1); /* "EXECUTE" stage (3), CDATA is read */ arm720t_scan_cp15(target, ARMV4_5_NOP, value, 1, 1); return ERROR_OK; } static int arm720t_write_cp15(struct target *target, uint32_t opcode, uint32_t value) { /* fetch CP15 opcode */ arm720t_scan_cp15(target, opcode, NULL, 1, 1); /* "DECODE" stage */ arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 1); /* "EXECUTE" stage (1) */ arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 0); arm720t_scan_cp15(target, 0x0, NULL, 0, 1); /* "EXECUTE" stage (2) */ arm720t_scan_cp15(target, value, NULL, 0, 1); arm720t_scan_cp15(target, ARMV4_5_NOP, NULL, 1, 1); return ERROR_OK; } static int arm720t_get_ttb(struct target *target, uint32_t *result) { uint32_t ttb = 0x0; int retval; retval = arm720t_read_cp15(target, 0xee120f10, &ttb); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; ttb &= 0xffffc000; *result = ttb; return ERROR_OK; } static int arm720t_disable_mmu_caches(struct target *target, int mmu, int d_u_cache, int i_cache) { uint32_t cp15_control; int retval; /* read cp15 control register */ retval = arm720t_read_cp15(target, 0xee110f10, &cp15_control); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (mmu) cp15_control &= ~0x1U; if (d_u_cache || i_cache) cp15_control &= ~0x4U; retval = arm720t_write_cp15(target, 0xee010f10, cp15_control); return retval; } static int arm720t_enable_mmu_caches(struct target *target, int mmu, int d_u_cache, int i_cache) { uint32_t cp15_control; int retval; /* read cp15 control register */ retval = arm720t_read_cp15(target, 0xee110f10, &cp15_control); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (mmu) cp15_control |= 0x1U; if (d_u_cache || i_cache) cp15_control |= 0x4U; retval = arm720t_write_cp15(target, 0xee010f10, cp15_control); return retval; } static int arm720t_post_debug_entry(struct target *target) { struct arm720t_common *arm720t = target_to_arm720(target); int retval; /* examine cp15 control reg */ retval = arm720t_read_cp15(target, 0xee110f10, &arm720t->cp15_control_reg); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; LOG_DEBUG("cp15_control_reg: %8.8" PRIx32 "", arm720t->cp15_control_reg); arm720t->armv4_5_mmu.mmu_enabled = (arm720t->cp15_control_reg & 0x1U) ? 1 : 0; arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = (arm720t->cp15_control_reg & 0x4U) ? 1 : 0; arm720t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0; /* save i/d fault status and address register */ retval = arm720t_read_cp15(target, 0xee150f10, &arm720t->fsr_reg); if (retval != ERROR_OK) return retval; retval = arm720t_read_cp15(target, 0xee160f10, &arm720t->far_reg); if (retval != ERROR_OK) return retval; retval = jtag_execute_queue(); return retval; } static void arm720t_pre_restore_context(struct target *target) { struct arm720t_common *arm720t = target_to_arm720(target); /* restore i/d fault status and address register */ arm720t_write_cp15(target, 0xee050f10, arm720t->fsr_reg); arm720t_write_cp15(target, 0xee060f10, arm720t->far_reg); } static int arm720t_verify_pointer(struct command_context *cmd_ctx, struct arm720t_common *arm720t) { if (arm720t->common_magic != ARM720T_COMMON_MAGIC) { command_print(cmd_ctx, "target is not an ARM720"); return ERROR_TARGET_INVALID; } return ERROR_OK; } static int arm720t_arch_state(struct target *target) { struct arm720t_common *arm720t = target_to_arm720(target); static const char *state[] = { "disabled", "enabled" }; arm_arch_state(target); LOG_USER("MMU: %s, Cache: %s", state[arm720t->armv4_5_mmu.mmu_enabled], state[arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled]); return ERROR_OK; } static int arm720_mmu(struct target *target, int *enabled) { if (target->state != TARGET_HALTED) { LOG_ERROR("%s: target not halted", __func__); return ERROR_TARGET_INVALID; } *enabled = target_to_arm720(target)->armv4_5_mmu.mmu_enabled; return ERROR_OK; } static int arm720_virt2phys(struct target *target, uint32_t virtual, uint32_t *physical) { uint32_t cb; struct arm720t_common *arm720t = target_to_arm720(target); uint32_t ret; int retval = armv4_5_mmu_translate_va(target, &arm720t->armv4_5_mmu, virtual, &cb, &ret); if (retval != ERROR_OK) return retval; *physical = ret; return ERROR_OK; } static int arm720t_read_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) { int retval; struct arm720t_common *arm720t = target_to_arm720(target); /* disable cache, but leave MMU enabled */ if (arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled) { retval = arm720t_disable_mmu_caches(target, 0, 1, 0); if (retval != ERROR_OK) return retval; } retval = arm7_9_read_memory(target, address, size, count, buffer); if (arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled) { retval = arm720t_enable_mmu_caches(target, 0, 1, 0); if (retval != ERROR_OK) return retval; } return retval; } static int arm720t_read_phys_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct arm720t_common *arm720t = target_to_arm720(target); return armv4_5_mmu_read_physical(target, &arm720t->armv4_5_mmu, address, size, count, buffer); } static int arm720t_write_phys_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct arm720t_common *arm720t = target_to_arm720(target); return armv4_5_mmu_write_physical(target, &arm720t->armv4_5_mmu, address, size, count, buffer); } static int arm720t_soft_reset_halt(struct target *target) { int retval = ERROR_OK; struct arm720t_common *arm720t = target_to_arm720(target); struct reg *dbg_stat = &arm720t->arm7_9_common .eice_cache->reg_list[EICE_DBG_STAT]; struct arm *arm = &arm720t->arm7_9_common.arm; retval = target_halt(target); if (retval != ERROR_OK) return retval; long long then = timeval_ms(); int timeout; while (!(timeout = ((timeval_ms()-then) > 1000))) { if (buf_get_u32(dbg_stat->value, EICE_DBG_STATUS_DBGACK, 1) == 0) { embeddedice_read_reg(dbg_stat); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; } else break; if (debug_level >= 3) alive_sleep(100); else keep_alive(); } if (timeout) { LOG_ERROR("Failed to halt CPU after 1 sec"); return ERROR_TARGET_TIMEOUT; } target->state = TARGET_HALTED; /* SVC, ARM state, IRQ and FIQ disabled */ uint32_t cpsr; cpsr = buf_get_u32(arm->cpsr->value, 0, 32); cpsr &= ~0xff; cpsr |= 0xd3; arm_set_cpsr(arm, cpsr); arm->cpsr->dirty = 1; /* start fetching from 0x0 */ buf_set_u32(arm->pc->value, 0, 32, 0x0); arm->pc->dirty = 1; arm->pc->valid = 1; retval = arm720t_disable_mmu_caches(target, 1, 1, 1); if (retval != ERROR_OK) return retval; arm720t->armv4_5_mmu.mmu_enabled = 0; arm720t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled = 0; arm720t->armv4_5_mmu.armv4_5_cache.i_cache_enabled = 0; retval = target_call_event_callbacks(target, TARGET_EVENT_HALTED); if (retval != ERROR_OK) return retval; return ERROR_OK; } static int arm720t_init_target(struct command_context *cmd_ctx, struct target *target) { return arm7tdmi_init_target(cmd_ctx, target); } /* FIXME remove forward decls */ static int arm720t_mrc(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t *value); static int arm720t_mcr(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t value); static int arm720t_init_arch_info(struct target *target, struct arm720t_common *arm720t, struct jtag_tap *tap) { struct arm7_9_common *arm7_9 = &arm720t->arm7_9_common; arm7_9->arm.mrc = arm720t_mrc; arm7_9->arm.mcr = arm720t_mcr; arm7tdmi_init_arch_info(target, arm7_9, tap); arm720t->common_magic = ARM720T_COMMON_MAGIC; arm7_9->post_debug_entry = arm720t_post_debug_entry; arm7_9->pre_restore_context = arm720t_pre_restore_context; arm720t->armv4_5_mmu.armv4_5_cache.ctype = -1; arm720t->armv4_5_mmu.get_ttb = arm720t_get_ttb; arm720t->armv4_5_mmu.read_memory = arm7_9_read_memory; arm720t->armv4_5_mmu.write_memory = arm7_9_write_memory; arm720t->armv4_5_mmu.disable_mmu_caches = arm720t_disable_mmu_caches; arm720t->armv4_5_mmu.enable_mmu_caches = arm720t_enable_mmu_caches; arm720t->armv4_5_mmu.has_tiny_pages = 0; arm720t->armv4_5_mmu.mmu_enabled = 0; return ERROR_OK; } static int arm720t_target_create(struct target *target, Jim_Interp *interp) { struct arm720t_common *arm720t = calloc(1, sizeof(*arm720t)); arm720t->arm7_9_common.arm.is_armv4 = true; return arm720t_init_arch_info(target, arm720t, target->tap); } COMMAND_HANDLER(arm720t_handle_cp15_command) { int retval; struct target *target = get_current_target(CMD_CTX); struct arm720t_common *arm720t = target_to_arm720(target); retval = arm720t_verify_pointer(CMD_CTX, arm720t); if (retval != ERROR_OK) return retval; if (target->state != TARGET_HALTED) { command_print(CMD_CTX, "target must be stopped for \"%s\" command", CMD_NAME); return ERROR_OK; } /* one or more argument, access a single register (write if second argument is given */ if (CMD_ARGC >= 1) { uint32_t opcode; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], opcode); if (CMD_ARGC == 1) { uint32_t value; retval = arm720t_read_cp15(target, opcode, &value); if (retval != ERROR_OK) { command_print(CMD_CTX, "couldn't access cp15 with opcode 0x%8.8" PRIx32 "", opcode); return ERROR_OK; } retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; command_print(CMD_CTX, "0x%8.8" PRIx32 ": 0x%8.8" PRIx32 "", opcode, value); } else if (CMD_ARGC == 2) { uint32_t value; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); retval = arm720t_write_cp15(target, opcode, value); if (retval != ERROR_OK) { command_print(CMD_CTX, "couldn't access cp15 with opcode 0x%8.8" PRIx32 "", opcode); return ERROR_OK; } command_print(CMD_CTX, "0x%8.8" PRIx32 ": 0x%8.8" PRIx32 "", opcode, value); } } return ERROR_OK; } static int arm720t_mrc(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t *value) { if (cpnum != 15) { LOG_ERROR("Only cp15 is supported"); return ERROR_FAIL; } /* read "to" r0 */ return arm720t_read_cp15(target, ARMV4_5_MRC(cpnum, op1, 0, CRn, CRm, op2), value); } static int arm720t_mcr(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t value) { if (cpnum != 15) { LOG_ERROR("Only cp15 is supported"); return ERROR_FAIL; } /* write "from" r0 */ return arm720t_write_cp15(target, ARMV4_5_MCR(cpnum, op1, 0, CRn, CRm, op2), value); } static const struct command_registration arm720t_exec_command_handlers[] = { { .name = "cp15", .handler = arm720t_handle_cp15_command, .mode = COMMAND_EXEC, /* prefer using less error-prone "arm mcr" or "arm mrc" */ .help = "display/modify cp15 register using ARM opcode" " (DEPRECATED)", .usage = "instruction [value]", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration arm720t_command_handlers[] = { { .chain = arm7_9_command_handlers, }, { .name = "arm720t", .mode = COMMAND_ANY, .help = "arm720t command group", .usage = "", .chain = arm720t_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; /** Holds methods for ARM720 targets. */ struct target_type arm720t_target = { .name = "arm720t", .poll = arm7_9_poll, .arch_state = arm720t_arch_state, .halt = arm7_9_halt, .resume = arm7_9_resume, .step = arm7_9_step, .assert_reset = arm7_9_assert_reset, .deassert_reset = arm7_9_deassert_reset, .soft_reset_halt = arm720t_soft_reset_halt, .get_gdb_reg_list = arm_get_gdb_reg_list, .read_memory = arm720t_read_memory, .write_memory = arm7_9_write_memory, .read_phys_memory = arm720t_read_phys_memory, .write_phys_memory = arm720t_write_phys_memory, .mmu = arm720_mmu, .virt2phys = arm720_virt2phys, .bulk_write_memory = arm7_9_bulk_write_memory, .checksum_memory = arm_checksum_memory, .blank_check_memory = arm_blank_check_memory, .run_algorithm = armv4_5_run_algorithm, .add_breakpoint = arm7_9_add_breakpoint, .remove_breakpoint = arm7_9_remove_breakpoint, .add_watchpoint = arm7_9_add_watchpoint, .remove_watchpoint = arm7_9_remove_watchpoint, .commands = arm720t_command_handlers, .target_create = arm720t_target_create, .init_target = arm720t_init_target, .examine = arm7_9_examine, .check_reset = arm7_9_check_reset, }; openocd-0.7.0/src/target/arm_disassembler.c0000644000175000001440000032324112134336410015621 00000000000000/*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2009 by David Brownell * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "target.h" #include "arm_disassembler.h" #include /* * This disassembler supports two main functions for OpenOCD: * * - Various "disassemble" commands. OpenOCD can serve as a * machine-language debugger, without help from GDB. * * - Single stepping. Not all ARM cores support hardware single * stepping. To work without that support, the debugger must * be able to decode instructions to find out where to put a * "next instruction" breakpoint. * * In addition, interpretation of ETM trace data needs some of the * decoding mechanisms. * * At this writing (September 2009) neither function is complete. * * - ARM decoding * * Old-style syntax (not UAL) is generally used * * VFP instructions are not understood (ARMv5 and later) * except as coprocessor 10/11 operations * * Most ARM instructions through ARMv6 are decoded, but some * of the post-ARMv4 opcodes may not be handled yet * CPS, SDIV, UDIV, LDREX*, STREX*, QASX, ... * * NEON instructions are not understood (ARMv7-A) * * - Thumb/Thumb2 decoding * * UAL syntax should be consistently used * * Any Thumb2 instructions used in Cortex-M3 (ARMv7-M) should * be handled properly. Accordingly, so should the subset * used in Cortex-M0/M1; and "original" 16-bit Thumb from * ARMv4T and ARMv5T. * * Conditional effects of Thumb2 "IT" (if-then) instructions * are not handled: the affected instructions are not shown * with their now-conditional suffixes. * * Some ARMv6 and ARMv7-M Thumb2 instructions may not be * handled (minimally for coprocessor access). * * SIMD instructions, and some other Thumb2 instructions * from ARMv7-A, are not understood. * * - ThumbEE decoding * * As a Thumb2 variant, the Thumb2 comments (above) apply. * * Opcodes changed by ThumbEE mode are not handled; these * instructions wrongly decode as LDM and STM. * * - Jazelle decoding ... no support whatsoever for Jazelle mode * or decoding. ARM encourages use of the more generic ThumbEE * mode, instead of Jazelle mode, in current chips. * * - Single-step/emulation ... spotty support, which is only weakly * tested. Thumb2 is not supported. (Arguably a full simulator * is not needed to support just single stepping. Recognizing * branch vs non-branch instructions suffices, except when the * instruction faults and triggers a synchronous exception which * can be intercepted using other means.) * * ARM DDI 0406B "ARM Architecture Reference Manual, ARM v7-A and * ARM v7-R edition" gives the most complete coverage of the various * generations of ARM instructions. At this writing it is publicly * accessible to anyone willing to create an account at the ARM * web site; see http://www.arm.com/documentation/ for information. * * ARM DDI 0403C "ARMv7-M Architecture Reference Manual" provides * more details relevant to the Thumb2-only processors (such as * the Cortex-M implementations). */ /* textual represenation of the condition field * ALways (default) is ommitted (empty string) */ static const char *arm_condition_strings[] = { "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC", "HI", "LS", "GE", "LT", "GT", "LE", "", "NV" }; /* make up for C's missing ROR */ static uint32_t ror(uint32_t value, int places) { return (value >> places) | (value << (32 - places)); } static int evaluate_unknown(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { instruction->type = ARM_UNDEFINED_INSTRUCTION; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION", address, opcode); return ERROR_OK; } static int evaluate_pld(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { /* PLD */ if ((opcode & 0x0d70f000) == 0x0550f000) { instruction->type = ARM_PLD; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD ...TODO...", address, opcode); return ERROR_OK; } return evaluate_unknown(opcode, address, instruction); } static int evaluate_srs(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { const char *wback = (opcode & (1 << 21)) ? "!" : ""; const char *mode = ""; switch ((opcode >> 23) & 0x3) { case 0: mode = "DA"; break; case 1: /* "IA" is default */ break; case 2: mode = "DB"; break; case 3: mode = "IB"; break; } switch (opcode & 0x0e500000) { case 0x08400000: snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSRS%s\tSP%s, #%d", address, opcode, mode, wback, (unsigned)(opcode & 0x1f)); break; case 0x08100000: snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tRFE%s\tr%d%s", address, opcode, mode, (unsigned)((opcode >> 16) & 0xf), wback); break; default: return evaluate_unknown(opcode, address, instruction); } return ERROR_OK; } static int evaluate_swi(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { instruction->type = ARM_SWI; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSVC %#6.6" PRIx32, address, opcode, (opcode & 0xffffff)); return ERROR_OK; } static int evaluate_blx_imm(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { int offset; uint32_t immediate; uint32_t target_address; instruction->type = ARM_BLX; immediate = opcode & 0x00ffffff; /* sign extend 24-bit immediate */ if (immediate & 0x00800000) offset = 0xff000000 | immediate; else offset = immediate; /* shift two bits left */ offset <<= 2; /* odd/event halfword */ if (opcode & 0x01000000) offset |= 0x2; target_address = address + 8 + offset; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBLX 0x%8.8" PRIx32 "", address, opcode, target_address); instruction->info.b_bl_bx_blx.reg_operand = -1; instruction->info.b_bl_bx_blx.target_address = target_address; return ERROR_OK; } static int evaluate_b_bl(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { uint8_t L; uint32_t immediate; int offset; uint32_t target_address; immediate = opcode & 0x00ffffff; L = (opcode & 0x01000000) >> 24; /* sign extend 24-bit immediate */ if (immediate & 0x00800000) offset = 0xff000000 | immediate; else offset = immediate; /* shift two bits left */ offset <<= 2; target_address = address + 8 + offset; if (L) instruction->type = ARM_BL; else instruction->type = ARM_B; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tB%s%s 0x%8.8" PRIx32, address, opcode, (L) ? "L" : "", COND(opcode), target_address); instruction->info.b_bl_bx_blx.reg_operand = -1; instruction->info.b_bl_bx_blx.target_address = target_address; return ERROR_OK; } /* Coprocessor load/store and double register transfers * both normal and extended instruction space (condition field b1111) */ static int evaluate_ldc_stc_mcrr_mrrc(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { uint8_t cp_num = (opcode & 0xf00) >> 8; /* MCRR or MRRC */ if (((opcode & 0x0ff00000) == 0x0c400000) || ((opcode & 0x0ff00000) == 0x0c400000)) { uint8_t cp_opcode, Rd, Rn, CRm; char *mnemonic; cp_opcode = (opcode & 0xf0) >> 4; Rd = (opcode & 0xf000) >> 12; Rn = (opcode & 0xf0000) >> 16; CRm = (opcode & 0xf); /* MCRR */ if ((opcode & 0x0ff00000) == 0x0c400000) { instruction->type = ARM_MCRR; mnemonic = "MCRR"; } else if ((opcode & 0x0ff00000) == 0x0c500000) { /* MRRC */ instruction->type = ARM_MRRC; mnemonic = "MRRC"; } else { LOG_ERROR("Unknown instruction"); return ERROR_FAIL; } snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s p%i, %x, r%i, r%i, c%i", address, opcode, mnemonic, ((opcode & 0xf0000000) == 0xf0000000) ? "2" : COND(opcode), COND(opcode), cp_num, cp_opcode, Rd, Rn, CRm); } else {/* LDC or STC */ uint8_t CRd, Rn, offset; uint8_t U; char *mnemonic; char addressing_mode[32]; CRd = (opcode & 0xf000) >> 12; Rn = (opcode & 0xf0000) >> 16; offset = (opcode & 0xff) << 2; /* load/store */ if (opcode & 0x00100000) { instruction->type = ARM_LDC; mnemonic = "LDC"; } else { instruction->type = ARM_STC; mnemonic = "STC"; } U = (opcode & 0x00800000) >> 23; /* addressing modes */ if ((opcode & 0x01200000) == 0x01000000)/* offset */ snprintf(addressing_mode, 32, "[r%i, #%s%d]", Rn, U ? "" : "-", offset); else if ((opcode & 0x01200000) == 0x01200000) /* pre-indexed */ snprintf(addressing_mode, 32, "[r%i, #%s%d]!", Rn, U ? "" : "-", offset); else if ((opcode & 0x01200000) == 0x00200000) /* post-indexed */ snprintf(addressing_mode, 32, "[r%i], #%s%d", Rn, U ? "" : "-", offset); else if ((opcode & 0x01200000) == 0x00000000) /* unindexed */ snprintf(addressing_mode, 32, "[r%i], {%d}", Rn, offset >> 2); snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s p%i, c%i, %s", address, opcode, mnemonic, ((opcode & 0xf0000000) == 0xf0000000) ? "2" : COND(opcode), (opcode & (1 << 22)) ? "L" : "", cp_num, CRd, addressing_mode); } return ERROR_OK; } /* Coprocessor data processing instructions * Coprocessor register transfer instructions * both normal and extended instruction space (condition field b1111) */ static int evaluate_cdp_mcr_mrc(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { const char *cond; char *mnemonic; uint8_t cp_num, opcode_1, CRd_Rd, CRn, CRm, opcode_2; cond = ((opcode & 0xf0000000) == 0xf0000000) ? "2" : COND(opcode); cp_num = (opcode & 0xf00) >> 8; CRd_Rd = (opcode & 0xf000) >> 12; CRn = (opcode & 0xf0000) >> 16; CRm = (opcode & 0xf); opcode_2 = (opcode & 0xe0) >> 5; /* CDP or MRC/MCR */ if (opcode & 0x00000010) { /* bit 4 set -> MRC/MCR */ if (opcode & 0x00100000) { /* bit 20 set -> MRC */ instruction->type = ARM_MRC; mnemonic = "MRC"; } else {/* bit 20 not set -> MCR */ instruction->type = ARM_MCR; mnemonic = "MCR"; } opcode_1 = (opcode & 0x00e00000) >> 21; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s p%i, 0x%2.2x, r%i, c%i, c%i, 0x%2.2x", address, opcode, mnemonic, cond, cp_num, opcode_1, CRd_Rd, CRn, CRm, opcode_2); } else {/* bit 4 not set -> CDP */ instruction->type = ARM_CDP; mnemonic = "CDP"; opcode_1 = (opcode & 0x00f00000) >> 20; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s p%i, 0x%2.2x, c%i, c%i, c%i, 0x%2.2x", address, opcode, mnemonic, cond, cp_num, opcode_1, CRd_Rd, CRn, CRm, opcode_2); } return ERROR_OK; } /* Load/store instructions */ static int evaluate_load_store(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { uint8_t I, P, U, B, W, L; uint8_t Rn, Rd; char *operation;/* "LDR" or "STR" */ char *suffix; /* "", "B", "T", "BT" */ char offset[32]; /* examine flags */ I = (opcode & 0x02000000) >> 25; P = (opcode & 0x01000000) >> 24; U = (opcode & 0x00800000) >> 23; B = (opcode & 0x00400000) >> 22; W = (opcode & 0x00200000) >> 21; L = (opcode & 0x00100000) >> 20; /* target register */ Rd = (opcode & 0xf000) >> 12; /* base register */ Rn = (opcode & 0xf0000) >> 16; instruction->info.load_store.Rd = Rd; instruction->info.load_store.Rn = Rn; instruction->info.load_store.U = U; /* determine operation */ if (L) operation = "LDR"; else operation = "STR"; /* determine instruction type and suffix */ if (B) { if ((P == 0) && (W == 1)) { if (L) instruction->type = ARM_LDRBT; else instruction->type = ARM_STRBT; suffix = "BT"; } else { if (L) instruction->type = ARM_LDRB; else instruction->type = ARM_STRB; suffix = "B"; } } else { if ((P == 0) && (W == 1)) { if (L) instruction->type = ARM_LDRT; else instruction->type = ARM_STRT; suffix = "T"; } else { if (L) instruction->type = ARM_LDR; else instruction->type = ARM_STR; suffix = ""; } } if (!I) { /* #+- */ uint32_t offset_12 = (opcode & 0xfff); if (offset_12) snprintf(offset, 32, ", #%s0x%" PRIx32 "", (U) ? "" : "-", offset_12); else snprintf(offset, 32, "%s", ""); instruction->info.load_store.offset_mode = 0; instruction->info.load_store.offset.offset = offset_12; } else {/* either +- or +-, , # */ uint8_t shift_imm, shift; uint8_t Rm; shift_imm = (opcode & 0xf80) >> 7; shift = (opcode & 0x60) >> 5; Rm = (opcode & 0xf); /* LSR encodes a shift by 32 bit as 0x0 */ if ((shift == 0x1) && (shift_imm == 0x0)) shift_imm = 0x20; /* ASR encodes a shift by 32 bit as 0x0 */ if ((shift == 0x2) && (shift_imm == 0x0)) shift_imm = 0x20; /* ROR by 32 bit is actually a RRX */ if ((shift == 0x3) && (shift_imm == 0x0)) shift = 0x4; instruction->info.load_store.offset_mode = 1; instruction->info.load_store.offset.reg.Rm = Rm; instruction->info.load_store.offset.reg.shift = shift; instruction->info.load_store.offset.reg.shift_imm = shift_imm; if ((shift_imm == 0x0) && (shift == 0x0)) /* +- */ snprintf(offset, 32, ", %sr%i", (U) ? "" : "-", Rm); else { /* +-, , # */ switch (shift) { case 0x0: /* LSL */ snprintf(offset, 32, ", %sr%i, LSL #0x%x", (U) ? "" : "-", Rm, shift_imm); break; case 0x1: /* LSR */ snprintf(offset, 32, ", %sr%i, LSR #0x%x", (U) ? "" : "-", Rm, shift_imm); break; case 0x2: /* ASR */ snprintf(offset, 32, ", %sr%i, ASR #0x%x", (U) ? "" : "-", Rm, shift_imm); break; case 0x3: /* ROR */ snprintf(offset, 32, ", %sr%i, ROR #0x%x", (U) ? "" : "-", Rm, shift_imm); break; case 0x4: /* RRX */ snprintf(offset, 32, ", %sr%i, RRX", (U) ? "" : "-", Rm); break; } } } if (P == 1) { if (W == 0) { /* offset */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, [r%i%s]", address, opcode, operation, COND(opcode), suffix, Rd, Rn, offset); instruction->info.load_store.index_mode = 0; } else {/* pre-indexed */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, [r%i%s]!", address, opcode, operation, COND(opcode), suffix, Rd, Rn, offset); instruction->info.load_store.index_mode = 1; } } else {/* post-indexed */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, [r%i]%s", address, opcode, operation, COND(opcode), suffix, Rd, Rn, offset); instruction->info.load_store.index_mode = 2; } return ERROR_OK; } static int evaluate_extend(uint32_t opcode, uint32_t address, char *cp) { unsigned rm = (opcode >> 0) & 0xf; unsigned rd = (opcode >> 12) & 0xf; unsigned rn = (opcode >> 16) & 0xf; char *type, *rot; switch ((opcode >> 24) & 0x3) { case 0: type = "B16"; break; case 1: sprintf(cp, "UNDEFINED"); return ARM_UNDEFINED_INSTRUCTION; case 2: type = "B"; break; default: type = "H"; break; } switch ((opcode >> 10) & 0x3) { case 0: rot = ""; break; case 1: rot = ", ROR #8"; break; case 2: rot = ", ROR #16"; break; default: rot = ", ROR #24"; break; } if (rn == 0xf) { sprintf(cp, "%cXT%s%s\tr%d, r%d%s", (opcode & (1 << 22)) ? 'U' : 'S', type, COND(opcode), rd, rm, rot); return ARM_MOV; } else { sprintf(cp, "%cXTA%s%s\tr%d, r%d, r%d%s", (opcode & (1 << 22)) ? 'U' : 'S', type, COND(opcode), rd, rn, rm, rot); return ARM_ADD; } } static int evaluate_p_add_sub(uint32_t opcode, uint32_t address, char *cp) { char *prefix; char *op; int type; switch ((opcode >> 20) & 0x7) { case 1: prefix = "S"; break; case 2: prefix = "Q"; break; case 3: prefix = "SH"; break; case 5: prefix = "U"; break; case 6: prefix = "UQ"; break; case 7: prefix = "UH"; break; default: goto undef; } switch ((opcode >> 5) & 0x7) { case 0: op = "ADD16"; type = ARM_ADD; break; case 1: op = "ADDSUBX"; type = ARM_ADD; break; case 2: op = "SUBADDX"; type = ARM_SUB; break; case 3: op = "SUB16"; type = ARM_SUB; break; case 4: op = "ADD8"; type = ARM_ADD; break; case 7: op = "SUB8"; type = ARM_SUB; break; default: goto undef; } sprintf(cp, "%s%s%s\tr%d, r%d, r%d", prefix, op, COND(opcode), (int) (opcode >> 12) & 0xf, (int) (opcode >> 16) & 0xf, (int) (opcode >> 0) & 0xf); return type; undef: /* these opcodes might be used someday */ sprintf(cp, "UNDEFINED"); return ARM_UNDEFINED_INSTRUCTION; } /* ARMv6 and later support "media" instructions (includes SIMD) */ static int evaluate_media(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { char *cp = instruction->text; char *mnemonic = NULL; sprintf(cp, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t", address, opcode); cp = strchr(cp, 0); /* parallel add/subtract */ if ((opcode & 0x01800000) == 0x00000000) { instruction->type = evaluate_p_add_sub(opcode, address, cp); return ERROR_OK; } /* halfword pack */ if ((opcode & 0x01f00020) == 0x00800000) { char *type, *shift; unsigned imm = (unsigned) (opcode >> 7) & 0x1f; if (opcode & (1 << 6)) { type = "TB"; shift = "ASR"; if (imm == 0) imm = 32; } else { type = "BT"; shift = "LSL"; } sprintf(cp, "PKH%s%s\tr%d, r%d, r%d, %s #%d", type, COND(opcode), (int) (opcode >> 12) & 0xf, (int) (opcode >> 16) & 0xf, (int) (opcode >> 0) & 0xf, shift, imm); return ERROR_OK; } /* word saturate */ if ((opcode & 0x01a00020) == 0x00a00000) { char *shift; unsigned imm = (unsigned) (opcode >> 7) & 0x1f; if (opcode & (1 << 6)) { shift = "ASR"; if (imm == 0) imm = 32; } else shift = "LSL"; sprintf(cp, "%cSAT%s\tr%d, #%d, r%d, %s #%d", (opcode & (1 << 22)) ? 'U' : 'S', COND(opcode), (int) (opcode >> 12) & 0xf, (int) (opcode >> 16) & 0x1f, (int) (opcode >> 0) & 0xf, shift, imm); return ERROR_OK; } /* sign extension */ if ((opcode & 0x018000f0) == 0x00800070) { instruction->type = evaluate_extend(opcode, address, cp); return ERROR_OK; } /* multiplies */ if ((opcode & 0x01f00080) == 0x01000000) { unsigned rn = (opcode >> 12) & 0xf; if (rn != 0xf) sprintf(cp, "SML%cD%s%s\tr%d, r%d, r%d, r%d", (opcode & (1 << 6)) ? 'S' : 'A', (opcode & (1 << 5)) ? "X" : "", COND(opcode), (int) (opcode >> 16) & 0xf, (int) (opcode >> 0) & 0xf, (int) (opcode >> 8) & 0xf, rn); else sprintf(cp, "SMU%cD%s%s\tr%d, r%d, r%d", (opcode & (1 << 6)) ? 'S' : 'A', (opcode & (1 << 5)) ? "X" : "", COND(opcode), (int) (opcode >> 16) & 0xf, (int) (opcode >> 0) & 0xf, (int) (opcode >> 8) & 0xf); return ERROR_OK; } if ((opcode & 0x01f00000) == 0x01400000) { sprintf(cp, "SML%cLD%s%s\tr%d, r%d, r%d, r%d", (opcode & (1 << 6)) ? 'S' : 'A', (opcode & (1 << 5)) ? "X" : "", COND(opcode), (int) (opcode >> 12) & 0xf, (int) (opcode >> 16) & 0xf, (int) (opcode >> 0) & 0xf, (int) (opcode >> 8) & 0xf); return ERROR_OK; } if ((opcode & 0x01f00000) == 0x01500000) { unsigned rn = (opcode >> 12) & 0xf; switch (opcode & 0xc0) { case 3: if (rn == 0xf) goto undef; /* FALL THROUGH */ case 0: break; default: goto undef; } if (rn != 0xf) sprintf(cp, "SMML%c%s%s\tr%d, r%d, r%d, r%d", (opcode & (1 << 6)) ? 'S' : 'A', (opcode & (1 << 5)) ? "R" : "", COND(opcode), (int) (opcode >> 16) & 0xf, (int) (opcode >> 0) & 0xf, (int) (opcode >> 8) & 0xf, rn); else sprintf(cp, "SMMUL%s%s\tr%d, r%d, r%d", (opcode & (1 << 5)) ? "R" : "", COND(opcode), (int) (opcode >> 16) & 0xf, (int) (opcode >> 0) & 0xf, (int) (opcode >> 8) & 0xf); return ERROR_OK; } /* simple matches against the remaining decode bits */ switch (opcode & 0x01f000f0) { case 0x00a00030: case 0x00e00030: /* parallel halfword saturate */ sprintf(cp, "%cSAT16%s\tr%d, #%d, r%d", (opcode & (1 << 22)) ? 'U' : 'S', COND(opcode), (int) (opcode >> 12) & 0xf, (int) (opcode >> 16) & 0xf, (int) (opcode >> 0) & 0xf); return ERROR_OK; case 0x00b00030: mnemonic = "REV"; break; case 0x00b000b0: mnemonic = "REV16"; break; case 0x00f000b0: mnemonic = "REVSH"; break; case 0x008000b0: /* select bytes */ sprintf(cp, "SEL%s\tr%d, r%d, r%d", COND(opcode), (int) (opcode >> 12) & 0xf, (int) (opcode >> 16) & 0xf, (int) (opcode >> 0) & 0xf); return ERROR_OK; case 0x01800010: /* unsigned sum of absolute differences */ if (((opcode >> 12) & 0xf) == 0xf) sprintf(cp, "USAD8%s\tr%d, r%d, r%d", COND(opcode), (int) (opcode >> 16) & 0xf, (int) (opcode >> 0) & 0xf, (int) (opcode >> 8) & 0xf); else sprintf(cp, "USADA8%s\tr%d, r%d, r%d, r%d", COND(opcode), (int) (opcode >> 16) & 0xf, (int) (opcode >> 0) & 0xf, (int) (opcode >> 8) & 0xf, (int) (opcode >> 12) & 0xf); return ERROR_OK; } if (mnemonic) { unsigned rm = (opcode >> 0) & 0xf; unsigned rd = (opcode >> 12) & 0xf; sprintf(cp, "%s%s\tr%d, r%d", mnemonic, COND(opcode), rm, rd); return ERROR_OK; } undef: /* these opcodes might be used someday */ sprintf(cp, "UNDEFINED"); return ERROR_OK; } /* Miscellaneous load/store instructions */ static int evaluate_misc_load_store(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { uint8_t P, U, I, W, L, S, H; uint8_t Rn, Rd; char *operation;/* "LDR" or "STR" */ char *suffix; /* "H", "SB", "SH", "D" */ char offset[32]; /* examine flags */ P = (opcode & 0x01000000) >> 24; U = (opcode & 0x00800000) >> 23; I = (opcode & 0x00400000) >> 22; W = (opcode & 0x00200000) >> 21; L = (opcode & 0x00100000) >> 20; S = (opcode & 0x00000040) >> 6; H = (opcode & 0x00000020) >> 5; /* target register */ Rd = (opcode & 0xf000) >> 12; /* base register */ Rn = (opcode & 0xf0000) >> 16; instruction->info.load_store.Rd = Rd; instruction->info.load_store.Rn = Rn; instruction->info.load_store.U = U; /* determine instruction type and suffix */ if (S) {/* signed */ if (L) {/* load */ if (H) { operation = "LDR"; instruction->type = ARM_LDRSH; suffix = "SH"; } else { operation = "LDR"; instruction->type = ARM_LDRSB; suffix = "SB"; } } else {/* there are no signed stores, so this is used to encode double-register *load/stores */ suffix = "D"; if (H) { operation = "STR"; instruction->type = ARM_STRD; } else { operation = "LDR"; instruction->type = ARM_LDRD; } } } else {/* unsigned */ suffix = "H"; if (L) {/* load */ operation = "LDR"; instruction->type = ARM_LDRH; } else {/* store */ operation = "STR"; instruction->type = ARM_STRH; } } if (I) {/* Immediate offset/index (#+-)*/ uint32_t offset_8 = ((opcode & 0xf00) >> 4) | (opcode & 0xf); snprintf(offset, 32, "#%s0x%" PRIx32 "", (U) ? "" : "-", offset_8); instruction->info.load_store.offset_mode = 0; instruction->info.load_store.offset.offset = offset_8; } else {/* Register offset/index (+-) */ uint8_t Rm; Rm = (opcode & 0xf); snprintf(offset, 32, "%sr%i", (U) ? "" : "-", Rm); instruction->info.load_store.offset_mode = 1; instruction->info.load_store.offset.reg.Rm = Rm; instruction->info.load_store.offset.reg.shift = 0x0; instruction->info.load_store.offset.reg.shift_imm = 0x0; } if (P == 1) { if (W == 0) { /* offset */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, [r%i, %s]", address, opcode, operation, COND(opcode), suffix, Rd, Rn, offset); instruction->info.load_store.index_mode = 0; } else {/* pre-indexed */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, [r%i, %s]!", address, opcode, operation, COND(opcode), suffix, Rd, Rn, offset); instruction->info.load_store.index_mode = 1; } } else {/* post-indexed */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, [r%i], %s", address, opcode, operation, COND(opcode), suffix, Rd, Rn, offset); instruction->info.load_store.index_mode = 2; } return ERROR_OK; } /* Load/store multiples instructions */ static int evaluate_ldm_stm(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { uint8_t P, U, S, W, L, Rn; uint32_t register_list; char *addressing_mode; char *mnemonic; char reg_list[69]; char *reg_list_p; int i; int first_reg = 1; P = (opcode & 0x01000000) >> 24; U = (opcode & 0x00800000) >> 23; S = (opcode & 0x00400000) >> 22; W = (opcode & 0x00200000) >> 21; L = (opcode & 0x00100000) >> 20; register_list = (opcode & 0xffff); Rn = (opcode & 0xf0000) >> 16; instruction->info.load_store_multiple.Rn = Rn; instruction->info.load_store_multiple.register_list = register_list; instruction->info.load_store_multiple.S = S; instruction->info.load_store_multiple.W = W; if (L) { instruction->type = ARM_LDM; mnemonic = "LDM"; } else { instruction->type = ARM_STM; mnemonic = "STM"; } if (P) { if (U) { instruction->info.load_store_multiple.addressing_mode = 1; addressing_mode = "IB"; } else { instruction->info.load_store_multiple.addressing_mode = 3; addressing_mode = "DB"; } } else { if (U) { instruction->info.load_store_multiple.addressing_mode = 0; /* "IA" is the default in UAL syntax */ addressing_mode = ""; } else { instruction->info.load_store_multiple.addressing_mode = 2; addressing_mode = "DA"; } } reg_list_p = reg_list; for (i = 0; i <= 15; i++) { if ((register_list >> i) & 1) { if (first_reg) { first_reg = 0; reg_list_p += snprintf(reg_list_p, (reg_list + 69 - reg_list_p), "r%i", i); } else reg_list_p += snprintf(reg_list_p, (reg_list + 69 - reg_list_p), ", r%i", i); } } snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i%s, {%s}%s", address, opcode, mnemonic, addressing_mode, COND(opcode), Rn, (W) ? "!" : "", reg_list, (S) ? "^" : ""); return ERROR_OK; } /* Multiplies, extra load/stores */ static int evaluate_mul_and_extra_ld_st(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { /* Multiply (accumulate) (long) and Swap/swap byte */ if ((opcode & 0x000000f0) == 0x00000090) { /* Multiply (accumulate) */ if ((opcode & 0x0f800000) == 0x00000000) { uint8_t Rm, Rs, Rn, Rd, S; Rm = opcode & 0xf; Rs = (opcode & 0xf00) >> 8; Rn = (opcode & 0xf000) >> 12; Rd = (opcode & 0xf0000) >> 16; S = (opcode & 0x00100000) >> 20; /* examine A bit (accumulate) */ if (opcode & 0x00200000) { instruction->type = ARM_MLA; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMLA%s%s r%i, r%i, r%i, r%i", address, opcode, COND(opcode), (S) ? "S" : "", Rd, Rm, Rs, Rn); } else { instruction->type = ARM_MUL; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMUL%s%s r%i, r%i, r%i", address, opcode, COND(opcode), (S) ? "S" : "", Rd, Rm, Rs); } return ERROR_OK; } /* Multiply (accumulate) long */ if ((opcode & 0x0f800000) == 0x00800000) { char *mnemonic = NULL; uint8_t Rm, Rs, RdHi, RdLow, S; Rm = opcode & 0xf; Rs = (opcode & 0xf00) >> 8; RdHi = (opcode & 0xf000) >> 12; RdLow = (opcode & 0xf0000) >> 16; S = (opcode & 0x00100000) >> 20; switch ((opcode & 0x00600000) >> 21) { case 0x0: instruction->type = ARM_UMULL; mnemonic = "UMULL"; break; case 0x1: instruction->type = ARM_UMLAL; mnemonic = "UMLAL"; break; case 0x2: instruction->type = ARM_SMULL; mnemonic = "SMULL"; break; case 0x3: instruction->type = ARM_SMLAL; mnemonic = "SMLAL"; break; } snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, r%i, r%i, r%i", address, opcode, mnemonic, COND(opcode), (S) ? "S" : "", RdLow, RdHi, Rm, Rs); return ERROR_OK; } /* Swap/swap byte */ if ((opcode & 0x0f800000) == 0x01000000) { uint8_t Rm, Rd, Rn; Rm = opcode & 0xf; Rd = (opcode & 0xf000) >> 12; Rn = (opcode & 0xf0000) >> 16; /* examine B flag */ instruction->type = (opcode & 0x00400000) ? ARM_SWPB : ARM_SWP; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s r%i, r%i, [r%i]", address, opcode, (opcode & 0x00400000) ? "SWPB" : "SWP", COND(opcode), Rd, Rm, Rn); return ERROR_OK; } } return evaluate_misc_load_store(opcode, address, instruction); } static int evaluate_mrs_msr(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { int R = (opcode & 0x00400000) >> 22; char *PSR = (R) ? "SPSR" : "CPSR"; /* Move register to status register (MSR) */ if (opcode & 0x00200000) { instruction->type = ARM_MSR; /* immediate variant */ if (opcode & 0x02000000) { uint8_t immediate = (opcode & 0xff); uint8_t rotate = (opcode & 0xf00); snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMSR%s %s_%s%s%s%s, 0x%8.8" PRIx32, address, opcode, COND(opcode), PSR, (opcode & 0x10000) ? "c" : "", (opcode & 0x20000) ? "x" : "", (opcode & 0x40000) ? "s" : "", (opcode & 0x80000) ? "f" : "", ror(immediate, (rotate * 2)) ); } else {/* register variant */ uint8_t Rm = opcode & 0xf; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMSR%s %s_%s%s%s%s, r%i", address, opcode, COND(opcode), PSR, (opcode & 0x10000) ? "c" : "", (opcode & 0x20000) ? "x" : "", (opcode & 0x40000) ? "s" : "", (opcode & 0x80000) ? "f" : "", Rm ); } } else {/* Move status register to register (MRS) */ uint8_t Rd; instruction->type = ARM_MRS; Rd = (opcode & 0x0000f000) >> 12; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMRS%s r%i, %s", address, opcode, COND(opcode), Rd, PSR); } return ERROR_OK; } /* Miscellaneous instructions */ static int evaluate_misc_instr(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { /* MRS/MSR */ if ((opcode & 0x000000f0) == 0x00000000) evaluate_mrs_msr(opcode, address, instruction); /* BX */ if ((opcode & 0x006000f0) == 0x00200010) { uint8_t Rm; instruction->type = ARM_BX; Rm = opcode & 0xf; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBX%s r%i", address, opcode, COND(opcode), Rm); instruction->info.b_bl_bx_blx.reg_operand = Rm; instruction->info.b_bl_bx_blx.target_address = -1; } /* BXJ - "Jazelle" support (ARMv5-J) */ if ((opcode & 0x006000f0) == 0x00200020) { uint8_t Rm; instruction->type = ARM_BX; Rm = opcode & 0xf; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBXJ%s r%i", address, opcode, COND(opcode), Rm); instruction->info.b_bl_bx_blx.reg_operand = Rm; instruction->info.b_bl_bx_blx.target_address = -1; } /* CLZ */ if ((opcode & 0x006000f0) == 0x00600010) { uint8_t Rm, Rd; instruction->type = ARM_CLZ; Rm = opcode & 0xf; Rd = (opcode & 0xf000) >> 12; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tCLZ%s r%i, r%i", address, opcode, COND(opcode), Rd, Rm); } /* BLX(2) */ if ((opcode & 0x006000f0) == 0x00200030) { uint8_t Rm; instruction->type = ARM_BLX; Rm = opcode & 0xf; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBLX%s r%i", address, opcode, COND(opcode), Rm); instruction->info.b_bl_bx_blx.reg_operand = Rm; instruction->info.b_bl_bx_blx.target_address = -1; } /* Enhanced DSP add/subtracts */ if ((opcode & 0x0000000f0) == 0x00000050) { uint8_t Rm, Rd, Rn; char *mnemonic = NULL; Rm = opcode & 0xf; Rd = (opcode & 0xf000) >> 12; Rn = (opcode & 0xf0000) >> 16; switch ((opcode & 0x00600000) >> 21) { case 0x0: instruction->type = ARM_QADD; mnemonic = "QADD"; break; case 0x1: instruction->type = ARM_QSUB; mnemonic = "QSUB"; break; case 0x2: instruction->type = ARM_QDADD; mnemonic = "QDADD"; break; case 0x3: instruction->type = ARM_QDSUB; mnemonic = "QDSUB"; break; } snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s r%i, r%i, r%i", address, opcode, mnemonic, COND(opcode), Rd, Rm, Rn); } /* Software breakpoints */ if ((opcode & 0x0000000f0) == 0x00000070) { uint32_t immediate; instruction->type = ARM_BKPT; immediate = ((opcode & 0x000fff00) >> 4) | (opcode & 0xf); snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBKPT 0x%4.4" PRIx32 "", address, opcode, immediate); } /* Enhanced DSP multiplies */ if ((opcode & 0x000000090) == 0x00000080) { int x = (opcode & 0x20) >> 5; int y = (opcode & 0x40) >> 6; /* SMLA < x> */ if ((opcode & 0x00600000) == 0x00000000) { uint8_t Rd, Rm, Rs, Rn; instruction->type = ARM_SMLAxy; Rd = (opcode & 0xf0000) >> 16; Rm = (opcode & 0xf); Rs = (opcode & 0xf00) >> 8; Rn = (opcode & 0xf000) >> 12; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSMLA%s%s%s r%i, r%i, r%i, r%i", address, opcode, (x) ? "T" : "B", (y) ? "T" : "B", COND(opcode), Rd, Rm, Rs, Rn); } /* SMLAL < x> */ if ((opcode & 0x00600000) == 0x00400000) { uint8_t RdLow, RdHi, Rm, Rs; instruction->type = ARM_SMLAxy; RdHi = (opcode & 0xf0000) >> 16; RdLow = (opcode & 0xf000) >> 12; Rm = (opcode & 0xf); Rs = (opcode & 0xf00) >> 8; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSMLA%s%s%s r%i, r%i, r%i, r%i", address, opcode, (x) ? "T" : "B", (y) ? "T" : "B", COND(opcode), RdLow, RdHi, Rm, Rs); } /* SMLAW < y> */ if (((opcode & 0x00600000) == 0x00100000) && (x == 0)) { uint8_t Rd, Rm, Rs, Rn; instruction->type = ARM_SMLAWy; Rd = (opcode & 0xf0000) >> 16; Rm = (opcode & 0xf); Rs = (opcode & 0xf00) >> 8; Rn = (opcode & 0xf000) >> 12; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSMLAW%s%s r%i, r%i, r%i, r%i", address, opcode, (y) ? "T" : "B", COND(opcode), Rd, Rm, Rs, Rn); } /* SMUL < x> */ if ((opcode & 0x00600000) == 0x00300000) { uint8_t Rd, Rm, Rs; instruction->type = ARM_SMULxy; Rd = (opcode & 0xf0000) >> 16; Rm = (opcode & 0xf); Rs = (opcode & 0xf00) >> 8; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSMULW%s%s%s r%i, r%i, r%i", address, opcode, (x) ? "T" : "B", (y) ? "T" : "B", COND(opcode), Rd, Rm, Rs); } /* SMULW < y> */ if (((opcode & 0x00600000) == 0x00100000) && (x == 1)) { uint8_t Rd, Rm, Rs; instruction->type = ARM_SMULWy; Rd = (opcode & 0xf0000) >> 16; Rm = (opcode & 0xf); Rs = (opcode & 0xf00) >> 8; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSMULW%s%s r%i, r%i, r%i", address, opcode, (y) ? "T" : "B", COND(opcode), Rd, Rm, Rs); } } return ERROR_OK; } static int evaluate_data_proc(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { uint8_t I, op, S, Rn, Rd; char *mnemonic = NULL; char shifter_operand[32]; I = (opcode & 0x02000000) >> 25; op = (opcode & 0x01e00000) >> 21; S = (opcode & 0x00100000) >> 20; Rd = (opcode & 0xf000) >> 12; Rn = (opcode & 0xf0000) >> 16; instruction->info.data_proc.Rd = Rd; instruction->info.data_proc.Rn = Rn; instruction->info.data_proc.S = S; switch (op) { case 0x0: instruction->type = ARM_AND; mnemonic = "AND"; break; case 0x1: instruction->type = ARM_EOR; mnemonic = "EOR"; break; case 0x2: instruction->type = ARM_SUB; mnemonic = "SUB"; break; case 0x3: instruction->type = ARM_RSB; mnemonic = "RSB"; break; case 0x4: instruction->type = ARM_ADD; mnemonic = "ADD"; break; case 0x5: instruction->type = ARM_ADC; mnemonic = "ADC"; break; case 0x6: instruction->type = ARM_SBC; mnemonic = "SBC"; break; case 0x7: instruction->type = ARM_RSC; mnemonic = "RSC"; break; case 0x8: instruction->type = ARM_TST; mnemonic = "TST"; break; case 0x9: instruction->type = ARM_TEQ; mnemonic = "TEQ"; break; case 0xa: instruction->type = ARM_CMP; mnemonic = "CMP"; break; case 0xb: instruction->type = ARM_CMN; mnemonic = "CMN"; break; case 0xc: instruction->type = ARM_ORR; mnemonic = "ORR"; break; case 0xd: instruction->type = ARM_MOV; mnemonic = "MOV"; break; case 0xe: instruction->type = ARM_BIC; mnemonic = "BIC"; break; case 0xf: instruction->type = ARM_MVN; mnemonic = "MVN"; break; } if (I) {/* immediate shifter operand (#)*/ uint8_t immed_8 = opcode & 0xff; uint8_t rotate_imm = (opcode & 0xf00) >> 8; uint32_t immediate; immediate = ror(immed_8, rotate_imm * 2); snprintf(shifter_operand, 32, "#0x%" PRIx32 "", immediate); instruction->info.data_proc.variant = 0; instruction->info.data_proc.shifter_operand.immediate.immediate = immediate; } else {/* register-based shifter operand */ uint8_t shift, Rm; shift = (opcode & 0x60) >> 5; Rm = (opcode & 0xf); if ((opcode & 0x10) != 0x10) { /* Immediate shifts ("" or ", *#") */ uint8_t shift_imm; shift_imm = (opcode & 0xf80) >> 7; instruction->info.data_proc.variant = 1; instruction->info.data_proc.shifter_operand.immediate_shift.Rm = Rm; instruction->info.data_proc.shifter_operand.immediate_shift.shift_imm = shift_imm; instruction->info.data_proc.shifter_operand.immediate_shift.shift = shift; /* LSR encodes a shift by 32 bit as 0x0 */ if ((shift == 0x1) && (shift_imm == 0x0)) shift_imm = 0x20; /* ASR encodes a shift by 32 bit as 0x0 */ if ((shift == 0x2) && (shift_imm == 0x0)) shift_imm = 0x20; /* ROR by 32 bit is actually a RRX */ if ((shift == 0x3) && (shift_imm == 0x0)) shift = 0x4; if ((shift_imm == 0x0) && (shift == 0x0)) snprintf(shifter_operand, 32, "r%i", Rm); else { if (shift == 0x0) /* LSL */ snprintf(shifter_operand, 32, "r%i, LSL #0x%x", Rm, shift_imm); else if (shift == 0x1) /* LSR */ snprintf(shifter_operand, 32, "r%i, LSR #0x%x", Rm, shift_imm); else if (shift == 0x2) /* ASR */ snprintf(shifter_operand, 32, "r%i, ASR #0x%x", Rm, shift_imm); else if (shift == 0x3) /* ROR */ snprintf(shifter_operand, 32, "r%i, ROR #0x%x", Rm, shift_imm); else if (shift == 0x4) /* RRX */ snprintf(shifter_operand, 32, "r%i, RRX", Rm); } } else {/* Register shifts (", ") */ uint8_t Rs = (opcode & 0xf00) >> 8; instruction->info.data_proc.variant = 2; instruction->info.data_proc.shifter_operand.register_shift.Rm = Rm; instruction->info.data_proc.shifter_operand.register_shift.Rs = Rs; instruction->info.data_proc.shifter_operand.register_shift.shift = shift; if (shift == 0x0) /* LSL */ snprintf(shifter_operand, 32, "r%i, LSL r%i", Rm, Rs); else if (shift == 0x1) /* LSR */ snprintf(shifter_operand, 32, "r%i, LSR r%i", Rm, Rs); else if (shift == 0x2) /* ASR */ snprintf(shifter_operand, 32, "r%i, ASR r%i", Rm, Rs); else if (shift == 0x3) /* ROR */ snprintf(shifter_operand, 32, "r%i, ROR r%i", Rm, Rs); } } if ((op < 0x8) || (op == 0xc) || (op == 0xe)) { /* {}{S} , , * */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, r%i, %s", address, opcode, mnemonic, COND(opcode), (S) ? "S" : "", Rd, Rn, shifter_operand); } else if ((op == 0xd) || (op == 0xf)) { /* {}{S} , * */ if (opcode == 0xe1a00000) /* print MOV r0,r0 as NOP */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tNOP", address, opcode); else snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, %s", address, opcode, mnemonic, COND(opcode), (S) ? "S" : "", Rd, shifter_operand); } else {/* {} , */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s r%i, %s", address, opcode, mnemonic, COND(opcode), Rn, shifter_operand); } return ERROR_OK; } int arm_evaluate_opcode(uint32_t opcode, uint32_t address, struct arm_instruction *instruction) { /* clear fields, to avoid confusion */ memset(instruction, 0, sizeof(struct arm_instruction)); instruction->opcode = opcode; instruction->instruction_size = 4; /* catch opcodes with condition field [31:28] = b1111 */ if ((opcode & 0xf0000000) == 0xf0000000) { /* Undefined instruction (or ARMv5E cache preload PLD) */ if ((opcode & 0x08000000) == 0x00000000) return evaluate_pld(opcode, address, instruction); /* Undefined instruction (or ARMv6+ SRS/RFE) */ if ((opcode & 0x0e000000) == 0x08000000) return evaluate_srs(opcode, address, instruction); /* Branch and branch with link and change to Thumb */ if ((opcode & 0x0e000000) == 0x0a000000) return evaluate_blx_imm(opcode, address, instruction); /* Extended coprocessor opcode space (ARMv5 and higher) * Coprocessor load/store and double register transfers */ if ((opcode & 0x0e000000) == 0x0c000000) return evaluate_ldc_stc_mcrr_mrrc(opcode, address, instruction); /* Coprocessor data processing */ if ((opcode & 0x0f000100) == 0x0c000000) return evaluate_cdp_mcr_mrc(opcode, address, instruction); /* Coprocessor register transfers */ if ((opcode & 0x0f000010) == 0x0c000010) return evaluate_cdp_mcr_mrc(opcode, address, instruction); /* Undefined instruction */ if ((opcode & 0x0f000000) == 0x0f000000) { instruction->type = ARM_UNDEFINED_INSTRUCTION; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION", address, opcode); return ERROR_OK; } } /* catch opcodes with [27:25] = b000 */ if ((opcode & 0x0e000000) == 0x00000000) { /* Multiplies, extra load/stores */ if ((opcode & 0x00000090) == 0x00000090) return evaluate_mul_and_extra_ld_st(opcode, address, instruction); /* Miscellaneous instructions */ if ((opcode & 0x0f900000) == 0x01000000) return evaluate_misc_instr(opcode, address, instruction); return evaluate_data_proc(opcode, address, instruction); } /* catch opcodes with [27:25] = b001 */ if ((opcode & 0x0e000000) == 0x02000000) { /* Undefined instruction */ if ((opcode & 0x0fb00000) == 0x03000000) { instruction->type = ARM_UNDEFINED_INSTRUCTION; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION", address, opcode); return ERROR_OK; } /* Move immediate to status register */ if ((opcode & 0x0fb00000) == 0x03200000) return evaluate_mrs_msr(opcode, address, instruction); return evaluate_data_proc(opcode, address, instruction); } /* catch opcodes with [27:25] = b010 */ if ((opcode & 0x0e000000) == 0x04000000) { /* Load/store immediate offset */ return evaluate_load_store(opcode, address, instruction); } /* catch opcodes with [27:25] = b011 */ if ((opcode & 0x0e000000) == 0x06000000) { /* Load/store register offset */ if ((opcode & 0x00000010) == 0x00000000) return evaluate_load_store(opcode, address, instruction); /* Architecturally Undefined instruction * ... don't expect these to ever be used */ if ((opcode & 0x07f000f0) == 0x07f000f0) { instruction->type = ARM_UNDEFINED_INSTRUCTION; snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEF", address, opcode); return ERROR_OK; } /* "media" instructions */ return evaluate_media(opcode, address, instruction); } /* catch opcodes with [27:25] = b100 */ if ((opcode & 0x0e000000) == 0x08000000) { /* Load/store multiple */ return evaluate_ldm_stm(opcode, address, instruction); } /* catch opcodes with [27:25] = b101 */ if ((opcode & 0x0e000000) == 0x0a000000) { /* Branch and branch with link */ return evaluate_b_bl(opcode, address, instruction); } /* catch opcodes with [27:25] = b110 */ if ((opcode & 0x0e000000) == 0x0c000000) { /* Coprocessor load/store and double register transfers */ return evaluate_ldc_stc_mcrr_mrrc(opcode, address, instruction); } /* catch opcodes with [27:25] = b111 */ if ((opcode & 0x0e000000) == 0x0e000000) { /* Software interrupt */ if ((opcode & 0x0f000000) == 0x0f000000) return evaluate_swi(opcode, address, instruction); /* Coprocessor data processing */ if ((opcode & 0x0f000010) == 0x0e000000) return evaluate_cdp_mcr_mrc(opcode, address, instruction); /* Coprocessor register transfers */ if ((opcode & 0x0f000010) == 0x0e000010) return evaluate_cdp_mcr_mrc(opcode, address, instruction); } LOG_ERROR("ARM: should never reach this point (opcode=%08x)", (unsigned) opcode); return -1; } static int evaluate_b_bl_blx_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { uint32_t offset = opcode & 0x7ff; uint32_t opc = (opcode >> 11) & 0x3; uint32_t target_address; char *mnemonic = NULL; /* sign extend 11-bit offset */ if (((opc == 0) || (opc == 2)) && (offset & 0x00000400)) offset = 0xfffff800 | offset; target_address = address + 4 + (offset << 1); switch (opc) { /* unconditional branch */ case 0: instruction->type = ARM_B; mnemonic = "B"; break; /* BLX suffix */ case 1: instruction->type = ARM_BLX; mnemonic = "BLX"; target_address &= 0xfffffffc; break; /* BL/BLX prefix */ case 2: instruction->type = ARM_UNKNOWN_INSTUCTION; mnemonic = "prefix"; target_address = offset << 12; break; /* BL suffix */ case 3: instruction->type = ARM_BL; mnemonic = "BL"; break; } /* TODO: deal correctly with dual opcode (prefixed) BL/BLX; * these are effectively 32-bit instructions even in Thumb1. For * disassembly, it's simplest to always use the Thumb2 decoder. * * But some cores will evidently handle them as two instructions, * where exceptions may occur between the two. The ETMv3.2+ ID * register has a bit which exposes this behavior. */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t%s\t%#8.8" PRIx32, address, opcode, mnemonic, target_address); instruction->info.b_bl_bx_blx.reg_operand = -1; instruction->info.b_bl_bx_blx.target_address = target_address; return ERROR_OK; } static int evaluate_add_sub_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { uint8_t Rd = (opcode >> 0) & 0x7; uint8_t Rn = (opcode >> 3) & 0x7; uint8_t Rm_imm = (opcode >> 6) & 0x7; uint32_t opc = opcode & (1 << 9); uint32_t reg_imm = opcode & (1 << 10); char *mnemonic; if (opc) { instruction->type = ARM_SUB; mnemonic = "SUBS"; } else { /* REVISIT: if reg_imm == 0, display as "MOVS" */ instruction->type = ARM_ADD; mnemonic = "ADDS"; } instruction->info.data_proc.Rd = Rd; instruction->info.data_proc.Rn = Rn; instruction->info.data_proc.S = 1; if (reg_imm) { instruction->info.data_proc.variant = 0;/*immediate*/ instruction->info.data_proc.shifter_operand.immediate.immediate = Rm_imm; snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, r%i, #%d", address, opcode, mnemonic, Rd, Rn, Rm_imm); } else { instruction->info.data_proc.variant = 1;/*immediate shift*/ instruction->info.data_proc.shifter_operand.immediate_shift.Rm = Rm_imm; snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, r%i, r%i", address, opcode, mnemonic, Rd, Rn, Rm_imm); } return ERROR_OK; } static int evaluate_shift_imm_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { uint8_t Rd = (opcode >> 0) & 0x7; uint8_t Rm = (opcode >> 3) & 0x7; uint8_t imm = (opcode >> 6) & 0x1f; uint8_t opc = (opcode >> 11) & 0x3; char *mnemonic = NULL; switch (opc) { case 0: instruction->type = ARM_MOV; mnemonic = "LSLS"; instruction->info.data_proc.shifter_operand.immediate_shift.shift = 0; break; case 1: instruction->type = ARM_MOV; mnemonic = "LSRS"; instruction->info.data_proc.shifter_operand.immediate_shift.shift = 1; break; case 2: instruction->type = ARM_MOV; mnemonic = "ASRS"; instruction->info.data_proc.shifter_operand.immediate_shift.shift = 2; break; } if ((imm == 0) && (opc != 0)) imm = 32; instruction->info.data_proc.Rd = Rd; instruction->info.data_proc.Rn = -1; instruction->info.data_proc.S = 1; instruction->info.data_proc.variant = 1;/*immediate_shift*/ instruction->info.data_proc.shifter_operand.immediate_shift.Rm = Rm; instruction->info.data_proc.shifter_operand.immediate_shift.shift_imm = imm; snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, r%i, #%#2.2x", address, opcode, mnemonic, Rd, Rm, imm); return ERROR_OK; } static int evaluate_data_proc_imm_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { uint8_t imm = opcode & 0xff; uint8_t Rd = (opcode >> 8) & 0x7; uint32_t opc = (opcode >> 11) & 0x3; char *mnemonic = NULL; instruction->info.data_proc.Rd = Rd; instruction->info.data_proc.Rn = Rd; instruction->info.data_proc.S = 1; instruction->info.data_proc.variant = 0;/*immediate*/ instruction->info.data_proc.shifter_operand.immediate.immediate = imm; switch (opc) { case 0: instruction->type = ARM_MOV; mnemonic = "MOVS"; instruction->info.data_proc.Rn = -1; break; case 1: instruction->type = ARM_CMP; mnemonic = "CMP"; instruction->info.data_proc.Rd = -1; break; case 2: instruction->type = ARM_ADD; mnemonic = "ADDS"; break; case 3: instruction->type = ARM_SUB; mnemonic = "SUBS"; break; } snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, #%#2.2x", address, opcode, mnemonic, Rd, imm); return ERROR_OK; } static int evaluate_data_proc_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { uint8_t high_reg, op, Rm, Rd, H1, H2; char *mnemonic = NULL; bool nop = false; high_reg = (opcode & 0x0400) >> 10; op = (opcode & 0x03C0) >> 6; Rd = (opcode & 0x0007); Rm = (opcode & 0x0038) >> 3; H1 = (opcode & 0x0080) >> 7; H2 = (opcode & 0x0040) >> 6; instruction->info.data_proc.Rd = Rd; instruction->info.data_proc.Rn = Rd; instruction->info.data_proc.S = (!high_reg || (instruction->type == ARM_CMP)); instruction->info.data_proc.variant = 1 /*immediate shift*/; instruction->info.data_proc.shifter_operand.immediate_shift.Rm = Rm; if (high_reg) { Rd |= H1 << 3; Rm |= H2 << 3; op >>= 2; switch (op) { case 0x0: instruction->type = ARM_ADD; mnemonic = "ADD"; break; case 0x1: instruction->type = ARM_CMP; mnemonic = "CMP"; break; case 0x2: instruction->type = ARM_MOV; mnemonic = "MOV"; if (Rd == Rm) nop = true; break; case 0x3: if ((opcode & 0x7) == 0x0) { instruction->info.b_bl_bx_blx.reg_operand = Rm; if (H1) { instruction->type = ARM_BLX; snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \tBLX\tr%i", address, opcode, Rm); } else { instruction->type = ARM_BX; snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \tBX\tr%i", address, opcode, Rm); } } else { instruction->type = ARM_UNDEFINED_INSTRUCTION; snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t" "UNDEFINED INSTRUCTION", address, opcode); } return ERROR_OK; break; } } else { switch (op) { case 0x0: instruction->type = ARM_AND; mnemonic = "ANDS"; break; case 0x1: instruction->type = ARM_EOR; mnemonic = "EORS"; break; case 0x2: instruction->type = ARM_MOV; mnemonic = "LSLS"; instruction->info.data_proc.variant = 2 /*register shift*/; instruction->info.data_proc.shifter_operand.register_shift.shift = 0; instruction->info.data_proc.shifter_operand.register_shift.Rm = Rd; instruction->info.data_proc.shifter_operand.register_shift.Rs = Rm; break; case 0x3: instruction->type = ARM_MOV; mnemonic = "LSRS"; instruction->info.data_proc.variant = 2 /*register shift*/; instruction->info.data_proc.shifter_operand.register_shift.shift = 1; instruction->info.data_proc.shifter_operand.register_shift.Rm = Rd; instruction->info.data_proc.shifter_operand.register_shift.Rs = Rm; break; case 0x4: instruction->type = ARM_MOV; mnemonic = "ASRS"; instruction->info.data_proc.variant = 2 /*register shift*/; instruction->info.data_proc.shifter_operand.register_shift.shift = 2; instruction->info.data_proc.shifter_operand.register_shift.Rm = Rd; instruction->info.data_proc.shifter_operand.register_shift.Rs = Rm; break; case 0x5: instruction->type = ARM_ADC; mnemonic = "ADCS"; break; case 0x6: instruction->type = ARM_SBC; mnemonic = "SBCS"; break; case 0x7: instruction->type = ARM_MOV; mnemonic = "RORS"; instruction->info.data_proc.variant = 2 /*register shift*/; instruction->info.data_proc.shifter_operand.register_shift.shift = 3; instruction->info.data_proc.shifter_operand.register_shift.Rm = Rd; instruction->info.data_proc.shifter_operand.register_shift.Rs = Rm; break; case 0x8: instruction->type = ARM_TST; mnemonic = "TST"; break; case 0x9: instruction->type = ARM_RSB; mnemonic = "RSBS"; instruction->info.data_proc.variant = 0 /*immediate*/; instruction->info.data_proc.shifter_operand.immediate.immediate = 0; instruction->info.data_proc.Rn = Rm; break; case 0xA: instruction->type = ARM_CMP; mnemonic = "CMP"; break; case 0xB: instruction->type = ARM_CMN; mnemonic = "CMN"; break; case 0xC: instruction->type = ARM_ORR; mnemonic = "ORRS"; break; case 0xD: instruction->type = ARM_MUL; mnemonic = "MULS"; break; case 0xE: instruction->type = ARM_BIC; mnemonic = "BICS"; break; case 0xF: instruction->type = ARM_MVN; mnemonic = "MVNS"; break; } } if (nop) snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \tNOP\t\t\t" "; (%s r%i, r%i)", address, opcode, mnemonic, Rd, Rm); else snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, r%i", address, opcode, mnemonic, Rd, Rm); return ERROR_OK; } /* PC-relative data addressing is word-aligned even with Thumb */ static inline uint32_t thumb_alignpc4(uint32_t addr) { return (addr + 4) & ~3; } static int evaluate_load_literal_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { uint32_t immediate; uint8_t Rd = (opcode >> 8) & 0x7; instruction->type = ARM_LDR; immediate = opcode & 0x000000ff; immediate *= 4; instruction->info.load_store.Rd = Rd; instruction->info.load_store.Rn = 15 /*PC*/; instruction->info.load_store.index_mode = 0; /*offset*/ instruction->info.load_store.offset_mode = 0; /*immediate*/ instruction->info.load_store.offset.offset = immediate; snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t" "LDR\tr%i, [pc, #%#" PRIx32 "]\t; %#8.8" PRIx32, address, opcode, Rd, immediate, thumb_alignpc4(address) + immediate); return ERROR_OK; } static int evaluate_load_store_reg_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { uint8_t Rd = (opcode >> 0) & 0x7; uint8_t Rn = (opcode >> 3) & 0x7; uint8_t Rm = (opcode >> 6) & 0x7; uint8_t opc = (opcode >> 9) & 0x7; char *mnemonic = NULL; switch (opc) { case 0: instruction->type = ARM_STR; mnemonic = "STR"; break; case 1: instruction->type = ARM_STRH; mnemonic = "STRH"; break; case 2: instruction->type = ARM_STRB; mnemonic = "STRB"; break; case 3: instruction->type = ARM_LDRSB; mnemonic = "LDRSB"; break; case 4: instruction->type = ARM_LDR; mnemonic = "LDR"; break; case 5: instruction->type = ARM_LDRH; mnemonic = "LDRH"; break; case 6: instruction->type = ARM_LDRB; mnemonic = "LDRB"; break; case 7: instruction->type = ARM_LDRSH; mnemonic = "LDRSH"; break; } snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, [r%i, r%i]", address, opcode, mnemonic, Rd, Rn, Rm); instruction->info.load_store.Rd = Rd; instruction->info.load_store.Rn = Rn; instruction->info.load_store.index_mode = 0; /*offset*/ instruction->info.load_store.offset_mode = 1; /*register*/ instruction->info.load_store.offset.reg.Rm = Rm; return ERROR_OK; } static int evaluate_load_store_imm_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { uint32_t offset = (opcode >> 6) & 0x1f; uint8_t Rd = (opcode >> 0) & 0x7; uint8_t Rn = (opcode >> 3) & 0x7; uint32_t L = opcode & (1 << 11); uint32_t B = opcode & (1 << 12); char *mnemonic; char suffix = ' '; uint32_t shift = 2; if (L) { instruction->type = ARM_LDR; mnemonic = "LDR"; } else { instruction->type = ARM_STR; mnemonic = "STR"; } if ((opcode&0xF000) == 0x8000) { suffix = 'H'; shift = 1; } else if (B) { suffix = 'B'; shift = 0; } snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t%s%c\tr%i, [r%i, #%#" PRIx32 "]", address, opcode, mnemonic, suffix, Rd, Rn, offset << shift); instruction->info.load_store.Rd = Rd; instruction->info.load_store.Rn = Rn; instruction->info.load_store.index_mode = 0; /*offset*/ instruction->info.load_store.offset_mode = 0; /*immediate*/ instruction->info.load_store.offset.offset = offset << shift; return ERROR_OK; } static int evaluate_load_store_stack_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { uint32_t offset = opcode & 0xff; uint8_t Rd = (opcode >> 8) & 0x7; uint32_t L = opcode & (1 << 11); char *mnemonic; if (L) { instruction->type = ARM_LDR; mnemonic = "LDR"; } else { instruction->type = ARM_STR; mnemonic = "STR"; } snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, [SP, #%#" PRIx32 "]", address, opcode, mnemonic, Rd, offset*4); instruction->info.load_store.Rd = Rd; instruction->info.load_store.Rn = 13 /*SP*/; instruction->info.load_store.index_mode = 0; /*offset*/ instruction->info.load_store.offset_mode = 0; /*immediate*/ instruction->info.load_store.offset.offset = offset*4; return ERROR_OK; } static int evaluate_add_sp_pc_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { uint32_t imm = opcode & 0xff; uint8_t Rd = (opcode >> 8) & 0x7; uint8_t Rn; uint32_t SP = opcode & (1 << 11); const char *reg_name; instruction->type = ARM_ADD; if (SP) { reg_name = "SP"; Rn = 13; } else { reg_name = "PC"; Rn = 15; } snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \tADD\tr%i, %s, #%#" PRIx32, address, opcode, Rd, reg_name, imm * 4); instruction->info.data_proc.variant = 0 /* immediate */; instruction->info.data_proc.Rd = Rd; instruction->info.data_proc.Rn = Rn; instruction->info.data_proc.shifter_operand.immediate.immediate = imm*4; return ERROR_OK; } static int evaluate_adjust_stack_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { uint32_t imm = opcode & 0x7f; uint8_t opc = opcode & (1 << 7); char *mnemonic; if (opc) { instruction->type = ARM_SUB; mnemonic = "SUB"; } else { instruction->type = ARM_ADD; mnemonic = "ADD"; } snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t%s\tSP, #%#" PRIx32, address, opcode, mnemonic, imm*4); instruction->info.data_proc.variant = 0 /* immediate */; instruction->info.data_proc.Rd = 13 /*SP*/; instruction->info.data_proc.Rn = 13 /*SP*/; instruction->info.data_proc.shifter_operand.immediate.immediate = imm*4; return ERROR_OK; } static int evaluate_breakpoint_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { uint32_t imm = opcode & 0xff; instruction->type = ARM_BKPT; snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \tBKPT\t%#2.2" PRIx32 "", address, opcode, imm); return ERROR_OK; } static int evaluate_load_store_multiple_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { uint32_t reg_list = opcode & 0xff; uint32_t L = opcode & (1 << 11); uint32_t R = opcode & (1 << 8); uint8_t Rn = (opcode >> 8) & 7; uint8_t addr_mode = 0 /* IA */; char reg_names[40]; char *reg_names_p; char *mnemonic; char ptr_name[7] = ""; int i; /* REVISIT: in ThumbEE mode, there are no LDM or STM instructions. * The STMIA and LDMIA opcodes are used for other instructions. */ if ((opcode & 0xf000) == 0xc000) { /* generic load/store multiple */ char *wback = "!"; if (L) { instruction->type = ARM_LDM; mnemonic = "LDM"; if (opcode & (1 << Rn)) wback = ""; } else { instruction->type = ARM_STM; mnemonic = "STM"; } snprintf(ptr_name, sizeof ptr_name, "r%i%s, ", Rn, wback); } else {/* push/pop */ Rn = 13;/* SP */ if (L) { instruction->type = ARM_LDM; mnemonic = "POP"; if (R) reg_list |= (1 << 15) /*PC*/; } else { instruction->type = ARM_STM; mnemonic = "PUSH"; addr_mode = 3; /*DB*/ if (R) reg_list |= (1 << 14) /*LR*/; } } reg_names_p = reg_names; for (i = 0; i <= 15; i++) { if (reg_list & (1 << i)) reg_names_p += snprintf(reg_names_p, (reg_names + 40 - reg_names_p), "r%i, ", i); } if (reg_names_p > reg_names) reg_names_p[-2] = '\0'; else /* invalid op : no registers */ reg_names[0] = '\0'; snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t%s\t%s{%s}", address, opcode, mnemonic, ptr_name, reg_names); instruction->info.load_store_multiple.register_list = reg_list; instruction->info.load_store_multiple.Rn = Rn; instruction->info.load_store_multiple.addressing_mode = addr_mode; return ERROR_OK; } static int evaluate_cond_branch_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { uint32_t offset = opcode & 0xff; uint8_t cond = (opcode >> 8) & 0xf; uint32_t target_address; if (cond == 0xf) { instruction->type = ARM_SWI; snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \tSVC\t%#2.2" PRIx32, address, opcode, offset); return ERROR_OK; } else if (cond == 0xe) { instruction->type = ARM_UNDEFINED_INSTRUCTION; snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \tUNDEFINED INSTRUCTION", address, opcode); return ERROR_OK; } /* sign extend 8-bit offset */ if (offset & 0x00000080) offset = 0xffffff00 | offset; target_address = address + 4 + (offset << 1); snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \tB%s\t%#8.8" PRIx32, address, opcode, arm_condition_strings[cond], target_address); instruction->type = ARM_B; instruction->info.b_bl_bx_blx.reg_operand = -1; instruction->info.b_bl_bx_blx.target_address = target_address; return ERROR_OK; } static int evaluate_cb_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { unsigned offset; /* added in Thumb2 */ offset = (opcode >> 3) & 0x1f; offset |= (opcode & 0x0200) >> 4; snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \tCB%sZ\tr%d, %#8.8" PRIx32, address, opcode, (opcode & 0x0800) ? "N" : "", opcode & 0x7, address + 4 + (offset << 1)); return ERROR_OK; } static int evaluate_extend_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { /* added in ARMv6 */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t%cXT%c\tr%d, r%d", address, opcode, (opcode & 0x0080) ? 'U' : 'S', (opcode & 0x0040) ? 'B' : 'H', opcode & 0x7, (opcode >> 3) & 0x7); return ERROR_OK; } static int evaluate_cps_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { /* added in ARMv6 */ if ((opcode & 0x0ff0) == 0x0650) snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \tSETEND %s", address, opcode, (opcode & 0x80) ? "BE" : "LE"); else /* ASSUME (opcode & 0x0fe0) == 0x0660 */ snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \tCPSI%c\t%s%s%s", address, opcode, (opcode & 0x0010) ? 'D' : 'E', (opcode & 0x0004) ? "A" : "", (opcode & 0x0002) ? "I" : "", (opcode & 0x0001) ? "F" : ""); return ERROR_OK; } static int evaluate_byterev_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { char *suffix; /* added in ARMv6 */ switch ((opcode >> 6) & 3) { case 0: suffix = ""; break; case 1: suffix = "16"; break; default: suffix = "SH"; break; } snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \tREV%s\tr%d, r%d", address, opcode, suffix, opcode & 0x7, (opcode >> 3) & 0x7); return ERROR_OK; } static int evaluate_hint_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { char *hint; switch ((opcode >> 4) & 0x0f) { case 0: hint = "NOP"; break; case 1: hint = "YIELD"; break; case 2: hint = "WFE"; break; case 3: hint = "WFI"; break; case 4: hint = "SEV"; break; default: hint = "HINT (UNRECOGNIZED)"; break; } snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \t%s", address, opcode, hint); return ERROR_OK; } static int evaluate_ifthen_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { unsigned cond = (opcode >> 4) & 0x0f; char *x = "", *y = "", *z = ""; if (opcode & 0x01) z = (opcode & 0x02) ? "T" : "E"; if (opcode & 0x03) y = (opcode & 0x04) ? "T" : "E"; if (opcode & 0x07) x = (opcode & 0x08) ? "T" : "E"; snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \tIT%s%s%s\t%s", address, opcode, x, y, z, arm_condition_strings[cond]); /* NOTE: strictly speaking, the next 1-4 instructions should * now be displayed with the relevant conditional suffix... */ return ERROR_OK; } int thumb_evaluate_opcode(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { /* clear fields, to avoid confusion */ memset(instruction, 0, sizeof(struct arm_instruction)); instruction->opcode = opcode; instruction->instruction_size = 2; if ((opcode & 0xe000) == 0x0000) { /* add/substract register or immediate */ if ((opcode & 0x1800) == 0x1800) return evaluate_add_sub_thumb(opcode, address, instruction); /* shift by immediate */ else return evaluate_shift_imm_thumb(opcode, address, instruction); } /* Add/substract/compare/move immediate */ if ((opcode & 0xe000) == 0x2000) return evaluate_data_proc_imm_thumb(opcode, address, instruction); /* Data processing instructions */ if ((opcode & 0xf800) == 0x4000) return evaluate_data_proc_thumb(opcode, address, instruction); /* Load from literal pool */ if ((opcode & 0xf800) == 0x4800) return evaluate_load_literal_thumb(opcode, address, instruction); /* Load/Store register offset */ if ((opcode & 0xf000) == 0x5000) return evaluate_load_store_reg_thumb(opcode, address, instruction); /* Load/Store immediate offset */ if (((opcode & 0xe000) == 0x6000) || ((opcode & 0xf000) == 0x8000)) return evaluate_load_store_imm_thumb(opcode, address, instruction); /* Load/Store from/to stack */ if ((opcode & 0xf000) == 0x9000) return evaluate_load_store_stack_thumb(opcode, address, instruction); /* Add to SP/PC */ if ((opcode & 0xf000) == 0xa000) return evaluate_add_sp_pc_thumb(opcode, address, instruction); /* Misc */ if ((opcode & 0xf000) == 0xb000) { switch ((opcode >> 8) & 0x0f) { case 0x0: return evaluate_adjust_stack_thumb(opcode, address, instruction); case 0x1: case 0x3: case 0x9: case 0xb: return evaluate_cb_thumb(opcode, address, instruction); case 0x2: return evaluate_extend_thumb(opcode, address, instruction); case 0x4: case 0x5: case 0xc: case 0xd: return evaluate_load_store_multiple_thumb(opcode, address, instruction); case 0x6: return evaluate_cps_thumb(opcode, address, instruction); case 0xa: if ((opcode & 0x00c0) == 0x0080) break; return evaluate_byterev_thumb(opcode, address, instruction); case 0xe: return evaluate_breakpoint_thumb(opcode, address, instruction); case 0xf: if (opcode & 0x000f) return evaluate_ifthen_thumb(opcode, address, instruction); else return evaluate_hint_thumb(opcode, address, instruction); } instruction->type = ARM_UNDEFINED_INSTRUCTION; snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%4.4x \tUNDEFINED INSTRUCTION", address, opcode); return ERROR_OK; } /* Load/Store multiple */ if ((opcode & 0xf000) == 0xc000) return evaluate_load_store_multiple_thumb(opcode, address, instruction); /* Conditional branch + SWI */ if ((opcode & 0xf000) == 0xd000) return evaluate_cond_branch_thumb(opcode, address, instruction); if ((opcode & 0xe000) == 0xe000) { /* Undefined instructions */ if ((opcode & 0xf801) == 0xe801) { instruction->type = ARM_UNDEFINED_INSTRUCTION; snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%8.8x\t" "UNDEFINED INSTRUCTION", address, opcode); return ERROR_OK; } else /* Branch to offset */ return evaluate_b_bl_blx_thumb(opcode, address, instruction); } LOG_ERROR("Thumb: should never reach this point (opcode=%04x)", opcode); return -1; } static int t2ev_b_bl(uint32_t opcode, uint32_t address, struct arm_instruction *instruction, char *cp) { unsigned offset; unsigned b21 = 1 << 21; unsigned b22 = 1 << 22; /* instead of combining two smaller 16-bit branch instructions, * Thumb2 uses only one larger 32-bit instruction. */ offset = opcode & 0x7ff; offset |= (opcode & 0x03ff0000) >> 5; if (opcode & (1 << 26)) { offset |= 0xff << 23; if ((opcode & (1 << 11)) == 0) b21 = 0; if ((opcode & (1 << 13)) == 0) b22 = 0; } else { if (opcode & (1 << 11)) b21 = 0; if (opcode & (1 << 13)) b22 = 0; } offset |= b21; offset |= b22; address += 4; address += offset << 1; instruction->type = (opcode & (1 << 14)) ? ARM_BL : ARM_B; instruction->info.b_bl_bx_blx.reg_operand = -1; instruction->info.b_bl_bx_blx.target_address = address; sprintf(cp, "%s\t%#8.8" PRIx32, (opcode & (1 << 14)) ? "BL" : "B.W", address); return ERROR_OK; } static int t2ev_cond_b(uint32_t opcode, uint32_t address, struct arm_instruction *instruction, char *cp) { unsigned offset; unsigned b17 = 1 << 17; unsigned b18 = 1 << 18; unsigned cond = (opcode >> 22) & 0x0f; offset = opcode & 0x7ff; offset |= (opcode & 0x003f0000) >> 5; if (opcode & (1 << 26)) { offset |= 0x1fff << 19; if ((opcode & (1 << 11)) == 0) b17 = 0; if ((opcode & (1 << 13)) == 0) b18 = 0; } else { if (opcode & (1 << 11)) b17 = 0; if (opcode & (1 << 13)) b18 = 0; } offset |= b17; offset |= b18; address += 4; address += offset << 1; instruction->type = ARM_B; instruction->info.b_bl_bx_blx.reg_operand = -1; instruction->info.b_bl_bx_blx.target_address = address; sprintf(cp, "B%s.W\t%#8.8" PRIx32, arm_condition_strings[cond], address); return ERROR_OK; } static const char *special_name(int number) { char *special = "(RESERVED)"; switch (number) { case 0: special = "apsr"; break; case 1: special = "iapsr"; break; case 2: special = "eapsr"; break; case 3: special = "xpsr"; break; case 5: special = "ipsr"; break; case 6: special = "epsr"; break; case 7: special = "iepsr"; break; case 8: special = "msp"; break; case 9: special = "psp"; break; case 16: special = "primask"; break; case 17: special = "basepri"; break; case 18: special = "basepri_max"; break; case 19: special = "faultmask"; break; case 20: special = "control"; break; } return special; } static int t2ev_hint(uint32_t opcode, uint32_t address, struct arm_instruction *instruction, char *cp) { const char *mnemonic; if (opcode & 0x0700) { instruction->type = ARM_UNDEFINED_INSTRUCTION; strcpy(cp, "UNDEFINED"); return ERROR_OK; } if (opcode & 0x00f0) { sprintf(cp, "DBG\t#%d", (int) opcode & 0xf); return ERROR_OK; } switch (opcode & 0x0f) { case 0: mnemonic = "NOP.W"; break; case 1: mnemonic = "YIELD.W"; break; case 2: mnemonic = "WFE.W"; break; case 3: mnemonic = "WFI.W"; break; case 4: mnemonic = "SEV.W"; break; default: mnemonic = "HINT.W (UNRECOGNIZED)"; break; } strcpy(cp, mnemonic); return ERROR_OK; } static int t2ev_misc(uint32_t opcode, uint32_t address, struct arm_instruction *instruction, char *cp) { const char *mnemonic; switch ((opcode >> 4) & 0x0f) { case 0: mnemonic = "LEAVEX"; break; case 1: mnemonic = "ENTERX"; break; case 2: mnemonic = "CLREX"; break; case 4: mnemonic = "DSB"; break; case 5: mnemonic = "DMB"; break; case 6: mnemonic = "ISB"; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } strcpy(cp, mnemonic); return ERROR_OK; } static int t2ev_b_misc(uint32_t opcode, uint32_t address, struct arm_instruction *instruction, char *cp) { /* permanently undefined */ if ((opcode & 0x07f07000) == 0x07f02000) { instruction->type = ARM_UNDEFINED_INSTRUCTION; strcpy(cp, "UNDEFINED"); return ERROR_OK; } switch ((opcode >> 12) & 0x5) { case 0x1: case 0x5: return t2ev_b_bl(opcode, address, instruction, cp); case 0x4: goto undef; case 0: if (((opcode >> 23) & 0x07) != 0x07) return t2ev_cond_b(opcode, address, instruction, cp); if (opcode & (1 << 26)) goto undef; break; } switch ((opcode >> 20) & 0x7f) { case 0x38: case 0x39: sprintf(cp, "MSR\t%s, r%d", special_name(opcode & 0xff), (int) (opcode >> 16) & 0x0f); return ERROR_OK; case 0x3a: return t2ev_hint(opcode, address, instruction, cp); case 0x3b: return t2ev_misc(opcode, address, instruction, cp); case 0x3c: sprintf(cp, "BXJ\tr%d", (int) (opcode >> 16) & 0x0f); return ERROR_OK; case 0x3e: case 0x3f: sprintf(cp, "MRS\tr%d, %s", (int) (opcode >> 8) & 0x0f, special_name(opcode & 0xff)); return ERROR_OK; } undef: return ERROR_COMMAND_SYNTAX_ERROR; } static int t2ev_data_mod_immed(uint32_t opcode, uint32_t address, struct arm_instruction *instruction, char *cp) { char *mnemonic = NULL; int rn = (opcode >> 16) & 0xf; int rd = (opcode >> 8) & 0xf; unsigned immed = opcode & 0xff; unsigned func; bool one = false; char *suffix = ""; char *suffix2 = ""; /* ARMv7-M: A5.3.2 Modified immediate constants */ func = (opcode >> 11) & 0x0e; if (immed & 0x80) func |= 1; if (opcode & (1 << 26)) func |= 0x10; /* "Modified" immediates */ switch (func >> 1) { case 0: break; case 2: immed <<= 8; /* FALLTHROUGH */ case 1: immed += immed << 16; break; case 3: immed += immed << 8; immed += immed << 16; break; default: immed |= 0x80; immed = ror(immed, func); } if (opcode & (1 << 20)) suffix = "S"; switch ((opcode >> 21) & 0xf) { case 0: if (rd == 0xf) { instruction->type = ARM_TST; mnemonic = "TST"; one = true; suffix = ""; rd = rn; } else { instruction->type = ARM_AND; mnemonic = "AND"; } break; case 1: instruction->type = ARM_BIC; mnemonic = "BIC"; break; case 2: if (rn == 0xf) { instruction->type = ARM_MOV; mnemonic = "MOV"; one = true; suffix2 = ".W"; } else { instruction->type = ARM_ORR; mnemonic = "ORR"; } break; case 3: if (rn == 0xf) { instruction->type = ARM_MVN; mnemonic = "MVN"; one = true; } else { /* instruction->type = ARM_ORN; */ mnemonic = "ORN"; } break; case 4: if (rd == 0xf) { instruction->type = ARM_TEQ; mnemonic = "TEQ"; one = true; suffix = ""; rd = rn; } else { instruction->type = ARM_EOR; mnemonic = "EOR"; } break; case 8: if (rd == 0xf) { instruction->type = ARM_CMN; mnemonic = "CMN"; one = true; suffix = ""; rd = rn; } else { instruction->type = ARM_ADD; mnemonic = "ADD"; suffix2 = ".W"; } break; case 10: instruction->type = ARM_ADC; mnemonic = "ADC"; suffix2 = ".W"; break; case 11: instruction->type = ARM_SBC; mnemonic = "SBC"; break; case 13: if (rd == 0xf) { instruction->type = ARM_CMP; mnemonic = "CMP"; one = true; suffix = ""; rd = rn; } else { instruction->type = ARM_SUB; mnemonic = "SUB"; } suffix2 = ".W"; break; case 14: instruction->type = ARM_RSB; mnemonic = "RSB"; suffix2 = ".W"; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } if (one) sprintf(cp, "%s%s\tr%d, #%d\t; %#8.8x", mnemonic, suffix2, rd, immed, immed); else sprintf(cp, "%s%s%s\tr%d, r%d, #%d\t; %#8.8x", mnemonic, suffix, suffix2, rd, rn, immed, immed); return ERROR_OK; } static int t2ev_data_immed(uint32_t opcode, uint32_t address, struct arm_instruction *instruction, char *cp) { char *mnemonic = NULL; int rn = (opcode >> 16) & 0xf; int rd = (opcode >> 8) & 0xf; unsigned immed; bool add = false; bool is_signed = false; immed = (opcode & 0x0ff) | ((opcode & 0x7000) >> 4); if (opcode & (1 << 26)) immed |= (1 << 11); switch ((opcode >> 20) & 0x1f) { case 0: if (rn == 0xf) { add = true; goto do_adr; } mnemonic = "ADDW"; break; case 4: immed |= (opcode >> 4) & 0xf000; sprintf(cp, "MOVW\tr%d, #%d\t; %#3.3x", rd, immed, immed); return ERROR_OK; case 0x0a: if (rn == 0xf) goto do_adr; mnemonic = "SUBW"; break; case 0x0c: /* move constant to top 16 bits of register */ immed |= (opcode >> 4) & 0xf000; sprintf(cp, "MOVT\tr%d, #%d\t; %#4.4x", rd, immed, immed); return ERROR_OK; case 0x10: case 0x12: is_signed = true; case 0x18: case 0x1a: /* signed/unsigned saturated add */ immed = (opcode >> 6) & 0x03; immed |= (opcode >> 10) & 0x1c; sprintf(cp, "%sSAT\tr%d, #%d, r%d, %s #%d\t", is_signed ? "S" : "U", rd, (int) (opcode & 0x1f) + is_signed, rn, (opcode & (1 << 21)) ? "ASR" : "LSL", immed ? immed : 32); return ERROR_OK; case 0x14: is_signed = true; /* FALLTHROUGH */ case 0x1c: /* signed/unsigned bitfield extract */ immed = (opcode >> 6) & 0x03; immed |= (opcode >> 10) & 0x1c; sprintf(cp, "%sBFX\tr%d, r%d, #%d, #%d\t", is_signed ? "S" : "U", rd, rn, immed, (int) (opcode & 0x1f) + 1); return ERROR_OK; case 0x16: immed = (opcode >> 6) & 0x03; immed |= (opcode >> 10) & 0x1c; if (rn == 0xf) /* bitfield clear */ sprintf(cp, "BFC\tr%d, #%d, #%d\t", rd, immed, (int) (opcode & 0x1f) + 1 - immed); else /* bitfield insert */ sprintf(cp, "BFI\tr%d, r%d, #%d, #%d\t", rd, rn, immed, (int) (opcode & 0x1f) + 1 - immed); return ERROR_OK; default: return ERROR_COMMAND_SYNTAX_ERROR; } sprintf(cp, "%s\tr%d, r%d, #%d\t; %#3.3x", mnemonic, rd, rn, immed, immed); return ERROR_OK; do_adr: address = thumb_alignpc4(address); if (add) address += immed; else address -= immed; /* REVISIT "ADD/SUB Rd, PC, #const ; 0x..." might be better; * not hiding the pc-relative stuff will sometimes be useful. */ sprintf(cp, "ADR.W\tr%d, %#8.8" PRIx32, rd, address); return ERROR_OK; } static int t2ev_store_single(uint32_t opcode, uint32_t address, struct arm_instruction *instruction, char *cp) { unsigned op = (opcode >> 20) & 0xf; char *size = ""; char *suffix = ""; char *p1 = ""; char *p2 = "]"; unsigned immed; unsigned rn = (opcode >> 16) & 0x0f; unsigned rt = (opcode >> 12) & 0x0f; if (rn == 0xf) return ERROR_COMMAND_SYNTAX_ERROR; if (opcode & 0x0800) op |= 1; switch (op) { /* byte */ case 0x8: case 0x9: size = "B"; goto imm12; case 0x1: size = "B"; goto imm8; case 0x0: size = "B"; break; /* halfword */ case 0xa: case 0xb: size = "H"; goto imm12; case 0x3: size = "H"; goto imm8; case 0x2: size = "H"; break; /* word */ case 0xc: case 0xd: goto imm12; case 0x5: goto imm8; case 0x4: break; /* error */ default: return ERROR_COMMAND_SYNTAX_ERROR; } sprintf(cp, "STR%s.W\tr%d, [r%d, r%d, LSL #%d]", size, rt, rn, (int) opcode & 0x0f, (int) (opcode >> 4) & 0x03); return ERROR_OK; imm12: immed = opcode & 0x0fff; sprintf(cp, "STR%s.W\tr%d, [r%d, #%u]\t; %#3.3x", size, rt, rn, immed, immed); return ERROR_OK; imm8: immed = opcode & 0x00ff; switch (opcode & 0x700) { case 0x600: suffix = "T"; break; case 0x000: case 0x200: return ERROR_COMMAND_SYNTAX_ERROR; } /* two indexed modes will write back rn */ if (opcode & 0x100) { if (opcode & 0x400) /* pre-indexed */ p2 = "]!"; else { /* post-indexed */ p1 = "]"; p2 = ""; } } sprintf(cp, "STR%s%s\tr%d, [r%d%s, #%s%u%s\t; %#2.2x", size, suffix, rt, rn, p1, (opcode & 0x200) ? "" : "-", immed, p2, immed); return ERROR_OK; } static int t2ev_mul32(uint32_t opcode, uint32_t address, struct arm_instruction *instruction, char *cp) { int ra = (opcode >> 12) & 0xf; switch (opcode & 0x007000f0) { case 0: if (ra == 0xf) sprintf(cp, "MUL\tr%d, r%d, r%d", (int) (opcode >> 8) & 0xf, (int) (opcode >> 16) & 0xf, (int) (opcode >> 0) & 0xf); else sprintf(cp, "MLA\tr%d, r%d, r%d, r%d", (int) (opcode >> 8) & 0xf, (int) (opcode >> 16) & 0xf, (int) (opcode >> 0) & 0xf, ra); break; case 0x10: sprintf(cp, "MLS\tr%d, r%d, r%d, r%d", (int) (opcode >> 8) & 0xf, (int) (opcode >> 16) & 0xf, (int) (opcode >> 0) & 0xf, ra); break; default: return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; } static int t2ev_mul64_div(uint32_t opcode, uint32_t address, struct arm_instruction *instruction, char *cp) { int op = (opcode >> 4) & 0xf; char *infix = "MUL"; op += (opcode >> 16) & 0x70; switch (op) { case 0x40: case 0x60: infix = "MLA"; /* FALLTHROUGH */ case 0: case 0x20: sprintf(cp, "%c%sL\tr%d, r%d, r%d, r%d", (op & 0x20) ? 'U' : 'S', infix, (int) (opcode >> 12) & 0xf, (int) (opcode >> 8) & 0xf, (int) (opcode >> 16) & 0xf, (int) (opcode >> 0) & 0xf); break; case 0x1f: case 0x3f: sprintf(cp, "%cDIV\tr%d, r%d, r%d", (op & 0x20) ? 'U' : 'S', (int) (opcode >> 8) & 0xf, (int) (opcode >> 16) & 0xf, (int) (opcode >> 0) & 0xf); break; default: return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; } static int t2ev_ldm_stm(uint32_t opcode, uint32_t address, struct arm_instruction *instruction, char *cp) { int rn = (opcode >> 16) & 0xf; int op = (opcode >> 22) & 0x6; int t = (opcode >> 21) & 1; unsigned registers = opcode & 0xffff; char *mode = ""; if (opcode & (1 << 20)) op |= 1; switch (op) { case 0: mode = "DB"; /* FALL THROUGH */ case 6: sprintf(cp, "SRS%s\tsp%s, #%d", mode, t ? "!" : "", (unsigned) (opcode & 0x1f)); return ERROR_OK; case 1: mode = "DB"; /* FALL THROUGH */ case 7: sprintf(cp, "RFE%s\tr%d%s", mode, (unsigned) ((opcode >> 16) & 0xf), t ? "!" : ""); return ERROR_OK; case 2: sprintf(cp, "STM.W\tr%d%s, ", rn, t ? "!" : ""); break; case 3: if (rn == 13 && t) sprintf(cp, "POP.W\t"); else sprintf(cp, "LDM.W\tr%d%s, ", rn, t ? "!" : ""); break; case 4: if (rn == 13 && t) sprintf(cp, "PUSH.W\t"); else sprintf(cp, "STMDB\tr%d%s, ", rn, t ? "!" : ""); break; case 5: sprintf(cp, "LDMDB.W\tr%d%s, ", rn, t ? "!" : ""); break; default: return ERROR_COMMAND_SYNTAX_ERROR; } cp = strchr(cp, 0); *cp++ = '{'; for (t = 0; registers; t++, registers >>= 1) { if ((registers & 1) == 0) continue; registers &= ~1; sprintf(cp, "r%d%s", t, registers ? ", " : ""); cp = strchr(cp, 0); } *cp++ = '}'; *cp++ = 0; return ERROR_OK; } /* load/store dual or exclusive, table branch */ static int t2ev_ldrex_strex(uint32_t opcode, uint32_t address, struct arm_instruction *instruction, char *cp) { unsigned op1op2 = (opcode >> 20) & 0x3; unsigned op3 = (opcode >> 4) & 0xf; char *mnemonic; unsigned rn = (opcode >> 16) & 0xf; unsigned rt = (opcode >> 12) & 0xf; unsigned rd = (opcode >> 8) & 0xf; unsigned imm = opcode & 0xff; char *p1 = ""; char *p2 = "]"; op1op2 |= (opcode >> 21) & 0xc; switch (op1op2) { case 0: mnemonic = "STREX"; goto strex; case 1: mnemonic = "LDREX"; goto ldrex; case 2: case 6: case 8: case 10: case 12: case 14: mnemonic = "STRD"; goto immediate; case 3: case 7: case 9: case 11: case 13: case 15: mnemonic = "LDRD"; if (rn == 15) goto literal; else goto immediate; case 4: switch (op3) { case 4: mnemonic = "STREXB"; break; case 5: mnemonic = "STREXH"; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } rd = opcode & 0xf; imm = 0; goto strex; case 5: switch (op3) { case 0: sprintf(cp, "TBB\t[r%u, r%u]", rn, imm & 0xf); return ERROR_OK; case 1: sprintf(cp, "TBH\t[r%u, r%u, LSL #1]", rn, imm & 0xf); return ERROR_OK; case 4: mnemonic = "LDREXB"; break; case 5: mnemonic = "LDREXH"; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } imm = 0; goto ldrex; } return ERROR_COMMAND_SYNTAX_ERROR; strex: imm <<= 2; if (imm) sprintf(cp, "%s\tr%u, r%u, [r%u, #%u]\t; %#2.2x", mnemonic, rd, rt, rn, imm, imm); else sprintf(cp, "%s\tr%u, r%u, [r%u]", mnemonic, rd, rt, rn); return ERROR_OK; ldrex: imm <<= 2; if (imm) sprintf(cp, "%s\tr%u, [r%u, #%u]\t; %#2.2x", mnemonic, rt, rn, imm, imm); else sprintf(cp, "%s\tr%u, [r%u]", mnemonic, rt, rn); return ERROR_OK; immediate: /* two indexed modes will write back rn */ if (opcode & (1 << 21)) { if (opcode & (1 << 24)) /* pre-indexed */ p2 = "]!"; else { /* post-indexed */ p1 = "]"; p2 = ""; } } imm <<= 2; sprintf(cp, "%s\tr%u, r%u, [r%u%s, #%s%u%s\t; %#2.2x", mnemonic, rt, rd, rn, p1, (opcode & (1 << 23)) ? "" : "-", imm, p2, imm); return ERROR_OK; literal: address = thumb_alignpc4(address); imm <<= 2; if (opcode & (1 << 23)) address += imm; else address -= imm; sprintf(cp, "%s\tr%u, r%u, %#8.8" PRIx32, mnemonic, rt, rd, address); return ERROR_OK; } static int t2ev_data_shift(uint32_t opcode, uint32_t address, struct arm_instruction *instruction, char *cp) { int op = (opcode >> 21) & 0xf; int rd = (opcode >> 8) & 0xf; int rn = (opcode >> 16) & 0xf; int type = (opcode >> 4) & 0x3; int immed = (opcode >> 6) & 0x3; char *mnemonic; char *suffix = ""; immed |= (opcode >> 10) & 0x1c; if (opcode & (1 << 20)) suffix = "S"; switch (op) { case 0: if (rd == 0xf) { if (!(opcode & (1 << 20))) return ERROR_COMMAND_SYNTAX_ERROR; instruction->type = ARM_TST; mnemonic = "TST"; suffix = ""; goto two; } instruction->type = ARM_AND; mnemonic = "AND"; break; case 1: instruction->type = ARM_BIC; mnemonic = "BIC"; break; case 2: if (rn == 0xf) { instruction->type = ARM_MOV; switch (type) { case 0: if (immed == 0) { sprintf(cp, "MOV%s.W\tr%d, r%d", suffix, rd, (int) (opcode & 0xf)); return ERROR_OK; } mnemonic = "LSL"; break; case 1: mnemonic = "LSR"; break; case 2: mnemonic = "ASR"; break; default: if (immed == 0) { sprintf(cp, "RRX%s\tr%d, r%d", suffix, rd, (int) (opcode & 0xf)); return ERROR_OK; } mnemonic = "ROR"; break; } goto immediate; } else { instruction->type = ARM_ORR; mnemonic = "ORR"; } break; case 3: if (rn == 0xf) { instruction->type = ARM_MVN; mnemonic = "MVN"; rn = rd; goto two; } else { /* instruction->type = ARM_ORN; */ mnemonic = "ORN"; } break; case 4: if (rd == 0xf) { if (!(opcode & (1 << 20))) return ERROR_COMMAND_SYNTAX_ERROR; instruction->type = ARM_TEQ; mnemonic = "TEQ"; suffix = ""; goto two; } instruction->type = ARM_EOR; mnemonic = "EOR"; break; case 8: if (rd == 0xf) { if (!(opcode & (1 << 20))) return ERROR_COMMAND_SYNTAX_ERROR; instruction->type = ARM_CMN; mnemonic = "CMN"; suffix = ""; goto two; } instruction->type = ARM_ADD; mnemonic = "ADD"; break; case 0xa: instruction->type = ARM_ADC; mnemonic = "ADC"; break; case 0xb: instruction->type = ARM_SBC; mnemonic = "SBC"; break; case 0xd: if (rd == 0xf) { if (!(opcode & (1 << 21))) return ERROR_COMMAND_SYNTAX_ERROR; instruction->type = ARM_CMP; mnemonic = "CMP"; suffix = ""; goto two; } instruction->type = ARM_SUB; mnemonic = "SUB"; break; case 0xe: instruction->type = ARM_RSB; mnemonic = "RSB"; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } sprintf(cp, "%s%s.W\tr%d, r%d, r%d", mnemonic, suffix, rd, rn, (int) (opcode & 0xf)); shift: cp = strchr(cp, 0); switch (type) { case 0: if (immed == 0) return ERROR_OK; suffix = "LSL"; break; case 1: suffix = "LSR"; if (immed == 32) immed = 0; break; case 2: suffix = "ASR"; if (immed == 32) immed = 0; break; case 3: if (immed == 0) { strcpy(cp, ", RRX"); return ERROR_OK; } suffix = "ROR"; break; } sprintf(cp, ", %s #%d", suffix, immed ? immed : 32); return ERROR_OK; two: sprintf(cp, "%s%s.W\tr%d, r%d", mnemonic, suffix, rn, (int) (opcode & 0xf)); goto shift; immediate: sprintf(cp, "%s%s.W\tr%d, r%d, #%d", mnemonic, suffix, rd, (int) (opcode & 0xf), immed ? immed : 32); return ERROR_OK; } static int t2ev_data_reg(uint32_t opcode, uint32_t address, struct arm_instruction *instruction, char *cp) { char *mnemonic; char *suffix = ""; if (((opcode >> 4) & 0xf) == 0) { switch ((opcode >> 21) & 0x7) { case 0: mnemonic = "LSL"; break; case 1: mnemonic = "LSR"; break; case 2: mnemonic = "ASR"; break; case 3: mnemonic = "ROR"; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } instruction->type = ARM_MOV; if (opcode & (1 << 20)) suffix = "S"; sprintf(cp, "%s%s.W\tr%d, r%d, r%d", mnemonic, suffix, (int) (opcode >> 8) & 0xf, (int) (opcode >> 16) & 0xf, (int) (opcode >> 0) & 0xf); } else if (opcode & (1 << 7)) { switch ((opcode >> 20) & 0xf) { case 0: case 1: case 4: case 5: switch ((opcode >> 4) & 0x3) { case 1: suffix = ", ROR #8"; break; case 2: suffix = ", ROR #16"; break; case 3: suffix = ", ROR #24"; break; } sprintf(cp, "%cXT%c.W\tr%d, r%d%s", (opcode & (1 << 24)) ? 'U' : 'S', (opcode & (1 << 26)) ? 'B' : 'H', (int) (opcode >> 8) & 0xf, (int) (opcode >> 0) & 0xf, suffix); break; case 8: case 9: case 0xa: case 0xb: if (opcode & (1 << 6)) return ERROR_COMMAND_SYNTAX_ERROR; if (((opcode >> 12) & 0xf) != 0xf) return ERROR_COMMAND_SYNTAX_ERROR; if (!(opcode & (1 << 20))) return ERROR_COMMAND_SYNTAX_ERROR; switch (((opcode >> 19) & 0x04) | ((opcode >> 4) & 0x3)) { case 0: mnemonic = "REV.W"; break; case 1: mnemonic = "REV16.W"; break; case 2: mnemonic = "RBIT"; break; case 3: mnemonic = "REVSH.W"; break; case 4: mnemonic = "CLZ"; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } sprintf(cp, "%s\tr%d, r%d", mnemonic, (int) (opcode >> 8) & 0xf, (int) (opcode >> 0) & 0xf); break; default: return ERROR_COMMAND_SYNTAX_ERROR; } } return ERROR_OK; } static int t2ev_load_word(uint32_t opcode, uint32_t address, struct arm_instruction *instruction, char *cp) { int rn = (opcode >> 16) & 0xf; int immed; instruction->type = ARM_LDR; if (rn == 0xf) { immed = opcode & 0x0fff; if ((opcode & (1 << 23)) == 0) immed = -immed; sprintf(cp, "LDR\tr%d, %#8.8" PRIx32, (int) (opcode >> 12) & 0xf, thumb_alignpc4(address) + immed); return ERROR_OK; } if (opcode & (1 << 23)) { immed = opcode & 0x0fff; sprintf(cp, "LDR.W\tr%d, [r%d, #%d]\t; %#3.3x", (int) (opcode >> 12) & 0xf, rn, immed, immed); return ERROR_OK; } if (!(opcode & (0x3f << 6))) { sprintf(cp, "LDR.W\tr%d, [r%d, r%d, LSL #%d]", (int) (opcode >> 12) & 0xf, rn, (int) (opcode >> 0) & 0xf, (int) (opcode >> 4) & 0x3); return ERROR_OK; } if (((opcode >> 8) & 0xf) == 0xe) { immed = opcode & 0x00ff; sprintf(cp, "LDRT\tr%d, [r%d, #%d]\t; %#2.2x", (int) (opcode >> 12) & 0xf, rn, immed, immed); return ERROR_OK; } if (((opcode >> 8) & 0xf) == 0xc || (opcode & 0x0900) == 0x0900) { char *p1 = "]", *p2 = ""; if (!(opcode & 0x0500)) return ERROR_COMMAND_SYNTAX_ERROR; immed = opcode & 0x00ff; /* two indexed modes will write back rn */ if (opcode & 0x100) { if (opcode & 0x400) /* pre-indexed */ p2 = "]!"; else { /* post-indexed */ p1 = "]"; p2 = ""; } } sprintf(cp, "LDR\tr%d, [r%d%s, #%s%u%s\t; %#2.2x", (int) (opcode >> 12) & 0xf, rn, p1, (opcode & 0x200) ? "" : "-", immed, p2, immed); return ERROR_OK; } return ERROR_COMMAND_SYNTAX_ERROR; } static int t2ev_load_byte_hints(uint32_t opcode, uint32_t address, struct arm_instruction *instruction, char *cp) { int rn = (opcode >> 16) & 0xf; int rt = (opcode >> 12) & 0xf; int op2 = (opcode >> 6) & 0x3f; unsigned immed; char *p1 = "", *p2 = "]"; char *mnemonic; switch ((opcode >> 23) & 0x3) { case 0: if ((rn & rt) == 0xf) { pld_literal: immed = opcode & 0xfff; address = thumb_alignpc4(address); if (opcode & (1 << 23)) address += immed; else address -= immed; sprintf(cp, "PLD\tr%d, %#8.8" PRIx32, rt, address); return ERROR_OK; } if (rn == 0x0f && rt != 0x0f) { ldrb_literal: immed = opcode & 0xfff; address = thumb_alignpc4(address); if (opcode & (1 << 23)) address += immed; else address -= immed; sprintf(cp, "LDRB\tr%d, %#8.8" PRIx32, rt, address); return ERROR_OK; } if (rn == 0x0f) break; if ((op2 & 0x3c) == 0x38) { immed = opcode & 0xff; sprintf(cp, "LDRBT\tr%d, [r%d, #%d]\t; %#2.2x", rt, rn, immed, immed); return ERROR_OK; } if ((op2 & 0x3c) == 0x30) { if (rt == 0x0f) { immed = opcode & 0xff; immed = -immed; preload_immediate: p1 = (opcode & (1 << 21)) ? "W" : ""; sprintf(cp, "PLD%s\t[r%d, #%d]\t; %#6.6x", p1, rn, immed, immed); return ERROR_OK; } mnemonic = "LDRB"; ldrxb_immediate_t3: immed = opcode & 0xff; if (!(opcode & 0x200)) immed = -immed; /* two indexed modes will write back rn */ if (opcode & 0x100) { if (opcode & 0x400) /* pre-indexed */ p2 = "]!"; else { /* post-indexed */ p1 = "]"; p2 = ""; } } ldrxb_immediate_t2: sprintf(cp, "%s\tr%d, [r%d%s, #%d%s\t; %#8.8x", mnemonic, rt, rn, p1, immed, p2, immed); return ERROR_OK; } if ((op2 & 0x24) == 0x24) { mnemonic = "LDRB"; goto ldrxb_immediate_t3; } if (op2 == 0) { int rm = opcode & 0xf; if (rt == 0x0f) sprintf(cp, "PLD\t"); else sprintf(cp, "LDRB.W\tr%d, ", rt); immed = (opcode >> 4) & 0x3; cp = strchr(cp, 0); sprintf(cp, "[r%d, r%d, LSL #%d]", rn, rm, immed); return ERROR_OK; } break; case 1: if ((rn & rt) == 0xf) goto pld_literal; if (rt == 0xf) { immed = opcode & 0xfff; goto preload_immediate; } if (rn == 0x0f) goto ldrb_literal; mnemonic = "LDRB.W"; immed = opcode & 0xfff; goto ldrxb_immediate_t2; case 2: if ((rn & rt) == 0xf) { immed = opcode & 0xfff; address = thumb_alignpc4(address); if (opcode & (1 << 23)) address += immed; else address -= immed; sprintf(cp, "PLI\t%#8.8" PRIx32, address); return ERROR_OK; } if (rn == 0xf && rt != 0xf) { ldrsb_literal: immed = opcode & 0xfff; address = thumb_alignpc4(address); if (opcode & (1 << 23)) address += immed; else address -= immed; sprintf(cp, "LDRSB\t%#8.8" PRIx32, address); return ERROR_OK; } if (rn == 0xf) break; if ((op2 & 0x3c) == 0x38) { immed = opcode & 0xff; sprintf(cp, "LDRSBT\tr%d, [r%d, #%d]\t; %#2.2x", rt, rn, immed, immed); return ERROR_OK; } if ((op2 & 0x3c) == 0x30) { if (rt == 0xf) { immed = opcode & 0xff; immed = -immed; /* pli */ sprintf(cp, "PLI\t[r%d, #%d]\t; -%#2.2x", rn, immed, -immed); return ERROR_OK; } mnemonic = "LDRSB"; goto ldrxb_immediate_t3; } if ((op2 & 0x24) == 0x24) { mnemonic = "LDRSB"; goto ldrxb_immediate_t3; } if (op2 == 0) { int rm = opcode & 0xf; if (rt == 0x0f) sprintf(cp, "PLI\t"); else sprintf(cp, "LDRSB.W\tr%d, ", rt); immed = (opcode >> 4) & 0x3; cp = strchr(cp, 0); sprintf(cp, "[r%d, r%d, LSL #%d]", rn, rm, immed); return ERROR_OK; } break; case 3: if (rt == 0xf) { immed = opcode & 0xfff; sprintf(cp, "PLI\t[r%d, #%d]\t; %#3.3x", rn, immed, immed); return ERROR_OK; } if (rn == 0xf) goto ldrsb_literal; immed = opcode & 0xfff; mnemonic = "LDRSB"; goto ldrxb_immediate_t2; } return ERROR_COMMAND_SYNTAX_ERROR; } static int t2ev_load_halfword(uint32_t opcode, uint32_t address, struct arm_instruction *instruction, char *cp) { int rn = (opcode >> 16) & 0xf; int rt = (opcode >> 12) & 0xf; int op2 = (opcode >> 6) & 0x3f; char *sign = ""; unsigned immed; if (rt == 0xf) { sprintf(cp, "HINT (UNALLOCATED)"); return ERROR_OK; } if (opcode & (1 << 24)) sign = "S"; if ((opcode & (1 << 23)) == 0) { if (rn == 0xf) { ldrh_literal: immed = opcode & 0xfff; address = thumb_alignpc4(address); if (opcode & (1 << 23)) address += immed; else address -= immed; sprintf(cp, "LDR%sH\tr%d, %#8.8" PRIx32, sign, rt, address); return ERROR_OK; } if (op2 == 0) { int rm = opcode & 0xf; immed = (opcode >> 4) & 0x3; sprintf(cp, "LDR%sH.W\tr%d, [r%d, r%d, LSL #%d]", sign, rt, rn, rm, immed); return ERROR_OK; } if ((op2 & 0x3c) == 0x38) { immed = opcode & 0xff; sprintf(cp, "LDR%sHT\tr%d, [r%d, #%d]\t; %#2.2x", sign, rt, rn, immed, immed); return ERROR_OK; } if ((op2 & 0x3c) == 0x30 || (op2 & 0x24) == 0x24) { char *p1 = "", *p2 = "]"; immed = opcode & 0xff; if (!(opcode & 0x200)) immed = -immed; /* two indexed modes will write back rn */ if (opcode & 0x100) { if (opcode & 0x400) /* pre-indexed */ p2 = "]!"; else { /* post-indexed */ p1 = "]"; p2 = ""; } } sprintf(cp, "LDR%sH\tr%d, [r%d%s, #%d%s\t; %#8.8x", sign, rt, rn, p1, immed, p2, immed); return ERROR_OK; } } else { if (rn == 0xf) goto ldrh_literal; immed = opcode & 0xfff; sprintf(cp, "LDR%sH%s\tr%d, [r%d, #%d]\t; %#6.6x", sign, *sign ? "" : ".W", rt, rn, immed, immed); return ERROR_OK; } return ERROR_COMMAND_SYNTAX_ERROR; } /* * REVISIT for Thumb2 instructions, instruction->type and friends aren't * always set. That means eventual arm_simulate_step() support for Thumb2 * will need work in this area. */ int thumb2_opcode(struct target *target, uint32_t address, struct arm_instruction *instruction) { int retval; uint16_t op; uint32_t opcode; char *cp; /* clear low bit ... it's set on function pointers */ address &= ~1; /* clear fields, to avoid confusion */ memset(instruction, 0, sizeof(struct arm_instruction)); /* read first halfword, see if this is the only one */ retval = target_read_u16(target, address, &op); if (retval != ERROR_OK) return retval; switch (op & 0xf800) { case 0xf800: case 0xf000: case 0xe800: /* 32-bit instructions */ instruction->instruction_size = 4; opcode = op << 16; retval = target_read_u16(target, address + 2, &op); if (retval != ERROR_OK) return retval; opcode |= op; instruction->opcode = opcode; break; default: /* 16-bit: Thumb1 + IT + CBZ/CBNZ + ... */ return thumb_evaluate_opcode(op, address, instruction); } snprintf(instruction->text, 128, "0x%8.8" PRIx32 " 0x%8.8" PRIx32 "\t", address, opcode); cp = strchr(instruction->text, 0); retval = ERROR_FAIL; /* ARMv7-M: A5.3.1 Data processing (modified immediate) */ if ((opcode & 0x1a008000) == 0x10000000) retval = t2ev_data_mod_immed(opcode, address, instruction, cp); /* ARMv7-M: A5.3.3 Data processing (plain binary immediate) */ else if ((opcode & 0x1a008000) == 0x12000000) retval = t2ev_data_immed(opcode, address, instruction, cp); /* ARMv7-M: A5.3.4 Branches and miscellaneous control */ else if ((opcode & 0x18008000) == 0x10008000) retval = t2ev_b_misc(opcode, address, instruction, cp); /* ARMv7-M: A5.3.5 Load/store multiple */ else if ((opcode & 0x1e400000) == 0x08000000) retval = t2ev_ldm_stm(opcode, address, instruction, cp); /* ARMv7-M: A5.3.6 Load/store dual or exclusive, table branch */ else if ((opcode & 0x1e400000) == 0x08400000) retval = t2ev_ldrex_strex(opcode, address, instruction, cp); /* ARMv7-M: A5.3.7 Load word */ else if ((opcode & 0x1f700000) == 0x18500000) retval = t2ev_load_word(opcode, address, instruction, cp); /* ARMv7-M: A5.3.8 Load halfword, unallocated memory hints */ else if ((opcode & 0x1e700000) == 0x18300000) retval = t2ev_load_halfword(opcode, address, instruction, cp); /* ARMv7-M: A5.3.9 Load byte, memory hints */ else if ((opcode & 0x1e700000) == 0x18100000) retval = t2ev_load_byte_hints(opcode, address, instruction, cp); /* ARMv7-M: A5.3.10 Store single data item */ else if ((opcode & 0x1f100000) == 0x18000000) retval = t2ev_store_single(opcode, address, instruction, cp); /* ARMv7-M: A5.3.11 Data processing (shifted register) */ else if ((opcode & 0x1e000000) == 0x0a000000) retval = t2ev_data_shift(opcode, address, instruction, cp); /* ARMv7-M: A5.3.12 Data processing (register) * and A5.3.13 Miscellaneous operations */ else if ((opcode & 0x1f000000) == 0x1a000000) retval = t2ev_data_reg(opcode, address, instruction, cp); /* ARMv7-M: A5.3.14 Multiply, and multiply accumulate */ else if ((opcode & 0x1f800000) == 0x1b000000) retval = t2ev_mul32(opcode, address, instruction, cp); /* ARMv7-M: A5.3.15 Long multiply, long multiply accumulate, divide */ else if ((opcode & 0x1f800000) == 0x1b800000) retval = t2ev_mul64_div(opcode, address, instruction, cp); if (retval == ERROR_OK) return retval; /* * Thumb2 also supports coprocessor, ThumbEE, and DSP/Media (SIMD) * instructions; not yet handled here. */ if (retval == ERROR_COMMAND_SYNTAX_ERROR) { instruction->type = ARM_UNDEFINED_INSTRUCTION; strcpy(cp, "UNDEFINED OPCODE"); return ERROR_OK; } LOG_DEBUG("Can't decode 32-bit Thumb2 yet (opcode=%08" PRIx32 ")", opcode); strcpy(cp, "(32-bit Thumb2 ...)"); return ERROR_OK; } int arm_access_size(struct arm_instruction *instruction) { if ((instruction->type == ARM_LDRB) || (instruction->type == ARM_LDRBT) || (instruction->type == ARM_LDRSB) || (instruction->type == ARM_STRB) || (instruction->type == ARM_STRBT)) return 1; else if ((instruction->type == ARM_LDRH) || (instruction->type == ARM_LDRSH) || (instruction->type == ARM_STRH)) return 2; else if ((instruction->type == ARM_LDR) || (instruction->type == ARM_LDRT) || (instruction->type == ARM_STR) || (instruction->type == ARM_STRT)) return 4; else if ((instruction->type == ARM_LDRD) || (instruction->type == ARM_STRD)) return 8; else { LOG_ERROR("BUG: instruction type %i isn't a load/store instruction", instruction->type); return 0; } } openocd-0.7.0/src/transport/0000755000175000001440000000000012141414412012757 500000000000000openocd-0.7.0/src/transport/transport.h0000644000175000001440000000531512134336410015113 00000000000000/* * Copyright (c) 2010 by David Brownell * Copyright (C) 2011 Tomasz Boleslaw CEDRO (http://www.tomek.cedro.info) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 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 */ #ifndef TRANSPORT_H #define TRANSPORT_H #include "helper/command.h" /** * Wrapper for transport lifecycle operations. * * OpenOCD talks to targets through some kind of debugging * or programming adapter, using some protocol that probably * has target-specific aspects. * * A "transport" reflects electrical protocol to the target, * e..g jtag, swd, spi, uart, ... NOT the messaging protocols * layered over it (e.g. JTAG has eICE, CoreSight, Nexus, OnCE, * and more). * * In addition to the lifecycle operations packaged by this * structure, a transport also involves an interface supported * by debug adapters and used by components such as debug targets. * For non-debug transports, there may be interfaces used to * write to flash chips. */ struct transport { /** * Each transport has a unique name, used to select it * from among the alternatives. Examples might include * "jtag", * "swd", "AVR_ISP" and more. */ const char *name; /** * When a transport is selected, this method registers * its commands and activates the transport (e.g. resets * the link). * * After those commands are registered, they will often * be used for further configuration of the debug link. */ int (*select)(struct command_context *ctx); /** * server startup uses this method to validate transport * configuration. (For example, with JTAG this interrogates * the scan chain against the list of expected TAPs.) */ int (*init)(struct command_context *ctx); /** * Transports are stored in a singly linked list. */ struct transport *next; }; int transport_register(struct transport *new_transport); struct transport *get_current_transport(void); int transport_register_commands(struct command_context *ctx); COMMAND_HELPER(transport_list_parse, char ***vector); int allow_transports(struct command_context *ctx, const char **vector); bool transports_are_declared(void); #endif openocd-0.7.0/src/transport/transport.c0000644000175000001440000002345312134336410015111 00000000000000/* * Copyright (c) 2010 by David Brownell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 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 */ #ifdef HAVE_CONFIG_H #include "config.h" #endif /** @file * Infrastructure for specifying and managing the transport protocol * used in a given debug or programming session. * * Examples of "debug-capable" transports are JTAG or SWD. * Additionally, JTAG supports boundary scan testing. * * Examples of "programming-capable" transports include SPI or UART; * those are used (often mediated by a ROM bootloader) for ISP style * programming, to perform an initial load of code into flash, or * sometimes into SRAM. Target code could use "variant" options to * decide how to use such protocols. For example, Cortex-M3 cores * from TI/Luminary and from NXP use different protocols for for * UART or SPI based firmware loading. * * As a rule, there are protocols layered on top of the transport. * For example, different chip families use JTAG in different ways * for debugging. Also, each family that supports programming over * a UART link for initial firmware loading tends to define its own * messaging and error handling. */ #include #include extern struct command_context *global_cmd_ctx; /*-----------------------------------------------------------------------*/ /* * Infrastructure internals */ /** List of transports known to OpenOCD. */ static struct transport *transport_list; /** * NULL-terminated Vector of names of transports which the * currently selected debug adapter supports. This is declared * by the time that adapter is fully set up. */ static const char **allowed_transports; /** * The transport being used for the current OpenOCD session. */ static struct transport *session; static int transport_select(struct command_context *ctx, const char *name) { /* name may only identify a known transport; * caller guarantees session's transport isn't yet set.*/ for (struct transport *t = transport_list; t; t = t->next) { if (strcmp(t->name, name) == 0) { int retval = t->select(ctx); /* select() registers commands specific to this * transport, and may also reset the link, e.g. * forcing it to JTAG or SWD mode. */ if (retval == ERROR_OK) session = t; else LOG_ERROR("Error selecting '%s' as transport", t->name); return retval; } } LOG_ERROR("No transport named '%s' is available.", name); return ERROR_FAIL; } /** * Called by debug adapter drivers, or affiliated Tcl config scripts, * to declare the set of transports supported by an adapter. When * there is only one member of that set, it is automatically selected. */ int allow_transports(struct command_context *ctx, const char **vector) { /* NOTE: caller is required to provide only a list * of *valid* transport names * * REVISIT should we validate that? and insist there's * at least one non-NULL element in that list? * * ... allow removals, e.g. external strapping prevents use * of one transport; C code should be definitive about what * can be used when all goes well. */ if (allowed_transports != NULL || session) { LOG_ERROR("Can't modify the set of allowed transports."); return ERROR_FAIL; } allowed_transports = vector; /* autoselect if there's no choice ... */ if (!vector[1]) { LOG_INFO("only one transport option; autoselect '%s'", vector[0]); return transport_select(ctx, vector[0]); } return ERROR_OK; } /** * Used to verify corrrect adapter driver initialization. * * @returns true iff the adapter declared one or more transports. */ bool transports_are_declared(void) { return allowed_transports != NULL; } /** * Registers a transport. There are general purpose transports * (such as JTAG), as well as relatively proprietary ones which are * specific to a given chip (or chip family). * * Code implementing a transport needs to register it before it can * be selected and then activated. This is a dynamic process, so * that chips (and families) can define transports as needed (without * nneeding error-prone static tables). * * @param new_transport the transport being registered. On a * successful return, this memory is owned by the transport framework. * * @returns ERROR_OK on success, else a fault code. */ int transport_register(struct transport *new_transport) { struct transport *t; for (t = transport_list; t; t = t->next) { if (strcmp(t->name, new_transport->name) == 0) { LOG_ERROR("transport name already used"); return ERROR_FAIL; } } if (!new_transport->select || !new_transport->init) LOG_ERROR("invalid transport %s", new_transport->name); /* splice this into the list */ new_transport->next = transport_list; transport_list = new_transport; LOG_DEBUG("register '%s'", new_transport->name); return ERROR_OK; } /** * Returns the transport currently being used by this debug or * programming session. * * @returns handle to the read-only transport entity. */ struct transport *get_current_transport(void) { /* REVISIT -- constify */ return session; } /*-----------------------------------------------------------------------*/ /* * Infrastructure for Tcl interface to transports. */ /** * Makes and stores a copy of a set of transports passed as * parameters to a command. * * @param vector where the resulting copy is stored, as an argv-style * NULL-terminated vector. */ COMMAND_HELPER(transport_list_parse, char ***vector) { char **argv; unsigned n = CMD_ARGC; unsigned j = 0; *vector = NULL; if (n < 1) return ERROR_COMMAND_SYNTAX_ERROR; /* our return vector must be NULL terminated */ argv = (char **) calloc(n + 1, sizeof(char *)); if (argv == NULL) return ERROR_FAIL; for (unsigned i = 0; i < n; i++) { struct transport *t; for (t = transport_list; t; t = t->next) { if (strcmp(t->name, CMD_ARGV[i]) != 0) continue; argv[j++] = strdup(CMD_ARGV[i]); break; } if (!t) { LOG_ERROR("no such transport '%s'", CMD_ARGV[i]); goto fail; } } *vector = argv; return ERROR_OK; fail: for (unsigned i = 0; i < n; i++) free(argv[i]); free(argv); return ERROR_FAIL; } COMMAND_HANDLER(handle_transport_init) { LOG_DEBUG("%s", __func__); if (!session) { LOG_ERROR("session's transport is not selected."); /* no session transport configured, print transports then fail */ const char **vector = allowed_transports; while (*vector) { LOG_ERROR("allow transport '%s'", *vector); vector++; } return ERROR_FAIL; } return session->init(CMD_CTX); } COMMAND_HANDLER(handle_transport_list) { if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; command_print(CMD_CTX, "The following transports are available:"); for (struct transport *t = transport_list; t; t = t->next) command_print(CMD_CTX, "\t%s", t->name); return ERROR_OK; } /** * Implements the Tcl "transport select" command, choosing the * transport to be used in this debug session from among the * set supported by the debug adapter being used. Return value * is scriptable (allowing "if swd then..." etc). */ static int jim_transport_select(Jim_Interp *interp, int argc, Jim_Obj * const *argv) { switch (argc) { case 1: /* return/display */ if (!session) { LOG_ERROR("session's transport is not selected."); return JIM_ERR; } else { Jim_SetResultString(interp, session->name, -1); return JIM_OK; } break; case 2: /* assign */ if (session) { /* can't change session's transport after-the-fact */ LOG_ERROR("session's transport is already selected."); return JIM_ERR; } /* Is this transport supported by our debug adapter? * Example, "JTAG-only" means SWD is not supported. * * NOTE: requires adapter to have been set up, with * transports declared via C. */ if (!allowed_transports) { LOG_ERROR("Debug adapter doesn't support any transports?"); return JIM_ERR; } for (unsigned i = 0; allowed_transports[i]; i++) { if (strcmp(allowed_transports[i], argv[1]->bytes) == 0) return transport_select(global_cmd_ctx, argv[1]->bytes); } LOG_ERROR("Debug adapter doesn't support '%s' transport", argv[1]->bytes); return JIM_ERR; break; default: Jim_WrongNumArgs(interp, 1, argv, "[too many parameters]"); return JIM_ERR; } } static const struct command_registration transport_commands[] = { { .name = "init", .handler = handle_transport_init, /* this would be COMMAND_CONFIG ... except that * it needs to trigger event handlers that may * require COMMAND_EXEC ... */ .mode = COMMAND_ANY, .help = "Initialize this session's transport", .usage = "" }, { .name = "list", .handler = handle_transport_list, .mode = COMMAND_ANY, .help = "list all built-in transports", .usage = "" }, { .name = "select", .jim_handler = jim_transport_select, .mode = COMMAND_ANY, .help = "Select this session's transport", .usage = "[transport_name]", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration transport_group[] = { { .name = "transport", .mode = COMMAND_ANY, .help = "Transport command group", .chain = transport_commands, .usage = "" }, COMMAND_REGISTRATION_DONE }; int transport_register_commands(struct command_context *ctx) { return register_commands(ctx, NULL, transport_group); } openocd-0.7.0/src/transport/Makefile.in0000644000175000001440000004113012141414276014753 00000000000000# Makefile.in generated by automake 1.13.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ DIST_COMMON = $(top_srcdir)/common.mk $(srcdir)/Makefile.in \ $(srcdir)/Makefile.am $(top_srcdir)/depcomp $(noinst_HEADERS) @INTERNAL_JIMTCL_TRUE@am__append_1 = -I$(top_srcdir)/jimtcl \ @INTERNAL_JIMTCL_TRUE@ -I$(top_builddir)/jimtcl subdir = src/transport ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/config_subdir.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libtransport_la_LIBADD = am_libtransport_la_OBJECTS = transport.lo libtransport_la_OBJECTS = $(am_libtransport_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libtransport_la_SOURCES) DIST_SOURCES = $(libtransport_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CC_FOR_BUILD = @CC_FOR_BUILD@ CFLAGS = @CFLAGS@ CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@ FGREP = @FGREP@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ doxygen_as_html = @doxygen_as_html@ doxygen_as_pdf = @doxygen_as_pdf@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ # common flags used in openocd build AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src \ -I$(top_srcdir)/src/helper -DPKGDATADIR=\"$(pkgdatadir)\" \ -DPKGLIBDIR=\"$(pkglibdir)\" $(am__append_1) #METASOURCES = AUTO noinst_LTLIBRARIES = libtransport.la libtransport_la_SOURCES = \ transport.c noinst_HEADERS = \ transport.h MAINTAINERCLEANFILES = $(srcdir)/Makefile.in all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/common.mk $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/transport/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/transport/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_srcdir)/common.mk: $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libtransport.la: $(libtransport_la_OBJECTS) $(libtransport_la_DEPENDENCIES) $(EXTRA_libtransport_la_DEPENDENCIES) $(AM_V_CCLD)$(LINK) $(libtransport_la_OBJECTS) $(libtransport_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/transport.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: openocd-0.7.0/src/transport/Makefile.am0000644000175000001440000000032212134336410014733 00000000000000include $(top_srcdir)/common.mk #METASOURCES = AUTO noinst_LTLIBRARIES = libtransport.la libtransport_la_SOURCES = \ transport.c noinst_HEADERS = \ transport.h MAINTAINERCLEANFILES = $(srcdir)/Makefile.in openocd-0.7.0/src/rtos/0000755000175000001440000000000012141414413011713 500000000000000openocd-0.7.0/src/rtos/linux_header.h0000644000175000001440000000211612134336410014455 00000000000000/* gdb script to update the header file according to kernel version and build option before executing function awareness kernel symbol must be loaded : symbol vmlinux define awareness set logging off set logging file linux_header.h set logging on printf "#define QAT %p\n",&((struct task_struct *)(0))->stack set $a=&((struct list_head *)(0))->next set $a=(int)$a+(int)&((struct task_struct *)(0))->tasks printf "#define NEXT %p\n",$a printf "#define COMM %p\n",&((struct task_struct *)(0))->comm printf "#define MEM %p\n",&((struct task_struct *)(0))->mm printf "#define ONCPU %p\n",&((struct task_struct *)(0))->on_cpu printf "#define PID %p\n",&((struct task_struct *)(0))->pid printf "#define CPU_CONT %p\n",&((struct thread_info *)(0))->cpu_context printf "#define PREEMPT %p\n",&((struct thread_info *)(0))->preempt_count printf "#define MM_CTX %p\n",&((struct mm_struct *)(0))->context end */ #define QAT 0x4 #define NEXT 0x1b0 #define COMM 0x2d4 #define MEM 0x1cc #define ONCPU 0x18 #define PID 0x1f4 #define CPU_CONT 0x1c #define PREEMPT 0x4 #define MM_CTX 0x160 openocd-0.7.0/src/rtos/FreeRTOS.c0000644000175000001440000003561612137175623013417 00000000000000/*************************************************************************** * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "target/target.h" #include "target/target_type.h" #include "rtos.h" #include "helper/log.h" #include "helper/types.h" #include "rtos_standard_stackings.h" #define FREERTOS_MAX_PRIORITIES 63 #define FreeRTOS_STRUCT(int_type, ptr_type, list_prev_offset) struct FreeRTOS_params { const char *target_name; const unsigned char thread_count_width; const unsigned char pointer_width; const unsigned char list_next_offset; const unsigned char list_width; const unsigned char list_elem_next_offset; const unsigned char list_elem_content_offset; const unsigned char thread_stack_offset; const unsigned char thread_name_offset; const struct rtos_register_stacking *stacking_info; }; const struct FreeRTOS_params FreeRTOS_params_list[] = { { "cortex_m", /* target_name */ 4, /* thread_count_width; */ 4, /* pointer_width; */ 16, /* list_next_offset; */ 20, /* list_width; */ 8, /* list_elem_next_offset; */ 12, /* list_elem_content_offset */ 0, /* thread_stack_offset; */ 52, /* thread_name_offset; */ &rtos_standard_Cortex_M3_stacking, /* stacking_info */ }, { "hla_target", /* target_name */ 4, /* thread_count_width; */ 4, /* pointer_width; */ 16, /* list_next_offset; */ 20, /* list_width; */ 8, /* list_elem_next_offset; */ 12, /* list_elem_content_offset */ 0, /* thread_stack_offset; */ 52, /* thread_name_offset; */ &rtos_standard_Cortex_M3_stacking, /* stacking_info */ } }; #define FREERTOS_NUM_PARAMS ((int)(sizeof(FreeRTOS_params_list)/sizeof(struct FreeRTOS_params))) static int FreeRTOS_detect_rtos(struct target *target); static int FreeRTOS_create(struct target *target); static int FreeRTOS_update_threads(struct rtos *rtos); static int FreeRTOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list); static int FreeRTOS_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]); struct rtos_type FreeRTOS_rtos = { .name = "FreeRTOS", .detect_rtos = FreeRTOS_detect_rtos, .create = FreeRTOS_create, .update_threads = FreeRTOS_update_threads, .get_thread_reg_list = FreeRTOS_get_thread_reg_list, .get_symbol_list_to_lookup = FreeRTOS_get_symbol_list_to_lookup, }; enum FreeRTOS_symbol_values { FreeRTOS_VAL_pxCurrentTCB = 0, FreeRTOS_VAL_pxReadyTasksLists = 1, FreeRTOS_VAL_xDelayedTaskList1 = 2, FreeRTOS_VAL_xDelayedTaskList2 = 3, FreeRTOS_VAL_pxDelayedTaskList = 4, FreeRTOS_VAL_pxOverflowDelayedTaskList = 5, FreeRTOS_VAL_xPendingReadyList = 6, FreeRTOS_VAL_xTasksWaitingTermination = 7, FreeRTOS_VAL_xSuspendedTaskList = 8, FreeRTOS_VAL_uxCurrentNumberOfTasks = 9, FreeRTOS_VAL_uxTopUsedPriority = 10, }; static char *FreeRTOS_symbol_list[] = { "pxCurrentTCB", "pxReadyTasksLists", "xDelayedTaskList1", "xDelayedTaskList2", "pxDelayedTaskList", "pxOverflowDelayedTaskList", "xPendingReadyList", "xTasksWaitingTermination", "xSuspendedTaskList", "uxCurrentNumberOfTasks", "uxTopUsedPriority", NULL }; /* TODO: */ /* this is not safe for little endian yet */ /* may be problems reading if sizes are not 32 bit long integers. */ /* test mallocs for failure */ static int FreeRTOS_update_threads(struct rtos *rtos) { int i = 0; int retval; int tasks_found = 0; const struct FreeRTOS_params *param; if (rtos->rtos_specific_params == NULL) return -1; param = (const struct FreeRTOS_params *) rtos->rtos_specific_params; if (rtos->symbols == NULL) { LOG_ERROR("No symbols for FreeRTOS"); return -3; } if (rtos->symbols[FreeRTOS_VAL_uxCurrentNumberOfTasks].address == 0) { LOG_ERROR("Don't have the number of threads in FreeRTOS"); return -2; } int thread_list_size = 0; retval = target_read_buffer(rtos->target, rtos->symbols[FreeRTOS_VAL_uxCurrentNumberOfTasks].address, param->thread_count_width, (uint8_t *)&thread_list_size); if (retval != ERROR_OK) { LOG_ERROR("Could not read FreeRTOS thread count from target"); return retval; } /* wipe out previous thread details if any */ if (rtos->thread_details != NULL) { int j; for (j = 0; j < rtos->thread_count; j++) { if (rtos->thread_details[j].display_str != NULL) { free(rtos->thread_details[j].display_str); rtos->thread_details[j].display_str = NULL; } if (rtos->thread_details[j].thread_name_str != NULL) { free(rtos->thread_details[j].thread_name_str); rtos->thread_details[j].thread_name_str = NULL; } if (rtos->thread_details[j].extra_info_str != NULL) { free(rtos->thread_details[j].extra_info_str); rtos->thread_details[j].extra_info_str = NULL; } } free(rtos->thread_details); rtos->thread_details = NULL; } /* read the current thread */ retval = target_read_buffer(rtos->target, rtos->symbols[FreeRTOS_VAL_pxCurrentTCB].address, param->pointer_width, (uint8_t *)&rtos->current_thread); if (retval != ERROR_OK) { LOG_ERROR("Error reading current thread in FreeRTOS thread list"); return retval; } if ((thread_list_size == 0) || (rtos->current_thread == 0)) { /* Either : No RTOS threads - there is always at least the current execution though */ /* OR : No current thread - all threads suspended - show the current execution * of idling */ char tmp_str[] = "Current Execution"; thread_list_size++; tasks_found++; rtos->thread_details = (struct thread_detail *) malloc( sizeof(struct thread_detail) * thread_list_size); if (!rtos->thread_details) { LOG_ERROR("Error allocating memory for %d threads", thread_list_size); return ERROR_FAIL; } rtos->thread_details->threadid = 1; rtos->thread_details->exists = true; rtos->thread_details->display_str = NULL; rtos->thread_details->extra_info_str = NULL; rtos->thread_details->thread_name_str = (char *) malloc(sizeof(tmp_str)); strcpy(rtos->thread_details->thread_name_str, tmp_str); if (thread_list_size == 1) { rtos->thread_count = 1; return ERROR_OK; } } else { /* create space for new thread details */ rtos->thread_details = (struct thread_detail *) malloc( sizeof(struct thread_detail) * thread_list_size); if (!rtos->thread_details) { LOG_ERROR("Error allocating memory for %d threads", thread_list_size); return ERROR_FAIL; } } /* Find out how many lists are needed to be read from pxReadyTasksLists, */ int64_t max_used_priority = 0; retval = target_read_buffer(rtos->target, rtos->symbols[FreeRTOS_VAL_uxTopUsedPriority].address, param->pointer_width, (uint8_t *)&max_used_priority); if (retval != ERROR_OK) return retval; if (max_used_priority > FREERTOS_MAX_PRIORITIES) { LOG_ERROR("FreeRTOS maximum used priority is unreasonably big, not proceeding: %" PRId64 "", max_used_priority); return ERROR_FAIL; } symbol_address_t *list_of_lists = (symbol_address_t *)malloc(sizeof(symbol_address_t) * (max_used_priority+1 + 5)); if (!list_of_lists) { LOG_ERROR("Error allocating memory for %" PRId64 " priorities", max_used_priority); return ERROR_FAIL; } int num_lists; for (num_lists = 0; num_lists <= max_used_priority; num_lists++) list_of_lists[num_lists] = rtos->symbols[FreeRTOS_VAL_pxReadyTasksLists].address + num_lists * param->list_width; list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xDelayedTaskList1].address; list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xDelayedTaskList2].address; list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xPendingReadyList].address; list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xSuspendedTaskList].address; list_of_lists[num_lists++] = rtos->symbols[FreeRTOS_VAL_xTasksWaitingTermination].address; for (i = 0; i < num_lists; i++) { if (list_of_lists[i] == 0) continue; /* Read the number of threads in this list */ int64_t list_thread_count = 0; retval = target_read_buffer(rtos->target, list_of_lists[i], param->thread_count_width, (uint8_t *)&list_thread_count); if (retval != ERROR_OK) { LOG_ERROR("Error reading number of threads in FreeRTOS thread list"); free(list_of_lists); return retval; } if (list_thread_count == 0) continue; /* Read the location of first list item */ uint64_t prev_list_elem_ptr = -1; uint64_t list_elem_ptr = 0; retval = target_read_buffer(rtos->target, list_of_lists[i] + param->list_next_offset, param->pointer_width, (uint8_t *)&list_elem_ptr); if (retval != ERROR_OK) { LOG_ERROR("Error reading first thread item location in FreeRTOS thread list"); free(list_of_lists); return retval; } while ((list_thread_count > 0) && (list_elem_ptr != 0) && (list_elem_ptr != prev_list_elem_ptr) && (tasks_found < thread_list_size)) { /* Get the location of the thread structure. */ rtos->thread_details[tasks_found].threadid = 0; retval = target_read_buffer(rtos->target, list_elem_ptr + param->list_elem_content_offset, param->pointer_width, (uint8_t *)&(rtos->thread_details[tasks_found].threadid)); if (retval != ERROR_OK) { LOG_ERROR("Error reading thread list item object in FreeRTOS thread list"); free(list_of_lists); return retval; } /* get thread name */ #define FREERTOS_THREAD_NAME_STR_SIZE (200) char tmp_str[FREERTOS_THREAD_NAME_STR_SIZE]; /* Read the thread name */ retval = target_read_buffer(rtos->target, rtos->thread_details[tasks_found].threadid + param->thread_name_offset, FREERTOS_THREAD_NAME_STR_SIZE, (uint8_t *)&tmp_str); if (retval != ERROR_OK) { LOG_ERROR("Error reading first thread item location in FreeRTOS thread list"); free(list_of_lists); return retval; } tmp_str[FREERTOS_THREAD_NAME_STR_SIZE-1] = '\x00'; if (tmp_str[0] == '\x00') strcpy(tmp_str, "No Name"); rtos->thread_details[tasks_found].thread_name_str = (char *)malloc(strlen(tmp_str)+1); strcpy(rtos->thread_details[tasks_found].thread_name_str, tmp_str); rtos->thread_details[tasks_found].display_str = NULL; rtos->thread_details[tasks_found].exists = true; if (rtos->thread_details[tasks_found].threadid == rtos->current_thread) { char running_str[] = "Running"; rtos->thread_details[tasks_found].extra_info_str = (char *) malloc( sizeof(running_str)); strcpy(rtos->thread_details[tasks_found].extra_info_str, running_str); } else rtos->thread_details[tasks_found].extra_info_str = NULL; tasks_found++; list_thread_count--; prev_list_elem_ptr = list_elem_ptr; list_elem_ptr = 0; retval = target_read_buffer(rtos->target, prev_list_elem_ptr + param->list_elem_next_offset, param->pointer_width, (uint8_t *)&list_elem_ptr); if (retval != ERROR_OK) { LOG_ERROR("Error reading next thread item location in FreeRTOS thread list"); free(list_of_lists); return retval; } } } free(list_of_lists); rtos->thread_count = tasks_found; return 0; } static int FreeRTOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list) { int retval; const struct FreeRTOS_params *param; int64_t stack_ptr = 0; *hex_reg_list = NULL; if (rtos == NULL) return -1; if (thread_id == 0) return -2; if (rtos->rtos_specific_params == NULL) return -1; param = (const struct FreeRTOS_params *) rtos->rtos_specific_params; /* Read the stack pointer */ retval = target_read_buffer(rtos->target, thread_id + param->thread_stack_offset, param->pointer_width, (uint8_t *)&stack_ptr); if (retval != ERROR_OK) { LOG_ERROR("Error reading stack frame from FreeRTOS thread"); return retval; } return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, hex_reg_list); } static int FreeRTOS_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) { unsigned int i; *symbol_list = (symbol_table_elem_t *) malloc( sizeof(symbol_table_elem_t) * ARRAY_SIZE(FreeRTOS_symbol_list)); for (i = 0; i < ARRAY_SIZE(FreeRTOS_symbol_list); i++) (*symbol_list)[i].symbol_name = FreeRTOS_symbol_list[i]; return 0; } #if 0 static int FreeRTOS_set_current_thread(struct rtos *rtos, threadid_t thread_id) { return 0; } static int FreeRTOS_get_thread_ascii_info(struct rtos *rtos, threadid_t thread_id, char **info) { int retval; const struct FreeRTOS_params *param; if (rtos == NULL) return -1; if (thread_id == 0) return -2; if (rtos->rtos_specific_params == NULL) return -3; param = (const struct FreeRTOS_params *) rtos->rtos_specific_params; #define FREERTOS_THREAD_NAME_STR_SIZE (200) char tmp_str[FREERTOS_THREAD_NAME_STR_SIZE]; /* Read the thread name */ retval = target_read_buffer(rtos->target, thread_id + param->thread_name_offset, FREERTOS_THREAD_NAME_STR_SIZE, (uint8_t *)&tmp_str); if (retval != ERROR_OK) { LOG_ERROR("Error reading first thread item location in FreeRTOS thread list"); return retval; } tmp_str[FREERTOS_THREAD_NAME_STR_SIZE-1] = '\x00'; if (tmp_str[0] == '\x00') strcpy(tmp_str, "No Name"); *info = (char *)malloc(strlen(tmp_str)+1); strcpy(*info, tmp_str); return 0; } #endif static int FreeRTOS_detect_rtos(struct target *target) { if ((target->rtos->symbols != NULL) && (target->rtos->symbols[FreeRTOS_VAL_pxReadyTasksLists].address != 0)) { /* looks like FreeRTOS */ return 1; } return 0; } static int FreeRTOS_create(struct target *target) { int i = 0; while ((i < FREERTOS_NUM_PARAMS) && (0 != strcmp(FreeRTOS_params_list[i].target_name, target->type->name))) { i++; } if (i >= FREERTOS_NUM_PARAMS) { LOG_ERROR("Could not find target in FreeRTOS compatibility list"); return -1; } target->rtos->rtos_specific_params = (void *) &FreeRTOS_params_list[i]; return 0; } openocd-0.7.0/src/rtos/rtos.c0000644000175000001440000003716712137151331013006 00000000000000/*************************************************************************** * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "rtos.h" #include "target/target.h" #include "helper/log.h" #include "helper/binarybuffer.h" #include "server/gdb_server.h" /* RTOSs */ extern struct rtos_type FreeRTOS_rtos; extern struct rtos_type ThreadX_rtos; extern struct rtos_type eCos_rtos; extern struct rtos_type Linux_os; extern struct rtos_type ChibiOS_rtos; static struct rtos_type *rtos_types[] = { &ThreadX_rtos, &FreeRTOS_rtos, &eCos_rtos, &Linux_os, &ChibiOS_rtos, NULL }; int rtos_thread_packet(struct connection *connection, char *packet, int packet_size); int rtos_smp_init(struct target *target) { if (target->rtos->type->smp_init) return target->rtos->type->smp_init(target); return ERROR_TARGET_INIT_FAILED; } static int os_alloc(struct target *target, struct rtos_type *ostype) { struct rtos *os = target->rtos = calloc(1, sizeof(struct rtos)); if (!os) return JIM_ERR; os->type = ostype; os->current_threadid = -1; os->current_thread = 0; os->symbols = NULL; os->target = target; /* RTOS drivers can override the packet handler in _create(). */ os->gdb_thread_packet = rtos_thread_packet; return JIM_OK; } static void os_free(struct target *target) { if (!target->rtos) return; if (target->rtos->symbols) free(target->rtos->symbols); free(target->rtos); target->rtos = NULL; } static int os_alloc_create(struct target *target, struct rtos_type *ostype) { int ret = os_alloc(target, ostype); if (JIM_OK == ret) { ret = target->rtos->type->create(target); if (ret != JIM_OK) os_free(target); } return ret; } int rtos_create(Jim_GetOptInfo *goi, struct target *target) { int x; char *cp; struct Jim_Obj *res; if (!goi->isconfigure && goi->argc != 0) { Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "NO PARAMS"); return JIM_ERR; } os_free(target); Jim_GetOpt_String(goi, &cp, NULL); if (0 == strcmp(cp, "auto")) { /* Auto detect tries to look up all symbols for each RTOS, * and runs the RTOS driver's _detect() function when GDB * finds all symbols for any RTOS. See rtos_qsymbol(). */ target->rtos_auto_detect = true; /* rtos_qsymbol() will iterate over all RTOSes. Allocate * target->rtos here, and set it to the first RTOS type. */ return os_alloc(target, rtos_types[0]); } for (x = 0; rtos_types[x]; x++) if (0 == strcmp(cp, rtos_types[x]->name)) return os_alloc_create(target, rtos_types[x]); Jim_SetResultFormatted(goi->interp, "Unknown RTOS type %s, try one of: ", cp); res = Jim_GetResult(goi->interp); for (x = 0; rtos_types[x]; x++) Jim_AppendStrings(goi->interp, res, rtos_types[x]->name, ", ", NULL); Jim_AppendStrings(goi->interp, res, " or auto", NULL); return JIM_ERR; } int gdb_thread_packet(struct connection *connection, char *packet, int packet_size) { struct target *target = get_target_from_connection(connection); if (target->rtos == NULL) return rtos_thread_packet(connection, packet, packet_size); /* thread not *found*/ return target->rtos->gdb_thread_packet(connection, packet, packet_size); } static char *next_symbol(struct rtos *os, char *cur_symbol, uint64_t cur_addr) { symbol_table_elem_t *s; if (!os->symbols) os->type->get_symbol_list_to_lookup(&os->symbols); if (!cur_symbol[0]) return os->symbols[0].symbol_name; for (s = os->symbols; s->symbol_name; s++) if (!strcmp(s->symbol_name, cur_symbol)) { s->address = cur_addr; s++; return s->symbol_name; } return NULL; } /* rtos_qsymbol() processes and replies to all qSymbol packets from GDB. * * GDB sends a qSymbol:: packet (empty address, empty name) to notify * that it can now answer qSymbol::hexcodedname queries, to look up symbols. * * If the qSymbol packet has no address that means GDB did not find the * symbol, in which case auto-detect will move on to try the next RTOS. * * rtos_qsymbol() then calls the next_symbol() helper function, which * iterates over symbol names for the current RTOS until it finds the * symbol in the received GDB packet, and then returns the next entry * in the list of symbols. * * If GDB replied about the last symbol for the RTOS and the RTOS was * specified explicitly, then no further symbol lookup is done. When * auto-detecting, the RTOS driver _detect() function must return success. * * rtos_qsymbol() returns 1 if an RTOS has been detected, or 0 otherwise. */ int rtos_qsymbol(struct connection *connection, char *packet, int packet_size) { int rtos_detected = 0; uint64_t addr; size_t reply_len; char reply[GDB_BUFFER_SIZE], cur_sym[GDB_BUFFER_SIZE / 2] = "", *next_sym; struct target *target = get_target_from_connection(connection); struct rtos *os = target->rtos; reply_len = sprintf(reply, "OK"); if (!os) goto done; /* Decode any symbol name in the packet*/ int len = unhexify(cur_sym, strchr(packet + 8, ':') + 1, strlen(strchr(packet + 8, ':') + 1)); cur_sym[len] = 0; if ((strcmp(packet, "qSymbol::") != 0) && /* GDB is not offering symbol lookup for the first time */ (!sscanf(packet, "qSymbol:%" SCNx64 ":", &addr))) { /* GDB did not found an address for a symbol */ /* GDB could not find an address for the previous symbol */ if (!target->rtos_auto_detect) { LOG_WARNING("RTOS %s not detected. (GDB could not find symbol \'%s\')", os->type->name, cur_sym); goto done; } else { /* Autodetecting RTOS - try next RTOS */ if (!rtos_try_next(target)) goto done; /* Next RTOS selected - invalidate current symbol */ cur_sym[0] = '\x00'; } } next_sym = next_symbol(os, cur_sym, addr); if (!next_sym) { /* No more symbols need looking up */ if (!target->rtos_auto_detect) { rtos_detected = 1; goto done; } if (os->type->detect_rtos(target)) { LOG_INFO("Auto-detected RTOS: %s", os->type->name); rtos_detected = 1; goto done; } else { LOG_WARNING("No RTOS could be auto-detected!"); goto done; } } if (8 + (strlen(next_sym) * 2) + 1 > sizeof(reply)) { LOG_ERROR("ERROR: RTOS symbol '%s' name is too long for GDB!", next_sym); goto done; } reply_len = snprintf(reply, sizeof(reply), "qSymbol:"); reply_len += hexify(reply + reply_len, next_sym, 0, sizeof(reply) - reply_len); done: gdb_put_packet(connection, reply, reply_len); return rtos_detected; } int rtos_thread_packet(struct connection *connection, char *packet, int packet_size) { struct target *target = get_target_from_connection(connection); if (strncmp(packet, "qThreadExtraInfo,", 17) == 0) { if ((target->rtos != NULL) && (target->rtos->thread_details != NULL) && (target->rtos->thread_count != 0)) { threadid_t threadid = 0; int found = -1; sscanf(packet, "qThreadExtraInfo,%" SCNx64, &threadid); if ((target->rtos != NULL) && (target->rtos->thread_details != NULL)) { int thread_num; for (thread_num = 0; thread_num < target->rtos->thread_count; thread_num++) { if (target->rtos->thread_details[thread_num].threadid == threadid) { if (target->rtos->thread_details[thread_num].exists) found = thread_num; } } } if (found == -1) { gdb_put_packet(connection, "E01", 3); /* thread not found */ return ERROR_OK; } struct thread_detail *detail = &target->rtos->thread_details[found]; int str_size = 0; if (detail->display_str != NULL) str_size += strlen(detail->display_str); if (detail->thread_name_str != NULL) str_size += strlen(detail->thread_name_str); if (detail->extra_info_str != NULL) str_size += strlen(detail->extra_info_str); char *tmp_str = (char *) malloc(str_size + 7); char *tmp_str_ptr = tmp_str; if (detail->display_str != NULL) tmp_str_ptr += sprintf(tmp_str_ptr, "%s", detail->display_str); if (detail->thread_name_str != NULL) { if (tmp_str_ptr != tmp_str) tmp_str_ptr += sprintf(tmp_str_ptr, " : "); tmp_str_ptr += sprintf(tmp_str_ptr, "%s", detail->thread_name_str); } if (detail->extra_info_str != NULL) { if (tmp_str_ptr != tmp_str) tmp_str_ptr += sprintf(tmp_str_ptr, " : "); tmp_str_ptr += sprintf(tmp_str_ptr, " : %s", detail->extra_info_str); } assert(strlen(tmp_str) == (size_t) (tmp_str_ptr - tmp_str)); char *hex_str = (char *) malloc(strlen(tmp_str) * 2 + 1); int pkt_len = hexify(hex_str, tmp_str, 0, strlen(tmp_str) * 2 + 1); gdb_put_packet(connection, hex_str, pkt_len); free(hex_str); free(tmp_str); return ERROR_OK; } gdb_put_packet(connection, "", 0); return ERROR_OK; } else if (strncmp(packet, "qSymbol", 7) == 0) { if (rtos_qsymbol(connection, packet, packet_size) == 1) { target->rtos_auto_detect = false; target->rtos->type->create(target); target->rtos->type->update_threads(target->rtos); } return ERROR_OK; } else if (strncmp(packet, "qfThreadInfo", 12) == 0) { int i; if ((target->rtos != NULL) && (target->rtos->thread_count != 0)) { char *out_str = (char *) malloc(17 * target->rtos->thread_count + 5); char *tmp_str = out_str; tmp_str += sprintf(tmp_str, "m"); for (i = 0; i < target->rtos->thread_count; i++) { if (i != 0) tmp_str += sprintf(tmp_str, ","); tmp_str += sprintf(tmp_str, "%016" PRIx64, target->rtos->thread_details[i].threadid); } tmp_str[0] = 0; gdb_put_packet(connection, out_str, strlen(out_str)); } else gdb_put_packet(connection, "", 0); return ERROR_OK; } else if (strncmp(packet, "qsThreadInfo", 12) == 0) { gdb_put_packet(connection, "l", 1); return ERROR_OK; } else if (strncmp(packet, "qAttached", 9) == 0) { gdb_put_packet(connection, "1", 1); return ERROR_OK; } else if (strncmp(packet, "qOffsets", 8) == 0) { char offsets[] = "Text=0;Data=0;Bss=0"; gdb_put_packet(connection, offsets, sizeof(offsets)-1); return ERROR_OK; } else if (strncmp(packet, "qCRC:", 5) == 0) { /* make sure we check this before "qC" packet below * otherwise it gets incorrectly handled */ return GDB_THREAD_PACKET_NOT_CONSUMED; } else if (strncmp(packet, "qC", 2) == 0) { if (target->rtos != NULL) { char buffer[19]; int size; size = snprintf(buffer, 19, "QC%016" PRIx64, target->rtos->current_thread); gdb_put_packet(connection, buffer, size); } else gdb_put_packet(connection, "QC0", 3); return ERROR_OK; } else if (packet[0] == 'T') { /* Is thread alive? */ threadid_t threadid; int found = -1; sscanf(packet, "T%" SCNx64, &threadid); if ((target->rtos != NULL) && (target->rtos->thread_details != NULL)) { int thread_num; for (thread_num = 0; thread_num < target->rtos->thread_count; thread_num++) { if (target->rtos->thread_details[thread_num].threadid == threadid) { if (target->rtos->thread_details[thread_num].exists) found = thread_num; } } } if (found != -1) gdb_put_packet(connection, "OK", 2); /* thread alive */ else gdb_put_packet(connection, "E01", 3); /* thread not found */ return ERROR_OK; } else if (packet[0] == 'H') { /* Set current thread ( 'c' for step and continue, 'g' for * all other operations ) */ if ((packet[1] == 'g') && (target->rtos != NULL)) sscanf(packet, "Hg%16" SCNx64, &target->rtos->current_threadid); gdb_put_packet(connection, "OK", 2); return ERROR_OK; } return GDB_THREAD_PACKET_NOT_CONSUMED; } int rtos_get_gdb_reg_list(struct connection *connection) { struct target *target = get_target_from_connection(connection); int64_t current_threadid = target->rtos->current_threadid; if ((target->rtos != NULL) && (current_threadid != -1) && (current_threadid != 0) && ((current_threadid != target->rtos->current_thread) || (target->smp))) { /* in smp several current thread are possible */ char *hex_reg_list; target->rtos->type->get_thread_reg_list(target->rtos, current_threadid, &hex_reg_list); if (hex_reg_list != NULL) { gdb_put_packet(connection, hex_reg_list, strlen(hex_reg_list)); free(hex_reg_list); return ERROR_OK; } } return ERROR_FAIL; } int rtos_generic_stack_read(struct target *target, const struct rtos_register_stacking *stacking, int64_t stack_ptr, char **hex_reg_list) { int list_size = 0; char *tmp_str_ptr; int64_t new_stack_ptr; int i; int retval; if (stack_ptr == 0) { LOG_ERROR("Error: null stack pointer in thread"); return -5; } /* Read the stack */ uint8_t *stack_data = (uint8_t *) malloc(stacking->stack_registers_size); uint32_t address = stack_ptr; if (stacking->stack_growth_direction == 1) address -= stacking->stack_registers_size; retval = target_read_buffer(target, address, stacking->stack_registers_size, stack_data); if (retval != ERROR_OK) { LOG_ERROR("Error reading stack frame from thread"); return retval; } #if 0 LOG_OUTPUT("Stack Data :"); for (i = 0; i < stacking->stack_registers_size; i++) LOG_OUTPUT("%02X", stack_data[i]); LOG_OUTPUT("\r\n"); #endif for (i = 0; i < stacking->num_output_registers; i++) list_size += stacking->register_offsets[i].width_bits/8; *hex_reg_list = (char *)malloc(list_size*2 + 1); tmp_str_ptr = *hex_reg_list; new_stack_ptr = stack_ptr - stacking->stack_growth_direction * stacking->stack_registers_size; if (stacking->stack_alignment != 0) { /* Align new stack pointer to x byte boundary */ new_stack_ptr = (new_stack_ptr & (~((int64_t) stacking->stack_alignment - 1))) + ((stacking->stack_growth_direction == -1) ? stacking->stack_alignment : 0); } for (i = 0; i < stacking->num_output_registers; i++) { int j; for (j = 0; j < stacking->register_offsets[i].width_bits/8; j++) { if (stacking->register_offsets[i].offset == -1) tmp_str_ptr += sprintf(tmp_str_ptr, "%02x", 0); else if (stacking->register_offsets[i].offset == -2) tmp_str_ptr += sprintf(tmp_str_ptr, "%02x", ((uint8_t *)&new_stack_ptr)[j]); else tmp_str_ptr += sprintf(tmp_str_ptr, "%02x", stack_data[stacking->register_offsets[i].offset + j]); } } /* LOG_OUTPUT("Output register string: %s\r\n", *hex_reg_list); */ return ERROR_OK; } int rtos_try_next(struct target *target) { struct rtos *os = target->rtos; struct rtos_type **type = rtos_types; if (!os) return 0; while (*type && os->type != *type) type++; if (!*type || !*(++type)) return 0; os->type = *type; if (os->symbols) { free(os->symbols); os->symbols = NULL; } return 1; } int rtos_update_threads(struct target *target) { if ((target->rtos != NULL) && (target->rtos->type != NULL)) target->rtos->type->update_threads(target->rtos); return ERROR_OK; } openocd-0.7.0/src/rtos/rtos_chibios_stackings.h0000644000175000001440000000332612134336410016547 00000000000000/*************************************************************************** * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef INCLUDED_RTOS_CHIBIOS_STACKINGS_H_ #define INCLUDED_RTOS_CHIBIOS_STACKINGS_H_ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "rtos.h" extern const struct rtos_register_stacking rtos_chibios_arm_v7m_stacking; #endif /* ifndef INCLUDED_RTOS_CHIBIOS_STACKINGS_H_ */ openocd-0.7.0/src/rtos/linux.c0000644000175000001440000011742312137151331013150 00000000000000/*************************************************************************** * Copyright (C) 2011 by STEricsson * * Heythem Bouhaja heythem.bouhaja@stericsson.com : creation * * Michel JAOUEN michel.jaouen@stericsson.com : adaptation to rtos * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "target/target.h" #include "target/target_type.h" #include "helper/log.h" #include "helper/types.h" #include "rtos.h" #include "rtos_standard_stackings.h" #include #include "server/gdb_server.h" #define LINUX_USER_KERNEL_BORDER 0xc0000000 #include "linux_header.h" #define PHYS #define MAX_THREADS 200 /* specific task */ struct linux_os { char *name; uint32_t init_task_addr; int thread_count; int threadid_count; int preupdtate_threadid_count; int nr_cpus; int threads_lookup; int threads_needs_update; struct current_thread *current_threads; struct threads *thread_list; /* virt2phys parameter */ uint32_t phys_mask; uint32_t phys_base; }; struct current_thread { int64_t threadid; int32_t core_id; #ifdef PID_CHECK uint32_t pid; #endif uint32_t TS; struct current_thread *next; }; struct threads { char name[17]; uint32_t base_addr; /* address to read magic */ uint32_t state; /* magic value : filled only at creation */ uint32_t pid; /* linux pid : id for identifying a thread */ uint32_t oncpu; /* content cpu number in current thread */ uint32_t asid; /* filled only at creation */ int64_t threadid; int status; /* dead = 1 alive = 2 current = 3 alive and current */ /* value that should not change during the live of a thread ? */ uint32_t thread_info_addr; /* contain latest thread_info_addr computed */ /* retrieve from thread_info */ struct cpu_context *context; struct threads *next; }; struct cpu_context { uint32_t R4; uint32_t R5; uint32_t R6; uint32_t R7; uint32_t R8; uint32_t R9; uint32_t IP; uint32_t FP; uint32_t SP; uint32_t PC; uint32_t preempt_count; }; struct cpu_context *cpu_context_read(struct target *target, uint32_t base_addr, uint32_t *info_addr); static int insert_into_threadlist(struct target *target, struct threads *t); static int linux_os_create(struct target *target); static int linux_os_dummy_update(struct rtos *rtos) { /* update is done only when thread request come * too many thread to do it on each stop */ return 0; } static int linux_compute_virt2phys(struct target *target, uint32_t address) { struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; uint32_t pa = 0; int retval = target->type->virt2phys(target, address, &pa); if (retval != ERROR_OK) { LOG_ERROR("Cannot compute linux virt2phys translation"); /* fixes default address */ linux_os->phys_base = 0; return ERROR_FAIL; } linux_os->init_task_addr = address; address = address & linux_os->phys_mask; linux_os->phys_base = pa - address; return ERROR_OK; } static int linux_read_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) { #ifdef PHYS struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; uint32_t pa = (address & linux_os->phys_mask) + linux_os->phys_base; #endif if (address < 0xc000000) { LOG_ERROR("linux awareness : address in user space"); return ERROR_FAIL; } #ifdef PHYS target_read_phys_memory(target, pa, size, count, buffer); #endif target_read_memory(target, address, size, count, buffer); return ERROR_OK; } static char *reg_converter(char *buffer, void *reg, int size) { int i; for (i = 0; i < size; i++) buffer += sprintf(buffer, "%02x", ((uint8_t *) reg)[i]); return buffer; } int fill_buffer(struct target *target, uint32_t addr, uint8_t *buffer) { if ((addr & 0xfffffffc) != addr) LOG_INFO("unaligned address %x!!", addr); int retval = linux_read_memory(target, addr, 4, 1, buffer); return retval; } uint32_t get_buffer(struct target *target, const uint8_t *buffer) { uint32_t value = 0; const uint8_t *value_ptr = buffer; value = target_buffer_get_u32(target, value_ptr); return value; } static int linux_os_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list) { struct target *target = rtos->target; struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; int i = 0; struct current_thread *tmp = linux_os->current_threads; struct current_thread *next; char *hex_string; int found = 0; int retval; /* check if a current thread is requested */ next = tmp; do { if (next->threadid == thread_id) found = 1; else next = next->next; } while ((found == 0) && (next != tmp) && (next != NULL)); if (found == 1) { /* search target to perfom the access */ struct reg **reg_list; int reg_list_size, reg_packet_size = 0; struct target_list *head; head = target->head; found = 0; do { if (head->target->coreid == next->core_id) { target = head->target; found = 1; } else head = head->next; } while ((head != (struct target_list *)NULL) && (found == 0)); if (found == 0) { LOG_ERROR ( "current thread %" PRIx64 ": no target to perform access of core id %x", thread_id, next->core_id); return ERROR_FAIL; } /*LOG_INFO("thread %lx current on core %x",thread_id, * target->coreid);*/ retval = target_get_gdb_reg_list(target, ®_list, ®_list_size); if (retval != ERROR_OK) return retval; for (i = 0; i < reg_list_size; i++) reg_packet_size += reg_list[i]->size; assert(reg_packet_size > 0); *hex_reg_list = malloc(DIV_ROUND_UP(reg_packet_size, 8) * 2); hex_string = *hex_reg_list; for (i = 0; i < reg_list_size; i++) { if (!reg_list[i]->valid) reg_list[i]->type->get(reg_list[i]); hex_string = reg_converter(hex_string, reg_list[i]->value, (reg_list[i]->size) / 8); } free(reg_list); } else { struct threads *temp = linux_os->thread_list; *hex_reg_list = (char *)calloc(1, 500 * sizeof(char)); hex_string = *hex_reg_list; for (i = 0; i < 16; i++) hex_string += sprintf(hex_string, "%02x", 0); while ((temp != NULL) && (temp->threadid != target->rtos->current_threadid)) temp = temp->next; if (temp != NULL) { if (temp->context == NULL) temp->context = cpu_context_read(target, temp-> base_addr, &temp-> thread_info_addr); hex_string = reg_converter(hex_string, &temp->context->R4, 4); hex_string = reg_converter(hex_string, &temp->context->R5, 4); hex_string = reg_converter(hex_string, &temp->context->R6, 4); hex_string = reg_converter(hex_string, &temp->context->R7, 4); hex_string = reg_converter(hex_string, &temp->context->R8, 4); hex_string = reg_converter(hex_string, &temp->context->R9, 4); for (i = 0; i < 4; i++) /*R10 = 0x0 */ hex_string += sprintf(hex_string, "%02x", 0); hex_string = reg_converter(hex_string, &temp->context->FP, 4); hex_string = reg_converter(hex_string, &temp->context->IP, 4); hex_string = reg_converter(hex_string, &temp->context->SP, 4); for (i = 0; i < 4; i++) hex_string += sprintf(hex_string, "%02x", 0); hex_string = reg_converter(hex_string, &temp->context->PC, 4); for (i = 0; i < 100; i++) /*100 */ hex_string += sprintf(hex_string, "%02x", 0); uint32_t cpsr = 0x00000000; reg_converter(hex_string, &cpsr, 4); } } return ERROR_OK; } static int linux_os_detect(struct target *target) { LOG_INFO("should no be called"); return 0; } static int linux_os_smp_init(struct target *target); static int linux_os_clean(struct target *target); #define INIT_TASK 0 static char *linux_symbol_list[] = { "init_task", NULL }; static int linux_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) { unsigned int i; *symbol_list = (symbol_table_elem_t *) malloc(sizeof(symbol_table_elem_t) * ARRAY_SIZE(linux_symbol_list)); for (i = 0; i < ARRAY_SIZE(linux_symbol_list); i++) (*symbol_list)[i].symbol_name = linux_symbol_list[i]; return 0; } static char *linux_ps_command(struct target *target); const struct rtos_type Linux_os = { .name = "linux", .detect_rtos = linux_os_detect, .create = linux_os_create, .smp_init = linux_os_smp_init, .update_threads = linux_os_dummy_update, .get_thread_reg_list = linux_os_thread_reg_list, .get_symbol_list_to_lookup = linux_get_symbol_list_to_lookup, .clean = linux_os_clean, .ps_command = linux_ps_command, }; static int linux_thread_packet(struct connection *connection, char *packet, int packet_size); static void linux_identify_current_threads(struct target *target); #ifdef PID_CHECK int fill_task_pid(struct target *target, struct threads *t) { uint32_t pid_addr = t->base_addr + PID; uint8_t buffer[4]; int retval = fill_buffer(target, pid_addr, buffer); if (retval == ERROR_OK) { uint32_t val = get_buffer(target, buffer); t->pid = val; } else LOG_ERROR("fill_task_pid: unable to read memory"); return retval; } #endif int fill_task(struct target *target, struct threads *t) { int retval; uint32_t pid_addr = t->base_addr + PID; uint32_t mem_addr = t->base_addr + MEM; uint32_t on_cpu = t->base_addr + ONCPU; uint8_t *buffer = calloc(1, 4); retval = fill_buffer(target, t->base_addr, buffer); if (retval == ERROR_OK) { uint32_t val = get_buffer(target, buffer); t->state = val; } else LOG_ERROR("fill_task: unable to read memory"); retval = fill_buffer(target, pid_addr, buffer); if (retval == ERROR_OK) { uint32_t val = get_buffer(target, buffer); t->pid = val; } else LOG_ERROR("fill task: unable to read memory"); retval = fill_buffer(target, on_cpu, buffer); if (retval == ERROR_OK) { uint32_t val = get_buffer(target, buffer); t->oncpu = val; } else LOG_ERROR("fill task: unable to read memory"); retval = fill_buffer(target, mem_addr, buffer); if (retval == ERROR_OK) { uint32_t val = get_buffer(target, buffer); if (val != 0) { uint32_t asid_addr = val + MM_CTX; retval = fill_buffer(target, asid_addr, buffer); if (retval == ERROR_OK) { val = get_buffer(target, buffer); t->asid = val; } else LOG_ERROR ("fill task: unable to read memory -- ASID"); } else t->asid = 0; } else LOG_ERROR("fill task: unable to read memory"); free(buffer); return retval; } int get_name(struct target *target, struct threads *t) { int retval; uint32_t full_name[4]; uint32_t comm = t->base_addr + COMM; int i; for (i = 0; i < 17; i++) t->name[i] = 0; retval = linux_read_memory(target, comm, 4, 4, (uint8_t *) full_name); if (retval != ERROR_OK) { LOG_ERROR("get_name: unable to read memory\n"); return ERROR_FAIL; } uint32_t raw_name = target_buffer_get_u32(target, (const uint8_t *) &full_name[0]); t->name[3] = raw_name >> 24; t->name[2] = raw_name >> 16; t->name[1] = raw_name >> 8; t->name[0] = raw_name; raw_name = target_buffer_get_u32(target, (const uint8_t *)&full_name[1]); t->name[7] = raw_name >> 24; t->name[6] = raw_name >> 16; t->name[5] = raw_name >> 8; t->name[4] = raw_name; raw_name = target_buffer_get_u32(target, (const uint8_t *)&full_name[2]); t->name[11] = raw_name >> 24; t->name[10] = raw_name >> 16; t->name[9] = raw_name >> 8; t->name[8] = raw_name; raw_name = target_buffer_get_u32(target, (const uint8_t *)&full_name[3]); t->name[15] = raw_name >> 24; t->name[14] = raw_name >> 16; t->name[13] = raw_name >> 8; t->name[12] = raw_name; return ERROR_OK; } int get_current(struct target *target, int create) { struct target_list *head; head = target->head; uint8_t *buf; uint32_t val; uint32_t ti_addr; uint8_t *buffer = calloc(1, 4); struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; struct current_thread *ctt = linux_os->current_threads; /* invalid current threads content */ while (ctt != NULL) { ctt->threadid = -1; ctt->TS = 0xdeadbeef; ctt = ctt->next; } while (head != (struct target_list *)NULL) { struct reg **reg_list; int reg_list_size; int retval; if (target_get_gdb_reg_list(head->target, ®_list, ®_list_size) != ERROR_OK) { free(buffer); return ERROR_TARGET_FAILURE; } if (!reg_list[13]->valid) reg_list[13]->type->get(reg_list[13]); buf = reg_list[13]->value; val = get_buffer(target, buf); ti_addr = (val & 0xffffe000); uint32_t TS_addr = ti_addr + 0xc; retval = fill_buffer(target, TS_addr, buffer); if (retval == ERROR_OK) { uint32_t TS = get_buffer(target, buffer); uint32_t cpu, on_cpu = TS + ONCPU; retval = fill_buffer(target, on_cpu, buffer); if (retval == ERROR_OK) { /*uint32_t cpu = get_buffer(target, buffer);*/ struct current_thread *ct = linux_os->current_threads; cpu = head->target->coreid; while ((ct != NULL) && (ct->core_id != (int32_t) cpu)) ct = ct->next; if ((ct != NULL) && (ct->TS == 0xdeadbeef)) ct->TS = TS; else LOG_ERROR ("error in linux current thread update"); if (create) { struct threads *t; t = calloc(1, sizeof(struct threads)); t->base_addr = ct->TS; fill_task(target, t); get_name(target, t); t->oncpu = cpu; insert_into_threadlist(target, t); t->status = 3; t->thread_info_addr = 0xdeadbeef; ct->threadid = t->threadid; linux_os->thread_count++; #ifdef PID_CHECK ct->pid = t->pid; #endif /*LOG_INFO("Creation of current thread %s",t->name);*/ } } } free(reg_list); head = head->next; } free(buffer); return ERROR_OK; } struct cpu_context *cpu_context_read(struct target *target, uint32_t base_addr, uint32_t *thread_info_addr_old) { struct cpu_context *context = calloc(1, sizeof(struct cpu_context)); uint32_t preempt_count_addr = 0; uint32_t registers[10]; uint8_t *buffer = calloc(1, 4); uint32_t stack = base_addr + QAT; uint32_t thread_info_addr = 0; uint32_t thread_info_addr_update = 0; int retval = ERROR_FAIL; context->R4 = 0xdeadbeef; context->R5 = 0xdeadbeef; context->R6 = 0xdeadbeef; context->R7 = 0xdeadbeef; context->R8 = 0xdeadbeef; context->R9 = 0xdeadbeef; context->IP = 0xdeadbeef; context->FP = 0xdeadbeef; context->SP = 0xdeadbeef; context->PC = 0xdeadbeef; retry: if (*thread_info_addr_old == 0xdeadbeef) { retval = fill_buffer(target, stack, buffer); if (retval == ERROR_OK) thread_info_addr = get_buffer(target, buffer); else LOG_ERROR("cpu_context: unable to read memory"); thread_info_addr_update = thread_info_addr; } else thread_info_addr = *thread_info_addr_old; preempt_count_addr = thread_info_addr + PREEMPT; retval = fill_buffer(target, preempt_count_addr, buffer); if (retval == ERROR_OK) context->preempt_count = get_buffer(target, buffer); else { if (*thread_info_addr_old != 0xdeadbeef) { LOG_ERROR ("cpu_context: cannot read at thread_info_addr"); if (*thread_info_addr_old < LINUX_USER_KERNEL_BORDER) LOG_INFO ("cpu_context : thread_info_addr in userspace!!!"); *thread_info_addr_old = 0xdeadbeef; goto retry; } LOG_ERROR("cpu_context: unable to read memory"); } thread_info_addr += CPU_CONT; retval = linux_read_memory(target, thread_info_addr, 4, 10, (uint8_t *) registers); if (retval != ERROR_OK) { free(buffer); LOG_ERROR("cpu_context: unable to read memory\n"); return context; } context->R4 = target_buffer_get_u32(target, (const uint8_t *)®isters[0]); context->R5 = target_buffer_get_u32(target, (const uint8_t *)®isters[1]); context->R6 = target_buffer_get_u32(target, (const uint8_t *)®isters[2]); context->R7 = target_buffer_get_u32(target, (const uint8_t *)®isters[3]); context->R8 = target_buffer_get_u32(target, (const uint8_t *)®isters[4]); context->R9 = target_buffer_get_u32(target, (const uint8_t *)®isters[5]); context->IP = target_buffer_get_u32(target, (const uint8_t *)®isters[6]); context->FP = target_buffer_get_u32(target, (const uint8_t *)®isters[7]); context->SP = target_buffer_get_u32(target, (const uint8_t *)®isters[8]); context->PC = target_buffer_get_u32(target, (const uint8_t *)®isters[9]); if (*thread_info_addr_old == 0xdeadbeef) *thread_info_addr_old = thread_info_addr_update; free(buffer); return context; } uint32_t next_task(struct target *target, struct threads *t) { uint8_t *buffer = calloc(1, 4); uint32_t next_addr = t->base_addr + NEXT; int retval = fill_buffer(target, next_addr, buffer); if (retval == ERROR_OK) { uint32_t val = get_buffer(target, buffer); val = val - NEXT; free(buffer); return val; } else LOG_ERROR("next task: unable to read memory"); free(buffer); return 0; } struct current_thread *add_current_thread(struct current_thread *currents, struct current_thread *ct) { ct->next = NULL; if (currents == NULL) { currents = ct; return currents; } else { struct current_thread *temp = currents; while (temp->next != NULL) temp = temp->next; temp->next = ct; return currents; } } struct threads *liste_del_task(struct threads *task_list, struct threads **t, struct threads *prev) { LOG_INFO("del task %" PRId64, (*t)->threadid); prev->next = (*t)->next; if (prev == task_list) task_list = prev; /* free content of threads */ if ((*t)->context) free((*t)->context); free(*t); *t = prev; return task_list; } struct threads *liste_add_task(struct threads *task_list, struct threads *t, struct threads **last) { t->next = NULL; if (*last == NULL) if (task_list == NULL) { task_list = t; return task_list; } else { struct threads *temp = task_list; while (temp->next != NULL) temp = temp->next; temp->next = t; *last = t; return task_list; } else { (*last)->next = t; *last = t; return task_list; } } #ifdef PID_CHECK static int current_pid(struct linux_os *linux_os, uint32_t pid) #else static int current_base_addr(struct linux_os *linux_os, uint32_t base_addr) #endif { struct current_thread *ct = linux_os->current_threads; #ifdef PID_CHECK while ((ct != NULL) && (ct->pid != pid)) #else while ((ct != NULL) && (ct->TS != base_addr)) #endif ct = ct->next; #ifdef PID_CHECK if ((ct != NULL) && (ct->pid == pid)) #else if ((ct != NULL) && (ct->TS == base_addr)) #endif return 1; return 0; } int linux_get_tasks(struct target *target, int context) { int loop = 0; int retval = 0; struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; linux_os->thread_list = NULL; linux_os->thread_count = 0; if (linux_os->init_task_addr == 0xdeadbeef) { LOG_INFO("no init symbol\n"); return ERROR_FAIL; } int64_t start = timeval_ms(); struct threads *t = calloc(1, sizeof(struct threads)); struct threads *last = NULL; t->base_addr = linux_os->init_task_addr; /* retrieve the thread id , currently running in the different smp core */ get_current(target, 1); while (((t->base_addr != linux_os->init_task_addr) && (t->base_addr != 0)) || (loop == 0)) { loop++; fill_task(target, t); retval = get_name(target, t); if (loop > MAX_THREADS) { free(t); LOG_INFO("more than %d threads !!", MAX_THREADS); return ERROR_FAIL; } if (retval != ERROR_OK) { free(t); return ERROR_FAIL; } /* check that this thread is not one the current threads already * created */ #ifdef PID_CHECK if (!current_pid(linux_os, t->pid)) { #else if (!current_base_addr(linux_os, t->base_addr)) { #endif t->threadid = linux_os->threadid_count; t->status = 1; linux_os->threadid_count++; linux_os->thread_list = liste_add_task(linux_os->thread_list, t, &last); /* no interest to fill the context if it is a current thread. */ linux_os->thread_count++; t->thread_info_addr = 0xdeadbeef; if (context) t->context = cpu_context_read(target, t->base_addr, &t->thread_info_addr); } else { /*LOG_INFO("thread %s is a current thread already created",t->name); */ free(t); } uint32_t base_addr = next_task(target, t); t = calloc(1, sizeof(struct threads)); t->base_addr = base_addr; } linux_os->threads_lookup = 1; linux_os->threads_needs_update = 0; linux_os->preupdtate_threadid_count = linux_os->threadid_count - 1; /* check that all current threads have been identified */ LOG_INFO("complete time %" PRId64 ", thread mean %" PRId64 "\n", (timeval_ms() - start), (timeval_ms() - start) / linux_os->threadid_count); LOG_INFO("threadid count %d", linux_os->threadid_count); free(t); return ERROR_OK; } static int clean_threadlist(struct target *target) { struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; struct threads *old, *temp = linux_os->thread_list; while (temp != NULL) { old = temp; if (temp->context) free(temp->context); temp = temp->next; free(old); } return ERROR_OK; } static int linux_os_clean(struct target *target) { struct linux_os *os_linux = (struct linux_os *) target->rtos->rtos_specific_params; clean_threadlist(target); os_linux->init_task_addr = 0xdeadbeef; os_linux->name = "linux"; os_linux->thread_list = NULL; os_linux->thread_count = 0; os_linux->nr_cpus = 0; os_linux->threads_lookup = 0; os_linux->threads_needs_update = 0; os_linux->threadid_count = 1; return ERROR_OK; } static int insert_into_threadlist(struct target *target, struct threads *t) { struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; struct threads *temp = linux_os->thread_list; t->threadid = linux_os->threadid_count; linux_os->threadid_count++; t->status = 1; t->next = NULL; if (temp == NULL) linux_os->thread_list = t; else { while (temp->next != NULL) temp = temp->next; t->next = NULL; temp->next = t; } return ERROR_OK; } static void linux_identify_current_threads(struct target *target) { struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; struct threads *thread_list = linux_os->thread_list; struct current_thread *ct = linux_os->current_threads; struct threads *t = NULL; while ((ct != NULL)) { if (ct->threadid == -1) { /* un-identified thread */ int found = 0; t = calloc(1, sizeof(struct threads)); t->base_addr = ct->TS; #ifdef PID_CHECK if (fill_task_pid(target, t) != ERROR_OK) { error_handling: free(t); LOG_ERROR ("linux identify_current_threads: unable to read pid"); return; } #endif /* search in the list of threads if pid already present */ while ((thread_list != NULL) && (found == 0)) { #ifdef PID_CHECK if (thread_list->pid == t->pid) { #else if (thread_list->base_addr == t->base_addr) { #endif free(t); t = thread_list; found = 1; } thread_list = thread_list->next; } if (!found) { /* it is a new thread */ if (fill_task(target, t) != ERROR_OK) goto error_handling; get_name(target, t); insert_into_threadlist(target, t); t->thread_info_addr = 0xdeadbeef; } t->status = 3; ct->threadid = t->threadid; #ifdef PID_CHECK ct->pid = t->pid; #endif linux_os->thread_count++; #if 0 if (found == 0) LOG_INFO("current thread core %x identified %s", ct->core_id, t->name); else LOG_INFO("current thread core %x, reused %s", ct->core_id, t->name); #endif } #if 0 else { struct threads tmp; tmp.base_addr = ct->TS; get_name(target, &tmp); LOG_INFO("current thread core %x , already identified %s !!!", ct->core_id, tmp.name); } #endif ct = ct->next; } return; #ifndef PID_CHECK error_handling: free(t); LOG_ERROR("unable to read pid"); return; #endif } static int linux_task_update(struct target *target, int context) { struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; struct threads *thread_list = linux_os->thread_list; int retval; int loop = 0; linux_os->thread_count = 0; /*thread_list = thread_list->next; skip init_task*/ while (thread_list != NULL) { thread_list->status = 0; /*setting all tasks to dead state*/ if (thread_list->context) { free(thread_list->context); thread_list->context = NULL; } thread_list = thread_list->next; } int found = 0; if (linux_os->init_task_addr == 0xdeadbeef) { LOG_INFO("no init symbol\n"); return ERROR_FAIL; } int64_t start = timeval_ms(); struct threads *t = calloc(1, sizeof(struct threads)); uint32_t previous = 0xdeadbeef; t->base_addr = linux_os->init_task_addr; retval = get_current(target, 0); /*check that all current threads have been identified */ linux_identify_current_threads(target); while (((t->base_addr != linux_os->init_task_addr) && (t->base_addr != previous)) || (loop == 0)) { /* for avoiding any permanent loop for any reason possibly due to * target */ loop++; previous = t->base_addr; /* read only pid */ #ifdef PID_CHECK retval = fill_task_pid(target, t); #endif if (retval != ERROR_OK) { free(t); return ERROR_FAIL; } thread_list = linux_os->thread_list; while (thread_list != NULL) { #ifdef PID_CHECK if (t->pid == thread_list->pid) { #else if (t->base_addr == thread_list->base_addr) { #endif if (!thread_list->status) { #ifdef PID_CHECK if (t->base_addr != thread_list->base_addr) LOG_INFO("thread base_addr has changed !!"); #endif /* this is not a current thread */ thread_list->base_addr = t->base_addr; thread_list->status = 1; /* we don 't update this field any more */ /*thread_list->state = t->state; thread_list->oncpu = t->oncpu; thread_list->asid = t->asid; */ if (context) thread_list->context = cpu_context_read(target, thread_list-> base_addr, &thread_list-> thread_info_addr); } else { /* it is a current thread no need to read context */ } linux_os->thread_count++; found = 1; break; } else { found = 0; thread_list = thread_list->next; } } if (found == 0) { uint32_t base_addr; fill_task(target, t); get_name(target, t); retval = insert_into_threadlist(target, t); t->thread_info_addr = 0xdeadbeef; if (context) t->context = cpu_context_read(target, t->base_addr, &t->thread_info_addr); base_addr = next_task(target, t); t = calloc(1, sizeof(struct threads)); t->base_addr = base_addr; linux_os->thread_count++; } else t->base_addr = next_task(target, t); } LOG_INFO("update thread done %" PRId64 ", mean%" PRId64 "\n", (timeval_ms() - start), (timeval_ms() - start) / loop); free(t); linux_os->threads_needs_update = 0; return ERROR_OK; } int linux_gdb_thread_packet(struct target *target, struct connection *connection, char *packet, int packet_size) { int retval; struct linux_os *linux_os = (struct linux_os *)target->rtos->rtos_specific_params; if (linux_os->init_task_addr == 0xdeadbeef) { /* it has not been initialized */ LOG_INFO("received thread request without init task address"); gdb_put_packet(connection, "l", 1); return ERROR_OK; } retval = linux_get_tasks(target, 1); if (retval != ERROR_OK) return ERROR_TARGET_FAILURE; char *out_str = (char *)calloc(1, 350 * sizeof(int64_t)); char *tmp_str = out_str; tmp_str += sprintf(tmp_str, "m"); struct threads *temp = linux_os->thread_list; tmp_str += sprintf(tmp_str, "%016" PRIx64, temp->threadid); temp = temp->next; while (temp != NULL) { tmp_str += sprintf(tmp_str, ","); tmp_str += sprintf(tmp_str, "%016" PRIx64, temp->threadid); temp = temp->next; } gdb_put_packet(connection, out_str, strlen(out_str)); return ERROR_OK; } int linux_gdb_thread_update(struct target *target, struct connection *connection, char *packet, int packet_size) { int found = 0; struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; struct threads *temp = linux_os->thread_list; while (temp != NULL) { if (temp->threadid == linux_os->preupdtate_threadid_count + 1) { /*LOG_INFO("FOUND");*/ found = 1; break; } else temp = temp->next; } if (found == 1) { /*LOG_INFO("INTO GDB THREAD UPDATE FOUNDING START TASK");*/ char *out_strr = (char *)calloc(1, 350 * sizeof(int64_t)); char *tmp_strr = out_strr; tmp_strr += sprintf(tmp_strr, "m"); /*LOG_INFO("CHAR MALLOC & M DONE");*/ tmp_strr += sprintf(tmp_strr, "%016" PRIx64, temp->threadid); temp = temp->next; while (temp != NULL) { /*LOG_INFO("INTO GDB THREAD UPDATE WHILE");*/ tmp_strr += sprintf(tmp_strr, ","); tmp_strr += sprintf(tmp_strr, "%016" PRIx64, temp->threadid); temp = temp->next; } /*tmp_str[0] = 0;*/ gdb_put_packet(connection, out_strr, strlen(out_strr)); linux_os->preupdtate_threadid_count = linux_os->threadid_count - 1; free(out_strr); } else gdb_put_packet(connection, "l", 1); return ERROR_OK; } int linux_thread_extra_info(struct target *target, struct connection *connection, char *packet, int packet_size) { int64_t threadid = 0; struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; sscanf(packet, "qThreadExtraInfo,%" SCNx64, &threadid); /*LOG_INFO("lookup extra info for thread %" SCNx64, threadid);*/ struct threads *temp = linux_os->thread_list; while (temp != NULL) { if (temp->threadid == threadid) { char *pid = " PID: "; char *pid_current = "*PID: "; char *name = "NAME: "; int str_size = strlen(pid) + strlen(name); char *tmp_str = (char *)calloc(1, str_size + 50); char *tmp_str_ptr = tmp_str; /* discriminate current task */ if (temp->status == 3) tmp_str_ptr += sprintf(tmp_str_ptr, "%s", pid_current); else tmp_str_ptr += sprintf(tmp_str_ptr, "%s", pid); tmp_str_ptr += sprintf(tmp_str_ptr, "%d", (int)temp->pid); tmp_str_ptr += sprintf(tmp_str_ptr, "%s", " | "); sprintf(tmp_str_ptr, "%s", name); sprintf(tmp_str_ptr, "%s", temp->name); char *hex_str = (char *)calloc(1, strlen(tmp_str) * 2 + 1); int pkt_len = hexify(hex_str, tmp_str, 0, strlen(tmp_str) * 2 + 1); gdb_put_packet(connection, hex_str, pkt_len); free(hex_str); free(tmp_str); return ERROR_OK; } temp = temp->next; } LOG_INFO("thread not found"); return ERROR_OK; } int linux_gdb_T_packet(struct connection *connection, struct target *target, char *packet, int packet_size) { int64_t threadid; struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; int retval = ERROR_OK; sscanf(packet, "T%" SCNx64, &threadid); if (linux_os->threads_needs_update == 0) { struct threads *temp = linux_os->thread_list; struct threads *prev = linux_os->thread_list; while (temp != NULL) { if (temp->threadid == threadid) { if (temp->status != 0) { gdb_put_packet(connection, "OK", 2); return ERROR_OK; } else { /* delete item in the list */ linux_os->thread_list = liste_del_task(linux_os-> thread_list, &temp, prev); linux_os->thread_count--; gdb_put_packet(connection, "E01", 3); return ERROR_OK; } } /* for deletion */ prev = temp; temp = temp->next; } LOG_INFO("gdb requested status on non existing thread"); gdb_put_packet(connection, "E01", 3); return ERROR_OK; } else { retval = linux_task_update(target, 1); struct threads *temp = linux_os->thread_list; while (temp != NULL) { if (temp->threadid == threadid) { if (temp->status == 1) { gdb_put_packet(connection, "OK", 2); return ERROR_OK; } else { gdb_put_packet(connection, "E01", 3); return ERROR_OK; } } temp = temp->next; } } return retval; } int linux_gdb_h_packet(struct connection *connection, struct target *target, char *packet, int packet_size) { struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; struct current_thread *ct = linux_os->current_threads; /* select to display the current thread of the selected target */ while ((ct != NULL) && (ct->core_id != target->coreid)) ct = ct->next; int64_t current_gdb_thread_rq; if (linux_os->threads_lookup == 1) { if ((ct != NULL) && (ct->threadid == -1)) { ct = linux_os->current_threads; while ((ct != NULL) && (ct->threadid == -1)) ct = ct->next; } if (ct == NULL) { /* no current thread can be identified * any way with smp */ LOG_INFO("no current thread identified"); /* attempt to display the name of the 2 threads identified with * get_current */ struct threads t; ct = linux_os->current_threads; while ((ct != NULL) && (ct->threadid == -1)) { t.base_addr = ct->TS; get_name(target, &t); LOG_INFO("name of unidentified thread %s", t.name); ct = ct->next; } gdb_put_packet(connection, "OK", 2); return ERROR_OK; } if (packet[1] == 'g') { sscanf(packet, "Hg%16" SCNx64, ¤t_gdb_thread_rq); if (current_gdb_thread_rq == 0) { target->rtos->current_threadid = ct->threadid; gdb_put_packet(connection, "OK", 2); } else { target->rtos->current_threadid = current_gdb_thread_rq; gdb_put_packet(connection, "OK", 2); } } else if (packet[1] == 'c') { sscanf(packet, "Hc%16" SCNx64, ¤t_gdb_thread_rq); if ((current_gdb_thread_rq == 0) || (current_gdb_thread_rq == ct->threadid)) { target->rtos->current_threadid = ct->threadid; gdb_put_packet(connection, "OK", 2); } else gdb_put_packet(connection, "E01", 3); } } else gdb_put_packet(connection, "OK", 2); return ERROR_OK; } static int linux_thread_packet(struct connection *connection, char *packet, int packet_size) { int retval = ERROR_OK; struct current_thread *ct; struct target *target = get_target_from_connection(connection); struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; switch (packet[0]) { case 'T': /* Is thread alive?*/ linux_gdb_T_packet(connection, target, packet, packet_size); break; case 'H': /* Set current thread */ /* ( 'c' for step and continue, 'g' for all other operations )*/ /*LOG_INFO(" H packet received '%s'", packet);*/ linux_gdb_h_packet(connection, target, packet, packet_size); break; case 'q': if (strncmp(packet, "qSymbol", 7) == 0) { if (rtos_qsymbol(connection, packet, packet_size) == 1) { linux_compute_virt2phys(target, target->rtos-> symbols[INIT_TASK]. address); } break; } else if (strncmp(packet, "qfThreadInfo", 12) == 0) { if (linux_os->thread_list == NULL) { retval = linux_gdb_thread_packet(target, connection, packet, packet_size); break; } else { retval = linux_gdb_thread_update(target, connection, packet, packet_size); break; } } else if (strncmp(packet, "qsThreadInfo", 12) == 0) { gdb_put_packet(connection, "l", 1); break; } else if (strncmp(packet, "qThreadExtraInfo,", 17) == 0) { linux_thread_extra_info(target, connection, packet, packet_size); break; } else { retval = GDB_THREAD_PACKET_NOT_CONSUMED; break; } case 'Q': /* previously response was : thread not found * gdb_put_packet(connection, "E01", 3); */ retval = GDB_THREAD_PACKET_NOT_CONSUMED; break; case 'c': case 's': { if (linux_os->threads_lookup == 1) { ct = linux_os->current_threads; while ((ct != NULL) && (ct->core_id) != target->coreid) ct = ct->next; if ((ct != NULL) && (ct->threadid == -1)) { ct = linux_os->current_threads; while ((ct != NULL) && (ct->threadid == -1)) ct = ct->next; } if ((ct != NULL) && (ct->threadid != target->rtos-> current_threadid) && (target->rtos->current_threadid != -1)) LOG_WARNING("WARNING! current GDB thread do not match" \ "current thread running." \ "Switch thread in GDB to threadid %d", (int)ct->threadid); LOG_INFO("threads_needs_update = 1"); linux_os->threads_needs_update = 1; } } /* if a packet handler returned an error, exit input loop */ if (retval != ERROR_OK) return retval; } return retval; } static int linux_os_smp_init(struct target *target) { struct target_list *head; /* keep only target->rtos */ struct rtos *rtos = target->rtos; struct linux_os *os_linux = (struct linux_os *)rtos->rtos_specific_params; struct current_thread *ct; head = target->head; while (head != (struct target_list *)NULL) { if (head->target->rtos != rtos) { struct linux_os *smp_os_linux = (struct linux_os *)head->target->rtos-> rtos_specific_params; /* remap smp target on rtos */ free(head->target->rtos); head->target->rtos = rtos; /* reuse allocated ct */ ct = smp_os_linux->current_threads; ct->threadid = -1; ct->TS = 0xdeadbeef; ct->core_id = head->target->coreid; os_linux->current_threads = add_current_thread(os_linux->current_threads, ct); os_linux->nr_cpus++; free(smp_os_linux); } head = head->next; } return ERROR_OK; } static int linux_os_create(struct target *target) { struct linux_os *os_linux = calloc(1, sizeof(struct linux_os)); struct current_thread *ct = calloc(1, sizeof(struct current_thread)); LOG_INFO("linux os creation\n"); os_linux->init_task_addr = 0xdeadbeef; os_linux->name = "linux"; os_linux->thread_list = NULL; os_linux->thread_count = 0; target->rtos->current_threadid = -1; os_linux->nr_cpus = 1; os_linux->threads_lookup = 0; os_linux->threads_needs_update = 0; os_linux->threadid_count = 1; os_linux->current_threads = NULL; target->rtos->rtos_specific_params = (void *)os_linux; ct->core_id = target->coreid; ct->threadid = -1; ct->TS = 0xdeadbeef; os_linux->current_threads = add_current_thread(os_linux->current_threads, ct); /* overload rtos thread default handler */ target->rtos->gdb_thread_packet = linux_thread_packet; /* initialize a default virt 2 phys translation */ os_linux->phys_mask = ~0xc0000000; os_linux->phys_base = 0x0; return JIM_OK; } static char *linux_ps_command(struct target *target) { struct linux_os *linux_os = (struct linux_os *) target->rtos->rtos_specific_params; int retval = ERROR_OK; char *display; if (linux_os->threads_lookup == 0) retval = linux_get_tasks(target, 1); else { if (linux_os->threads_needs_update != 0) retval = linux_task_update(target, 0); } if (retval == ERROR_OK) { struct threads *temp = linux_os->thread_list; char *tmp; LOG_INFO("allocation for %d threads line", linux_os->thread_count); display = calloc((linux_os->thread_count + 2) * 80, 1); if (!display) goto error; tmp = display; tmp += sprintf(tmp, "PID\t\tCPU\t\tASID\t\tNAME\n"); tmp += sprintf(tmp, "---\t\t---\t\t----\t\t----\n"); while (temp != NULL) { if (temp->status) { if (temp->context) tmp += sprintf(tmp, "%d\t\t%d\t\t%x\t\t%s\n", (int)temp->pid, temp->oncpu, temp->asid, temp->name); else tmp += sprintf(tmp, "%d\t\t%d\t\t%x\t\t%s\n", (int)temp->pid, temp->oncpu, temp->asid, temp->name); } temp = temp->next; } return display; } error: display = calloc(40, 1); sprintf(display, "linux_ps_command failed\n"); return display; } openocd-0.7.0/src/rtos/rtos_ecos_stackings.c0000644000175000001440000000460712134336410016056 00000000000000/*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "rtos.h" static const struct stack_register_offset rtos_eCos_Cortex_M3_stack_offsets[] = { { 0x0c, 32 }, /* r0 */ { 0x10, 32 }, /* r1 */ { 0x14, 32 }, /* r2 */ { 0x18, 32 }, /* r3 */ { 0x1c, 32 }, /* r4 */ { 0x20, 32 }, /* r5 */ { 0x24, 32 }, /* r6 */ { 0x28, 32 }, /* r7 */ { 0x2c, 32 }, /* r8 */ { 0x30, 32 }, /* r9 */ { 0x34, 32 }, /* r10 */ { 0x38, 32 }, /* r11 */ { 0x3c, 32 }, /* r12 */ { -2, 32 }, /* sp */ { -1, 32 }, /* lr */ { 0x40, 32 }, /* pc */ { -1, 96 }, /* FPA1 */ { -1, 96 }, /* FPA2 */ { -1, 96 }, /* FPA3 */ { -1, 96 }, /* FPA4 */ { -1, 96 }, /* FPA5 */ { -1, 96 }, /* FPA6 */ { -1, 96 }, /* FPA7 */ { -1, 96 }, /* FPA8 */ { -1, 32 }, /* FPS */ { -1, 32 }, /* xPSR */ }; const struct rtos_register_stacking rtos_eCos_Cortex_M3_stacking = { 0x44, /* stack_registers_size */ -1, /* stack_growth_direction */ 26, /* num_output_registers */ 8, /* stack_alignment */ rtos_eCos_Cortex_M3_stack_offsets /* register_offsets */ }; openocd-0.7.0/src/rtos/Makefile.in0000644000175000001440000007167212141414276013724 00000000000000# Makefile.in generated by automake 1.13.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # *************************************************************************** # * Copyright (C) 2011 by Broadcom Corporation * # * Evan Hunter - ehunter@broadcom.com * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU General Public License as published by * # * the Free Software Foundation; either version 2 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. * # *************************************************************************** VPATH = @srcdir@ am__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ DIST_COMMON = $(top_srcdir)/common.mk $(srcdir)/Makefile.in \ $(srcdir)/Makefile.am $(top_srcdir)/depcomp $(noinst_HEADERS) @INTERNAL_JIMTCL_TRUE@am__append_1 = -I$(top_srcdir)/jimtcl \ @INTERNAL_JIMTCL_TRUE@ -I$(top_builddir)/jimtcl # FD_* macros are sloppy with their signs on MinGW32 platform @IS_MINGW_TRUE@am__append_2 = -Wno-sign-compare subdir = src/rtos ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/config_subdir.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) librtos_la_LIBADD = am_librtos_la_OBJECTS = librtos_la-rtos.lo \ librtos_la-rtos_standard_stackings.lo \ librtos_la-rtos_ecos_stackings.lo \ librtos_la-rtos_chibios_stackings.lo librtos_la-FreeRTOS.lo \ librtos_la-ThreadX.lo librtos_la-eCos.lo librtos_la-linux.lo \ librtos_la-ChibiOS.lo librtos_la_OBJECTS = $(am_librtos_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = librtos_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(librtos_la_CFLAGS) \ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(librtos_la_SOURCES) DIST_SOURCES = $(librtos_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CC_FOR_BUILD = @CC_FOR_BUILD@ CFLAGS = @CFLAGS@ CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@ FGREP = @FGREP@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ doxygen_as_html = @doxygen_as_html@ doxygen_as_pdf = @doxygen_as_pdf@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ # common flags used in openocd build AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src \ -I$(top_srcdir)/src/helper -DPKGDATADIR=\"$(pkgdatadir)\" \ -DPKGLIBDIR=\"$(pkglibdir)\" $(am__append_1) METASOURCES = AUTO noinst_LTLIBRARIES = librtos.la noinst_HEADERS = rtos.h rtos_standard_stackings.h rtos_ecos_stackings.h linux_header.h rtos_chibios_stackings.h librtos_la_SOURCES = rtos.c rtos_standard_stackings.c rtos_ecos_stackings.c rtos_chibios_stackings.c FreeRTOS.c ThreadX.c eCos.c linux.c ChibiOS.c librtos_la_CFLAGS = $(am__append_2) MAINTAINERCLEANFILES = $(srcdir)/Makefile.in all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/common.mk $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/rtos/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/rtos/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_srcdir)/common.mk: $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } librtos.la: $(librtos_la_OBJECTS) $(librtos_la_DEPENDENCIES) $(EXTRA_librtos_la_DEPENDENCIES) $(AM_V_CCLD)$(librtos_la_LINK) $(librtos_la_OBJECTS) $(librtos_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/librtos_la-ChibiOS.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/librtos_la-FreeRTOS.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/librtos_la-ThreadX.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/librtos_la-eCos.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/librtos_la-linux.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/librtos_la-rtos.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/librtos_la-rtos_chibios_stackings.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/librtos_la-rtos_ecos_stackings.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/librtos_la-rtos_standard_stackings.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< librtos_la-rtos.lo: rtos.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librtos_la_CFLAGS) $(CFLAGS) -MT librtos_la-rtos.lo -MD -MP -MF $(DEPDIR)/librtos_la-rtos.Tpo -c -o librtos_la-rtos.lo `test -f 'rtos.c' || echo '$(srcdir)/'`rtos.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/librtos_la-rtos.Tpo $(DEPDIR)/librtos_la-rtos.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rtos.c' object='librtos_la-rtos.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librtos_la_CFLAGS) $(CFLAGS) -c -o librtos_la-rtos.lo `test -f 'rtos.c' || echo '$(srcdir)/'`rtos.c librtos_la-rtos_standard_stackings.lo: rtos_standard_stackings.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librtos_la_CFLAGS) $(CFLAGS) -MT librtos_la-rtos_standard_stackings.lo -MD -MP -MF $(DEPDIR)/librtos_la-rtos_standard_stackings.Tpo -c -o librtos_la-rtos_standard_stackings.lo `test -f 'rtos_standard_stackings.c' || echo '$(srcdir)/'`rtos_standard_stackings.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/librtos_la-rtos_standard_stackings.Tpo $(DEPDIR)/librtos_la-rtos_standard_stackings.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rtos_standard_stackings.c' object='librtos_la-rtos_standard_stackings.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librtos_la_CFLAGS) $(CFLAGS) -c -o librtos_la-rtos_standard_stackings.lo `test -f 'rtos_standard_stackings.c' || echo '$(srcdir)/'`rtos_standard_stackings.c librtos_la-rtos_ecos_stackings.lo: rtos_ecos_stackings.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librtos_la_CFLAGS) $(CFLAGS) -MT librtos_la-rtos_ecos_stackings.lo -MD -MP -MF $(DEPDIR)/librtos_la-rtos_ecos_stackings.Tpo -c -o librtos_la-rtos_ecos_stackings.lo `test -f 'rtos_ecos_stackings.c' || echo '$(srcdir)/'`rtos_ecos_stackings.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/librtos_la-rtos_ecos_stackings.Tpo $(DEPDIR)/librtos_la-rtos_ecos_stackings.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rtos_ecos_stackings.c' object='librtos_la-rtos_ecos_stackings.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librtos_la_CFLAGS) $(CFLAGS) -c -o librtos_la-rtos_ecos_stackings.lo `test -f 'rtos_ecos_stackings.c' || echo '$(srcdir)/'`rtos_ecos_stackings.c librtos_la-rtos_chibios_stackings.lo: rtos_chibios_stackings.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librtos_la_CFLAGS) $(CFLAGS) -MT librtos_la-rtos_chibios_stackings.lo -MD -MP -MF $(DEPDIR)/librtos_la-rtos_chibios_stackings.Tpo -c -o librtos_la-rtos_chibios_stackings.lo `test -f 'rtos_chibios_stackings.c' || echo '$(srcdir)/'`rtos_chibios_stackings.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/librtos_la-rtos_chibios_stackings.Tpo $(DEPDIR)/librtos_la-rtos_chibios_stackings.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rtos_chibios_stackings.c' object='librtos_la-rtos_chibios_stackings.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librtos_la_CFLAGS) $(CFLAGS) -c -o librtos_la-rtos_chibios_stackings.lo `test -f 'rtos_chibios_stackings.c' || echo '$(srcdir)/'`rtos_chibios_stackings.c librtos_la-FreeRTOS.lo: FreeRTOS.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librtos_la_CFLAGS) $(CFLAGS) -MT librtos_la-FreeRTOS.lo -MD -MP -MF $(DEPDIR)/librtos_la-FreeRTOS.Tpo -c -o librtos_la-FreeRTOS.lo `test -f 'FreeRTOS.c' || echo '$(srcdir)/'`FreeRTOS.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/librtos_la-FreeRTOS.Tpo $(DEPDIR)/librtos_la-FreeRTOS.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='FreeRTOS.c' object='librtos_la-FreeRTOS.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librtos_la_CFLAGS) $(CFLAGS) -c -o librtos_la-FreeRTOS.lo `test -f 'FreeRTOS.c' || echo '$(srcdir)/'`FreeRTOS.c librtos_la-ThreadX.lo: ThreadX.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librtos_la_CFLAGS) $(CFLAGS) -MT librtos_la-ThreadX.lo -MD -MP -MF $(DEPDIR)/librtos_la-ThreadX.Tpo -c -o librtos_la-ThreadX.lo `test -f 'ThreadX.c' || echo '$(srcdir)/'`ThreadX.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/librtos_la-ThreadX.Tpo $(DEPDIR)/librtos_la-ThreadX.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ThreadX.c' object='librtos_la-ThreadX.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librtos_la_CFLAGS) $(CFLAGS) -c -o librtos_la-ThreadX.lo `test -f 'ThreadX.c' || echo '$(srcdir)/'`ThreadX.c librtos_la-eCos.lo: eCos.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librtos_la_CFLAGS) $(CFLAGS) -MT librtos_la-eCos.lo -MD -MP -MF $(DEPDIR)/librtos_la-eCos.Tpo -c -o librtos_la-eCos.lo `test -f 'eCos.c' || echo '$(srcdir)/'`eCos.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/librtos_la-eCos.Tpo $(DEPDIR)/librtos_la-eCos.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='eCos.c' object='librtos_la-eCos.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librtos_la_CFLAGS) $(CFLAGS) -c -o librtos_la-eCos.lo `test -f 'eCos.c' || echo '$(srcdir)/'`eCos.c librtos_la-linux.lo: linux.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librtos_la_CFLAGS) $(CFLAGS) -MT librtos_la-linux.lo -MD -MP -MF $(DEPDIR)/librtos_la-linux.Tpo -c -o librtos_la-linux.lo `test -f 'linux.c' || echo '$(srcdir)/'`linux.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/librtos_la-linux.Tpo $(DEPDIR)/librtos_la-linux.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='linux.c' object='librtos_la-linux.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librtos_la_CFLAGS) $(CFLAGS) -c -o librtos_la-linux.lo `test -f 'linux.c' || echo '$(srcdir)/'`linux.c librtos_la-ChibiOS.lo: ChibiOS.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librtos_la_CFLAGS) $(CFLAGS) -MT librtos_la-ChibiOS.lo -MD -MP -MF $(DEPDIR)/librtos_la-ChibiOS.Tpo -c -o librtos_la-ChibiOS.lo `test -f 'ChibiOS.c' || echo '$(srcdir)/'`ChibiOS.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/librtos_la-ChibiOS.Tpo $(DEPDIR)/librtos_la-ChibiOS.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ChibiOS.c' object='librtos_la-ChibiOS.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(librtos_la_CFLAGS) $(CFLAGS) -c -o librtos_la-ChibiOS.lo `test -f 'ChibiOS.c' || echo '$(srcdir)/'`ChibiOS.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: openocd-0.7.0/src/rtos/ThreadX.c0000644000175000001440000003274712137175623013367 00000000000000/*************************************************************************** * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "target/target.h" #include "target/target_type.h" #include "rtos.h" #include "helper/log.h" #include "helper/types.h" #include "rtos_standard_stackings.h" static int ThreadX_detect_rtos(struct target *target); static int ThreadX_create(struct target *target); static int ThreadX_update_threads(struct rtos *rtos); static int ThreadX_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list); static int ThreadX_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]); struct ThreadX_thread_state { int value; char *desc; }; struct ThreadX_thread_state ThreadX_thread_states[] = { { 0, "Ready" }, { 1, "Completed" }, { 2, "Terminated" }, { 3, "Suspended" }, { 4, "Sleeping" }, { 5, "Waiting - Queue" }, { 6, "Waiting - Semaphore" }, { 7, "Waiting - Event flag" }, { 8, "Waiting - Memory" }, { 9, "Waiting - Memory" }, { 10, "Waiting - I/O" }, { 11, "Waiting - Filesystem" }, { 12, "Waiting - Network" }, { 13, "Waiting - Mutex" }, }; #define THREADX_NUM_STATES (sizeof(ThreadX_thread_states)/sizeof(struct ThreadX_thread_state)) struct ThreadX_params { char *target_name; unsigned char pointer_width; unsigned char thread_stack_offset; unsigned char thread_name_offset; unsigned char thread_state_offset; unsigned char thread_next_offset; const struct rtos_register_stacking *stacking_info; }; const struct ThreadX_params ThreadX_params_list[] = { { "cortex_m", /* target_name */ 4, /* pointer_width; */ 8, /* thread_stack_offset; */ 40, /* thread_name_offset; */ 48, /* thread_state_offset; */ 136, /* thread_next_offset */ &rtos_standard_Cortex_M3_stacking, /* stacking_info */ }, { "cortex_r4", /* target_name */ 4, /* pointer_width; */ 8, /* thread_stack_offset; */ 40, /* thread_name_offset; */ 48, /* thread_state_offset; */ 136, /* thread_next_offset */ &rtos_standard_Cortex_R4_stacking, /* stacking_info */ }, }; #define THREADX_NUM_PARAMS ((int)(sizeof(ThreadX_params_list)/sizeof(struct ThreadX_params))) enum ThreadX_symbol_values { ThreadX_VAL_tx_thread_current_ptr = 0, ThreadX_VAL_tx_thread_created_ptr = 1, ThreadX_VAL_tx_thread_created_count = 2, }; static char *ThreadX_symbol_list[] = { "_tx_thread_current_ptr", "_tx_thread_created_ptr", "_tx_thread_created_count", NULL }; const struct rtos_type ThreadX_rtos = { .name = "ThreadX", .detect_rtos = ThreadX_detect_rtos, .create = ThreadX_create, .update_threads = ThreadX_update_threads, .get_thread_reg_list = ThreadX_get_thread_reg_list, .get_symbol_list_to_lookup = ThreadX_get_symbol_list_to_lookup, }; static int ThreadX_update_threads(struct rtos *rtos) { int retval; int tasks_found = 0; int thread_list_size = 0; const struct ThreadX_params *param; if (rtos == NULL) return -1; if (rtos->rtos_specific_params == NULL) return -3; param = (const struct ThreadX_params *) rtos->rtos_specific_params; if (rtos->symbols == NULL) { LOG_ERROR("No symbols for ThreadX"); return -4; } if (rtos->symbols[ThreadX_VAL_tx_thread_created_count].address == 0) { LOG_ERROR("Don't have the number of threads in ThreadX"); return -2; } /* read the number of threads */ retval = target_read_buffer(rtos->target, rtos->symbols[ThreadX_VAL_tx_thread_created_count].address, 4, (uint8_t *)&thread_list_size); if (retval != ERROR_OK) { LOG_ERROR("Could not read ThreadX thread count from target"); return retval; } /* wipe out previous thread details if any */ if (rtos->thread_details != NULL) { int j; for (j = 0; j < rtos->thread_count; j++) { if (rtos->thread_details[j].display_str != NULL) { free(rtos->thread_details[j].display_str); rtos->thread_details[j].display_str = NULL; } if (rtos->thread_details[j].thread_name_str != NULL) { free(rtos->thread_details[j].thread_name_str); rtos->thread_details[j].thread_name_str = NULL; } if (rtos->thread_details[j].extra_info_str != NULL) { free(rtos->thread_details[j].extra_info_str); rtos->thread_details[j].extra_info_str = NULL; } } free(rtos->thread_details); rtos->thread_details = NULL; } /* read the current thread id */ retval = target_read_buffer(rtos->target, rtos->symbols[ThreadX_VAL_tx_thread_current_ptr].address, 4, (uint8_t *)&rtos->current_thread); if (retval != ERROR_OK) { LOG_ERROR("Could not read ThreadX current thread from target"); return retval; } if ((thread_list_size == 0) || (rtos->current_thread == 0)) { /* Either : No RTOS threads - there is always at least the current execution though */ /* OR : No current thread - all threads suspended - show the current execution * of idling */ char tmp_str[] = "Current Execution"; thread_list_size++; tasks_found++; rtos->thread_details = (struct thread_detail *) malloc( sizeof(struct thread_detail) * thread_list_size); rtos->thread_details->threadid = 1; rtos->thread_details->exists = true; rtos->thread_details->display_str = NULL; rtos->thread_details->extra_info_str = NULL; rtos->thread_details->thread_name_str = (char *) malloc(sizeof(tmp_str)); strcpy(rtos->thread_details->thread_name_str, tmp_str); if (thread_list_size == 0) { rtos->thread_count = 1; return ERROR_OK; } } else { /* create space for new thread details */ rtos->thread_details = (struct thread_detail *) malloc( sizeof(struct thread_detail) * thread_list_size); } /* Read the pointer to the first thread */ int64_t thread_ptr = 0; retval = target_read_buffer(rtos->target, rtos->symbols[ThreadX_VAL_tx_thread_created_ptr].address, param->pointer_width, (uint8_t *)&thread_ptr); if (retval != ERROR_OK) { LOG_ERROR("Could not read ThreadX thread location from target"); return retval; } /* loop over all threads */ int64_t prev_thread_ptr = 0; while ((thread_ptr != prev_thread_ptr) && (tasks_found < thread_list_size)) { #define THREADX_THREAD_NAME_STR_SIZE (200) char tmp_str[THREADX_THREAD_NAME_STR_SIZE]; unsigned int i = 0; int64_t name_ptr = 0; /* Save the thread pointer */ rtos->thread_details[tasks_found].threadid = thread_ptr; /* read the name pointer */ retval = target_read_buffer(rtos->target, thread_ptr + param->thread_name_offset, param->pointer_width, (uint8_t *)&name_ptr); if (retval != ERROR_OK) { LOG_ERROR("Could not read ThreadX thread name pointer from target"); return retval; } /* Read the thread name */ retval = target_read_buffer(rtos->target, name_ptr, THREADX_THREAD_NAME_STR_SIZE, (uint8_t *)&tmp_str); if (retval != ERROR_OK) { LOG_ERROR("Error reading thread name from ThreadX target"); return retval; } tmp_str[THREADX_THREAD_NAME_STR_SIZE-1] = '\x00'; if (tmp_str[0] == '\x00') strcpy(tmp_str, "No Name"); rtos->thread_details[tasks_found].thread_name_str = (char *)malloc(strlen(tmp_str)+1); strcpy(rtos->thread_details[tasks_found].thread_name_str, tmp_str); /* Read the thread status */ int64_t thread_status = 0; retval = target_read_buffer(rtos->target, thread_ptr + param->thread_state_offset, 4, (uint8_t *)&thread_status); if (retval != ERROR_OK) { LOG_ERROR("Error reading thread state from ThreadX target"); return retval; } for (i = 0; (i < THREADX_NUM_STATES) && (ThreadX_thread_states[i].value != thread_status); i++) { /* empty */ } char *state_desc; if (i < THREADX_NUM_STATES) state_desc = ThreadX_thread_states[i].desc; else state_desc = "Unknown state"; rtos->thread_details[tasks_found].extra_info_str = (char *)malloc(strlen( state_desc)+1); strcpy(rtos->thread_details[tasks_found].extra_info_str, state_desc); rtos->thread_details[tasks_found].exists = true; rtos->thread_details[tasks_found].display_str = NULL; tasks_found++; prev_thread_ptr = thread_ptr; /* Get the location of the next thread structure. */ thread_ptr = 0; retval = target_read_buffer(rtos->target, prev_thread_ptr + param->thread_next_offset, param->pointer_width, (uint8_t *) &thread_ptr); if (retval != ERROR_OK) { LOG_ERROR("Error reading next thread pointer in ThreadX thread list"); return retval; } } rtos->thread_count = tasks_found; return 0; } static int ThreadX_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list) { int retval; const struct ThreadX_params *param; *hex_reg_list = NULL; if (rtos == NULL) return -1; if (thread_id == 0) return -2; if (rtos->rtos_specific_params == NULL) return -3; param = (const struct ThreadX_params *) rtos->rtos_specific_params; /* Read the stack pointer */ int64_t stack_ptr = 0; retval = target_read_buffer(rtos->target, thread_id + param->thread_stack_offset, param->pointer_width, (uint8_t *)&stack_ptr); if (retval != ERROR_OK) { LOG_ERROR("Error reading stack frame from ThreadX thread"); return retval; } return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, hex_reg_list); } static int ThreadX_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) { unsigned int i; *symbol_list = (symbol_table_elem_t *) malloc( sizeof(symbol_table_elem_t) * ARRAY_SIZE(ThreadX_symbol_list)); for (i = 0; i < ARRAY_SIZE(ThreadX_symbol_list); i++) (*symbol_list)[i].symbol_name = ThreadX_symbol_list[i]; return 0; } static int ThreadX_detect_rtos(struct target *target) { if ((target->rtos->symbols != NULL) && (target->rtos->symbols[ThreadX_VAL_tx_thread_created_ptr].address != 0)) { /* looks like ThreadX */ return 1; } return 0; } #if 0 static int ThreadX_set_current_thread(struct rtos *rtos, threadid_t thread_id) { return 0; } static int ThreadX_get_thread_detail(struct rtos *rtos, threadid_t thread_id, struct thread_detail *detail) { unsigned int i = 0; int retval; #define THREADX_THREAD_NAME_STR_SIZE (200) char tmp_str[THREADX_THREAD_NAME_STR_SIZE]; const struct ThreadX_params *param; if (rtos == NULL) return -1; if (thread_id == 0) return -2; if (rtos->rtos_specific_params == NULL) return -3; param = (const struct ThreadX_params *) rtos->rtos_specific_params; if (rtos->symbols == NULL) { LOG_ERROR("No symbols for ThreadX"); return -3; } detail->threadid = thread_id; int64_t name_ptr = 0; /* read the name pointer */ retval = target_read_buffer(rtos->target, thread_id + param->thread_name_offset, param->pointer_width, (uint8_t *)&name_ptr); if (retval != ERROR_OK) { LOG_ERROR("Could not read ThreadX thread name pointer from target"); return retval; } /* Read the thread name */ retval = target_read_buffer(rtos->target, name_ptr, THREADX_THREAD_NAME_STR_SIZE, (uint8_t *)&tmp_str); if (retval != ERROR_OK) { LOG_ERROR("Error reading thread name from ThreadX target"); return retval; } tmp_str[THREADX_THREAD_NAME_STR_SIZE-1] = '\x00'; if (tmp_str[0] == '\x00') strcpy(tmp_str, "No Name"); detail->thread_name_str = (char *)malloc(strlen(tmp_str)+1); /* Read the thread status */ int64_t thread_status = 0; retval = target_read_buffer(rtos->target, thread_id + param->thread_state_offset, 4, (uint8_t *)&thread_status); if (retval != ERROR_OK) { LOG_ERROR("Error reading thread state from ThreadX target"); return retval; } for (i = 0; (i < THREADX_NUM_STATES) && (ThreadX_thread_states[i].value != thread_status); i++) { /* empty */ } char *state_desc; if (i < THREADX_NUM_STATES) state_desc = ThreadX_thread_states[i].desc; else state_desc = "Unknown state"; detail->extra_info_str = (char *)malloc(strlen(state_desc)+1); detail->exists = true; detail->display_str = NULL; return 0; } #endif static int ThreadX_create(struct target *target) { int i = 0; while ((i < THREADX_NUM_PARAMS) && (0 != strcmp(ThreadX_params_list[i].target_name, target->type->name))) { i++; } if (i >= THREADX_NUM_PARAMS) { LOG_ERROR("Could not find target in ThreadX compatibility list"); return -1; } target->rtos->rtos_specific_params = (void *) &ThreadX_params_list[i]; target->rtos->current_thread = 0; target->rtos->thread_details = NULL; return 0; } openocd-0.7.0/src/rtos/eCos.c0000644000175000001440000002736312137175623012717 00000000000000/*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "target/target.h" #include "target/target_type.h" #include "rtos.h" #include "helper/log.h" #include "helper/types.h" #include "rtos_ecos_stackings.h" static int eCos_detect_rtos(struct target *target); static int eCos_create(struct target *target); static int eCos_update_threads(struct rtos *rtos); static int eCos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list); static int eCos_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]); struct eCos_thread_state { int value; char *desc; }; struct eCos_thread_state eCos_thread_states[] = { { 0, "Ready" }, { 1, "Sleeping" }, { 2, "Countsleep" }, { 4, "Suspended" }, { 8, "Creating" }, { 16, "Exited" } }; #define ECOS_NUM_STATES (sizeof(eCos_thread_states)/sizeof(struct eCos_thread_state)) struct eCos_params { char *target_name; unsigned char pointer_width; unsigned char thread_stack_offset; unsigned char thread_name_offset; unsigned char thread_state_offset; unsigned char thread_next_offset; unsigned char thread_uniqueid_offset; const struct rtos_register_stacking *stacking_info; }; const struct eCos_params eCos_params_list[] = { { "cortex_m", /* target_name */ 4, /* pointer_width; */ 0x0c, /* thread_stack_offset; */ 0x9c, /* thread_name_offset; */ 0x3c, /* thread_state_offset; */ 0xa0, /* thread_next_offset */ 0x4c, /* thread_uniqueid_offset */ &rtos_eCos_Cortex_M3_stacking /* stacking_info */ } }; #define ECOS_NUM_PARAMS ((int)(sizeof(eCos_params_list)/sizeof(struct eCos_params))) enum eCos_symbol_values { eCos_VAL_thread_list = 0, eCos_VAL_current_thread_ptr = 1 }; static char *eCos_symbol_list[] = { "Cyg_Thread::thread_list", "Cyg_Scheduler_Base::current_thread", NULL }; const struct rtos_type eCos_rtos = { .name = "eCos", .detect_rtos = eCos_detect_rtos, .create = eCos_create, .update_threads = eCos_update_threads, .get_thread_reg_list = eCos_get_thread_reg_list, .get_symbol_list_to_lookup = eCos_get_symbol_list_to_lookup, }; static int eCos_update_threads(struct rtos *rtos) { int retval; int tasks_found = 0; int thread_list_size = 0; const struct eCos_params *param; if (rtos == NULL) return -1; if (rtos->rtos_specific_params == NULL) return -3; param = (const struct eCos_params *) rtos->rtos_specific_params; if (rtos->symbols == NULL) { LOG_ERROR("No symbols for eCos"); return -4; } if (rtos->symbols[eCos_VAL_thread_list].address == 0) { LOG_ERROR("Don't have the thread list head"); return -2; } /* wipe out previous thread details if any */ if (rtos->thread_details != NULL) { int j; for (j = 0; j < rtos->thread_count; j++) { if (rtos->thread_details[j].display_str != NULL) { free(rtos->thread_details[j].display_str); rtos->thread_details[j].display_str = NULL; } if (rtos->thread_details[j].thread_name_str != NULL) { free(rtos->thread_details[j].thread_name_str); rtos->thread_details[j].thread_name_str = NULL; } if (rtos->thread_details[j].extra_info_str != NULL) { free(rtos->thread_details[j].extra_info_str); rtos->thread_details[j].extra_info_str = NULL; } } free(rtos->thread_details); rtos->thread_details = NULL; } /* determine the number of current threads */ uint32_t thread_list_head = rtos->symbols[eCos_VAL_thread_list].address; uint32_t thread_index; target_read_buffer(rtos->target, thread_list_head, param->pointer_width, (uint8_t *) &thread_index); uint32_t first_thread = thread_index; do { thread_list_size++; retval = target_read_buffer(rtos->target, thread_index + param->thread_next_offset, param->pointer_width, (uint8_t *) &thread_index); if (retval != ERROR_OK) return retval; } while (thread_index != first_thread); /* read the current thread id */ uint32_t current_thread_addr; retval = target_read_buffer(rtos->target, rtos->symbols[eCos_VAL_current_thread_ptr].address, 4, (uint8_t *)¤t_thread_addr); if (retval != ERROR_OK) return retval; rtos->current_thread = 0; retval = target_read_buffer(rtos->target, current_thread_addr + param->thread_uniqueid_offset, 2, (uint8_t *)&rtos->current_thread); if (retval != ERROR_OK) { LOG_ERROR("Could not read eCos current thread from target"); return retval; } if ((thread_list_size == 0) || (rtos->current_thread == 0)) { /* Either : No RTOS threads - there is always at least the current execution though */ /* OR : No current thread - all threads suspended - show the current execution * of idling */ char tmp_str[] = "Current Execution"; thread_list_size++; tasks_found++; rtos->thread_details = (struct thread_detail *) malloc( sizeof(struct thread_detail) * thread_list_size); rtos->thread_details->threadid = 1; rtos->thread_details->exists = true; rtos->thread_details->display_str = NULL; rtos->thread_details->extra_info_str = NULL; rtos->thread_details->thread_name_str = (char *) malloc(sizeof(tmp_str)); strcpy(rtos->thread_details->thread_name_str, tmp_str); if (thread_list_size == 0) { rtos->thread_count = 1; return ERROR_OK; } } else { /* create space for new thread details */ rtos->thread_details = (struct thread_detail *) malloc( sizeof(struct thread_detail) * thread_list_size); } /* loop over all threads */ thread_index = first_thread; do { #define ECOS_THREAD_NAME_STR_SIZE (200) char tmp_str[ECOS_THREAD_NAME_STR_SIZE]; unsigned int i = 0; uint32_t name_ptr = 0; uint32_t prev_thread_ptr; /* Save the thread pointer */ uint16_t thread_id; retval = target_read_buffer(rtos->target, thread_index + param->thread_uniqueid_offset, 2, (uint8_t *)&thread_id); if (retval != ERROR_OK) { LOG_ERROR("Could not read eCos thread id from target"); return retval; } rtos->thread_details[tasks_found].threadid = thread_id; /* read the name pointer */ retval = target_read_buffer(rtos->target, thread_index + param->thread_name_offset, param->pointer_width, (uint8_t *)&name_ptr); if (retval != ERROR_OK) { LOG_ERROR("Could not read eCos thread name pointer from target"); return retval; } /* Read the thread name */ retval = target_read_buffer(rtos->target, name_ptr, ECOS_THREAD_NAME_STR_SIZE, (uint8_t *)&tmp_str); if (retval != ERROR_OK) { LOG_ERROR("Error reading thread name from eCos target"); return retval; } tmp_str[ECOS_THREAD_NAME_STR_SIZE-1] = '\x00'; if (tmp_str[0] == '\x00') strcpy(tmp_str, "No Name"); rtos->thread_details[tasks_found].thread_name_str = (char *)malloc(strlen(tmp_str)+1); strcpy(rtos->thread_details[tasks_found].thread_name_str, tmp_str); /* Read the thread status */ int64_t thread_status = 0; retval = target_read_buffer(rtos->target, thread_index + param->thread_state_offset, 4, (uint8_t *)&thread_status); if (retval != ERROR_OK) { LOG_ERROR("Error reading thread state from eCos target"); return retval; } for (i = 0; (i < ECOS_NUM_STATES) && (eCos_thread_states[i].value != thread_status); i++) { /* * empty */ } char *state_desc; if (i < ECOS_NUM_STATES) state_desc = eCos_thread_states[i].desc; else state_desc = "Unknown state"; rtos->thread_details[tasks_found].extra_info_str = (char *)malloc(strlen( state_desc)+1); strcpy(rtos->thread_details[tasks_found].extra_info_str, state_desc); rtos->thread_details[tasks_found].exists = true; rtos->thread_details[tasks_found].display_str = NULL; tasks_found++; prev_thread_ptr = thread_index; /* Get the location of the next thread structure. */ thread_index = rtos->symbols[eCos_VAL_thread_list].address; retval = target_read_buffer(rtos->target, prev_thread_ptr + param->thread_next_offset, param->pointer_width, (uint8_t *) &thread_index); if (retval != ERROR_OK) { LOG_ERROR("Error reading next thread pointer in eCos thread list"); return retval; } } while (thread_index != first_thread); rtos->thread_count = tasks_found; return 0; } static int eCos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list) { int retval; const struct eCos_params *param; *hex_reg_list = NULL; if (rtos == NULL) return -1; if (thread_id == 0) return -2; if (rtos->rtos_specific_params == NULL) return -3; param = (const struct eCos_params *) rtos->rtos_specific_params; /* Find the thread with that thread id */ uint16_t id = 0; uint32_t thread_list_head = rtos->symbols[eCos_VAL_thread_list].address; uint32_t thread_index; target_read_buffer(rtos->target, thread_list_head, param->pointer_width, (uint8_t *)&thread_index); bool done = false; while (!done) { retval = target_read_buffer(rtos->target, thread_index + param->thread_uniqueid_offset, 2, (uint8_t *)&id); if (retval != ERROR_OK) { LOG_ERROR("Error reading unique id from eCos thread"); return retval; } if (id == thread_id) { done = true; break; } target_read_buffer(rtos->target, thread_index + param->thread_next_offset, param->pointer_width, (uint8_t *) &thread_index); } if (done) { /* Read the stack pointer */ int64_t stack_ptr = 0; retval = target_read_buffer(rtos->target, thread_index + param->thread_stack_offset, param->pointer_width, (uint8_t *)&stack_ptr); if (retval != ERROR_OK) { LOG_ERROR("Error reading stack frame from eCos thread"); return retval; } return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, hex_reg_list); } return -1; } static int eCos_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) { unsigned int i; *symbol_list = (symbol_table_elem_t *) malloc( sizeof(symbol_table_elem_t) * ARRAY_SIZE(eCos_symbol_list)); for (i = 0; i < ARRAY_SIZE(eCos_symbol_list); i++) (*symbol_list)[i].symbol_name = eCos_symbol_list[i]; return 0; } static int eCos_detect_rtos(struct target *target) { if ((target->rtos->symbols != NULL) && (target->rtos->symbols[eCos_VAL_thread_list].address != 0)) { /* looks like eCos */ return 1; } return 0; } static int eCos_create(struct target *target) { int i = 0; while ((i < ECOS_NUM_PARAMS) && (0 != strcmp(eCos_params_list[i].target_name, target->type->name))) { i++; } if (i >= ECOS_NUM_PARAMS) { LOG_ERROR("Could not find target in eCos compatibility list"); return -1; } target->rtos->rtos_specific_params = (void *) &eCos_params_list[i]; target->rtos->current_thread = 0; target->rtos->thread_details = NULL; return 0; } openocd-0.7.0/src/rtos/rtos.h0000644000175000001440000000752412137151331013005 00000000000000/*************************************************************************** * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef RTOS_H #define RTOS_H #include "server/server.h" #include typedef int64_t threadid_t; typedef int64_t symbol_address_t; struct reg; /** * Table should be terminated by an element with NULL in symbol_name */ typedef struct symbol_table_elem_struct { char *symbol_name; symbol_address_t address; } symbol_table_elem_t; struct thread_detail { threadid_t threadid; bool exists; char *display_str; char *thread_name_str; char *extra_info_str; }; struct rtos { const struct rtos_type *type; symbol_table_elem_t *symbols; struct target *target; /* add a context variable instead of global variable */ int64_t current_threadid; threadid_t current_thread; struct thread_detail *thread_details; int thread_count; int (*gdb_thread_packet)(struct connection *connection, char *packet, int packet_size); void *rtos_specific_params; }; struct rtos_type { char *name; int (*detect_rtos)(struct target *target); int (*create)(struct target *target); int (*smp_init)(struct target *target); int (*update_threads)(struct rtos *rtos); int (*get_thread_reg_list)(struct rtos *rtos, int64_t thread_id, char **hex_reg_list); int (*get_symbol_list_to_lookup)(symbol_table_elem_t *symbol_list[]); int (*clean)(struct target *target); char * (*ps_command)(struct target *target); }; struct stack_register_offset { signed short offset; /* offset in bytes from stack head, or -1 to indicate * register is not stacked, or -2 to indicate this is the * stack pointer register */ unsigned short width_bits; }; struct rtos_register_stacking { unsigned char stack_registers_size; signed char stack_growth_direction; unsigned char num_output_registers; unsigned char stack_alignment; const struct stack_register_offset *register_offsets; }; #define GDB_THREAD_PACKET_NOT_CONSUMED (-40) int rtos_create(Jim_GetOptInfo *goi, struct target *target); int rtos_generic_stack_read(struct target *target, const struct rtos_register_stacking *stacking, int64_t stack_ptr, char **hex_reg_list); int rtos_try_next(struct target *target); int gdb_thread_packet(struct connection *connection, char *packet, int packet_size); int rtos_get_gdb_reg_list(struct connection *connection); int rtos_update_threads(struct target *target); int rtos_smp_init(struct target *target); /* function for handling symbol access */ int rtos_qsymbol(struct connection *connection, char *packet, int packet_size); #endif /* RTOS_H */ openocd-0.7.0/src/rtos/rtos_standard_stackings.c0000644000175000001440000000723712134336410016727 00000000000000/*************************************************************************** * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "rtos.h" static const struct stack_register_offset rtos_standard_Cortex_M3_stack_offsets[] = { { 0x20, 32 }, /* r0 */ { 0x24, 32 }, /* r1 */ { 0x28, 32 }, /* r2 */ { 0x2c, 32 }, /* r3 */ { 0x00, 32 }, /* r4 */ { 0x04, 32 }, /* r5 */ { 0x08, 32 }, /* r6 */ { 0x0c, 32 }, /* r7 */ { 0x10, 32 }, /* r8 */ { 0x14, 32 }, /* r9 */ { 0x18, 32 }, /* r10 */ { 0x1c, 32 }, /* r11 */ { 0x30, 32 }, /* r12 */ { -2, 32 }, /* sp */ { 0x34, 32 }, /* lr */ { 0x38, 32 }, /* pc */ { -1, 96 }, /* FPA1 */ { -1, 96 }, /* FPA2 */ { -1, 96 }, /* FPA3 */ { -1, 96 }, /* FPA4 */ { -1, 96 }, /* FPA5 */ { -1, 96 }, /* FPA6 */ { -1, 96 }, /* FPA7 */ { -1, 96 }, /* FPA8 */ { -1, 32 }, /* FPS */ { 0x3c, 32 }, /* xPSR */ }; static const struct stack_register_offset rtos_standard_Cortex_R4_stack_offsets[] = { { 0x08, 32 }, /* r0 (a1) */ { 0x0c, 32 }, /* r1 (a2) */ { 0x10, 32 }, /* r2 (a3) */ { 0x14, 32 }, /* r3 (a4) */ { 0x18, 32 }, /* r4 (v1) */ { 0x1c, 32 }, /* r5 (v2) */ { 0x20, 32 }, /* r6 (v3) */ { 0x24, 32 }, /* r7 (v4) */ { 0x28, 32 }, /* r8 (a1) */ { 0x2c, 32 }, /* r9 (sb) */ { 0x30, 32 }, /* r10 (sl) */ { 0x34, 32 }, /* r11 (fp) */ { 0x38, 32 }, /* r12 (ip) */ { -2, 32 }, /* sp */ { 0x3c, 32 }, /* lr */ { 0x40, 32 }, /* pc */ { -1, 96 }, /* FPA1 */ { -1, 96 }, /* FPA2 */ { -1, 96 }, /* FPA3 */ { -1, 96 }, /* FPA4 */ { -1, 96 }, /* FPA5 */ { -1, 96 }, /* FPA6 */ { -1, 96 }, /* FPA7 */ { -1, 96 }, /* FPA8 */ { -1, 32 }, /* FPS */ { 0x04, 32 }, /* CSPR */ }; const struct rtos_register_stacking rtos_standard_Cortex_M3_stacking = { 0x40, /* stack_registers_size */ -1, /* stack_growth_direction */ 26, /* num_output_registers */ 8, /* stack_alignment */ rtos_standard_Cortex_M3_stack_offsets /* register_offsets */ }; const struct rtos_register_stacking rtos_standard_Cortex_R4_stacking = { 0x48, /* stack_registers_size */ -1, /* stack_growth_direction */ 26, /* num_output_registers */ 8, /* stack_alignment */ rtos_standard_Cortex_R4_stack_offsets /* register_offsets */ }; openocd-0.7.0/src/rtos/ChibiOS.c0000644000175000001440000004345612137175623013307 00000000000000/*************************************************************************** * Copyright (C) 2012 by Matthias Blaicher * * Matthias Blaicher - matthias@blaicher.com * * * * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "target/target.h" #include "target/target_type.h" #include "target/armv7m.h" #include "target/cortex_m.h" #include "rtos.h" #include "helper/log.h" #include "helper/types.h" #include "rtos_chibios_stackings.h" /** * @brief ChibiOS/RT memory signature record. * * @details Definition copied from os/kernel/include/chregistry.h of ChibiOS/RT. */ struct ChibiOS_chdebug { char ch_identifier[4]; /**< @brief Always set to "main". */ uint8_t ch_zero; /**< @brief Must be zero. */ uint8_t ch_size; /**< @brief Size of this structure. */ uint16_t ch_version; /**< @brief Encoded ChibiOS/RT version. */ uint8_t ch_ptrsize; /**< @brief Size of a pointer. */ uint8_t ch_timesize; /**< @brief Size of a @p systime_t. */ uint8_t ch_threadsize; /**< @brief Size of a @p Thread struct. */ uint8_t cf_off_prio; /**< @brief Offset of @p p_prio field. */ uint8_t cf_off_ctx; /**< @brief Offset of @p p_ctx field. */ uint8_t cf_off_newer; /**< @brief Offset of @p p_newer field. */ uint8_t cf_off_older; /**< @brief Offset of @p p_older field. */ uint8_t cf_off_name; /**< @brief Offset of @p p_name field. */ uint8_t cf_off_stklimit; /**< @brief Offset of @p p_stklimit field. */ uint8_t cf_off_state; /**< @brief Offset of @p p_state field. */ uint8_t cf_off_flags; /**< @brief Offset of @p p_flags field. */ uint8_t cf_off_refs; /**< @brief Offset of @p p_refs field. */ uint8_t cf_off_preempt; /**< @brief Offset of @p p_preempt field. */ uint8_t cf_off_time; /**< @brief Offset of @p p_time field. */ }; #define GET_CH_KERNEL_MAJOR(codedVersion) ((codedVersion >> 11) & 0x1f) #define GET_CH_KERNEL_MINOR(codedVersion) ((codedVersion >> 6) & 0x1f) #define GET_CH_KERNEL_PATCH(codedVersion) ((codedVersion >> 0) & 0x3f) /** * @brief ChibiOS thread states. */ const char *ChibiOS_thread_states[] = { "READY", "CURRENT", "SUSPENDED", "WTSEM", "WTMTX", "WTCOND", "SLEEPING", "WTEXIT", "WTOREVT", "WTANDEVT", "SNDMSGQ", "SNDMSG", "WTMSG", "WTQUEUE", "FINAL" }; #define CHIBIOS_NUM_STATES (sizeof(ChibiOS_thread_states)/sizeof(char *)) /* Maximum ChibiOS thread name. There is no real limit set by ChibiOS but 64 * chars ought to be enough. */ #define CHIBIOS_THREAD_NAME_STR_SIZE (64) struct ChibiOS_params { const char *target_name; struct ChibiOS_chdebug *signature; const struct rtos_register_stacking *stacking_info; }; struct ChibiOS_params ChibiOS_params_list[] = { { "cortex_m", /* target_name */ 0, NULL, /* stacking_info */ }, { "hla_target", /* target_name */ 0, NULL, /* stacking_info */ } }; #define CHIBIOS_NUM_PARAMS ((int)(sizeof(ChibiOS_params_list)/sizeof(struct ChibiOS_params))) static int ChibiOS_detect_rtos(struct target *target); static int ChibiOS_create(struct target *target); static int ChibiOS_update_threads(struct rtos *rtos); static int ChibiOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list); static int ChibiOS_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]); struct rtos_type ChibiOS_rtos = { .name = "ChibiOS", .detect_rtos = ChibiOS_detect_rtos, .create = ChibiOS_create, .update_threads = ChibiOS_update_threads, .get_thread_reg_list = ChibiOS_get_thread_reg_list, .get_symbol_list_to_lookup = ChibiOS_get_symbol_list_to_lookup, }; enum ChibiOS_symbol_values { ChibiOS_VAL_rlist = 0, ChibiOS_VAL_ch_debug = 1, ChibiOS_VAL_chSysInit = 2 }; static char *ChibiOS_symbol_list[] = { "rlist", /* Thread ready list*/ "ch_debug", /* Memory Signatur containing offsets of fields in rlist*/ "chSysInit", /* Necessary part of API, used for ChibiOS detection*/ NULL }; static int ChibiOS_update_memory_signature(struct rtos *rtos) { int retval; struct ChibiOS_params *param; struct ChibiOS_chdebug *signature; param = (struct ChibiOS_params *) rtos->rtos_specific_params; /* Free existing memory description.*/ if (param->signature) { free(param->signature); param->signature = 0; } signature = malloc(sizeof(*signature)); if (!signature) { LOG_ERROR("Could not allocate space for ChibiOS/RT memory signature"); return -1; } retval = target_read_buffer(rtos->target, rtos->symbols[ChibiOS_VAL_ch_debug].address, sizeof(*signature), (uint8_t *) signature); if (retval != ERROR_OK) { LOG_ERROR("Could not read ChibiOS/RT memory signature from target"); goto errfree; } if (strncmp(signature->ch_identifier, "main", 4) != 0) { LOG_ERROR("Memory signature identifier does not contain magic bytes."); goto errfree; } if (signature->ch_size < sizeof(*signature)) { LOG_ERROR("ChibiOS/RT memory signature claims to be smaller " "than expected"); goto errfree; } if (signature->ch_size > sizeof(*signature)) { LOG_WARNING("ChibiOS/RT memory signature claims to be bigger than" " expected. Assuming compatibility..."); } /* Convert endianness of version field */ const uint8_t *versionTarget = (const uint8_t *) &signature->ch_version; signature->ch_version = rtos->target->endianness == TARGET_LITTLE_ENDIAN ? le_to_h_u32(versionTarget) : be_to_h_u32(versionTarget); const uint16_t ch_version = signature->ch_version; LOG_INFO("Successfully loaded memory map of ChibiOS/RT target " "running version %i.%i.%i", GET_CH_KERNEL_MAJOR(ch_version), GET_CH_KERNEL_MINOR(ch_version), GET_CH_KERNEL_PATCH(ch_version)); /* Currently, we have the inherent assumption that all address pointers * are 32 bit wide. */ if (signature->ch_ptrsize != sizeof(uint32_t)) { LOG_ERROR("ChibiOS/RT target memory signature claims an address" "width unequal to 32 bits!"); free(signature); return -1; } param->signature = signature; return 0; errfree: /* Error reading the ChibiOS memory structure */ free(signature); param->signature = 0; return -1; } static int ChibiOS_update_stacking(struct rtos *rtos) { /* Sometimes the stacking can not be determined only by looking at the * target name but only a runtime. * * For example, this is the case for cortex-m4 targets and ChibiOS which * only stack the FPU registers if it is enabled during ChibiOS build. * * Terminating which stacking is used is target depending. * * Assumptions: * - Once ChibiOS is actually initialized, the stacking is fixed. * - During startup code, the FPU might not be initialized and the * detection might fail. * - Since no threads are running during startup, the problem is solved * by delaying stacking detection until there are more threads * available than the current execution. In which case * ChibiOS_get_thread_reg_list is called. */ int retval; if (!rtos->rtos_specific_params) return -1; struct ChibiOS_params *param; param = (struct ChibiOS_params *) rtos->rtos_specific_params; /* Check for armv7m with *enabled* FPU, i.e. a Cortex M4 */ struct armv7m_common *armv7m_target = target_to_armv7m(rtos->target); if (is_armv7m(armv7m_target)) { if (armv7m_target->fp_feature == FPv4_SP) { /* Found ARM v7m target which includes a FPU */ uint32_t cpacr; retval = target_read_u32(rtos->target, FPU_CPACR, &cpacr); if (retval != ERROR_OK) { LOG_ERROR("Could not read CPACR register to check FPU state"); return -1; } /* Check if CP10 and CP11 are set to full access. * In ChibiOS this is done in ResetHandler() in crt0.c */ if (cpacr & 0x00F00000) { /* Found target with enabled FPU */ /* FIXME: Need to figure out how to specify the FPU registers */ LOG_ERROR("ChibiOS ARM v7m targets with enabled FPU " " are NOT supported"); return -1; } } /* Found ARM v7m target with no or disabled FPU */ param->stacking_info = &rtos_chibios_arm_v7m_stacking; return 0; } return -1; } static int ChibiOS_update_threads(struct rtos *rtos) { int retval; const struct ChibiOS_params *param; int tasks_found = 0; int rtos_valid = -1; if (!rtos->rtos_specific_params) return -1; if (!rtos->symbols) { LOG_ERROR("No symbols for ChibiOS"); return -3; } param = (const struct ChibiOS_params *) rtos->rtos_specific_params; /* Update the memory signature saved in the target memory */ if (!param->signature) { retval = ChibiOS_update_memory_signature(rtos); if (retval != ERROR_OK) { LOG_ERROR("Reading the memory signature of ChibiOS/RT failed"); return retval; } } /* wipe out previous thread details if any */ int j; if (rtos->thread_details) { for (j = 0; j < rtos->thread_count; j++) { struct thread_detail *current_thread = &rtos->thread_details[j]; if (current_thread->display_str != NULL) free(current_thread->display_str); if (current_thread->thread_name_str != NULL) free(current_thread->thread_name_str); if (current_thread->extra_info_str != NULL) free(current_thread->extra_info_str); } free(rtos->thread_details); rtos->thread_details = NULL; rtos->thread_count = 0; } /* ChibiOS does not save the current thread count. We have to first * parse the double linked thread list to check for errors and the number of * threads. */ const uint32_t rlist = rtos->symbols[ChibiOS_VAL_rlist].address; const struct ChibiOS_chdebug *signature = param->signature; uint32_t current; uint32_t previous; uint32_t older; current = rlist; previous = rlist; while (1) { retval = target_read_u32(rtos->target, current + signature->cf_off_newer, ¤t); if (retval != ERROR_OK) { LOG_ERROR("Could not read next ChibiOS thread"); return retval; } /* Could be NULL if the kernel is not initialized yet or if the * registry is corrupted. */ if (current == 0) { LOG_ERROR("ChibiOS registry integrity check failed, NULL pointer"); rtos_valid = 0; break; } /* Fetch previous thread in the list as a integrity check. */ retval = target_read_u32(rtos->target, current + signature->cf_off_older, &older); if ((retval != ERROR_OK) || (older == 0) || (older != previous)) { LOG_ERROR("ChibiOS registry integrity check failed, " "double linked list violation"); rtos_valid = 0; break; } /* Check for full iteration of the linked list. */ if (current == rlist) break; tasks_found++; previous = current; } if (!rtos_valid) { /* No RTOS, there is always at least the current execution, though */ LOG_INFO("Only showing current execution because of a broken " "ChibiOS thread registry."); const char tmp_thread_name[] = "Current Execution"; const char tmp_thread_extra_info[] = "No RTOS thread"; rtos->thread_details = (struct thread_detail *) malloc( sizeof(struct thread_detail)); rtos->thread_details->threadid = 1; rtos->thread_details->exists = true; rtos->thread_details->display_str = NULL; rtos->thread_details->extra_info_str = (char *) malloc( sizeof(tmp_thread_extra_info)); strcpy(rtos->thread_details->extra_info_str, tmp_thread_extra_info); rtos->thread_details->thread_name_str = (char *) malloc( sizeof(tmp_thread_name)); strcpy(rtos->thread_details->thread_name_str, tmp_thread_name); rtos->current_thread = 1; rtos->thread_count = 1; return ERROR_OK; } /* create space for new thread details */ rtos->thread_details = (struct thread_detail *) malloc( sizeof(struct thread_detail) * tasks_found); if (!rtos->thread_details) { LOG_ERROR("Could not allocate space for thread details"); return -1; } rtos->thread_count = tasks_found; /* Loop through linked list. */ struct thread_detail *curr_thrd_details = rtos->thread_details; while (curr_thrd_details < rtos->thread_details + tasks_found) { uint32_t name_ptr = 0; char tmp_str[CHIBIOS_THREAD_NAME_STR_SIZE]; retval = target_read_u32(rtos->target, current + signature->cf_off_newer, ¤t); if (retval != ERROR_OK) { LOG_ERROR("Could not read next ChibiOS thread"); return -6; } /* Check for full iteration of the linked list. */ if (current == rlist) break; /* Save the thread pointer */ curr_thrd_details->threadid = current; /* read the name pointer */ retval = target_read_u32(rtos->target, current + signature->cf_off_name, &name_ptr); if (retval != ERROR_OK) { LOG_ERROR("Could not read ChibiOS thread name pointer from target"); return retval; } /* Read the thread name */ retval = target_read_buffer(rtos->target, name_ptr, CHIBIOS_THREAD_NAME_STR_SIZE, (uint8_t *)&tmp_str); if (retval != ERROR_OK) { LOG_ERROR("Error reading thread name from ChibiOS target"); return retval; } tmp_str[CHIBIOS_THREAD_NAME_STR_SIZE - 1] = '\x00'; if (tmp_str[0] == '\x00') strcpy(tmp_str, "No Name"); curr_thrd_details->thread_name_str = (char *)malloc( strlen(tmp_str) + 1); strcpy(curr_thrd_details->thread_name_str, tmp_str); /* State info */ uint8_t threadState; const char *state_desc; retval = target_read_u8(rtos->target, current + signature->cf_off_state, &threadState); if (retval != ERROR_OK) { LOG_ERROR("Error reading thread state from ChibiOS target"); return retval; } if (threadState < CHIBIOS_NUM_STATES) state_desc = ChibiOS_thread_states[threadState]; else state_desc = "Unknown state"; curr_thrd_details->extra_info_str = (char *)malloc(strlen( state_desc)+1); strcpy(curr_thrd_details->extra_info_str, state_desc); curr_thrd_details->exists = true; curr_thrd_details->display_str = NULL; curr_thrd_details++; } uint32_t current_thrd; /* NOTE: By design, cf_off_name equals readylist_current_offset */ retval = target_read_u32(rtos->target, rlist + signature->cf_off_name, ¤t_thrd); if (retval != ERROR_OK) { LOG_ERROR("Could not read current Thread from ChibiOS target"); return retval; } rtos->current_thread = current_thrd; return 0; } static int ChibiOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list) { int retval; const struct ChibiOS_params *param; uint32_t stack_ptr = 0; *hex_reg_list = NULL; if ((rtos == NULL) || (thread_id == 0) || (rtos->rtos_specific_params == NULL)) return -1; param = (const struct ChibiOS_params *) rtos->rtos_specific_params; if (!param->signature) return -1; /* Update stacking if it can only be determined from runtime information */ if ((param->stacking_info == 0) && (ChibiOS_update_stacking(rtos) != ERROR_OK)) { LOG_ERROR("Failed to determine exact stacking for the target type %s", rtos->target->type->name); return -1; } /* Read the stack pointer */ retval = target_read_u32(rtos->target, thread_id + param->signature->cf_off_ctx, &stack_ptr); if (retval != ERROR_OK) { LOG_ERROR("Error reading stack frame from ChibiOS thread"); return retval; } return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, hex_reg_list); } static int ChibiOS_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) { unsigned int i; *symbol_list = (symbol_table_elem_t *) malloc( sizeof(symbol_table_elem_t) * ARRAY_SIZE(ChibiOS_symbol_list)); for (i = 0; i < ARRAY_SIZE(ChibiOS_symbol_list); i++) (*symbol_list)[i].symbol_name = ChibiOS_symbol_list[i]; return 0; } static int ChibiOS_detect_rtos(struct target *target) { if ((target->rtos->symbols != NULL) && (target->rtos->symbols[ChibiOS_VAL_rlist].address != 0) && (target->rtos->symbols[ChibiOS_VAL_chSysInit].address != 0)) { if (target->rtos->symbols[ChibiOS_VAL_ch_debug].address == 0) { LOG_INFO("It looks like the target is running ChibiOS without " "ch_debug."); return 0; } /* looks like ChibiOS with memory map enabled.*/ return 1; } return 0; } static int ChibiOS_create(struct target *target) { int i = 0; while ((i < CHIBIOS_NUM_PARAMS) && (0 != strcmp(ChibiOS_params_list[i].target_name, target->type->name))) { i++; } if (i >= CHIBIOS_NUM_PARAMS) { LOG_WARNING("Could not find target \"%s\" in ChibiOS compatibility " "list", target->type->name); return -1; } target->rtos->rtos_specific_params = (void *) &ChibiOS_params_list[i]; return 0; } openocd-0.7.0/src/rtos/rtos_ecos_stackings.h0000644000175000001440000000307612134336410016062 00000000000000/*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef INCLUDED_RTOS_STANDARD_STACKINGS_H_ #define INCLUDED_RTOS_STANDARD_STACKINGS_H_ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "rtos.h" extern const struct rtos_register_stacking rtos_eCos_Cortex_M3_stacking; #endif /* ifndef INCLUDED_RTOS_STANDARD_STACKINGS_H_ */ openocd-0.7.0/src/rtos/Makefile.am0000644000175000001440000000373412134336410013700 00000000000000# *************************************************************************** # * Copyright (C) 2011 by Broadcom Corporation * # * Evan Hunter - ehunter@broadcom.com * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU General Public License as published by * # * the Free Software Foundation; either version 2 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. * # *************************************************************************** include $(top_srcdir)/common.mk METASOURCES = AUTO noinst_LTLIBRARIES = librtos.la noinst_HEADERS = rtos.h rtos_standard_stackings.h rtos_ecos_stackings.h linux_header.h rtos_chibios_stackings.h librtos_la_SOURCES = rtos.c rtos_standard_stackings.c rtos_ecos_stackings.c rtos_chibios_stackings.c FreeRTOS.c ThreadX.c eCos.c linux.c ChibiOS.c librtos_la_CFLAGS = if IS_MINGW # FD_* macros are sloppy with their signs on MinGW32 platform librtos_la_CFLAGS += -Wno-sign-compare endif MAINTAINERCLEANFILES = $(srcdir)/Makefile.in openocd-0.7.0/src/rtos/rtos_chibios_stackings.c0000644000175000001440000000541312134336410016541 00000000000000/*************************************************************************** * Copyright (C) 2012 by Matthias Blaicher * * Matthias Blaicher - matthias@blaicher.com * * * * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "rtos.h" static const struct stack_register_offset rtos_chibios_arm_v7m_stack_offsets[] = { { -1, 32 }, /* r0 */ { -1, 32 }, /* r1 */ { -1, 32 }, /* r2 */ { -1, 32 }, /* r3 */ { 0x00, 32 }, /* r4 */ { 0x04, 32 }, /* r5 */ { 0x08, 32 }, /* r6 */ { 0x0c, 32 }, /* r7 */ { 0x10, 32 }, /* r8 */ { 0x14, 32 }, /* r9 */ { 0x18, 32 }, /* r10 */ { 0x1c, 32 }, /* r11 */ { -1, 32 }, /* r12 */ { -2, 32 }, /* sp */ { -1, 32 }, /* lr */ { 0x20, 32 }, /* pc */ { -1, 96 }, /* FPA1 */ { -1, 96 }, /* FPA2 */ { -1, 96 }, /* FPA3 */ { -1, 96 }, /* FPA4 */ { -1, 96 }, /* FPA5 */ { -1, 96 }, /* FPA6 */ { -1, 96 }, /* FPA7 */ { -1, 96 }, /* FPA8 */ { -1, 32 }, /* FPS */ { -1, 32 }, /* xPSR */ }; const struct rtos_register_stacking rtos_chibios_arm_v7m_stacking = { 0x24, /* stack_registers_size */ -1, /* stack_growth_direction */ 26, /* num_output_registers */ 0, /* stack_alignment */ rtos_chibios_arm_v7m_stack_offsets /* register_offsets */ }; openocd-0.7.0/src/rtos/rtos_standard_stackings.h0000644000175000001440000000345112134336410016726 00000000000000/*************************************************************************** * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef INCLUDED_RTOS_STANDARD_STACKINGS_H_ #define INCLUDED_RTOS_STANDARD_STACKINGS_H_ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "rtos.h" extern const struct rtos_register_stacking rtos_standard_Cortex_M3_stacking; extern const struct rtos_register_stacking rtos_standard_Cortex_R4_stacking; #endif /* ifndef INCLUDED_RTOS_STANDARD_STACKINGS_H_ */ openocd-0.7.0/src/Makefile.in0000644000175000001440000010227212141414275012723 00000000000000# Makefile.in generated by automake 1.13.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ DIST_COMMON = $(top_srcdir)/common.mk $(srcdir)/Makefile.in \ $(srcdir)/Makefile.am $(top_srcdir)/depcomp $(noinst_HEADERS) @INTERNAL_JIMTCL_TRUE@am__append_1 = -I$(top_srcdir)/jimtcl \ @INTERNAL_JIMTCL_TRUE@ -I$(top_builddir)/jimtcl bin_PROGRAMS = openocd$(EXEEXT) @INTERNAL_JIMTCL_TRUE@am__append_2 = $(top_builddir)/jimtcl/libjim.a @INTERNAL_JIMTCL_FALSE@am__append_3 = -ljim @ULINK_TRUE@am__append_4 = -lm # banner output includes RELSTR appended to $VERSION from the configure script # guess-rev.sh returns either a repository version ID or "-snapshot" @RELEASE_TRUE@am__append_5 = -DRELSTR=\"\" -DGITVERSION=\"\" @RELEASE_FALSE@am__append_6 = -DRELSTR=\"`$(top_srcdir)/guess-rev.sh \ @RELEASE_FALSE@ $(top_srcdir)`\" -DGITVERSION=\"`cd \ @RELEASE_FALSE@ $(top_srcdir) && git describe`\" @USE_LIBUSB1_TRUE@am__append_7 = -lusb-1.0 @USE_LIBUSB0_TRUE@am__append_8 = -lusb subdir = src ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/config_subdir.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" LTLIBRARIES = $(lib_LTLIBRARIES) am__DEPENDENCIES_1 = am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) libopenocd_la_DEPENDENCIES = $(top_builddir)/src/xsvf/libxsvf.la \ $(top_builddir)/src/svf/libsvf.la \ $(top_builddir)/src/pld/libpld.la \ $(top_builddir)/src/jtag/libjtag.la \ $(top_builddir)/src/transport/libtransport.la \ $(top_builddir)/src/flash/libflash.la \ $(top_builddir)/src/target/libtarget.la \ $(top_builddir)/src/server/libserver.la \ $(top_builddir)/src/rtos/librtos.la \ $(top_builddir)/src/helper/libhelper.la $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) am_libopenocd_la_OBJECTS = libopenocd_la-hello.lo \ libopenocd_la-openocd.lo libopenocd_la-startup_tcl.lo libopenocd_la_OBJECTS = $(am_libopenocd_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libopenocd_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libopenocd_la_LDFLAGS) $(LDFLAGS) -o $@ PROGRAMS = $(bin_PROGRAMS) am__objects_1 = main.$(OBJEXT) am_openocd_OBJECTS = $(am__objects_1) openocd_OBJECTS = $(am_openocd_OBJECTS) openocd_DEPENDENCIES = libopenocd.la $(am__append_2) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libopenocd_la_SOURCES) $(openocd_SOURCES) DIST_SOURCES = $(libopenocd_la_SOURCES) $(openocd_SOURCES) RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(noinst_HEADERS) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CC_FOR_BUILD = @CC_FOR_BUILD@ CFLAGS = @CFLAGS@ CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@ FGREP = @FGREP@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ doxygen_as_html = @doxygen_as_html@ doxygen_as_pdf = @doxygen_as_pdf@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ # common flags used in openocd build AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src \ -I$(top_srcdir)/src/helper -DPKGDATADIR=\"$(pkgdatadir)\" \ -DPKGLIBDIR=\"$(pkglibdir)\" $(am__append_1) SUBDIRS = \ jtag \ helper \ target \ transport \ flash \ svf \ xsvf \ pld \ server \ rtos lib_LTLIBRARIES = libopenocd.la MAINFILE = main.c openocd_SOURCES = $(MAINFILE) openocd_LDADD = libopenocd.la $(am__append_2) $(am__append_3) \ $(am__append_4) libopenocd_la_SOURCES = \ hello.c \ openocd.c \ startup_tcl.c noinst_HEADERS = \ hello.h \ openocd.h # add default CPPFLAGS libopenocd_la_CPPFLAGS = -DPKGBLDDATE=\"`date +%F-%R`\" \ $(am__append_5) $(am__append_6) $(AM_CPPFLAGS) $(CPPFLAGS) # the library search path. libopenocd_la_LDFLAGS = $(all_libraries) @IS_MINGW_FALSE@MINGWLDADD = @IS_MINGW_TRUE@MINGWLDADD = -lws2_32 @FT2232_LIBFTDI_FALSE@@PRESTO_LIBFTDI_FALSE@@USB_BLASTER_LIBFTDI_FALSE@FTDI2232LIB = @FT2232_LIBFTDI_FALSE@@PRESTO_LIBFTDI_TRUE@@USB_BLASTER_LIBFTDI_FALSE@FTDI2232LIB = -lftdi -lusb @FT2232_LIBFTDI_FALSE@@USB_BLASTER_LIBFTDI_TRUE@FTDI2232LIB = -lftdi -lusb @FT2232_LIBFTDI_TRUE@FTDI2232LIB = -lftdi -lusb LIBUSB = $(am__append_7) $(am__append_8) libopenocd_la_LIBADD = \ $(top_builddir)/src/xsvf/libxsvf.la \ $(top_builddir)/src/svf/libsvf.la \ $(top_builddir)/src/pld/libpld.la \ $(top_builddir)/src/jtag/libjtag.la \ $(top_builddir)/src/transport/libtransport.la \ $(top_builddir)/src/flash/libflash.la \ $(top_builddir)/src/target/libtarget.la \ $(top_builddir)/src/server/libserver.la \ $(top_builddir)/src/rtos/librtos.la \ $(top_builddir)/src/helper/libhelper.la \ $(FTDI2232LIB) $(MINGWLDADD) $(LIBUSB) STARTUP_TCL_SRCS = \ $(srcdir)/helper/startup.tcl \ $(srcdir)/jtag/startup.tcl \ $(srcdir)/target/startup.tcl \ $(srcdir)/flash/startup.tcl \ $(srcdir)/server/startup.tcl EXTRA_DIST = $(STARTUP_TCL_SRCS) BUILT_SOURCES = startup.tcl BIN2C = $(top_builddir)/src/helper/bin2char$(EXEEXT_FOR_BUILD) # add startup_tcl.c to make clean list CLEANFILES = startup.tcl startup_tcl.c MAINTAINERCLEANFILES = $(srcdir)/Makefile.in all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-recursive .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/common.mk $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_srcdir)/common.mk: $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libopenocd.la: $(libopenocd_la_OBJECTS) $(libopenocd_la_DEPENDENCIES) $(EXTRA_libopenocd_la_DEPENDENCIES) $(AM_V_CCLD)$(libopenocd_la_LINK) -rpath $(libdir) $(libopenocd_la_OBJECTS) $(libopenocd_la_LIBADD) $(LIBS) install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list openocd$(EXEEXT): $(openocd_OBJECTS) $(openocd_DEPENDENCIES) $(EXTRA_openocd_DEPENDENCIES) @rm -f openocd$(EXEEXT) $(AM_V_CCLD)$(LINK) $(openocd_OBJECTS) $(openocd_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libopenocd_la-hello.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libopenocd_la-openocd.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libopenocd_la-startup_tcl.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< libopenocd_la-hello.lo: hello.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenocd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libopenocd_la-hello.lo -MD -MP -MF $(DEPDIR)/libopenocd_la-hello.Tpo -c -o libopenocd_la-hello.lo `test -f 'hello.c' || echo '$(srcdir)/'`hello.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libopenocd_la-hello.Tpo $(DEPDIR)/libopenocd_la-hello.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hello.c' object='libopenocd_la-hello.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenocd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libopenocd_la-hello.lo `test -f 'hello.c' || echo '$(srcdir)/'`hello.c libopenocd_la-openocd.lo: openocd.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenocd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libopenocd_la-openocd.lo -MD -MP -MF $(DEPDIR)/libopenocd_la-openocd.Tpo -c -o libopenocd_la-openocd.lo `test -f 'openocd.c' || echo '$(srcdir)/'`openocd.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libopenocd_la-openocd.Tpo $(DEPDIR)/libopenocd_la-openocd.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='openocd.c' object='libopenocd_la-openocd.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenocd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libopenocd_la-openocd.lo `test -f 'openocd.c' || echo '$(srcdir)/'`openocd.c libopenocd_la-startup_tcl.lo: startup_tcl.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenocd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libopenocd_la-startup_tcl.lo -MD -MP -MF $(DEPDIR)/libopenocd_la-startup_tcl.Tpo -c -o libopenocd_la-startup_tcl.lo `test -f 'startup_tcl.c' || echo '$(srcdir)/'`startup_tcl.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libopenocd_la-startup_tcl.Tpo $(DEPDIR)/libopenocd_la-startup_tcl.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='startup_tcl.c' object='libopenocd_la-startup_tcl.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libopenocd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libopenocd_la-startup_tcl.lo `test -f 'startup_tcl.c' || echo '$(srcdir)/'`startup_tcl.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$(top_distdir)" distdir="$(distdir)" \ dist-hook check-am: all-am check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-recursive all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(HEADERS) install-binPROGRAMS: install-libLTLIBRARIES installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-recursive clean-am: clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \ clean-libtool mostlyclean-am distclean: distclean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-binPROGRAMS install-libLTLIBRARIES install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES .MAKE: $(am__recursive_targets) all check install install-am \ install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-binPROGRAMS clean-generic \ clean-libLTLIBRARIES clean-libtool cscopelist-am ctags \ ctags-am dist-hook distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-binPROGRAMS install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ install-libLTLIBRARIES install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-binPROGRAMS \ uninstall-libLTLIBRARIES startup.tcl: $(STARTUP_TCL_SRCS) cat $^ > $@ # Convert .tcl to cfile startup_tcl.c: startup.tcl $(BIN2C) $(BIN2C) openocd_startup_tcl < $< > $@ || rm -f $@ # we do not want generated file in the dist dist-hook: rm -f $(distdir)/startup_tcl.c # The "quick" target builds executables & reinstalls the executables # Primary use: developer types to quicken the edit/compile/debug # cycle. by not requiring a "full build and full install". Note the # assumption is: You are only rebuilding the EXE.... and everything # else is/was previously installed. # # use at your own risk quick: all install-binPROGRAMS # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: openocd-0.7.0/src/svf/0000755000175000001440000000000012141414413011522 500000000000000openocd-0.7.0/src/svf/svf.h0000644000175000001440000000442212134336410012415 00000000000000/*************************************************************************** * Copyright (C) 2009 by Simon Qian * * SimonQian@SimonQian.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef SVF_H #define SVF_H #include int svf_register_commands(struct command_context *cmd_ctx); /** * svf_add_statemove() moves from the current state to @a goal_state. * * @param goal_state The final TAP state. * @return ERROR_OK on success, or an error code on failure. * * The current and goal states must satisfy svf_tap_state_is_stable(). * State transition paths used by this routine are those given in the * SVF specification for single-argument STATE commands (and also used * for various other state transitions). */ int svf_add_statemove(tap_state_t goal_state); /** * svf_tap_state_is_stable() returns true for stable non-SHIFT states * * @param state The TAP state in question * @return true iff the state is stable and not a SHIFT state. */ bool svf_tap_state_is_stable(tap_state_t state); #endif /* SVF_H */ openocd-0.7.0/src/svf/svf.c0000644000175000001440000013034412134336410012413 00000000000000/*************************************************************************** * Copyright (C) 2009 by Simon Qian * * SimonQian@SimonQian.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /* The specification for SVF is available here: * http://www.asset-intertech.com/support/svf.pdf * Below, this document is refered to as the "SVF spec". * * The specification for XSVF is available here: * http://www.xilinx.com/support/documentation/application_notes/xapp503.pdf * Below, this document is refered to as the "XSVF spec". */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "svf.h" #include /* SVF command */ enum svf_command { ENDDR, ENDIR, FREQUENCY, HDR, HIR, PIO, PIOMAP, RUNTEST, SDR, SIR, STATE, TDR, TIR, TRST, }; static const char *svf_command_name[14] = { "ENDDR", "ENDIR", "FREQUENCY", "HDR", "HIR", "PIO", "PIOMAP", "RUNTEST", "SDR", "SIR", "STATE", "TDR", "TIR", "TRST" }; enum trst_mode { TRST_ON, TRST_OFF, TRST_Z, TRST_ABSENT }; static const char *svf_trst_mode_name[4] = { "ON", "OFF", "Z", "ABSENT" }; struct svf_statemove { tap_state_t from; tap_state_t to; uint32_t num_of_moves; tap_state_t paths[8]; }; /* * These paths are from the SVF specification for the STATE command, to be * used when the STATE command only includes the final state. The first * element of the path is the "from" (current) state, and the last one is * the "to" (target) state. * * All specified paths are the shortest ones in the JTAG spec, and are thus * not (!!) exact matches for the paths used elsewhere in OpenOCD. Note * that PAUSE-to-PAUSE transitions all go through UPDATE and then CAPTURE, * which has specific effects on the various registers; they are not NOPs. * * Paths to RESET are disabled here. As elsewhere in OpenOCD, and in XSVF * and many SVF implementations, we don't want to risk missing that state. * To get to RESET, always we ignore the current state. */ static const struct svf_statemove svf_statemoves[] = { /* from to num_of_moves, paths[8] */ /* {TAP_RESET, TAP_RESET, 1, {TAP_RESET}}, */ {TAP_RESET, TAP_IDLE, 2, {TAP_RESET, TAP_IDLE} }, {TAP_RESET, TAP_DRPAUSE, 6, {TAP_RESET, TAP_IDLE, TAP_DRSELECT, TAP_DRCAPTURE, TAP_DREXIT1, TAP_DRPAUSE} }, {TAP_RESET, TAP_IRPAUSE, 7, {TAP_RESET, TAP_IDLE, TAP_DRSELECT, TAP_IRSELECT, TAP_IRCAPTURE, TAP_IREXIT1, TAP_IRPAUSE} }, /* {TAP_IDLE, TAP_RESET, 4, {TAP_IDLE, * TAP_DRSELECT, TAP_IRSELECT, TAP_RESET}}, */ {TAP_IDLE, TAP_IDLE, 1, {TAP_IDLE} }, {TAP_IDLE, TAP_DRPAUSE, 5, {TAP_IDLE, TAP_DRSELECT, TAP_DRCAPTURE, TAP_DREXIT1, TAP_DRPAUSE} }, {TAP_IDLE, TAP_IRPAUSE, 6, {TAP_IDLE, TAP_DRSELECT, TAP_IRSELECT, TAP_IRCAPTURE, TAP_IREXIT1, TAP_IRPAUSE} }, /* {TAP_DRPAUSE, TAP_RESET, 6, {TAP_DRPAUSE, * TAP_DREXIT2, TAP_DRUPDATE, TAP_DRSELECT, TAP_IRSELECT, TAP_RESET}}, */ {TAP_DRPAUSE, TAP_IDLE, 4, {TAP_DRPAUSE, TAP_DREXIT2, TAP_DRUPDATE, TAP_IDLE} }, {TAP_DRPAUSE, TAP_DRPAUSE, 7, {TAP_DRPAUSE, TAP_DREXIT2, TAP_DRUPDATE, TAP_DRSELECT, TAP_DRCAPTURE, TAP_DREXIT1, TAP_DRPAUSE} }, {TAP_DRPAUSE, TAP_IRPAUSE, 8, {TAP_DRPAUSE, TAP_DREXIT2, TAP_DRUPDATE, TAP_DRSELECT, TAP_IRSELECT, TAP_IRCAPTURE, TAP_IREXIT1, TAP_IRPAUSE} }, /* {TAP_IRPAUSE, TAP_RESET, 6, {TAP_IRPAUSE, * TAP_IREXIT2, TAP_IRUPDATE, TAP_DRSELECT, TAP_IRSELECT, TAP_RESET}}, */ {TAP_IRPAUSE, TAP_IDLE, 4, {TAP_IRPAUSE, TAP_IREXIT2, TAP_IRUPDATE, TAP_IDLE} }, {TAP_IRPAUSE, TAP_DRPAUSE, 7, {TAP_IRPAUSE, TAP_IREXIT2, TAP_IRUPDATE, TAP_DRSELECT, TAP_DRCAPTURE, TAP_DREXIT1, TAP_DRPAUSE} }, {TAP_IRPAUSE, TAP_IRPAUSE, 8, {TAP_IRPAUSE, TAP_IREXIT2, TAP_IRUPDATE, TAP_DRSELECT, TAP_IRSELECT, TAP_IRCAPTURE, TAP_IREXIT1, TAP_IRPAUSE} } }; #define XXR_TDI (1 << 0) #define XXR_TDO (1 << 1) #define XXR_MASK (1 << 2) #define XXR_SMASK (1 << 3) struct svf_xxr_para { int len; int data_mask; uint8_t *tdi; uint8_t *tdo; uint8_t *mask; uint8_t *smask; }; struct svf_para { float frequency; tap_state_t ir_end_state; tap_state_t dr_end_state; tap_state_t runtest_run_state; tap_state_t runtest_end_state; enum trst_mode trst_mode; struct svf_xxr_para hir_para; struct svf_xxr_para hdr_para; struct svf_xxr_para tir_para; struct svf_xxr_para tdr_para; struct svf_xxr_para sir_para; struct svf_xxr_para sdr_para; }; static struct svf_para svf_para; static const struct svf_para svf_para_init = { /* frequency, ir_end_state, dr_end_state, runtest_run_state, runtest_end_state, trst_mode */ 0, TAP_IDLE, TAP_IDLE, TAP_IDLE, TAP_IDLE, TRST_Z, /* hir_para */ /* {len, data_mask, tdi, tdo, mask, smask}, */ {0, 0, NULL, NULL, NULL, NULL}, /* hdr_para */ /* {len, data_mask, tdi, tdo, mask, smask}, */ {0, 0, NULL, NULL, NULL, NULL}, /* tir_para */ /* {len, data_mask, tdi, tdo, mask, smask}, */ {0, 0, NULL, NULL, NULL, NULL}, /* tdr_para */ /* {len, data_mask, tdi, tdo, mask, smask}, */ {0, 0, NULL, NULL, NULL, NULL}, /* sir_para */ /* {len, data_mask, tdi, tdo, mask, smask}, */ {0, 0, NULL, NULL, NULL, NULL}, /* sdr_para */ /* {len, data_mask, tdi, tdo, mask, smask}, */ {0, 0, NULL, NULL, NULL, NULL}, }; struct svf_check_tdo_para { int line_num; /* used to record line number of the check operation */ /* so more information could be printed */ int enabled; /* check is enabled or not */ int buffer_offset; /* buffer_offset to buffers */ int bit_len; /* bit length to check */ }; #define SVF_CHECK_TDO_PARA_SIZE 1024 static struct svf_check_tdo_para *svf_check_tdo_para; static int svf_check_tdo_para_index; static int svf_read_command_from_file(FILE *fd); static int svf_check_tdo(void); static int svf_add_check_para(uint8_t enabled, int buffer_offset, int bit_len); static int svf_run_command(struct command_context *cmd_ctx, char *cmd_str); static FILE *svf_fd; static char *svf_read_line; static size_t svf_read_line_size; static char *svf_command_buffer; static size_t svf_command_buffer_size; static int svf_line_number = 1; static int svf_getline(char **lineptr, size_t *n, FILE *stream); #define SVF_MAX_BUFFER_SIZE_TO_COMMIT (1024 * 1024) static uint8_t *svf_tdi_buffer, *svf_tdo_buffer, *svf_mask_buffer; static int svf_buffer_index, svf_buffer_size ; static int svf_quiet; static int svf_nil; /* Targetting particular tap */ static int svf_tap_is_specified; static int svf_set_padding(struct svf_xxr_para *para, int len, unsigned char tdi); /* Progress Indicator */ static int svf_progress_enabled; static long svf_total_lines; static int svf_percentage; static int svf_last_printed_percentage = -1; static void svf_free_xxd_para(struct svf_xxr_para *para) { if (NULL != para) { if (para->tdi != NULL) { free(para->tdi); para->tdi = NULL; } if (para->tdo != NULL) { free(para->tdo); para->tdo = NULL; } if (para->mask != NULL) { free(para->mask); para->mask = NULL; } if (para->smask != NULL) { free(para->smask); para->smask = NULL; } } } static unsigned svf_get_mask_u32(int bitlen) { uint32_t bitmask; if (bitlen < 0) bitmask = 0; else if (bitlen >= 32) bitmask = 0xFFFFFFFF; else bitmask = (1 << bitlen) - 1; return bitmask; } int svf_add_statemove(tap_state_t state_to) { tap_state_t state_from = cmd_queue_cur_state; unsigned index_var; /* when resetting, be paranoid and ignore current state */ if (state_to == TAP_RESET) { if (svf_nil) return ERROR_OK; jtag_add_tlr(); return ERROR_OK; } for (index_var = 0; index_var < ARRAY_SIZE(svf_statemoves); index_var++) { if ((svf_statemoves[index_var].from == state_from) && (svf_statemoves[index_var].to == state_to)) { if (svf_nil) continue; /* recorded path includes current state ... avoid *extra TCKs! */ if (svf_statemoves[index_var].num_of_moves > 1) jtag_add_pathmove(svf_statemoves[index_var].num_of_moves - 1, svf_statemoves[index_var].paths + 1); else jtag_add_pathmove(svf_statemoves[index_var].num_of_moves, svf_statemoves[index_var].paths); return ERROR_OK; } } LOG_ERROR("SVF: can not move to %s", tap_state_name(state_to)); return ERROR_FAIL; } COMMAND_HANDLER(handle_svf_command) { #define SVF_MIN_NUM_OF_OPTIONS 1 #define SVF_MAX_NUM_OF_OPTIONS 5 int command_num = 0; int ret = ERROR_OK; long long time_measure_ms; int time_measure_s, time_measure_m; /* use NULL to indicate a "plain" svf file which accounts for * any additional devices in the scan chain, otherwise the device * that should be affected */ struct jtag_tap *tap = NULL; if ((CMD_ARGC < SVF_MIN_NUM_OF_OPTIONS) || (CMD_ARGC > SVF_MAX_NUM_OF_OPTIONS)) return ERROR_COMMAND_SYNTAX_ERROR; /* parse command line */ svf_quiet = 0; svf_nil = 0; for (unsigned int i = 0; i < CMD_ARGC; i++) { if (strcmp(CMD_ARGV[i], "-tap") == 0) { tap = jtag_tap_by_string(CMD_ARGV[i+1]); if (!tap) { command_print(CMD_CTX, "Tap: %s unknown", CMD_ARGV[i+1]); return ERROR_FAIL; } i++; } else if ((strcmp(CMD_ARGV[i], "quiet") == 0) || (strcmp(CMD_ARGV[i], "-quiet") == 0)) svf_quiet = 1; else if ((strcmp(CMD_ARGV[i], "nil") == 0) || (strcmp(CMD_ARGV[i], "-nil") == 0)) svf_nil = 1; else if ((strcmp(CMD_ARGV[i], "progress") == 0) || (strcmp(CMD_ARGV[i], "-progress") == 0)) svf_progress_enabled = 1; else { svf_fd = fopen(CMD_ARGV[i], "r"); if (svf_fd == NULL) { int err = errno; command_print(CMD_CTX, "open(\"%s\"): %s", CMD_ARGV[i], strerror(err)); /* no need to free anything now */ return ERROR_COMMAND_SYNTAX_ERROR; } else LOG_USER("svf processing file: \"%s\"", CMD_ARGV[i]); } } if (svf_fd == NULL) return ERROR_COMMAND_SYNTAX_ERROR; /* get time */ time_measure_ms = timeval_ms(); /* init */ svf_line_number = 1; svf_command_buffer_size = 0; svf_check_tdo_para_index = 0; svf_check_tdo_para = malloc(sizeof(struct svf_check_tdo_para) * SVF_CHECK_TDO_PARA_SIZE); if (NULL == svf_check_tdo_para) { LOG_ERROR("not enough memory"); ret = ERROR_FAIL; goto free_all; } svf_buffer_index = 0; /* double the buffer size */ /* in case current command cannot be committed, and next command is a bit scan command */ /* here is 32K bits for this big scan command, it should be enough */ /* buffer will be reallocated if buffer size is not enough */ svf_tdi_buffer = (uint8_t *)malloc(2 * SVF_MAX_BUFFER_SIZE_TO_COMMIT); if (NULL == svf_tdi_buffer) { LOG_ERROR("not enough memory"); ret = ERROR_FAIL; goto free_all; } svf_tdo_buffer = (uint8_t *)malloc(2 * SVF_MAX_BUFFER_SIZE_TO_COMMIT); if (NULL == svf_tdo_buffer) { LOG_ERROR("not enough memory"); ret = ERROR_FAIL; goto free_all; } svf_mask_buffer = (uint8_t *)malloc(2 * SVF_MAX_BUFFER_SIZE_TO_COMMIT); if (NULL == svf_mask_buffer) { LOG_ERROR("not enough memory"); ret = ERROR_FAIL; goto free_all; } svf_buffer_size = 2 * SVF_MAX_BUFFER_SIZE_TO_COMMIT; memcpy(&svf_para, &svf_para_init, sizeof(svf_para)); if (!svf_nil) { /* TAP_RESET */ jtag_add_tlr(); } if (tap) { /* Tap is specified, set header/trailer paddings */ int header_ir_len = 0, header_dr_len = 0, trailer_ir_len = 0, trailer_dr_len = 0; struct jtag_tap *check_tap; svf_tap_is_specified = 1; for (check_tap = jtag_all_taps(); check_tap; check_tap = check_tap->next_tap) { if (check_tap->abs_chain_position < tap->abs_chain_position) { /* Header */ header_ir_len += check_tap->ir_length; header_dr_len++; } else if (check_tap->abs_chain_position > tap->abs_chain_position) { /* Trailer */ trailer_ir_len += check_tap->ir_length; trailer_dr_len++; } } /* HDR %d TDI (0) */ if (ERROR_OK != svf_set_padding(&svf_para.hdr_para, header_dr_len, 0)) { LOG_ERROR("failed to set data header"); return ERROR_FAIL; } /* HIR %d TDI (0xFF) */ if (ERROR_OK != svf_set_padding(&svf_para.hir_para, header_ir_len, 0xFF)) { LOG_ERROR("failed to set instruction header"); return ERROR_FAIL; } /* TDR %d TDI (0) */ if (ERROR_OK != svf_set_padding(&svf_para.tdr_para, trailer_dr_len, 0)) { LOG_ERROR("failed to set data trailer"); return ERROR_FAIL; } /* TIR %d TDI (0xFF) */ if (ERROR_OK != svf_set_padding(&svf_para.tir_para, trailer_ir_len, 0xFF)) { LOG_ERROR("failed to set instruction trailer"); return ERROR_FAIL; } } if (svf_progress_enabled) { /* Count total lines in file. */ while (!feof(svf_fd)) { svf_getline(&svf_command_buffer, &svf_command_buffer_size, svf_fd); svf_total_lines++; } rewind(svf_fd); } while (ERROR_OK == svf_read_command_from_file(svf_fd)) { /* Log Output */ if (svf_quiet) { if (svf_progress_enabled) { svf_percentage = ((svf_line_number * 20) / svf_total_lines) * 5; if (svf_last_printed_percentage != svf_percentage) { LOG_USER_N("\r%d%% ", svf_percentage); svf_last_printed_percentage = svf_percentage; } } } else { if (svf_progress_enabled) { svf_percentage = ((svf_line_number * 20) / svf_total_lines) * 5; LOG_USER_N("%3d%% %s", svf_percentage, svf_read_line); } else LOG_USER_N("%s", svf_read_line); } /* Run Command */ if (ERROR_OK != svf_run_command(CMD_CTX, svf_command_buffer)) { LOG_ERROR("fail to run command at line %d", svf_line_number); ret = ERROR_FAIL; break; } command_num++; } if ((!svf_nil) && (ERROR_OK != jtag_execute_queue())) ret = ERROR_FAIL; else if (ERROR_OK != svf_check_tdo()) ret = ERROR_FAIL; /* print time */ time_measure_ms = timeval_ms() - time_measure_ms; time_measure_s = time_measure_ms / 1000; time_measure_ms %= 1000; time_measure_m = time_measure_s / 60; time_measure_s %= 60; if (time_measure_ms < 1000) command_print(CMD_CTX, "\r\nTime used: %dm%ds%lldms ", time_measure_m, time_measure_s, time_measure_ms); free_all: fclose(svf_fd); svf_fd = 0; /* free buffers */ if (svf_command_buffer) { free(svf_command_buffer); svf_command_buffer = NULL; svf_command_buffer_size = 0; } if (svf_check_tdo_para) { free(svf_check_tdo_para); svf_check_tdo_para = NULL; svf_check_tdo_para_index = 0; } if (svf_tdi_buffer) { free(svf_tdi_buffer); svf_tdi_buffer = NULL; } if (svf_tdo_buffer) { free(svf_tdo_buffer); svf_tdo_buffer = NULL; } if (svf_mask_buffer) { free(svf_mask_buffer); svf_mask_buffer = NULL; } svf_buffer_index = 0; svf_buffer_size = 0; svf_free_xxd_para(&svf_para.hdr_para); svf_free_xxd_para(&svf_para.hir_para); svf_free_xxd_para(&svf_para.tdr_para); svf_free_xxd_para(&svf_para.tir_para); svf_free_xxd_para(&svf_para.sdr_para); svf_free_xxd_para(&svf_para.sir_para); if (ERROR_OK == ret) command_print(CMD_CTX, "svf file programmed successfully for %d commands", command_num); else command_print(CMD_CTX, "svf file programmed failed"); return ret; } static int svf_getline(char **lineptr, size_t *n, FILE *stream) { #define MIN_CHUNK 16 /* Buffer is increased by this size each time as required */ size_t i = 0; if (*lineptr == NULL) { *n = MIN_CHUNK; *lineptr = (char *)malloc(*n); if (!*lineptr) return -1; } (*lineptr)[0] = fgetc(stream); while ((*lineptr)[i] != '\n') { (*lineptr)[++i] = fgetc(stream); if (feof(stream)) { (*lineptr)[0] = 0; return -1; } if ((i + 2) > *n) { *n += MIN_CHUNK; *lineptr = realloc(*lineptr, *n); } } (*lineptr)[++i] = 0; return sizeof(*lineptr); } #define SVFP_CMD_INC_CNT 1024 static int svf_read_command_from_file(FILE *fd) { unsigned char ch; int i = 0; size_t cmd_pos = 0; int cmd_ok = 0, slash = 0; if (svf_getline(&svf_read_line, &svf_read_line_size, svf_fd) <= 0) return ERROR_FAIL; svf_line_number++; ch = svf_read_line[0]; while (!cmd_ok && (ch != 0)) { switch (ch) { case '!': slash = 0; if (svf_getline(&svf_read_line, &svf_read_line_size, svf_fd) <= 0) return ERROR_FAIL; svf_line_number++; i = -1; break; case '/': if (++slash == 2) { slash = 0; if (svf_getline(&svf_read_line, &svf_read_line_size, svf_fd) <= 0) return ERROR_FAIL; svf_line_number++; i = -1; } break; case ';': slash = 0; cmd_ok = 1; break; case '\n': svf_line_number++; if (svf_getline(&svf_read_line, &svf_read_line_size, svf_fd) <= 0) return ERROR_FAIL; i = -1; case '\r': slash = 0; /* Don't save '\r' and '\n' if no data is parsed */ if (!cmd_pos) break; default: /* The parsing code currently expects a space * before parentheses -- "TDI (123)". Also a * space afterwards -- "TDI (123) TDO(456)". * But such spaces are optional... instead of * parser updates, cope with that by adding the * spaces as needed. * * Ensure there are 3 bytes available, for: * - current character * - added space. * - terminating NUL ('\0') */ if ((cmd_pos + 2) >= svf_command_buffer_size) { svf_command_buffer = realloc(svf_command_buffer, (cmd_pos + 2)); if (svf_command_buffer == NULL) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } } /* insert a space before '(' */ if ('(' == ch) svf_command_buffer[cmd_pos++] = ' '; svf_command_buffer[cmd_pos++] = (char)toupper(ch); /* insert a space after ')' */ if (')' == ch) svf_command_buffer[cmd_pos++] = ' '; break; } ch = svf_read_line[++i]; } if (cmd_ok) { svf_command_buffer[cmd_pos] = '\0'; return ERROR_OK; } else return ERROR_FAIL; } static int svf_parse_cmd_string(char *str, int len, char **argus, int *num_of_argu) { int pos = 0, num = 0, space_found = 1, in_bracket = 0; while (pos < len) { switch (str[pos]) { case '!': case '/': LOG_ERROR("fail to parse svf command"); return ERROR_FAIL; case '(': in_bracket = 1; goto parse_char; case ')': in_bracket = 0; goto parse_char; default: parse_char: if (!in_bracket && isspace((int) str[pos])) { space_found = 1; str[pos] = '\0'; } else if (space_found) { argus[num++] = &str[pos]; space_found = 0; } break; } pos++; } *num_of_argu = num; return ERROR_OK; } bool svf_tap_state_is_stable(tap_state_t state) { return (TAP_RESET == state) || (TAP_IDLE == state) || (TAP_DRPAUSE == state) || (TAP_IRPAUSE == state); } static int svf_find_string_in_array(char *str, char **strs, int num_of_element) { int i; for (i = 0; i < num_of_element; i++) { if (!strcmp(str, strs[i])) return i; } return 0xFF; } static int svf_adjust_array_length(uint8_t **arr, int orig_bit_len, int new_bit_len) { int new_byte_len = (new_bit_len + 7) >> 3; if ((NULL == *arr) || (((orig_bit_len + 7) >> 3) < ((new_bit_len + 7) >> 3))) { if (*arr != NULL) { free(*arr); *arr = NULL; } *arr = (uint8_t *)malloc(new_byte_len); if (NULL == *arr) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } memset(*arr, 0, new_byte_len); } return ERROR_OK; } static int svf_set_padding(struct svf_xxr_para *para, int len, unsigned char tdi) { int error = ERROR_OK; error |= svf_adjust_array_length(¶->tdi, para->len, len); memset(para->tdi, tdi, (len + 7) >> 3); error |= svf_adjust_array_length(¶->tdo, para->len, len); error |= svf_adjust_array_length(¶->mask, para->len, len); para->len = len; para->data_mask = XXR_TDI; return error; } static int svf_copy_hexstring_to_binary(char *str, uint8_t **bin, int orig_bit_len, int bit_len) { int i, str_len = strlen(str), str_hbyte_len = (bit_len + 3) >> 2; uint8_t ch = 0; if (ERROR_OK != svf_adjust_array_length(bin, orig_bit_len, bit_len)) { LOG_ERROR("fail to adjust length of array"); return ERROR_FAIL; } /* fill from LSB (end of str) to MSB (beginning of str) */ for (i = 0; i < str_hbyte_len; i++) { ch = 0; while (str_len > 0) { ch = str[--str_len]; /* Skip whitespace. The SVF specification (rev E) is * deficient in terms of basic lexical issues like * where whitespace is allowed. Long bitstrings may * require line ends for correctness, since there is * a hard limit on line length. */ if (!isspace(ch)) { if ((ch >= '0') && (ch <= '9')) { ch = ch - '0'; break; } else if ((ch >= 'A') && (ch <= 'F')) { ch = ch - 'A' + 10; break; } else { LOG_ERROR("invalid hex string"); return ERROR_FAIL; } } ch = 0; } /* write bin */ if (i % 2) { /* MSB */ (*bin)[i / 2] |= ch << 4; } else { /* LSB */ (*bin)[i / 2] = 0; (*bin)[i / 2] |= ch; } } /* consume optional leading '0' MSBs or whitespace */ while (str_len > 0 && ((str[str_len - 1] == '0') || isspace((int) str[str_len - 1]))) str_len--; /* check validity: we must have consumed everything */ if (str_len > 0 || (ch & ~((2 << ((bit_len - 1) % 4)) - 1)) != 0) { LOG_ERROR("value execeeds length"); return ERROR_FAIL; } return ERROR_OK; } static int svf_check_tdo(void) { int i, len, index_var; for (i = 0; i < svf_check_tdo_para_index; i++) { index_var = svf_check_tdo_para[i].buffer_offset; len = svf_check_tdo_para[i].bit_len; if ((svf_check_tdo_para[i].enabled) && buf_cmp_mask(&svf_tdi_buffer[index_var], &svf_tdo_buffer[index_var], &svf_mask_buffer[index_var], len)) { unsigned bitmask; unsigned received, expected, tapmask; bitmask = svf_get_mask_u32(svf_check_tdo_para[i].bit_len); memcpy(&received, svf_tdi_buffer + index_var, sizeof(unsigned)); memcpy(&expected, svf_tdo_buffer + index_var, sizeof(unsigned)); memcpy(&tapmask, svf_mask_buffer + index_var, sizeof(unsigned)); LOG_ERROR("tdo check error at line %d", svf_check_tdo_para[i].line_num); LOG_ERROR("read = 0x%X, want = 0x%X, mask = 0x%X", received & bitmask, expected & bitmask, tapmask & bitmask); return ERROR_FAIL; } } svf_check_tdo_para_index = 0; return ERROR_OK; } static int svf_add_check_para(uint8_t enabled, int buffer_offset, int bit_len) { if (svf_check_tdo_para_index >= SVF_CHECK_TDO_PARA_SIZE) { LOG_ERROR("toooooo many operation undone"); return ERROR_FAIL; } svf_check_tdo_para[svf_check_tdo_para_index].line_num = svf_line_number; svf_check_tdo_para[svf_check_tdo_para_index].bit_len = bit_len; svf_check_tdo_para[svf_check_tdo_para_index].enabled = enabled; svf_check_tdo_para[svf_check_tdo_para_index].buffer_offset = buffer_offset; svf_check_tdo_para_index++; return ERROR_OK; } static int svf_execute_tap(void) { if ((!svf_nil) && (ERROR_OK != jtag_execute_queue())) return ERROR_FAIL; else if (ERROR_OK != svf_check_tdo()) return ERROR_FAIL; svf_buffer_index = 0; return ERROR_OK; } static int svf_run_command(struct command_context *cmd_ctx, char *cmd_str) { char *argus[256], command; int num_of_argu = 0, i; /* tmp variable */ int i_tmp; /* for RUNTEST */ int run_count; float min_time; /* for XXR */ struct svf_xxr_para *xxr_para_tmp; uint8_t **pbuffer_tmp; struct scan_field field; /* for STATE */ tap_state_t *path = NULL, state; /* flag padding commands skipped due to -tap command */ int padding_command_skipped = 0; if (ERROR_OK != svf_parse_cmd_string(cmd_str, strlen(cmd_str), argus, &num_of_argu)) return ERROR_FAIL; /* NOTE: we're a bit loose here, because we ignore case in * TAP state names (instead of insisting on uppercase). */ command = svf_find_string_in_array(argus[0], (char **)svf_command_name, ARRAY_SIZE(svf_command_name)); switch (command) { case ENDDR: case ENDIR: if (num_of_argu != 2) { LOG_ERROR("invalid parameter of %s", argus[0]); return ERROR_FAIL; } i_tmp = tap_state_by_name(argus[1]); if (svf_tap_state_is_stable(i_tmp)) { if (command == ENDIR) { svf_para.ir_end_state = i_tmp; LOG_DEBUG("\tIR end_state = %s", tap_state_name(i_tmp)); } else { svf_para.dr_end_state = i_tmp; LOG_DEBUG("\tDR end_state = %s", tap_state_name(i_tmp)); } } else { LOG_ERROR("%s: %s is not a stable state", argus[0], argus[1]); return ERROR_FAIL; } break; case FREQUENCY: if ((num_of_argu != 1) && (num_of_argu != 3)) { LOG_ERROR("invalid parameter of %s", argus[0]); return ERROR_FAIL; } if (1 == num_of_argu) { /* TODO: set jtag speed to full speed */ svf_para.frequency = 0; } else { if (strcmp(argus[2], "HZ")) { LOG_ERROR("HZ not found in FREQUENCY command"); return ERROR_FAIL; } if (ERROR_OK != svf_execute_tap()) return ERROR_FAIL; svf_para.frequency = atof(argus[1]); /* TODO: set jtag speed to */ if (svf_para.frequency > 0) { command_run_linef(cmd_ctx, "adapter_khz %d", (int)svf_para.frequency / 1000); LOG_DEBUG("\tfrequency = %f", svf_para.frequency); } } break; case HDR: if (svf_tap_is_specified) { padding_command_skipped = 1; break; } xxr_para_tmp = &svf_para.hdr_para; goto XXR_common; case HIR: if (svf_tap_is_specified) { padding_command_skipped = 1; break; } xxr_para_tmp = &svf_para.hir_para; goto XXR_common; case TDR: if (svf_tap_is_specified) { padding_command_skipped = 1; break; } xxr_para_tmp = &svf_para.tdr_para; goto XXR_common; case TIR: if (svf_tap_is_specified) { padding_command_skipped = 1; break; } xxr_para_tmp = &svf_para.tir_para; goto XXR_common; case SDR: xxr_para_tmp = &svf_para.sdr_para; goto XXR_common; case SIR: xxr_para_tmp = &svf_para.sir_para; goto XXR_common; XXR_common: /* XXR length [TDI (tdi)] [TDO (tdo)][MASK (mask)] [SMASK (smask)] */ if ((num_of_argu > 10) || (num_of_argu % 2)) { LOG_ERROR("invalid parameter of %s", argus[0]); return ERROR_FAIL; } i_tmp = xxr_para_tmp->len; xxr_para_tmp->len = atoi(argus[1]); LOG_DEBUG("\tlength = %d", xxr_para_tmp->len); xxr_para_tmp->data_mask = 0; for (i = 2; i < num_of_argu; i += 2) { if ((strlen(argus[i + 1]) < 3) || (argus[i + 1][0] != '(') || (argus[i + 1][strlen(argus[i + 1]) - 1] != ')')) { LOG_ERROR("data section error"); return ERROR_FAIL; } argus[i + 1][strlen(argus[i + 1]) - 1] = '\0'; /* TDI, TDO, MASK, SMASK */ if (!strcmp(argus[i], "TDI")) { /* TDI */ pbuffer_tmp = &xxr_para_tmp->tdi; xxr_para_tmp->data_mask |= XXR_TDI; } else if (!strcmp(argus[i], "TDO")) { /* TDO */ pbuffer_tmp = &xxr_para_tmp->tdo; xxr_para_tmp->data_mask |= XXR_TDO; } else if (!strcmp(argus[i], "MASK")) { /* MASK */ pbuffer_tmp = &xxr_para_tmp->mask; xxr_para_tmp->data_mask |= XXR_MASK; } else if (!strcmp(argus[i], "SMASK")) { /* SMASK */ pbuffer_tmp = &xxr_para_tmp->smask; xxr_para_tmp->data_mask |= XXR_SMASK; } else { LOG_ERROR("unknow parameter: %s", argus[i]); return ERROR_FAIL; } if (ERROR_OK != svf_copy_hexstring_to_binary(&argus[i + 1][1], pbuffer_tmp, i_tmp, xxr_para_tmp->len)) { LOG_ERROR("fail to parse hex value"); return ERROR_FAIL; } LOG_DEBUG("\t%s = 0x%X", argus[i], (**(int **)pbuffer_tmp) & svf_get_mask_u32(xxr_para_tmp->len)); } /* If a command changes the length of the last scan of the same type and the * MASK parameter is absent, */ /* the mask pattern used is all cares */ if (!(xxr_para_tmp->data_mask & XXR_MASK) && (i_tmp != xxr_para_tmp->len)) { /* MASK not defined and length changed */ if (ERROR_OK != svf_adjust_array_length(&xxr_para_tmp->mask, i_tmp, xxr_para_tmp->len)) { LOG_ERROR("fail to adjust length of array"); return ERROR_FAIL; } buf_set_ones(xxr_para_tmp->mask, xxr_para_tmp->len); } /* If TDO is absent, no comparison is needed, set the mask to 0 */ if (!(xxr_para_tmp->data_mask & XXR_TDO)) { if (NULL == xxr_para_tmp->tdo) { if (ERROR_OK != svf_adjust_array_length(&xxr_para_tmp->tdo, i_tmp, xxr_para_tmp->len)) { LOG_ERROR("fail to adjust length of array"); return ERROR_FAIL; } } if (NULL == xxr_para_tmp->mask) { if (ERROR_OK != svf_adjust_array_length(&xxr_para_tmp->mask, i_tmp, xxr_para_tmp->len)) { LOG_ERROR("fail to adjust length of array"); return ERROR_FAIL; } } memset(xxr_para_tmp->mask, 0, (xxr_para_tmp->len + 7) >> 3); } /* do scan if necessary */ if (SDR == command) { /* check buffer size first, reallocate if necessary */ i = svf_para.hdr_para.len + svf_para.sdr_para.len + svf_para.tdr_para.len; if ((svf_buffer_size - svf_buffer_index) < ((i + 7) >> 3)) { #if 1 /* simply print error message */ LOG_ERROR("buffer is not enough, report to author"); return ERROR_FAIL; #else uint8_t *buffer_tmp; /* reallocate buffer */ buffer_tmp = (uint8_t *)malloc(svf_buffer_index + ((i + 7) >> 3)); if (NULL == buffer_tmp) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } memcpy(buffer_tmp, svf_tdi_buffer, svf_buffer_index); /* svf_tdi_buffer isn't NULL here */ free(svf_tdi_buffer); svf_tdi_buffer = buffer_tmp; buffer_tmp = (uint8_t *)malloc(svf_buffer_index + ((i + 7) >> 3)); if (NULL == buffer_tmp) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } memcpy(buffer_tmp, svf_tdo_buffer, svf_buffer_index); /* svf_tdo_buffer isn't NULL here */ free(svf_tdo_buffer); svf_tdo_buffer = buffer_tmp; buffer_tmp = (uint8_t *)malloc(svf_buffer_index + ((i + 7) >> 3)); if (NULL == buffer_tmp) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } memcpy(buffer_tmp, svf_mask_buffer, svf_buffer_index); /* svf_mask_buffer isn't NULL here */ free(svf_mask_buffer); svf_mask_buffer = buffer_tmp; buffer_tmp = NULL; svf_buffer_size = svf_buffer_index + ((i + 7) >> 3); #endif } /* assemble dr data */ i = 0; buf_set_buf(svf_para.hdr_para.tdi, 0, &svf_tdi_buffer[svf_buffer_index], i, svf_para.hdr_para.len); i += svf_para.hdr_para.len; buf_set_buf(svf_para.sdr_para.tdi, 0, &svf_tdi_buffer[svf_buffer_index], i, svf_para.sdr_para.len); i += svf_para.sdr_para.len; buf_set_buf(svf_para.tdr_para.tdi, 0, &svf_tdi_buffer[svf_buffer_index], i, svf_para.tdr_para.len); i += svf_para.tdr_para.len; /* add check data */ if (svf_para.sdr_para.data_mask & XXR_TDO) { /* assemble dr mask data */ i = 0; buf_set_buf(svf_para.hdr_para.mask, 0, &svf_mask_buffer[svf_buffer_index], i, svf_para.hdr_para.len); i += svf_para.hdr_para.len; buf_set_buf(svf_para.sdr_para.mask, 0, &svf_mask_buffer[svf_buffer_index], i, svf_para.sdr_para.len); i += svf_para.sdr_para.len; buf_set_buf(svf_para.tdr_para.mask, 0, &svf_mask_buffer[svf_buffer_index], i, svf_para.tdr_para.len); /* assemble dr check data */ i = 0; buf_set_buf(svf_para.hdr_para.tdo, 0, &svf_tdo_buffer[svf_buffer_index], i, svf_para.hdr_para.len); i += svf_para.hdr_para.len; buf_set_buf(svf_para.sdr_para.tdo, 0, &svf_tdo_buffer[svf_buffer_index], i, svf_para.sdr_para.len); i += svf_para.sdr_para.len; buf_set_buf(svf_para.tdr_para.tdo, 0, &svf_tdo_buffer[svf_buffer_index], i, svf_para.tdr_para.len); i += svf_para.tdr_para.len; svf_add_check_para(1, svf_buffer_index, i); } else svf_add_check_para(0, svf_buffer_index, i); field.num_bits = i; field.out_value = &svf_tdi_buffer[svf_buffer_index]; field.in_value = &svf_tdi_buffer[svf_buffer_index]; if (!svf_nil) { /* NOTE: doesn't use SVF-specified state paths */ jtag_add_plain_dr_scan(field.num_bits, field.out_value, field.in_value, svf_para.dr_end_state); } svf_buffer_index += (i + 7) >> 3; } else if (SIR == command) { /* check buffer size first, reallocate if necessary */ i = svf_para.hir_para.len + svf_para.sir_para.len + svf_para.tir_para.len; if ((svf_buffer_size - svf_buffer_index) < ((i + 7) >> 3)) { #if 1 /* simply print error message */ LOG_ERROR("buffer is not enough, report to author"); return ERROR_FAIL; #else uint8_t *buffer_tmp; /* reallocate buffer */ buffer_tmp = (uint8_t *)malloc(svf_buffer_index + ((i + 7) >> 3)); if (NULL == buffer_tmp) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } memcpy(buffer_tmp, svf_tdi_buffer, svf_buffer_index); /* svf_tdi_buffer isn't NULL here */ free(svf_tdi_buffer); svf_tdi_buffer = buffer_tmp; buffer_tmp = (uint8_t *)malloc(svf_buffer_index + ((i + 7) >> 3)); if (NULL == buffer_tmp) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } memcpy(buffer_tmp, svf_tdo_buffer, svf_buffer_index); /* svf_tdo_buffer isn't NULL here */ free(svf_tdo_buffer); svf_tdo_buffer = buffer_tmp; buffer_tmp = (uint8_t *)malloc(svf_buffer_index + ((i + 7) >> 3)); if (NULL == buffer_tmp) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } memcpy(buffer_tmp, svf_mask_buffer, svf_buffer_index); /* svf_mask_buffer isn't NULL here */ free(svf_mask_buffer); svf_mask_buffer = buffer_tmp; buffer_tmp = NULL; svf_buffer_size = svf_buffer_index + ((i + 7) >> 3); #endif } /* assemble ir data */ i = 0; buf_set_buf(svf_para.hir_para.tdi, 0, &svf_tdi_buffer[svf_buffer_index], i, svf_para.hir_para.len); i += svf_para.hir_para.len; buf_set_buf(svf_para.sir_para.tdi, 0, &svf_tdi_buffer[svf_buffer_index], i, svf_para.sir_para.len); i += svf_para.sir_para.len; buf_set_buf(svf_para.tir_para.tdi, 0, &svf_tdi_buffer[svf_buffer_index], i, svf_para.tir_para.len); i += svf_para.tir_para.len; /* add check data */ if (svf_para.sir_para.data_mask & XXR_TDO) { /* assemble dr mask data */ i = 0; buf_set_buf(svf_para.hir_para.mask, 0, &svf_mask_buffer[svf_buffer_index], i, svf_para.hir_para.len); i += svf_para.hir_para.len; buf_set_buf(svf_para.sir_para.mask, 0, &svf_mask_buffer[svf_buffer_index], i, svf_para.sir_para.len); i += svf_para.sir_para.len; buf_set_buf(svf_para.tir_para.mask, 0, &svf_mask_buffer[svf_buffer_index], i, svf_para.tir_para.len); /* assemble dr check data */ i = 0; buf_set_buf(svf_para.hir_para.tdo, 0, &svf_tdo_buffer[svf_buffer_index], i, svf_para.hir_para.len); i += svf_para.hir_para.len; buf_set_buf(svf_para.sir_para.tdo, 0, &svf_tdo_buffer[svf_buffer_index], i, svf_para.sir_para.len); i += svf_para.sir_para.len; buf_set_buf(svf_para.tir_para.tdo, 0, &svf_tdo_buffer[svf_buffer_index], i, svf_para.tir_para.len); i += svf_para.tir_para.len; svf_add_check_para(1, svf_buffer_index, i); } else svf_add_check_para(0, svf_buffer_index, i); field.num_bits = i; field.out_value = &svf_tdi_buffer[svf_buffer_index]; field.in_value = &svf_tdi_buffer[svf_buffer_index]; if (!svf_nil) { /* NOTE: doesn't use SVF-specified state paths */ jtag_add_plain_ir_scan(field.num_bits, field.out_value, field.in_value, svf_para.ir_end_state); } svf_buffer_index += (i + 7) >> 3; } break; case PIO: case PIOMAP: LOG_ERROR("PIO and PIOMAP are not supported"); return ERROR_FAIL; break; case RUNTEST: /* RUNTEST [run_state] run_count run_clk [min_time SEC [MAXIMUM max_time * SEC]] [ENDSTATE end_state] */ /* RUNTEST [run_state] min_time SEC [MAXIMUM max_time SEC] [ENDSTATE * end_state] */ if ((num_of_argu < 3) && (num_of_argu > 11)) { LOG_ERROR("invalid parameter of %s", argus[0]); return ERROR_FAIL; } /* init */ run_count = 0; min_time = 0; i = 1; /* run_state */ i_tmp = tap_state_by_name(argus[i]); if (i_tmp != TAP_INVALID) { if (svf_tap_state_is_stable(i_tmp)) { svf_para.runtest_run_state = i_tmp; /* When a run_state is specified, the new * run_state becomes the default end_state. */ svf_para.runtest_end_state = i_tmp; LOG_DEBUG("\trun_state = %s", tap_state_name(i_tmp)); i++; } else { LOG_ERROR("%s: %s is not a stable state", argus[0], tap_state_name(i_tmp)); return ERROR_FAIL; } } /* run_count run_clk */ if (((i + 2) <= num_of_argu) && strcmp(argus[i + 1], "SEC")) { if (!strcmp(argus[i + 1], "TCK")) { /* clock source is TCK */ run_count = atoi(argus[i]); LOG_DEBUG("\trun_count@TCK = %d", run_count); } else { LOG_ERROR("%s not supported for clock", argus[i + 1]); return ERROR_FAIL; } i += 2; } /* min_time SEC */ if (((i + 2) <= num_of_argu) && !strcmp(argus[i + 1], "SEC")) { min_time = atof(argus[i]); LOG_DEBUG("\tmin_time = %fs", min_time); i += 2; } /* MAXIMUM max_time SEC */ if (((i + 3) <= num_of_argu) && !strcmp(argus[i], "MAXIMUM") && !strcmp(argus[i + 2], "SEC")) { float max_time = 0; max_time = atof(argus[i + 1]); LOG_DEBUG("\tmax_time = %fs", max_time); i += 3; } /* ENDSTATE end_state */ if (((i + 2) <= num_of_argu) && !strcmp(argus[i], "ENDSTATE")) { i_tmp = tap_state_by_name(argus[i + 1]); if (svf_tap_state_is_stable(i_tmp)) { svf_para.runtest_end_state = i_tmp; LOG_DEBUG("\tend_state = %s", tap_state_name(i_tmp)); } else { LOG_ERROR("%s: %s is not a stable state", argus[0], tap_state_name(i_tmp)); return ERROR_FAIL; } i += 2; } /* all parameter should be parsed */ if (i == num_of_argu) { #if 1 /* FIXME handle statemove failures */ uint32_t min_usec = 1000000 * min_time; /* enter into run_state if necessary */ if (cmd_queue_cur_state != svf_para.runtest_run_state) svf_add_statemove(svf_para.runtest_run_state); /* add clocks and/or min wait */ if (run_count > 0) { if (!svf_nil) jtag_add_clocks(run_count); } if (min_usec > 0) { if (!svf_nil) jtag_add_sleep(min_usec); } /* move to end_state if necessary */ if (svf_para.runtest_end_state != svf_para.runtest_run_state) svf_add_statemove(svf_para.runtest_end_state); #else if (svf_para.runtest_run_state != TAP_IDLE) { LOG_ERROR("cannot runtest in %s state", tap_state_name(svf_para.runtest_run_state)); return ERROR_FAIL; } if (!svf_nil) jtag_add_runtest(run_count, svf_para.runtest_end_state); #endif } else { LOG_ERROR("fail to parse parameter of RUNTEST, %d out of %d is parsed", i, num_of_argu); return ERROR_FAIL; } break; case STATE: /* STATE [pathstate1 [pathstate2 ...[pathstaten]]] stable_state */ if (num_of_argu < 2) { LOG_ERROR("invalid parameter of %s", argus[0]); return ERROR_FAIL; } if (num_of_argu > 2) { /* STATE pathstate1 ... stable_state */ path = (tap_state_t *)malloc((num_of_argu - 1) * sizeof(tap_state_t)); if (NULL == path) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } num_of_argu--; /* num of path */ i_tmp = 1; /* path is from parameter 1 */ for (i = 0; i < num_of_argu; i++, i_tmp++) { path[i] = tap_state_by_name(argus[i_tmp]); if (path[i] == TAP_INVALID) { LOG_ERROR("%s: %s is not a valid state", argus[0], argus[i_tmp]); free(path); return ERROR_FAIL; } /* OpenOCD refuses paths containing TAP_RESET */ if (TAP_RESET == path[i]) { /* FIXME last state MUST be stable! */ if (i > 0) { if (!svf_nil) jtag_add_pathmove(i, path); } if (!svf_nil) jtag_add_tlr(); num_of_argu -= i + 1; i = -1; } } if (num_of_argu > 0) { /* execute last path if necessary */ if (svf_tap_state_is_stable(path[num_of_argu - 1])) { /* last state MUST be stable state */ if (!svf_nil) jtag_add_pathmove(num_of_argu, path); LOG_DEBUG("\tmove to %s by path_move", tap_state_name(path[num_of_argu - 1])); } else { LOG_ERROR("%s: %s is not a stable state", argus[0], tap_state_name(path[num_of_argu - 1])); free(path); return ERROR_FAIL; } } free(path); path = NULL; } else { /* STATE stable_state */ state = tap_state_by_name(argus[1]); if (svf_tap_state_is_stable(state)) { LOG_DEBUG("\tmove to %s by svf_add_statemove", tap_state_name(state)); /* FIXME handle statemove failures */ svf_add_statemove(state); } else { LOG_ERROR("%s: %s is not a stable state", argus[0], tap_state_name(state)); return ERROR_FAIL; } } break; case TRST: /* TRST trst_mode */ if (num_of_argu != 2) { LOG_ERROR("invalid parameter of %s", argus[0]); return ERROR_FAIL; } if (svf_para.trst_mode != TRST_ABSENT) { if (ERROR_OK != svf_execute_tap()) return ERROR_FAIL; i_tmp = svf_find_string_in_array(argus[1], (char **)svf_trst_mode_name, ARRAY_SIZE(svf_trst_mode_name)); switch (i_tmp) { case TRST_ON: if (!svf_nil) jtag_add_reset(1, 0); break; case TRST_Z: case TRST_OFF: if (!svf_nil) jtag_add_reset(0, 0); break; case TRST_ABSENT: break; default: LOG_ERROR("unknown TRST mode: %s", argus[1]); return ERROR_FAIL; } svf_para.trst_mode = i_tmp; LOG_DEBUG("\ttrst_mode = %s", svf_trst_mode_name[svf_para.trst_mode]); } else { LOG_ERROR("can not accpet TRST command if trst_mode is ABSENT"); return ERROR_FAIL; } break; default: LOG_ERROR("invalid svf command: %s", argus[0]); return ERROR_FAIL; break; } if (!svf_quiet) { if (padding_command_skipped) LOG_USER("(Above Padding command skipped, as per -tap argument)"); } if (debug_level >= LOG_LVL_DEBUG) { /* for convenient debugging, execute tap if possible */ if ((svf_buffer_index > 0) && \ (((command != STATE) && (command != RUNTEST)) || \ ((command == STATE) && (num_of_argu == 2)))) { if (ERROR_OK != svf_execute_tap()) return ERROR_FAIL; /* output debug info */ if ((SIR == command) || (SDR == command)) { int read_value; memcpy(&read_value, svf_tdi_buffer, sizeof(int)); /* in debug mode, data is from index 0 */ int read_mask = svf_get_mask_u32(svf_check_tdo_para[0].bit_len); LOG_DEBUG("\tTDO read = 0x%X", read_value & read_mask); } } } else { /* for fast executing, execute tap if necessary */ /* half of the buffer is for the next command */ if (((svf_buffer_index >= SVF_MAX_BUFFER_SIZE_TO_COMMIT) || (svf_check_tdo_para_index >= SVF_CHECK_TDO_PARA_SIZE / 2)) && \ (((command != STATE) && (command != RUNTEST)) || \ ((command == STATE) && (num_of_argu == 2)))) return svf_execute_tap(); } return ERROR_OK; } static const struct command_registration svf_command_handlers[] = { { .name = "svf", .handler = handle_svf_command, .mode = COMMAND_EXEC, .help = "Runs a SVF file.", .usage = "svf [-tap device.tap] [quiet] [nil] [progress]", }, COMMAND_REGISTRATION_DONE }; int svf_register_commands(struct command_context *cmd_ctx) { return register_commands(cmd_ctx, NULL, svf_command_handlers); } openocd-0.7.0/src/svf/Makefile.in0000644000175000001440000004072012141414276013521 00000000000000# Makefile.in generated by automake 1.13.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ DIST_COMMON = $(top_srcdir)/common.mk $(srcdir)/Makefile.in \ $(srcdir)/Makefile.am $(top_srcdir)/depcomp $(noinst_HEADERS) @INTERNAL_JIMTCL_TRUE@am__append_1 = -I$(top_srcdir)/jimtcl \ @INTERNAL_JIMTCL_TRUE@ -I$(top_builddir)/jimtcl subdir = src/svf ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/config_subdir.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libsvf_la_LIBADD = am_libsvf_la_OBJECTS = svf.lo libsvf_la_OBJECTS = $(am_libsvf_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libsvf_la_SOURCES) DIST_SOURCES = $(libsvf_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CC_FOR_BUILD = @CC_FOR_BUILD@ CFLAGS = @CFLAGS@ CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@ FGREP = @FGREP@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ doxygen_as_html = @doxygen_as_html@ doxygen_as_pdf = @doxygen_as_pdf@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ # common flags used in openocd build AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src \ -I$(top_srcdir)/src/helper -DPKGDATADIR=\"$(pkgdatadir)\" \ -DPKGLIBDIR=\"$(pkglibdir)\" $(am__append_1) METASOURCES = AUTO noinst_LTLIBRARIES = libsvf.la noinst_HEADERS = svf.h libsvf_la_SOURCES = svf.c MAINTAINERCLEANFILES = $(srcdir)/Makefile.in all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/common.mk $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/svf/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/svf/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_srcdir)/common.mk: $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libsvf.la: $(libsvf_la_OBJECTS) $(libsvf_la_DEPENDENCIES) $(EXTRA_libsvf_la_DEPENDENCIES) $(AM_V_CCLD)$(LINK) $(libsvf_la_OBJECTS) $(libsvf_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/svf.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: openocd-0.7.0/src/svf/Makefile.am0000644000175000001440000000026212134336410013500 00000000000000include $(top_srcdir)/common.mk METASOURCES = AUTO noinst_LTLIBRARIES = libsvf.la noinst_HEADERS = svf.h libsvf_la_SOURCES = svf.c MAINTAINERCLEANFILES = $(srcdir)/Makefile.in openocd-0.7.0/src/pld/0000755000175000001440000000000012141414413011503 500000000000000openocd-0.7.0/src/pld/virtex2.c0000644000175000001440000001524012134336410013176 00000000000000/*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "virtex2.h" #include "xilinx_bit.h" #include "pld.h" static int virtex2_set_instr(struct jtag_tap *tap, uint32_t new_instr) { if (tap == NULL) return ERROR_FAIL; if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != new_instr) { struct scan_field field; field.num_bits = tap->ir_length; void *t = calloc(DIV_ROUND_UP(field.num_bits, 8), 1); field.out_value = t; buf_set_u32(t, 0, field.num_bits, new_instr); field.in_value = NULL; jtag_add_ir_scan(tap, &field, TAP_IDLE); free(t); } return ERROR_OK; } static int virtex2_send_32(struct pld_device *pld_device, int num_words, uint32_t *words) { struct virtex2_pld_device *virtex2_info = pld_device->driver_priv; struct scan_field scan_field; uint8_t *values; int i; values = malloc(num_words * 4); scan_field.num_bits = num_words * 32; scan_field.out_value = values; scan_field.in_value = NULL; for (i = 0; i < num_words; i++) buf_set_u32(values + 4 * i, 0, 32, flip_u32(*words++, 32)); virtex2_set_instr(virtex2_info->tap, 0x5); /* CFG_IN */ jtag_add_dr_scan(virtex2_info->tap, 1, &scan_field, TAP_DRPAUSE); free(values); return ERROR_OK; } static inline void virtexflip32(jtag_callback_data_t arg) { uint8_t *in = (uint8_t *)arg; *((uint32_t *)arg) = flip_u32(le_to_h_u32(in), 32); } static int virtex2_receive_32(struct pld_device *pld_device, int num_words, uint32_t *words) { struct virtex2_pld_device *virtex2_info = pld_device->driver_priv; struct scan_field scan_field; scan_field.num_bits = 32; scan_field.out_value = NULL; scan_field.in_value = NULL; virtex2_set_instr(virtex2_info->tap, 0x4); /* CFG_OUT */ while (num_words--) { scan_field.in_value = (uint8_t *)words; jtag_add_dr_scan(virtex2_info->tap, 1, &scan_field, TAP_DRPAUSE); jtag_add_callback(virtexflip32, (jtag_callback_data_t)words); words++; } return ERROR_OK; } static int virtex2_read_stat(struct pld_device *pld_device, uint32_t *status) { uint32_t data[5]; jtag_add_tlr(); data[0] = 0xaa995566; /* synch word */ data[1] = 0x2800E001; /* Type 1, read, address 7, 1 word */ data[2] = 0x20000000; /* NOOP (Type 1, read, address 0, 0 words */ data[3] = 0x20000000; /* NOOP */ data[4] = 0x20000000; /* NOOP */ virtex2_send_32(pld_device, 5, data); virtex2_receive_32(pld_device, 1, status); jtag_execute_queue(); LOG_DEBUG("status: 0x%8.8" PRIx32 "", *status); return ERROR_OK; } static int virtex2_load(struct pld_device *pld_device, const char *filename) { struct virtex2_pld_device *virtex2_info = pld_device->driver_priv; struct xilinx_bit_file bit_file; int retval; unsigned int i; struct scan_field field; field.in_value = NULL; retval = xilinx_read_bit_file(&bit_file, filename); if (retval != ERROR_OK) return retval; virtex2_set_instr(virtex2_info->tap, 0xb); /* JPROG_B */ jtag_execute_queue(); jtag_add_sleep(1000); virtex2_set_instr(virtex2_info->tap, 0x5); /* CFG_IN */ jtag_execute_queue(); for (i = 0; i < bit_file.length; i++) bit_file.data[i] = flip_u32(bit_file.data[i], 8); field.num_bits = bit_file.length * 8; field.out_value = bit_file.data; jtag_add_dr_scan(virtex2_info->tap, 1, &field, TAP_DRPAUSE); jtag_execute_queue(); jtag_add_tlr(); virtex2_set_instr(virtex2_info->tap, 0xc); /* JSTART */ jtag_add_runtest(13, TAP_IDLE); virtex2_set_instr(virtex2_info->tap, 0x3f); /* BYPASS */ virtex2_set_instr(virtex2_info->tap, 0x3f); /* BYPASS */ virtex2_set_instr(virtex2_info->tap, 0xc); /* JSTART */ jtag_add_runtest(13, TAP_IDLE); virtex2_set_instr(virtex2_info->tap, 0x3f); /* BYPASS */ jtag_execute_queue(); return ERROR_OK; } COMMAND_HANDLER(virtex2_handle_read_stat_command) { struct pld_device *device; uint32_t status; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; unsigned dev_id; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], dev_id); device = get_pld_device_by_num(dev_id); if (!device) { command_print(CMD_CTX, "pld device '#%s' is out of bounds", CMD_ARGV[0]); return ERROR_OK; } virtex2_read_stat(device, &status); command_print(CMD_CTX, "virtex2 status register: 0x%8.8" PRIx32 "", status); return ERROR_OK; } PLD_DEVICE_COMMAND_HANDLER(virtex2_pld_device_command) { struct jtag_tap *tap; struct virtex2_pld_device *virtex2_info; if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; tap = jtag_tap_by_string(CMD_ARGV[1]); if (tap == NULL) { command_print(CMD_CTX, "Tap: %s does not exist", CMD_ARGV[1]); return ERROR_OK; } virtex2_info = malloc(sizeof(struct virtex2_pld_device)); virtex2_info->tap = tap; pld->driver_priv = virtex2_info; return ERROR_OK; } static const struct command_registration virtex2_exec_command_handlers[] = { { .name = "read_stat", .mode = COMMAND_EXEC, .handler = virtex2_handle_read_stat_command, .help = "read status register", .usage = "pld_num", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration virtex2_command_handler[] = { { .name = "virtex2", .mode = COMMAND_ANY, .help = "Virtex-II specific commands", .usage = "", .chain = virtex2_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; struct pld_driver virtex2_pld = { .name = "virtex2", .commands = virtex2_command_handler, .pld_device_command = &virtex2_pld_device_command, .load = &virtex2_load, }; openocd-0.7.0/src/pld/Makefile.in0000644000175000001440000004125212141414276013503 00000000000000# Makefile.in generated by automake 1.13.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ DIST_COMMON = $(top_srcdir)/common.mk $(srcdir)/Makefile.in \ $(srcdir)/Makefile.am $(top_srcdir)/depcomp $(noinst_HEADERS) @INTERNAL_JIMTCL_TRUE@am__append_1 = -I$(top_srcdir)/jimtcl \ @INTERNAL_JIMTCL_TRUE@ -I$(top_builddir)/jimtcl subdir = src/pld ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/config_subdir.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libpld_la_LIBADD = am_libpld_la_OBJECTS = pld.lo xilinx_bit.lo virtex2.lo libpld_la_OBJECTS = $(am_libpld_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libpld_la_SOURCES) DIST_SOURCES = $(libpld_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CC_FOR_BUILD = @CC_FOR_BUILD@ CFLAGS = @CFLAGS@ CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@ FGREP = @FGREP@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ doxygen_as_html = @doxygen_as_html@ doxygen_as_pdf = @doxygen_as_pdf@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ # common flags used in openocd build AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src \ -I$(top_srcdir)/src/helper -DPKGDATADIR=\"$(pkgdatadir)\" \ -DPKGLIBDIR=\"$(pkglibdir)\" $(am__append_1) METASOURCES = AUTO noinst_LTLIBRARIES = libpld.la noinst_HEADERS = pld.h xilinx_bit.h virtex2.h libpld_la_SOURCES = pld.c xilinx_bit.c virtex2.c MAINTAINERCLEANFILES = $(srcdir)/Makefile.in all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/common.mk $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/pld/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/pld/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_srcdir)/common.mk: $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libpld.la: $(libpld_la_OBJECTS) $(libpld_la_DEPENDENCIES) $(EXTRA_libpld_la_DEPENDENCIES) $(AM_V_CCLD)$(LINK) $(libpld_la_OBJECTS) $(libpld_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pld.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/virtex2.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xilinx_bit.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: openocd-0.7.0/src/pld/xilinx_bit.c0000644000175000001440000001036712134336410013751 00000000000000/*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "xilinx_bit.h" #include "pld.h" #include #include static int read_section(FILE *input_file, int length_size, char section, uint32_t *buffer_length, uint8_t **buffer) { uint8_t length_buffer[4]; int length; char section_char; int read_count; if ((length_size != 2) && (length_size != 4)) { LOG_ERROR("BUG: length_size neither 2 nor 4"); return ERROR_PLD_FILE_LOAD_FAILED; } read_count = fread(§ion_char, 1, 1, input_file); if (read_count != 1) return ERROR_PLD_FILE_LOAD_FAILED; if (section_char != section) return ERROR_PLD_FILE_LOAD_FAILED; read_count = fread(length_buffer, 1, length_size, input_file); if (read_count != length_size) return ERROR_PLD_FILE_LOAD_FAILED; if (length_size == 4) length = be_to_h_u32(length_buffer); else /* (length_size == 2) */ length = be_to_h_u16(length_buffer); if (buffer_length) *buffer_length = length; *buffer = malloc(length); read_count = fread(*buffer, 1, length, input_file); if (read_count != length) return ERROR_PLD_FILE_LOAD_FAILED; return ERROR_OK; } int xilinx_read_bit_file(struct xilinx_bit_file *bit_file, const char *filename) { FILE *input_file; struct stat input_stat; int read_count; if (!filename || !bit_file) return ERROR_COMMAND_SYNTAX_ERROR; if (stat(filename, &input_stat) == -1) { LOG_ERROR("couldn't stat() %s: %s", filename, strerror(errno)); return ERROR_PLD_FILE_LOAD_FAILED; } if (S_ISDIR(input_stat.st_mode)) { LOG_ERROR("%s is a directory", filename); return ERROR_PLD_FILE_LOAD_FAILED; } if (input_stat.st_size == 0) { LOG_ERROR("Empty file %s", filename); return ERROR_PLD_FILE_LOAD_FAILED; } input_file = fopen(filename, "rb"); if (input_file == NULL) { LOG_ERROR("couldn't open %s: %s", filename, strerror(errno)); return ERROR_PLD_FILE_LOAD_FAILED; } read_count = fread(bit_file->unknown_header, 1, 13, input_file); if (read_count != 13) { LOG_ERROR("couldn't read unknown_header from file '%s'", filename); return ERROR_PLD_FILE_LOAD_FAILED; } if (read_section(input_file, 2, 'a', NULL, &bit_file->source_file) != ERROR_OK) return ERROR_PLD_FILE_LOAD_FAILED; if (read_section(input_file, 2, 'b', NULL, &bit_file->part_name) != ERROR_OK) return ERROR_PLD_FILE_LOAD_FAILED; if (read_section(input_file, 2, 'c', NULL, &bit_file->date) != ERROR_OK) return ERROR_PLD_FILE_LOAD_FAILED; if (read_section(input_file, 2, 'd', NULL, &bit_file->time) != ERROR_OK) return ERROR_PLD_FILE_LOAD_FAILED; if (read_section(input_file, 4, 'e', &bit_file->length, &bit_file->data) != ERROR_OK) return ERROR_PLD_FILE_LOAD_FAILED; LOG_DEBUG("bit_file: %s %s %s,%s %" PRIi32 "", bit_file->source_file, bit_file->part_name, bit_file->date, bit_file->time, bit_file->length); fclose(input_file); return ERROR_OK; } openocd-0.7.0/src/pld/pld.c0000644000175000001440000001401712134336410012353 00000000000000/*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "pld.h" #include #include /* pld drivers */ extern struct pld_driver virtex2_pld; static struct pld_driver *pld_drivers[] = { &virtex2_pld, NULL, }; static struct pld_device *pld_devices; struct pld_device *get_pld_device_by_num(int num) { struct pld_device *p; int i = 0; for (p = pld_devices; p; p = p->next) { if (i++ == num) return p; } return NULL; } /* pld device [driver_options ...] */ COMMAND_HANDLER(handle_pld_device_command) { int i; int found = 0; if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; for (i = 0; pld_drivers[i]; i++) { if (strcmp(CMD_ARGV[0], pld_drivers[i]->name) == 0) { struct pld_device *p, *c; /* register pld specific commands */ int retval; if (pld_drivers[i]->commands) { retval = register_commands(CMD_CTX, NULL, pld_drivers[i]->commands); if (ERROR_OK != retval) { LOG_ERROR("couldn't register '%s' commands", CMD_ARGV[0]); return ERROR_FAIL; } } c = malloc(sizeof(struct pld_device)); c->driver = pld_drivers[i]; c->next = NULL; retval = CALL_COMMAND_HANDLER( pld_drivers[i]->pld_device_command, c); if (ERROR_OK != retval) { LOG_ERROR("'%s' driver rejected pld device", CMD_ARGV[0]); free(c); return ERROR_OK; } /* put pld device in linked list */ if (pld_devices) { /* find last pld device */ for (p = pld_devices; p && p->next; p = p->next) ; if (p) p->next = c; } else pld_devices = c; found = 1; } } /* no matching pld driver found */ if (!found) { LOG_ERROR("pld driver '%s' not found", CMD_ARGV[0]); exit(-1); } return ERROR_OK; } COMMAND_HANDLER(handle_pld_devices_command) { struct pld_device *p; int i = 0; if (!pld_devices) { command_print(CMD_CTX, "no pld devices configured"); return ERROR_OK; } for (p = pld_devices; p; p = p->next) command_print(CMD_CTX, "#%i: %s", i++, p->driver->name); return ERROR_OK; } COMMAND_HANDLER(handle_pld_load_command) { int retval; struct timeval start, end, duration; struct pld_device *p; gettimeofday(&start, NULL); if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; unsigned dev_id; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], dev_id); p = get_pld_device_by_num(dev_id); if (!p) { command_print(CMD_CTX, "pld device '#%s' is out of bounds", CMD_ARGV[0]); return ERROR_OK; } retval = p->driver->load(p, CMD_ARGV[1]); if (retval != ERROR_OK) { command_print(CMD_CTX, "failed loading file %s to pld device %u", CMD_ARGV[1], dev_id); switch (retval) { } return retval; } else { gettimeofday(&end, NULL); timeval_subtract(&duration, &end, &start); command_print(CMD_CTX, "loaded file %s to pld device %u in %jis %jius", CMD_ARGV[1], dev_id, (intmax_t)duration.tv_sec, (intmax_t)duration.tv_usec); } return ERROR_OK; } static const struct command_registration pld_exec_command_handlers[] = { { .name = "devices", .handler = handle_pld_devices_command, .mode = COMMAND_EXEC, .help = "list configured pld devices", }, { .name = "load", .handler = handle_pld_load_command, .mode = COMMAND_EXEC, .help = "load configuration file into PLD", .usage = "pld_num filename", }, COMMAND_REGISTRATION_DONE }; static int pld_init(struct command_context *cmd_ctx) { if (!pld_devices) return ERROR_OK; struct command *parent = command_find_in_context(cmd_ctx, "pld"); return register_commands(cmd_ctx, parent, pld_exec_command_handlers); } COMMAND_HANDLER(handle_pld_init_command) { if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; static bool pld_initialized; if (pld_initialized) { LOG_INFO("'pld init' has already been called"); return ERROR_OK; } pld_initialized = true; LOG_DEBUG("Initializing PLDs..."); return pld_init(CMD_CTX); } static const struct command_registration pld_config_command_handlers[] = { { .name = "device", .mode = COMMAND_CONFIG, .handler = handle_pld_device_command, .help = "configure a PLD device", .usage = "driver_name [driver_args ... ]", }, { .name = "init", .mode = COMMAND_CONFIG, .handler = handle_pld_init_command, .help = "initialize PLD devices", .usage = "" }, COMMAND_REGISTRATION_DONE }; static const struct command_registration pld_command_handler[] = { { .name = "pld", .mode = COMMAND_ANY, .help = "programmable logic device commands", .usage = "", .chain = pld_config_command_handlers, }, COMMAND_REGISTRATION_DONE }; int pld_register_commands(struct command_context *cmd_ctx) { return register_commands(cmd_ctx, NULL, pld_command_handler); } openocd-0.7.0/src/pld/xilinx_bit.h0000644000175000001440000000337112134336410013753 00000000000000/*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef XILINX_BIT_H #define XILINX_BIT_H struct xilinx_bit_file { uint8_t unknown_header[13]; uint8_t *source_file; uint8_t *part_name; uint8_t *date; uint8_t *time; uint32_t length; uint8_t *data; }; int xilinx_read_bit_file(struct xilinx_bit_file *bit_file, const char *filename); #endif /* XILINX_BIT_H */ openocd-0.7.0/src/pld/Makefile.am0000644000175000001440000000034012134336410013456 00000000000000include $(top_srcdir)/common.mk METASOURCES = AUTO noinst_LTLIBRARIES = libpld.la noinst_HEADERS = pld.h xilinx_bit.h virtex2.h libpld_la_SOURCES = pld.c xilinx_bit.c virtex2.c MAINTAINERCLEANFILES = $(srcdir)/Makefile.in openocd-0.7.0/src/pld/pld.h0000644000175000001440000000427312134336410012363 00000000000000/*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef PLD_H #define PLD_H #include struct pld_device; #define __PLD_DEVICE_COMMAND(name) \ COMMAND_HELPER(name, struct pld_device *pld) struct pld_driver { const char *name; __PLD_DEVICE_COMMAND((*pld_device_command)); const struct command_registration *commands; int (*load)(struct pld_device *pld_device, const char *filename); }; #define PLD_DEVICE_COMMAND_HANDLER(name) \ static __PLD_DEVICE_COMMAND(name) struct pld_device { struct pld_driver *driver; void *driver_priv; struct pld_device *next; }; int pld_register_commands(struct command_context *cmd_ctx); struct pld_device *get_pld_device_by_num(int num); #define ERROR_PLD_DEVICE_INVALID (-1000) #define ERROR_PLD_FILE_LOAD_FAILED (-1001) #endif /* PLD_H */ openocd-0.7.0/src/pld/virtex2.h0000644000175000001440000000310412134336410013177 00000000000000/*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef VIRTEX2_H #define VIRTEX2_H #include struct virtex2_pld_device { struct jtag_tap *tap; }; #endif /* VIRTEX2_H */ openocd-0.7.0/src/openocd.c0000644000175000001440000002234712134336410012451 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 Richard Missenden * * richard.missenden@googlemail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "openocd.h" #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_STRINGS_H #include #endif #define OPENOCD_VERSION \ "Open On-Chip Debugger " VERSION RELSTR " (" PKGBLDDATE ")" /* Give scripts and TELNET a way to find out what version this is */ static int jim_version_command(Jim_Interp *interp, int argc, Jim_Obj * const *argv) { if (argc > 2) return JIM_ERR; const char *str = ""; char *version_str; version_str = OPENOCD_VERSION; if (argc == 2) str = Jim_GetString(argv[1], NULL); if (strcmp("git", str) == 0) version_str = GITVERSION; Jim_SetResult(interp, Jim_NewStringObj(interp, version_str, -1)); return JIM_OK; } static int log_target_callback_event_handler(struct target *target, enum target_event event, void *priv) { switch (event) { case TARGET_EVENT_GDB_START: target->display = 0; break; case TARGET_EVENT_GDB_END: target->display = 1; break; case TARGET_EVENT_HALTED: if (target->display) { /* do not display information when debugger caused the halt */ target_arch_state(target); } break; default: break; } return ERROR_OK; } static bool init_at_startup = true; COMMAND_HANDLER(handle_noinit_command) { if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; init_at_startup = false; return ERROR_OK; } /* OpenOCD can't really handle failure of this command. Patches welcome! :-) */ COMMAND_HANDLER(handle_init_command) { if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; int retval; static int initialized; if (initialized) return ERROR_OK; initialized = 1; retval = command_run_line(CMD_CTX, "target init"); if (ERROR_OK != retval) return ERROR_FAIL; retval = adapter_init(CMD_CTX); if (retval != ERROR_OK) { /* we must be able to set up the debug adapter */ return retval; } LOG_DEBUG("Debug Adapter init complete"); /* "transport init" verifies the expected devices are present; * for JTAG, it checks the list of configured TAPs against * what's discoverable, possibly with help from the platform's * JTAG event handlers. (which require COMMAND_EXEC) */ command_context_mode(CMD_CTX, COMMAND_EXEC); retval = command_run_line(CMD_CTX, "transport init"); if (ERROR_OK != retval) return ERROR_FAIL; LOG_DEBUG("Examining targets..."); if (target_examine() != ERROR_OK) LOG_DEBUG("target examination failed"); command_context_mode(CMD_CTX, COMMAND_CONFIG); if (command_run_line(CMD_CTX, "flash init") != ERROR_OK) return ERROR_FAIL; if (command_run_line(CMD_CTX, "mflash init") != ERROR_OK) return ERROR_FAIL; if (command_run_line(CMD_CTX, "nand init") != ERROR_OK) return ERROR_FAIL; if (command_run_line(CMD_CTX, "pld init") != ERROR_OK) return ERROR_FAIL; command_context_mode(CMD_CTX, COMMAND_EXEC); /* initialize telnet subsystem */ gdb_target_add_all(all_targets); target_register_event_callback(log_target_callback_event_handler, CMD_CTX); return ERROR_OK; } COMMAND_HANDLER(handle_add_script_search_dir_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; add_script_search_dir(CMD_ARGV[0]); return ERROR_OK; } static const struct command_registration openocd_command_handlers[] = { { .name = "version", .jim_handler = jim_version_command, .mode = COMMAND_ANY, .help = "show program version", }, { .name = "noinit", .handler = &handle_noinit_command, .mode = COMMAND_CONFIG, .help = "Prevent 'init' from being called at startup.", .usage = "" }, { .name = "init", .handler = &handle_init_command, .mode = COMMAND_ANY, .help = "Initializes configured targets and servers. " "Changes command mode from CONFIG to EXEC. " "Unless 'noinit' is called, this command is " "called automatically at the end of startup.", .usage = "" }, { .name = "add_script_search_dir", .handler = &handle_add_script_search_dir_command, .mode = COMMAND_ANY, .help = "dir to search for config files and scripts", .usage = "" }, COMMAND_REGISTRATION_DONE }; static int openocd_register_commands(struct command_context *cmd_ctx) { return register_commands(cmd_ctx, NULL, openocd_command_handlers); } struct command_context *global_cmd_ctx; /* NB! this fn can be invoked outside this file for non PC hosted builds * NB! do not change to 'static'!!!! */ struct command_context *setup_command_handler(Jim_Interp *interp) { log_init(); LOG_DEBUG("log_init: complete"); const char *startup = openocd_startup_tcl; struct command_context *cmd_ctx = command_init(startup, interp); /* register subsystem commands */ typedef int (*command_registrant_t)(struct command_context *cmd_ctx_value); static const command_registrant_t command_registrants[] = { &openocd_register_commands, &server_register_commands, &gdb_register_commands, &log_register_commands, &transport_register_commands, &interface_register_commands, &target_register_commands, &flash_register_commands, &nand_register_commands, &pld_register_commands, &mflash_register_commands, NULL }; for (unsigned i = 0; NULL != command_registrants[i]; i++) { int retval = (*command_registrants[i])(cmd_ctx); if (ERROR_OK != retval) { command_done(cmd_ctx); return NULL; } } LOG_DEBUG("command registration: complete"); LOG_OUTPUT(OPENOCD_VERSION "\n" "Licensed under GNU GPL v2\n"); global_cmd_ctx = cmd_ctx; return cmd_ctx; } /** OpenOCD runtime meat that can become single-thread in future. It parse * commandline, reads configuration, sets up the target and starts server loop. * Commandline arguments are passed into this function from openocd_main(). */ static int openocd_thread(int argc, char *argv[], struct command_context *cmd_ctx) { int ret; if (parse_cmdline_args(cmd_ctx, argc, argv) != ERROR_OK) return EXIT_FAILURE; if (server_preinit() != ERROR_OK) return EXIT_FAILURE; ret = parse_config_file(cmd_ctx); if (ret != ERROR_OK) return EXIT_FAILURE; ret = server_init(cmd_ctx); if (ERROR_OK != ret) return EXIT_FAILURE; if (init_at_startup) { ret = command_run_line(cmd_ctx, "init"); if (ERROR_OK != ret) return EXIT_FAILURE; } server_loop(cmd_ctx); server_quit(); return ret; } /* normally this is the main() function entry, but if OpenOCD is linked * into application, then this fn will not be invoked, but rather that * application will have it's own implementation of main(). */ int openocd_main(int argc, char *argv[]) { int ret; /* initialize commandline interface */ struct command_context *cmd_ctx; cmd_ctx = setup_command_handler(NULL); if (util_init(cmd_ctx) != ERROR_OK) return EXIT_FAILURE; if (ioutil_init(cmd_ctx) != ERROR_OK) return EXIT_FAILURE; LOG_OUTPUT("For bug reports, read\n\t" "http://openocd.sourceforge.net/doc/doxygen/bugs.html" "\n"); command_context_mode(cmd_ctx, COMMAND_CONFIG); command_set_output_handler(cmd_ctx, configuration_output_handler, NULL); /* Start the executable meat that can evolve into thread in future. */ ret = openocd_thread(argc, argv, cmd_ctx); unregister_all_commands(cmd_ctx, NULL); /* free commandline interface */ command_done(cmd_ctx); adapter_quit(); return ret; } openocd-0.7.0/src/jtag/0000755000175000001440000000000012141414412011650 500000000000000openocd-0.7.0/src/jtag/zy1000/0000755000175000001440000000000012141414412012613 500000000000000openocd-0.7.0/src/jtag/zy1000/zy1000.c0000644000175000001440000007453312134336410013661 00000000000000/*************************************************************************** * Copyright (C) 2007-2010 by Øyvind Harboe * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /* This file supports the zy1000 debugger: * * http://www.ultsol.com/index.php/component/content/article/8/33-zylin-zy1000-jtag-probe * * The zy1000 is a standalone debugger that has a web interface and * requires no drivers on the developer host as all communication * is via TCP/IP. The zy1000 gets it performance(~400-700kBytes/s * DCC downloads @ 16MHz target) as it has an FPGA to hardware * accelerate the JTAG commands, while offering *very* low latency * between OpenOCD and the FPGA registers. * * The disadvantage of the zy1000 is that it has a feeble CPU compared to * a PC(ca. 50-500 DMIPS depending on how one counts it), whereas a PC * is on the order of 10000 DMIPS(i.e. at a factor of 20-200). * * The zy1000 revc hardware is using an Altera Nios CPU, whereas the * revb is using ARM7 + Xilinx. * * See Zylin web pages or contact Zylin for more information. * * The reason this code is in OpenOCD rather than OpenOCD linked with the * ZY1000 code is that OpenOCD is the long road towards getting * libopenocd into place. libopenocd will support both low performance, * low latency systems(embedded) and high performance high latency * systems(PCs). */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include /* Assume we're connecting to a revc w/60MHz clock. */ #define ZYLIN_KHZ 60000 /* The software needs to check if it's in RCLK mode or not */ static bool zy1000_rclk; static int zy1000_khz(int khz, int *jtag_speed) { if (khz == 0) *jtag_speed = 0; else { int speed; /* Round speed up to nearest divisor. * * E.g. 16000kHz * (64000 + 15999) / 16000 = 4 * (4 + 1) / 2 = 2 * 2 * 2 = 4 * * 64000 / 4 = 16000 * * E.g. 15999 * (64000 + 15998) / 15999 = 5 * (5 + 1) / 2 = 3 * 3 * 2 = 6 * * 64000 / 6 = 10666 * */ speed = (ZYLIN_KHZ + (khz - 1)) / khz; speed = (speed + 1) / 2; speed *= 2; if (speed > 8190) { /* maximum dividend */ speed = 8190; } *jtag_speed = speed; } return ERROR_OK; } static int zy1000_speed_div(int speed, int *khz) { if (speed == 0) *khz = 0; else *khz = ZYLIN_KHZ / speed; return ERROR_OK; } static bool readPowerDropout(void) { uint32_t state; /* sample and clear power dropout */ ZY1000_POKE(ZY1000_JTAG_BASE + 0x10, 0x80); ZY1000_PEEK(ZY1000_JTAG_BASE + 0x10, state); bool powerDropout; powerDropout = (state & 0x80) != 0; return powerDropout; } static bool readSRST(void) { uint32_t state; /* sample and clear SRST sensing */ ZY1000_POKE(ZY1000_JTAG_BASE + 0x10, 0x00000040); ZY1000_PEEK(ZY1000_JTAG_BASE + 0x10, state); bool srstAsserted; srstAsserted = (state & 0x40) != 0; return srstAsserted; } static int zy1000_srst_asserted(int *srst_asserted) { *srst_asserted = readSRST(); return ERROR_OK; } static int zy1000_power_dropout(int *dropout) { *dropout = readPowerDropout(); return ERROR_OK; } /* Wait for SRST to assert or deassert */ static void waitSRST(bool asserted) { bool first = true; long long start = 0; long total = 0; const char *mode = asserted ? "assert" : "deassert"; for (;; ) { bool srstAsserted = readSRST(); if ((asserted && srstAsserted) || (!asserted && !srstAsserted)) { if (total > 1) LOG_USER("SRST took %dms to %s", (int)total, mode); break; } if (first) { first = false; start = timeval_ms(); } total = timeval_ms() - start; keep_alive(); if (total > 5000) { LOG_ERROR("SRST took too long to %s: %dms", mode, (int)total); break; } } } void zy1000_reset(int trst, int srst) { LOG_DEBUG("zy1000 trst=%d, srst=%d", trst, srst); /* flush the JTAG FIFO. Not flushing the queue before messing with * reset has such interesting bugs as causing hard to reproduce * RCLK bugs as RCLK will stop responding when TRST is asserted */ waitIdle(); if (!srst) ZY1000_POKE(ZY1000_JTAG_BASE + 0x14, 0x00000001); else { /* Danger!!! if clk != 0 when in * idle in TAP_IDLE, reset halt on str912 will fail. */ ZY1000_POKE(ZY1000_JTAG_BASE + 0x10, 0x00000001); waitSRST(true); } if (!trst) ZY1000_POKE(ZY1000_JTAG_BASE + 0x14, 0x00000002); else { /* assert reset */ ZY1000_POKE(ZY1000_JTAG_BASE + 0x10, 0x00000002); } if (trst || (srst && (jtag_get_reset_config() & RESET_SRST_PULLS_TRST))) { /* we're now in the RESET state until trst is deasserted */ ZY1000_POKE(ZY1000_JTAG_BASE + 0x20, TAP_RESET); } else { /* We'll get RCLK failure when we assert TRST, so clear any false positives here */ ZY1000_POKE(ZY1000_JTAG_BASE + 0x14, 0x400); } /* wait for srst to float back up */ if ((!srst && ((jtag_get_reset_config() & RESET_TRST_PULLS_SRST) == 0)) || (!srst && !trst && (jtag_get_reset_config() & RESET_TRST_PULLS_SRST))) waitSRST(false); } int zy1000_speed(int speed) { /* flush JTAG master FIFO before setting speed */ waitIdle(); zy1000_rclk = false; if (speed == 0) { /*0 means RCLK*/ ZY1000_POKE(ZY1000_JTAG_BASE + 0x10, 0x100); zy1000_rclk = true; LOG_DEBUG("jtag_speed using RCLK"); } else { if (speed > 8190 || speed < 2) { LOG_USER( "valid ZY1000 jtag_speed=[8190,2]. With divisor is %dkHz / even values between 8190-2, i.e. min %dHz, max %dMHz", ZYLIN_KHZ, (ZYLIN_KHZ * 1000) / 8190, ZYLIN_KHZ / (2 * 1000)); return ERROR_COMMAND_SYNTAX_ERROR; } int khz; speed &= ~1; zy1000_speed_div(speed, &khz); LOG_USER("jtag_speed %d => JTAG clk=%d kHz", speed, khz); ZY1000_POKE(ZY1000_JTAG_BASE + 0x14, 0x100); ZY1000_POKE(ZY1000_JTAG_BASE + 0x1c, speed); } return ERROR_OK; } static bool savePower; static void setPower(bool power) { savePower = power; if (power) ZY1000_POKE(ZY1000_JTAG_BASE + 0x14, 0x8); else ZY1000_POKE(ZY1000_JTAG_BASE + 0x10, 0x8); } COMMAND_HANDLER(handle_power_command) { switch (CMD_ARGC) { case 1: { bool enable; COMMAND_PARSE_ON_OFF(CMD_ARGV[0], enable); setPower(enable); /* fall through */ } case 0: LOG_INFO("Target power %s", savePower ? "on" : "off"); break; default: return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; } #if !BUILD_ZY1000_MASTER static char *tcp_server = "notspecified"; static int jim_zy1000_server(Jim_Interp *interp, int argc, Jim_Obj * const *argv) { if (argc != 2) return JIM_ERR; tcp_server = strdup(Jim_GetString(argv[1], NULL)); return JIM_OK; } #endif static int zylinjtag_Jim_Command_powerstatus(Jim_Interp *interp, int argc, Jim_Obj * const *argv) { if (argc != 1) { Jim_WrongNumArgs(interp, 1, argv, "powerstatus"); return JIM_ERR; } bool dropout = readPowerDropout(); Jim_SetResult(interp, Jim_NewIntObj(interp, dropout)); return JIM_OK; } int zy1000_quit(void) { return ERROR_OK; } int interface_jtag_execute_queue(void) { uint32_t empty; waitIdle(); /* We must make sure to write data read back to memory location before we return * from this fn */ zy1000_flush_readqueue(); /* and handle any callbacks... */ zy1000_flush_callbackqueue(); if (zy1000_rclk) { /* Only check for errors when using RCLK to speed up * jtag over TCP/IP */ ZY1000_PEEK(ZY1000_JTAG_BASE + 0x10, empty); /* clear JTAG error register */ ZY1000_POKE(ZY1000_JTAG_BASE + 0x14, 0x400); if ((empty&0x400) != 0) { LOG_WARNING("RCLK timeout"); /* the error is informative only as we don't want to break the firmware if there * is a false positive. */ /* return ERROR_FAIL; */ } } return ERROR_OK; } static void writeShiftValue(uint8_t *data, int bits); /* here we shuffle N bits out/in */ static inline void scanBits(const uint8_t *out_value, uint8_t *in_value, int num_bits, bool pause_now, tap_state_t shiftState, tap_state_t end_state) { tap_state_t pause_state = shiftState; for (int j = 0; j < num_bits; j += 32) { int k = num_bits - j; if (k > 32) { k = 32; /* we have more to shift out */ } else if (pause_now) { /* this was the last to shift out this time */ pause_state = end_state; } /* we have (num_bits + 7)/8 bytes of bits to toggle out. */ /* bits are pushed out LSB to MSB */ uint32_t value; value = 0; if (out_value != NULL) { for (int l = 0; l < k; l += 8) value |= out_value[(j + l)/8]<= 32 is not defined by the C standard * and will in fact shift by &0x1f bits on nios */ } shiftValueInner(shiftState, pause_state, k, value); if (in_value != NULL) writeShiftValue(in_value + (j/8), k); } } static inline void scanFields(int num_fields, const struct scan_field *fields, tap_state_t shiftState, tap_state_t end_state) { for (int i = 0; i < num_fields; i++) { scanBits(fields[i].out_value, fields[i].in_value, fields[i].num_bits, (i == num_fields-1), shiftState, end_state); } } int interface_jtag_add_ir_scan(struct jtag_tap *active, const struct scan_field *fields, tap_state_t state) { int scan_size = 0; struct jtag_tap *tap, *nextTap; tap_state_t pause_state = TAP_IRSHIFT; for (tap = jtag_tap_next_enabled(NULL); tap != NULL; tap = nextTap) { nextTap = jtag_tap_next_enabled(tap); if (nextTap == NULL) pause_state = state; scan_size = tap->ir_length; /* search the list */ if (tap == active) { scanFields(1, fields, TAP_IRSHIFT, pause_state); /* update device information */ buf_cpy(fields[0].out_value, tap->cur_instr, scan_size); tap->bypass = 0; } else { /* if a device isn't listed, set it to BYPASS */ assert(scan_size <= 32); shiftValueInner(TAP_IRSHIFT, pause_state, scan_size, 0xffffffff); /* Optimization code will check what the cur_instr is set to, so * we must set it to bypass value. */ buf_set_ones(tap->cur_instr, tap->ir_length); tap->bypass = 1; } } return ERROR_OK; } int interface_jtag_add_plain_ir_scan(int num_bits, const uint8_t *out_bits, uint8_t *in_bits, tap_state_t state) { scanBits(out_bits, in_bits, num_bits, true, TAP_IRSHIFT, state); return ERROR_OK; } int interface_jtag_add_dr_scan(struct jtag_tap *active, int num_fields, const struct scan_field *fields, tap_state_t state) { struct jtag_tap *tap, *nextTap; tap_state_t pause_state = TAP_DRSHIFT; for (tap = jtag_tap_next_enabled(NULL); tap != NULL; tap = nextTap) { nextTap = jtag_tap_next_enabled(tap); if (nextTap == NULL) pause_state = state; /* Find a range of fields to write to this tap */ if (tap == active) { assert(!tap->bypass); scanFields(num_fields, fields, TAP_DRSHIFT, pause_state); } else { /* Shift out a 0 for disabled tap's */ assert(tap->bypass); shiftValueInner(TAP_DRSHIFT, pause_state, 1, 0); } } return ERROR_OK; } int interface_jtag_add_plain_dr_scan(int num_bits, const uint8_t *out_bits, uint8_t *in_bits, tap_state_t state) { scanBits(out_bits, in_bits, num_bits, true, TAP_DRSHIFT, state); return ERROR_OK; } int interface_jtag_add_tlr() { setCurrentState(TAP_RESET); return ERROR_OK; } int interface_jtag_add_reset(int req_trst, int req_srst) { zy1000_reset(req_trst, req_srst); return ERROR_OK; } static int zy1000_jtag_add_clocks(int num_cycles, tap_state_t state, tap_state_t clockstate) { /* num_cycles can be 0 */ setCurrentState(clockstate); /* execute num_cycles, 32 at the time. */ int i; for (i = 0; i < num_cycles; i += 32) { int num; num = 32; if (num_cycles-i < num) num = num_cycles-i; shiftValueInner(clockstate, clockstate, num, 0); } #if !TEST_MANUAL() /* finish in end_state */ setCurrentState(state); #else tap_state_t t = TAP_IDLE; /* test manual drive code on any target */ int tms; uint8_t tms_scan = tap_get_tms_path(t, state); int tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); for (i = 0; i < tms_count; i++) { tms = (tms_scan >> i) & 1; waitIdle(); ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, tms); } waitIdle(); ZY1000_POKE(ZY1000_JTAG_BASE + 0x20, state); #endif return ERROR_OK; } int interface_jtag_add_runtest(int num_cycles, tap_state_t state) { return zy1000_jtag_add_clocks(num_cycles, state, TAP_IDLE); } int interface_jtag_add_clocks(int num_cycles) { return zy1000_jtag_add_clocks(num_cycles, cmd_queue_cur_state, cmd_queue_cur_state); } int interface_add_tms_seq(unsigned num_bits, const uint8_t *seq, enum tap_state state) { /*wait for the fifo to be empty*/ waitIdle(); for (unsigned i = 0; i < num_bits; i++) { int tms; if (((seq[i/8] >> (i % 8)) & 1) == 0) tms = 0; else tms = 1; waitIdle(); ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, tms); } waitIdle(); if (state != TAP_INVALID) ZY1000_POKE(ZY1000_JTAG_BASE + 0x20, state); else { /* this would be normal if * we are switching to SWD mode */ } return ERROR_OK; } int interface_jtag_add_pathmove(int num_states, const tap_state_t *path) { int state_count; int tms = 0; state_count = 0; tap_state_t cur_state = cmd_queue_cur_state; uint8_t seq[16]; memset(seq, 0, sizeof(seq)); assert(num_states < (int)((sizeof(seq) * 8))); while (num_states) { if (tap_state_transition(cur_state, false) == path[state_count]) tms = 0; else if (tap_state_transition(cur_state, true) == path[state_count]) tms = 1; else { LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_name(cur_state), tap_state_name(path[state_count])); exit(-1); } seq[state_count/8] = seq[state_count/8] | (tms << (state_count % 8)); cur_state = path[state_count]; state_count++; num_states--; } return interface_add_tms_seq(state_count, seq, cur_state); } static void jtag_pre_post_bits(struct jtag_tap *tap, int *pre, int *post) { /* bypass bits before and after */ int pre_bits = 0; int post_bits = 0; bool found = false; struct jtag_tap *cur_tap, *nextTap; for (cur_tap = jtag_tap_next_enabled(NULL); cur_tap != NULL; cur_tap = nextTap) { nextTap = jtag_tap_next_enabled(cur_tap); if (cur_tap == tap) found = true; else { if (found) post_bits++; else pre_bits++; } } *pre = pre_bits; *post = post_bits; } #if 0 static const int embeddedice_num_bits[] = {32, 6}; uint32_t values[2]; values[0] = value; values[1] = (1 << 5) | reg_addr; jtag_add_dr_out(tap, 2, embeddedice_num_bits, values, TAP_IDLE); #endif void embeddedice_write_dcc(struct jtag_tap *tap, int reg_addr, const uint8_t *buffer, int little, int count) { #if 0 int i; for (i = 0; i < count; i++) { embeddedice_write_reg_inner(tap, reg_addr, fast_target_buffer_get_u32(buffer, little)); buffer += 4; } #else int pre_bits; int post_bits; jtag_pre_post_bits(tap, &pre_bits, &post_bits); if ((pre_bits > 32) || (post_bits + 6 > 32)) { int i; for (i = 0; i < count; i++) { embeddedice_write_reg_inner(tap, reg_addr, fast_target_buffer_get_u32(buffer, little)); buffer += 4; } } else { int i; for (i = 0; i < count; i++) { /* Fewer pokes means we get to use the FIFO more efficiently */ shiftValueInner(TAP_DRSHIFT, TAP_DRSHIFT, pre_bits, 0); shiftValueInner(TAP_DRSHIFT, TAP_DRSHIFT, 32, fast_target_buffer_get_u32(buffer, little)); /* Danger! here we need to exit into the TAP_IDLE state to make * DCC pick up this value. */ shiftValueInner(TAP_DRSHIFT, TAP_IDLE, 6 + post_bits, (reg_addr | (1 << 5))); buffer += 4; } } #endif } int arm11_run_instr_data_to_core_noack_inner(struct jtag_tap *tap, uint32_t opcode, const uint32_t *data, size_t count) { /* bypass bits before and after */ int pre_bits; int post_bits; jtag_pre_post_bits(tap, &pre_bits, &post_bits); post_bits += 2; if ((pre_bits > 32) || (post_bits > 32)) { int arm11_run_instr_data_to_core_noack_inner_default(struct jtag_tap *, uint32_t, const uint32_t *, size_t); return arm11_run_instr_data_to_core_noack_inner_default(tap, opcode, data, count); } else { static const int bits[] = {32, 2}; uint32_t values[] = {0, 0}; /* FIX!!!!!! the target_write_memory() API started this nasty problem * with unaligned uint32_t * pointers... */ const uint8_t *t = (const uint8_t *)data; while (--count > 0) { #if 1 /* Danger! This code doesn't update cmd_queue_cur_state, so * invoking jtag_add_pathmove() before jtag_add_dr_out() after * this loop would fail! */ shiftValueInner(TAP_DRSHIFT, TAP_DRSHIFT, pre_bits, 0); uint32_t value; value = *t++; value |= (*t++<<8); value |= (*t++<<16); value |= (*t++<<24); shiftValueInner(TAP_DRSHIFT, TAP_DRSHIFT, 32, value); /* minimum 2 bits */ shiftValueInner(TAP_DRSHIFT, TAP_DRPAUSE, post_bits, 0); /* copy & paste from arm11_dbgtap.c */ /* TAP_DREXIT2, TAP_DRUPDATE, TAP_IDLE, TAP_IDLE, TAP_IDLE, TAP_DRSELECT, * TAP_DRCAPTURE, TAP_DRSHIFT */ /* KLUDGE! we have to flush the fifo or the Nios CPU locks up. * This is probably a bug in the Avalon bus(cross clocking bridge?) * or in the jtag registers module. */ waitIdle(); ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, 1); ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, 1); ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, 0); ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, 0); ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, 0); ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, 1); ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, 0); ZY1000_POKE(ZY1000_JTAG_BASE + 0x28, 0); /* we don't have to wait for the queue to empty here */ ZY1000_POKE(ZY1000_JTAG_BASE + 0x20, TAP_DRSHIFT); waitIdle(); #else static const tap_state_t arm11_MOVE_DRPAUSE_IDLE_DRPAUSE_with_delay[] = { TAP_DREXIT2, TAP_DRUPDATE, TAP_IDLE, TAP_IDLE, TAP_IDLE, TAP_DRSELECT, TAP_DRCAPTURE, TAP_DRSHIFT }; values[0] = *t++; values[0] |= (*t++<<8); values[0] |= (*t++<<16); values[0] |= (*t++<<24); jtag_add_dr_out(tap, 2, bits, values, TAP_IDLE); jtag_add_pathmove(ARRAY_SIZE(arm11_MOVE_DRPAUSE_IDLE_DRPAUSE_with_delay), arm11_MOVE_DRPAUSE_IDLE_DRPAUSE_with_delay); #endif } values[0] = *t++; values[0] |= (*t++<<8); values[0] |= (*t++<<16); values[0] |= (*t++<<24); /* This will happen on the last iteration updating cmd_queue_cur_state * so we don't have to track it during the common code path */ jtag_add_dr_out(tap, 2, bits, values, TAP_IDLE); return jtag_execute_queue(); } } static const struct command_registration zy1000_commands[] = { { .name = "power", .handler = handle_power_command, .mode = COMMAND_ANY, .help = "Turn power switch to target on/off. " "With no arguments, prints status.", .usage = "('on'|'off)", }, #if !BUILD_ZY1000_MASTER { .name = "zy1000_server", .mode = COMMAND_ANY, .jim_handler = jim_zy1000_server, .help = "Tcpip address for ZY1000 server.", .usage = "address", }, #endif { .name = "powerstatus", .mode = COMMAND_ANY, .jim_handler = zylinjtag_Jim_Command_powerstatus, .help = "Returns power status of target", }, COMMAND_REGISTRATION_DONE }; #if !BUILD_ZY1000_MASTER static int tcp_ip = -1; /* Write large packets if we can */ static size_t out_pos; static uint8_t out_buffer[16384]; static size_t in_pos; static size_t in_write; static uint8_t in_buffer[16384]; static bool flush_writes(void) { bool ok = (write(tcp_ip, out_buffer, out_pos) == (int)out_pos); out_pos = 0; return ok; } static bool writeLong(uint32_t l) { int i; for (i = 0; i < 4; i++) { uint8_t c = (l >> (i*8))&0xff; out_buffer[out_pos++] = c; if (out_pos >= sizeof(out_buffer)) { if (!flush_writes()) return false; } } return true; } static bool readLong(uint32_t *out_data) { uint32_t data = 0; int i; for (i = 0; i < 4; i++) { uint8_t c; if (in_pos == in_write) { /* If we have some data that we can send, send them before * we wait for more data */ if (out_pos > 0) { if (!flush_writes()) return false; } /* read more */ int t; t = read(tcp_ip, in_buffer, sizeof(in_buffer)); if (t < 1) return false; in_write = (size_t) t; in_pos = 0; } c = in_buffer[in_pos++]; data |= (c << (i*8)); } *out_data = data; return true; } enum ZY1000_CMD { ZY1000_CMD_POKE = 0x0, ZY1000_CMD_PEEK = 0x8, ZY1000_CMD_SLEEP = 0x1, ZY1000_CMD_WAITIDLE = 2 }; #include /* for socket(), connect(), send(), and recv() */ #include /* for sockaddr_in and inet_addr() */ /* We initialize this late since we need to know the server address * first. */ static void tcpip_open(void) { if (tcp_ip >= 0) return; struct sockaddr_in echoServAddr;/* Echo server address */ /* Create a reliable, stream socket using TCP */ tcp_ip = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (tcp_ip < 0) { fprintf(stderr, "Failed to connect to zy1000 server\n"); exit(-1); } /* Construct the server address structure */ memset(&echoServAddr, 0, sizeof(echoServAddr)); /* Zero out structure */ echoServAddr.sin_family = AF_INET; /* Internet address family */ echoServAddr.sin_addr.s_addr = inet_addr(tcp_server); /* Server IP address */ echoServAddr.sin_port = htons(7777); /* Server port */ /* Establish the connection to the echo server */ if (connect(tcp_ip, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0) { fprintf(stderr, "Failed to connect to zy1000 server\n"); exit(-1); } int flag = 1; setsockopt(tcp_ip, /* socket affected */ IPPROTO_TCP, /* set option at TCP level */ TCP_NODELAY, /* name of option */ (char *)&flag, /* the cast is historical cruft */ sizeof(int)); /* length of option value */ } /* send a poke */ void zy1000_tcpout(uint32_t address, uint32_t data) { tcpip_open(); if (!writeLong((ZY1000_CMD_POKE << 24) | address) || !writeLong(data)) { fprintf(stderr, "Could not write to zy1000 server\n"); exit(-1); } } /* By sending the wait to the server, we avoid a readback * of status. Radically improves performance for this operation * with long ping times. */ void waitIdle(void) { tcpip_open(); if (!writeLong((ZY1000_CMD_WAITIDLE << 24))) { fprintf(stderr, "Could not write to zy1000 server\n"); exit(-1); } } uint32_t zy1000_tcpin(uint32_t address) { tcpip_open(); zy1000_flush_readqueue(); uint32_t data; if (!writeLong((ZY1000_CMD_PEEK << 24) | address) || !readLong(&data)) { fprintf(stderr, "Could not read from zy1000 server\n"); exit(-1); } return data; } int interface_jtag_add_sleep(uint32_t us) { tcpip_open(); if (!writeLong((ZY1000_CMD_SLEEP << 24)) || !writeLong(us)) { fprintf(stderr, "Could not read from zy1000 server\n"); exit(-1); } return ERROR_OK; } /* queue a readback */ #define readqueue_size 16384 static struct { uint8_t *dest; int bits; } readqueue[readqueue_size]; static int readqueue_pos; /* flush the readqueue, this means reading any data that * we're expecting and store them into the final position */ void zy1000_flush_readqueue(void) { if (readqueue_pos == 0) { /* simply debugging by allowing easy breakpoints when there * is something to do. */ return; } int i; tcpip_open(); for (i = 0; i < readqueue_pos; i++) { uint32_t value; if (!readLong(&value)) { fprintf(stderr, "Could not read from zy1000 server\n"); exit(-1); } uint8_t *in_value = readqueue[i].dest; int k = readqueue[i].bits; /* we're shifting in data to MSB, shift data to be aligned for returning the value */ value >>= 32-k; for (int l = 0; l < k; l += 8) in_value[l/8] = (value >> l)&0xff; } readqueue_pos = 0; } /* By queuing the callback's we avoid flushing the * read queue until jtag_execute_queue(). This can * reduce latency dramatically for cases where * callbacks are used extensively. */ #define callbackqueue_size 128 static struct callbackentry { jtag_callback_t callback; jtag_callback_data_t data0; jtag_callback_data_t data1; jtag_callback_data_t data2; jtag_callback_data_t data3; } callbackqueue[callbackqueue_size]; static int callbackqueue_pos; void zy1000_jtag_add_callback4(jtag_callback_t callback, jtag_callback_data_t data0, jtag_callback_data_t data1, jtag_callback_data_t data2, jtag_callback_data_t data3) { if (callbackqueue_pos >= callbackqueue_size) zy1000_flush_callbackqueue(); callbackqueue[callbackqueue_pos].callback = callback; callbackqueue[callbackqueue_pos].data0 = data0; callbackqueue[callbackqueue_pos].data1 = data1; callbackqueue[callbackqueue_pos].data2 = data2; callbackqueue[callbackqueue_pos].data3 = data3; callbackqueue_pos++; /* KLUDGE! * make callbacks synchronous for now as minidriver requires callback * to be synchronous. * * We can get away with making read and writes asynchronous so we * don't completely kill performance. */ zy1000_flush_callbackqueue(); } static int zy1000_jtag_convert_to_callback4(jtag_callback_data_t data0, jtag_callback_data_t data1, jtag_callback_data_t data2, jtag_callback_data_t data3) { ((jtag_callback1_t)data1)(data0); return ERROR_OK; } void zy1000_jtag_add_callback(jtag_callback1_t callback, jtag_callback_data_t data0) { zy1000_jtag_add_callback4(zy1000_jtag_convert_to_callback4, data0, (jtag_callback_data_t)callback, 0, 0); } void zy1000_flush_callbackqueue(void) { /* we have to flush the read queue so we have access to the data the callbacks will use */ zy1000_flush_readqueue(); int i; for (i = 0; i < callbackqueue_pos; i++) { struct callbackentry *entry = &callbackqueue[i]; jtag_set_error(entry->callback(entry->data0, entry->data1, entry->data2, entry->data3)); } callbackqueue_pos = 0; } static void writeShiftValue(uint8_t *data, int bits) { waitIdle(); if (!writeLong((ZY1000_CMD_PEEK << 24) | (ZY1000_JTAG_BASE + 0xc))) { fprintf(stderr, "Could not read from zy1000 server\n"); exit(-1); } if (readqueue_pos >= readqueue_size) zy1000_flush_readqueue(); readqueue[readqueue_pos].dest = data; readqueue[readqueue_pos].bits = bits; readqueue_pos++; /* KLUDGE!!! minidriver requires readqueue to be synchronous */ zy1000_flush_readqueue(); } #else static void writeShiftValue(uint8_t *data, int bits) { uint32_t value; waitIdle(); ZY1000_PEEK(ZY1000_JTAG_BASE + 0xc, value); VERBOSE(LOG_INFO("getShiftValue %08x", value)); /* data in, LSB to MSB */ /* we're shifting in data to MSB, shift data to be aligned for returning the value */ value >>= 32 - bits; for (int l = 0; l < bits; l += 8) data[l/8] = (value >> l)&0xff; } #endif #if BUILD_ZY1000_MASTER #ifdef WATCHDOG_BASE /* If we connect to port 8888 we must send a char every 10s or the board resets itself */ static void watchdog_server(cyg_addrword_t data) { int so_reuseaddr_option = 1; int fd = socket(AF_INET, SOCK_STREAM, 0); if (fd == -1) { LOG_ERROR("error creating socket: %s", strerror(errno)); exit(-1); } setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &so_reuseaddr_option, sizeof(int)); struct sockaddr_in sin; unsigned int address_size; address_size = sizeof(sin); memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = INADDR_ANY; sin.sin_port = htons(8888); if (bind(fd, (struct sockaddr *) &sin, sizeof(sin)) == -1) { LOG_ERROR("couldn't bind to socket: %s", strerror(errno)); exit(-1); } if (listen(fd, 1) == -1) { LOG_ERROR("couldn't listen on socket: %s", strerror(errno)); exit(-1); } for (;; ) { int watchdog_ip = accept(fd, (struct sockaddr *) &sin, &address_size); /* Start watchdog, must be reset every 10 seconds. */ HAL_WRITE_UINT32(WATCHDOG_BASE + 4, 4); if (watchdog_ip < 0) { LOG_ERROR("couldn't open watchdog socket: %s", strerror(errno)); exit(-1); } int flag = 1; setsockopt(watchdog_ip, /* socket affected */ IPPROTO_TCP, /* set option at TCP level */ TCP_NODELAY, /* name of option */ (char *)&flag, /* the cast is historical cruft */ sizeof(int)); /* length of option value */ char buf; for (;; ) { if (read(watchdog_ip, &buf, 1) == 1) { /* Reset timer */ HAL_WRITE_UINT32(WATCHDOG_BASE + 8, 0x1234); /* Echo so we can telnet in and see that resetting works */ write(watchdog_ip, &buf, 1); } else { /* Stop tickling the watchdog, the CPU will reset in < 10 seconds * now. */ return; } } /* Never reached */ } } #endif #endif #if BUILD_ZY1000_MASTER int interface_jtag_add_sleep(uint32_t us) { jtag_sleep(us); return ERROR_OK; } #endif #if BUILD_ZY1000_MASTER volatile void *zy1000_jtag_master; #include #endif int zy1000_init(void) { #if BUILD_ZY1000_MASTER int fd = open("/dev/mem", O_RDWR | O_SYNC); if (fd == -1) { LOG_ERROR("No access to /dev/mem"); return ERROR_FAIL; } #ifndef REGISTERS_BASE #define REGISTERS_BASE 0x9002000 #define REGISTERS_SPAN 128 #endif zy1000_jtag_master = mmap(0, REGISTERS_SPAN, PROT_READ | PROT_WRITE, MAP_SHARED, fd, REGISTERS_BASE); if (zy1000_jtag_master == (void *) -1) { close(fd); LOG_ERROR("No access to /dev/mem"); return ERROR_FAIL; } #endif ZY1000_POKE(ZY1000_JTAG_BASE + 0x10, 0x30); /* Turn on LED1 & LED2 */ setPower(true); /* on by default */ /* deassert resets. Important to avoid infinite loop waiting for SRST to deassert */ zy1000_reset(0, 0); return ERROR_OK; } struct jtag_interface zy1000_interface = { .name = "ZY1000", .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = NULL, .speed = zy1000_speed, .commands = zy1000_commands, .init = zy1000_init, .quit = zy1000_quit, .khz = zy1000_khz, .speed_div = zy1000_speed_div, .power_dropout = zy1000_power_dropout, .srst_asserted = zy1000_srst_asserted, }; openocd-0.7.0/src/jtag/commands.c0000644000175000001440000001605612134336410013550 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2009 SoftPLC Corporation * * http://softplc.com * * dick@softplc.com * * * * Copyright (C) 2009 Zachary T Welch * * zw@superlucidity.net * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "commands.h" struct cmd_queue_page { void *address; size_t used; struct cmd_queue_page *next; }; #define CMD_QUEUE_PAGE_SIZE (1024 * 1024) static struct cmd_queue_page *cmd_queue_pages; struct jtag_command *jtag_command_queue; static struct jtag_command **next_command_pointer = &jtag_command_queue; void jtag_queue_command(struct jtag_command *cmd) { /* this command goes on the end, so ensure the queue terminates */ cmd->next = NULL; struct jtag_command **last_cmd = next_command_pointer; assert(NULL != last_cmd); assert(NULL == *last_cmd); *last_cmd = cmd; /* store location where the next command pointer will be stored */ next_command_pointer = &cmd->next; } void *cmd_queue_alloc(size_t size) { struct cmd_queue_page **p_page = &cmd_queue_pages; int offset; uint8_t *t; /* * WARNING: * We align/round the *SIZE* per below * so that all pointers returned by * this function are reasonably well * aligned. * * If we did not, then an "odd-length" request would cause the * *next* allocation to be at an *odd* address, and because * this function has the same type of api as malloc() - we * must also return pointers that have the same type of * alignment. * * What I do not/have is a reasonable portable means * to align by... * * The solution here, is based on these suggestions. * http://gcc.gnu.org/ml/gcc-help/2008-12/msg00041.html * */ union worse_case_align { int i; long l; float f; void *v; }; #define ALIGN_SIZE (sizeof(union worse_case_align)) /* The alignment process. */ size = (size + ALIGN_SIZE - 1) & (~(ALIGN_SIZE - 1)); /* Done... */ if (*p_page) { while ((*p_page)->next) p_page = &((*p_page)->next); if (CMD_QUEUE_PAGE_SIZE - (*p_page)->used < size) p_page = &((*p_page)->next); } if (!*p_page) { *p_page = malloc(sizeof(struct cmd_queue_page)); (*p_page)->used = 0; (*p_page)->address = malloc(CMD_QUEUE_PAGE_SIZE); (*p_page)->next = NULL; } offset = (*p_page)->used; (*p_page)->used += size; t = (uint8_t *)((*p_page)->address); return t + offset; } static void cmd_queue_free(void) { struct cmd_queue_page *page = cmd_queue_pages; while (page) { struct cmd_queue_page *last = page; free(page->address); page = page->next; free(last); } cmd_queue_pages = NULL; } void jtag_command_queue_reset(void) { cmd_queue_free(); jtag_command_queue = NULL; next_command_pointer = &jtag_command_queue; } enum scan_type jtag_scan_type(const struct scan_command *cmd) { int i; int type = 0; for (i = 0; i < cmd->num_fields; i++) { if (cmd->fields[i].in_value) type |= SCAN_IN; if (cmd->fields[i].out_value) type |= SCAN_OUT; } return type; } int jtag_scan_size(const struct scan_command *cmd) { int bit_count = 0; int i; /* count bits in scan command */ for (i = 0; i < cmd->num_fields; i++) bit_count += cmd->fields[i].num_bits; return bit_count; } int jtag_build_buffer(const struct scan_command *cmd, uint8_t **buffer) { int bit_count = 0; int i; bit_count = jtag_scan_size(cmd); *buffer = calloc(1, DIV_ROUND_UP(bit_count, 8)); bit_count = 0; DEBUG_JTAG_IO("%s num_fields: %i", cmd->ir_scan ? "IRSCAN" : "DRSCAN", cmd->num_fields); for (i = 0; i < cmd->num_fields; i++) { if (cmd->fields[i].out_value) { #ifdef _DEBUG_JTAG_IO_ char *char_buf = buf_to_str(cmd->fields[i].out_value, (cmd->fields[i].num_bits > DEBUG_JTAG_IOZ) ? DEBUG_JTAG_IOZ : cmd->fields[i].num_bits, 16); LOG_DEBUG("fields[%i].out_value[%i]: 0x%s", i, cmd->fields[i].num_bits, char_buf); free(char_buf); #endif buf_set_buf(cmd->fields[i].out_value, 0, *buffer, bit_count, cmd->fields[i].num_bits); } else { DEBUG_JTAG_IO("fields[%i].out_value[%i]: NULL", i, cmd->fields[i].num_bits); } bit_count += cmd->fields[i].num_bits; } /*DEBUG_JTAG_IO("bit_count totalling: %i", bit_count); */ return bit_count; } int jtag_read_buffer(uint8_t *buffer, const struct scan_command *cmd) { int i; int bit_count = 0; int retval; /* we return ERROR_OK, unless a check fails, or a handler reports a problem */ retval = ERROR_OK; for (i = 0; i < cmd->num_fields; i++) { /* if neither in_value nor in_handler * are specified we don't have to examine this field */ if (cmd->fields[i].in_value) { int num_bits = cmd->fields[i].num_bits; uint8_t *captured = buf_set_buf(buffer, bit_count, malloc(DIV_ROUND_UP(num_bits, 8)), 0, num_bits); #ifdef _DEBUG_JTAG_IO_ char *char_buf = buf_to_str(captured, (num_bits > DEBUG_JTAG_IOZ) ? DEBUG_JTAG_IOZ : num_bits, 16); LOG_DEBUG("fields[%i].in_value[%i]: 0x%s", i, num_bits, char_buf); free(char_buf); #endif if (cmd->fields[i].in_value) buf_cpy(captured, cmd->fields[i].in_value, num_bits); free(captured); } bit_count += cmd->fields[i].num_bits; } return retval; } openocd-0.7.0/src/jtag/interface.h0000644000175000001440000002666612134336410013724 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2009 Zachary T Welch * * zw@superlucidity.net * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef OPENOCD_JTAG_INTERFACE_H #define OPENOCD_JTAG_INTERFACE_H #include /* @file * The "Cable Helper API" is what the cable drivers can use to help * implement their "Cable API". So a Cable Helper API is a set of * helper functions used by cable drivers, and this is different from a * Cable API. A "Cable API" is what higher level code used to talk to a * cable. */ /** implementation of wrapper function tap_set_state() */ void tap_set_state_impl(tap_state_t new_state); /** * This function sets the state of a "state follower" which tracks the * state of the TAPs connected to the cable. The state follower is * hopefully always in the same state as the actual TAPs in the jtag * chain, and will be so if there are no bugs in the tracking logic * within that cable driver. * * All the cable drivers call this function to indicate the state they * think the TAPs attached to their cables are in. Because this * function can also log transitions, it will be helpful to call this * function with every transition that the TAPs being manipulated are * expected to traverse, not just end points of a multi-step state path. * * @param new_state The state we think the TAPs are currently in (or * are about to enter). */ #if defined(_DEBUG_JTAG_IO_) #define tap_set_state(new_state) \ do { \ LOG_DEBUG("tap_set_state(%s)", tap_state_name(new_state)); \ tap_set_state_impl(new_state); \ } while (0) #else static inline void tap_set_state(tap_state_t new_state) { tap_set_state_impl(new_state); } #endif /** * This function gets the state of the "state follower" which tracks the * state of the TAPs connected to the cable. @see tap_set_state @return * tap_state_t The state the TAPs are in now. */ tap_state_t tap_get_state(void); /** * This function sets the state of an "end state follower" which tracks * the state that any cable driver thinks will be the end (resultant) * state of the current TAP SIR or SDR operation. * * At completion of that TAP operation this value is copied into the * state follower via tap_set_state(). * * @param new_end_state The state the TAPs should enter at completion of * a pending TAP operation. */ void tap_set_end_state(tap_state_t new_end_state); /** * For more information, @see tap_set_end_state * @return tap_state_t - The state the TAPs should be in at completion of the current TAP operation. */ tap_state_t tap_get_end_state(void); /** * This function provides a "bit sequence" indicating what has to be * done with TMS during a sequence of seven TAP clock cycles in order to * get from state \a "from" to state \a "to". * * The length of the sequence must be determined with a parallel call to * tap_get_tms_path_len(). * * @param from The starting state. * @param to The desired final state. * @return int The required TMS bit sequence, with the first bit in the * sequence at bit 0. */ int tap_get_tms_path(tap_state_t from, tap_state_t to); /** * Function int tap_get_tms_path_len * returns the total number of bits that represents a TMS path * transition as given by the function tap_get_tms_path(). * * For at least one interface (JLink) it's not OK to simply "pad" TMS * sequences to fit a whole byte. (I suspect this is a general TAP * problem within OOCD.) Padding TMS causes all manner of instability * that's not easily discovered. Using this routine we can apply * EXACTLY the state transitions required to make something work - no * more - no less. * * @param from is the starting state * @param to is the resultant or final state * @return int - the total number of bits in a transition. */ int tap_get_tms_path_len(tap_state_t from, tap_state_t to); /** * Function tap_move_ndx * when given a stable state, returns an index from 0-5. The index corresponds to a * sequence of stable states which are given in this order:

* { TAP_RESET, TAP_IDLE, TAP_DRSHIFT, TAP_DRPAUSE, TAP_IRSHIFT, TAP_IRPAUSE } *

* This sequence corresponds to look up tables which are used in some of the * cable drivers. * @param astate is the stable state to find in the sequence. If a non stable * state is passed, this may cause the program to output an error message * and terminate. * @return int - the array (or sequence) index as described above */ int tap_move_ndx(tap_state_t astate); /** * Function tap_is_state_stable * returns true if the \a astate is stable. */ bool tap_is_state_stable(tap_state_t astate); /** * Function tap_state_transition * takes a current TAP state and returns the next state according to the tms value. * @param current_state is the state of a TAP currently. * @param tms is either zero or non-zero, just like a real TMS line in a jtag interface. * @return tap_state_t - the next state a TAP would enter. */ tap_state_t tap_state_transition(tap_state_t current_state, bool tms); /** Allow switching between old and new TMS tables. @see tap_get_tms_path */ void tap_use_new_tms_table(bool use_new); /** @returns True if new TMS table is active; false otherwise. */ bool tap_uses_new_tms_table(void); #ifdef _DEBUG_JTAG_IO_ /** * @brief Prints verbose TAP state transitions for the given TMS/TDI buffers. * @param tms_buf must points to a buffer containing the TMS bitstream. * @param tdi_buf must points to a buffer containing the TDI bitstream. * @param tap_len must specify the length of the TMS/TDI bitstreams. * @param start_tap_state must specify the current TAP state. * @returns the final TAP state; pass as @a start_tap_state in following call. */ tap_state_t jtag_debug_state_machine(const void *tms_buf, const void *tdi_buf, unsigned tap_len, tap_state_t start_tap_state); #else static inline tap_state_t jtag_debug_state_machine(const void *tms_buf, const void *tdi_buf, unsigned tap_len, tap_state_t start_tap_state) { return start_tap_state; } #endif /* _DEBUG_JTAG_IO_ */ /** * Represents a driver for a debugging interface. * * @todo Rename; perhaps "debug_driver". This isn't an interface, * it's a driver! Also, not all drivers support JTAG. * * @todo We need a per-instance structure too, and changes to pass * that structure to the driver. Instances can for example be in * either SWD or JTAG modes. This will help remove globals, and * eventually to cope with systems which have more than one such * debugging interface. */ struct jtag_interface { /** The name of the JTAG interface driver. */ char *name; /** * Bit vector listing capabilities exposed by this driver. */ unsigned supported; #define DEBUG_CAP_TMS_SEQ (1 << 0) /** transports supported in C code (NULL terminated vector) */ const char **transports; const struct swd_driver *swd; /** * Execute queued commands. * @returns ERROR_OK on success, or an error code on failure. */ int (*execute_queue)(void); /** * Set the interface speed. * @param speed The new interface speed setting. * @returns ERROR_OK on success, or an error code on failure. */ int (*speed)(int speed); /** * The interface driver may register additional commands to expose * additional features not covered by the standard command set. */ const struct command_registration *commands; /** * Interface driver must initialize any resources and connect to a * JTAG device. * * quit() is invoked if and only if init() succeeds. quit() is always * invoked if init() succeeds. Same as malloc() + free(). Always * invoke free() if malloc() succeeds and do not invoke free() * otherwise. * * @returns ERROR_OK on success, or an error code on failure. */ int (*init)(void); /** * Interface driver must tear down all resources and disconnect from * the JTAG device. * * @returns ERROR_OK on success, or an error code on failure. */ int (*quit)(void); /** * Returns JTAG maxium speed for KHz. 0 = RTCK. The function returns * a failure if it can't support the KHz/RTCK. * * WARNING!!!! if RTCK is *slow* then think carefully about * whether you actually want to support this in the driver. * Many target scripts are written to handle the absence of RTCK * and use a fallback kHz TCK. * @returns ERROR_OK on success, or an error code on failure. */ int (*khz)(int khz, int *jtag_speed); /** * Calculate the clock frequency (in KHz) for the given @a speed. * @param speed The desired interface speed setting. * @param khz On return, contains the speed in KHz (0 for RTCK). * @returns ERROR_OK on success, or an error code if the * interface cannot support the specified speed (KHz or RTCK). */ int (*speed_div)(int speed, int *khz); /** * Read and clear the power dropout flag. Note that a power dropout * can be transitionary, easily much less than a ms. * * To find out if the power is *currently* on, one must invoke this * method twice. Once to clear the power dropout flag and a second * time to read the current state. The default implementation * never reports power dropouts. * * @returns ERROR_OK on success, or an error code on failure. */ int (*power_dropout)(int *power_dropout); /** * Read and clear the srst asserted detection flag. * * Like power_dropout this does *not* read the current * state. SRST assertion is transitionary and may be much * less than 1ms, so the interface driver must watch for these * events until this routine is called. * * @param srst_asserted On return, indicates whether SRST has * been asserted. * @returns ERROR_OK on success, or an error code on failure. */ int (*srst_asserted)(int *srst_asserted); }; extern const char *jtag_only[]; extern const struct swd_driver *swd; void adapter_assert_reset(void); void adapter_deassert_reset(void); #endif /* OPENOCD_JTAG_INTERFACE_H */ openocd-0.7.0/src/jtag/adapter.c0000644000175000001440000003625212134336410013367 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2009 SoftPLC Corporation * * http://softplc.com * * dick@softplc.com * * * * Copyright (C) 2009 Zachary T Welch * * zw@superlucidity.net * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "jtag.h" #include "minidriver.h" #include "interface.h" #include "interfaces.h" #include #ifdef HAVE_STRINGS_H #include #endif /** * @file * Holds support for configuring debug adapters from TCl scripts. */ extern struct jtag_interface *jtag_interface; const char *jtag_only[] = { "jtag", NULL }; static int jim_adapter_name(Jim_Interp *interp, int argc, Jim_Obj * const *argv) { Jim_GetOptInfo goi; Jim_GetOpt_Setup(&goi, interp, argc-1, argv + 1); /* return the name of the interface */ /* TCL code might need to know the exact type... */ /* FUTURE: we allow this as a means to "set" the interface. */ if (goi.argc != 0) { Jim_WrongNumArgs(goi.interp, 1, goi.argv-1, "(no params)"); return JIM_ERR; } const char *name = jtag_interface ? jtag_interface->name : NULL; Jim_SetResultString(goi.interp, name ? : "undefined", -1); return JIM_OK; } static int default_khz(int khz, int *jtag_speed) { LOG_ERROR("Translation from khz to jtag_speed not implemented"); return ERROR_FAIL; } static int default_speed_div(int speed, int *khz) { LOG_ERROR("Translation from jtag_speed to khz not implemented"); return ERROR_FAIL; } static int default_power_dropout(int *dropout) { *dropout = 0; /* by default we can't detect power dropout */ return ERROR_OK; } static int default_srst_asserted(int *srst_asserted) { *srst_asserted = 0; /* by default we can't detect srst asserted */ return ERROR_OK; } COMMAND_HANDLER(interface_transport_command) { char **transports; int retval; retval = CALL_COMMAND_HANDLER(transport_list_parse, &transports); if (retval != ERROR_OK) return retval; retval = allow_transports(CMD_CTX, (const char **)transports); if (retval != ERROR_OK) { for (unsigned i = 0; transports[i]; i++) free(transports[i]); free(transports); } return retval; } COMMAND_HANDLER(handle_interface_list_command) { if (strcmp(CMD_NAME, "interface_list") == 0 && CMD_ARGC > 0) return ERROR_COMMAND_SYNTAX_ERROR; command_print(CMD_CTX, "The following debug interfaces are available:"); for (unsigned i = 0; NULL != jtag_interfaces[i]; i++) { const char *name = jtag_interfaces[i]->name; command_print(CMD_CTX, "%u: %s", i + 1, name); } return ERROR_OK; } COMMAND_HANDLER(handle_interface_command) { int retval; /* check whether the interface is already configured */ if (jtag_interface) { LOG_WARNING("Interface already configured, ignoring"); return ERROR_OK; } /* interface name is a mandatory argument */ if (CMD_ARGC != 1 || CMD_ARGV[0][0] == '\0') return ERROR_COMMAND_SYNTAX_ERROR; for (unsigned i = 0; NULL != jtag_interfaces[i]; i++) { if (strcmp(CMD_ARGV[0], jtag_interfaces[i]->name) != 0) continue; if (NULL != jtag_interfaces[i]->commands) { retval = register_commands(CMD_CTX, NULL, jtag_interfaces[i]->commands); if (ERROR_OK != retval) return retval; } jtag_interface = jtag_interfaces[i]; /* LEGACY SUPPORT ... adapter drivers must declare what * transports they allow. Until they all do so, assume * the legacy drivers are JTAG-only */ if (!jtag_interface->transports) LOG_WARNING("Adapter driver '%s' did not declare " "which transports it allows; assuming " "legacy JTAG-only", jtag_interface->name); retval = allow_transports(CMD_CTX, jtag_interface->transports ? jtag_interface->transports : jtag_only); if (ERROR_OK != retval) return retval; if (jtag_interface->khz == NULL) jtag_interface->khz = default_khz; if (jtag_interface->speed_div == NULL) jtag_interface->speed_div = default_speed_div; if (jtag_interface->power_dropout == NULL) jtag_interface->power_dropout = default_power_dropout; if (jtag_interface->srst_asserted == NULL) jtag_interface->srst_asserted = default_srst_asserted; return ERROR_OK; } /* no valid interface was found (i.e. the configuration option, * didn't match one of the compiled-in interfaces */ LOG_ERROR("The specified debug interface was not found (%s)", CMD_ARGV[0]); CALL_COMMAND_HANDLER(handle_interface_list_command); return ERROR_JTAG_INVALID_INTERFACE; } COMMAND_HANDLER(handle_reset_config_command) { int new_cfg = 0; int mask = 0; /* Original versions cared about the order of these tokens: * reset_config signals [combination [trst_type [srst_type]]] * They also clobbered the previous configuration even on error. * * Here we don't care about the order, and only change values * which have been explicitly specified. */ for (; CMD_ARGC; CMD_ARGC--, CMD_ARGV++) { int tmp = 0; int m; /* gating */ m = RESET_SRST_NO_GATING; if (strcmp(*CMD_ARGV, "srst_gates_jtag") == 0) /* default: don't use JTAG while SRST asserted */; else if (strcmp(*CMD_ARGV, "srst_nogate") == 0) tmp = RESET_SRST_NO_GATING; else m = 0; if (mask & m) { LOG_ERROR("extra reset_config %s spec (%s)", "gating", *CMD_ARGV); return ERROR_COMMAND_SYNTAX_ERROR; } if (m) goto next; /* signals */ m = RESET_HAS_TRST | RESET_HAS_SRST; if (strcmp(*CMD_ARGV, "none") == 0) tmp = RESET_NONE; else if (strcmp(*CMD_ARGV, "trst_only") == 0) tmp = RESET_HAS_TRST; else if (strcmp(*CMD_ARGV, "srst_only") == 0) tmp = RESET_HAS_SRST; else if (strcmp(*CMD_ARGV, "trst_and_srst") == 0) tmp = RESET_HAS_TRST | RESET_HAS_SRST; else m = 0; if (mask & m) { LOG_ERROR("extra reset_config %s spec (%s)", "signal", *CMD_ARGV); return ERROR_COMMAND_SYNTAX_ERROR; } if (m) goto next; /* combination (options for broken wiring) */ m = RESET_SRST_PULLS_TRST | RESET_TRST_PULLS_SRST; if (strcmp(*CMD_ARGV, "separate") == 0) /* separate reset lines - default */; else if (strcmp(*CMD_ARGV, "srst_pulls_trst") == 0) tmp |= RESET_SRST_PULLS_TRST; else if (strcmp(*CMD_ARGV, "trst_pulls_srst") == 0) tmp |= RESET_TRST_PULLS_SRST; else if (strcmp(*CMD_ARGV, "combined") == 0) tmp |= RESET_SRST_PULLS_TRST | RESET_TRST_PULLS_SRST; else m = 0; if (mask & m) { LOG_ERROR("extra reset_config %s spec (%s)", "combination", *CMD_ARGV); return ERROR_COMMAND_SYNTAX_ERROR; } if (m) goto next; /* trst_type (NOP without HAS_TRST) */ m = RESET_TRST_OPEN_DRAIN; if (strcmp(*CMD_ARGV, "trst_open_drain") == 0) tmp |= RESET_TRST_OPEN_DRAIN; else if (strcmp(*CMD_ARGV, "trst_push_pull") == 0) /* push/pull from adapter - default */; else m = 0; if (mask & m) { LOG_ERROR("extra reset_config %s spec (%s)", "trst_type", *CMD_ARGV); return ERROR_COMMAND_SYNTAX_ERROR; } if (m) goto next; /* srst_type (NOP without HAS_SRST) */ m = RESET_SRST_PUSH_PULL; if (strcmp(*CMD_ARGV, "srst_push_pull") == 0) tmp |= RESET_SRST_PUSH_PULL; else if (strcmp(*CMD_ARGV, "srst_open_drain") == 0) /* open drain from adapter - default */; else m = 0; if (mask & m) { LOG_ERROR("extra reset_config %s spec (%s)", "srst_type", *CMD_ARGV); return ERROR_COMMAND_SYNTAX_ERROR; } if (m) goto next; /* connect_type - only valid when srst_nogate */ m = RESET_CNCT_UNDER_SRST; if (strcmp(*CMD_ARGV, "connect_assert_srst") == 0) tmp |= RESET_CNCT_UNDER_SRST; else if (strcmp(*CMD_ARGV, "connect_deassert_srst") == 0) /* connect normally - default */; else m = 0; if (mask & m) { LOG_ERROR("extra reset_config %s spec (%s)", "connect_type", *CMD_ARGV); return ERROR_COMMAND_SYNTAX_ERROR; } if (m) goto next; /* caller provided nonsense; fail */ LOG_ERROR("unknown reset_config flag (%s)", *CMD_ARGV); return ERROR_COMMAND_SYNTAX_ERROR; next: /* Remember the bits which were specified (mask) * and their new values (new_cfg). */ mask |= m; new_cfg |= tmp; } /* clear previous values of those bits, save new values */ if (mask) { int old_cfg = jtag_get_reset_config(); old_cfg &= ~mask; new_cfg |= old_cfg; jtag_set_reset_config(new_cfg); } else new_cfg = jtag_get_reset_config(); /* * Display the (now-)current reset mode */ char *modes[6]; /* minimal JTAG has neither SRST nor TRST (so that's the default) */ switch (new_cfg & (RESET_HAS_TRST | RESET_HAS_SRST)) { case RESET_HAS_SRST: modes[0] = "srst_only"; break; case RESET_HAS_TRST: modes[0] = "trst_only"; break; case RESET_TRST_AND_SRST: modes[0] = "trst_and_srst"; break; default: modes[0] = "none"; break; } /* normally SRST and TRST are decoupled; but bugs happen ... */ switch (new_cfg & (RESET_SRST_PULLS_TRST | RESET_TRST_PULLS_SRST)) { case RESET_SRST_PULLS_TRST: modes[1] = "srst_pulls_trst"; break; case RESET_TRST_PULLS_SRST: modes[1] = "trst_pulls_srst"; break; case RESET_SRST_PULLS_TRST | RESET_TRST_PULLS_SRST: modes[1] = "combined"; break; default: modes[1] = "separate"; break; } /* TRST-less connectors include Altera, Xilinx, and minimal JTAG */ if (new_cfg & RESET_HAS_TRST) { if (new_cfg & RESET_TRST_OPEN_DRAIN) modes[3] = " trst_open_drain"; else modes[3] = " trst_push_pull"; } else modes[3] = ""; /* SRST-less connectors include TI-14, Xilinx, and minimal JTAG */ if (new_cfg & RESET_HAS_SRST) { if (new_cfg & RESET_SRST_NO_GATING) modes[2] = " srst_nogate"; else modes[2] = " srst_gates_jtag"; if (new_cfg & RESET_SRST_PUSH_PULL) modes[4] = " srst_push_pull"; else modes[4] = " srst_open_drain"; if (new_cfg & RESET_CNCT_UNDER_SRST) modes[5] = " connect_assert_srst"; else modes[5] = " connect_deassert_srst"; } else { modes[2] = ""; modes[4] = ""; modes[5] = ""; } command_print(CMD_CTX, "%s %s%s%s%s%s", modes[0], modes[1], modes[2], modes[3], modes[4], modes[5]); return ERROR_OK; } COMMAND_HANDLER(handle_adapter_nsrst_delay_command) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC == 1) { unsigned delay; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], delay); jtag_set_nsrst_delay(delay); } command_print(CMD_CTX, "adapter_nsrst_delay: %u", jtag_get_nsrst_delay()); return ERROR_OK; } COMMAND_HANDLER(handle_adapter_nsrst_assert_width_command) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC == 1) { unsigned width; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], width); jtag_set_nsrst_assert_width(width); } command_print(CMD_CTX, "adapter_nsrst_assert_width: %u", jtag_get_nsrst_assert_width()); return ERROR_OK; } COMMAND_HANDLER(handle_adapter_khz_command) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; int retval = ERROR_OK; if (CMD_ARGC == 1) { unsigned khz = 0; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], khz); retval = jtag_config_khz(khz); if (ERROR_OK != retval) return retval; } int cur_speed = jtag_get_speed_khz(); retval = jtag_get_speed_readable(&cur_speed); if (ERROR_OK != retval) return retval; if (cur_speed) command_print(CMD_CTX, "adapter speed: %d kHz", cur_speed); else command_print(CMD_CTX, "adapter speed: RCLK - adaptive"); return retval; } static const struct command_registration interface_command_handlers[] = { { .name = "adapter_khz", .handler = handle_adapter_khz_command, .mode = COMMAND_ANY, .help = "With an argument, change to the specified maximum " "jtag speed. For JTAG, 0 KHz signifies adaptive " " clocking. " "With or without argument, display current setting.", .usage = "[khz]", }, { .name = "adapter_name", .mode = COMMAND_ANY, .jim_handler = jim_adapter_name, .help = "Returns the name of the currently " "selected adapter (driver)", }, { .name = "adapter_nsrst_delay", .handler = handle_adapter_nsrst_delay_command, .mode = COMMAND_ANY, .help = "delay after deasserting SRST in ms", .usage = "[milliseconds]", }, { .name = "adapter_nsrst_assert_width", .handler = handle_adapter_nsrst_assert_width_command, .mode = COMMAND_ANY, .help = "delay after asserting SRST in ms", .usage = "[milliseconds]", }, { .name = "interface", .handler = handle_interface_command, .mode = COMMAND_CONFIG, .help = "Select a debug adapter interface (driver)", .usage = "driver_name", }, { .name = "interface_transports", .handler = interface_transport_command, .mode = COMMAND_CONFIG, .help = "Declare transports the interface supports.", .usage = "transport ... ", }, { .name = "interface_list", .handler = handle_interface_list_command, .mode = COMMAND_ANY, .help = "List all built-in debug adapter interfaces (drivers)", }, { .name = "reset_config", .handler = handle_reset_config_command, .mode = COMMAND_ANY, .help = "configure adapter reset behavior", .usage = "[none|trst_only|srst_only|trst_and_srst] " "[srst_pulls_trst|trst_pulls_srst|combined|separate] " "[srst_gates_jtag|srst_nogate] " "[trst_push_pull|trst_open_drain] " "[srst_push_pull|srst_open_drain]", }, COMMAND_REGISTRATION_DONE }; /** * Register the commands which deal with arbitrary debug adapter drivers. * * @todo Remove internal assumptions that all debug adapters use JTAG for * transport. Various types and data structures are not named generically. */ int interface_register_commands(struct command_context *ctx) { return register_commands(ctx, NULL, interface_command_handlers); } openocd-0.7.0/src/jtag/jtag.h0000644000175000001440000005733112134336410012702 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef JTAG_H #define JTAG_H #include #include #ifdef _DEBUG_JTAG_IO_ #define DEBUG_JTAG_IO(expr ...) \ do { if (1) LOG_DEBUG(expr); } while (0) #else #define DEBUG_JTAG_IO(expr ...) \ do { if (0) LOG_DEBUG(expr); } while (0) #endif #ifndef DEBUG_JTAG_IOZ #define DEBUG_JTAG_IOZ 64 #endif /*------------------------------------------------------*/ /** * Defines JTAG Test Access Port states. * * These definitions were gleaned from the ARM7TDMI-S Technical * Reference Manual and validated against several other ARM core * technical manuals. * * FIXME some interfaces require specific numbers be used, as they * are handed-off directly to their hardware implementations. * Fix those drivers to map as appropriate ... then pick some * sane set of numbers here (where 0/uninitialized == INVALID). */ typedef enum tap_state { TAP_INVALID = -1, #if BUILD_ZY1000 /* These are the old numbers. Leave as-is for now... */ TAP_RESET = 0, TAP_IDLE = 8, TAP_DRSELECT = 1, TAP_DRCAPTURE = 2, TAP_DRSHIFT = 3, TAP_DREXIT1 = 4, TAP_DRPAUSE = 5, TAP_DREXIT2 = 6, TAP_DRUPDATE = 7, TAP_IRSELECT = 9, TAP_IRCAPTURE = 10, TAP_IRSHIFT = 11, TAP_IREXIT1 = 12, TAP_IRPAUSE = 13, TAP_IREXIT2 = 14, TAP_IRUPDATE = 15, #else /* Proper ARM recommended numbers */ TAP_DREXIT2 = 0x0, TAP_DREXIT1 = 0x1, TAP_DRSHIFT = 0x2, TAP_DRPAUSE = 0x3, TAP_IRSELECT = 0x4, TAP_DRUPDATE = 0x5, TAP_DRCAPTURE = 0x6, TAP_DRSELECT = 0x7, TAP_IREXIT2 = 0x8, TAP_IREXIT1 = 0x9, TAP_IRSHIFT = 0xa, TAP_IRPAUSE = 0xb, TAP_IDLE = 0xc, TAP_IRUPDATE = 0xd, TAP_IRCAPTURE = 0xe, TAP_RESET = 0x0f, #endif } tap_state_t; /** * Function tap_state_name * Returns a string suitable for display representing the JTAG tap_state */ const char *tap_state_name(tap_state_t state); /** Provides user-friendly name lookup of TAP states. */ tap_state_t tap_state_by_name(const char *name); /** The current TAP state of the pending JTAG command queue. */ extern tap_state_t cmd_queue_cur_state; /** * This structure defines a single scan field in the scan. It provides * fields for the field's width and pointers to scan input and output * values. * * In addition, this structure includes a value and mask that is used by * jtag_add_dr_scan_check() to validate the value that was scanned out. */ struct scan_field { /** The number of bits this field specifies (up to 32) */ int num_bits; /** A pointer to value to be scanned into the device */ const uint8_t *out_value; /** A pointer to a 32-bit memory location for data scanned out */ uint8_t *in_value; /** The value used to check the data scanned out. */ uint8_t *check_value; /** The mask to go with check_value */ uint8_t *check_mask; }; struct jtag_tap { const char *chip; const char *tapname; const char *dotted_name; int abs_chain_position; /** Is this TAP disabled after JTAG reset? */ bool disabled_after_reset; /** Is this TAP currently enabled? */ bool enabled; int ir_length; /**< size of instruction register */ uint32_t ir_capture_value; uint8_t *expected; /**< Capture-IR expected value */ uint32_t ir_capture_mask; uint8_t *expected_mask; /**< Capture-IR expected mask */ uint32_t idcode; /**< device identification code */ /** not all devices have idcode, * we'll discover this during chain examination */ bool hasidcode; /** Array of expected identification codes */ uint32_t *expected_ids; /** Number of expected identification codes */ uint8_t expected_ids_cnt; /** Flag saying whether to ignore version field in expected_ids[] */ bool ignore_version; /** current instruction */ uint8_t *cur_instr; /** Bypass register selected */ int bypass; struct jtag_tap_event_action *event_action; struct jtag_tap *next_tap; /* dap instance if some null if no instance , initialized to 0 by calloc*/ struct adiv5_dap *dap; /* private pointer to support none-jtag specific functions */ void *priv; }; void jtag_tap_init(struct jtag_tap *tap); void jtag_tap_free(struct jtag_tap *tap); struct jtag_tap *jtag_all_taps(void); const char *jtag_tap_name(const struct jtag_tap *tap); struct jtag_tap *jtag_tap_by_string(const char* dotted_name); struct jtag_tap *jtag_tap_by_jim_obj(Jim_Interp* interp, Jim_Obj *obj); struct jtag_tap *jtag_tap_by_position(unsigned abs_position); struct jtag_tap *jtag_tap_next_enabled(struct jtag_tap *p); unsigned jtag_tap_count_enabled(void); unsigned jtag_tap_count(void); /* * - TRST_ASSERTED triggers two sets of callbacks, after operations to * reset the scan chain -- via TMS+TCK signaling, or deasserting the * nTRST signal -- are queued: * * + Callbacks in C code fire first, patching internal state * + Then post-reset event scripts fire ... activating JTAG circuits * via TCK cycles, exiting SWD mode via TMS sequences, etc * * During those callbacks, scan chain contents have not been validated. * JTAG operations that address a specific TAP (primarily DR/IR scans) * must *not* be queued. * * - TAP_EVENT_SETUP is reported after TRST_ASSERTED, and after the scan * chain has been validated. JTAG operations including scans that * target specific TAPs may be performed. * * - TAP_EVENT_ENABLE and TAP_EVENT_DISABLE implement TAP activation and * deactivation outside the core using scripted code that understands * the specific JTAG router type. They might be triggered indirectly * from EVENT_SETUP operations. */ enum jtag_event { JTAG_TRST_ASSERTED, JTAG_TAP_EVENT_SETUP, JTAG_TAP_EVENT_ENABLE, JTAG_TAP_EVENT_DISABLE, }; struct jtag_tap_event_action { /** The event for which this action will be triggered. */ enum jtag_event event; /** The interpreter to use for evaluating the @c body. */ Jim_Interp *interp; /** Contains a script to 'eval' when the @c event is triggered. */ Jim_Obj *body; /* next action in linked list */ struct jtag_tap_event_action *next; }; /** * Defines the function signature requide for JTAG event callback * functions, which are added with jtag_register_event_callback() * and removed jtag_unregister_event_callback(). * @param event The event to handle. * @param prive A pointer to data that was passed to * jtag_register_event_callback(). * @returns Must return ERROR_OK on success, or an error code on failure. * * @todo Change to return void or define a use for its return code. */ typedef int (*jtag_event_handler_t)(enum jtag_event event, void *priv); int jtag_register_event_callback(jtag_event_handler_t f, void *x); int jtag_unregister_event_callback(jtag_event_handler_t f, void *x); int jtag_call_event_callbacks(enum jtag_event event); /** @returns The current JTAG speed setting. */ int jtag_get_speed(int *speed); /** * Given a @a speed setting, use the interface @c speed_div callback to * adjust the setting. * @param speed The speed setting to convert back to readable KHz. * @returns ERROR_OK if the interface has not been initialized or on success; * otherwise, the error code produced by the @c speed_div callback. */ int jtag_get_speed_readable(int *speed); /** Attempt to configure the interface for the specified KHz. */ int jtag_config_khz(unsigned khz); /** * Attempt to enable RTCK/RCLK. If that fails, fallback to the * specified frequency. */ int jtag_config_rclk(unsigned fallback_speed_khz); /** Retreives the clock speed of the JTAG interface in KHz. */ unsigned jtag_get_speed_khz(void); enum reset_types { RESET_NONE = 0x0, RESET_HAS_TRST = 0x1, RESET_HAS_SRST = 0x2, RESET_TRST_AND_SRST = 0x3, RESET_SRST_PULLS_TRST = 0x4, RESET_TRST_PULLS_SRST = 0x8, RESET_TRST_OPEN_DRAIN = 0x10, RESET_SRST_PUSH_PULL = 0x20, RESET_SRST_NO_GATING = 0x40, RESET_CNCT_UNDER_SRST = 0x80 }; enum reset_types jtag_get_reset_config(void); void jtag_set_reset_config(enum reset_types type); void jtag_set_nsrst_delay(unsigned delay); unsigned jtag_get_nsrst_delay(void); void jtag_set_ntrst_delay(unsigned delay); unsigned jtag_get_ntrst_delay(void); void jtag_set_nsrst_assert_width(unsigned delay); unsigned jtag_get_nsrst_assert_width(void); void jtag_set_ntrst_assert_width(unsigned delay); unsigned jtag_get_ntrst_assert_width(void); /** @returns The current state of TRST. */ int jtag_get_trst(void); /** @returns The current state of SRST. */ int jtag_get_srst(void); /** Enable or disable data scan verification checking. */ void jtag_set_verify(bool enable); /** @returns True if data scan verification will be performed. */ bool jtag_will_verify(void); /** Enable or disable verification of IR scan checking. */ void jtag_set_verify_capture_ir(bool enable); /** @returns True if IR scan verification will be performed. */ bool jtag_will_verify_capture_ir(void); /** Initialize debug adapter upon startup. */ int adapter_init(struct command_context *cmd_ctx); /** Shutdown the debug adapter upon program exit. */ int adapter_quit(void); /** Set ms to sleep after jtag_execute_queue() flushes queue. Debug purposes. */ void jtag_set_flush_queue_sleep(int ms); /** * Initialize JTAG chain using only a RESET reset. If init fails, * try reset + init. */ int jtag_init(struct command_context *cmd_ctx); /** reset, then initialize JTAG chain */ int jtag_init_reset(struct command_context *cmd_ctx); int jtag_register_commands(struct command_context *cmd_ctx); int jtag_init_inner(struct command_context *cmd_ctx); /** * @file * The JTAG interface can be implemented with a software or hardware fifo. * * TAP_DRSHIFT and TAP_IRSHIFT are illegal end states; however, * TAP_DRSHIFT/IRSHIFT can be emulated as end states, by using longer * scans. * * Code that is relatively insensitive to the path taken through state * machine (as long as it is JTAG compliant) can use @a endstate for * jtag_add_xxx_scan(). Otherwise, the pause state must be specified as * end state and a subsequent jtag_add_pathmove() must be issued. */ /** * Generate an IR SCAN with a list of scan fields with one entry for * each enabled TAP. * * If the input field list contains an instruction value for a TAP then * that is used otherwise the TAP is set to bypass. * * TAPs for which no fields are passed are marked as bypassed for * subsequent DR SCANs. * */ void jtag_add_ir_scan(struct jtag_tap *tap, struct scan_field *fields, tap_state_t endstate); /** * The same as jtag_add_ir_scan except no verification is performed out * the output values. */ void jtag_add_ir_scan_noverify(struct jtag_tap *tap, const struct scan_field *fields, tap_state_t state); /** * Scan out the bits in ir scan mode. * * If in_bits == NULL, discard incoming bits. */ void jtag_add_plain_ir_scan(int num_bits, const uint8_t *out_bits, uint8_t *in_bits, tap_state_t endstate); /** * Generate a DR SCAN using the fields passed to the function. * For connected TAPs, the function checks in_fields and uses fields * specified there. For bypassed TAPs, the function generates a dummy * 1-bit field. The bypass status of TAPs is set by jtag_add_ir_scan(). */ void jtag_add_dr_scan(struct jtag_tap *tap, int num_fields, const struct scan_field *fields, tap_state_t endstate); /** A version of jtag_add_dr_scan() that uses the check_value/mask fields */ void jtag_add_dr_scan_check(struct jtag_tap *tap, int num_fields, struct scan_field *fields, tap_state_t endstate); /** * Scan out the bits in ir scan mode. * * If in_bits == NULL, discard incoming bits. */ void jtag_add_plain_dr_scan(int num_bits, const uint8_t *out_bits, uint8_t *in_bits, tap_state_t endstate); /** * Defines the type of data passed to the jtag_callback_t interface. * The underlying type must allow storing an @c int or pointer type. */ typedef intptr_t jtag_callback_data_t; /** * Defines a simple JTAG callback that can allow conversions on data * scanned in from an interface. * * This callback should only be used for conversion that cannot fail. * For conversion types or checks that can fail, use the more complete * variant: jtag_callback_t. */ typedef void (*jtag_callback1_t)(jtag_callback_data_t data0); /** A simpler version of jtag_add_callback4(). */ void jtag_add_callback(jtag_callback1_t, jtag_callback_data_t data0); /** * Defines the interface of the JTAG callback mechanism. Such * callbacks can be executed once the queue has been flushed. * * The JTAG queue can be executed synchronously or asynchronously. * Typically for USB, the queue is executed asynchronously. For * low-latency interfaces, the queue may be executed synchronously. * * The callback mechanism is very general and does not make many * assumptions about what the callback does or what its arguments are. * These callbacks are typically executed *after* the *entire* JTAG * queue has been executed for e.g. USB interfaces, and they are * guaranteeed to be invoked in the order that they were queued. * * If the execution of the queue fails before the callbacks, then -- * depending on driver implementation -- the callbacks may or may not be * invoked. * * @todo Make that behavior consistent. * * @param data0 Typically used to point to the data to operate on. * Frequently this will be the data clocked in during a shift operation. * @param data1 An integer big enough to use as an @c int or a pointer. * @param data2 An integer big enough to use as an @c int or a pointer. * @param data3 An integer big enough to use as an @c int or a pointer. * @returns an error code */ typedef int (*jtag_callback_t)(jtag_callback_data_t data0, jtag_callback_data_t data1, jtag_callback_data_t data2, jtag_callback_data_t data3); /** * Run a TAP_RESET reset where the end state is TAP_RESET, * regardless of the start state. */ void jtag_add_tlr(void); /** * Application code *must* assume that interfaces will * implement transitions between states with different * paths and path lengths through the state diagram. The * path will vary across interface and also across versions * of the same interface over time. Even if the OpenOCD code * is unchanged, the actual path taken may vary over time * and versions of interface firmware or PCB revisions. * * Use jtag_add_pathmove() when specific transition sequences * are required. * * Do not use jtag_add_pathmove() unless you need to, but do use it * if you have to. * * DANGER! If the target is dependent upon a particular sequence * of transitions for things to work correctly(e.g. as a workaround * for an errata that contradicts the JTAG standard), then pathmove * must be used, even if some jtag interfaces happen to use the * desired path. Worse, the jtag interface used for testing a * particular implementation, could happen to use the "desired" * path when transitioning to/from end * state. * * A list of unambigious single clock state transitions, not * all drivers can support this, but it is required for e.g. * XScale and Xilinx support * * Note! TAP_RESET must not be used in the path! * * Note that the first on the list must be reachable * via a single transition from the current state. * * All drivers are required to implement jtag_add_pathmove(). * However, if the pathmove sequence can not be precisely * executed, an interface_jtag_add_pathmove() or jtag_execute_queue() * must return an error. It is legal, but not recommended, that * a driver returns an error in all cases for a pathmove if it * can only implement a few transitions and therefore * a partial implementation of pathmove would have little practical * application. * * If an error occurs, jtag_error will contain one of these error codes: * - ERROR_JTAG_NOT_STABLE_STATE -- The final state was not stable. * - ERROR_JTAG_STATE_INVALID -- The path passed through TAP_RESET. * - ERROR_JTAG_TRANSITION_INVALID -- The path includes invalid * state transitions. */ void jtag_add_pathmove(int num_states, const tap_state_t *path); /** * jtag_add_statemove() moves from the current state to @a goal_state. * * @param goal_state The final TAP state. * @return ERROR_OK on success, or an error code on failure. * * Moves from the current state to the goal \a state. * Both states must be stable. */ int jtag_add_statemove(tap_state_t goal_state); /** * Goes to TAP_IDLE (if we're not already there), cycle * precisely num_cycles in the TAP_IDLE state, after which move * to @a endstate (unless it is also TAP_IDLE). * * @param num_cycles Number of cycles in TAP_IDLE state. This argument * may be 0, in which case this routine will navigate to @a endstate * via TAP_IDLE. * @param endstate The final state. */ void jtag_add_runtest(int num_cycles, tap_state_t endstate); /** * A reset of the TAP state machine can be requested. * * Whether tms or trst reset is used depends on the capabilities of * the target and jtag interface(reset_config command configures this). * * srst can driver a reset of the TAP state machine and vice * versa * * Application code may need to examine value of jtag_reset_config * to determine the proper codepath * * DANGER! Even though srst drives trst, trst might not be connected to * the interface, and it might actually be *harmful* to assert trst in this case. * * This is why combinations such as "reset_config srst_only srst_pulls_trst" * are supported. * * only req_tlr_or_trst and srst can have a transition for a * call as the effects of transitioning both at the "same time" * are undefined, but when srst_pulls_trst or vice versa, * then trst & srst *must* be asserted together. */ void jtag_add_reset(int req_tlr_or_trst, int srst); void jtag_add_sleep(uint32_t us); int jtag_add_tms_seq(unsigned nbits, const uint8_t *seq, enum tap_state t); /** * Function jtag_add_clocks * first checks that the state in which the clocks are to be issued is * stable, then queues up num_cycles clocks for transmission. */ void jtag_add_clocks(int num_cycles); /** * For software FIFO implementations, the queued commands can be executed * during this call or earlier. A sw queue might decide to push out * some of the jtag_add_xxx() operations once the queue is "big enough". * * This fn will return an error code if any of the prior jtag_add_xxx() * calls caused a failure, e.g. check failure. Note that it does not * matter if the operation was executed *before* jtag_execute_queue(), * jtag_execute_queue() will still return an error code. * * All jtag_add_xxx() calls that have in_handler != NULL will have been * executed when this fn returns, but if what has been queued only * clocks data out, without reading anything back, then JTAG could * be running *after* jtag_execute_queue() returns. The API does * not define a way to flush a hw FIFO that runs *after* * jtag_execute_queue() returns. * * jtag_add_xxx() commands can either be executed immediately or * at some time between the jtag_add_xxx() fn call and jtag_execute_queue(). */ int jtag_execute_queue(void); /** same as jtag_execute_queue() but does not clear the error flag */ void jtag_execute_queue_noclear(void); /** @returns the number of times the scan queue has been flushed */ int jtag_get_flush_queue_count(void); /** Report Tcl event to all TAPs */ void jtag_notify_event(enum jtag_event); /* can be implemented by hw + sw */ int jtag_power_dropout(int *dropout); int jtag_srst_asserted(int *srst_asserted); /* JTAG support functions */ /** * Execute jtag queue and check value with an optional mask. * @param field Pointer to scan field. * @param value Pointer to scan value. * @param mask Pointer to scan mask; may be NULL. * @returns Nothing, but calls jtag_set_error() on any error. */ void jtag_check_value_mask(struct scan_field *field, uint8_t *value, uint8_t *mask); void jtag_sleep(uint32_t us); /* * The JTAG subsystem defines a number of error codes, * using codes between -100 and -199. */ #define ERROR_JTAG_INIT_FAILED (-100) #define ERROR_JTAG_INVALID_INTERFACE (-101) #define ERROR_JTAG_NOT_IMPLEMENTED (-102) #define ERROR_JTAG_TRST_ASSERTED (-103) #define ERROR_JTAG_QUEUE_FAILED (-104) #define ERROR_JTAG_NOT_STABLE_STATE (-105) #define ERROR_JTAG_DEVICE_ERROR (-107) #define ERROR_JTAG_STATE_INVALID (-108) #define ERROR_JTAG_TRANSITION_INVALID (-109) #define ERROR_JTAG_INIT_SOFT_FAIL (-110) /** * jtag_add_dr_out() is a version of jtag_add_dr_scan() which * only scans data out. It operates on 32 bit integers instead * of 8 bit, which makes it a better impedance match with * the calling code which often operate on 32 bit integers. * * Current or end_state can not be TAP_RESET. end_state can be TAP_INVALID * * num_bits[i] is the number of bits to clock out from value[i] LSB first. * * If the device is in bypass, then that is an error condition in * the caller code that is not detected by this fn, whereas * jtag_add_dr_scan() does detect it. Similarly if the device is not in * bypass, data must be passed to it. * * If anything fails, then jtag_error will be set and jtag_execute() will * return an error. There is no way to determine if there was a failure * during this function call. * * This is an inline fn to speed up embedded hosts. Also note that * interface_jtag_add_dr_out() can be a *small* inline function for * embedded hosts. * * There is no jtag_add_dr_outin() version of this fn that also allows * clocking data back in. Patches gladly accepted! */ /** * Set the current JTAG core execution error, unless one was set * by a previous call previously. Driver or application code must * use jtag_error_clear to reset jtag_error once this routine has been * called with a non-zero error code. */ void jtag_set_error(int error); /** * Resets jtag_error to ERROR_OK, returning its previous value. * @returns The previous value of @c jtag_error. */ int jtag_error_clear(void); /** * Return true if it's safe for a background polling task to access the * JTAG scan chain. Polling may be explicitly disallowed, and is also * unsafe while nTRST is active or the JTAG clock is gated off. */ bool is_jtag_poll_safe(void); /** * Return flag reporting whether JTAG polling is disallowed. */ bool jtag_poll_get_enabled(void); /** * Assign flag reporting whether JTAG polling is disallowed. */ void jtag_poll_set_enabled(bool value); /* The minidriver may have inline versions of some of the low * level APIs that are used in inner loops. */ #include bool transport_is_jtag(void); int jim_jtag_newtap(Jim_Interp *interp, int argc, Jim_Obj *const *argv); #endif /* JTAG_H */ openocd-0.7.0/src/jtag/drivers/0000755000175000001440000000000012141414412013326 500000000000000openocd-0.7.0/src/jtag/drivers/rlink_ep1_cmd.h0000644000175000001440000000554112134336410016136 00000000000000/*************************************************************************** * Copyright (C) 2008 Lou Deluxe * * lou.openocd012@fixit.nospammail.net * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /* * Command opcodes that can be sent over endpoint 1. * This codifies information provided by Rob Brown . * The buffer can contain several of these, but only one which returns data. * Some of these opcodes have arguments, which follow immediately. * If shorter than the packet size, trailing positions should be zero-filled. */ /* LED update enables: * When enabled, each LED is updated automatically. * When not enabled, each LED can be controlled manually with EP1_CMD_SET_PORTD_LEDS. */ #define EP1_CMD_LEDUE_BOTH (0x05) /* EP1_CMD_LEDUE_NONE has the side effect of turning the LEDs on */ #define EP1_CMD_LEDUE_NONE (0x06) #define EP1_CMD_LEDUE_ERROR (0x17) #define EP1_CMD_LEDUE_BUSY (0x18) #define EP1_CMD_DTC_STOP (0x0b) #define EP1_CMD_DTC_LOAD (0x0c) #define EP1_CMD_DTC_CALL (0x0d) #define EP1_CMD_SET_UPLOAD (0x0f) #define EP1_CMD_SET_DOWNLOAD (0x10) #define EP1_CMD_DTC_WAIT (0x12) #define EP1_CMD_DTC_GET_STATUS (0x15) /* a quick way to just read back one byte */ #define EP1_CMD_DTC_GET_CACHED_STATUS (0x16) /* Writes upper 2 bits (SHDN and SEL) of port D with argument */ #define EP1_CMD_SET_PORTD_VPP (0x19) /* Writes lower 2 bits (BUSY and ERROR) of port D with argument */ #define EP1_CMD_SET_PORTD_LEDS (0x1a) #define EP1_CMD_MEMORY_READ (0x28) #define EP1_CMD_MEMORY_WRITE (0x29) #define EP1_CMD_GET_FWREV (0xfe) #define EP1_CMD_GET_SERIAL (0xff) openocd-0.7.0/src/jtag/drivers/rlink.h0000644000175000001440000000321312134336410014540 00000000000000/*************************************************************************** * Copyright (C) 2008 Lou Deluxe * * lou.openocd012@fixit.nospammail.net * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ struct rlink_speed_table { uint8_t const *dtc; uint16_t dtc_size; uint16_t khz; uint8_t prescaler; }; extern const struct rlink_speed_table rlink_speed_table[]; extern const size_t rlink_speed_table_size; openocd-0.7.0/src/jtag/drivers/ft2232.c0000644000175000001440000034605012137151331014347 00000000000000/*************************************************************************** * Copyright (C) 2009 by Øyvind Harboe * * Øyvind Harboe * * * * Copyright (C) 2009 by SoftPLC Corporation. http://softplc.com * * Dick Hollenbeck * * * * Copyright (C) 2004, 2006 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /** * @file * JTAG adapters based on the FT2232 full and high speed USB parts are * popular low cost JTAG debug solutions. Many FT2232 based JTAG adapters * are discrete, but development boards may integrate them as alternatives * to more capable (and expensive) third party JTAG pods. * * JTAG uses only one of the two communications channels ("MPSSE engines") * on these devices. Adapters based on FT4232 parts have four ports/channels * (A/B/C/D), instead of just two (A/B). * * Especially on development boards integrating one of these chips (as * opposed to discrete pods/dongles), the additional channels can be used * for a variety of purposes, but OpenOCD only uses one channel at a time. * * - As a USB-to-serial adapter for the target's console UART ... * which may be able to support ROM boot loaders that load initial * firmware images to flash (or SRAM). * * - On systems which support ARM's SWD in addition to JTAG, or instead * of it, that second port can be used for reading SWV/SWO trace data. * * - Additional JTAG links, e.g. to a CPLD or * FPGA. * * FT2232 based JTAG adapters are "dumb" not "smart", because most JTAG * request/response interactions involve round trips over the USB link. * A "smart" JTAG adapter has intelligence close to the scan chain, so it * can for example poll quickly for a status change (usually taking on the * order of microseconds not milliseconds) before beginning a queued * transaction which require the previous one to have completed. * * There are dozens of adapters of this type, differing in details which * this driver needs to understand. Those "layout" details are required * as part of FT2232 driver configuration. * * This code uses information contained in the MPSSE specification which was * found here: * http://www.ftdichip.com/Documents/AppNotes/AN2232C-01_MPSSE_Cmnd.pdf * Hereafter this is called the "MPSSE Spec". * * The datasheet for the ftdichip.com's FT2232D part is here: * http://www.ftdichip.com/Documents/DataSheets/DS_FT2232D.pdf * * Also note the issue with code 0x4b (clock data to TMS) noted in * http://developer.intra2net.com/mailarchive/html/libftdi/2009/msg00292.html * which can affect longer JTAG state paths. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* project specific includes */ #include #include #include #if IS_CYGWIN == 1 #include #endif #include #if (BUILD_FT2232_FTD2XX == 1 && BUILD_FT2232_LIBFTDI == 1) #error "BUILD_FT2232_FTD2XX && BUILD_FT2232_LIBFTDI are mutually exclusive" #elif (BUILD_FT2232_FTD2XX != 1 && BUILD_FT2232_LIBFTDI != 1) #error "BUILD_FT2232_FTD2XX || BUILD_FT2232_LIBFTDI must be chosen" #endif /* FT2232 access library includes */ #if BUILD_FT2232_FTD2XX == 1 #include #include "ftd2xx_common.h" enum ftdi_interface { INTERFACE_ANY = 0, INTERFACE_A = 1, INTERFACE_B = 2, INTERFACE_C = 3, INTERFACE_D = 4 }; #elif BUILD_FT2232_LIBFTDI == 1 #include #endif /* max TCK for the high speed devices 30000 kHz */ #define FTDI_x232H_MAX_TCK 30000 /* max TCK for the full speed devices 6000 kHz */ #define FTDI_2232C_MAX_TCK 6000 /* this speed value tells that RTCK is requested */ #define RTCK_SPEED -1 /* * On my Athlon XP 1900+ EHCI host with FT2232H JTAG dongle I get read timeout * errors with a retry count of 100. Increasing it solves the problem for me. * - Dimitar * * FIXME There's likely an issue with the usb_read_timeout from libftdi. * Fix that (libusb? kernel? libftdi? here?) and restore the retry count * to something sane. */ #define LIBFTDI_READ_RETRY_COUNT 2000 #ifndef BUILD_FT2232_HIGHSPEED #if BUILD_FT2232_FTD2XX == 1 enum { FT_DEVICE_2232H = 6, FT_DEVICE_4232H, FT_DEVICE_232H }; #elif BUILD_FT2232_LIBFTDI == 1 enum ftdi_chip_type { TYPE_2232H = 4, TYPE_4232H = 5, TYPE_232H = 6 }; #endif #endif /** * Send out \a num_cycles on the TCK line while the TAP(s) are in a * stable state. Calling code must ensure that current state is stable, * that verification is not done in here. * * @param num_cycles The number of clocks cycles to send. * @param cmd The command to send. * * @returns ERROR_OK on success, or ERROR_JTAG_QUEUE_FAILED on failure. */ static int ft2232_stableclocks(int num_cycles, struct jtag_command *cmd); static char *ft2232_device_desc_A; static char *ft2232_device_desc; static char *ft2232_serial; static uint8_t ft2232_latency = 2; static unsigned ft2232_max_tck = FTDI_2232C_MAX_TCK; static int ft2232_channel = INTERFACE_ANY; #define MAX_USB_IDS 8 /* vid = pid = 0 marks the end of the list */ static uint16_t ft2232_vid[MAX_USB_IDS + 1] = { 0x0403, 0 }; static uint16_t ft2232_pid[MAX_USB_IDS + 1] = { 0x6010, 0 }; struct ft2232_layout { char *name; int (*init)(void); void (*reset)(int trst, int srst); void (*blink)(void); int channel; }; /* init procedures for supported layouts */ static int usbjtag_init(void); static int jtagkey_init(void); static int lm3s811_jtag_init(void); static int icdi_jtag_init(void); static int olimex_jtag_init(void); static int flyswatter1_init(void); static int flyswatter2_init(void); static int minimodule_init(void); static int turtle_init(void); static int comstick_init(void); static int stm32stick_init(void); static int axm0432_jtag_init(void); static int sheevaplug_init(void); static int icebear_jtag_init(void); static int cortino_jtag_init(void); static int signalyzer_init(void); static int signalyzer_h_init(void); static int ktlink_init(void); static int redbee_init(void); static int lisa_l_init(void); static int flossjtag_init(void); static int xds100v2_init(void); static int digilent_hs1_init(void); /* reset procedures for supported layouts */ static void ftx23_reset(int trst, int srst); static void jtagkey_reset(int trst, int srst); static void olimex_jtag_reset(int trst, int srst); static void flyswatter1_reset(int trst, int srst); static void flyswatter2_reset(int trst, int srst); static void minimodule_reset(int trst, int srst); static void turtle_reset(int trst, int srst); static void comstick_reset(int trst, int srst); static void stm32stick_reset(int trst, int srst); static void axm0432_jtag_reset(int trst, int srst); static void sheevaplug_reset(int trst, int srst); static void icebear_jtag_reset(int trst, int srst); static void signalyzer_h_reset(int trst, int srst); static void ktlink_reset(int trst, int srst); static void redbee_reset(int trst, int srst); static void xds100v2_reset(int trst, int srst); static void digilent_hs1_reset(int trst, int srst); /* blink procedures for layouts that support a blinking led */ static void olimex_jtag_blink(void); static void flyswatter1_jtag_blink(void); static void flyswatter2_jtag_blink(void); static void turtle_jtag_blink(void); static void signalyzer_h_blink(void); static void ktlink_blink(void); static void lisa_l_blink(void); static void flossjtag_blink(void); /* common transport support options */ /* static const char *jtag_and_swd[] = { "jtag", "swd", NULL }; */ static const struct ft2232_layout ft2232_layouts[] = { { .name = "usbjtag", .init = usbjtag_init, .reset = ftx23_reset, }, { .name = "jtagkey", .init = jtagkey_init, .reset = jtagkey_reset, }, { .name = "jtagkey_prototype_v1", .init = jtagkey_init, .reset = jtagkey_reset, }, { .name = "oocdlink", .init = jtagkey_init, .reset = jtagkey_reset, }, { .name = "signalyzer", .init = signalyzer_init, .reset = ftx23_reset, }, { .name = "evb_lm3s811", .init = lm3s811_jtag_init, .reset = ftx23_reset, }, { .name = "luminary_icdi", .init = icdi_jtag_init, .reset = ftx23_reset, }, { .name = "olimex-jtag", .init = olimex_jtag_init, .reset = olimex_jtag_reset, .blink = olimex_jtag_blink }, { .name = "flyswatter", .init = flyswatter1_init, .reset = flyswatter1_reset, .blink = flyswatter1_jtag_blink }, { .name = "flyswatter2", .init = flyswatter2_init, .reset = flyswatter2_reset, .blink = flyswatter2_jtag_blink }, { .name = "minimodule", .init = minimodule_init, .reset = minimodule_reset, }, { .name = "turtelizer2", .init = turtle_init, .reset = turtle_reset, .blink = turtle_jtag_blink }, { .name = "comstick", .init = comstick_init, .reset = comstick_reset, }, { .name = "stm32stick", .init = stm32stick_init, .reset = stm32stick_reset, }, { .name = "axm0432_jtag", .init = axm0432_jtag_init, .reset = axm0432_jtag_reset, }, { .name = "sheevaplug", .init = sheevaplug_init, .reset = sheevaplug_reset, }, { .name = "icebear", .init = icebear_jtag_init, .reset = icebear_jtag_reset, }, { .name = "cortino", .init = cortino_jtag_init, .reset = comstick_reset, }, { .name = "signalyzer-h", .init = signalyzer_h_init, .reset = signalyzer_h_reset, .blink = signalyzer_h_blink }, { .name = "ktlink", .init = ktlink_init, .reset = ktlink_reset, .blink = ktlink_blink }, { .name = "redbee-econotag", .init = redbee_init, .reset = redbee_reset, }, { .name = "redbee-usb", .init = redbee_init, .reset = redbee_reset, .channel = INTERFACE_B, }, { .name = "lisa-l", .init = lisa_l_init, .reset = ftx23_reset, .blink = lisa_l_blink, .channel = INTERFACE_B, }, { .name = "flossjtag", .init = flossjtag_init, .reset = ftx23_reset, .blink = flossjtag_blink, }, { .name = "xds100v2", .init = xds100v2_init, .reset = xds100v2_reset, }, { .name = "digilent-hs1", .init = digilent_hs1_init, .reset = digilent_hs1_reset, .channel = INTERFACE_A, }, { .name = NULL, /* END OF TABLE */ }, }; /* bitmask used to drive nTRST; usually a GPIOLx signal */ static uint8_t nTRST; static uint8_t nTRSTnOE; /* bitmask used to drive nSRST; usually a GPIOLx signal */ static uint8_t nSRST; static uint8_t nSRSTnOE; /** the layout being used with this debug session */ static const struct ft2232_layout *layout; /** default bitmask values driven on DBUS: TCK/TDI/TDO/TMS and GPIOL(0..4) */ static uint8_t low_output; /* note that direction bit == 1 means that signal is an output */ /** default direction bitmask for DBUS: TCK/TDI/TDO/TMS and GPIOL(0..4) */ static uint8_t low_direction; /** default value bitmask for CBUS GPIOH(0..4) */ static uint8_t high_output; /** default direction bitmask for CBUS GPIOH(0..4) */ static uint8_t high_direction; #if BUILD_FT2232_FTD2XX == 1 static FT_HANDLE ftdih; static FT_DEVICE ftdi_device; #elif BUILD_FT2232_LIBFTDI == 1 static struct ftdi_context ftdic; static enum ftdi_chip_type ftdi_device; #endif static struct jtag_command *first_unsent; /* next command that has to be sent */ static int require_send; /* http://urjtag.wiki.sourceforge.net/Cable + FT2232 says: "There is a significant difference between libftdi and libftd2xx. The latter one allows to schedule up to 64*64 bytes of result data while libftdi fails with more than 4*64. As a consequence, the FT2232 driver is forced to perform around 16x more USB transactions for long command streams with TDO capture when running with libftdi." No idea how we get #define FT2232_BUFFER_SIZE 131072 a comment would have been nice. */ #if BUILD_FT2232_FTD2XX == 1 #define FT2232_BUFFER_READ_QUEUE_SIZE (64*64) #else #define FT2232_BUFFER_READ_QUEUE_SIZE (64*4) #endif #define FT2232_BUFFER_SIZE 131072 static uint8_t *ft2232_buffer; static int ft2232_buffer_size; static int ft2232_read_pointer; static int ft2232_expect_read; /** * Function buffer_write * writes a byte into the byte buffer, "ft2232_buffer", which must be sent later. * @param val is the byte to send. */ static inline void buffer_write(uint8_t val) { assert(ft2232_buffer); assert((unsigned) ft2232_buffer_size < (unsigned) FT2232_BUFFER_SIZE); ft2232_buffer[ft2232_buffer_size++] = val; } /** * Function buffer_read * returns a byte from the byte buffer. */ static inline uint8_t buffer_read(void) { assert(ft2232_buffer); assert(ft2232_read_pointer < ft2232_buffer_size); return ft2232_buffer[ft2232_read_pointer++]; } /** * Clocks out \a bit_count bits on the TMS line, starting with the least * significant bit of tms_bits and progressing to more significant bits. * Rigorous state transition logging is done here via tap_set_state(). * * @param mpsse_cmd One of the MPSSE TMS oriented commands such as * 0x4b or 0x6b. See the MPSSE spec referenced above for their * functionality. The MPSSE command "Clock Data to TMS/CS Pin (no Read)" * is often used for this, 0x4b. * * @param tms_bits Holds the sequence of bits to send. * @param tms_count Tells how many bits in the sequence. * @param tdi_bit A single bit to pass on to TDI before the first TCK * cycle and held static for the duration of TMS clocking. * * See the MPSSE spec referenced above. */ static void clock_tms(uint8_t mpsse_cmd, int tms_bits, int tms_count, bool tdi_bit) { uint8_t tms_byte; int i; int tms_ndx; /* bit index into tms_byte */ assert(tms_count > 0); DEBUG_JTAG_IO("mpsse cmd=%02x, tms_bits = 0x%08x, bit_count=%d", mpsse_cmd, tms_bits, tms_count); for (tms_byte = tms_ndx = i = 0; i < tms_count; ++i, tms_bits >>= 1) { bool bit = tms_bits & 1; if (bit) tms_byte |= (1 << tms_ndx); /* always do state transitions in public view */ tap_set_state(tap_state_transition(tap_get_state(), bit)); /* we wrote a bit to tms_byte just above, increment bit index. if bit was zero * also increment. */ ++tms_ndx; if (tms_ndx == 7 || i == tms_count-1) { buffer_write(mpsse_cmd); buffer_write(tms_ndx - 1); /* Bit 7 of the byte is passed on to TDI/DO before the first TCK/SK of * TMS/CS and is held static for the duration of TMS/CS clocking. */ buffer_write(tms_byte | (tdi_bit << 7)); } } } /** * Function get_tms_buffer_requirements * returns what clock_tms() will consume if called with * same \a bit_count. */ static inline int get_tms_buffer_requirements(int bit_count) { return ((bit_count + 6)/7) * 3; } /** * Function move_to_state * moves the TAP controller from the current state to a * \a goal_state through a path given by tap_get_tms_path(). State transition * logging is performed by delegation to clock_tms(). * * @param goal_state is the destination state for the move. */ static void move_to_state(tap_state_t goal_state) { tap_state_t start_state = tap_get_state(); /* goal_state is 1/2 of a tuple/pair of states which allow convenient * lookup of the required TMS pattern to move to this state from the start state. */ /* do the 2 lookups */ int tms_bits = tap_get_tms_path(start_state, goal_state); int tms_count = tap_get_tms_path_len(start_state, goal_state); DEBUG_JTAG_IO("start=%s goal=%s", tap_state_name(start_state), tap_state_name(goal_state)); clock_tms(0x4b, tms_bits, tms_count, 0); } static int ft2232_write(uint8_t *buf, int size, uint32_t *bytes_written) { #if BUILD_FT2232_FTD2XX == 1 FT_STATUS status; DWORD dw_bytes_written = 0; status = FT_Write(ftdih, buf, size, &dw_bytes_written); if (status != FT_OK) { *bytes_written = dw_bytes_written; LOG_ERROR("FT_Write returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } else *bytes_written = dw_bytes_written; #elif BUILD_FT2232_LIBFTDI == 1 int retval = ftdi_write_data(&ftdic, buf, size); if (retval < 0) { *bytes_written = 0; LOG_ERROR("ftdi_write_data: %s", ftdi_get_error_string(&ftdic)); return ERROR_JTAG_DEVICE_ERROR; } else *bytes_written = retval; #endif if (*bytes_written != (uint32_t)size) return ERROR_JTAG_DEVICE_ERROR; return ERROR_OK; } static int ft2232_read(uint8_t *buf, uint32_t size, uint32_t *bytes_read) { #if BUILD_FT2232_FTD2XX == 1 DWORD dw_bytes_read; FT_STATUS status; int timeout = 5; *bytes_read = 0; while ((*bytes_read < size) && timeout--) { status = FT_Read(ftdih, buf + *bytes_read, size - *bytes_read, &dw_bytes_read); if (status != FT_OK) { *bytes_read = 0; LOG_ERROR("FT_Read returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } *bytes_read += dw_bytes_read; } #elif BUILD_FT2232_LIBFTDI == 1 int retval; int timeout = LIBFTDI_READ_RETRY_COUNT; *bytes_read = 0; while ((*bytes_read < size) && timeout--) { retval = ftdi_read_data(&ftdic, buf + *bytes_read, size - *bytes_read); if (retval < 0) { *bytes_read = 0; LOG_ERROR("ftdi_read_data: %s", ftdi_get_error_string(&ftdic)); return ERROR_JTAG_DEVICE_ERROR; } *bytes_read += retval; } #endif if (*bytes_read < size) { LOG_ERROR("couldn't read enough bytes from " "FT2232 device (%i < %i)", (unsigned)*bytes_read, (unsigned)size); return ERROR_JTAG_DEVICE_ERROR; } return ERROR_OK; } static bool ft2232_device_is_highspeed(void) { #if BUILD_FT2232_FTD2XX == 1 return (ftdi_device == FT_DEVICE_2232H) || (ftdi_device == FT_DEVICE_4232H) #ifdef HAS_ENUM_FT232H || (ftdi_device == FT_DEVICE_232H) #endif ; #elif BUILD_FT2232_LIBFTDI == 1 return (ftdi_device == TYPE_2232H || ftdi_device == TYPE_4232H #ifdef HAS_ENUM_FT232H || ftdi_device == TYPE_232H #endif ); #endif } /* * Commands that only apply to the highspeed FTx232H devices (FT2232H, FT4232H, FT232H). * See chapter 6 in http://www.ftdichip.com/Documents/AppNotes/ * AN_108_Command_Processor_for_MPSSE_and_MCU_Host_Bus_Emulation_Modes.pdf */ static int ftx232h_adaptive_clocking(bool enable) { uint8_t buf = enable ? 0x96 : 0x97; LOG_DEBUG("%2.2x", buf); uint32_t bytes_written; int retval; retval = ft2232_write(&buf, sizeof(buf), &bytes_written); if (retval != ERROR_OK) { LOG_ERROR("couldn't write command to %s adaptive clocking" , enable ? "enable" : "disable"); return retval; } return ERROR_OK; } /** * Enable/disable the clk divide by 5 of the 60MHz master clock. * This result in a JTAG clock speed range of 91.553Hz-6MHz * respective 457.763Hz-30MHz. */ static int ftx232h_clk_divide_by_5(bool enable) { uint32_t bytes_written; uint8_t buf = enable ? 0x8b : 0x8a; if (ft2232_write(&buf, sizeof(buf), &bytes_written) != ERROR_OK) { LOG_ERROR("couldn't write command to %s clk divide by 5" , enable ? "enable" : "disable"); return ERROR_JTAG_INIT_FAILED; } ft2232_max_tck = enable ? FTDI_2232C_MAX_TCK : FTDI_x232H_MAX_TCK; LOG_INFO("max TCK change to: %u kHz", ft2232_max_tck); return ERROR_OK; } static int ft2232_speed(int speed) { uint8_t buf[3]; int retval; uint32_t bytes_written; retval = ERROR_OK; bool enable_adaptive_clocking = (RTCK_SPEED == speed); if (ft2232_device_is_highspeed()) retval = ftx232h_adaptive_clocking(enable_adaptive_clocking); else if (enable_adaptive_clocking) { LOG_ERROR("ft2232 device %lu does not support RTCK" , (long unsigned int)ftdi_device); return ERROR_FAIL; } if ((enable_adaptive_clocking) || (ERROR_OK != retval)) return retval; buf[0] = 0x86; /* command "set divisor" */ buf[1] = speed & 0xff; /* valueL (0 = 6MHz, 1 = 3MHz, 2 = 2.0MHz, ...*/ buf[2] = (speed >> 8) & 0xff; /* valueH */ LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); retval = ft2232_write(buf, sizeof(buf), &bytes_written); if (retval != ERROR_OK) { LOG_ERROR("couldn't set FT2232 TCK speed"); return retval; } return ERROR_OK; } static int ft2232_speed_div(int speed, int *khz) { /* Take a look in the FT2232 manual, * AN2232C-01 Command Processor for * MPSSE and MCU Host Bus. Chapter 3.8 */ *khz = (RTCK_SPEED == speed) ? 0 : ft2232_max_tck / (1 + speed); return ERROR_OK; } static int ft2232_khz(int khz, int *jtag_speed) { if (khz == 0) { if (ft2232_device_is_highspeed()) { *jtag_speed = RTCK_SPEED; return ERROR_OK; } else { LOG_DEBUG("RCLK not supported"); return ERROR_FAIL; } } /* Take a look in the FT2232 manual, * AN2232C-01 Command Processor for * MPSSE and MCU Host Bus. Chapter 3.8 * * We will calc here with a multiplier * of 10 for better rounding later. */ /* Calc speed, (ft2232_max_tck / khz) - 1 * Use 65000 for better rounding */ *jtag_speed = ((ft2232_max_tck*10) / khz) - 10; /* Add 0.9 for rounding */ *jtag_speed += 9; /* Calc real speed */ *jtag_speed = *jtag_speed / 10; /* Check if speed is greater than 0 */ if (*jtag_speed < 0) *jtag_speed = 0; /* Check max value */ if (*jtag_speed > 0xFFFF) *jtag_speed = 0xFFFF; return ERROR_OK; } static void ft2232_end_state(tap_state_t state) { if (tap_is_state_stable(state)) tap_set_end_state(state); else { LOG_ERROR("BUG: %s is not a stable end state", tap_state_name(state)); exit(-1); } } static void ft2232_read_scan(enum scan_type type, uint8_t *buffer, int scan_size) { int num_bytes = (scan_size + 7) / 8; int bits_left = scan_size; int cur_byte = 0; while (num_bytes-- > 1) { buffer[cur_byte++] = buffer_read(); bits_left -= 8; } buffer[cur_byte] = 0x0; /* There is one more partial byte left from the clock data in/out instructions */ if (bits_left > 1) buffer[cur_byte] = buffer_read() >> 1; /* This shift depends on the length of the *clock data to tms instruction, insterted *at end of the scan, now fixed to a two *step transition in ft2232_add_scan */ buffer[cur_byte] = (buffer[cur_byte] | (((buffer_read()) << 1) & 0x80)) >> (8 - bits_left); } static void ft2232_debug_dump_buffer(void) { int i; char line[256]; char *line_p = line; for (i = 0; i < ft2232_buffer_size; i++) { line_p += snprintf(line_p, sizeof(line) - (line_p - line), "%2.2x ", ft2232_buffer[i]); if (i % 16 == 15) { LOG_DEBUG("%s", line); line_p = line; } } if (line_p != line) LOG_DEBUG("%s", line); } static int ft2232_send_and_recv(struct jtag_command *first, struct jtag_command *last) { struct jtag_command *cmd; uint8_t *buffer; int scan_size; enum scan_type type; int retval; uint32_t bytes_written = 0; uint32_t bytes_read = 0; #ifdef _DEBUG_USB_IO_ struct timeval start, inter, inter2, end; struct timeval d_inter, d_inter2, d_end; #endif #ifdef _DEBUG_USB_COMMS_ LOG_DEBUG("write buffer (size %i):", ft2232_buffer_size); ft2232_debug_dump_buffer(); #endif #ifdef _DEBUG_USB_IO_ gettimeofday(&start, NULL); #endif retval = ft2232_write(ft2232_buffer, ft2232_buffer_size, &bytes_written); if (retval != ERROR_OK) { LOG_ERROR("couldn't write MPSSE commands to FT2232"); return retval; } #ifdef _DEBUG_USB_IO_ gettimeofday(&inter, NULL); #endif if (ft2232_expect_read) { /* FIXME this "timeout" is never changed ... */ int timeout = LIBFTDI_READ_RETRY_COUNT; ft2232_buffer_size = 0; #ifdef _DEBUG_USB_IO_ gettimeofday(&inter2, NULL); #endif retval = ft2232_read(ft2232_buffer, ft2232_expect_read, &bytes_read); if (retval != ERROR_OK) { LOG_ERROR("couldn't read from FT2232"); return retval; } #ifdef _DEBUG_USB_IO_ gettimeofday(&end, NULL); timeval_subtract(&d_inter, &inter, &start); timeval_subtract(&d_inter2, &inter2, &start); timeval_subtract(&d_end, &end, &start); LOG_INFO("inter: %u.%06u, inter2: %u.%06u end: %u.%06u", (unsigned)d_inter.tv_sec, (unsigned)d_inter.tv_usec, (unsigned)d_inter2.tv_sec, (unsigned)d_inter2.tv_usec, (unsigned)d_end.tv_sec, (unsigned)d_end.tv_usec); #endif ft2232_buffer_size = bytes_read; if (ft2232_expect_read != ft2232_buffer_size) { LOG_ERROR("ft2232_expect_read (%i) != " "ft2232_buffer_size (%i) " "(%i retries)", ft2232_expect_read, ft2232_buffer_size, LIBFTDI_READ_RETRY_COUNT - timeout); ft2232_debug_dump_buffer(); exit(-1); } #ifdef _DEBUG_USB_COMMS_ LOG_DEBUG("read buffer (%i retries): %i bytes", LIBFTDI_READ_RETRY_COUNT - timeout, ft2232_buffer_size); ft2232_debug_dump_buffer(); #endif } ft2232_expect_read = 0; ft2232_read_pointer = 0; /* return ERROR_OK, unless a jtag_read_buffer returns a failed check * that wasn't handled by a caller-provided error handler */ retval = ERROR_OK; cmd = first; while (cmd != last) { switch (cmd->type) { case JTAG_SCAN: type = jtag_scan_type(cmd->cmd.scan); if (type != SCAN_OUT) { scan_size = jtag_scan_size(cmd->cmd.scan); buffer = calloc(DIV_ROUND_UP(scan_size, 8), 1); ft2232_read_scan(type, buffer, scan_size); if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) retval = ERROR_JTAG_QUEUE_FAILED; free(buffer); } break; default: break; } cmd = cmd->next; } ft2232_buffer_size = 0; return retval; } /** * Function ft2232_add_pathmove * moves the TAP controller from the current state to a new state through the * given path, where path is an array of tap_state_t's. * * @param path is an array of tap_stat_t which gives the states to traverse through * ending with the last state at path[num_states-1] * @param num_states is the count of state steps to move through */ static void ft2232_add_pathmove(tap_state_t *path, int num_states) { int state_count = 0; assert((unsigned) num_states <= 32u); /* tms_bits only holds 32 bits */ DEBUG_JTAG_IO("-"); /* this loop verifies that the path is legal and logs each state in the path */ while (num_states) { unsigned char tms_byte = 0; /* zero this on each MPSSE batch */ int bit_count = 0; int num_states_batch = num_states > 7 ? 7 : num_states; /* command "Clock Data to TMS/CS Pin (no Read)" */ buffer_write(0x4b); /* number of states remaining */ buffer_write(num_states_batch - 1); while (num_states_batch--) { /* either TMS=0 or TMS=1 must work ... */ if (tap_state_transition(tap_get_state(), false) == path[state_count]) buf_set_u32(&tms_byte, bit_count++, 1, 0x0); else if (tap_state_transition(tap_get_state(), true) == path[state_count]) buf_set_u32(&tms_byte, bit_count++, 1, 0x1); /* ... or else the caller goofed BADLY */ else { LOG_ERROR("BUG: %s -> %s isn't a valid " "TAP state transition", tap_state_name(tap_get_state()), tap_state_name(path[state_count])); exit(-1); } tap_set_state(path[state_count]); state_count++; num_states--; } buffer_write(tms_byte); } tap_set_end_state(tap_get_state()); } static void ft2232_add_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size) { int num_bytes = (scan_size + 7) / 8; int bits_left = scan_size; int cur_byte = 0; int last_bit; if (!ir_scan) { if (tap_get_state() != TAP_DRSHIFT) move_to_state(TAP_DRSHIFT); } else { if (tap_get_state() != TAP_IRSHIFT) move_to_state(TAP_IRSHIFT); } /* add command for complete bytes */ while (num_bytes > 1) { int thisrun_bytes; if (type == SCAN_IO) { /* Clock Data Bytes In and Out LSB First */ buffer_write(0x39); /* LOG_DEBUG("added TDI bytes (io %i)", num_bytes); */ } else if (type == SCAN_OUT) { /* Clock Data Bytes Out on -ve Clock Edge LSB First (no Read) */ buffer_write(0x19); /* LOG_DEBUG("added TDI bytes (o)"); */ } else if (type == SCAN_IN) { /* Clock Data Bytes In on +ve Clock Edge LSB First (no Write) */ buffer_write(0x28); /* LOG_DEBUG("added TDI bytes (i %i)", num_bytes); */ } thisrun_bytes = (num_bytes > 65537) ? 65536 : (num_bytes - 1); num_bytes -= thisrun_bytes; buffer_write((uint8_t) (thisrun_bytes - 1)); buffer_write((uint8_t) ((thisrun_bytes - 1) >> 8)); if (type != SCAN_IN) { /* add complete bytes */ while (thisrun_bytes-- > 0) { buffer_write(buffer[cur_byte++]); bits_left -= 8; } } else /* (type == SCAN_IN) */ bits_left -= 8 * (thisrun_bytes); } /* the most signifcant bit is scanned during TAP movement */ if (type != SCAN_IN) last_bit = (buffer[cur_byte] >> (bits_left - 1)) & 0x1; else last_bit = 0; /* process remaining bits but the last one */ if (bits_left > 1) { if (type == SCAN_IO) { /* Clock Data Bits In and Out LSB First */ buffer_write(0x3b); /* LOG_DEBUG("added TDI bits (io) %i", bits_left - 1); */ } else if (type == SCAN_OUT) { /* Clock Data Bits Out on -ve Clock Edge LSB First (no Read) */ buffer_write(0x1b); /* LOG_DEBUG("added TDI bits (o)"); */ } else if (type == SCAN_IN) { /* Clock Data Bits In on +ve Clock Edge LSB First (no Write) */ buffer_write(0x2a); /* LOG_DEBUG("added TDI bits (i %i)", bits_left - 1); */ } buffer_write(bits_left - 2); if (type != SCAN_IN) buffer_write(buffer[cur_byte]); } if ((ir_scan && (tap_get_end_state() == TAP_IRSHIFT)) || (!ir_scan && (tap_get_end_state() == TAP_DRSHIFT))) { if (type == SCAN_IO) { /* Clock Data Bits In and Out LSB First */ buffer_write(0x3b); /* LOG_DEBUG("added TDI bits (io) %i", bits_left - 1); */ } else if (type == SCAN_OUT) { /* Clock Data Bits Out on -ve Clock Edge LSB First (no Read) */ buffer_write(0x1b); /* LOG_DEBUG("added TDI bits (o)"); */ } else if (type == SCAN_IN) { /* Clock Data Bits In on +ve Clock Edge LSB First (no Write) */ buffer_write(0x2a); /* LOG_DEBUG("added TDI bits (i %i)", bits_left - 1); */ } buffer_write(0x0); if (type != SCAN_IN) buffer_write(last_bit); } else { int tms_bits; int tms_count; uint8_t mpsse_cmd; /* move from Shift-IR/DR to end state */ if (type != SCAN_OUT) { /* We always go to the PAUSE state in two step at the end of an IN or IO *scan * This must be coordinated with the bit shifts in ft2232_read_scan */ tms_bits = 0x01; tms_count = 2; /* Clock Data to TMS/CS Pin with Read */ mpsse_cmd = 0x6b; } else { tms_bits = tap_get_tms_path(tap_get_state(), tap_get_end_state()); tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); /* Clock Data to TMS/CS Pin (no Read) */ mpsse_cmd = 0x4b; } DEBUG_JTAG_IO("finish %s", (type == SCAN_OUT) ? "without read" : "via PAUSE"); clock_tms(mpsse_cmd, tms_bits, tms_count, last_bit); } if (tap_get_state() != tap_get_end_state()) move_to_state(tap_get_end_state()); } static int ft2232_large_scan(struct scan_command *cmd, enum scan_type type, uint8_t *buffer, int scan_size) { int num_bytes = (scan_size + 7) / 8; int bits_left = scan_size; int cur_byte = 0; int last_bit; uint8_t *receive_buffer = malloc(DIV_ROUND_UP(scan_size, 8)); uint8_t *receive_pointer = receive_buffer; uint32_t bytes_written; uint32_t bytes_read; int retval; int thisrun_read = 0; if (!receive_buffer) { LOG_ERROR("failed to allocate memory"); exit(-1); } if (cmd->ir_scan) { LOG_ERROR("BUG: large IR scans are not supported"); exit(-1); } if (tap_get_state() != TAP_DRSHIFT) move_to_state(TAP_DRSHIFT); retval = ft2232_write(ft2232_buffer, ft2232_buffer_size, &bytes_written); if (retval != ERROR_OK) { LOG_ERROR("couldn't write MPSSE commands to FT2232"); exit(-1); } LOG_DEBUG("ft2232_buffer_size: %i, bytes_written: %i", ft2232_buffer_size, (int)bytes_written); ft2232_buffer_size = 0; /* add command for complete bytes */ while (num_bytes > 1) { int thisrun_bytes; if (type == SCAN_IO) { /* Clock Data Bytes In and Out LSB First */ buffer_write(0x39); /* LOG_DEBUG("added TDI bytes (io %i)", num_bytes); */ } else if (type == SCAN_OUT) { /* Clock Data Bytes Out on -ve Clock Edge LSB First (no Read) */ buffer_write(0x19); /* LOG_DEBUG("added TDI bytes (o)"); */ } else if (type == SCAN_IN) { /* Clock Data Bytes In on +ve Clock Edge LSB First (no Write) */ buffer_write(0x28); /* LOG_DEBUG("added TDI bytes (i %i)", num_bytes); */ } thisrun_bytes = (num_bytes > 65537) ? 65536 : (num_bytes - 1); thisrun_read = thisrun_bytes; num_bytes -= thisrun_bytes; buffer_write((uint8_t) (thisrun_bytes - 1)); buffer_write((uint8_t) ((thisrun_bytes - 1) >> 8)); if (type != SCAN_IN) { /* add complete bytes */ while (thisrun_bytes-- > 0) { buffer_write(buffer[cur_byte]); cur_byte++; bits_left -= 8; } } else /* (type == SCAN_IN) */ bits_left -= 8 * (thisrun_bytes); retval = ft2232_write(ft2232_buffer, ft2232_buffer_size, &bytes_written); if (retval != ERROR_OK) { LOG_ERROR("couldn't write MPSSE commands to FT2232"); exit(-1); } LOG_DEBUG("ft2232_buffer_size: %i, bytes_written: %i", ft2232_buffer_size, (int)bytes_written); ft2232_buffer_size = 0; if (type != SCAN_OUT) { retval = ft2232_read(receive_pointer, thisrun_read, &bytes_read); if (retval != ERROR_OK) { LOG_ERROR("couldn't read from FT2232"); exit(-1); } LOG_DEBUG("thisrun_read: %i, bytes_read: %i", thisrun_read, (int)bytes_read); receive_pointer += bytes_read; } } thisrun_read = 0; /* the most signifcant bit is scanned during TAP movement */ if (type != SCAN_IN) last_bit = (buffer[cur_byte] >> (bits_left - 1)) & 0x1; else last_bit = 0; /* process remaining bits but the last one */ if (bits_left > 1) { if (type == SCAN_IO) { /* Clock Data Bits In and Out LSB First */ buffer_write(0x3b); /* LOG_DEBUG("added TDI bits (io) %i", bits_left - 1); */ } else if (type == SCAN_OUT) { /* Clock Data Bits Out on -ve Clock Edge LSB First (no Read) */ buffer_write(0x1b); /* LOG_DEBUG("added TDI bits (o)"); */ } else if (type == SCAN_IN) { /* Clock Data Bits In on +ve Clock Edge LSB First (no Write) */ buffer_write(0x2a); /* LOG_DEBUG("added TDI bits (i %i)", bits_left - 1); */ } buffer_write(bits_left - 2); if (type != SCAN_IN) buffer_write(buffer[cur_byte]); if (type != SCAN_OUT) thisrun_read += 2; } if (tap_get_end_state() == TAP_DRSHIFT) { if (type == SCAN_IO) { /* Clock Data Bits In and Out LSB First */ buffer_write(0x3b); /* LOG_DEBUG("added TDI bits (io) %i", bits_left - 1); */ } else if (type == SCAN_OUT) { /* Clock Data Bits Out on -ve Clock Edge LSB First (no Read) */ buffer_write(0x1b); /* LOG_DEBUG("added TDI bits (o)"); */ } else if (type == SCAN_IN) { /* Clock Data Bits In on +ve Clock Edge LSB First (no Write) */ buffer_write(0x2a); /* LOG_DEBUG("added TDI bits (i %i)", bits_left - 1); */ } buffer_write(0x0); buffer_write(last_bit); } else { int tms_bits = tap_get_tms_path(tap_get_state(), tap_get_end_state()); int tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); uint8_t mpsse_cmd; /* move from Shift-IR/DR to end state */ if (type != SCAN_OUT) { /* Clock Data to TMS/CS Pin with Read */ mpsse_cmd = 0x6b; /* LOG_DEBUG("added TMS scan (read)"); */ } else { /* Clock Data to TMS/CS Pin (no Read) */ mpsse_cmd = 0x4b; /* LOG_DEBUG("added TMS scan (no read)"); */ } DEBUG_JTAG_IO("finish, %s", (type == SCAN_OUT) ? "no read" : "read"); clock_tms(mpsse_cmd, tms_bits, tms_count, last_bit); } if (type != SCAN_OUT) thisrun_read += 1; retval = ft2232_write(ft2232_buffer, ft2232_buffer_size, &bytes_written); if (retval != ERROR_OK) { LOG_ERROR("couldn't write MPSSE commands to FT2232"); exit(-1); } LOG_DEBUG("ft2232_buffer_size: %i, bytes_written: %i", ft2232_buffer_size, (int)bytes_written); ft2232_buffer_size = 0; if (type != SCAN_OUT) { retval = ft2232_read(receive_pointer, thisrun_read, &bytes_read); if (retval != ERROR_OK) { LOG_ERROR("couldn't read from FT2232"); exit(-1); } LOG_DEBUG("thisrun_read: %i, bytes_read: %i", thisrun_read, (int)bytes_read); } free(receive_buffer); return ERROR_OK; } static int ft2232_predict_scan_out(int scan_size, enum scan_type type) { int predicted_size = 3; int num_bytes = (scan_size - 1) / 8; if (tap_get_state() != TAP_DRSHIFT) predicted_size += get_tms_buffer_requirements( tap_get_tms_path_len(tap_get_state(), TAP_DRSHIFT)); if (type == SCAN_IN) { /* only from device to host */ /* complete bytes */ predicted_size += DIV_ROUND_UP(num_bytes, 65536) * 3; /* remaining bits - 1 (up to 7) */ predicted_size += ((scan_size - 1) % 8) ? 2 : 0; } else {/* host to device, or bidirectional * complete bytes */ predicted_size += num_bytes + DIV_ROUND_UP(num_bytes, 65536) * 3; /* remaining bits -1 (up to 7) */ predicted_size += ((scan_size - 1) % 8) ? 3 : 0; } return predicted_size; } static int ft2232_predict_scan_in(int scan_size, enum scan_type type) { int predicted_size = 0; if (type != SCAN_OUT) { /* complete bytes */ predicted_size += (DIV_ROUND_UP(scan_size, 8) > 1) ? (DIV_ROUND_UP(scan_size, 8) - 1) : 0; /* remaining bits - 1 */ predicted_size += ((scan_size - 1) % 8) ? 1 : 0; /* last bit (from TMS scan) */ predicted_size += 1; } /* LOG_DEBUG("scan_size: %i, predicted_size: %i", scan_size, predicted_size); */ return predicted_size; } /* semi-generic FT2232/FT4232 reset code */ static void ftx23_reset(int trst, int srst) { enum reset_types jtag_reset_config = jtag_get_reset_config(); if (trst == 1) { if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) low_direction |= nTRSTnOE; /* switch to output pin (output is low) */ else low_output &= ~nTRST; /* switch output low */ } else if (trst == 0) { if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) low_direction &= ~nTRSTnOE; /* switch to input pin (high-Z + internal *and external pullup) */ else low_output |= nTRST; /* switch output high */ } if (srst == 1) { if (jtag_reset_config & RESET_SRST_PUSH_PULL) low_output &= ~nSRST; /* switch output low */ else low_direction |= nSRSTnOE; /* switch to output pin (output is low) */ } else if (srst == 0) { if (jtag_reset_config & RESET_SRST_PUSH_PULL) low_output |= nSRST; /* switch output high */ else low_direction &= ~nSRSTnOE; /* switch to input pin (high-Z) */ } /* command "set data bits low byte" */ buffer_write(0x80); buffer_write(low_output); buffer_write(low_direction); } static void jtagkey_reset(int trst, int srst) { enum reset_types jtag_reset_config = jtag_get_reset_config(); if (trst == 1) { if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) high_output &= ~nTRSTnOE; else high_output &= ~nTRST; } else if (trst == 0) { if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) high_output |= nTRSTnOE; else high_output |= nTRST; } if (srst == 1) { if (jtag_reset_config & RESET_SRST_PUSH_PULL) high_output &= ~nSRST; else high_output &= ~nSRSTnOE; } else if (srst == 0) { if (jtag_reset_config & RESET_SRST_PUSH_PULL) high_output |= nSRST; else high_output |= nSRSTnOE; } /* command "set data bits high byte" */ buffer_write(0x82); buffer_write(high_output); buffer_write(high_direction); LOG_DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, high_direction); } static void olimex_jtag_reset(int trst, int srst) { enum reset_types jtag_reset_config = jtag_get_reset_config(); if (trst == 1) { if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) high_output &= ~nTRSTnOE; else high_output &= ~nTRST; } else if (trst == 0) { if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) high_output |= nTRSTnOE; else high_output |= nTRST; } if (srst == 1) high_output |= nSRST; else if (srst == 0) high_output &= ~nSRST; /* command "set data bits high byte" */ buffer_write(0x82); buffer_write(high_output); buffer_write(high_direction); LOG_DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, high_direction); } static void axm0432_jtag_reset(int trst, int srst) { if (trst == 1) { tap_set_state(TAP_RESET); high_output &= ~nTRST; } else if (trst == 0) high_output |= nTRST; if (srst == 1) high_output &= ~nSRST; else if (srst == 0) high_output |= nSRST; /* command "set data bits low byte" */ buffer_write(0x82); buffer_write(high_output); buffer_write(high_direction); LOG_DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, high_direction); } static void flyswatter_reset(int trst, int srst) { if (trst == 1) low_output &= ~nTRST; else if (trst == 0) low_output |= nTRST; if (srst == 1) low_output |= nSRST; else if (srst == 0) low_output &= ~nSRST; /* command "set data bits low byte" */ buffer_write(0x80); buffer_write(low_output); buffer_write(low_direction); LOG_DEBUG("trst: %i, srst: %i, low_output: 0x%2.2x, low_direction: 0x%2.2x", trst, srst, low_output, low_direction); } static void flyswatter1_reset(int trst, int srst) { flyswatter_reset(trst, srst); } static void flyswatter2_reset(int trst, int srst) { flyswatter_reset(trst, !srst); } static void minimodule_reset(int trst, int srst) { if (srst == 1) low_output &= ~nSRST; else if (srst == 0) low_output |= nSRST; /* command "set data bits low byte" */ buffer_write(0x80); buffer_write(low_output); buffer_write(low_direction); LOG_DEBUG("trst: %i, srst: %i, low_output: 0x%2.2x, low_direction: 0x%2.2x", trst, srst, low_output, low_direction); } static void turtle_reset(int trst, int srst) { trst = trst; if (srst == 1) low_output |= nSRST; else if (srst == 0) low_output &= ~nSRST; /* command "set data bits low byte" */ buffer_write(0x80); buffer_write(low_output); buffer_write(low_direction); LOG_DEBUG("srst: %i, low_output: 0x%2.2x, low_direction: 0x%2.2x", srst, low_output, low_direction); } static void comstick_reset(int trst, int srst) { if (trst == 1) high_output &= ~nTRST; else if (trst == 0) high_output |= nTRST; if (srst == 1) high_output &= ~nSRST; else if (srst == 0) high_output |= nSRST; /* command "set data bits high byte" */ buffer_write(0x82); buffer_write(high_output); buffer_write(high_direction); LOG_DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, high_direction); } static void stm32stick_reset(int trst, int srst) { if (trst == 1) high_output &= ~nTRST; else if (trst == 0) high_output |= nTRST; if (srst == 1) low_output &= ~nSRST; else if (srst == 0) low_output |= nSRST; /* command "set data bits low byte" */ buffer_write(0x80); buffer_write(low_output); buffer_write(low_direction); /* command "set data bits high byte" */ buffer_write(0x82); buffer_write(high_output); buffer_write(high_direction); LOG_DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, high_direction); } static void sheevaplug_reset(int trst, int srst) { if (trst == 1) high_output &= ~nTRST; else if (trst == 0) high_output |= nTRST; if (srst == 1) high_output &= ~nSRSTnOE; else if (srst == 0) high_output |= nSRSTnOE; /* command "set data bits high byte" */ buffer_write(0x82); buffer_write(high_output); buffer_write(high_direction); LOG_DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, high_direction); } static void redbee_reset(int trst, int srst) { if (trst == 1) { tap_set_state(TAP_RESET); high_output &= ~nTRST; } else if (trst == 0) high_output |= nTRST; if (srst == 1) high_output &= ~nSRST; else if (srst == 0) high_output |= nSRST; /* command "set data bits low byte" */ buffer_write(0x82); buffer_write(high_output); buffer_write(high_direction); LOG_DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, " "high_direction: 0x%2.2x", trst, srst, high_output, high_direction); } static void xds100v2_reset(int trst, int srst) { if (trst == 1) { tap_set_state(TAP_RESET); high_output &= ~nTRST; } else if (trst == 0) high_output |= nTRST; if (srst == 1) high_output |= nSRST; else if (srst == 0) high_output &= ~nSRST; /* command "set data bits low byte" */ buffer_write(0x82); buffer_write(high_output); buffer_write(high_direction); LOG_DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, " "high_direction: 0x%2.2x", trst, srst, high_output, high_direction); } static int ft2232_execute_runtest(struct jtag_command *cmd) { int retval; int i; int predicted_size = 0; retval = ERROR_OK; DEBUG_JTAG_IO("runtest %i cycles, end in %s", cmd->cmd.runtest->num_cycles, tap_state_name(cmd->cmd.runtest->end_state)); /* only send the maximum buffer size that FT2232C can handle */ predicted_size = 0; if (tap_get_state() != TAP_IDLE) predicted_size += 3; predicted_size += 3 * DIV_ROUND_UP(cmd->cmd.runtest->num_cycles, 7); if (cmd->cmd.runtest->end_state != TAP_IDLE) predicted_size += 3; if (tap_get_end_state() != TAP_IDLE) predicted_size += 3; if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE) { if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) retval = ERROR_JTAG_QUEUE_FAILED; require_send = 0; first_unsent = cmd; } if (tap_get_state() != TAP_IDLE) { move_to_state(TAP_IDLE); require_send = 1; } i = cmd->cmd.runtest->num_cycles; while (i > 0) { /* there are no state transitions in this code, so omit state tracking */ /* command "Clock Data to TMS/CS Pin (no Read)" */ buffer_write(0x4b); /* scan 7 bits */ buffer_write((i > 7) ? 6 : (i - 1)); /* TMS data bits */ buffer_write(0x0); i -= (i > 7) ? 7 : i; /* LOG_DEBUG("added TMS scan (no read)"); */ } ft2232_end_state(cmd->cmd.runtest->end_state); if (tap_get_state() != tap_get_end_state()) move_to_state(tap_get_end_state()); require_send = 1; DEBUG_JTAG_IO("runtest: %i, end in %s", cmd->cmd.runtest->num_cycles, tap_state_name(tap_get_end_state())); return retval; } static int ft2232_execute_statemove(struct jtag_command *cmd) { int predicted_size = 0; int retval = ERROR_OK; DEBUG_JTAG_IO("statemove end in %s", tap_state_name(cmd->cmd.statemove->end_state)); /* only send the maximum buffer size that FT2232C can handle */ predicted_size = 3; if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE) { if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) retval = ERROR_JTAG_QUEUE_FAILED; require_send = 0; first_unsent = cmd; } ft2232_end_state(cmd->cmd.statemove->end_state); /* For TAP_RESET, ignore the current recorded state. It's often * wrong at server startup, and this transation is critical whenever * it's requested. */ if (tap_get_end_state() == TAP_RESET) { clock_tms(0x4b, 0xff, 5, 0); require_send = 1; /* shortest-path move to desired end state */ } else if (tap_get_state() != tap_get_end_state()) { move_to_state(tap_get_end_state()); require_send = 1; } return retval; } /** * Clock a bunch of TMS (or SWDIO) transitions, to change the JTAG * (or SWD) state machine. */ static int ft2232_execute_tms(struct jtag_command *cmd) { int retval = ERROR_OK; unsigned num_bits = cmd->cmd.tms->num_bits; const uint8_t *bits = cmd->cmd.tms->bits; unsigned count; DEBUG_JTAG_IO("TMS: %d bits", num_bits); /* only send the maximum buffer size that FT2232C can handle */ count = 3 * DIV_ROUND_UP(num_bits, 4); if (ft2232_buffer_size + 3*count + 1 > FT2232_BUFFER_SIZE) { if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) retval = ERROR_JTAG_QUEUE_FAILED; require_send = 0; first_unsent = cmd; } /* Shift out in batches of at most 6 bits; there's a report of an * FT2232 bug in this area, where shifting exactly 7 bits can make * problems with TMS signaling for the last clock cycle: * * http://developer.intra2net.com/mailarchive/html/ * libftdi/2009/msg00292.html * * Command 0x4b is: "Clock Data to TMS/CS Pin (no Read)" * * Note that pathmoves in JTAG are not often seven bits, so that * isn't a particularly likely situation outside of "special" * signaling such as switching between JTAG and SWD modes. */ while (num_bits) { if (num_bits <= 6) { buffer_write(0x4b); buffer_write(num_bits - 1); buffer_write(*bits & 0x3f); break; } /* Yes, this is lazy ... we COULD shift out more data * bits per operation, but doing it in nybbles is easy */ buffer_write(0x4b); buffer_write(3); buffer_write(*bits & 0xf); num_bits -= 4; count = (num_bits > 4) ? 4 : num_bits; buffer_write(0x4b); buffer_write(count - 1); buffer_write((*bits >> 4) & 0xf); num_bits -= count; bits++; } require_send = 1; return retval; } static int ft2232_execute_pathmove(struct jtag_command *cmd) { int predicted_size = 0; int retval = ERROR_OK; tap_state_t *path = cmd->cmd.pathmove->path; int num_states = cmd->cmd.pathmove->num_states; DEBUG_JTAG_IO("pathmove: %i states, current: %s end: %s", num_states, tap_state_name(tap_get_state()), tap_state_name(path[num_states-1])); /* only send the maximum buffer size that FT2232C can handle */ predicted_size = 3 * DIV_ROUND_UP(num_states, 7); if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE) { if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) retval = ERROR_JTAG_QUEUE_FAILED; require_send = 0; first_unsent = cmd; } ft2232_add_pathmove(path, num_states); require_send = 1; return retval; } static int ft2232_execute_scan(struct jtag_command *cmd) { uint8_t *buffer; int scan_size; /* size of IR or DR scan */ int predicted_size = 0; int retval = ERROR_OK; enum scan_type type = jtag_scan_type(cmd->cmd.scan); DEBUG_JTAG_IO("%s type:%d", cmd->cmd.scan->ir_scan ? "IRSCAN" : "DRSCAN", type); scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); predicted_size = ft2232_predict_scan_out(scan_size, type); if ((predicted_size + 1) > FT2232_BUFFER_SIZE) { LOG_DEBUG("oversized ft2232 scan (predicted_size > FT2232_BUFFER_SIZE)"); /* unsent commands before this */ if (first_unsent != cmd) if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) retval = ERROR_JTAG_QUEUE_FAILED; /* current command */ ft2232_end_state(cmd->cmd.scan->end_state); ft2232_large_scan(cmd->cmd.scan, type, buffer, scan_size); require_send = 0; first_unsent = cmd->next; if (buffer) free(buffer); return retval; } else if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE) { LOG_DEBUG( "ft2232 buffer size reached, sending queued commands (first_unsent: %p, cmd: %p)", first_unsent, cmd); if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) retval = ERROR_JTAG_QUEUE_FAILED; require_send = 0; first_unsent = cmd; } ft2232_expect_read += ft2232_predict_scan_in(scan_size, type); /* LOG_DEBUG("new read size: %i", ft2232_expect_read); */ ft2232_end_state(cmd->cmd.scan->end_state); ft2232_add_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size); require_send = 1; if (buffer) free(buffer); DEBUG_JTAG_IO("%s scan, %i bits, end in %s", (cmd->cmd.scan->ir_scan) ? "IR" : "DR", scan_size, tap_state_name(tap_get_end_state())); return retval; } static int ft2232_execute_reset(struct jtag_command *cmd) { int retval; int predicted_size = 0; retval = ERROR_OK; DEBUG_JTAG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); /* only send the maximum buffer size that FT2232C can handle */ predicted_size = 3; if (ft2232_buffer_size + predicted_size + 1 > FT2232_BUFFER_SIZE) { if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) retval = ERROR_JTAG_QUEUE_FAILED; require_send = 0; first_unsent = cmd; } if ((cmd->cmd.reset->trst == 1) || (cmd->cmd.reset->srst && (jtag_get_reset_config() & RESET_SRST_PULLS_TRST))) tap_set_state(TAP_RESET); layout->reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); require_send = 1; DEBUG_JTAG_IO("trst: %i, srst: %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); return retval; } static int ft2232_execute_sleep(struct jtag_command *cmd) { int retval; retval = ERROR_OK; DEBUG_JTAG_IO("sleep %" PRIi32, cmd->cmd.sleep->us); if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) retval = ERROR_JTAG_QUEUE_FAILED; first_unsent = cmd->next; jtag_sleep(cmd->cmd.sleep->us); DEBUG_JTAG_IO("sleep %" PRIi32 " usec while in %s", cmd->cmd.sleep->us, tap_state_name(tap_get_state())); return retval; } static int ft2232_execute_stableclocks(struct jtag_command *cmd) { int retval; retval = ERROR_OK; /* this is only allowed while in a stable state. A check for a stable * state was done in jtag_add_clocks() */ if (ft2232_stableclocks(cmd->cmd.stableclocks->num_cycles, cmd) != ERROR_OK) retval = ERROR_JTAG_QUEUE_FAILED; DEBUG_JTAG_IO("clocks %i while in %s", cmd->cmd.stableclocks->num_cycles, tap_state_name(tap_get_state())); return retval; } static int ft2232_execute_command(struct jtag_command *cmd) { int retval; switch (cmd->type) { case JTAG_RESET: retval = ft2232_execute_reset(cmd); break; case JTAG_RUNTEST: retval = ft2232_execute_runtest(cmd); break; case JTAG_TLR_RESET: retval = ft2232_execute_statemove(cmd); break; case JTAG_PATHMOVE: retval = ft2232_execute_pathmove(cmd); break; case JTAG_SCAN: retval = ft2232_execute_scan(cmd); break; case JTAG_SLEEP: retval = ft2232_execute_sleep(cmd); break; case JTAG_STABLECLOCKS: retval = ft2232_execute_stableclocks(cmd); break; case JTAG_TMS: retval = ft2232_execute_tms(cmd); break; default: LOG_ERROR("BUG: unknown JTAG command type encountered"); retval = ERROR_JTAG_QUEUE_FAILED; break; } return retval; } static int ft2232_execute_queue(void) { struct jtag_command *cmd = jtag_command_queue; /* currently processed command */ int retval; first_unsent = cmd; /* next command that has to be sent */ require_send = 0; /* return ERROR_OK, unless ft2232_send_and_recv reports a failed check * that wasn't handled by a caller-provided error handler */ retval = ERROR_OK; ft2232_buffer_size = 0; ft2232_expect_read = 0; /* blink, if the current layout has that feature */ if (layout->blink) layout->blink(); while (cmd) { /* fill the write buffer with the desired command */ if (ft2232_execute_command(cmd) != ERROR_OK) retval = ERROR_JTAG_QUEUE_FAILED; /* Start reading input before FT2232 TX buffer fills up. * Sometimes this happens because we don't know the * length of the last command before we execute it. So * we simple inform the user. */ cmd = cmd->next; if (ft2232_expect_read >= FT2232_BUFFER_READ_QUEUE_SIZE) { if (ft2232_expect_read > (FT2232_BUFFER_READ_QUEUE_SIZE+1)) LOG_DEBUG("read buffer size looks too high %d/%d", ft2232_expect_read, (FT2232_BUFFER_READ_QUEUE_SIZE+1)); if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) retval = ERROR_JTAG_QUEUE_FAILED; first_unsent = cmd; } } if (require_send > 0) if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) retval = ERROR_JTAG_QUEUE_FAILED; return retval; } #if BUILD_FT2232_FTD2XX == 1 static int ft2232_init_ftd2xx(uint16_t vid, uint16_t pid, int more, int *try_more) { FT_STATUS status; DWORD deviceID; char SerialNumber[16]; char Description[64]; DWORD openex_flags = 0; char *openex_string = NULL; uint8_t latency_timer; if (layout == NULL) { LOG_WARNING("No ft2232 layout specified'"); return ERROR_JTAG_INIT_FAILED; } LOG_DEBUG("'ft2232' interface using FTD2XX with '%s' layout (%4.4x:%4.4x)", layout->name, vid, pid); #if IS_WIN32 == 0 /* Add non-standard Vid/Pid to the linux driver */ status = FT_SetVIDPID(vid, pid); if (status != FT_OK) LOG_WARNING("couldn't add %4.4x:%4.4x", vid, pid); #endif if (ft2232_device_desc && ft2232_serial) { LOG_WARNING( "can't open by device description and serial number, giving precedence to serial"); ft2232_device_desc = NULL; } if (ft2232_device_desc) { openex_string = ft2232_device_desc; openex_flags = FT_OPEN_BY_DESCRIPTION; } else if (ft2232_serial) { openex_string = ft2232_serial; openex_flags = FT_OPEN_BY_SERIAL_NUMBER; } else { LOG_ERROR("neither device description nor serial number specified"); LOG_ERROR( "please add \"ft2232_device_desc \" or \"ft2232_serial \" to your .cfg file"); return ERROR_JTAG_INIT_FAILED; } status = FT_OpenEx(openex_string, openex_flags, &ftdih); if (status != FT_OK) { /* under Win32, the FTD2XX driver appends an "A" to the end * of the description, if we tried by the desc, then * try by the alternate "A" description. */ if (openex_string == ft2232_device_desc) { /* Try the alternate method. */ openex_string = ft2232_device_desc_A; status = FT_OpenEx(openex_string, openex_flags, &ftdih); if (status == FT_OK) { /* yea, the "alternate" method worked! */ } else { /* drat, give the user a meaningfull message. * telling the use we tried *BOTH* methods. */ LOG_WARNING("Unable to open FTDI Device tried: '%s' and '%s'", ft2232_device_desc, ft2232_device_desc_A); } } } if (status != FT_OK) { DWORD num_devices; if (more) { LOG_WARNING("unable to open ftdi device (trying more): %s", ftd2xx_status_string(status)); *try_more = 1; return ERROR_JTAG_INIT_FAILED; } LOG_ERROR("unable to open ftdi device: %s", ftd2xx_status_string(status)); status = FT_ListDevices(&num_devices, NULL, FT_LIST_NUMBER_ONLY); if (status == FT_OK) { char **desc_array = malloc(sizeof(char *) * (num_devices + 1)); uint32_t i; for (i = 0; i < num_devices; i++) desc_array[i] = malloc(64); desc_array[num_devices] = NULL; status = FT_ListDevices(desc_array, &num_devices, FT_LIST_ALL | openex_flags); if (status == FT_OK) { LOG_ERROR("ListDevices: %" PRIu32, (uint32_t)num_devices); for (i = 0; i < num_devices; i++) LOG_ERROR("%" PRIu32 ": \"%s\"", i, desc_array[i]); } for (i = 0; i < num_devices; i++) free(desc_array[i]); free(desc_array); } else LOG_ERROR("ListDevices: NONE"); return ERROR_JTAG_INIT_FAILED; } status = FT_SetLatencyTimer(ftdih, ft2232_latency); if (status != FT_OK) { LOG_ERROR("unable to set latency timer: %s", ftd2xx_status_string(status)); return ERROR_JTAG_INIT_FAILED; } status = FT_GetLatencyTimer(ftdih, &latency_timer); if (status != FT_OK) { /* ftd2xx 1.04 (linux) has a bug when calling FT_GetLatencyTimer * so ignore errors if using this driver version */ DWORD dw_version; status = FT_GetDriverVersion(ftdih, &dw_version); LOG_ERROR("unable to get latency timer: %s", ftd2xx_status_string(status)); if ((status == FT_OK) && (dw_version == 0x10004)) { LOG_ERROR("ftd2xx 1.04 detected - this has known issues " \ "with FT_GetLatencyTimer, upgrade to a newer version"); } else return ERROR_JTAG_INIT_FAILED; } else LOG_DEBUG("current latency timer: %i", latency_timer); status = FT_SetTimeouts(ftdih, 5000, 5000); if (status != FT_OK) { LOG_ERROR("unable to set timeouts: %s", ftd2xx_status_string(status)); return ERROR_JTAG_INIT_FAILED; } status = FT_SetBitMode(ftdih, 0x0b, 2); if (status != FT_OK) { LOG_ERROR("unable to enable bit i/o mode: %s", ftd2xx_status_string(status)); return ERROR_JTAG_INIT_FAILED; } status = FT_GetDeviceInfo(ftdih, &ftdi_device, &deviceID, SerialNumber, Description, NULL); if (status != FT_OK) { LOG_ERROR("unable to get FT_GetDeviceInfo: %s", ftd2xx_status_string(status)); return ERROR_JTAG_INIT_FAILED; } else { static const char *type_str[] = { "BM", "AM", "100AX", "UNKNOWN", "2232C", "232R", "2232H", "4232H", "232H" }; unsigned no_of_known_types = ARRAY_SIZE(type_str) - 1; unsigned type_index = ((unsigned)ftdi_device <= no_of_known_types) ? ftdi_device : FT_DEVICE_UNKNOWN; LOG_INFO("device: %" PRIu32 " \"%s\"", (uint32_t)ftdi_device, type_str[type_index]); LOG_INFO("deviceID: %" PRIu32, (uint32_t)deviceID); LOG_INFO("SerialNumber: %s", SerialNumber); LOG_INFO("Description: %s", Description); } return ERROR_OK; } static int ft2232_purge_ftd2xx(void) { FT_STATUS status; status = FT_Purge(ftdih, FT_PURGE_RX | FT_PURGE_TX); if (status != FT_OK) { LOG_ERROR("error purging ftd2xx device: %s", ftd2xx_status_string(status)); return ERROR_JTAG_INIT_FAILED; } return ERROR_OK; } #endif /* BUILD_FT2232_FTD2XX == 1 */ #if BUILD_FT2232_LIBFTDI == 1 static int ft2232_init_libftdi(uint16_t vid, uint16_t pid, int more, int *try_more, int channel) { uint8_t latency_timer; if (layout == NULL) { LOG_WARNING("No ft2232 layout specified'"); return ERROR_JTAG_INIT_FAILED; } LOG_DEBUG("'ft2232' interface using libftdi with '%s' layout (%4.4x:%4.4x)", layout->name, vid, pid); if (ftdi_init(&ftdic) < 0) return ERROR_JTAG_INIT_FAILED; /* default to INTERFACE_A */ if (channel == INTERFACE_ANY) channel = INTERFACE_A; if (ftdi_set_interface(&ftdic, channel) < 0) { LOG_ERROR("unable to select FT2232 channel A: %s", ftdic.error_str); return ERROR_JTAG_INIT_FAILED; } /* context, vendor id, product id */ if (ftdi_usb_open_desc(&ftdic, vid, pid, ft2232_device_desc, ft2232_serial) < 0) { if (more) LOG_WARNING("unable to open ftdi device (trying more): %s", ftdic.error_str); else LOG_ERROR("unable to open ftdi device: %s", ftdic.error_str); *try_more = 1; return ERROR_JTAG_INIT_FAILED; } /* There is already a reset in ftdi_usb_open_desc, this should be redundant */ if (ftdi_usb_reset(&ftdic) < 0) { LOG_ERROR("unable to reset ftdi device"); return ERROR_JTAG_INIT_FAILED; } if (ftdi_set_latency_timer(&ftdic, ft2232_latency) < 0) { LOG_ERROR("unable to set latency timer"); return ERROR_JTAG_INIT_FAILED; } if (ftdi_get_latency_timer(&ftdic, &latency_timer) < 0) { LOG_ERROR("unable to get latency timer"); return ERROR_JTAG_INIT_FAILED; } else LOG_DEBUG("current latency timer: %i", latency_timer); ftdi_set_bitmode(&ftdic, 0x0b, 2); /* ctx, JTAG I/O mask */ ftdi_device = ftdic.type; static const char *type_str[] = { "AM", "BM", "2232C", "R", "2232H", "4232H", "232H", "Unknown" }; unsigned no_of_known_types = ARRAY_SIZE(type_str) - 1; unsigned type_index = ((unsigned)ftdi_device < no_of_known_types) ? ftdi_device : no_of_known_types; LOG_DEBUG("FTDI chip type: %i \"%s\"", (int)ftdi_device, type_str[type_index]); return ERROR_OK; } static int ft2232_purge_libftdi(void) { if (ftdi_usb_purge_buffers(&ftdic) < 0) { LOG_ERROR("ftdi_purge_buffers: %s", ftdic.error_str); return ERROR_JTAG_INIT_FAILED; } return ERROR_OK; } #endif /* BUILD_FT2232_LIBFTDI == 1 */ static int ft2232_set_data_bits_low_byte(uint8_t value, uint8_t direction) { uint8_t buf[3]; uint32_t bytes_written; buf[0] = 0x80; /* command "set data bits low byte" */ buf[1] = value; /* value */ buf[2] = direction; /* direction */ LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); if (ft2232_write(buf, sizeof(buf), &bytes_written) != ERROR_OK) { LOG_ERROR("couldn't initialize data bits low byte"); return ERROR_JTAG_INIT_FAILED; } return ERROR_OK; } static int ft2232_set_data_bits_high_byte(uint8_t value, uint8_t direction) { uint8_t buf[3]; uint32_t bytes_written; buf[0] = 0x82; /* command "set data bits high byte" */ buf[1] = value; /* value */ buf[2] = direction; /* direction */ LOG_DEBUG("%2.2x %2.2x %2.2x", buf[0], buf[1], buf[2]); if (ft2232_write(buf, sizeof(buf), &bytes_written) != ERROR_OK) { LOG_ERROR("couldn't initialize data bits high byte"); return ERROR_JTAG_INIT_FAILED; } return ERROR_OK; } static int ft2232_init(void) { uint8_t buf[1]; int retval; uint32_t bytes_written; if (tap_get_tms_path_len(TAP_IRPAUSE, TAP_IRPAUSE) == 7) LOG_DEBUG("ft2232 interface using 7 step jtag state transitions"); else LOG_DEBUG("ft2232 interface using shortest path jtag state transitions"); if (layout == NULL) { LOG_WARNING("No ft2232 layout specified'"); return ERROR_JTAG_INIT_FAILED; } for (int i = 0; 1; i++) { /* * "more indicates that there are more IDs to try, so we should * not print an error for an ID mismatch (but for anything * else, we should). * * try_more indicates that the error code returned indicates an * ID mismatch (and nothing else) and that we should proceeed * with the next ID pair. */ int more = ft2232_vid[i + 1] || ft2232_pid[i + 1]; int try_more = 0; #if BUILD_FT2232_FTD2XX == 1 retval = ft2232_init_ftd2xx(ft2232_vid[i], ft2232_pid[i], more, &try_more); #elif BUILD_FT2232_LIBFTDI == 1 retval = ft2232_init_libftdi(ft2232_vid[i], ft2232_pid[i], more, &try_more, ft2232_channel); #endif if (retval >= 0) break; if (!more || !try_more) return retval; } ft2232_buffer_size = 0; ft2232_buffer = malloc(FT2232_BUFFER_SIZE); if (layout->init() != ERROR_OK) return ERROR_JTAG_INIT_FAILED; if (ft2232_device_is_highspeed()) { #ifndef BUILD_FT2232_HIGHSPEED #if BUILD_FT2232_FTD2XX == 1 LOG_WARNING( "High Speed device found - You need a newer FTD2XX driver (version 2.04.16 or later)"); #elif BUILD_FT2232_LIBFTDI == 1 LOG_WARNING( "High Speed device found - You need a newer libftdi version (0.16 or later)"); #endif #endif /* make sure the legacy mode is disabled */ if (ftx232h_clk_divide_by_5(false) != ERROR_OK) return ERROR_JTAG_INIT_FAILED; } buf[0] = 0x85; /* Disconnect TDI/DO to TDO/DI for Loopback */ retval = ft2232_write(buf, 1, &bytes_written); if (retval != ERROR_OK) { LOG_ERROR("couldn't write to FT2232 to disable loopback"); return ERROR_JTAG_INIT_FAILED; } #if BUILD_FT2232_FTD2XX == 1 return ft2232_purge_ftd2xx(); #elif BUILD_FT2232_LIBFTDI == 1 return ft2232_purge_libftdi(); #endif return ERROR_OK; } /** Updates defaults for DBUS signals: the four JTAG signals * (TCK, TDI, TDO, TMS) and * the four GPIOL signals. */ static inline void ftx232_dbus_init(void) { low_output = 0x08; low_direction = 0x0b; } /** Initializes DBUS signals: the four JTAG signals (TCK, TDI, TDO, TMS), * the four GPIOL signals. Initialization covers value and direction, * as customized for each layout. */ static int ftx232_dbus_write(void) { enum reset_types jtag_reset_config = jtag_get_reset_config(); if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) { low_direction &= ~nTRSTnOE; /* nTRST input */ low_output &= ~nTRST; /* nTRST = 0 */ } else { low_direction |= nTRSTnOE; /* nTRST output */ low_output |= nTRST; /* nTRST = 1 */ } if (jtag_reset_config & RESET_SRST_PUSH_PULL) { low_direction |= nSRSTnOE; /* nSRST output */ low_output |= nSRST; /* nSRST = 1 */ } else { low_direction &= ~nSRSTnOE; /* nSRST input */ low_output &= ~nSRST; /* nSRST = 0 */ } /* initialize low byte for jtag */ if (ft2232_set_data_bits_low_byte(low_output, low_direction) != ERROR_OK) { LOG_ERROR("couldn't initialize FT2232 DBUS"); return ERROR_JTAG_INIT_FAILED; } return ERROR_OK; } static int usbjtag_init(void) { /* * NOTE: This is now _specific_ to the "usbjtag" layout. * Don't try cram any more layouts into this. */ ftx232_dbus_init(); nTRST = 0x10; nTRSTnOE = 0x10; nSRST = 0x40; nSRSTnOE = 0x40; return ftx232_dbus_write(); } static int lm3s811_jtag_init(void) { ftx232_dbus_init(); /* There are multiple revisions of LM3S811 eval boards: * - Rev B (and older?) boards have no SWO trace support. * - Rev C boards add ADBUS_6 DBG_ENn and BDBUS_4 SWO_EN; * they should use the "luminary_icdi" layout instead. */ nTRST = 0x0; nTRSTnOE = 0x00; nSRST = 0x20; nSRSTnOE = 0x20; low_output = 0x88; low_direction = 0x8b; return ftx232_dbus_write(); } static int icdi_jtag_init(void) { ftx232_dbus_init(); /* Most Luminary eval boards support SWO trace output, * and should use this "luminary_icdi" layout. * * ADBUS 0..3 are used for JTAG as usual. GPIOs are used * to switch between JTAG and SWD, or switch the ft2232 UART * on the second MPSSE channel/interface (BDBUS) * between (i) the stellaris UART (on Luminary boards) * or (ii) SWO trace data (generic). * * We come up in JTAG mode and may switch to SWD later (with * SWO/trace option if SWD is active). * * DBUS == GPIO-Lx * CBUS == GPIO-Hx */ #define ICDI_JTAG_EN (1 << 7) /* ADBUS 7 (a.k.a. DBGMOD) */ #define ICDI_DBG_ENn (1 << 6) /* ADBUS 6 */ #define ICDI_SRST (1 << 5) /* ADBUS 5 */ /* GPIOs on second channel/interface (UART) ... */ #define ICDI_SWO_EN (1 << 4) /* BDBUS 4 */ #define ICDI_TX_SWO (1 << 1) /* BDBUS 1 */ #define ICDI_VCP_RX (1 << 0) /* BDBUS 0 (to stellaris UART) */ nTRST = 0x0; nTRSTnOE = 0x00; nSRST = ICDI_SRST; nSRSTnOE = ICDI_SRST; low_direction |= ICDI_JTAG_EN | ICDI_DBG_ENn; low_output |= ICDI_JTAG_EN; low_output &= ~ICDI_DBG_ENn; return ftx232_dbus_write(); } static int signalyzer_init(void) { ftx232_dbus_init(); nTRST = 0x10; nTRSTnOE = 0x10; nSRST = 0x20; nSRSTnOE = 0x20; return ftx232_dbus_write(); } static int axm0432_jtag_init(void) { low_output = 0x08; low_direction = 0x2b; /* initialize low byte for jtag */ if (ft2232_set_data_bits_low_byte(low_output, low_direction) != ERROR_OK) { LOG_ERROR("couldn't initialize FT2232 with 'JTAGkey' layout"); return ERROR_JTAG_INIT_FAILED; } if (strcmp(layout->name, "axm0432_jtag") == 0) { nTRST = 0x08; nTRSTnOE = 0x0; /* No output enable for TRST*/ nSRST = 0x04; nSRSTnOE = 0x0; /* No output enable for SRST*/ } else { LOG_ERROR("BUG: axm0432_jtag_init called for non axm0432 layout"); exit(-1); } high_output = 0x0; high_direction = 0x0c; enum reset_types jtag_reset_config = jtag_get_reset_config(); if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) LOG_ERROR("can't set nTRSTOE to push-pull on the Dicarlo jtag"); else high_output |= nTRST; if (jtag_reset_config & RESET_SRST_PUSH_PULL) LOG_ERROR("can't set nSRST to push-pull on the Dicarlo jtag"); else high_output |= nSRST; /* initialize high byte for jtag */ if (ft2232_set_data_bits_high_byte(high_output, high_direction) != ERROR_OK) { LOG_ERROR("couldn't initialize FT2232 with 'Dicarlo' layout"); return ERROR_JTAG_INIT_FAILED; } return ERROR_OK; } static int redbee_init(void) { low_output = 0x08; low_direction = 0x2b; /* initialize low byte for jtag */ if (ft2232_set_data_bits_low_byte(low_output, low_direction) != ERROR_OK) { LOG_ERROR("couldn't initialize FT2232 with 'redbee' layout"); return ERROR_JTAG_INIT_FAILED; } nTRST = 0x08; nTRSTnOE = 0x0; /* No output enable for TRST*/ nSRST = 0x04; nSRSTnOE = 0x0; /* No output enable for SRST*/ high_output = 0x0; high_direction = 0x0c; enum reset_types jtag_reset_config = jtag_get_reset_config(); if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) LOG_ERROR("can't set nTRSTOE to push-pull on redbee"); else high_output |= nTRST; if (jtag_reset_config & RESET_SRST_PUSH_PULL) LOG_ERROR("can't set nSRST to push-pull on redbee"); else high_output |= nSRST; /* initialize high byte for jtag */ if (ft2232_set_data_bits_high_byte(high_output, high_direction) != ERROR_OK) { LOG_ERROR("couldn't initialize FT2232 with 'redbee' layout"); return ERROR_JTAG_INIT_FAILED; } return ERROR_OK; } static int jtagkey_init(void) { low_output = 0x08; low_direction = 0x1b; /* initialize low byte for jtag */ if (ft2232_set_data_bits_low_byte(low_output, low_direction) != ERROR_OK) { LOG_ERROR("couldn't initialize FT2232 with 'JTAGkey' layout"); return ERROR_JTAG_INIT_FAILED; } if (strcmp(layout->name, "jtagkey") == 0) { nTRST = 0x01; nTRSTnOE = 0x4; nSRST = 0x02; nSRSTnOE = 0x08; } else if ((strcmp(layout->name, "jtagkey_prototype_v1") == 0) || (strcmp(layout->name, "oocdlink") == 0)) { nTRST = 0x02; nTRSTnOE = 0x1; nSRST = 0x08; nSRSTnOE = 0x04; } else { LOG_ERROR("BUG: jtagkey_init called for non jtagkey layout"); exit(-1); } high_output = 0x0; high_direction = 0x0f; enum reset_types jtag_reset_config = jtag_get_reset_config(); if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) { high_output |= nTRSTnOE; high_output &= ~nTRST; } else { high_output &= ~nTRSTnOE; high_output |= nTRST; } if (jtag_reset_config & RESET_SRST_PUSH_PULL) { high_output &= ~nSRSTnOE; high_output |= nSRST; } else { high_output |= nSRSTnOE; high_output &= ~nSRST; } /* initialize high byte for jtag */ if (ft2232_set_data_bits_high_byte(high_output, high_direction) != ERROR_OK) { LOG_ERROR("couldn't initialize FT2232 with 'JTAGkey' layout"); return ERROR_JTAG_INIT_FAILED; } return ERROR_OK; } static int olimex_jtag_init(void) { low_output = 0x08; low_direction = 0x1b; /* initialize low byte for jtag */ if (ft2232_set_data_bits_low_byte(low_output, low_direction) != ERROR_OK) { LOG_ERROR("couldn't initialize FT2232 with 'Olimex' layout"); return ERROR_JTAG_INIT_FAILED; } nTRST = 0x01; nTRSTnOE = 0x4; nSRST = 0x02; nSRSTnOE = 0x00;/* no output enable for nSRST */ high_output = 0x0; high_direction = 0x0f; enum reset_types jtag_reset_config = jtag_get_reset_config(); if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) { high_output |= nTRSTnOE; high_output &= ~nTRST; } else { high_output &= ~nTRSTnOE; high_output |= nTRST; } if (jtag_reset_config & RESET_SRST_PUSH_PULL) LOG_ERROR("can't set nSRST to push-pull on the Olimex ARM-USB-OCD"); else high_output &= ~nSRST; /* turn red LED on */ high_output |= 0x08; /* initialize high byte for jtag */ if (ft2232_set_data_bits_high_byte(high_output, high_direction) != ERROR_OK) { LOG_ERROR("couldn't initialize FT2232 with 'Olimex' layout"); return ERROR_JTAG_INIT_FAILED; } return ERROR_OK; } static int flyswatter_init(int rev) { low_output = 0x18; low_direction = 0x7b; if ((rev < 0) || (rev > 3)) { LOG_ERROR("bogus 'flyswatter' revision supplied (%i)", rev); return ERROR_JTAG_INIT_FAILED; } if (rev == 1) low_direction |= 1 << 7; /* initialize low byte for jtag */ if (ft2232_set_data_bits_low_byte(low_output, low_direction) != ERROR_OK) { LOG_ERROR("couldn't initialize FT2232 with 'flyswatter' layout"); return ERROR_JTAG_INIT_FAILED; } nTRST = 0x10; nTRSTnOE = 0x0; /* not output enable for nTRST */ nSRST = 0x20; nSRSTnOE = 0x00; /* no output enable for nSRST */ high_output = 0x00; if (rev == 1) high_direction = 0x0c; else high_direction = 0x01; /* turn red LED3 on, LED2 off */ high_output |= 0x08; /* initialize high byte for jtag */ if (ft2232_set_data_bits_high_byte(high_output, high_direction) != ERROR_OK) { LOG_ERROR("couldn't initialize FT2232 with 'flyswatter' layout"); return ERROR_JTAG_INIT_FAILED; } return ERROR_OK; } static int flyswatter1_init(void) { return flyswatter_init(1); } static int flyswatter2_init(void) { return flyswatter_init(2); } static int minimodule_init(void) { low_output = 0x18; /* check if srst should be 1 or 0 initially. (0x08) (flyswatter was * 0x18) */ low_direction = 0xfb; /* 0xfb; */ /* initialize low byte for jtag */ if (ft2232_set_data_bits_low_byte(low_output, low_direction) != ERROR_OK) { LOG_ERROR("couldn't initialize FT2232 with 'minimodule' layout"); return ERROR_JTAG_INIT_FAILED; } nSRST = 0x20; high_output = 0x00; high_direction = 0x05; /* turn red LED3 on, LED2 off */ /* high_output |= 0x08; */ /* initialize high byte for jtag */ if (ft2232_set_data_bits_high_byte(high_output, high_direction) != ERROR_OK) { LOG_ERROR("couldn't initialize FT2232 with 'minimodule' layout"); return ERROR_JTAG_INIT_FAILED; } return ERROR_OK; } static int turtle_init(void) { low_output = 0x08; low_direction = 0x5b; /* initialize low byte for jtag */ if (ft2232_set_data_bits_low_byte(low_output, low_direction) != ERROR_OK) { LOG_ERROR("couldn't initialize FT2232 with 'turtelizer2' layout"); return ERROR_JTAG_INIT_FAILED; } nSRST = 0x40; high_output = 0x00; high_direction = 0x0C; /* initialize high byte for jtag */ if (ft2232_set_data_bits_high_byte(high_output, high_direction) != ERROR_OK) { LOG_ERROR("couldn't initialize FT2232 with 'turtelizer2' layout"); return ERROR_JTAG_INIT_FAILED; } return ERROR_OK; } static int comstick_init(void) { low_output = 0x08; low_direction = 0x0b; /* initialize low byte for jtag */ if (ft2232_set_data_bits_low_byte(low_output, low_direction) != ERROR_OK) { LOG_ERROR("couldn't initialize FT2232 with 'comstick' layout"); return ERROR_JTAG_INIT_FAILED; } nTRST = 0x01; nTRSTnOE = 0x00; /* no output enable for nTRST */ nSRST = 0x02; nSRSTnOE = 0x00; /* no output enable for nSRST */ high_output = 0x03; high_direction = 0x03; /* initialize high byte for jtag */ if (ft2232_set_data_bits_high_byte(high_output, high_direction) != ERROR_OK) { LOG_ERROR("couldn't initialize FT2232 with 'comstick' layout"); return ERROR_JTAG_INIT_FAILED; } return ERROR_OK; } static int stm32stick_init(void) { low_output = 0x88; low_direction = 0x8b; /* initialize low byte for jtag */ if (ft2232_set_data_bits_low_byte(low_output, low_direction) != ERROR_OK) { LOG_ERROR("couldn't initialize FT2232 with 'stm32stick' layout"); return ERROR_JTAG_INIT_FAILED; } nTRST = 0x01; nTRSTnOE = 0x00; /* no output enable for nTRST */ nSRST = 0x80; nSRSTnOE = 0x00; /* no output enable for nSRST */ high_output = 0x01; high_direction = 0x03; /* initialize high byte for jtag */ if (ft2232_set_data_bits_high_byte(high_output, high_direction) != ERROR_OK) { LOG_ERROR("couldn't initialize FT2232 with 'stm32stick' layout"); return ERROR_JTAG_INIT_FAILED; } return ERROR_OK; } static int sheevaplug_init(void) { low_output = 0x08; low_direction = 0x1b; /* initialize low byte for jtag */ if (ft2232_set_data_bits_low_byte(low_output, low_direction) != ERROR_OK) { LOG_ERROR("couldn't initialize FT2232 with 'sheevaplug' layout"); return ERROR_JTAG_INIT_FAILED; } nTRSTnOE = 0x1; nTRST = 0x02; nSRSTnOE = 0x4; nSRST = 0x08; high_output = 0x0; high_direction = 0x0f; /* nTRST is always push-pull */ high_output &= ~nTRSTnOE; high_output |= nTRST; /* nSRST is always open-drain */ high_output |= nSRSTnOE; high_output &= ~nSRST; /* initialize high byte for jtag */ if (ft2232_set_data_bits_high_byte(high_output, high_direction) != ERROR_OK) { LOG_ERROR("couldn't initialize FT2232 with 'sheevaplug' layout"); return ERROR_JTAG_INIT_FAILED; } return ERROR_OK; } static int cortino_jtag_init(void) { low_output = 0x08; low_direction = 0x1b; /* initialize low byte for jtag */ if (ft2232_set_data_bits_low_byte(low_output, low_direction) != ERROR_OK) { LOG_ERROR("couldn't initialize FT2232 with 'cortino' layout"); return ERROR_JTAG_INIT_FAILED; } nTRST = 0x01; nTRSTnOE = 0x00; /* no output enable for nTRST */ nSRST = 0x02; nSRSTnOE = 0x00; /* no output enable for nSRST */ high_output = 0x03; high_direction = 0x03; /* initialize high byte for jtag */ if (ft2232_set_data_bits_high_byte(high_output, high_direction) != ERROR_OK) { LOG_ERROR("couldn't initialize FT2232 with 'cortino' layout"); return ERROR_JTAG_INIT_FAILED; } return ERROR_OK; } static int lisa_l_init(void) { ftx232_dbus_init(); nTRST = 0x10; nTRSTnOE = 0x10; nSRST = 0x40; nSRSTnOE = 0x40; high_output = 0x00; high_direction = 0x18; /* initialize high byte for jtag */ if (ft2232_set_data_bits_high_byte(high_output, high_direction) != ERROR_OK) { LOG_ERROR("couldn't initialize FT2232 with 'lisa_l' layout"); return ERROR_JTAG_INIT_FAILED; } return ftx232_dbus_write(); } static int flossjtag_init(void) { ftx232_dbus_init(); nTRST = 0x10; nTRSTnOE = 0x10; nSRST = 0x40; nSRSTnOE = 0x40; high_output = 0x00; high_direction = 0x18; /* initialize high byte for jtag */ if (ft2232_set_data_bits_high_byte(high_output, high_direction) != ERROR_OK) { LOG_ERROR("couldn't initialize FT2232 with 'Floss-JTAG' layout"); return ERROR_JTAG_INIT_FAILED; } return ftx232_dbus_write(); } /* * The reference schematic from TI for the XDS100v2 has a CPLD on which opens * the door for a number of different configurations * * Known Implementations: * http://processors.wiki.ti.com/images/9/93/TMS570LS20216_USB_STICK_Schematic.pdf * * http://processors.wiki.ti.com/index.php/XDS100 (rev2) * * CLPD logic: Rising edge to enable outputs (XDS100_PWR_RST) * * ACBUS3 to transition 0->1 (OE rising edge) * * CPLD logic: Put the EMU0/1 pins in Hi-Z: * * ADBUS5/GPIOL1 = EMU_EN = 1 * * ADBUS6/GPIOL2 = EMU0 = 0 * * ACBUS4/SPARE0 = EMU1 = 0 * * CPLD logic: Disable loopback * * ACBUS6/SPARE2 = LOOPBACK = 0 */ #define XDS100_nEMU_EN (1<<5) #define XDS100_nEMU0 (1<<6) #define XDS100_PWR_RST (1<<3) #define XDS100_nEMU1 (1<<4) #define XDS100_LOOPBACK (1<<6) static int xds100v2_init(void) { /* These are in the lower byte */ nTRST = 0x10; nTRSTnOE = 0x10; /* These aren't actually used on 14 pin connectors * These are in the upper byte */ nSRST = 0x01; nSRSTnOE = 0x01; low_output = 0x08 | nTRST | XDS100_nEMU_EN; low_direction = 0x0b | nTRSTnOE | XDS100_nEMU_EN | XDS100_nEMU0; if (ft2232_set_data_bits_low_byte(low_output, low_direction) != ERROR_OK) { LOG_ERROR("couldn't initialize FT2232 with 'xds100v2' layout"); return ERROR_JTAG_INIT_FAILED; } high_output = 0; high_direction = nSRSTnOE | XDS100_LOOPBACK | XDS100_PWR_RST | XDS100_nEMU1; /* initialize high byte for jtag */ if (ft2232_set_data_bits_high_byte(high_output, high_direction) != ERROR_OK) { LOG_ERROR("couldn't put CPLD in to reset with 'xds100v2' layout"); return ERROR_JTAG_INIT_FAILED; } high_output |= XDS100_PWR_RST; /* initialize high byte for jtag */ if (ft2232_set_data_bits_high_byte(high_output, high_direction) != ERROR_OK) { LOG_ERROR("couldn't bring CPLD out of reset with 'xds100v2' layout"); return ERROR_JTAG_INIT_FAILED; } return ERROR_OK; } static void olimex_jtag_blink(void) { /* Olimex ARM-USB-OCD has a LED connected to ACBUS3 * ACBUS3 is bit 3 of the GPIOH port */ high_output ^= 0x08; buffer_write(0x82); buffer_write(high_output); buffer_write(high_direction); } static void flyswatter_jtag_blink(unsigned char led) { buffer_write(0x82); buffer_write(high_output ^ led); buffer_write(high_direction); } static void flyswatter1_jtag_blink(void) { /* * Flyswatter has two LEDs connected to ACBUS2 and ACBUS3 */ flyswatter_jtag_blink(0xc); } static void flyswatter2_jtag_blink(void) { /* * Flyswatter2 only has one LED connected to ACBUS2 */ flyswatter_jtag_blink(0x4); } static void turtle_jtag_blink(void) { /* * Turtelizer2 has two LEDs connected to ACBUS2 and ACBUS3 */ if (high_output & 0x08) high_output = 0x04; else high_output = 0x08; buffer_write(0x82); buffer_write(high_output); buffer_write(high_direction); } static void lisa_l_blink(void) { /* * Lisa/L has two LEDs connected to BCBUS3 and BCBUS4 */ if (high_output & 0x10) high_output = 0x08; else high_output = 0x10; buffer_write(0x82); buffer_write(high_output); buffer_write(high_direction); } static void flossjtag_blink(void) { /* * Floss-JTAG has two LEDs connected to ACBUS3 and ACBUS4 */ if (high_output & 0x10) high_output = 0x08; else high_output = 0x10; buffer_write(0x82); buffer_write(high_output); buffer_write(high_direction); } static int ft2232_quit(void) { #if BUILD_FT2232_FTD2XX == 1 FT_Close(ftdih); #elif BUILD_FT2232_LIBFTDI == 1 ftdi_usb_close(&ftdic); ftdi_deinit(&ftdic); #endif free(ft2232_buffer); ft2232_buffer = NULL; return ERROR_OK; } COMMAND_HANDLER(ft2232_handle_device_desc_command) { char *cp; char buf[200]; if (CMD_ARGC == 1) { ft2232_device_desc = strdup(CMD_ARGV[0]); cp = strchr(ft2232_device_desc, 0); /* under Win32, the FTD2XX driver appends an "A" to the end * of the description, this examines the given desc * and creates the 'missing' _A or non_A variable. */ if ((cp[-1] == 'A') && (cp[-2] == ' ')) { /* it was, so make this the "A" version. */ ft2232_device_desc_A = ft2232_device_desc; /* and *CREATE* the non-A version. */ strcpy(buf, ft2232_device_desc); cp = strchr(buf, 0); cp[-2] = 0; ft2232_device_desc = strdup(buf); } else { /* A not defined * so create it */ sprintf(buf, "%s A", ft2232_device_desc); ft2232_device_desc_A = strdup(buf); } } else LOG_ERROR("expected exactly one argument to ft2232_device_desc "); return ERROR_OK; } COMMAND_HANDLER(ft2232_handle_serial_command) { if (CMD_ARGC == 1) ft2232_serial = strdup(CMD_ARGV[0]); else return ERROR_COMMAND_SYNTAX_ERROR; return ERROR_OK; } COMMAND_HANDLER(ft2232_handle_layout_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; if (layout) { LOG_ERROR("already specified ft2232_layout %s", layout->name); return (strcmp(layout->name, CMD_ARGV[0]) != 0) ? ERROR_FAIL : ERROR_OK; } for (const struct ft2232_layout *l = ft2232_layouts; l->name; l++) { if (strcmp(l->name, CMD_ARGV[0]) == 0) { layout = l; ft2232_channel = l->channel; return ERROR_OK; } } LOG_ERROR("No FT2232 layout '%s' found", CMD_ARGV[0]); return ERROR_FAIL; } COMMAND_HANDLER(ft2232_handle_vid_pid_command) { if (CMD_ARGC > MAX_USB_IDS * 2) { LOG_WARNING("ignoring extra IDs in ft2232_vid_pid " "(maximum is %d pairs)", MAX_USB_IDS); CMD_ARGC = MAX_USB_IDS * 2; } if (CMD_ARGC < 2 || (CMD_ARGC & 1)) { LOG_WARNING("incomplete ft2232_vid_pid configuration directive"); if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; /* remove the incomplete trailing id */ CMD_ARGC -= 1; } unsigned i; for (i = 0; i < CMD_ARGC; i += 2) { COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i], ft2232_vid[i >> 1]); COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], ft2232_pid[i >> 1]); } /* * Explicitly terminate, in case there are multiples instances of * ft2232_vid_pid. */ ft2232_vid[i >> 1] = ft2232_pid[i >> 1] = 0; return ERROR_OK; } COMMAND_HANDLER(ft2232_handle_latency_command) { if (CMD_ARGC == 1) ft2232_latency = atoi(CMD_ARGV[0]); else return ERROR_COMMAND_SYNTAX_ERROR; return ERROR_OK; } COMMAND_HANDLER(ft2232_handle_channel_command) { if (CMD_ARGC == 1) { ft2232_channel = atoi(CMD_ARGV[0]); if (ft2232_channel < 0 || ft2232_channel > 4) LOG_ERROR("ft2232_channel must be in the 0 to 4 range"); } else LOG_ERROR("expected exactly one argument to ft2232_channel "); return ERROR_OK; } static int ft2232_stableclocks(int num_cycles, struct jtag_command *cmd) { int retval = 0; /* 7 bits of either ones or zeros. */ uint8_t tms = (tap_get_state() == TAP_RESET ? 0x7F : 0x00); while (num_cycles > 0) { /* the command 0x4b, "Clock Data to TMS/CS Pin (no Read)" handles * at most 7 bits per invocation. Here we invoke it potentially * several times. */ int bitcount_per_command = (num_cycles > 7) ? 7 : num_cycles; if (ft2232_buffer_size + 3 >= FT2232_BUFFER_SIZE) { if (ft2232_send_and_recv(first_unsent, cmd) != ERROR_OK) retval = ERROR_JTAG_QUEUE_FAILED; first_unsent = cmd; } /* there are no state transitions in this code, so omit state tracking */ /* command "Clock Data to TMS/CS Pin (no Read)" */ buffer_write(0x4b); /* scan 7 bit */ buffer_write(bitcount_per_command - 1); /* TMS data bits are either all zeros or ones to stay in the current stable state */ buffer_write(tms); require_send = 1; num_cycles -= bitcount_per_command; } return retval; } /* --------------------------------------------------------------------- * Support for IceBear JTAG adapter from Section5: * http://section5.ch/icebear * * Author: Sten, debian@sansys-electronic.com */ /* Icebear pin layout * * ADBUS5 (nEMU) nSRST | 2 1| GND (10k->VCC) * GND GND | 4 3| n.c. * ADBUS3 TMS | 6 5| ADBUS6 VCC * ADBUS0 TCK | 8 7| ADBUS7 (GND) * ADBUS4 nTRST |10 9| ACBUS0 (GND) * ADBUS1 TDI |12 11| ACBUS1 (GND) * ADBUS2 TDO |14 13| GND GND * * ADBUS0 O L TCK ACBUS0 GND * ADBUS1 O L TDI ACBUS1 GND * ADBUS2 I TDO ACBUS2 n.c. * ADBUS3 O H TMS ACBUS3 n.c. * ADBUS4 O H nTRST * ADBUS5 O H nSRST * ADBUS6 - VCC * ADBUS7 - GND */ static int icebear_jtag_init(void) { low_direction = 0x0b; /* output: TCK TDI TMS; input: TDO */ low_output = 0x08; /* high: TMS; low: TCK TDI */ nTRST = 0x10; nSRST = 0x20; enum reset_types jtag_reset_config = jtag_get_reset_config(); if ((jtag_reset_config & RESET_TRST_OPEN_DRAIN) != 0) low_direction &= ~nTRST; /* nTRST high impedance */ else { low_direction |= nTRST; low_output |= nTRST; } low_direction |= nSRST; low_output |= nSRST; /* initialize low byte for jtag */ if (ft2232_set_data_bits_low_byte(low_output, low_direction) != ERROR_OK) { LOG_ERROR("couldn't initialize FT2232 with 'IceBear' layout (low)"); return ERROR_JTAG_INIT_FAILED; } high_output = 0x0; high_direction = 0x00; /* initialize high byte for jtag */ if (ft2232_set_data_bits_high_byte(high_output, high_direction) != ERROR_OK) { LOG_ERROR("couldn't initialize FT2232 with 'IceBear' layout (high)"); return ERROR_JTAG_INIT_FAILED; } return ERROR_OK; } static void icebear_jtag_reset(int trst, int srst) { if (trst == 1) { low_direction |= nTRST; low_output &= ~nTRST; } else if (trst == 0) { enum reset_types jtag_reset_config = jtag_get_reset_config(); if ((jtag_reset_config & RESET_TRST_OPEN_DRAIN) != 0) low_direction &= ~nTRST; else low_output |= nTRST; } if (srst == 1) low_output &= ~nSRST; else if (srst == 0) low_output |= nSRST; /* command "set data bits low byte" */ buffer_write(0x80); buffer_write(low_output); buffer_write(low_direction); LOG_DEBUG("trst: %i, srst: %i, low_output: 0x%2.2x, low_direction: 0x%2.2x", trst, srst, low_output, low_direction); } /* --------------------------------------------------------------------- * Support for Signalyzer H2 and Signalyzer H4 * JTAG adapter from Xverve Technologies Inc. * http://www.signalyzer.com or http://www.xverve.com * * Author: Oleg Seiljus, oleg@signalyzer.com */ static unsigned char signalyzer_h_side; static unsigned int signalyzer_h_adapter_type; static int signalyzer_h_ctrl_write(int address, unsigned short value); #if BUILD_FT2232_FTD2XX == 1 static int signalyzer_h_ctrl_read(int address, unsigned short *value); #endif #define SIGNALYZER_COMMAND_ADDR 128 #define SIGNALYZER_DATA_BUFFER_ADDR 129 #define SIGNALYZER_COMMAND_VERSION 0x41 #define SIGNALYZER_COMMAND_RESET 0x42 #define SIGNALYZER_COMMAND_POWERCONTROL_GET 0x50 #define SIGNALYZER_COMMAND_POWERCONTROL_SET 0x51 #define SIGNALYZER_COMMAND_PWM_SET 0x52 #define SIGNALYZER_COMMAND_LED_SET 0x53 #define SIGNALYZER_COMMAND_ADC 0x54 #define SIGNALYZER_COMMAND_GPIO_STATE 0x55 #define SIGNALYZER_COMMAND_GPIO_MODE 0x56 #define SIGNALYZER_COMMAND_GPIO_PORT 0x57 #define SIGNALYZER_COMMAND_I2C 0x58 #define SIGNALYZER_CHAN_A 1 #define SIGNALYZER_CHAN_B 2 /* LEDS use channel C */ #define SIGNALYZER_CHAN_C 4 #define SIGNALYZER_LED_GREEN 1 #define SIGNALYZER_LED_RED 2 #define SIGNALYZER_MODULE_TYPE_EM_LT16_A 0x0301 #define SIGNALYZER_MODULE_TYPE_EM_ARM_JTAG 0x0302 #define SIGNALYZER_MODULE_TYPE_EM_JTAG 0x0303 #define SIGNALYZER_MODULE_TYPE_EM_ARM_JTAG_P 0x0304 #define SIGNALYZER_MODULE_TYPE_EM_JTAG_P 0x0305 static int signalyzer_h_ctrl_write(int address, unsigned short value) { #if BUILD_FT2232_FTD2XX == 1 return FT_WriteEE(ftdih, address, value); #elif BUILD_FT2232_LIBFTDI == 1 return 0; #endif } #if BUILD_FT2232_FTD2XX == 1 static int signalyzer_h_ctrl_read(int address, unsigned short *value) { return FT_ReadEE(ftdih, address, value); } #endif static int signalyzer_h_led_set(unsigned char channel, unsigned char led, int on_time_ms, int off_time_ms, unsigned char cycles) { unsigned char on_time; unsigned char off_time; if (on_time_ms < 0xFFFF) on_time = (unsigned char)(on_time_ms / 62); else on_time = 0xFF; off_time = (unsigned char)(off_time_ms / 62); #if BUILD_FT2232_FTD2XX == 1 FT_STATUS status; status = signalyzer_h_ctrl_write(SIGNALYZER_DATA_BUFFER_ADDR, ((uint32_t)(channel << 8) | led)); if (status != FT_OK) { LOG_ERROR("signalyzer_h_ctrl_write returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } status = signalyzer_h_ctrl_write((SIGNALYZER_DATA_BUFFER_ADDR + 1), ((uint32_t)(on_time << 8) | off_time)); if (status != FT_OK) { LOG_ERROR("signalyzer_h_ctrl_write returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } status = signalyzer_h_ctrl_write((SIGNALYZER_DATA_BUFFER_ADDR + 2), ((uint32_t)cycles)); if (status != FT_OK) { LOG_ERROR("signalyzer_h_ctrl_write returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } status = signalyzer_h_ctrl_write(SIGNALYZER_COMMAND_ADDR, SIGNALYZER_COMMAND_LED_SET); if (status != FT_OK) { LOG_ERROR("signalyzer_h_ctrl_write returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } return ERROR_OK; #elif BUILD_FT2232_LIBFTDI == 1 int retval; retval = signalyzer_h_ctrl_write(SIGNALYZER_DATA_BUFFER_ADDR, ((uint32_t)(channel << 8) | led)); if (retval < 0) { LOG_ERROR("signalyzer_h_ctrl_write returned: %s", ftdi_get_error_string(&ftdic)); return ERROR_JTAG_DEVICE_ERROR; } retval = signalyzer_h_ctrl_write((SIGNALYZER_DATA_BUFFER_ADDR + 1), ((uint32_t)(on_time << 8) | off_time)); if (retval < 0) { LOG_ERROR("signalyzer_h_ctrl_write returned: %s", ftdi_get_error_string(&ftdic)); return ERROR_JTAG_DEVICE_ERROR; } retval = signalyzer_h_ctrl_write((SIGNALYZER_DATA_BUFFER_ADDR + 2), (uint32_t)cycles); if (retval < 0) { LOG_ERROR("signalyzer_h_ctrl_write returned: %s", ftdi_get_error_string(&ftdic)); return ERROR_JTAG_DEVICE_ERROR; } retval = signalyzer_h_ctrl_write(SIGNALYZER_COMMAND_ADDR, SIGNALYZER_COMMAND_LED_SET); if (retval < 0) { LOG_ERROR("signalyzer_h_ctrl_write returned: %s", ftdi_get_error_string(&ftdic)); return ERROR_JTAG_DEVICE_ERROR; } return ERROR_OK; #endif } static int signalyzer_h_init(void) { #if BUILD_FT2232_FTD2XX == 1 FT_STATUS status; int i; #endif char *end_of_desc; uint16_t read_buf[12] = { 0 }; /* turn on center green led */ signalyzer_h_led_set(SIGNALYZER_CHAN_C, SIGNALYZER_LED_GREEN, 0xFFFF, 0x00, 0x00); /* determine what channel config wants to open * TODO: change me... current implementation is made to work * with openocd description parsing. */ end_of_desc = strrchr(ft2232_device_desc, 0x00); if (end_of_desc) { signalyzer_h_side = *(end_of_desc - 1); if (signalyzer_h_side == 'B') signalyzer_h_side = SIGNALYZER_CHAN_B; else signalyzer_h_side = SIGNALYZER_CHAN_A; } else { LOG_ERROR("No Channel was specified"); return ERROR_FAIL; } signalyzer_h_led_set(signalyzer_h_side, SIGNALYZER_LED_GREEN, 1000, 1000, 0xFF); #if BUILD_FT2232_FTD2XX == 1 /* read signalyzer versionining information */ status = signalyzer_h_ctrl_write(SIGNALYZER_COMMAND_ADDR, SIGNALYZER_COMMAND_VERSION); if (status != FT_OK) { LOG_ERROR("signalyzer_h_ctrl_write returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } for (i = 0; i < 10; i++) { status = signalyzer_h_ctrl_read((SIGNALYZER_DATA_BUFFER_ADDR + i), &read_buf[i]); if (status != FT_OK) { LOG_ERROR("signalyzer_h_ctrl_read returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } } LOG_INFO("Signalyzer: ID info: { %.4x %.4x %.4x %.4x %.4x %.4x %.4x }", read_buf[0], read_buf[1], read_buf[2], read_buf[3], read_buf[4], read_buf[5], read_buf[6]); /* set gpio register */ status = signalyzer_h_ctrl_write(SIGNALYZER_DATA_BUFFER_ADDR, (uint32_t)(signalyzer_h_side << 8)); if (status != FT_OK) { LOG_ERROR("signalyzer_h_ctrl_write returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } status = signalyzer_h_ctrl_write(SIGNALYZER_DATA_BUFFER_ADDR + 1, 0x0404); if (status != FT_OK) { LOG_ERROR("signalyzer_h_ctrl_write returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } status = signalyzer_h_ctrl_write(SIGNALYZER_COMMAND_ADDR, SIGNALYZER_COMMAND_GPIO_STATE); if (status != FT_OK) { LOG_ERROR("signalyzer_h_ctrl_write returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } /* read adapter type information */ status = signalyzer_h_ctrl_write(SIGNALYZER_DATA_BUFFER_ADDR, ((uint32_t)(signalyzer_h_side << 8) | 0x01)); if (status != FT_OK) { LOG_ERROR("signalyzer_h_ctrl_write returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } status = signalyzer_h_ctrl_write( (SIGNALYZER_DATA_BUFFER_ADDR + 1), 0xA000); if (status != FT_OK) { LOG_ERROR("signalyzer_h_ctrl_write returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } status = signalyzer_h_ctrl_write( (SIGNALYZER_DATA_BUFFER_ADDR + 2), 0x0008); if (status != FT_OK) { LOG_ERROR("signalyzer_h_ctrl_write returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } status = signalyzer_h_ctrl_write(SIGNALYZER_COMMAND_ADDR, SIGNALYZER_COMMAND_I2C); if (status != FT_OK) { LOG_ERROR("signalyzer_h_ctrl_write returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } usleep(100000); status = signalyzer_h_ctrl_read(SIGNALYZER_COMMAND_ADDR, &read_buf[0]); if (status != FT_OK) { LOG_ERROR("signalyzer_h_ctrl_read returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } if (read_buf[0] != 0x0498) signalyzer_h_adapter_type = 0x0000; else { for (i = 0; i < 4; i++) { status = signalyzer_h_ctrl_read((SIGNALYZER_DATA_BUFFER_ADDR + i), &read_buf[i]); if (status != FT_OK) { LOG_ERROR("signalyzer_h_ctrl_read returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } } signalyzer_h_adapter_type = read_buf[0]; } #elif BUILD_FT2232_LIBFTDI == 1 /* currently libftdi does not allow reading individual eeprom * locations, therefore adapter type cannot be detected. * override with most common type */ signalyzer_h_adapter_type = SIGNALYZER_MODULE_TYPE_EM_ARM_JTAG; #endif enum reset_types jtag_reset_config = jtag_get_reset_config(); /* ADAPTOR: EM_LT16_A */ if (signalyzer_h_adapter_type == SIGNALYZER_MODULE_TYPE_EM_LT16_A) { LOG_INFO("Signalyzer: EM-LT (16-channel level translator) " "detected. (HW: %2x).", (read_buf[1] >> 8)); nTRST = 0x10; nTRSTnOE = 0x10; nSRST = 0x20; nSRSTnOE = 0x20; low_output = 0x08; low_direction = 0x1b; high_output = 0x0; high_direction = 0x0; if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) { low_direction &= ~nTRSTnOE; /* nTRST input */ low_output &= ~nTRST; /* nTRST = 0 */ } else { low_direction |= nTRSTnOE; /* nTRST output */ low_output |= nTRST; /* nTRST = 1 */ } if (jtag_reset_config & RESET_SRST_PUSH_PULL) { low_direction |= nSRSTnOE; /* nSRST output */ low_output |= nSRST; /* nSRST = 1 */ } else { low_direction &= ~nSRSTnOE; /* nSRST input */ low_output &= ~nSRST; /* nSRST = 0 */ } #if BUILD_FT2232_FTD2XX == 1 /* enable power to the module */ status = signalyzer_h_ctrl_write(SIGNALYZER_DATA_BUFFER_ADDR, ((uint32_t)(signalyzer_h_side << 8) | 0x01)); if (status != FT_OK) { LOG_ERROR("signalyzer_h_ctrl_write returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } status = signalyzer_h_ctrl_write(SIGNALYZER_COMMAND_ADDR, SIGNALYZER_COMMAND_POWERCONTROL_SET); if (status != FT_OK) { LOG_ERROR("signalyzer_h_ctrl_write returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } /* set gpio mode register */ status = signalyzer_h_ctrl_write(SIGNALYZER_DATA_BUFFER_ADDR, (uint32_t)(signalyzer_h_side << 8)); if (status != FT_OK) { LOG_ERROR("signalyzer_h_ctrl_write returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } status = signalyzer_h_ctrl_write(SIGNALYZER_DATA_BUFFER_ADDR + 1, 0x0000); if (status != FT_OK) { LOG_ERROR("signalyzer_h_ctrl_write returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } status = signalyzer_h_ctrl_write(SIGNALYZER_COMMAND_ADDR, SIGNALYZER_COMMAND_GPIO_MODE); if (status != FT_OK) { LOG_ERROR("signalyzer_h_ctrl_write returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } /* set gpio register */ status = signalyzer_h_ctrl_write(SIGNALYZER_DATA_BUFFER_ADDR, (uint32_t)(signalyzer_h_side << 8)); if (status != FT_OK) { LOG_ERROR("signalyzer_h_ctrl_write returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } status = signalyzer_h_ctrl_write(SIGNALYZER_DATA_BUFFER_ADDR + 1, 0x4040); if (status != FT_OK) { LOG_ERROR("signalyzer_h_ctrl_write returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } status = signalyzer_h_ctrl_write(SIGNALYZER_COMMAND_ADDR, SIGNALYZER_COMMAND_GPIO_STATE); if (status != FT_OK) { LOG_ERROR("signalyzer_h_ctrl_write returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } #endif } /* ADAPTOR: EM_ARM_JTAG, EM_ARM_JTAG_P, EM_JTAG, EM_JTAG_P */ else if ((signalyzer_h_adapter_type == SIGNALYZER_MODULE_TYPE_EM_ARM_JTAG) || (signalyzer_h_adapter_type == SIGNALYZER_MODULE_TYPE_EM_ARM_JTAG_P) || (signalyzer_h_adapter_type == SIGNALYZER_MODULE_TYPE_EM_JTAG) || (signalyzer_h_adapter_type == SIGNALYZER_MODULE_TYPE_EM_JTAG_P)) { if (signalyzer_h_adapter_type == SIGNALYZER_MODULE_TYPE_EM_ARM_JTAG) LOG_INFO("Signalyzer: EM-ARM-JTAG (ARM JTAG) " "detected. (HW: %2x).", (read_buf[1] >> 8)); else if (signalyzer_h_adapter_type == SIGNALYZER_MODULE_TYPE_EM_ARM_JTAG_P) LOG_INFO("Signalyzer: EM-ARM-JTAG_P " "(ARM JTAG with PSU) detected. (HW: %2x).", (read_buf[1] >> 8)); else if (signalyzer_h_adapter_type == SIGNALYZER_MODULE_TYPE_EM_JTAG) LOG_INFO("Signalyzer: EM-JTAG (Generic JTAG) " "detected. (HW: %2x).", (read_buf[1] >> 8)); else if (signalyzer_h_adapter_type == SIGNALYZER_MODULE_TYPE_EM_JTAG_P) LOG_INFO("Signalyzer: EM-JTAG-P " "(Generic JTAG with PSU) detected. (HW: %2x).", (read_buf[1] >> 8)); nTRST = 0x02; nTRSTnOE = 0x04; nSRST = 0x08; nSRSTnOE = 0x10; low_output = 0x08; low_direction = 0x1b; high_output = 0x0; high_direction = 0x1f; if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) { high_output |= nTRSTnOE; high_output &= ~nTRST; } else { high_output &= ~nTRSTnOE; high_output |= nTRST; } if (jtag_reset_config & RESET_SRST_PUSH_PULL) { high_output &= ~nSRSTnOE; high_output |= nSRST; } else { high_output |= nSRSTnOE; high_output &= ~nSRST; } #if BUILD_FT2232_FTD2XX == 1 /* enable power to the module */ status = signalyzer_h_ctrl_write(SIGNALYZER_DATA_BUFFER_ADDR, ((uint32_t)(signalyzer_h_side << 8) | 0x01)); if (status != FT_OK) { LOG_ERROR("signalyzer_h_ctrl_write returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } status = signalyzer_h_ctrl_write(SIGNALYZER_COMMAND_ADDR, SIGNALYZER_COMMAND_POWERCONTROL_SET); if (status != FT_OK) { LOG_ERROR("signalyzer_h_ctrl_write returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } /* set gpio mode register (IO_16 and IO_17 set as analog * inputs, other is gpio) */ status = signalyzer_h_ctrl_write(SIGNALYZER_DATA_BUFFER_ADDR, (uint32_t)(signalyzer_h_side << 8)); if (status != FT_OK) { LOG_ERROR("signalyzer_h_ctrl_write returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } status = signalyzer_h_ctrl_write(SIGNALYZER_DATA_BUFFER_ADDR + 1, 0x0060); if (status != FT_OK) { LOG_ERROR("signalyzer_h_ctrl_write returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } status = signalyzer_h_ctrl_write(SIGNALYZER_COMMAND_ADDR, SIGNALYZER_COMMAND_GPIO_MODE); if (status != FT_OK) { LOG_ERROR("signalyzer_h_ctrl_write returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } /* set gpio register (all inputs, for -P modules, * PSU will be turned off) */ status = signalyzer_h_ctrl_write(SIGNALYZER_DATA_BUFFER_ADDR, (uint32_t)(signalyzer_h_side << 8)); if (status != FT_OK) { LOG_ERROR("signalyzer_h_ctrl_write returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } status = signalyzer_h_ctrl_write(SIGNALYZER_DATA_BUFFER_ADDR + 1, 0x0000); if (status != FT_OK) { LOG_ERROR("signalyzer_h_ctrl_write returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } status = signalyzer_h_ctrl_write(SIGNALYZER_COMMAND_ADDR, SIGNALYZER_COMMAND_GPIO_STATE); if (status != FT_OK) { LOG_ERROR("signalyzer_h_ctrl_write returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } #endif } else if (signalyzer_h_adapter_type == 0x0000) { LOG_INFO("Signalyzer: No external modules were detected."); nTRST = 0x10; nTRSTnOE = 0x10; nSRST = 0x20; nSRSTnOE = 0x20; low_output = 0x08; low_direction = 0x1b; high_output = 0x0; high_direction = 0x0; if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) { low_direction &= ~nTRSTnOE; /* nTRST input */ low_output &= ~nTRST; /* nTRST = 0 */ } else { low_direction |= nTRSTnOE; /* nTRST output */ low_output |= nTRST; /* nTRST = 1 */ } if (jtag_reset_config & RESET_SRST_PUSH_PULL) { low_direction |= nSRSTnOE; /* nSRST output */ low_output |= nSRST; /* nSRST = 1 */ } else { low_direction &= ~nSRSTnOE; /* nSRST input */ low_output &= ~nSRST; /* nSRST = 0 */ } } else { LOG_ERROR("Unknown module type is detected: %.4x", signalyzer_h_adapter_type); return ERROR_JTAG_DEVICE_ERROR; } /* initialize low byte of controller for jtag operation */ if (ft2232_set_data_bits_low_byte(low_output, low_direction) != ERROR_OK) { LOG_ERROR("couldn't initialize Signalyzer-H layout"); return ERROR_JTAG_INIT_FAILED; } #if BUILD_FT2232_FTD2XX == 1 if (ftdi_device == FT_DEVICE_2232H) { /* initialize high byte of controller for jtag operation */ if (ft2232_set_data_bits_high_byte(high_output, high_direction) != ERROR_OK) { LOG_ERROR("couldn't initialize Signalyzer-H layout"); return ERROR_JTAG_INIT_FAILED; } } #elif BUILD_FT2232_LIBFTDI == 1 if (ftdi_device == TYPE_2232H) { /* initialize high byte of controller for jtag operation */ if (ft2232_set_data_bits_high_byte(high_output, high_direction) != ERROR_OK) { LOG_ERROR("couldn't initialize Signalyzer-H layout"); return ERROR_JTAG_INIT_FAILED; } } #endif return ERROR_OK; } static void signalyzer_h_reset(int trst, int srst) { enum reset_types jtag_reset_config = jtag_get_reset_config(); /* ADAPTOR: EM_LT16_A */ if (signalyzer_h_adapter_type == SIGNALYZER_MODULE_TYPE_EM_LT16_A) { if (trst == 1) { if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) /* switch to output pin (output is low) */ low_direction |= nTRSTnOE; else /* switch output low */ low_output &= ~nTRST; } else if (trst == 0) { if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) /* switch to input pin (high-Z + internal * and external pullup) */ low_direction &= ~nTRSTnOE; else /* switch output high */ low_output |= nTRST; } if (srst == 1) { if (jtag_reset_config & RESET_SRST_PUSH_PULL) /* switch output low */ low_output &= ~nSRST; else /* switch to output pin (output is low) */ low_direction |= nSRSTnOE; } else if (srst == 0) { if (jtag_reset_config & RESET_SRST_PUSH_PULL) /* switch output high */ low_output |= nSRST; else /* switch to input pin (high-Z) */ low_direction &= ~nSRSTnOE; } /* command "set data bits low byte" */ buffer_write(0x80); buffer_write(low_output); buffer_write(low_direction); LOG_DEBUG("trst: %i, srst: %i, low_output: 0x%2.2x, " "low_direction: 0x%2.2x", trst, srst, low_output, low_direction); } /* ADAPTOR: EM_ARM_JTAG, EM_ARM_JTAG_P, EM_JTAG, EM_JTAG_P */ else if ((signalyzer_h_adapter_type == SIGNALYZER_MODULE_TYPE_EM_ARM_JTAG) || (signalyzer_h_adapter_type == SIGNALYZER_MODULE_TYPE_EM_ARM_JTAG_P) || (signalyzer_h_adapter_type == SIGNALYZER_MODULE_TYPE_EM_JTAG) || (signalyzer_h_adapter_type == SIGNALYZER_MODULE_TYPE_EM_JTAG_P)) { if (trst == 1) { if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) high_output &= ~nTRSTnOE; else high_output &= ~nTRST; } else if (trst == 0) { if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) high_output |= nTRSTnOE; else high_output |= nTRST; } if (srst == 1) { if (jtag_reset_config & RESET_SRST_PUSH_PULL) high_output &= ~nSRST; else high_output &= ~nSRSTnOE; } else if (srst == 0) { if (jtag_reset_config & RESET_SRST_PUSH_PULL) high_output |= nSRST; else high_output |= nSRSTnOE; } /* command "set data bits high byte" */ buffer_write(0x82); buffer_write(high_output); buffer_write(high_direction); LOG_INFO("trst: %i, srst: %i, high_output: 0x%2.2x, " "high_direction: 0x%2.2x", trst, srst, high_output, high_direction); } else if (signalyzer_h_adapter_type == 0x0000) { if (trst == 1) { if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) /* switch to output pin (output is low) */ low_direction |= nTRSTnOE; else /* switch output low */ low_output &= ~nTRST; } else if (trst == 0) { if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) /* switch to input pin (high-Z + internal * and external pullup) */ low_direction &= ~nTRSTnOE; else /* switch output high */ low_output |= nTRST; } if (srst == 1) { if (jtag_reset_config & RESET_SRST_PUSH_PULL) /* switch output low */ low_output &= ~nSRST; else /* switch to output pin (output is low) */ low_direction |= nSRSTnOE; } else if (srst == 0) { if (jtag_reset_config & RESET_SRST_PUSH_PULL) /* switch output high */ low_output |= nSRST; else /* switch to input pin (high-Z) */ low_direction &= ~nSRSTnOE; } /* command "set data bits low byte" */ buffer_write(0x80); buffer_write(low_output); buffer_write(low_direction); LOG_DEBUG("trst: %i, srst: %i, low_output: 0x%2.2x, " "low_direction: 0x%2.2x", trst, srst, low_output, low_direction); } } static void signalyzer_h_blink(void) { signalyzer_h_led_set(signalyzer_h_side, SIGNALYZER_LED_RED, 100, 0, 1); } /******************************************************************** * Support for KT-LINK * JTAG adapter from KRISTECH * http://www.kristech.eu *******************************************************************/ static int ktlink_init(void) { uint8_t swd_en = 0x20; /* 0x20 SWD disable, 0x00 SWD enable (ADBUS5) */ low_output = 0x08 | swd_en; /* value; TMS=1,TCK=0,TDI=0,SWD=swd_en */ low_direction = 0x3B; /* out=1; TCK/TDI/TMS=out,TDO=in,SWD=out,RTCK=in,SRSTIN=in */ /* initialize low byte for jtag */ if (ft2232_set_data_bits_low_byte(low_output, low_direction) != ERROR_OK) { LOG_ERROR("couldn't initialize FT2232 with 'ktlink' layout"); return ERROR_JTAG_INIT_FAILED; } nTRST = 0x01; nSRST = 0x02; nTRSTnOE = 0x04; nSRSTnOE = 0x08; high_output = 0x80; /* turn LED on */ high_direction = 0xFF; /* all outputs */ enum reset_types jtag_reset_config = jtag_get_reset_config(); if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) { high_output |= nTRSTnOE; high_output &= ~nTRST; } else { high_output &= ~nTRSTnOE; high_output |= nTRST; } if (jtag_reset_config & RESET_SRST_PUSH_PULL) { high_output &= ~nSRSTnOE; high_output |= nSRST; } else { high_output |= nSRSTnOE; high_output &= ~nSRST; } /* initialize high byte for jtag */ if (ft2232_set_data_bits_high_byte(high_output, high_direction) != ERROR_OK) { LOG_ERROR("couldn't initialize FT2232 with 'ktlink' layout"); return ERROR_JTAG_INIT_FAILED; } return ERROR_OK; } static void ktlink_reset(int trst, int srst) { enum reset_types jtag_reset_config = jtag_get_reset_config(); if (trst == 1) { if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) high_output &= ~nTRSTnOE; else high_output &= ~nTRST; } else if (trst == 0) { if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) high_output |= nTRSTnOE; else high_output |= nTRST; } if (srst == 1) { if (jtag_reset_config & RESET_SRST_PUSH_PULL) high_output &= ~nSRST; else high_output &= ~nSRSTnOE; } else if (srst == 0) { if (jtag_reset_config & RESET_SRST_PUSH_PULL) high_output |= nSRST; else high_output |= nSRSTnOE; } buffer_write(0x82); /* command "set data bits high byte" */ buffer_write(high_output); buffer_write(high_direction); LOG_DEBUG("trst: %i, srst: %i, high_output: 0x%2.2x, high_direction: 0x%2.2x", trst, srst, high_output, high_direction); } static void ktlink_blink(void) { /* LED connected to ACBUS7 */ high_output ^= 0x80; buffer_write(0x82); /* command "set data bits high byte" */ buffer_write(high_output); buffer_write(high_direction); } /******************************************************************** * Support for Digilent HS-1 * JTAG adapter from Digilent * http://www.digilent.com * Author: Stephane Bonnet bonnetst@hds.utc.fr *******************************************************************/ static int digilent_hs1_init(void) { /* the adapter only supports the base JTAG signals, no nTRST nor nSRST */ low_output = 0x88; low_direction = 0x8b; /* initialize low byte for jtag */ if (ft2232_set_data_bits_low_byte(low_output, low_direction) != ERROR_OK) { LOG_ERROR("couldn't initialize FT2232 with 'digilent_hs1' layout"); return ERROR_JTAG_INIT_FAILED; } return ERROR_OK; } static void digilent_hs1_reset(int trst, int srst) { /* Dummy function, no reset signals supported. */ } static const struct command_registration ft2232_command_handlers[] = { { .name = "ft2232_device_desc", .handler = &ft2232_handle_device_desc_command, .mode = COMMAND_CONFIG, .help = "set the USB device description of the FTDI FT2232 device", .usage = "description_string", }, { .name = "ft2232_serial", .handler = &ft2232_handle_serial_command, .mode = COMMAND_CONFIG, .help = "set the serial number of the FTDI FT2232 device", .usage = "serial_string", }, { .name = "ft2232_layout", .handler = &ft2232_handle_layout_command, .mode = COMMAND_CONFIG, .help = "set the layout of the FT2232 GPIO signals used " "to control output-enables and reset signals", .usage = "layout_name", }, { .name = "ft2232_vid_pid", .handler = &ft2232_handle_vid_pid_command, .mode = COMMAND_CONFIG, .help = "the vendor ID and product ID of the FTDI FT2232 device", .usage = "(vid pid)* ", }, { .name = "ft2232_latency", .handler = &ft2232_handle_latency_command, .mode = COMMAND_CONFIG, .help = "set the FT2232 latency timer to a new value", .usage = "value", }, { .name = "ft2232_channel", .handler = &ft2232_handle_channel_command, .mode = COMMAND_CONFIG, .help = "set the FT2232 channel to a new value", .usage = "value", }, COMMAND_REGISTRATION_DONE }; struct jtag_interface ft2232_interface = { .name = "ft2232", .supported = DEBUG_CAP_TMS_SEQ, .commands = ft2232_command_handlers, .transports = jtag_only, .init = ft2232_init, .quit = ft2232_quit, .speed = ft2232_speed, .speed_div = ft2232_speed_div, .khz = ft2232_khz, .execute_queue = ft2232_execute_queue, }; openocd-0.7.0/src/jtag/drivers/ti_icdi_usb.c0000644000175000001440000004324212137151331015677 00000000000000/*************************************************************************** * * * Copyright (C) 2012 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* project specific includes */ #include #include #include #include #include #include #include #include #define ICDI_WRITE_ENDPOINT 0x02 #define ICDI_READ_ENDPOINT 0x83 #define ICDI_WRITE_TIMEOUT 1000 #define ICDI_READ_TIMEOUT 1000 #define ICDI_PACKET_SIZE 2048 #define PACKET_START "$" #define PACKET_END "#" struct icdi_usb_handle_s { libusb_context *usb_ctx; libusb_device_handle *usb_dev; char *read_buffer; char *write_buffer; int max_packet; int read_count; }; static int icdi_usb_read_mem32(void *handle, uint32_t addr, uint16_t len, uint8_t *buffer); static int icdi_usb_write_mem32(void *handle, uint32_t addr, uint16_t len, const uint8_t *buffer); static int remote_escape_output(const char *buffer, int len, char *out_buf, int *out_len, int out_maxlen) { int input_index, output_index; output_index = 0; for (input_index = 0; input_index < len; input_index++) { char b = buffer[input_index]; if (b == '$' || b == '#' || b == '}' || b == '*') { /* These must be escaped. */ if (output_index + 2 > out_maxlen) break; out_buf[output_index++] = '}'; out_buf[output_index++] = b ^ 0x20; } else { if (output_index + 1 > out_maxlen) break; out_buf[output_index++] = b; } } *out_len = input_index; return output_index; } static int remote_unescape_input(const char *buffer, int len, char *out_buf, int out_maxlen) { int input_index, output_index; int escaped; output_index = 0; escaped = 0; for (input_index = 0; input_index < len; input_index++) { char b = buffer[input_index]; if (output_index + 1 > out_maxlen) LOG_ERROR("Received too much data from the target."); if (escaped) { out_buf[output_index++] = b ^ 0x20; escaped = 0; } else if (b == '}') escaped = 1; else out_buf[output_index++] = b; } if (escaped) LOG_ERROR("Unmatched escape character in target response."); return output_index; } static int icdi_send_packet(void *handle, int len) { unsigned char cksum = 0; struct icdi_usb_handle_s *h; int result, retry = 0; int transferred = 0; assert(handle != NULL); h = (struct icdi_usb_handle_s *)handle; /* check we have a large enough buffer for checksum "#00" */ if (len + 3 > h->max_packet) { LOG_ERROR("packet buffer too small"); return ERROR_FAIL; } /* calculate checksum - offset start of packet */ for (int i = 1; i < len; i++) cksum += h->write_buffer[i]; len += sprintf(&h->write_buffer[len], PACKET_END "%02x", cksum); #ifdef _DEBUG_USB_COMMS_ char buffer[50]; char ch = h->write_buffer[1]; if (ch == 'x' || ch == 'X') LOG_DEBUG("writing packet: "); else { memcpy(buffer, h->write_buffer, len >= 50 ? 50-1 : len); buffer[len] = 0; LOG_DEBUG("writing packet: %s", buffer); } #endif while (1) { result = libusb_bulk_transfer(h->usb_dev, ICDI_WRITE_ENDPOINT, (unsigned char *)h->write_buffer, len, &transferred, ICDI_WRITE_TIMEOUT); if (result != 0 || transferred != len) { LOG_DEBUG("Error TX Data %d", result); return ERROR_FAIL; } /* check that the client got the message ok, or shall we resend */ result = libusb_bulk_transfer(h->usb_dev, ICDI_READ_ENDPOINT, (unsigned char *)h->read_buffer, h->max_packet, &transferred, ICDI_READ_TIMEOUT); if (result != 0 || transferred < 1) { LOG_DEBUG("Error RX Data %d", result); return ERROR_FAIL; } #ifdef _DEBUG_USB_COMMS_ LOG_DEBUG("received reply: '%c' : count %d", h->read_buffer[0], transferred); #endif if (h->read_buffer[0] == '-') { LOG_DEBUG("Resending packet %d", ++retry); } else { if (h->read_buffer[0] != '+') LOG_DEBUG("Unexpected Reply from ICDI: %c", h->read_buffer[0]); break; } if (retry == 3) { LOG_DEBUG("maximum nack retries attempted"); return ERROR_FAIL; } } retry = 0; h->read_count = transferred; while (1) { /* read reply from icdi */ result = libusb_bulk_transfer(h->usb_dev, ICDI_READ_ENDPOINT, (unsigned char *)h->read_buffer + h->read_count, h->max_packet - h->read_count, &transferred, ICDI_READ_TIMEOUT); #ifdef _DEBUG_USB_COMMS_ LOG_DEBUG("received data: count %d", transferred); #endif /* check for errors but retry for timeout */ if (result != 0) { if (result == LIBUSB_ERROR_TIMEOUT) { LOG_DEBUG("Error RX timeout %d", result); } else { LOG_DEBUG("Error RX Data %d", result); return ERROR_FAIL; } } h->read_count += transferred; /* we need to make sure we have a full packet, including checksum */ if (h->read_count > 5) { /* check that we have received an packet delimiter * we do not validate the checksum * reply should contain $...#AA - so we check for # */ if (h->read_buffer[h->read_count - 3] == '#') return ERROR_OK; } if (retry++ == 3) { LOG_DEBUG("maximum data retries attempted"); break; } } return ERROR_FAIL; } static int icdi_send_cmd(void *handle, const char *cmd) { struct icdi_usb_handle_s *h; h = (struct icdi_usb_handle_s *)handle; int cmd_len = snprintf(h->write_buffer, h->max_packet, PACKET_START "%s", cmd); return icdi_send_packet(handle, cmd_len); } static int icdi_send_remote_cmd(void *handle, const char *data) { struct icdi_usb_handle_s *h; h = (struct icdi_usb_handle_s *)handle; size_t cmd_len = sprintf(h->write_buffer, PACKET_START "qRcmd,"); cmd_len += hexify(h->write_buffer + cmd_len, data, 0, h->max_packet - cmd_len); return icdi_send_packet(handle, cmd_len); } static int icdi_get_cmd_result(void *handle) { struct icdi_usb_handle_s *h; int offset = 0; char ch; assert(handle != NULL); h = (struct icdi_usb_handle_s *)handle; do { ch = h->read_buffer[offset++]; if (offset > h->read_count) return ERROR_FAIL; } while (ch != '$'); if (memcmp("OK", h->read_buffer + offset, 2) == 0) return ERROR_OK; if (h->read_buffer[offset] == 'E') { /* get error code */ char result; if (unhexify(&result, h->read_buffer + offset + 1, 1) != 1) return ERROR_FAIL; return result; } /* for now we assume everything else is ok */ return ERROR_OK; } static int icdi_usb_idcode(void *handle, uint32_t *idcode) { return ERROR_OK; } static int icdi_usb_write_debug_reg(void *handle, uint32_t addr, uint32_t val) { return icdi_usb_write_mem32(handle, addr, 1, (uint8_t *)&val); } static enum target_state icdi_usb_state(void *handle) { int result; struct icdi_usb_handle_s *h; uint32_t dhcsr; h = (struct icdi_usb_handle_s *)handle; result = icdi_usb_read_mem32(h, DCB_DHCSR, 1, (uint8_t *)&dhcsr); if (result != ERROR_OK) return TARGET_UNKNOWN; if (dhcsr & S_HALT) return TARGET_HALTED; return TARGET_RUNNING; } static int icdi_usb_version(void *handle) { struct icdi_usb_handle_s *h; h = (struct icdi_usb_handle_s *)handle; char version[20]; /* get info about icdi */ int result = icdi_send_remote_cmd(handle, "version"); if (result != ERROR_OK) return result; if (h->read_count < 8) { LOG_ERROR("Invalid Reply Received"); return ERROR_FAIL; } /* convert reply */ if (unhexify(version, h->read_buffer + 2, 4) != 4) { LOG_WARNING("unable to get ICDI version"); return ERROR_OK; } /* null terminate and print info */ version[4] = 0; LOG_INFO("ICDI Firmware version: %s", version); return ERROR_OK; } static int icdi_usb_query(void *handle) { int result; struct icdi_usb_handle_s *h; h = (struct icdi_usb_handle_s *)handle; result = icdi_send_cmd(handle, "qSupported"); if (result != ERROR_OK) return result; /* check result */ result = icdi_get_cmd_result(handle); if (result != ERROR_OK) { LOG_ERROR("query supported failed: 0x%x", result); return ERROR_FAIL; } /* from this we can get the max packet supported */ /* query packet buffer size */ char *offset = strstr(h->read_buffer, "PacketSize"); if (offset) { char *separator; int max_packet; max_packet = strtoul(offset + 11, &separator, 16); if (!max_packet) LOG_ERROR("invalid max packet, using defaults"); else h->max_packet = max_packet; LOG_DEBUG("max packet supported : %" PRIu32 " bytes", h->max_packet); } /* if required re allocate packet buffer */ if (h->max_packet != ICDI_PACKET_SIZE) { h->read_buffer = realloc(h->read_buffer, h->max_packet); h->write_buffer = realloc(h->write_buffer, h->max_packet); if (h->read_buffer == 0 || h->write_buffer == 0) { LOG_ERROR("unable to reallocate memory"); return ERROR_FAIL; } } /* set extended mode */ result = icdi_send_cmd(handle, "!"); if (result != ERROR_OK) return result; /* check result */ result = icdi_get_cmd_result(handle); if (result != ERROR_OK) { LOG_ERROR("unable to enable extended mode: 0x%x", result); return ERROR_FAIL; } return ERROR_OK; } static int icdi_usb_reset(void *handle) { /* we do this in hla_target.c */ return ERROR_OK; } static int icdi_usb_assert_srst(void *handle, int srst) { /* TODO not supported yet */ return ERROR_COMMAND_NOTFOUND; } static int icdi_usb_run(void *handle) { int result; /* resume target at current address */ result = icdi_send_cmd(handle, "c"); if (result != ERROR_OK) return result; /* check result */ result = icdi_get_cmd_result(handle); if (result != ERROR_OK) { LOG_ERROR("continue failed: 0x%x", result); return ERROR_FAIL; } return result; } static int icdi_usb_halt(void *handle) { int result; /* this query halts the target ?? */ result = icdi_send_cmd(handle, "?"); if (result != ERROR_OK) return result; /* check result */ result = icdi_get_cmd_result(handle); if (result != ERROR_OK) { LOG_ERROR("halt failed: 0x%x", result); return ERROR_FAIL; } return result; } static int icdi_usb_step(void *handle) { int result; /* step target at current address */ result = icdi_send_cmd(handle, "s"); if (result != ERROR_OK) return result; /* check result */ result = icdi_get_cmd_result(handle); if (result != ERROR_OK) { LOG_ERROR("step failed: 0x%x", result); return ERROR_FAIL; } return result; } static int icdi_usb_read_regs(void *handle) { /* currently unsupported */ return ERROR_OK; } static int icdi_usb_read_reg(void *handle, int num, uint32_t *val) { int result; struct icdi_usb_handle_s *h; char cmd[10]; h = (struct icdi_usb_handle_s *)handle; snprintf(cmd, sizeof(cmd), "p%x", num); result = icdi_send_cmd(handle, cmd); if (result != ERROR_OK) return result; /* check result */ result = icdi_get_cmd_result(handle); if (result != ERROR_OK) { LOG_ERROR("register read failed: 0x%x", result); return ERROR_FAIL; } /* convert result */ if (unhexify((char *)val, h->read_buffer + 2, 4) != 4) { LOG_ERROR("failed to convert result"); return ERROR_FAIL; } return result; } static int icdi_usb_write_reg(void *handle, int num, uint32_t val) { int result; char cmd[20]; int cmd_len = snprintf(cmd, sizeof(cmd), "P%x=", num); hexify(cmd + cmd_len, (char *)&val, 4, sizeof(cmd)); result = icdi_send_cmd(handle, cmd); if (result != ERROR_OK) return result; /* check result */ result = icdi_get_cmd_result(handle); if (result != ERROR_OK) { LOG_ERROR("register write failed: 0x%x", result); return ERROR_FAIL; } return result; } static int icdi_usb_read_mem(void *handle, uint32_t addr, uint32_t len, uint8_t *buffer) { int result; struct icdi_usb_handle_s *h; char cmd[20]; h = (struct icdi_usb_handle_s *)handle; snprintf(cmd, sizeof(cmd), "x%x,%x", addr, len); result = icdi_send_cmd(handle, cmd); if (result != ERROR_OK) return result; /* check result */ result = icdi_get_cmd_result(handle); if (result != ERROR_OK) { LOG_ERROR("memory read failed: 0x%x", result); return ERROR_FAIL; } /* unescape input */ int read_len = remote_unescape_input(h->read_buffer + 5, h->read_count - 8, (char *)buffer, len); if (read_len != (int)len) { LOG_ERROR("read more bytes than expected: actual 0x%" PRIx32 " expected 0x%" PRIx32, read_len, len); return ERROR_FAIL; } return ERROR_OK; } static int icdi_usb_write_mem(void *handle, uint32_t addr, uint32_t len, const uint8_t *buffer) { int result; struct icdi_usb_handle_s *h; h = (struct icdi_usb_handle_s *)handle; size_t cmd_len = snprintf(h->write_buffer, h->max_packet, PACKET_START "X%x,%x:", addr, len); int out_len; cmd_len += remote_escape_output((char *)buffer, len, h->write_buffer + cmd_len, &out_len, h->max_packet - cmd_len); if (out_len < (int)len) { /* for now issue a error as we have no way of allocating a larger buffer */ LOG_ERROR("memory buffer too small: requires 0x%" PRIx32 " actual 0x%" PRIx32, out_len, len); return ERROR_FAIL; } result = icdi_send_packet(handle, cmd_len); if (result != ERROR_OK) return result; /* check result */ result = icdi_get_cmd_result(handle); if (result != ERROR_OK) { LOG_ERROR("memory write failed: 0x%x", result); return ERROR_FAIL; } return ERROR_OK; } static int icdi_usb_read_mem8(void *handle, uint32_t addr, uint16_t len, uint8_t *buffer) { return icdi_usb_read_mem(handle, addr, len, buffer); } static int icdi_usb_write_mem8(void *handle, uint32_t addr, uint16_t len, const uint8_t *buffer) { return icdi_usb_write_mem(handle, addr, len, buffer); } static int icdi_usb_read_mem32(void *handle, uint32_t addr, uint16_t len, uint8_t *buffer) { return icdi_usb_read_mem(handle, addr, len * 4, buffer); } static int icdi_usb_write_mem32(void *handle, uint32_t addr, uint16_t len, const uint8_t *buffer) { return icdi_usb_write_mem(handle, addr, len * 4, buffer); } static int icdi_usb_close(void *handle) { struct icdi_usb_handle_s *h; h = (struct icdi_usb_handle_s *)handle; if (h->usb_dev) libusb_close(h->usb_dev); if (h->usb_ctx) libusb_exit(h->usb_ctx); if (h->read_buffer) free(h->read_buffer); if (h->write_buffer) free(h->write_buffer); free(handle); return ERROR_OK; } static int icdi_usb_open(struct hl_interface_param_s *param, void **fd) { int retval; struct icdi_usb_handle_s *h; LOG_DEBUG("icdi_usb_open"); h = calloc(1, sizeof(struct icdi_usb_handle_s)); if (h == 0) { LOG_ERROR("unable to allocate memory"); return ERROR_FAIL; } LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x", param->transport, param->vid, param->pid); if (libusb_init(&h->usb_ctx) != 0) { LOG_ERROR("libusb init failed"); goto error_open; } h->usb_dev = libusb_open_device_with_vid_pid(h->usb_ctx, param->vid, param->pid); if (!h->usb_dev) { LOG_ERROR("open failed"); goto error_open; } if (libusb_claim_interface(h->usb_dev, 2)) { LOG_DEBUG("claim interface failed"); goto error_open; } /* check if mode is supported */ retval = ERROR_OK; switch (param->transport) { #if 0 /* TODO place holder as swd is not currently supported */ case HL_TRANSPORT_SWD: #endif case HL_TRANSPORT_JTAG: break; default: retval = ERROR_FAIL; break; } if (retval != ERROR_OK) { LOG_ERROR("mode (transport) not supported by device"); goto error_open; } /* allocate buffer */ h->read_buffer = malloc(ICDI_PACKET_SIZE); h->write_buffer = malloc(ICDI_PACKET_SIZE); h->max_packet = ICDI_PACKET_SIZE; if (h->read_buffer == 0 || h->write_buffer == 0) { LOG_DEBUG("malloc failed"); goto error_open; } /* query icdi version etc */ retval = icdi_usb_version(h); if (retval != ERROR_OK) goto error_open; /* query icdi support */ retval = icdi_usb_query(h); if (retval != ERROR_OK) goto error_open; *fd = h; /* set the max target read/write buffer in bytes * as we are using gdb binary packets to transfer memory we have to * reserve half the buffer for any possible escape chars plus * at least 64 bytes for the gdb packet header */ param->max_buffer = (((h->max_packet - 64) / 4) * 4) / 2; return ERROR_OK; error_open: icdi_usb_close(h); return ERROR_FAIL; } struct hl_layout_api_s icdi_usb_layout_api = { .open = icdi_usb_open, .close = icdi_usb_close, .idcode = icdi_usb_idcode, .state = icdi_usb_state, .reset = icdi_usb_reset, .assert_srst = icdi_usb_assert_srst, .run = icdi_usb_run, .halt = icdi_usb_halt, .step = icdi_usb_step, .read_regs = icdi_usb_read_regs, .read_reg = icdi_usb_read_reg, .write_reg = icdi_usb_write_reg, .read_mem8 = icdi_usb_read_mem8, .write_mem8 = icdi_usb_write_mem8, .read_mem32 = icdi_usb_read_mem32, .write_mem32 = icdi_usb_write_mem32, .write_debug_reg = icdi_usb_write_debug_reg }; openocd-0.7.0/src/jtag/drivers/mpsse.h0000644000175000001440000000746712134336410014567 00000000000000/************************************************************************** * Copyright (C) 2012 by Andreas Fritiofson * * andreas.fritiofson@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef MPSSE_H_ #define MPSSE_H_ #include #include "helper/binarybuffer.h" /* Mode flags */ #define POS_EDGE_OUT 0x00 #define NEG_EDGE_OUT 0x01 #define POS_EDGE_IN 0x00 #define NEG_EDGE_IN 0x04 #define MSB_FIRST 0x00 #define LSB_FIRST 0x08 enum ftdi_chip_type { TYPE_FT2232C, TYPE_FT2232H, TYPE_FT4232H, TYPE_FT232H, }; struct mpsse_ctx; /* Device handling */ struct mpsse_ctx *mpsse_open(const uint16_t *vid, const uint16_t *pid, const char *description, const char *serial, int channel); void mpsse_close(struct mpsse_ctx *ctx); bool mpsse_is_high_speed(struct mpsse_ctx *ctx); /* Command queuing. These correspond to the MPSSE commands with the same names, but no need to care * about bit/byte transfer or data length limitation. Read data is guaranteed to be available only * after the following mpsse_flush(). */ int mpsse_clock_data_out(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, unsigned length, uint8_t mode); int mpsse_clock_data_in(struct mpsse_ctx *ctx, uint8_t *in, unsigned in_offset, unsigned length, uint8_t mode); int mpsse_clock_data(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, uint8_t *in, unsigned in_offset, unsigned length, uint8_t mode); int mpsse_clock_tms_cs_out(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, unsigned length, bool tdi, uint8_t mode); int mpsse_clock_tms_cs(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, uint8_t *in, unsigned in_offset, unsigned length, bool tdi, uint8_t mode); int mpsse_set_data_bits_low_byte(struct mpsse_ctx *ctx, uint8_t data, uint8_t dir); int mpsse_set_data_bits_high_byte(struct mpsse_ctx *ctx, uint8_t data, uint8_t dir); int mpsse_read_data_bits_low_byte(struct mpsse_ctx *ctx, uint8_t *data); int mpsse_read_data_bits_high_byte(struct mpsse_ctx *ctx, uint8_t *data); int mpsse_loopback_config(struct mpsse_ctx *ctx, bool enable); int mpsse_set_divisor(struct mpsse_ctx *ctx, uint16_t divisor); int mpsse_divide_by_5_config(struct mpsse_ctx *ctx, bool enable); int mpsse_rtck_config(struct mpsse_ctx *ctx, bool enable); /* Helper to set frequency in Hertz. Returns actual realizable frequency or negative error. * Frequency 0 means RTCK. */ int mpsse_set_frequency(struct mpsse_ctx *ctx, int frequency); /* Queue handling */ int mpsse_flush(struct mpsse_ctx *ctx); void mpsse_purge(struct mpsse_ctx *ctx); #endif /* MPSSE_H_ */ openocd-0.7.0/src/jtag/drivers/minidriver_imp.h0000644000175000001440000000502112134336410016435 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Copyright (C) 2007-2009 Øyvind Harboe * * Copyright (C) 2009 Zachary T Welch * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef MINIDRIVER_IMP_H #define MINIDRIVER_IMP_H #include static inline void interface_jtag_add_scan_check_alloc(struct scan_field *field) { unsigned num_bytes = DIV_ROUND_UP(field->num_bits, 8); field->in_value = (uint8_t *)cmd_queue_alloc(num_bytes); } void interface_jtag_add_dr_out(struct jtag_tap *tap, int num_fields, const int *num_bits, const uint32_t *value, tap_state_t end_state); void interface_jtag_add_callback(jtag_callback1_t f, jtag_callback_data_t data0); void interface_jtag_add_callback4(jtag_callback_t f, jtag_callback_data_t data0, jtag_callback_data_t data1, jtag_callback_data_t data2, jtag_callback_data_t data3); void jtag_add_dr_out(struct jtag_tap *tap, int num_fields, const int *num_bits, const uint32_t *value, tap_state_t end_state); void jtag_add_callback4(jtag_callback_t f, jtag_callback_data_t data0, jtag_callback_data_t data1, jtag_callback_data_t data2, jtag_callback_data_t data3); #endif /* MINIDRIVER_IMP_H */ openocd-0.7.0/src/jtag/drivers/libusb1_common.h0000644000175000001440000000611012137151331016331 00000000000000/*************************************************************************** * Copyright (C) 2009 by Zachary T Welch * * * * Copyright (C) 2011 by Mauro Gamba * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef JTAG_LIBUSB_COMMON_H #define JTAG_LIBUSB_COMMON_H #include #define jtag_libusb_device libusb_device #define jtag_libusb_device_handle libusb_device_handle #define jtag_libusb_device_descriptor libusb_device_descriptor #define jtag_libusb_interface libusb_interface #define jtag_libusb_interface_descriptor libusb_interface_descriptor #define jtag_libusb_endpoint_descriptor libusb_endpoint_descriptor #define jtag_libusb_config_descriptor libusb_config_descriptor #define jtag_libusb_reset_device(dev) libusb_reset_device(dev) #define jtag_libusb_get_device(devh) libusb_get_device(devh) static inline int jtag_libusb_claim_interface(jtag_libusb_device_handle *devh, int iface) { return libusb_claim_interface(devh, iface); }; int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[], struct jtag_libusb_device_handle **out); void jtag_libusb_close(jtag_libusb_device_handle *dev); int jtag_libusb_control_transfer(jtag_libusb_device_handle *dev, uint8_t requestType, uint8_t request, uint16_t wValue, uint16_t wIndex, char *bytes, uint16_t size, unsigned int timeout); int jtag_libusb_bulk_write(struct jtag_libusb_device_handle *dev, int ep, char *bytes, int size, int timeout); int jtag_libusb_bulk_read(struct jtag_libusb_device_handle *dev, int ep, char *bytes, int size, int timeout); int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh, int configuration); int jtag_libusb_get_endpoints(struct jtag_libusb_device *udev, unsigned int *usb_read_ep, unsigned int *usb_write_ep); #endif /* JTAG_USB_COMMON_H */ openocd-0.7.0/src/jtag/drivers/rlink_speed_table.c0000644000175000001440000001311212134336410017061 00000000000000/* This file was created automatically by ../../../tools/rlink_make_speed_table/rlink_make_speed_table.pl. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "rlink.h" #include "rlink_st7.h" static const uint8_t dtc_64[] = { 0, 2, 68, 84, 67, 2, 13, 160, 176, 151, 147, 182, 141, 152, 177, 129, 148, 191, 143, 142, 5, 3, 0, 0, 0, 2, 68, 84, 67, 4, 0, 192, 5, 15, 0, 42, 42, 42, 73, 0, 88, 0, 160, 189, 0, 0, 0, 0, 106, 9, 1, 8, 22, 100, 111, 119, 110, 108, 111, 97, 100, 2, 226, 7, 219, 39, 137, 51, 172, 130, 192, 96, 175, 191, 130, 217, 128, 57, 69, 177, 159, 179, 68, 178, 159, 193, 133, 153, 176, 159, 130, 132, 135, 164, 134, 51, 129, 60, 223, 9, 98, 128, 177, 129, 96, 201, 160, 130, 201, 51, 137, 201, 57, 68, 160, 176, 67, 219, 39, 154, 201, 40, 69, 219, 39, 150, 17, 27, 205, 51, 43, 99, 60, 118, 193, 96, 201, 160, 130, 24, 205, 51, 43, 99, 218, 156, 47, 60, 105, 193, 96, 201, 160, 138, 166, 178, 136, 160, 183, 139, 86, 202, 8, 2, 36, 138, 105, 193, 96, 201, 160, 43, 139, 167, 181, 136, 70, 177, 147, 67, 193, 96, 219, 39, 131, 161, 176, 130, 195, 53, 131, 178, 10, 66, 176, 151, 60, 97, 58, 151, 215, 2, 40, 66, 1, 0, 160, 185, 130, 60, 97, 203, 130, 60, 194, 139, 127, 195, 53, 156, 47, 200, 96, 201, 56, 177, 66, 176, 147, 201, 57, 168, 66, 160, 38, 155, 160, 176, 139, 171, 182, 136, 167, 183, 96, 201, 59, 66, 46, 193, 151, 96, 201, 160, 139, 219, 39, 131, 160, 191, 130, 195, 53, 131, 177, 10, 66, 176, 147, 151, 0, 60, 97, 58, 151, 0, 160, 185, 130, 60, 97, 203, 8, 2, 36, 139, 124, 193, 151, 96 }; static const uint8_t dtc_11[] = { 0, 2, 68, 84, 67, 2, 13, 160, 176, 151, 147, 182, 141, 152, 177, 129, 148, 188, 143, 142, 5, 3, 0, 0, 0, 2, 68, 84, 67, 4, 0, 192, 5, 15, 0, 42, 42, 42, 73, 0, 88, 0, 154, 183, 0, 0, 0, 0, 106, 9, 1, 8, 22, 100, 111, 119, 110, 108, 111, 97, 100, 2, 213, 7, 219, 39, 137, 51, 172, 130, 192, 96, 175, 191, 130, 217, 128, 57, 69, 177, 159, 179, 68, 178, 159, 193, 133, 153, 176, 159, 130, 132, 135, 164, 134, 51, 129, 60, 223, 9, 98, 128, 177, 129, 96, 201, 160, 130, 201, 51, 137, 201, 57, 68, 160, 176, 67, 219, 39, 154, 201, 40, 69, 219, 39, 150, 17, 27, 205, 51, 43, 99, 60, 118, 193, 96, 201, 160, 130, 24, 205, 51, 43, 99, 218, 156, 47, 60, 105, 193, 96, 201, 160, 138, 166, 178, 136, 160, 183, 139, 86, 202, 8, 2, 36, 138, 105, 193, 96, 201, 160, 43, 139, 167, 181, 136, 70, 177, 147, 67, 193, 96, 219, 39, 131, 195, 53, 131, 178, 10, 66, 176, 151, 0, 0, 0, 0, 0, 58, 151, 215, 2, 40, 66, 1, 203, 130, 60, 194, 139, 121, 195, 53, 156, 47, 200, 96, 201, 56, 177, 66, 176, 147, 201, 57, 168, 66, 160, 38, 155, 160, 176, 139, 171, 176, 136, 167, 183, 96, 201, 59, 66, 46, 193, 151, 96, 201, 160, 139, 219, 39, 131, 195, 53, 131, 177, 10, 66, 176, 147, 151, 0, 0, 0, 0, 0, 58, 151, 203, 8, 2, 36, 139, 117, 193, 151, 96 }; static const uint8_t dtc_8[] = { 0, 2, 68, 84, 67, 2, 13, 160, 176, 151, 147, 182, 141, 152, 177, 129, 148, 187, 143, 142, 5, 3, 0, 0, 0, 2, 68, 84, 67, 4, 0, 192, 5, 15, 0, 42, 42, 42, 73, 0, 88, 0, 152, 181, 0, 0, 0, 0, 106, 9, 1, 8, 22, 100, 111, 119, 110, 108, 111, 97, 100, 2, 209, 7, 219, 39, 137, 51, 172, 130, 192, 96, 175, 191, 130, 217, 128, 57, 69, 177, 159, 179, 68, 178, 159, 193, 133, 153, 176, 159, 130, 132, 135, 164, 134, 51, 129, 60, 223, 9, 98, 128, 177, 129, 96, 201, 160, 130, 201, 51, 137, 201, 57, 68, 160, 176, 67, 219, 39, 154, 201, 40, 69, 219, 39, 150, 17, 27, 205, 51, 43, 99, 60, 118, 193, 96, 201, 160, 130, 24, 205, 51, 43, 99, 218, 156, 47, 60, 105, 193, 96, 201, 160, 138, 166, 178, 136, 160, 183, 139, 86, 202, 8, 2, 36, 138, 105, 193, 96, 201, 160, 43, 139, 167, 181, 136, 70, 177, 147, 67, 193, 96, 219, 39, 131, 195, 53, 131, 178, 10, 66, 176, 151, 0, 0, 0, 58, 151, 215, 2, 40, 66, 1, 203, 130, 60, 194, 139, 119, 195, 53, 156, 47, 200, 96, 201, 56, 177, 66, 176, 147, 201, 57, 168, 66, 160, 38, 155, 160, 176, 139, 170, 190, 136, 167, 183, 96, 201, 59, 66, 46, 193, 151, 96, 201, 160, 139, 219, 39, 131, 195, 53, 131, 177, 10, 66, 176, 147, 151, 0, 0, 0, 58, 151, 203, 8, 2, 36, 139, 115, 193, 151, 96 }; static const uint8_t dtc_2[] = { 0, 2, 68, 84, 67, 2, 14, 160, 176, 151, 147, 182, 141, 152, 177, 129, 148, 186, 143, 185, 142, 5, 3, 0, 0, 0, 2, 68, 84, 67, 4, 0, 192, 5, 15, 0, 42, 42, 42, 73, 0, 88, 0, 149, 178, 0, 0, 0, 0, 106, 9, 1, 8, 22, 100, 111, 119, 110, 108, 111, 97, 100, 2, 203, 7, 219, 39, 137, 51, 172, 130, 192, 96, 175, 191, 130, 217, 128, 57, 69, 177, 159, 179, 68, 178, 159, 193, 133, 153, 176, 159, 130, 132, 135, 164, 134, 51, 129, 60, 223, 9, 98, 128, 177, 129, 96, 201, 160, 130, 201, 51, 137, 201, 57, 68, 160, 176, 67, 219, 39, 154, 201, 40, 69, 219, 39, 150, 17, 27, 205, 51, 43, 99, 60, 118, 193, 96, 201, 160, 130, 24, 205, 51, 43, 99, 218, 156, 47, 60, 105, 193, 96, 201, 160, 138, 166, 178, 136, 160, 183, 139, 86, 202, 8, 2, 36, 138, 105, 193, 96, 201, 160, 43, 139, 167, 181, 136, 70, 177, 147, 67, 193, 96, 219, 39, 131, 195, 53, 131, 178, 10, 66, 176, 151, 58, 151, 215, 2, 40, 66, 1, 203, 130, 60, 194, 139, 116, 195, 53, 156, 47, 200, 96, 201, 56, 177, 66, 176, 147, 201, 57, 168, 66, 160, 38, 155, 160, 176, 139, 170, 187, 136, 167, 183, 96, 201, 59, 66, 46, 193, 151, 96, 201, 160, 139, 219, 39, 131, 195, 53, 131, 177, 10, 66, 176, 147, 151, 58, 151, 203, 8, 2, 36, 139, 112, 193, 151, 96 }; const struct rlink_speed_table rlink_speed_table[] = {{ dtc_64, sizeof(dtc_64), (ST7_FOSC * 2) / (1000 * 64), 64 }, { dtc_11, sizeof(dtc_11), (ST7_FOSC * 2) / (1000 * 11), 11 }, { dtc_8, sizeof(dtc_8), (ST7_FOSC * 2) / (1000 * 8), 8 }, { dtc_2, sizeof(dtc_2), (ST7_FOSC * 2) / (1000 * 2), 2 } }; const size_t rlink_speed_table_size = ARRAY_SIZE(rlink_speed_table); openocd-0.7.0/src/jtag/drivers/rlink.c0000644000175000001440000011400712134336410014537 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 Rob Brown, Lou Deluxe * * rob@cobbleware.com, lou.openocd012@fixit.nospammail.net * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* project specific includes */ #include #include #include "rlink.h" #include "rlink_st7.h" #include "rlink_ep1_cmd.h" #include "rlink_dtc_cmd.h" #include "usb_common.h" /* This feature is made useless by running the DTC all the time. When automatic, the LED is on *whenever the DTC is running. Otherwise, USB messages are sent to turn it on and off. */ #undef AUTOMATIC_BUSY_LED /* This feature may require derating the speed due to reduced hold time. */ #undef USE_HARDWARE_SHIFTER_FOR_TMS #define INTERFACE_NAME "RLink" #define USB_IDVENDOR (0x138e) #define USB_IDPRODUCT (0x9000) #define USB_EP1OUT_ADDR (0x01) #define USB_EP1OUT_SIZE (16) #define USB_EP1IN_ADDR (USB_EP1OUT_ADDR | 0x80) #define USB_EP1IN_SIZE (USB_EP1OUT_SIZE) #define USB_EP2OUT_ADDR (0x02) #define USB_EP2OUT_SIZE (64) #define USB_EP2IN_ADDR (USB_EP2OUT_ADDR | 0x80) #define USB_EP2IN_SIZE (USB_EP2OUT_SIZE) #define USB_EP2BANK_SIZE (512) #define USB_TIMEOUT_MS (3 * 1000) #define DTC_STATUS_POLL_BYTE (ST7_USB_BUF_EP0OUT + 0xff) #define ST7_PD_NBUSY_LED ST7_PD0 #define ST7_PD_NRUN_LED ST7_PD1 /* low enables VPP at adapter header, high connects it to GND instead */ #define ST7_PD_VPP_SEL ST7_PD6 /* low: VPP = 12v, high: VPP <= 5v */ #define ST7_PD_VPP_SHDN ST7_PD7 /* These pins are connected together */ #define ST7_PE_ADAPTER_SENSE_IN ST7_PE3 #define ST7_PE_ADAPTER_SENSE_OUT ST7_PE4 /* Symbolic mapping between port pins and numbered IO lines */ #define ST7_PA_IO1 ST7_PA1 #define ST7_PA_IO2 ST7_PA2 #define ST7_PA_IO4 ST7_PA4 #define ST7_PA_IO8 ST7_PA6 #define ST7_PA_IO10 ST7_PA7 #define ST7_PB_IO5 ST7_PB5 #define ST7_PC_IO9 ST7_PC1 #define ST7_PC_IO3 ST7_PC2 #define ST7_PC_IO7 ST7_PC3 #define ST7_PE_IO6 ST7_PE5 /* Symbolic mapping between numbered IO lines and adapter signals */ #define ST7_PA_RTCK ST7_PA_IO0 #define ST7_PA_NTRST ST7_PA_IO1 #define ST7_PC_TDI ST7_PC_IO3 #define ST7_PA_DBGRQ ST7_PA_IO4 #define ST7_PB_NSRST ST7_PB_IO5 #define ST7_PE_TMS ST7_PE_IO6 #define ST7_PC_TCK ST7_PC_IO7 #define ST7_PC_TDO ST7_PC_IO9 #define ST7_PA_DBGACK ST7_PA_IO10 static usb_dev_handle *pHDev; /* * ep1 commands are up to USB_EP1OUT_SIZE bytes in length. * This function takes care of zeroing the unused bytes before sending the packet. * Any reply packet is not handled by this function. */ static int ep1_generic_commandl(usb_dev_handle *pHDev_param, size_t length, ...) { uint8_t usb_buffer[USB_EP1OUT_SIZE]; uint8_t *usb_buffer_p; va_list ap; int usb_ret; if (length > sizeof(usb_buffer)) length = sizeof(usb_buffer); usb_buffer_p = usb_buffer; va_start(ap, length); while (length > 0) { *usb_buffer_p++ = va_arg(ap, int); length--; } memset( usb_buffer_p, 0, sizeof(usb_buffer) - (usb_buffer_p - usb_buffer) ); usb_ret = usb_bulk_write( pHDev_param, USB_EP1OUT_ADDR, (char *)usb_buffer, sizeof(usb_buffer), USB_TIMEOUT_MS ); return usb_ret; } #if 0 static ssize_t ep1_memory_read( usb_dev_handle *pHDev, uint16_t addr, size_t length, uint8_t *buffer) { uint8_t usb_buffer[USB_EP1OUT_SIZE]; int usb_ret; size_t remain; ssize_t count; usb_buffer[0] = EP1_CMD_MEMORY_READ; memset( usb_buffer + 4, 0, sizeof(usb_buffer) - 4 ); remain = length; count = 0; while (remain) { if (remain > sizeof(usb_buffer)) length = sizeof(usb_buffer); else length = remain; usb_buffer[1] = addr >> 8; usb_buffer[2] = addr; usb_buffer[3] = length; usb_ret = usb_bulk_write( pHDev, USB_EP1OUT_ADDR, usb_buffer, sizeof(usb_buffer), USB_TIMEOUT_MS ); if (usb_ret < sizeof(usb_buffer)) break; usb_ret = usb_bulk_read( pHDev, USB_EP1IN_ADDR, buffer, length, USB_TIMEOUT_MS ); if (usb_ret < length) break; addr += length; buffer += length; count += length; remain -= length; } return count; } #endif static ssize_t ep1_memory_write(usb_dev_handle *pHDev_param, uint16_t addr, size_t length, uint8_t const *buffer) { uint8_t usb_buffer[USB_EP1OUT_SIZE]; int usb_ret; size_t remain; ssize_t count; usb_buffer[0] = EP1_CMD_MEMORY_WRITE; remain = length; count = 0; while (remain) { if (remain > (sizeof(usb_buffer) - 4)) length = (sizeof(usb_buffer) - 4); else length = remain; usb_buffer[1] = addr >> 8; usb_buffer[2] = addr; usb_buffer[3] = length; memcpy( usb_buffer + 4, buffer, length ); memset( usb_buffer + 4 + length, 0, sizeof(usb_buffer) - 4 - length ); usb_ret = usb_bulk_write( pHDev_param, USB_EP1OUT_ADDR, (char *)usb_buffer, sizeof(usb_buffer), USB_TIMEOUT_MS ); if ((size_t)usb_ret < sizeof(usb_buffer)) break; addr += length; buffer += length; count += length; remain -= length; } return count; } #if 0 static ssize_t ep1_memory_writel(usb_dev_handle *pHDev, uint16_t addr, size_t length, ...) { uint8_t buffer[USB_EP1OUT_SIZE - 4]; uint8_t *buffer_p; va_list ap; size_t remain; if (length > sizeof(buffer)) length = sizeof(buffer); remain = length; buffer_p = buffer; va_start(ap, length); while (remain > 0) { *buffer_p++ = va_arg(ap, int); remain--; } return ep1_memory_write(pHDev, addr, length, buffer); } #endif #define DTCLOAD_COMMENT (0) #define DTCLOAD_ENTRY (1) #define DTCLOAD_LOAD (2) #define DTCLOAD_RUN (3) #define DTCLOAD_LUT_START (4) #define DTCLOAD_LUT (5) #define DTC_LOAD_BUFFER ST7_USB_BUF_EP2UIDO /* This gets set by the DTC loader */ static uint8_t dtc_entry_download; /* The buffer is specially formatted to represent a valid image to load into the DTC. */ static int dtc_load_from_buffer(usb_dev_handle *pHDev_param, const uint8_t *buffer, size_t length) { struct header_s { uint8_t type; uint8_t length; }; int usb_err; struct header_s *header; uint8_t lut_start = 0xc0; dtc_entry_download = 0; /* Stop the DTC before loading anything. */ usb_err = ep1_generic_commandl( pHDev_param, 1, EP1_CMD_DTC_STOP ); if (usb_err < 0) return usb_err; while (length) { if (length < sizeof(*header)) { LOG_ERROR("Malformed DTC image"); exit(1); } header = (struct header_s *)buffer; buffer += sizeof(*header); length -= sizeof(*header); if (length < (size_t)header->length + 1) { LOG_ERROR("Malformed DTC image"); exit(1); } switch (header->type) { case DTCLOAD_COMMENT: break; case DTCLOAD_ENTRY: /* store entry addresses somewhere */ if (!strncmp("download", (char *)buffer + 1, 8)) dtc_entry_download = buffer[0]; break; case DTCLOAD_LOAD: /* Send the DTC program to ST7 RAM. */ usb_err = ep1_memory_write( pHDev_param, DTC_LOAD_BUFFER, header->length + 1, buffer ); if (usb_err < 0) return usb_err; /* Load it into the DTC. */ usb_err = ep1_generic_commandl( pHDev_param, 3, EP1_CMD_DTC_LOAD, (DTC_LOAD_BUFFER >> 8), DTC_LOAD_BUFFER ); if (usb_err < 0) return usb_err; break; case DTCLOAD_RUN: usb_err = ep1_generic_commandl( pHDev_param, 3, EP1_CMD_DTC_CALL, buffer[0], EP1_CMD_DTC_WAIT ); if (usb_err < 0) return usb_err; break; case DTCLOAD_LUT_START: lut_start = buffer[0]; break; case DTCLOAD_LUT: usb_err = ep1_memory_write( pHDev_param, ST7_USB_BUF_EP0OUT + lut_start, header->length + 1, buffer ); if (usb_err < 0) return usb_err; break; default: LOG_ERROR("Invalid DTC image record type: 0x%02x", header->type); exit(1); break; } buffer += (header->length + 1); length -= (header->length + 1); } return 0; } /* * Start the DTC running in download mode (waiting for 512 byte command packets on ep2). */ static int dtc_start_download(void) { int usb_err; uint8_t ep2txr; /* set up for download mode and make sure EP2 is set up to transmit */ usb_err = ep1_generic_commandl( pHDev, 7, EP1_CMD_DTC_STOP, EP1_CMD_SET_UPLOAD, EP1_CMD_SET_DOWNLOAD, EP1_CMD_MEMORY_READ, /* read EP2TXR for its data toggle */ ST7_EP2TXR >> 8, ST7_EP2TXR, 1 ); if (usb_err < 0) return usb_err; /* read back ep2txr */ usb_err = usb_bulk_read( pHDev, USB_EP1IN_ADDR, (char *)&ep2txr, 1, USB_TIMEOUT_MS ); if (usb_err < 0) return usb_err; usb_err = ep1_generic_commandl( pHDev, 13, EP1_CMD_MEMORY_WRITE, /* preinitialize poll byte */ DTC_STATUS_POLL_BYTE >> 8, DTC_STATUS_POLL_BYTE, 1, 0x00, EP1_CMD_MEMORY_WRITE, /* set EP2IN to return data */ ST7_EP2TXR >> 8, ST7_EP2TXR, 1, (ep2txr & ST7_EP2TXR_DTOG_TX) | ST7_EP2TXR_STAT_VALID, EP1_CMD_DTC_CALL, /* start running the DTC */ dtc_entry_download, EP1_CMD_DTC_GET_CACHED_STATUS ); if (usb_err < 0) return usb_err; /* wait for completion */ usb_err = usb_bulk_read( pHDev, USB_EP1IN_ADDR, (char *)&ep2txr, 1, USB_TIMEOUT_MS ); return usb_err; } static int dtc_run_download( usb_dev_handle *pHDev_param, uint8_t *command_buffer, int command_buffer_size, uint8_t *reply_buffer, int reply_buffer_size ) { char dtc_status; int usb_err; int i; LOG_DEBUG("%d/%d", command_buffer_size, reply_buffer_size); usb_err = usb_bulk_write( pHDev_param, USB_EP2OUT_ADDR, (char *)command_buffer, USB_EP2BANK_SIZE, USB_TIMEOUT_MS ); if (usb_err < 0) return usb_err; /* Wait for DTC to finish running command buffer */ for (i = 50;; ) { usb_err = ep1_generic_commandl( pHDev_param, 4, EP1_CMD_MEMORY_READ, DTC_STATUS_POLL_BYTE >> 8, DTC_STATUS_POLL_BYTE, 1 ); if (usb_err < 0) return usb_err; usb_err = usb_bulk_read( pHDev_param, USB_EP1IN_ADDR, &dtc_status, 1, USB_TIMEOUT_MS ); if (usb_err < 0) return usb_err; if (dtc_status & 0x01) break; if (!--i) { LOG_ERROR("too many retries waiting for DTC status"); return -ETIMEDOUT; } } if (reply_buffer && reply_buffer_size) { usb_err = usb_bulk_read( pHDev_param, USB_EP2IN_ADDR, (char *)reply_buffer, reply_buffer_size, USB_TIMEOUT_MS ); if (usb_err < reply_buffer_size) { LOG_ERROR("Read of endpoint 2 returned %d, expected %d", usb_err, reply_buffer_size ); return usb_err; } } return usb_err; } /* * The dtc reply queue is a singly linked list that describes what to do * with the reply packet that comes from the DTC. Only SCAN_IN and SCAN_IO generate * these entries. */ struct dtc_reply_queue_entry { struct dtc_reply_queue_entry *next; struct jtag_command *cmd; /* the command that resulted in this entry */ struct { uint8_t *buffer; /* the scan buffer */ int size; /* size of the scan buffer in bits */ int offset; /* how many bits were already done before this? */ int length; /* how many bits are processed in this operation? */ enum scan_type type; /* SCAN_IN/SCAN_OUT/SCAN_IO */ } scan; }; /* * The dtc_queue consists of a buffer of pending commands and a reply queue. * rlink_scan and tap_state_run add to the command buffer and maybe to the reply queue. */ static struct { struct dtc_reply_queue_entry *rq_head; struct dtc_reply_queue_entry *rq_tail; uint32_t cmd_index; uint32_t reply_index; uint8_t cmd_buffer[USB_EP2BANK_SIZE]; } dtc_queue; /* * The tap state queue is for accumulating TAP state changes wiithout needlessly * flushing the dtc_queue. When it fills or is run, it adds the accumulated bytes to * the dtc_queue. */ static struct { uint32_t length; uint32_t buffer; } tap_state_queue; static int dtc_queue_init(void) { dtc_queue.rq_head = NULL; dtc_queue.rq_tail = NULL; dtc_queue.cmd_index = 0; dtc_queue.reply_index = 0; return 0; } static inline struct dtc_reply_queue_entry *dtc_queue_enqueue_reply( enum scan_type type, uint8_t *buffer, int size, int offset, int length, struct jtag_command *cmd) { struct dtc_reply_queue_entry *rq_entry; rq_entry = malloc(sizeof(struct dtc_reply_queue_entry)); if (rq_entry != NULL) { rq_entry->scan.type = type; rq_entry->scan.buffer = buffer; rq_entry->scan.size = size; rq_entry->scan.offset = offset; rq_entry->scan.length = length; rq_entry->cmd = cmd; rq_entry->next = NULL; if (dtc_queue.rq_head == NULL) dtc_queue.rq_head = rq_entry; else dtc_queue.rq_tail->next = rq_entry; dtc_queue.rq_tail = rq_entry; } return rq_entry; } /* * Running the queue means that any pending command buffer is run * and any reply data dealt with. The command buffer is then cleared for subsequent processing. * The queue is automatically run by append when it is necessary to get space for the append. */ static int dtc_queue_run(void) { struct dtc_reply_queue_entry *rq_p, *rq_next; int retval; int usb_err; int bit_cnt; int x; uint8_t *dtc_p, *tdo_p; uint8_t dtc_mask, tdo_mask; uint8_t reply_buffer[USB_EP2IN_SIZE]; assert((dtc_queue.rq_head != 0) == (dtc_queue.reply_index > 0)); assert(dtc_queue.cmd_index < USB_EP2BANK_SIZE); assert(dtc_queue.reply_index <= USB_EP2IN_SIZE); retval = ERROR_OK; if (dtc_queue.cmd_index < 1) return retval; dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = DTC_CMD_STOP; usb_err = dtc_run_download(pHDev, dtc_queue.cmd_buffer, dtc_queue.cmd_index, reply_buffer, sizeof(reply_buffer) ); if (usb_err < 0) { LOG_ERROR("dtc_run_download: %s", usb_strerror()); exit(1); } if (dtc_queue.rq_head != NULL) { /* process the reply, which empties the reply queue and frees its entries */ dtc_p = reply_buffer; /* The rigamarole with the masks and doing it bit-by-bit is due to the fact that the *scan buffer is LSb-first and the DTC code is MSb-first for hardware reasons. It *was that or craft a function to do the reversal, and that wouldn't work with *bit-stuffing (supplying extra bits to use mostly byte operations), or any other *scheme which would throw the byte alignment off. */ for ( rq_p = dtc_queue.rq_head; rq_p != NULL; rq_p = rq_next ) { tdo_p = rq_p->scan.buffer + (rq_p->scan.offset / 8); tdo_mask = 1 << (rq_p->scan.offset % 8); bit_cnt = rq_p->scan.length; if (bit_cnt >= 8) { /* bytes */ dtc_mask = 1 << (8 - 1); for ( ; bit_cnt; bit_cnt-- ) { if (*dtc_p & dtc_mask) *tdo_p |= tdo_mask; else *tdo_p &= ~tdo_mask; dtc_mask >>= 1; if (dtc_mask == 0) { dtc_p++; dtc_mask = 1 << (8 - 1); } tdo_mask <<= 1; if (tdo_mask == 0) { tdo_p++; tdo_mask = 1; } } } else { /* extra bits or last bit */ x = *dtc_p++; if ((rq_p->scan.type == SCAN_IN) && ( rq_p->scan.offset != rq_p->scan.size - 1 )) { /* extra bits were sent as a full byte with padding on the *end */ dtc_mask = 1 << (8 - 1); } else dtc_mask = 1 << (bit_cnt - 1); for ( ; bit_cnt; bit_cnt-- ) { if (x & dtc_mask) *tdo_p |= tdo_mask; else *tdo_p &= ~tdo_mask; dtc_mask >>= 1; tdo_mask <<= 1; if (tdo_mask == 0) { tdo_p++; tdo_mask = 1; } } } if ((rq_p->scan.offset + rq_p->scan.length) >= rq_p->scan.size) { /* feed scan buffer back into openocd and free it */ if (jtag_read_buffer(rq_p->scan.buffer, rq_p->cmd->cmd.scan) != ERROR_OK) retval = ERROR_JTAG_QUEUE_FAILED; free(rq_p->scan.buffer); } rq_next = rq_p->next; free(rq_p); } dtc_queue.rq_head = NULL; dtc_queue.rq_tail = NULL; } /* reset state for new appends */ dtc_queue.cmd_index = 0; dtc_queue.reply_index = 0; return retval; } /* runs the queue if it cannot take reserved_cmd bytes of command data * or reserved_reply bytes of reply data */ static int dtc_queue_run_if_full(int reserved_cmd, int reserved_reply) { /* reserve one additional byte for the STOP cmd appended during run */ if (dtc_queue.cmd_index + reserved_cmd + 1 > USB_EP2BANK_SIZE) return dtc_queue_run(); if (dtc_queue.reply_index + reserved_reply > USB_EP2IN_SIZE) return dtc_queue_run(); return ERROR_OK; } static int tap_state_queue_init(void) { tap_state_queue.length = 0; tap_state_queue.buffer = 0; return 0; } static int tap_state_queue_run(void) { int i; int bits; uint8_t byte_param; int retval; retval = 0; if (!tap_state_queue.length) return retval; bits = 1; byte_param = 0; for (i = tap_state_queue.length; i--; ) { byte_param <<= 1; if (tap_state_queue.buffer & 1) byte_param |= 1; if ((bits >= 8) || !i) { byte_param <<= (8 - bits); /* make sure there's room for two cmd bytes */ dtc_queue_run_if_full(2, 0); #ifdef USE_HARDWARE_SHIFTER_FOR_TMS if (bits == 8) { dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = DTC_CMD_SHIFT_TMS_BYTES(1); } else { #endif dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = DTC_CMD_SHIFT_TMS_BITS(bits); #ifdef USE_HARDWARE_SHIFTER_FOR_TMS } #endif dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = byte_param; byte_param = 0; bits = 1; } else bits++; tap_state_queue.buffer >>= 1; } retval = tap_state_queue_init(); return retval; } static int tap_state_queue_append(uint8_t tms) { int retval; if (tap_state_queue.length >= sizeof(tap_state_queue.buffer) * 8) { retval = tap_state_queue_run(); if (retval != 0) return retval; } if (tms) tap_state_queue.buffer |= (1 << tap_state_queue.length); tap_state_queue.length++; return 0; } static void rlink_end_state(tap_state_t state) { if (tap_is_state_stable(state)) tap_set_end_state(state); else { LOG_ERROR("BUG: %i is not a valid end state", state); exit(-1); } } static void rlink_state_move(void) { int i = 0, tms = 0; uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state()); int tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); for (i = 0; i < tms_count; i++) { tms = (tms_scan >> i) & 1; tap_state_queue_append(tms); } tap_set_state(tap_get_end_state()); } static void rlink_path_move(struct pathmove_command *cmd) { int num_states = cmd->num_states; int state_count; int tms = 0; state_count = 0; while (num_states) { if (tap_state_transition(tap_get_state(), false) == cmd->path[state_count]) tms = 0; else if (tap_state_transition(tap_get_state(), true) == cmd->path[state_count]) tms = 1; else { LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_name(tap_get_state()), tap_state_name(cmd->path[state_count])); exit(-1); } tap_state_queue_append(tms); tap_set_state(cmd->path[state_count]); state_count++; num_states--; } tap_set_end_state(tap_get_state()); } static void rlink_runtest(int num_cycles) { int i; tap_state_t saved_end_state = tap_get_end_state(); /* only do a state_move when we're not already in RTI */ if (tap_get_state() != TAP_IDLE) { rlink_end_state(TAP_IDLE); rlink_state_move(); } /* execute num_cycles */ for (i = 0; i < num_cycles; i++) tap_state_queue_append(0); /* finish in end_state */ rlink_end_state(saved_end_state); if (tap_get_state() != tap_get_end_state()) rlink_state_move(); } /* (1) assert or (0) deassert reset lines */ static void rlink_reset(int trst, int srst) { uint8_t bitmap; int usb_err; /* Read port A for bit op */ usb_err = ep1_generic_commandl( pHDev, 4, EP1_CMD_MEMORY_READ, ST7_PADR >> 8, ST7_PADR, 1 ); if (usb_err < 0) { LOG_ERROR("%s", usb_strerror()); exit(1); } usb_err = usb_bulk_read( pHDev, USB_EP1IN_ADDR, (char *)&bitmap, 1, USB_TIMEOUT_MS ); if (usb_err < 1) { LOG_ERROR("%s", usb_strerror()); exit(1); } if (trst) bitmap &= ~ST7_PA_NTRST; else bitmap |= ST7_PA_NTRST; /* Write port A and read port B for bit op * port B has no OR, and we want to emulate open drain on NSRST, so we initialize DR to 0 *and assert NSRST by setting DDR to 1. */ usb_err = ep1_generic_commandl( pHDev, 9, EP1_CMD_MEMORY_WRITE, ST7_PADR >> 8, ST7_PADR, 1, bitmap, EP1_CMD_MEMORY_READ, ST7_PBDDR >> 8, ST7_PBDDR, 1 ); if (usb_err < 0) { LOG_ERROR("%s", usb_strerror()); exit(1); } usb_err = usb_bulk_read( pHDev, USB_EP1IN_ADDR, (char *)&bitmap, 1, USB_TIMEOUT_MS ); if (usb_err < 1) { LOG_ERROR("%s", usb_strerror()); exit(1); } if (srst) bitmap |= ST7_PB_NSRST; else bitmap &= ~ST7_PB_NSRST; /* write port B and read dummy to ensure completion before returning */ usb_err = ep1_generic_commandl( pHDev, 6, EP1_CMD_MEMORY_WRITE, ST7_PBDDR >> 8, ST7_PBDDR, 1, bitmap, EP1_CMD_DTC_GET_CACHED_STATUS ); if (usb_err < 0) { LOG_ERROR("%s", usb_strerror()); exit(1); } usb_err = usb_bulk_read( pHDev, USB_EP1IN_ADDR, (char *)&bitmap, 1, USB_TIMEOUT_MS ); if (usb_err < 1) { LOG_ERROR("%s", usb_strerror()); exit(1); } } static int rlink_scan(struct jtag_command *cmd, enum scan_type type, uint8_t *buffer, int scan_size) { bool ir_scan; tap_state_t saved_end_state; int byte_bits; int extra_bits; int chunk_bits; int chunk_bytes; int x; int tdi_bit_offset; uint8_t tdi_mask, *tdi_p; uint8_t dtc_mask; if (scan_size < 1) { LOG_ERROR("scan_size cannot be less than 1 bit"); exit(1); } ir_scan = cmd->cmd.scan->ir_scan; /* Move to the proper state before starting to shift TDI/TDO. */ if (!((!ir_scan && (tap_get_state() == TAP_DRSHIFT)) || (ir_scan && (tap_get_state() == TAP_IRSHIFT)))) { saved_end_state = tap_get_end_state(); rlink_end_state(ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT); rlink_state_move(); rlink_end_state(saved_end_state); } tap_state_queue_run(); #if 0 printf("scan_size = %d, type = 0x%x\n", scan_size, type); { int i; /* clear unused bits in scan buffer for ease of debugging * (it makes diffing output easier) */ buffer[scan_size / 8] &= ((1 << ((scan_size - 1) % 8) + 1) - 1); printf("before scan:"); for (i = 0; i < (scan_size + 7) / 8; i++) printf(" %02x", buffer[i]); printf("\n"); } #endif /* The number of bits that can be shifted as complete bytes */ byte_bits = (int)(scan_size - 1) / 8 * 8; /* The number of bits left over, not counting the last bit */ extra_bits = (scan_size - 1) - byte_bits; tdi_bit_offset = 0; tdi_p = buffer; tdi_mask = 1; if (extra_bits && (type == SCAN_OUT)) { /* Schedule any extra bits into the DTC command buffer, padding as needed * For SCAN_OUT, this comes before the full bytes so the (leading) padding bits will *fall off the end */ /* make sure there's room for two cmd bytes */ dtc_queue_run_if_full(2, 0); x = 0; dtc_mask = 1 << (extra_bits - 1); while (extra_bits--) { if (*tdi_p & tdi_mask) x |= dtc_mask; dtc_mask >>= 1; tdi_mask <<= 1; if (tdi_mask == 0) { tdi_p++; tdi_mask = 1; } } dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = DTC_CMD_SHIFT_TDI_BYTES(1); dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = x; } /* Loop scheduling full bytes into the DTC command buffer */ while (byte_bits) { /* make sure there's room for one (for in scans) or two cmd bytes and * at least one reply byte for in or inout scans*/ dtc_queue_run_if_full(type == SCAN_IN ? 1 : 2, type != SCAN_OUT ? 1 : 0); chunk_bits = byte_bits; /* we can only use up to 16 bytes at a time */ if (chunk_bits > (16 * 8)) chunk_bits = (16 * 8); if (type != SCAN_IN) { /* how much is there room for, considering stop and byte op? */ x = (sizeof(dtc_queue.cmd_buffer) - (dtc_queue.cmd_index + 1 + 1)) * 8; if (chunk_bits > x) chunk_bits = x; } if (type != SCAN_OUT) { /* how much is there room for in the reply buffer? */ x = (USB_EP2IN_SIZE - dtc_queue.reply_index) * 8; if (chunk_bits > x) chunk_bits = x; } /* so the loop will end */ byte_bits -= chunk_bits; if (type != SCAN_OUT) { if (dtc_queue_enqueue_reply( type, buffer, scan_size, tdi_bit_offset, chunk_bits, cmd ) == NULL) { LOG_ERROR("enqueuing DTC reply entry: %s", strerror(errno)); exit(1); } dtc_queue.reply_index += (chunk_bits + 7) / 8; tdi_bit_offset += chunk_bits; } /* chunk_bits is a multiple of 8, so there are no rounding issues. */ chunk_bytes = chunk_bits / 8; switch (type) { case SCAN_IN: x = DTC_CMD_SHIFT_TDO_BYTES(chunk_bytes); break; case SCAN_OUT: x = DTC_CMD_SHIFT_TDI_BYTES(chunk_bytes); break; default: x = DTC_CMD_SHIFT_TDIO_BYTES(chunk_bytes); break; } dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = x; if (type != SCAN_IN) { x = 0; dtc_mask = 1 << (8 - 1); while (chunk_bits--) { if (*tdi_p & tdi_mask) x |= dtc_mask; dtc_mask >>= 1; if (dtc_mask == 0) { dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = x; x = 0; dtc_mask = 1 << (8 - 1); } tdi_mask <<= 1; if (tdi_mask == 0) { tdi_p++; tdi_mask = 1; } } } } if (extra_bits && (type != SCAN_OUT)) { /* Schedule any extra bits into the DTC command buffer */ /* make sure there's room for one (for in scans) or two cmd bytes * and one reply byte */ dtc_queue_run_if_full(type == SCAN_IN ? 1 : 2, 1); if (dtc_queue_enqueue_reply( type, buffer, scan_size, tdi_bit_offset, extra_bits, cmd ) == NULL) { LOG_ERROR("enqueuing DTC reply entry: %s", strerror(errno)); exit(1); } dtc_queue.reply_index++; tdi_bit_offset += extra_bits; if (type == SCAN_IN) { dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = DTC_CMD_SHIFT_TDO_BYTES(1); } else { dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = DTC_CMD_SHIFT_TDIO_BITS(extra_bits); x = 0; dtc_mask = 1 << (8 - 1); while (extra_bits--) { if (*tdi_p & tdi_mask) x |= dtc_mask; dtc_mask >>= 1; tdi_mask <<= 1; if (tdi_mask == 0) { tdi_p++; tdi_mask = 1; } } dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = x; } } /* Schedule the last bit into the DTC command buffer */ /* make sure there's room for one cmd byte and one reply byte * for in or inout scans*/ dtc_queue_run_if_full(1, type == SCAN_OUT ? 0 : 1); if (type == SCAN_OUT) { dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = DTC_CMD_SHIFT_TMS_TDI_BIT_PAIR(1, (*tdi_p & tdi_mask), 0); } else { if (dtc_queue_enqueue_reply( type, buffer, scan_size, tdi_bit_offset, 1, cmd ) == NULL) { LOG_ERROR("enqueuing DTC reply entry: %s", strerror(errno)); exit(1); } dtc_queue.reply_index++; dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = DTC_CMD_SHIFT_TMS_TDI_BIT_PAIR(1, (*tdi_p & tdi_mask), 1); } /* Move to pause state */ tap_state_queue_append(0); tap_set_state(ir_scan ? TAP_IRPAUSE : TAP_DRPAUSE); if (tap_get_state() != tap_get_end_state()) rlink_state_move(); return 0; } static int rlink_execute_queue(void) { struct jtag_command *cmd = jtag_command_queue; /* currently processed command */ int scan_size; enum scan_type type; uint8_t *buffer; int retval, tmp_retval; /* return ERROR_OK, unless something goes wrong */ retval = ERROR_OK; #ifndef AUTOMATIC_BUSY_LED /* turn LED on */ ep1_generic_commandl(pHDev, 2, EP1_CMD_SET_PORTD_LEDS, ~(ST7_PD_NBUSY_LED) ); #endif while (cmd) { switch (cmd->type) { case JTAG_RUNTEST: case JTAG_TLR_RESET: case JTAG_PATHMOVE: case JTAG_SCAN: break; default: /* some events, such as resets, need a queue flush to ensure *consistency */ tap_state_queue_run(); dtc_queue_run(); break; } switch (cmd->type) { case JTAG_RESET: #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); #endif if ((cmd->cmd.reset->trst == 1) || (cmd->cmd.reset->srst && (jtag_get_reset_config() & RESET_SRST_PULLS_TRST))) tap_set_state(TAP_RESET); rlink_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); break; case JTAG_RUNTEST: #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); #endif if (cmd->cmd.runtest->end_state != -1) rlink_end_state(cmd->cmd.runtest->end_state); rlink_runtest(cmd->cmd.runtest->num_cycles); break; case JTAG_TLR_RESET: #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("statemove end in %i", cmd->cmd.statemove->end_state); #endif if (cmd->cmd.statemove->end_state != -1) rlink_end_state(cmd->cmd.statemove->end_state); rlink_state_move(); break; case JTAG_PATHMOVE: #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("pathmove: %i states, end in %i", cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); #endif rlink_path_move(cmd->cmd.pathmove); break; case JTAG_SCAN: #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("%s scan end in %i", (cmd->cmd.scan->ir_scan) ? "IR" : "DR", cmd->cmd.scan->end_state); #endif if (cmd->cmd.scan->end_state != -1) rlink_end_state(cmd->cmd.scan->end_state); scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); type = jtag_scan_type(cmd->cmd.scan); if (rlink_scan(cmd, type, buffer, scan_size) != ERROR_OK) retval = ERROR_FAIL; break; case JTAG_SLEEP: #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("sleep %i", cmd->cmd.sleep->us); #endif jtag_sleep(cmd->cmd.sleep->us); break; default: LOG_ERROR("BUG: unknown JTAG command type encountered"); exit(-1); } cmd = cmd->next; } /* Flush the DTC queue to make sure any pending reads have been done before exiting this *function */ tap_state_queue_run(); tmp_retval = dtc_queue_run(); if (tmp_retval != ERROR_OK) retval = tmp_retval; #ifndef AUTOMATIC_BUSY_LED /* turn LED onff */ ep1_generic_commandl(pHDev, 2, EP1_CMD_SET_PORTD_LEDS, ~0 ); #endif return retval; } /* Using an unindexed table because it is infrequently accessed and it is short. The table must be *in order of ascending speed (and descending prescaler), as it is scanned in reverse. */ static int rlink_speed(int speed) { int i; if (speed == 0) { /* fastest speed */ speed = rlink_speed_table[rlink_speed_table_size - 1].prescaler; } for (i = rlink_speed_table_size; i--; ) { if (rlink_speed_table[i].prescaler == speed) { if (dtc_load_from_buffer(pHDev, rlink_speed_table[i].dtc, rlink_speed_table[i].dtc_size) != 0) { LOG_ERROR( "An error occurred while trying to load DTC code for speed \"%d\".", speed); exit(1); } if (dtc_start_download() < 0) { LOG_ERROR("starting DTC: %s", usb_strerror()); exit(1); } return ERROR_OK; } } LOG_ERROR("%d is not a supported speed", speed); return ERROR_FAIL; } static int rlink_speed_div(int speed, int *khz) { int i; for (i = rlink_speed_table_size; i--; ) { if (rlink_speed_table[i].prescaler == speed) { *khz = rlink_speed_table[i].khz; return ERROR_OK; } } LOG_ERROR("%d is not a supported speed", speed); return ERROR_FAIL; } static int rlink_khz(int khz, int *speed) { int i; if (khz == 0) { LOG_ERROR("RCLK not supported"); return ERROR_FAIL; } for (i = rlink_speed_table_size; i--; ) { if (rlink_speed_table[i].khz <= khz) { *speed = rlink_speed_table[i].prescaler; return ERROR_OK; } } LOG_WARNING("The lowest supported JTAG speed is %d KHz", rlink_speed_table[0].khz); *speed = rlink_speed_table[0].prescaler; return ERROR_OK; } static int rlink_init(void) { int i, j, retries; uint8_t reply_buffer[USB_EP1IN_SIZE]; usb_init(); const uint16_t vids[] = { USB_IDVENDOR, 0 }; const uint16_t pids[] = { USB_IDPRODUCT, 0 }; if (jtag_usb_open(vids, pids, &pHDev) != ERROR_OK) return ERROR_FAIL; struct usb_device *dev = usb_device(pHDev); if (dev->descriptor.bNumConfigurations > 1) { LOG_ERROR("Whoops! NumConfigurations is not 1, don't know what to do..."); return ERROR_FAIL; } if (dev->config->bNumInterfaces > 1) { LOG_ERROR("Whoops! NumInterfaces is not 1, don't know what to do..."); return ERROR_FAIL; } LOG_DEBUG("Opened device, pHDev = %p", pHDev); /* usb_set_configuration required under win32 */ usb_set_configuration(pHDev, dev->config[0].bConfigurationValue); retries = 3; do { i = usb_claim_interface(pHDev, 0); if (i) { LOG_ERROR("usb_claim_interface: %s", usb_strerror()); #ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP j = usb_detach_kernel_driver_np(pHDev, 0); if (j) LOG_ERROR("detach kernel driver: %s", usb_strerror()); #endif } else { LOG_DEBUG("interface claimed!"); break; } } while (--retries); if (i) { LOG_ERROR("Initialisation failed."); return ERROR_FAIL; } if (usb_set_altinterface(pHDev, 0) != 0) { LOG_ERROR("Failed to set interface."); return ERROR_FAIL; } /* The device starts out in an unknown state on open. As such, * result reads time out, and it's not even known whether the * command was accepted. So, for this first command, we issue * it repeatedly until its response doesn't time out. Also, if * sending a command is going to time out, we find that out here. * * It must be possible to open the device in such a way that * this special magic isn't needed, but, so far, it escapes us. */ for (i = 0; i < 5; i++) { j = ep1_generic_commandl( pHDev, 1, EP1_CMD_GET_FWREV ); if (j < USB_EP1OUT_SIZE) { LOG_ERROR("USB write error: %s", usb_strerror()); return ERROR_FAIL; } j = usb_bulk_read( pHDev, USB_EP1IN_ADDR, (char *)reply_buffer, sizeof(reply_buffer), 200 ); if (j != -ETIMEDOUT) break; } if (j < (int)sizeof(reply_buffer)) { LOG_ERROR("USB read error: %s", usb_strerror()); return ERROR_FAIL; } LOG_DEBUG(INTERFACE_NAME " firmware version: %d.%d.%d", reply_buffer[0], reply_buffer[1], reply_buffer[2]); if ((reply_buffer[0] != 0) || (reply_buffer[1] != 0) || (reply_buffer[2] != 3)) LOG_WARNING( "The rlink device is not of the version that the developers have played with. It may or may not work."); /* Probe port E for adapter presence */ ep1_generic_commandl( pHDev, 16, EP1_CMD_MEMORY_WRITE, /* Drive sense pin with 0 */ ST7_PEDR >> 8, ST7_PEDR, 3, 0x00, /* DR */ ST7_PE_ADAPTER_SENSE_OUT, /* DDR */ ST7_PE_ADAPTER_SENSE_OUT, /* OR */ EP1_CMD_MEMORY_READ, /* Read back */ ST7_PEDR >> 8, ST7_PEDR, 1, EP1_CMD_MEMORY_WRITE, /* Drive sense pin with 1 */ ST7_PEDR >> 8, ST7_PEDR, 1, ST7_PE_ADAPTER_SENSE_OUT ); usb_bulk_read( pHDev, USB_EP1IN_ADDR, (char *)reply_buffer, 1, USB_TIMEOUT_MS ); if ((reply_buffer[0] & ST7_PE_ADAPTER_SENSE_IN) != 0) LOG_WARNING("target detection problem"); ep1_generic_commandl( pHDev, 11, EP1_CMD_MEMORY_READ, /* Read back */ ST7_PEDR >> 8, ST7_PEDR, 1, EP1_CMD_MEMORY_WRITE, /* float port E */ ST7_PEDR >> 8, ST7_PEDR, 3, 0x00, /* DR */ 0x00, /* DDR */ 0x00 /* OR */ ); usb_bulk_read( pHDev, USB_EP1IN_ADDR, (char *)reply_buffer, 1, USB_TIMEOUT_MS ); if ((reply_buffer[0] & ST7_PE_ADAPTER_SENSE_IN) == 0) LOG_WARNING("target not plugged in"); /* float ports A and B */ ep1_generic_commandl( pHDev, 11, EP1_CMD_MEMORY_WRITE, ST7_PADDR >> 8, ST7_PADDR, 2, 0x00, 0x00, EP1_CMD_MEMORY_WRITE, ST7_PBDDR >> 8, ST7_PBDDR, 1, 0x00 ); /* make sure DTC is stopped, set VPP control, set up ports A and B */ ep1_generic_commandl( pHDev, 14, EP1_CMD_DTC_STOP, EP1_CMD_SET_PORTD_VPP, ~(ST7_PD_VPP_SHDN), EP1_CMD_MEMORY_WRITE, ST7_PADR >> 8, ST7_PADR, 2, ((~(0)) & (ST7_PA_NTRST)), (ST7_PA_NTRST), /* port B has no OR, and we want to emulate open drain on NSRST, so we set DR to 0 *here and later assert NSRST by setting DDR bit to 1. */ EP1_CMD_MEMORY_WRITE, ST7_PBDR >> 8, ST7_PBDR, 1, 0x00 ); /* set LED updating mode and make sure they're unlit */ ep1_generic_commandl( pHDev, 3, #ifdef AUTOMATIC_BUSY_LED EP1_CMD_LEDUE_BUSY, #else EP1_CMD_LEDUE_NONE, #endif EP1_CMD_SET_PORTD_LEDS, ~0 ); tap_state_queue_init(); dtc_queue_init(); rlink_reset(0, 0); return ERROR_OK; } static int rlink_quit(void) { /* stop DTC and make sure LEDs are off */ ep1_generic_commandl( pHDev, 6, EP1_CMD_DTC_STOP, EP1_CMD_LEDUE_NONE, EP1_CMD_SET_PORTD_LEDS, ~0, EP1_CMD_SET_PORTD_VPP, ~0 ); usb_release_interface(pHDev, 0); usb_close(pHDev); return ERROR_OK; } struct jtag_interface rlink_interface = { .name = "rlink", .init = rlink_init, .quit = rlink_quit, .speed = rlink_speed, .speed_div = rlink_speed_div, .khz = rlink_khz, .execute_queue = rlink_execute_queue, }; openocd-0.7.0/src/jtag/drivers/ftdi.c0000644000175000001440000005671112134336410014355 00000000000000/************************************************************************** * Copyright (C) 2012 by Andreas Fritiofson * * andreas.fritiofson@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /** * @file * JTAG adapters based on the FT2232 full and high speed USB parts are * popular low cost JTAG debug solutions. Many FT2232 based JTAG adapters * are discrete, but development boards may integrate them as alternatives * to more capable (and expensive) third party JTAG pods. * * JTAG uses only one of the two communications channels ("MPSSE engines") * on these devices. Adapters based on FT4232 parts have four ports/channels * (A/B/C/D), instead of just two (A/B). * * Especially on development boards integrating one of these chips (as * opposed to discrete pods/dongles), the additional channels can be used * for a variety of purposes, but OpenOCD only uses one channel at a time. * * - As a USB-to-serial adapter for the target's console UART ... * which may be able to support ROM boot loaders that load initial * firmware images to flash (or SRAM). * * - On systems which support ARM's SWD in addition to JTAG, or instead * of it, that second port can be used for reading SWV/SWO trace data. * * - Additional JTAG links, e.g. to a CPLD or * FPGA. * * FT2232 based JTAG adapters are "dumb" not "smart", because most JTAG * request/response interactions involve round trips over the USB link. * A "smart" JTAG adapter has intelligence close to the scan chain, so it * can for example poll quickly for a status change (usually taking on the * order of microseconds not milliseconds) before beginning a queued * transaction which require the previous one to have completed. * * There are dozens of adapters of this type, differing in details which * this driver needs to understand. Those "layout" details are required * as part of FT2232 driver configuration. * * This code uses information contained in the MPSSE specification which was * found here: * http://www.ftdichip.com/Documents/AppNotes/AN2232C-01_MPSSE_Cmnd.pdf * Hereafter this is called the "MPSSE Spec". * * The datasheet for the ftdichip.com's FT2232D part is here: * http://www.ftdichip.com/Documents/DataSheets/DS_FT2232D.pdf * * Also note the issue with code 0x4b (clock data to TMS) noted in * http://developer.intra2net.com/mailarchive/html/libftdi/2009/msg00292.html * which can affect longer JTAG state paths. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* project specific includes */ #include #include #include #if IS_CYGWIN == 1 #include #endif #include /* FTDI access library includes */ #include "mpsse.h" #define JTAG_MODE (LSB_FIRST | POS_EDGE_IN | NEG_EDGE_OUT) static char *ftdi_device_desc; static char *ftdi_serial; static uint8_t ftdi_channel; #define MAX_USB_IDS 8 /* vid = pid = 0 marks the end of the list */ static uint16_t ftdi_vid[MAX_USB_IDS + 1] = { 0 }; static uint16_t ftdi_pid[MAX_USB_IDS + 1] = { 0 }; static struct mpsse_ctx *mpsse_ctx; struct signal { const char *name; uint16_t data_mask; uint16_t oe_mask; bool invert_data; bool invert_oe; struct signal *next; }; static struct signal *signals; static uint16_t output; static uint16_t direction; static struct signal *find_signal_by_name(const char *name) { for (struct signal *sig = signals; sig; sig = sig->next) { if (strcmp(name, sig->name) == 0) return sig; } return NULL; } static struct signal *create_signal(const char *name) { struct signal **psig = &signals; while (*psig) psig = &(*psig)->next; *psig = calloc(1, sizeof(**psig)); if (*psig) (*psig)->name = strdup(name); if ((*psig)->name == NULL) { free(*psig); *psig = NULL; } return *psig; } static int ftdi_set_signal(const struct signal *s, char value) { int retval; bool data; bool oe; if (s->data_mask == 0 && s->oe_mask == 0) { LOG_ERROR("interface doesn't provide signal '%s'", s->name); return ERROR_FAIL; } switch (value) { case '0': data = s->invert_data; oe = !s->invert_oe; break; case '1': if (s->data_mask == 0) { LOG_ERROR("interface can't drive '%s' high", s->name); return ERROR_FAIL; } data = !s->invert_data; oe = !s->invert_oe; break; case 'z': case 'Z': if (s->oe_mask == 0) { LOG_ERROR("interface can't tri-state '%s'", s->name); return ERROR_FAIL; } data = s->invert_data; oe = s->invert_oe; break; default: assert(0 && "invalid signal level specifier"); return ERROR_FAIL; } output = data ? output | s->data_mask : output & ~s->data_mask; if (s->oe_mask == s->data_mask) direction = oe ? direction | s->oe_mask : direction & ~s->oe_mask; else output = oe ? output | s->oe_mask : output & ~s->oe_mask; retval = mpsse_set_data_bits_low_byte(mpsse_ctx, output & 0xff, direction & 0xff); if (retval == ERROR_OK) retval = mpsse_set_data_bits_high_byte(mpsse_ctx, output >> 8, direction >> 8); if (retval != ERROR_OK) { LOG_ERROR("couldn't initialize FTDI GPIO"); return ERROR_JTAG_INIT_FAILED; } return ERROR_OK; } /** * Function move_to_state * moves the TAP controller from the current state to a * \a goal_state through a path given by tap_get_tms_path(). State transition * logging is performed by delegation to clock_tms(). * * @param goal_state is the destination state for the move. */ static int move_to_state(tap_state_t goal_state) { tap_state_t start_state = tap_get_state(); /* goal_state is 1/2 of a tuple/pair of states which allow convenient lookup of the required TMS pattern to move to this state from the start state. */ /* do the 2 lookups */ int tms_bits = tap_get_tms_path(start_state, goal_state); int tms_count = tap_get_tms_path_len(start_state, goal_state); DEBUG_JTAG_IO("start=%s goal=%s", tap_state_name(start_state), tap_state_name(goal_state)); /* Track state transitions step by step */ for (int i = 0; i < tms_count; i++) tap_set_state(tap_state_transition(tap_get_state(), (tms_bits >> i) & 1)); return mpsse_clock_tms_cs_out(mpsse_ctx, (uint8_t *)&tms_bits, 0, tms_count, false, JTAG_MODE); } static int ftdi_speed(int speed) { int retval; retval = mpsse_set_frequency(mpsse_ctx, speed); if (retval < 0) { LOG_ERROR("couldn't set FTDI TCK speed"); return retval; } return ERROR_OK; } static int ftdi_speed_div(int speed, int *khz) { *khz = speed / 1000; return ERROR_OK; } static int ftdi_khz(int khz, int *jtag_speed) { if (khz == 0 && !mpsse_is_high_speed(mpsse_ctx)) { LOG_DEBUG("RCLK not supported"); return ERROR_FAIL; } *jtag_speed = khz * 1000; return ERROR_OK; } static void ftdi_end_state(tap_state_t state) { if (tap_is_state_stable(state)) tap_set_end_state(state); else { LOG_ERROR("BUG: %s is not a stable end state", tap_state_name(state)); exit(-1); } } static int ftdi_execute_runtest(struct jtag_command *cmd) { int retval = ERROR_OK; int i; uint8_t zero = 0; DEBUG_JTAG_IO("runtest %i cycles, end in %s", cmd->cmd.runtest->num_cycles, tap_state_name(cmd->cmd.runtest->end_state)); if (tap_get_state() != TAP_IDLE) move_to_state(TAP_IDLE); /* TODO: Reuse ftdi_execute_stableclocks */ i = cmd->cmd.runtest->num_cycles; while (i > 0 && retval == ERROR_OK) { /* there are no state transitions in this code, so omit state tracking */ unsigned this_len = i > 7 ? 7 : i; retval = mpsse_clock_tms_cs_out(mpsse_ctx, &zero, 0, this_len, false, JTAG_MODE); i -= this_len; } ftdi_end_state(cmd->cmd.runtest->end_state); if (tap_get_state() != tap_get_end_state()) move_to_state(tap_get_end_state()); DEBUG_JTAG_IO("runtest: %i, end in %s", cmd->cmd.runtest->num_cycles, tap_state_name(tap_get_end_state())); return retval; } static int ftdi_execute_statemove(struct jtag_command *cmd) { int retval = ERROR_OK; DEBUG_JTAG_IO("statemove end in %s", tap_state_name(cmd->cmd.statemove->end_state)); ftdi_end_state(cmd->cmd.statemove->end_state); /* shortest-path move to desired end state */ if (tap_get_state() != tap_get_end_state() || tap_get_end_state() == TAP_RESET) move_to_state(tap_get_end_state()); return retval; } /** * Clock a bunch of TMS (or SWDIO) transitions, to change the JTAG * (or SWD) state machine. REVISIT: Not the best method, perhaps. */ static int ftdi_execute_tms(struct jtag_command *cmd) { DEBUG_JTAG_IO("TMS: %d bits", cmd->cmd.tms->num_bits); /* TODO: Missing tap state tracking, also missing from ft2232.c! */ return mpsse_clock_tms_cs_out(mpsse_ctx, cmd->cmd.tms->bits, 0, cmd->cmd.tms->num_bits, false, JTAG_MODE); } static int ftdi_execute_pathmove(struct jtag_command *cmd) { int retval = ERROR_OK; tap_state_t *path = cmd->cmd.pathmove->path; int num_states = cmd->cmd.pathmove->num_states; DEBUG_JTAG_IO("pathmove: %i states, current: %s end: %s", num_states, tap_state_name(tap_get_state()), tap_state_name(path[num_states-1])); int state_count = 0; unsigned bit_count = 0; uint8_t tms_byte = 0; DEBUG_JTAG_IO("-"); /* this loop verifies that the path is legal and logs each state in the path */ while (num_states-- && retval == ERROR_OK) { /* either TMS=0 or TMS=1 must work ... */ if (tap_state_transition(tap_get_state(), false) == path[state_count]) buf_set_u32(&tms_byte, bit_count++, 1, 0x0); else if (tap_state_transition(tap_get_state(), true) == path[state_count]) { buf_set_u32(&tms_byte, bit_count++, 1, 0x1); /* ... or else the caller goofed BADLY */ } else { LOG_ERROR("BUG: %s -> %s isn't a valid " "TAP state transition", tap_state_name(tap_get_state()), tap_state_name(path[state_count])); exit(-1); } tap_set_state(path[state_count]); state_count++; if (bit_count == 7 || num_states == 0) { retval = mpsse_clock_tms_cs_out(mpsse_ctx, &tms_byte, 0, bit_count, false, JTAG_MODE); bit_count = 0; } } tap_set_end_state(tap_get_state()); return retval; } static int ftdi_execute_scan(struct jtag_command *cmd) { int retval = ERROR_OK; DEBUG_JTAG_IO("%s type:%d", cmd->cmd.scan->ir_scan ? "IRSCAN" : "DRSCAN", jtag_scan_type(cmd->cmd.scan)); /* Make sure there are no trailing fields with num_bits == 0, or the logic below will fail. */ while (cmd->cmd.scan->num_fields > 0 && cmd->cmd.scan->fields[cmd->cmd.scan->num_fields - 1].num_bits == 0) { cmd->cmd.scan->num_fields--; LOG_DEBUG("discarding trailing empty field"); } if (cmd->cmd.scan->num_fields == 0) { LOG_DEBUG("empty scan, doing nothing"); return retval; } if (cmd->cmd.scan->ir_scan) { if (tap_get_state() != TAP_IRSHIFT) move_to_state(TAP_IRSHIFT); } else { if (tap_get_state() != TAP_DRSHIFT) move_to_state(TAP_DRSHIFT); } ftdi_end_state(cmd->cmd.scan->end_state); struct scan_field *field = cmd->cmd.scan->fields; unsigned scan_size = 0; for (int i = 0; i < cmd->cmd.scan->num_fields; i++, field++) { scan_size += field->num_bits; DEBUG_JTAG_IO("%s%s field %d/%d %d bits", field->in_value ? "in" : "", field->out_value ? "out" : "", i, cmd->cmd.scan->num_fields, field->num_bits); if (i == cmd->cmd.scan->num_fields - 1 && tap_get_state() != tap_get_end_state()) { /* Last field, and we're leaving IRSHIFT/DRSHIFT. Clock last bit during tap * movement. This last field can't have length zero, it was checked above. */ mpsse_clock_data(mpsse_ctx, field->out_value, 0, field->in_value, 0, field->num_bits - 1, JTAG_MODE); uint8_t last_bit = 0; if (field->out_value) bit_copy(&last_bit, 0, field->out_value, field->num_bits - 1, 1); uint8_t tms_bits = 0x01; retval = mpsse_clock_tms_cs(mpsse_ctx, &tms_bits, 0, field->in_value, field->num_bits - 1, 1, last_bit, JTAG_MODE); tap_set_state(tap_state_transition(tap_get_state(), 1)); retval = mpsse_clock_tms_cs_out(mpsse_ctx, &tms_bits, 1, 1, last_bit, JTAG_MODE); tap_set_state(tap_state_transition(tap_get_state(), 0)); } else mpsse_clock_data(mpsse_ctx, field->out_value, 0, field->in_value, 0, field->num_bits, JTAG_MODE); if (retval != ERROR_OK) { LOG_ERROR("failed to add field %d in scan", i); return retval; } } if (tap_get_state() != tap_get_end_state()) move_to_state(tap_get_end_state()); DEBUG_JTAG_IO("%s scan, %i bits, end in %s", (cmd->cmd.scan->ir_scan) ? "IR" : "DR", scan_size, tap_state_name(tap_get_end_state())); return retval; } static int ftdi_execute_reset(struct jtag_command *cmd) { DEBUG_JTAG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); if (cmd->cmd.reset->trst == 1 || (cmd->cmd.reset->srst && (jtag_get_reset_config() & RESET_SRST_PULLS_TRST))) tap_set_state(TAP_RESET); struct signal *trst = find_signal_by_name("nTRST"); if (trst && cmd->cmd.reset->trst == 1) { ftdi_set_signal(trst, '0'); } else if (trst && cmd->cmd.reset->trst == 0) { if (jtag_get_reset_config() & RESET_TRST_OPEN_DRAIN) ftdi_set_signal(trst, 'z'); else ftdi_set_signal(trst, '1'); } struct signal *srst = find_signal_by_name("nSRST"); if (srst && cmd->cmd.reset->srst == 1) { ftdi_set_signal(srst, '0'); } else if (srst && cmd->cmd.reset->srst == 0) { if (jtag_get_reset_config() & RESET_SRST_PUSH_PULL) ftdi_set_signal(srst, '1'); else ftdi_set_signal(srst, 'z'); } DEBUG_JTAG_IO("trst: %i, srst: %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); return ERROR_OK; } static int ftdi_execute_sleep(struct jtag_command *cmd) { int retval = ERROR_OK; DEBUG_JTAG_IO("sleep %" PRIi32, cmd->cmd.sleep->us); retval = mpsse_flush(mpsse_ctx); jtag_sleep(cmd->cmd.sleep->us); DEBUG_JTAG_IO("sleep %" PRIi32 " usec while in %s", cmd->cmd.sleep->us, tap_state_name(tap_get_state())); return retval; } static int ftdi_execute_stableclocks(struct jtag_command *cmd) { int retval = ERROR_OK; /* this is only allowed while in a stable state. A check for a stable * state was done in jtag_add_clocks() */ int num_cycles = cmd->cmd.stableclocks->num_cycles; /* 7 bits of either ones or zeros. */ uint8_t tms = tap_get_state() == TAP_RESET ? 0x7f : 0x00; /* TODO: Use mpsse_clock_data with in=out=0 for this, if TMS can be set to * the correct level and remain there during the scan */ while (num_cycles > 0 && retval == ERROR_OK) { /* there are no state transitions in this code, so omit state tracking */ unsigned this_len = num_cycles > 7 ? 7 : num_cycles; retval = mpsse_clock_tms_cs_out(mpsse_ctx, &tms, 0, this_len, false, JTAG_MODE); num_cycles -= this_len; } DEBUG_JTAG_IO("clocks %i while in %s", cmd->cmd.stableclocks->num_cycles, tap_state_name(tap_get_state())); return retval; } static int ftdi_execute_command(struct jtag_command *cmd) { int retval; switch (cmd->type) { case JTAG_RESET: retval = ftdi_execute_reset(cmd); break; case JTAG_RUNTEST: retval = ftdi_execute_runtest(cmd); break; case JTAG_TLR_RESET: retval = ftdi_execute_statemove(cmd); break; case JTAG_PATHMOVE: retval = ftdi_execute_pathmove(cmd); break; case JTAG_SCAN: retval = ftdi_execute_scan(cmd); break; case JTAG_SLEEP: retval = ftdi_execute_sleep(cmd); break; case JTAG_STABLECLOCKS: retval = ftdi_execute_stableclocks(cmd); break; case JTAG_TMS: retval = ftdi_execute_tms(cmd); break; default: LOG_ERROR("BUG: unknown JTAG command type encountered: %d", cmd->type); retval = ERROR_JTAG_QUEUE_FAILED; break; } return retval; } static int ftdi_execute_queue(void) { int retval = ERROR_OK; /* blink, if the current layout has that feature */ struct signal *led = find_signal_by_name("LED"); if (led) ftdi_set_signal(led, '1'); for (struct jtag_command *cmd = jtag_command_queue; cmd; cmd = cmd->next) { /* fill the write buffer with the desired command */ if (ftdi_execute_command(cmd) != ERROR_OK) retval = ERROR_JTAG_QUEUE_FAILED; } if (led) ftdi_set_signal(led, '0'); retval = mpsse_flush(mpsse_ctx); if (retval != ERROR_OK) LOG_ERROR("error while flushing MPSSE queue: %d", retval); return retval; } static int ftdi_initialize(void) { int retval; if (tap_get_tms_path_len(TAP_IRPAUSE, TAP_IRPAUSE) == 7) LOG_DEBUG("ftdi interface using 7 step jtag state transitions"); else LOG_DEBUG("ftdi interface using shortest path jtag state transitions"); for (int i = 0; ftdi_vid[i] || ftdi_pid[i]; i++) { mpsse_ctx = mpsse_open(&ftdi_vid[i], &ftdi_pid[i], ftdi_device_desc, ftdi_serial, ftdi_channel); if (mpsse_ctx) break; } if (!mpsse_ctx) return ERROR_JTAG_INIT_FAILED; retval = mpsse_set_data_bits_low_byte(mpsse_ctx, output & 0xff, direction & 0xff); if (retval == ERROR_OK) retval = mpsse_set_data_bits_high_byte(mpsse_ctx, output >> 8, direction >> 8); if (retval != ERROR_OK) { LOG_ERROR("couldn't initialize FTDI with configured layout"); return ERROR_JTAG_INIT_FAILED; } retval = mpsse_loopback_config(mpsse_ctx, false); if (retval != ERROR_OK) { LOG_ERROR("couldn't write to FTDI to disable loopback"); return ERROR_JTAG_INIT_FAILED; } return mpsse_flush(mpsse_ctx); } static int ftdi_quit(void) { mpsse_close(mpsse_ctx); return ERROR_OK; } COMMAND_HANDLER(ftdi_handle_device_desc_command) { if (CMD_ARGC == 1) { if (ftdi_device_desc) free(ftdi_device_desc); ftdi_device_desc = strdup(CMD_ARGV[0]); } else { LOG_ERROR("expected exactly one argument to ftdi_device_desc "); } return ERROR_OK; } COMMAND_HANDLER(ftdi_handle_serial_command) { if (CMD_ARGC == 1) { if (ftdi_serial) free(ftdi_serial); ftdi_serial = strdup(CMD_ARGV[0]); } else { return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; } COMMAND_HANDLER(ftdi_handle_channel_command) { if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], ftdi_channel); else return ERROR_COMMAND_SYNTAX_ERROR; return ERROR_OK; } COMMAND_HANDLER(ftdi_handle_layout_init_command) { if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], output); COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], direction); return ERROR_OK; } COMMAND_HANDLER(ftdi_handle_layout_signal_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; bool invert_data = false; uint16_t data_mask = 0; bool invert_oe = false; uint16_t oe_mask = 0; for (unsigned i = 1; i < CMD_ARGC; i += 2) { if (strcmp("-data", CMD_ARGV[i]) == 0) { invert_data = false; COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], data_mask); } else if (strcmp("-ndata", CMD_ARGV[i]) == 0) { invert_data = true; COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], data_mask); } else if (strcmp("-oe", CMD_ARGV[i]) == 0) { invert_oe = false; COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], oe_mask); } else if (strcmp("-noe", CMD_ARGV[i]) == 0) { invert_oe = true; COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], oe_mask); } else { LOG_ERROR("unknown option '%s'", CMD_ARGV[i]); return ERROR_COMMAND_SYNTAX_ERROR; } } struct signal *sig; sig = find_signal_by_name(CMD_ARGV[0]); if (!sig) sig = create_signal(CMD_ARGV[0]); if (!sig) { LOG_ERROR("failed to create signal %s", CMD_ARGV[0]); return ERROR_FAIL; } sig->invert_data = invert_data; sig->data_mask = data_mask; sig->invert_oe = invert_oe; sig->oe_mask = oe_mask; return ERROR_OK; } COMMAND_HANDLER(ftdi_handle_set_signal_command) { if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; struct signal *sig; sig = find_signal_by_name(CMD_ARGV[0]); if (!sig) { LOG_ERROR("interface configuration doesn't define signal '%s'", CMD_ARGV[0]); return ERROR_FAIL; } switch (*CMD_ARGV[1]) { case '0': case '1': case 'z': case 'Z': /* single character level specifier only */ if (CMD_ARGV[1][1] == '\0') { ftdi_set_signal(sig, *CMD_ARGV[1]); break; } default: LOG_ERROR("unknown signal level '%s', use 0, 1 or z", CMD_ARGV[1]); return ERROR_COMMAND_SYNTAX_ERROR; } return mpsse_flush(mpsse_ctx); } COMMAND_HANDLER(ftdi_handle_vid_pid_command) { if (CMD_ARGC > MAX_USB_IDS * 2) { LOG_WARNING("ignoring extra IDs in ftdi_vid_pid " "(maximum is %d pairs)", MAX_USB_IDS); CMD_ARGC = MAX_USB_IDS * 2; } if (CMD_ARGC < 2 || (CMD_ARGC & 1)) { LOG_WARNING("incomplete ftdi_vid_pid configuration directive"); if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; /* remove the incomplete trailing id */ CMD_ARGC -= 1; } unsigned i; for (i = 0; i < CMD_ARGC; i += 2) { COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i], ftdi_vid[i >> 1]); COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], ftdi_pid[i >> 1]); } /* * Explicitly terminate, in case there are multiples instances of * ftdi_vid_pid. */ ftdi_vid[i >> 1] = ftdi_pid[i >> 1] = 0; return ERROR_OK; } static const struct command_registration ftdi_command_handlers[] = { { .name = "ftdi_device_desc", .handler = &ftdi_handle_device_desc_command, .mode = COMMAND_CONFIG, .help = "set the USB device description of the FTDI device", .usage = "description_string", }, { .name = "ftdi_serial", .handler = &ftdi_handle_serial_command, .mode = COMMAND_CONFIG, .help = "set the serial number of the FTDI device", .usage = "serial_string", }, { .name = "ftdi_channel", .handler = &ftdi_handle_channel_command, .mode = COMMAND_CONFIG, .help = "set the channel of the FTDI device that is used as JTAG", .usage = "(0-3)", }, { .name = "ftdi_layout_init", .handler = &ftdi_handle_layout_init_command, .mode = COMMAND_CONFIG, .help = "initialize the FTDI GPIO signals used " "to control output-enables and reset signals", .usage = "data direction", }, { .name = "ftdi_layout_signal", .handler = &ftdi_handle_layout_signal_command, .mode = COMMAND_ANY, .help = "define a signal controlled by one or more FTDI GPIO as data " "and/or output enable", .usage = "name [-data mask|-ndata mask] [-oe mask|-noe mask]", }, { .name = "ftdi_set_signal", .handler = &ftdi_handle_set_signal_command, .mode = COMMAND_EXEC, .help = "control a layout-specific signal", .usage = "name (1|0|z)", }, { .name = "ftdi_vid_pid", .handler = &ftdi_handle_vid_pid_command, .mode = COMMAND_CONFIG, .help = "the vendor ID and product ID of the FTDI device", .usage = "(vid pid)* ", }, COMMAND_REGISTRATION_DONE }; struct jtag_interface ftdi_interface = { .name = "ftdi", .supported = DEBUG_CAP_TMS_SEQ, .commands = ftdi_command_handlers, .transports = jtag_only, .init = ftdi_initialize, .quit = ftdi_quit, .speed = ftdi_speed, .speed_div = ftdi_speed_div, .khz = ftdi_khz, .execute_queue = ftdi_execute_queue, }; openocd-0.7.0/src/jtag/drivers/usbprog.c0000644000175000001440000004102612137151331015101 00000000000000/*************************************************************************** * Copyright (C) 2007 by Benedikt Sauter * * sauter@ixbat.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /* * This file is based on Dominic Rath's amt_jtagaccel.c. * * usbprog is a free programming adapter. You can easily install * different firmware versions from an "online pool" over USB. * The adapter can be used for programming and debugging AVR and ARM * processors, as USB to RS232 converter, as JTAG interface or as * simple I/O interface (5 lines). * * http://www.embedded-projects.net/usbprog */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "usb_common.h" #define VID 0x1781 #define PID 0x0c63 /* Pins at usbprog */ #define TDO_BIT 0 #define TDI_BIT 3 #define TCK_BIT 2 #define TMS_BIT 1 static void usbprog_end_state(tap_state_t state); static void usbprog_state_move(void); static void usbprog_path_move(struct pathmove_command *cmd); static void usbprog_runtest(int num_cycles); static void usbprog_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size); #define UNKNOWN_COMMAND 0x00 #define PORT_DIRECTION 0x01 #define PORT_SET 0x02 #define PORT_GET 0x03 #define PORT_SETBIT 0x04 #define PORT_GETBIT 0x05 #define WRITE_TDI 0x06 #define READ_TDO 0x07 #define WRITE_AND_READ 0x08 #define WRITE_TMS 0x09 #define WRITE_TMS_CHAIN 0x0A struct usbprog_jtag { struct usb_dev_handle *usb_handle; }; static struct usbprog_jtag *usbprog_jtag_handle; static struct usbprog_jtag *usbprog_jtag_open(void); /* static void usbprog_jtag_close(struct usbprog_jtag *usbprog_jtag); */ static void usbprog_jtag_init(struct usbprog_jtag *usbprog_jtag); static unsigned char usbprog_jtag_message(struct usbprog_jtag *usbprog_jtag, char *msg, int msglen); static void usbprog_jtag_read_tdo(struct usbprog_jtag *usbprog_jtag, char *buffer, int size); static void usbprog_jtag_write_tdi(struct usbprog_jtag *usbprog_jtag, char *buffer, int size); static void usbprog_jtag_write_and_read(struct usbprog_jtag *usbprog_jtag, char *buffer, int size); static void usbprog_jtag_write_tms(struct usbprog_jtag *usbprog_jtag, char tms_scan); static char tms_chain[64]; static int tms_chain_index; static void usbprog_jtag_tms_collect(char tms_scan); static void usbprog_jtag_tms_send(struct usbprog_jtag *usbprog_jtag); static void usbprog_write(int tck, int tms, int tdi); static void usbprog_reset(int trst, int srst); static void usbprog_jtag_set_direction(struct usbprog_jtag *usbprog_jtag, unsigned char direction); static void usbprog_jtag_write_slice(struct usbprog_jtag *usbprog_jtag, unsigned char value); /* static unsigned char usbprog_jtag_get_port(struct usbprog_jtag *usbprog_jtag); */ static void usbprog_jtag_set_bit(struct usbprog_jtag *usbprog_jtag, int bit, int value); /* static int usbprog_jtag_get_bit(struct usbprog_jtag *usbprog_jtag, int bit); */ static int usbprog_execute_queue(void) { struct jtag_command *cmd = jtag_command_queue; /* currently processed command */ int scan_size; enum scan_type type; uint8_t *buffer; while (cmd) { switch (cmd->type) { case JTAG_RESET: #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); #endif if (cmd->cmd.reset->trst == 1) tap_set_state(TAP_RESET); usbprog_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); break; case JTAG_RUNTEST: #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); #endif usbprog_end_state(cmd->cmd.runtest->end_state); usbprog_runtest(cmd->cmd.runtest->num_cycles); break; case JTAG_TLR_RESET: #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("statemove end in %i", cmd->cmd.statemove->end_state); #endif usbprog_end_state(cmd->cmd.statemove->end_state); usbprog_state_move(); break; case JTAG_PATHMOVE: #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("pathmove: %i states, end in %i", cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); #endif usbprog_path_move(cmd->cmd.pathmove); break; case JTAG_SCAN: #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("scan end in %i", cmd->cmd.scan->end_state); #endif usbprog_end_state(cmd->cmd.scan->end_state); scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); type = jtag_scan_type(cmd->cmd.scan); usbprog_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size); if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) return ERROR_JTAG_QUEUE_FAILED; if (buffer) free(buffer); break; case JTAG_SLEEP: #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("sleep %i", cmd->cmd.sleep->us); #endif jtag_sleep(cmd->cmd.sleep->us); break; default: LOG_ERROR("BUG: unknown JTAG command type encountered"); exit(-1); } cmd = cmd->next; } return ERROR_OK; } static int usbprog_init(void) { usbprog_jtag_handle = usbprog_jtag_open(); tms_chain_index = 0; if (usbprog_jtag_handle == 0) { LOG_ERROR("Can't find USB JTAG Interface! Please check connection and permissions."); return ERROR_JTAG_INIT_FAILED; } LOG_INFO("USB JTAG Interface ready!"); usbprog_jtag_init(usbprog_jtag_handle); usbprog_reset(0, 0); usbprog_write(0, 0, 0); return ERROR_OK; } static int usbprog_quit(void) { return ERROR_OK; } /*************** jtag execute commands **********************/ static void usbprog_end_state(tap_state_t state) { if (tap_is_state_stable(state)) tap_set_end_state(state); else { LOG_ERROR("BUG: %i is not a valid end state", state); exit(-1); } } static void usbprog_state_move(void) { uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state()); usbprog_jtag_write_tms(usbprog_jtag_handle, (char)tms_scan); tap_set_state(tap_get_end_state()); } static void usbprog_path_move(struct pathmove_command *cmd) { int num_states = cmd->num_states; int state_count; /* There may be queued transitions, and before following a specified path, we must flush those queued transitions */ usbprog_jtag_tms_send(usbprog_jtag_handle); state_count = 0; while (num_states) { if (tap_state_transition(tap_get_state(), false) == cmd->path[state_count]) { /* LOG_INFO("1"); */ usbprog_write(0, 0, 0); usbprog_write(1, 0, 0); } else if (tap_state_transition(tap_get_state(), true) == cmd->path[state_count]) { /* LOG_INFO("2"); */ usbprog_write(0, 1, 0); usbprog_write(1, 1, 0); } else { LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_name(tap_get_state()), tap_state_name(cmd->path[state_count])); exit(-1); } tap_set_state(cmd->path[state_count]); state_count++; num_states--; } tap_set_end_state(tap_get_state()); } static void usbprog_runtest(int num_cycles) { int i; /* only do a state_move when we're not already in IDLE */ if (tap_get_state() != TAP_IDLE) { usbprog_end_state(TAP_IDLE); usbprog_state_move(); } /* execute num_cycles */ if (num_cycles > 0) { usbprog_jtag_tms_send(usbprog_jtag_handle); usbprog_write(0, 0, 0); } else { usbprog_jtag_tms_send(usbprog_jtag_handle); /* LOG_INFO("NUM CYCLES %i",num_cycles); */ } for (i = 0; i < num_cycles; i++) { usbprog_write(1, 0, 0); usbprog_write(0, 0, 0); } #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("runtest: cur_state %s end_state %s", tap_state_name( tap_get_state()), tap_state_name(tap_get_end_state())); #endif /* finish in end_state */ /* usbprog_end_state(saved_end_state); if (tap_get_state() != tap_get_end_state()) usbprog_state_move(); */ } static void usbprog_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size) { tap_state_t saved_end_state = tap_get_end_state(); if (ir_scan) usbprog_end_state(TAP_IRSHIFT); else usbprog_end_state(TAP_DRSHIFT); /* Only move if we're not already there */ if (tap_get_state() != tap_get_end_state()) usbprog_state_move(); usbprog_end_state(saved_end_state); usbprog_jtag_tms_send(usbprog_jtag_handle); void (*f)(struct usbprog_jtag *usbprog_jtag, char *buffer_local, int size); switch (type) { case SCAN_OUT: f = &usbprog_jtag_write_tdi; break; case SCAN_IN: f = &usbprog_jtag_read_tdo; break; case SCAN_IO: f = &usbprog_jtag_write_and_read; break; default: LOG_ERROR("unknown scan type: %i", type); exit(-1); } f(usbprog_jtag_handle, (char *)buffer, scan_size); /* The adapter does the transition to PAUSE internally */ if (ir_scan) tap_set_state(TAP_IRPAUSE); else tap_set_state(TAP_DRPAUSE); if (tap_get_state() != tap_get_end_state()) usbprog_state_move(); } /*************** jtag wrapper functions *********************/ static void usbprog_write(int tck, int tms, int tdi) { unsigned char output_value = 0x00; if (tms) output_value |= (1 << TMS_BIT); if (tdi) output_value |= (1 << TDI_BIT); if (tck) output_value |= (1 << TCK_BIT); usbprog_jtag_write_slice(usbprog_jtag_handle, output_value); } /* (1) assert or (0) deassert reset lines */ static void usbprog_reset(int trst, int srst) { LOG_DEBUG("trst: %i, srst: %i", trst, srst); if (trst) usbprog_jtag_set_bit(usbprog_jtag_handle, 5, 0); else usbprog_jtag_set_bit(usbprog_jtag_handle, 5, 1); if (srst) usbprog_jtag_set_bit(usbprog_jtag_handle, 4, 0); else usbprog_jtag_set_bit(usbprog_jtag_handle, 4, 1); } /*************** jtag lowlevel functions ********************/ struct usb_bus *busses; struct usbprog_jtag *usbprog_jtag_open(void) { usb_set_debug(10); usb_init(); const uint16_t vids[] = { VID, 0 }; const uint16_t pids[] = { PID, 0 }; struct usb_dev_handle *dev; if (jtag_usb_open(vids, pids, &dev) != ERROR_OK) return NULL; struct usbprog_jtag *tmp = malloc(sizeof(struct usbprog_jtag)); tmp->usb_handle = dev; usb_set_configuration(dev, 1); usb_claim_interface(dev, 0); usb_set_altinterface(dev, 0); return tmp; } #if 0 static void usbprog_jtag_close(struct usbprog_jtag *usbprog_jtag) { usb_close(usbprog_jtag->usb_handle); free(usbprog_jtag); } #endif static unsigned char usbprog_jtag_message(struct usbprog_jtag *usbprog_jtag, char *msg, int msglen) { int res = usb_bulk_write(usbprog_jtag->usb_handle, 3, msg, msglen, 100); if ((msg[0] == 2) || (msg[0] == 1) || (msg[0] == 4) || (msg[0] == 0) || \ (msg[0] == 6) || (msg[0] == 0x0A) || (msg[0] == 9)) return 1; if (res == msglen) { /* LOG_INFO("HALLLLOOO %i",(int)msg[0]); */ res = usb_bulk_read(usbprog_jtag->usb_handle, 0x82, msg, 2, 100); if (res > 0) return (unsigned char)msg[1]; else return -1; } else return -1; return 0; } static void usbprog_jtag_init(struct usbprog_jtag *usbprog_jtag) { usbprog_jtag_set_direction(usbprog_jtag, 0xFE); } static void usbprog_jtag_write_and_read(struct usbprog_jtag *usbprog_jtag, char *buffer, int size) { char tmp[64]; /* fastes packet size for usb controller */ int send_bits, bufindex = 0, fillindex = 0, i, loops; char swap; /* 61 byte can be transfered (488 bit) */ while (size > 0) { if (size > 488) { send_bits = 488; size = size - 488; loops = 61; } else { send_bits = size; loops = size / 8; loops++; size = 0; } tmp[0] = WRITE_AND_READ; tmp[1] = (char)(send_bits >> 8); /* high */ tmp[2] = (char)(send_bits); /* low */ for (i = 0; i < loops; i++) { tmp[3 + i] = buffer[bufindex]; bufindex++; } if (usb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 64, 1000) == 64) { /* LOG_INFO("HALLLLOOO2 %i",(int)tmp[0]); */ usleep(1); int timeout = 0; while (usb_bulk_read(usbprog_jtag->usb_handle, 0x82, tmp, 64, 1000) < 1) { timeout++; if (timeout > 10) break; } for (i = 0; i < loops; i++) { swap = tmp[3 + i]; buffer[fillindex++] = swap; } } } } static void usbprog_jtag_read_tdo(struct usbprog_jtag *usbprog_jtag, char *buffer, int size) { char tmp[64]; /* fastes packet size for usb controller */ int send_bits, fillindex = 0, i, loops; char swap; /* 61 byte can be transfered (488 bit) */ while (size > 0) { if (size > 488) { send_bits = 488; size = size - 488; loops = 61; } else { send_bits = size; loops = size / 8; loops++; size = 0; } tmp[0] = WRITE_AND_READ; tmp[1] = (char)(send_bits >> 8); /* high */ tmp[2] = (char)(send_bits); /* low */ usb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 3, 1000); /* LOG_INFO("HALLLLOOO3 %i",(int)tmp[0]); */ int timeout = 0; usleep(1); while (usb_bulk_read(usbprog_jtag->usb_handle, 0x82, tmp, 64, 10) < 1) { timeout++; if (timeout > 10) break; } for (i = 0; i < loops; i++) { swap = tmp[3 + i]; buffer[fillindex++] = swap; } } } static void usbprog_jtag_write_tdi(struct usbprog_jtag *usbprog_jtag, char *buffer, int size) { char tmp[64]; /* fastes packet size for usb controller */ int send_bits, bufindex = 0, i, loops; /* 61 byte can be transfered (488 bit) */ while (size > 0) { if (size > 488) { send_bits = 488; size = size - 488; loops = 61; } else { send_bits = size; loops = size/8; /* if (loops == 0) */ loops++; size = 0; } tmp[0] = WRITE_TDI; tmp[1] = (char)(send_bits >> 8); /* high */ tmp[2] = (char)(send_bits); /* low */ for (i = 0; i < loops; i++) { tmp[3 + i] = buffer[bufindex]; bufindex++; } usb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, 64, 1000); } } static void usbprog_jtag_write_tms(struct usbprog_jtag *usbprog_jtag, char tms_scan) { usbprog_jtag_tms_collect(tms_scan); } static void usbprog_jtag_set_direction(struct usbprog_jtag *usbprog_jtag, unsigned char direction) { char tmp[2]; tmp[0] = PORT_DIRECTION; tmp[1] = (char)direction; usbprog_jtag_message(usbprog_jtag, tmp, 2); } static void usbprog_jtag_write_slice(struct usbprog_jtag *usbprog_jtag, unsigned char value) { char tmp[2]; tmp[0] = PORT_SET; tmp[1] = (char)value; usbprog_jtag_message(usbprog_jtag, tmp, 2); } #if 0 static unsigned char usbprog_jtag_get_port(struct usbprog_jtag *usbprog_jtag) { char tmp[2]; tmp[0] = PORT_GET; tmp[1] = 0x00; return usbprog_jtag_message(usbprog_jtag, tmp, 2); } #endif static void usbprog_jtag_set_bit(struct usbprog_jtag *usbprog_jtag, int bit, int value) { char tmp[3]; tmp[0] = PORT_SETBIT; tmp[1] = (char)bit; if (value == 1) tmp[2] = 0x01; else tmp[2] = 0x00; usbprog_jtag_message(usbprog_jtag, tmp, 3); } #if 0 static int usbprog_jtag_get_bit(struct usbprog_jtag *usbprog_jtag, int bit) { char tmp[2]; tmp[0] = PORT_GETBIT; tmp[1] = (char)bit; if (usbprog_jtag_message(usbprog_jtag, tmp, 2) > 0) return 1; else return 0; } #endif static void usbprog_jtag_tms_collect(char tms_scan) { tms_chain[tms_chain_index] = tms_scan; tms_chain_index++; } static void usbprog_jtag_tms_send(struct usbprog_jtag *usbprog_jtag) { int i; /* LOG_INFO("TMS SEND"); */ if (tms_chain_index > 0) { char tmp[tms_chain_index + 2]; tmp[0] = WRITE_TMS_CHAIN; tmp[1] = (char)(tms_chain_index); for (i = 0; i < tms_chain_index + 1; i++) tmp[2 + i] = tms_chain[i]; usb_bulk_write(usbprog_jtag->usb_handle, 3, tmp, tms_chain_index + 2, 1000); tms_chain_index = 0; } } struct jtag_interface usbprog_interface = { .name = "usbprog", .execute_queue = usbprog_execute_queue, .init = usbprog_init, .quit = usbprog_quit }; openocd-0.7.0/src/jtag/drivers/arm-jtag-ew.c0000644000175000001440000005217112134336410015536 00000000000000/*************************************************************************** * Copyright (C) 2009 by Dimitar Dimitrov * * based on Dominic Rath's and Benedikt Sauter's usbprog.c * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include "usb_common.h" #define USB_VID 0x15ba #define USB_PID 0x001e #define ARMJTAGEW_EPT_BULK_OUT 0x01u #define ARMJTAGEW_EPT_BULK_IN 0x82u #define ARMJTAGEW_USB_TIMEOUT 2000 #define ARMJTAGEW_IN_BUFFER_SIZE (4*1024) #define ARMJTAGEW_OUT_BUFFER_SIZE (4*1024) /* USB command request codes. */ #define CMD_GET_VERSION 0x00 #define CMD_SELECT_DPIMPL 0x10 #define CMD_SET_TCK_FREQUENCY 0x11 #define CMD_GET_TCK_FREQUENCY 0x12 #define CMD_MEASURE_MAX_TCK_FREQ 0x15 #define CMD_MEASURE_RTCK_RESPONSE 0x16 #define CMD_TAP_SHIFT 0x17 #define CMD_SET_TAPHW_STATE 0x20 #define CMD_GET_TAPHW_STATE 0x21 #define CMD_TGPWR_SETUP 0x22 /* Global USB buffers */ static uint8_t usb_in_buffer[ARMJTAGEW_IN_BUFFER_SIZE]; static uint8_t usb_out_buffer[ARMJTAGEW_OUT_BUFFER_SIZE]; /* Queue command functions */ static void armjtagew_end_state(tap_state_t state); static void armjtagew_state_move(void); static void armjtagew_path_move(int num_states, tap_state_t *path); static void armjtagew_runtest(int num_cycles); static void armjtagew_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command); static void armjtagew_reset(int trst, int srst); /* static void armjtagew_simple_command(uint8_t command); */ static int armjtagew_get_status(void); /* tap buffer functions */ static void armjtagew_tap_init(void); static int armjtagew_tap_execute(void); static void armjtagew_tap_ensure_space(int scans, int bits); static void armjtagew_tap_append_step(int tms, int tdi); static void armjtagew_tap_append_scan(int length, uint8_t *buffer, struct scan_command *command); /* ARM-JTAG-EW lowlevel functions */ struct armjtagew { struct usb_dev_handle *usb_handle; }; static struct armjtagew *armjtagew_usb_open(void); static void armjtagew_usb_close(struct armjtagew *armjtagew); static int armjtagew_usb_message(struct armjtagew *armjtagew, int out_length, int in_length); static int armjtagew_usb_write(struct armjtagew *armjtagew, int out_length); static int armjtagew_usb_read(struct armjtagew *armjtagew, int exp_in_length); /* helper functions */ static int armjtagew_get_version_info(void); #ifdef _DEBUG_USB_COMMS_ static void armjtagew_debug_buffer(uint8_t *buffer, int length); #endif static struct armjtagew *armjtagew_handle; /************************************************************************** * External interface implementation */ static int armjtagew_execute_queue(void) { struct jtag_command *cmd = jtag_command_queue; int scan_size; enum scan_type type; uint8_t *buffer; while (cmd != NULL) { switch (cmd->type) { case JTAG_RUNTEST: DEBUG_JTAG_IO("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, \ cmd->cmd.runtest->end_state); armjtagew_end_state(cmd->cmd.runtest->end_state); armjtagew_runtest(cmd->cmd.runtest->num_cycles); break; case JTAG_TLR_RESET: DEBUG_JTAG_IO("statemove end in %i", cmd->cmd.statemove->end_state); armjtagew_end_state(cmd->cmd.statemove->end_state); armjtagew_state_move(); break; case JTAG_PATHMOVE: DEBUG_JTAG_IO("pathmove: %i states, end in %i", \ cmd->cmd.pathmove->num_states, \ cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); armjtagew_path_move(cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path); break; case JTAG_SCAN: DEBUG_JTAG_IO("scan end in %i", cmd->cmd.scan->end_state); armjtagew_end_state(cmd->cmd.scan->end_state); scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); DEBUG_JTAG_IO("scan input, length = %d", scan_size); #ifdef _DEBUG_USB_COMMS_ armjtagew_debug_buffer(buffer, (scan_size + 7) / 8); #endif type = jtag_scan_type(cmd->cmd.scan); armjtagew_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size, cmd->cmd.scan); break; case JTAG_RESET: DEBUG_JTAG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); armjtagew_tap_execute(); if (cmd->cmd.reset->trst == 1) tap_set_state(TAP_RESET); armjtagew_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); break; case JTAG_SLEEP: DEBUG_JTAG_IO("sleep %i", cmd->cmd.sleep->us); armjtagew_tap_execute(); jtag_sleep(cmd->cmd.sleep->us); break; default: LOG_ERROR("BUG: unknown JTAG command type encountered"); exit(-1); } cmd = cmd->next; } return armjtagew_tap_execute(); } /* Sets speed in kHz. */ static int armjtagew_speed(int speed) { int result; int speed_real; usb_out_buffer[0] = CMD_SET_TCK_FREQUENCY; buf_set_u32(usb_out_buffer + 1, 0, 32, speed*1000); result = armjtagew_usb_message(armjtagew_handle, 5, 4); if (result < 0) { LOG_ERROR("ARM-JTAG-EW setting speed failed (%d)", result); return ERROR_JTAG_DEVICE_ERROR; } usb_out_buffer[0] = CMD_GET_TCK_FREQUENCY; result = armjtagew_usb_message(armjtagew_handle, 1, 4); speed_real = (int)buf_get_u32(usb_in_buffer, 0, 32) / 1000; if (result < 0) { LOG_ERROR("ARM-JTAG-EW getting speed failed (%d)", result); return ERROR_JTAG_DEVICE_ERROR; } else LOG_INFO("Requested speed %dkHz, emulator reported %dkHz.", speed, speed_real); return ERROR_OK; } static int armjtagew_khz(int khz, int *jtag_speed) { *jtag_speed = khz; return ERROR_OK; } static int armjtagew_speed_div(int speed, int *khz) { *khz = speed; return ERROR_OK; } static int armjtagew_init(void) { int check_cnt; armjtagew_handle = armjtagew_usb_open(); if (armjtagew_handle == 0) { LOG_ERROR( "Cannot find ARM-JTAG-EW Interface! Please check connection and permissions."); return ERROR_JTAG_INIT_FAILED; } check_cnt = 0; while (check_cnt < 3) { if (armjtagew_get_version_info() == ERROR_OK) { /* attempt to get status */ armjtagew_get_status(); break; } check_cnt++; } if (check_cnt == 3) LOG_INFO("ARM-JTAG-EW initial read failed, don't worry"); /* Initial JTAG speed (for reset and initialization): 32 kHz */ armjtagew_speed(32); LOG_INFO("ARM-JTAG-EW JTAG Interface ready"); armjtagew_reset(0, 0); armjtagew_tap_init(); return ERROR_OK; } static int armjtagew_quit(void) { armjtagew_usb_close(armjtagew_handle); return ERROR_OK; } /************************************************************************** * Queue command implementations */ static void armjtagew_end_state(tap_state_t state) { if (tap_is_state_stable(state)) tap_set_end_state(state); else { LOG_ERROR("BUG: %i is not a valid end state", state); exit(-1); } } /* Goes to the end state. */ static void armjtagew_state_move(void) { int i; int tms = 0; uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state()); int tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); for (i = 0; i < tms_count; i++) { tms = (tms_scan >> i) & 1; armjtagew_tap_append_step(tms, 0); } tap_set_state(tap_get_end_state()); } static void armjtagew_path_move(int num_states, tap_state_t *path) { int i; for (i = 0; i < num_states; i++) { /* * TODO: The ARM-JTAG-EW hardware delays TDI with 3 TCK cycles when in RTCK mode. * Either handle that here, or update the documentation with examples * how to fix that in the configuration files. */ if (path[i] == tap_state_transition(tap_get_state(), false)) armjtagew_tap_append_step(0, 0); else if (path[i] == tap_state_transition(tap_get_state(), true)) armjtagew_tap_append_step(1, 0); else { LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_name(tap_get_state()), tap_state_name(path[i])); exit(-1); } tap_set_state(path[i]); } tap_set_end_state(tap_get_state()); } static void armjtagew_runtest(int num_cycles) { int i; tap_state_t saved_end_state = tap_get_end_state(); /* only do a state_move when we're not already in IDLE */ if (tap_get_state() != TAP_IDLE) { armjtagew_end_state(TAP_IDLE); armjtagew_state_move(); } /* execute num_cycles */ for (i = 0; i < num_cycles; i++) armjtagew_tap_append_step(0, 0); /* finish in end_state */ armjtagew_end_state(saved_end_state); if (tap_get_state() != tap_get_end_state()) armjtagew_state_move(); } static void armjtagew_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command) { tap_state_t saved_end_state; armjtagew_tap_ensure_space(1, scan_size + 8); saved_end_state = tap_get_end_state(); /* Move to appropriate scan state */ armjtagew_end_state(ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT); /* Only move if we're not already there */ if (tap_get_state() != tap_get_end_state()) armjtagew_state_move(); armjtagew_end_state(saved_end_state); /* Scan */ armjtagew_tap_append_scan(scan_size, buffer, command); /* We are in Exit1, go to Pause */ armjtagew_tap_append_step(0, 0); tap_set_state(ir_scan ? TAP_IRPAUSE : TAP_DRPAUSE); if (tap_get_state() != tap_get_end_state()) armjtagew_state_move(); } static void armjtagew_reset(int trst, int srst) { const uint8_t trst_mask = (1u << 5); const uint8_t srst_mask = (1u << 6); uint8_t val = 0; uint8_t outp_en = 0; uint8_t change_mask = 0; int result; LOG_DEBUG("trst: %i, srst: %i", trst, srst); if (srst == 0) { val |= srst_mask; outp_en &= ~srst_mask; /* tristate */ change_mask |= srst_mask; } else if (srst == 1) { val &= ~srst_mask; outp_en |= srst_mask; change_mask |= srst_mask; } if (trst == 0) { val |= trst_mask; outp_en &= ~trst_mask; /* tristate */ change_mask |= trst_mask; } else if (trst == 1) { val &= ~trst_mask; outp_en |= trst_mask; change_mask |= trst_mask; } usb_out_buffer[0] = CMD_SET_TAPHW_STATE; usb_out_buffer[1] = val; usb_out_buffer[2] = outp_en; usb_out_buffer[3] = change_mask; result = armjtagew_usb_write(armjtagew_handle, 4); if (result != 4) LOG_ERROR("ARM-JTAG-EW TRST/SRST pin set failed failed (%d)", result); } static int armjtagew_get_status(void) { int result; usb_out_buffer[0] = CMD_GET_TAPHW_STATE; result = armjtagew_usb_message(armjtagew_handle, 1, 12); if (result == 0) { unsigned int u_tg = buf_get_u32(usb_in_buffer, 0, 16); LOG_INFO( "U_tg = %d mV, U_aux = %d mV, U_tgpwr = %d mV, I_tgpwr = %d mA, D1 = %d, Target power %s %s", (int)(buf_get_u32(usb_in_buffer + 0, 0, 16)), (int)(buf_get_u32(usb_in_buffer + 2, 0, 16)), (int)(buf_get_u32(usb_in_buffer + 4, 0, 16)), (int)(buf_get_u32(usb_in_buffer + 6, 0, 16)), usb_in_buffer[9], usb_in_buffer[11] ? "OVERCURRENT" : "OK", usb_in_buffer[10] ? "enabled" : "disabled"); if (u_tg < 1500) LOG_ERROR("Vref too low. Check Target Power"); } else LOG_ERROR("ARM-JTAG-EW command CMD_GET_TAPHW_STATE failed (%d)", result); return ERROR_OK; } static int armjtagew_get_version_info(void) { int result; char sn[16]; char auxinfo[257]; /* query hardware version */ usb_out_buffer[0] = CMD_GET_VERSION; result = armjtagew_usb_message(armjtagew_handle, 1, 4 + 15 + 256); if (result != 0) { LOG_ERROR("ARM-JTAG-EW command CMD_GET_VERSION failed (%d)", result); return ERROR_JTAG_DEVICE_ERROR; } memcpy(sn, usb_in_buffer + 4, 15); sn[15] = '\0'; memcpy(auxinfo, usb_in_buffer + 4+15, 256); auxinfo[256] = '\0'; LOG_INFO( "ARM-JTAG-EW firmware version %d.%d, hardware revision %c, SN=%s, Additional info: %s", \ usb_in_buffer[1], usb_in_buffer[0], \ isgraph(usb_in_buffer[2]) ? usb_in_buffer[2] : 'X', \ sn, auxinfo); if (1 != usb_in_buffer[1] || 6 != usb_in_buffer[0]) LOG_WARNING( "ARM-JTAG-EW firmware version %d.%d is untested with this version of OpenOCD. You might experience unexpected behavior.", usb_in_buffer[1], usb_in_buffer[0]); return ERROR_OK; } COMMAND_HANDLER(armjtagew_handle_armjtagew_info_command) { if (armjtagew_get_version_info() == ERROR_OK) { /* attempt to get status */ armjtagew_get_status(); } return ERROR_OK; } static const struct command_registration armjtagew_command_handlers[] = { { .name = "armjtagew_info", .handler = &armjtagew_handle_armjtagew_info_command, .mode = COMMAND_EXEC, .help = "query armjtagew info", }, COMMAND_REGISTRATION_DONE }; struct jtag_interface armjtagew_interface = { .name = "arm-jtag-ew", .commands = armjtagew_command_handlers, .transports = jtag_only, .execute_queue = armjtagew_execute_queue, .speed = armjtagew_speed, .speed_div = armjtagew_speed_div, .khz = armjtagew_khz, .init = armjtagew_init, .quit = armjtagew_quit, }; /************************************************************************** * ARM-JTAG-EW tap functions */ /* 2048 is the max value we can use here */ #define ARMJTAGEW_TAP_BUFFER_SIZE 2048 static int tap_length; static uint8_t tms_buffer[ARMJTAGEW_TAP_BUFFER_SIZE]; static uint8_t tdi_buffer[ARMJTAGEW_TAP_BUFFER_SIZE]; static uint8_t tdo_buffer[ARMJTAGEW_TAP_BUFFER_SIZE]; struct pending_scan_result { int first; /* First bit position in tdo_buffer to read */ int length; /* Number of bits to read */ struct scan_command *command; /* Corresponding scan command */ uint8_t *buffer; }; #define MAX_PENDING_SCAN_RESULTS 256 static int pending_scan_results_length; static struct pending_scan_result pending_scan_results_buffer[MAX_PENDING_SCAN_RESULTS]; static int last_tms; static void armjtagew_tap_init(void) { tap_length = 0; pending_scan_results_length = 0; } static void armjtagew_tap_ensure_space(int scans, int bits) { int available_scans = MAX_PENDING_SCAN_RESULTS - pending_scan_results_length; int available_bits = ARMJTAGEW_TAP_BUFFER_SIZE * 8 - tap_length; if (scans > available_scans || bits > available_bits) armjtagew_tap_execute(); } static void armjtagew_tap_append_step(int tms, int tdi) { last_tms = tms; int index_local = tap_length / 8; if (index_local < ARMJTAGEW_TAP_BUFFER_SIZE) { int bit_index = tap_length % 8; uint8_t bit = 1 << bit_index; if (tms) tms_buffer[index_local] |= bit; else tms_buffer[index_local] &= ~bit; if (tdi) tdi_buffer[index_local] |= bit; else tdi_buffer[index_local] &= ~bit; tap_length++; } else LOG_ERROR("armjtagew_tap_append_step, overflow"); } void armjtagew_tap_append_scan(int length, uint8_t *buffer, struct scan_command *command) { struct pending_scan_result *pending_scan_result = &pending_scan_results_buffer[pending_scan_results_length]; int i; pending_scan_result->first = tap_length; pending_scan_result->length = length; pending_scan_result->command = command; pending_scan_result->buffer = buffer; for (i = 0; i < length; i++) armjtagew_tap_append_step((i < length-1 ? 0 : 1), (buffer[i/8] >> (i%8)) & 1); pending_scan_results_length++; } /* Pad and send a tap sequence to the device, and receive the answer. * For the purpose of padding we assume that we are in idle or pause state. */ static int armjtagew_tap_execute(void) { int byte_length; int tms_offset; int tdi_offset; int i; int result; if (tap_length > 0) { /* Pad last byte so that tap_length is divisible by 8 */ while (tap_length % 8 != 0) { /* More of the last TMS value keeps us in the same state, * analogous to free-running JTAG interfaces. */ armjtagew_tap_append_step(last_tms, 0); } byte_length = tap_length / 8; usb_out_buffer[0] = CMD_TAP_SHIFT; buf_set_u32(usb_out_buffer + 1, 0, 16, byte_length); tms_offset = 3; for (i = 0; i < byte_length; i++) usb_out_buffer[tms_offset + i] = flip_u32(tms_buffer[i], 8); tdi_offset = tms_offset + byte_length; for (i = 0; i < byte_length; i++) usb_out_buffer[tdi_offset + i] = flip_u32(tdi_buffer[i], 8); result = armjtagew_usb_message(armjtagew_handle, 3 + 2 * byte_length, byte_length + 4); if (result == 0) { int stat_local; stat_local = (int)buf_get_u32(usb_in_buffer + byte_length, 0, 32); if (stat_local) { LOG_ERROR( "armjtagew_tap_execute, emulator returned error code %d for a CMD_TAP_SHIFT command", stat_local); return ERROR_JTAG_QUEUE_FAILED; } for (i = 0; i < byte_length; i++) tdo_buffer[i] = flip_u32(usb_in_buffer[i], 8); for (i = 0; i < pending_scan_results_length; i++) { struct pending_scan_result *pending_scan_result = &pending_scan_results_buffer[i]; uint8_t *buffer = pending_scan_result->buffer; int length = pending_scan_result->length; int first = pending_scan_result->first; struct scan_command *command = pending_scan_result->command; /* Copy to buffer */ buf_set_buf(tdo_buffer, first, buffer, 0, length); DEBUG_JTAG_IO("pending scan result, length = %d", length); #ifdef _DEBUG_USB_COMMS_ armjtagew_debug_buffer(buffer, byte_length); #endif if (jtag_read_buffer(buffer, command) != ERROR_OK) { armjtagew_tap_init(); return ERROR_JTAG_QUEUE_FAILED; } if (pending_scan_result->buffer != NULL) free(pending_scan_result->buffer); } } else { LOG_ERROR("armjtagew_tap_execute, wrong result %d, expected %d", result, byte_length); return ERROR_JTAG_QUEUE_FAILED; } armjtagew_tap_init(); } return ERROR_OK; } /**************************************************************************** * JLink USB low-level functions */ static struct armjtagew *armjtagew_usb_open() { usb_init(); const uint16_t vids[] = { USB_VID, 0 }; const uint16_t pids[] = { USB_PID, 0 }; struct usb_dev_handle *dev; if (jtag_usb_open(vids, pids, &dev) != ERROR_OK) return NULL; struct armjtagew *result = malloc(sizeof(struct armjtagew)); result->usb_handle = dev; #if 0 /* usb_set_configuration required under win32 */ usb_set_configuration(dev, dev->config[0].bConfigurationValue); #endif usb_claim_interface(dev, 0); #if 0 /* * This makes problems under Mac OS X. And is not needed * under Windows. Hopefully this will not break a linux build */ usb_set_altinterface(dev, 0); #endif return result; } static void armjtagew_usb_close(struct armjtagew *armjtagew) { usb_close(armjtagew->usb_handle); free(armjtagew); } /* Send a message and receive the reply. */ static int armjtagew_usb_message(struct armjtagew *armjtagew, int out_length, int in_length) { int result; result = armjtagew_usb_write(armjtagew, out_length); if (result == out_length) { result = armjtagew_usb_read(armjtagew, in_length); if (result != in_length) { LOG_ERROR("usb_bulk_read failed (requested=%d, result=%d)", in_length, result); return -1; } } else { LOG_ERROR("usb_bulk_write failed (requested=%d, result=%d)", out_length, result); return -1; } return 0; } /* Write data from out_buffer to USB. */ static int armjtagew_usb_write(struct armjtagew *armjtagew, int out_length) { int result; if (out_length > ARMJTAGEW_OUT_BUFFER_SIZE) { LOG_ERROR("armjtagew_write illegal out_length=%d (max=%d)", out_length, ARMJTAGEW_OUT_BUFFER_SIZE); return -1; } result = usb_bulk_write(armjtagew->usb_handle, ARMJTAGEW_EPT_BULK_OUT, \ (char *)usb_out_buffer, out_length, ARMJTAGEW_USB_TIMEOUT); DEBUG_JTAG_IO("armjtagew_usb_write, out_length = %d, result = %d", out_length, result); #ifdef _DEBUG_USB_COMMS_ armjtagew_debug_buffer(usb_out_buffer, out_length); #endif return result; } /* Read data from USB into in_buffer. */ static int armjtagew_usb_read(struct armjtagew *armjtagew, int exp_in_length) { int result = usb_bulk_read(armjtagew->usb_handle, ARMJTAGEW_EPT_BULK_IN, \ (char *)usb_in_buffer, exp_in_length, ARMJTAGEW_USB_TIMEOUT); DEBUG_JTAG_IO("armjtagew_usb_read, result = %d", result); #ifdef _DEBUG_USB_COMMS_ armjtagew_debug_buffer(usb_in_buffer, result); #endif return result; } #ifdef _DEBUG_USB_COMMS_ #define BYTES_PER_LINE 16 static void armjtagew_debug_buffer(uint8_t *buffer, int length) { char line[81]; char s[4]; int i; int j; for (i = 0; i < length; i += BYTES_PER_LINE) { snprintf(line, 5, "%04x", i); for (j = i; j < i + BYTES_PER_LINE && j < length; j++) { snprintf(s, 4, " %02x", buffer[j]); strcat(line, s); } LOG_DEBUG("%s", line); /* Prevent GDB timeout (writing to log might take some time) */ keep_alive(); } } #endif openocd-0.7.0/src/jtag/drivers/remote_bitbang.c0000644000175000001440000001722612137151331016406 00000000000000/*************************************************************************** * Copyright (C) 2011 by Richard Uhler * * ruhler@mit.edu * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _WIN32 #include #include #endif #include #include "bitbang.h" #ifndef UNIX_PATH_LEN #define UNIX_PATH_LEN 108 #endif /* arbitrary limit on host name length: */ #define REMOTE_BITBANG_HOST_MAX 255 #define REMOTE_BITBANG_RAISE_ERROR(expr ...) \ do { \ LOG_ERROR(expr); \ LOG_ERROR("Terminating openocd."); \ exit(-1); \ } while (0) static char remote_bitbang_host[REMOTE_BITBANG_HOST_MAX] = "openocd"; static uint16_t remote_bitbang_port; FILE *remote_bitbang_in; FILE *remote_bitbang_out; static void remote_bitbang_putc(int c) { if (EOF == fputc(c, remote_bitbang_out)) REMOTE_BITBANG_RAISE_ERROR("remote_bitbang_putc: %s", strerror(errno)); } static int remote_bitbang_quit(void) { if (EOF == fputc('Q', remote_bitbang_out)) { LOG_ERROR("fputs: %s", strerror(errno)); return ERROR_FAIL; } if (EOF == fflush(remote_bitbang_out)) { LOG_ERROR("fflush: %s", strerror(errno)); return ERROR_FAIL; } /* We only need to close one of the FILE*s, because they both use the same */ /* underlying file descriptor. */ if (EOF == fclose(remote_bitbang_out)) { LOG_ERROR("fclose: %s", strerror(errno)); return ERROR_FAIL; } LOG_INFO("remote_bitbang interface quit"); return ERROR_OK; } /* Get the next read response. */ static int remote_bitbang_rread(void) { if (EOF == fflush(remote_bitbang_out)) { remote_bitbang_quit(); REMOTE_BITBANG_RAISE_ERROR("fflush: %s", strerror(errno)); } int c = fgetc(remote_bitbang_in); switch (c) { case '0': return 0; case '1': return 1; default: remote_bitbang_quit(); REMOTE_BITBANG_RAISE_ERROR( "remote_bitbang: invalid read response: %c(%i)", c, c); } } static int remote_bitbang_read(void) { remote_bitbang_putc('R'); return remote_bitbang_rread(); } static void remote_bitbang_write(int tck, int tms, int tdi) { char c = '0' + ((tck ? 0x4 : 0x0) | (tms ? 0x2 : 0x0) | (tdi ? 0x1 : 0x0)); remote_bitbang_putc(c); } static void remote_bitbang_reset(int trst, int srst) { char c = 'r' + ((trst ? 0x2 : 0x0) | (srst ? 0x1 : 0x0)); remote_bitbang_putc(c); } static void remote_bitbang_blink(int on) { char c = on ? 'B' : 'b'; remote_bitbang_putc(c); } static struct bitbang_interface remote_bitbang_bitbang = { .read = &remote_bitbang_read, .write = &remote_bitbang_write, .reset = &remote_bitbang_reset, .blink = &remote_bitbang_blink, }; static int remote_bitbang_init_tcp(void) { LOG_INFO("Connecting to %s:%i", remote_bitbang_host, remote_bitbang_port); int fd = socket(PF_INET, SOCK_STREAM, 0); if (fd < 0) { LOG_ERROR("socket: %s", strerror(errno)); return ERROR_FAIL; } struct hostent *hent = gethostbyname(remote_bitbang_host); if (hent == NULL) { char *errorstr = "???"; switch (h_errno) { case HOST_NOT_FOUND: errorstr = "host not found"; break; case NO_ADDRESS: errorstr = "no address"; break; case NO_RECOVERY: errorstr = "no recovery"; break; case TRY_AGAIN: errorstr = "try again"; break; } LOG_ERROR("gethostbyname: %s", errorstr); return ERROR_FAIL; } struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(remote_bitbang_port); addr.sin_addr = *(struct in_addr *)hent->h_addr; if (connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) { LOG_ERROR("connect: %s", strerror(errno)); return ERROR_FAIL; } remote_bitbang_in = fdopen(fd, "r"); if (remote_bitbang_in == NULL) { LOG_ERROR("fdopen: failed to open read stream"); return ERROR_FAIL; } remote_bitbang_out = fdopen(fd, "w"); if (remote_bitbang_out == NULL) { LOG_ERROR("fdopen: failed to open write stream"); return ERROR_FAIL; } LOG_INFO("remote_bitbang driver initialized"); return ERROR_OK; } static int remote_bitbang_init_unix(void) { LOG_INFO("Connecting to unix socket %s", remote_bitbang_host); int fd = socket(PF_UNIX, SOCK_STREAM, 0); if (fd < 0) { LOG_ERROR("socket: %s", strerror(errno)); return ERROR_FAIL; } struct sockaddr_un addr; addr.sun_family = AF_UNIX; strncpy(addr.sun_path, remote_bitbang_host, UNIX_PATH_LEN); addr.sun_path[UNIX_PATH_LEN-1] = '\0'; if (connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) { LOG_ERROR("connect: %s", strerror(errno)); return ERROR_FAIL; } remote_bitbang_in = fdopen(fd, "r"); if (remote_bitbang_in == NULL) { LOG_ERROR("fdopen: failed to open read stream"); return ERROR_FAIL; } remote_bitbang_out = fdopen(fd, "w"); if (remote_bitbang_out == NULL) { LOG_ERROR("fdopen: failed to open write stream"); return ERROR_FAIL; } LOG_INFO("remote_bitbang driver initialized"); return ERROR_OK; } static int remote_bitbang_init(void) { bitbang_interface = &remote_bitbang_bitbang; LOG_INFO("Initializing remote_bitbang driver"); if (remote_bitbang_port == 0) return remote_bitbang_init_unix(); return remote_bitbang_init_tcp(); } COMMAND_HANDLER(remote_bitbang_handle_remote_bitbang_port_command) { if (CMD_ARGC == 1) { COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], remote_bitbang_port); return ERROR_OK; } return ERROR_COMMAND_SYNTAX_ERROR; } COMMAND_HANDLER(remote_bitbang_handle_remote_bitbang_host_command) { if (CMD_ARGC == 1) { strncpy(remote_bitbang_host, CMD_ARGV[0], REMOTE_BITBANG_HOST_MAX); remote_bitbang_host[REMOTE_BITBANG_HOST_MAX-1] = '\0'; return ERROR_OK; } return ERROR_COMMAND_SYNTAX_ERROR; } static const struct command_registration remote_bitbang_command_handlers[] = { { .name = "remote_bitbang_port", .handler = remote_bitbang_handle_remote_bitbang_port_command, .mode = COMMAND_CONFIG, .help = "Set the port to use to connect to the remote jtag.\n" " if 0, use unix sockets to connect to the remote jtag.", .usage = "port_number", }, { .name = "remote_bitbang_host", .handler = remote_bitbang_handle_remote_bitbang_host_command, .mode = COMMAND_CONFIG, .help = "Set the host to use to connect to the remote jtag.\n" " if port is 0, this is the name of the unix socket to use.", .usage = "host_name", }, COMMAND_REGISTRATION_DONE, }; struct jtag_interface remote_bitbang_interface = { .name = "remote_bitbang", .execute_queue = &bitbang_execute_queue, .commands = remote_bitbang_command_handlers, .init = &remote_bitbang_init, .quit = &remote_bitbang_quit, }; openocd-0.7.0/src/jtag/drivers/at91rm9200.c0000644000175000001440000001750212137151331015052 00000000000000/*************************************************************************** * Copyright (C) 2006 by Anders Larsen * * al@alarsen.net * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "bitbang.h" #include /* AT91RM9200 */ #define AT91C_BASE_SYS (0xfffff000) /* GPIO assignment */ #define PIOA (0 << 7) #define PIOB (1 << 7) #define PIOC (2 << 7) #define PIOD (3 << 7) #define PIO_PER (0) /* PIO enable */ #define PIO_OER (4) /* output enable */ #define PIO_ODR (5) /* output disable */ #define PIO_SODR (12) /* set output data */ #define PIO_CODR (13) /* clear output data */ #define PIO_PDSR (15) /* pin data status */ #define PIO_PPUER (25) /* pull-up enable */ #define NC (0) /* not connected */ #define P0 (1 << 0) #define P1 (1 << 1) #define P2 (1 << 2) #define P3 (1 << 3) #define P4 (1 << 4) #define P5 (1 << 5) #define P6 (1 << 6) #define P7 (1 << 7) #define P8 (1 << 8) #define P9 (1 << 9) #define P10 (1 << 10) #define P11 (1 << 11) #define P12 (1 << 12) #define P13 (1 << 13) #define P14 (1 << 14) #define P15 (1 << 15) #define P16 (1 << 16) #define P17 (1 << 17) #define P18 (1 << 18) #define P19 (1 << 19) #define P20 (1 << 20) #define P21 (1 << 21) #define P22 (1 << 22) #define P23 (1 << 23) #define P24 (1 << 24) #define P25 (1 << 25) #define P26 (1 << 26) #define P27 (1 << 27) #define P28 (1 << 28) #define P29 (1 << 29) #define P30 (1 << 30) #define P31 (1 << 31) struct device_t { char *name; int TDO_PIO; /* PIO holding TDO */ uint32_t TDO_MASK; /* TDO bitmask */ int TRST_PIO; /* PIO holding TRST */ uint32_t TRST_MASK; /* TRST bitmask */ int TMS_PIO; /* PIO holding TMS */ uint32_t TMS_MASK; /* TMS bitmask */ int TCK_PIO; /* PIO holding TCK */ uint32_t TCK_MASK; /* TCK bitmask */ int TDI_PIO; /* PIO holding TDI */ uint32_t TDI_MASK; /* TDI bitmask */ int SRST_PIO; /* PIO holding SRST */ uint32_t SRST_MASK; /* SRST bitmask */ }; static struct device_t devices[] = { { "rea_ecr", PIOD, P27, PIOA, NC, PIOD, P23, PIOD, P24, PIOD, P26, PIOC, P5 }, { .name = NULL }, }; /* configuration */ static char *at91rm9200_device; /* interface variables */ static struct device_t *device; static int dev_mem_fd; static void *sys_controller; static uint32_t *pio_base; /* low level command set */ static int at91rm9200_read(void); static void at91rm9200_write(int tck, int tms, int tdi); static void at91rm9200_reset(int trst, int srst); static int at91rm9200_init(void); static int at91rm9200_quit(void); static struct bitbang_interface at91rm9200_bitbang = { .read = at91rm9200_read, .write = at91rm9200_write, .reset = at91rm9200_reset, .blink = 0 }; static int at91rm9200_read(void) { return (pio_base[device->TDO_PIO + PIO_PDSR] & device->TDO_MASK) != 0; } static void at91rm9200_write(int tck, int tms, int tdi) { if (tck) pio_base[device->TCK_PIO + PIO_SODR] = device->TCK_MASK; else pio_base[device->TCK_PIO + PIO_CODR] = device->TCK_MASK; if (tms) pio_base[device->TMS_PIO + PIO_SODR] = device->TMS_MASK; else pio_base[device->TMS_PIO + PIO_CODR] = device->TMS_MASK; if (tdi) pio_base[device->TDI_PIO + PIO_SODR] = device->TDI_MASK; else pio_base[device->TDI_PIO + PIO_CODR] = device->TDI_MASK; } /* (1) assert or (0) deassert reset lines */ static void at91rm9200_reset(int trst, int srst) { if (trst == 0) pio_base[device->TRST_PIO + PIO_SODR] = device->TRST_MASK; else if (trst == 1) pio_base[device->TRST_PIO + PIO_CODR] = device->TRST_MASK; if (srst == 0) pio_base[device->SRST_PIO + PIO_SODR] = device->SRST_MASK; else if (srst == 1) pio_base[device->SRST_PIO + PIO_CODR] = device->SRST_MASK; } COMMAND_HANDLER(at91rm9200_handle_device_command) { if (CMD_ARGC == 0) return ERROR_COMMAND_SYNTAX_ERROR; /* only if the device name wasn't overwritten by cmdline */ if (at91rm9200_device == 0) { at91rm9200_device = malloc(strlen(CMD_ARGV[0]) + sizeof(char)); strcpy(at91rm9200_device, CMD_ARGV[0]); } return ERROR_OK; } static const struct command_registration at91rm9200_command_handlers[] = { { .name = "at91rm9200_device", .handler = &at91rm9200_handle_device_command, .mode = COMMAND_CONFIG, .help = "query armjtagew info", }, COMMAND_REGISTRATION_DONE }; struct jtag_interface at91rm9200_interface = { .name = "at91rm9200", .execute_queue = bitbang_execute_queue, .commands = at91rm9200_command_handlers, .init = at91rm9200_init, .quit = at91rm9200_quit, }; static int at91rm9200_init(void) { struct device_t *cur_device; cur_device = devices; if (at91rm9200_device == NULL || at91rm9200_device[0] == 0) { at91rm9200_device = "rea_ecr"; LOG_WARNING("No at91rm9200 device specified, using default 'rea_ecr'"); } while (cur_device->name) { if (strcmp(cur_device->name, at91rm9200_device) == 0) { device = cur_device; break; } cur_device++; } if (!device) { LOG_ERROR("No matching device found for %s", at91rm9200_device); return ERROR_JTAG_INIT_FAILED; } bitbang_interface = &at91rm9200_bitbang; dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC); if (dev_mem_fd < 0) { perror("open"); return ERROR_JTAG_INIT_FAILED; } sys_controller = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, dev_mem_fd, AT91C_BASE_SYS); if (sys_controller == MAP_FAILED) { perror("mmap"); close(dev_mem_fd); return ERROR_JTAG_INIT_FAILED; } pio_base = (uint32_t *)sys_controller + 0x100; /* * Configure TDO as an input, and TDI, TCK, TMS, TRST, SRST * as outputs. Drive TDI and TCK low, and TMS/TRST/SRST high. */ pio_base[device->TDI_PIO + PIO_CODR] = device->TDI_MASK; pio_base[device->TDI_PIO + PIO_OER] = device->TDI_MASK; pio_base[device->TDI_PIO + PIO_PER] = device->TDI_MASK; pio_base[device->TCK_PIO + PIO_CODR] = device->TCK_MASK; pio_base[device->TCK_PIO + PIO_OER] = device->TCK_MASK; pio_base[device->TCK_PIO + PIO_PER] = device->TCK_MASK; pio_base[device->TMS_PIO + PIO_SODR] = device->TMS_MASK; pio_base[device->TMS_PIO + PIO_OER] = device->TMS_MASK; pio_base[device->TMS_PIO + PIO_PER] = device->TMS_MASK; pio_base[device->TRST_PIO + PIO_SODR] = device->TRST_MASK; pio_base[device->TRST_PIO + PIO_OER] = device->TRST_MASK; pio_base[device->TRST_PIO + PIO_PER] = device->TRST_MASK; pio_base[device->SRST_PIO + PIO_SODR] = device->SRST_MASK; pio_base[device->SRST_PIO + PIO_OER] = device->SRST_MASK; pio_base[device->SRST_PIO + PIO_PER] = device->SRST_MASK; pio_base[device->TDO_PIO + PIO_ODR] = device->TDO_MASK; pio_base[device->TDO_PIO + PIO_PPUER] = device->TDO_MASK; pio_base[device->TDO_PIO + PIO_PER] = device->TDO_MASK; return ERROR_OK; } static int at91rm9200_quit(void) { return ERROR_OK; } openocd-0.7.0/src/jtag/drivers/buspirate.c0000644000175000001440000005607612137151331015431 00000000000000/*************************************************************************** * Copyright (C) 2010 by Michal Demin * * based on usbprog.c and arm-jtag-ew.c * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #undef DEBUG_SERIAL /*#define DEBUG_SERIAL */ static int buspirate_execute_queue(void); static int buspirate_init(void); static int buspirate_quit(void); static void buspirate_end_state(tap_state_t state); static void buspirate_state_move(void); static void buspirate_path_move(int num_states, tap_state_t *path); static void buspirate_runtest(int num_cycles); static void buspirate_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command); #define CMD_UNKNOWN 0x00 #define CMD_PORT_MODE 0x01 #define CMD_FEATURE 0x02 #define CMD_READ_ADCS 0x03 /*#define CMD_TAP_SHIFT 0x04 // old protocol */ #define CMD_TAP_SHIFT 0x05 #define CMD_ENTER_OOCD 0x06 #define CMD_UART_SPEED 0x07 #define CMD_JTAG_SPEED 0x08 /* Not all OSes have this speed defined */ #if !defined(B1000000) #define B1000000 0010010 #endif enum { MODE_HIZ = 0, MODE_JTAG = 1, /* push-pull outputs */ MODE_JTAG_OD = 2, /* open-drain outputs */ }; enum { FEATURE_LED = 0x01, FEATURE_VREG = 0x02, FEATURE_TRST = 0x04, FEATURE_SRST = 0x08, FEATURE_PULLUP = 0x10 }; enum { ACTION_DISABLE = 0, ACTION_ENABLE = 1 }; enum { SERIAL_NORMAL = 0, SERIAL_FAST = 1 }; static int buspirate_fd = -1; static int buspirate_pinmode = MODE_JTAG_OD; static int buspirate_baudrate = SERIAL_NORMAL; static int buspirate_vreg; static int buspirate_pullup; static char *buspirate_port; /* TAP interface */ static void buspirate_tap_init(void); static int buspirate_tap_execute(void); static void buspirate_tap_append(int tms, int tdi); static void buspirate_tap_append_scan(int length, uint8_t *buffer, struct scan_command *command); static void buspirate_tap_make_space(int scan, int bits); static void buspirate_reset(int trst, int srst); /* low level interface */ static void buspirate_jtag_reset(int); static void buspirate_jtag_enable(int); static unsigned char buspirate_jtag_command(int, char *, int); static void buspirate_jtag_set_speed(int, char); static void buspirate_jtag_set_mode(int, char); static void buspirate_jtag_set_feature(int, char, char); static void buspirate_jtag_get_adcs(int); /* low level HW communication interface */ static int buspirate_serial_open(char *port); static int buspirate_serial_setspeed(int fd, char speed); static int buspirate_serial_write(int fd, char *buf, int size); static int buspirate_serial_read(int fd, char *buf, int size); static void buspirate_serial_close(int fd); static void buspirate_print_buffer(char *buf, int size); static int buspirate_execute_queue(void) { /* currently processed command */ struct jtag_command *cmd = jtag_command_queue; int scan_size; enum scan_type type; uint8_t *buffer; while (cmd) { switch (cmd->type) { case JTAG_RUNTEST: DEBUG_JTAG_IO("runtest %i cycles, end in %s", cmd->cmd.runtest->num_cycles, tap_state_name(cmd->cmd.runtest ->end_state)); buspirate_end_state(cmd->cmd.runtest ->end_state); buspirate_runtest(cmd->cmd.runtest ->num_cycles); break; case JTAG_TLR_RESET: DEBUG_JTAG_IO("statemove end in %s", tap_state_name(cmd->cmd.statemove ->end_state)); buspirate_end_state(cmd->cmd.statemove ->end_state); buspirate_state_move(); break; case JTAG_PATHMOVE: DEBUG_JTAG_IO("pathmove: %i states, end in %s", cmd->cmd.pathmove->num_states, tap_state_name(cmd->cmd.pathmove ->path[cmd->cmd.pathmove ->num_states - 1])); buspirate_path_move(cmd->cmd.pathmove ->num_states, cmd->cmd.pathmove->path); break; case JTAG_SCAN: DEBUG_JTAG_IO("scan end in %s", tap_state_name(cmd->cmd.scan ->end_state)); buspirate_end_state(cmd->cmd.scan ->end_state); scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); type = jtag_scan_type(cmd->cmd.scan); buspirate_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size, cmd->cmd.scan); break; case JTAG_RESET: DEBUG_JTAG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); /* flush buffers, so we can reset */ buspirate_tap_execute(); if (cmd->cmd.reset->trst == 1) tap_set_state(TAP_RESET); buspirate_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); break; case JTAG_SLEEP: DEBUG_JTAG_IO("sleep %i", cmd->cmd.sleep->us); buspirate_tap_execute(); jtag_sleep(cmd->cmd.sleep->us); break; default: LOG_ERROR("BUG: unknown JTAG command type encountered"); exit(-1); } cmd = cmd->next; } return buspirate_tap_execute(); } static int buspirate_init(void) { if (buspirate_port == NULL) { LOG_ERROR("You need to specify the serial port!"); return ERROR_JTAG_INIT_FAILED; } buspirate_fd = buspirate_serial_open(buspirate_port); if (buspirate_fd == -1) { LOG_ERROR("Could not open serial port"); return ERROR_JTAG_INIT_FAILED; } buspirate_serial_setspeed(buspirate_fd, SERIAL_NORMAL); buspirate_jtag_enable(buspirate_fd); if (buspirate_baudrate != SERIAL_NORMAL) buspirate_jtag_set_speed(buspirate_fd, SERIAL_FAST); LOG_INFO("Buspirate Interface ready!"); buspirate_tap_init(); buspirate_jtag_set_mode(buspirate_fd, buspirate_pinmode); buspirate_jtag_set_feature(buspirate_fd, FEATURE_VREG, (buspirate_vreg == 1) ? ACTION_ENABLE : ACTION_DISABLE); buspirate_jtag_set_feature(buspirate_fd, FEATURE_PULLUP, (buspirate_pullup == 1) ? ACTION_ENABLE : ACTION_DISABLE); buspirate_reset(0, 0); return ERROR_OK; } static int buspirate_quit(void) { LOG_INFO("Shutting down buspirate."); buspirate_jtag_set_mode(buspirate_fd, MODE_HIZ); buspirate_jtag_set_speed(buspirate_fd, SERIAL_NORMAL); buspirate_jtag_reset(buspirate_fd); buspirate_serial_close(buspirate_fd); if (buspirate_port) { free(buspirate_port); buspirate_port = NULL; } return ERROR_OK; } /* openocd command interface */ COMMAND_HANDLER(buspirate_handle_adc_command) { if (buspirate_fd == -1) return ERROR_OK; /* send the command */ buspirate_jtag_get_adcs(buspirate_fd); return ERROR_OK; } COMMAND_HANDLER(buspirate_handle_vreg_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; if (atoi(CMD_ARGV[0]) == 1) buspirate_vreg = 1; else if (atoi(CMD_ARGV[0]) == 0) buspirate_vreg = 0; else LOG_ERROR("usage: buspirate_vreg <1|0>"); return ERROR_OK; } COMMAND_HANDLER(buspirate_handle_pullup_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; if (atoi(CMD_ARGV[0]) == 1) buspirate_pullup = 1; else if (atoi(CMD_ARGV[0]) == 0) buspirate_pullup = 0; else LOG_ERROR("usage: buspirate_pullup <1|0>"); return ERROR_OK; } COMMAND_HANDLER(buspirate_handle_led_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; if (atoi(CMD_ARGV[0]) == 1) { /* enable led */ buspirate_jtag_set_feature(buspirate_fd, FEATURE_LED, ACTION_ENABLE); } else if (atoi(CMD_ARGV[0]) == 0) { /* disable led */ buspirate_jtag_set_feature(buspirate_fd, FEATURE_LED, ACTION_DISABLE); } else { LOG_ERROR("usage: buspirate_led <1|0>"); } return ERROR_OK; } COMMAND_HANDLER(buspirate_handle_mode_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGV[0][0] == 'n') buspirate_pinmode = MODE_JTAG; else if (CMD_ARGV[0][0] == 'o') buspirate_pinmode = MODE_JTAG_OD; else LOG_ERROR("usage: buspirate_mode "); return ERROR_OK; } COMMAND_HANDLER(buspirate_handle_speed_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGV[0][0] == 'n') buspirate_baudrate = SERIAL_NORMAL; else if (CMD_ARGV[0][0] == 'f') buspirate_baudrate = SERIAL_FAST; else LOG_ERROR("usage: buspirate_speed "); return ERROR_OK; } COMMAND_HANDLER(buspirate_handle_port_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; if (buspirate_port == NULL) buspirate_port = strdup(CMD_ARGV[0]); return ERROR_OK; } static const struct command_registration buspirate_command_handlers[] = { { .name = "buspirate_adc", .handler = &buspirate_handle_adc_command, .mode = COMMAND_EXEC, .help = "reads voltages on adc pins", }, { .name = "buspirate_vreg", .usage = "<1|0>", .handler = &buspirate_handle_vreg_command, .mode = COMMAND_CONFIG, .help = "changes the state of voltage regulators", }, { .name = "buspirate_pullup", .usage = "<1|0>", .handler = &buspirate_handle_pullup_command, .mode = COMMAND_CONFIG, .help = "changes the state of pullup", }, { .name = "buspirate_led", .usage = "<1|0>", .handler = &buspirate_handle_led_command, .mode = COMMAND_EXEC, .help = "changes the state of led", }, { .name = "buspirate_speed", .usage = "", .handler = &buspirate_handle_speed_command, .mode = COMMAND_CONFIG, .help = "speed of the interface", }, { .name = "buspirate_mode", .usage = "", .handler = &buspirate_handle_mode_command, .mode = COMMAND_CONFIG, .help = "pin mode of the interface", }, { .name = "buspirate_port", .usage = "/dev/ttyUSB0", .handler = &buspirate_handle_port_command, .mode = COMMAND_CONFIG, .help = "name of the serial port to open", }, COMMAND_REGISTRATION_DONE }; struct jtag_interface buspirate_interface = { .name = "buspirate", .execute_queue = buspirate_execute_queue, .commands = buspirate_command_handlers, .init = buspirate_init, .quit = buspirate_quit }; /*************** jtag execute commands **********************/ static void buspirate_end_state(tap_state_t state) { if (tap_is_state_stable(state)) tap_set_end_state(state); else { LOG_ERROR("BUG: %i is not a valid end state", state); exit(-1); } } static void buspirate_state_move(void) { int i = 0, tms = 0; uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state()); int tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); for (i = 0; i < tms_count; i++) { tms = (tms_scan >> i) & 1; buspirate_tap_append(tms, 0); } tap_set_state(tap_get_end_state()); } static void buspirate_path_move(int num_states, tap_state_t *path) { int i; for (i = 0; i < num_states; i++) { if (tap_state_transition(tap_get_state(), false) == path[i]) { buspirate_tap_append(0, 0); } else if (tap_state_transition(tap_get_state(), true) == path[i]) { buspirate_tap_append(1, 0); } else { LOG_ERROR("BUG: %s -> %s isn't a valid " "TAP transition", tap_state_name(tap_get_state()), tap_state_name(path[i])); exit(-1); } tap_set_state(path[i]); } tap_set_end_state(tap_get_state()); } static void buspirate_runtest(int num_cycles) { int i; tap_state_t saved_end_state = tap_get_end_state(); /* only do a state_move when we're not already in IDLE */ if (tap_get_state() != TAP_IDLE) { buspirate_end_state(TAP_IDLE); buspirate_state_move(); } for (i = 0; i < num_cycles; i++) buspirate_tap_append(0, 0); DEBUG_JTAG_IO("runtest: cur_state %s end_state %s", tap_state_name(tap_get_state()), tap_state_name(tap_get_end_state())); /* finish in end_state */ buspirate_end_state(saved_end_state); if (tap_get_state() != tap_get_end_state()) buspirate_state_move(); } static void buspirate_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command) { tap_state_t saved_end_state; buspirate_tap_make_space(1, scan_size+8); /* is 8 correct ? (2 moves = 16) */ saved_end_state = tap_get_end_state(); buspirate_end_state(ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT); /* Only move if we're not already there */ if (tap_get_state() != tap_get_end_state()) buspirate_state_move(); buspirate_tap_append_scan(scan_size, buffer, command); /* move to PAUSE */ buspirate_tap_append(0, 0); /* restore the saved state */ buspirate_end_state(saved_end_state); tap_set_state(ir_scan ? TAP_IRPAUSE : TAP_DRPAUSE); if (tap_get_state() != tap_get_end_state()) buspirate_state_move(); } /************************* TAP related stuff **********/ #define BUSPIRATE_BUFFER_SIZE 1024 #define BUSPIRATE_MAX_PENDING_SCANS 32 static char tms_chain[BUSPIRATE_BUFFER_SIZE]; /* send */ static char tdi_chain[BUSPIRATE_BUFFER_SIZE]; /* send */ static int tap_chain_index; struct pending_scan_result /* this was stolen from arm-jtag-ew */ { int first; /* First bit position in tdo_buffer to read */ int length; /* Number of bits to read */ struct scan_command *command; /* Corresponding scan command */ uint8_t *buffer; }; static struct pending_scan_result tap_pending_scans[BUSPIRATE_MAX_PENDING_SCANS]; static int tap_pending_scans_num; static void buspirate_tap_init(void) { tap_chain_index = 0; tap_pending_scans_num = 0; } static int buspirate_tap_execute(void) { char tmp[4096]; uint8_t *in_buf; int i; int fill_index = 0; int ret; int bytes_to_send; if (tap_chain_index <= 0) return ERROR_OK; LOG_DEBUG("executing tap num bits = %i scans = %i", tap_chain_index, tap_pending_scans_num); bytes_to_send = (tap_chain_index+7) / 8; tmp[0] = CMD_TAP_SHIFT; /* this command expects number of bits */ tmp[1] = (char)(tap_chain_index >> 8); /* high */ tmp[2] = (char)(tap_chain_index); /* low */ fill_index = 3; for (i = 0; i < bytes_to_send; i++) { tmp[fill_index] = tdi_chain[i]; fill_index++; tmp[fill_index] = tms_chain[i]; fill_index++; } ret = buspirate_serial_write(buspirate_fd, tmp, 3 + bytes_to_send*2); if (ret != bytes_to_send*2+3) { LOG_ERROR("error writing :("); return ERROR_JTAG_DEVICE_ERROR; } ret = buspirate_serial_read(buspirate_fd, tmp, bytes_to_send + 3); if (ret != bytes_to_send + 3) { LOG_ERROR("error reading"); return ERROR_FAIL; } in_buf = (uint8_t *)(&tmp[3]); /* parse the scans */ for (i = 0; i < tap_pending_scans_num; i++) { uint8_t *buffer = tap_pending_scans[i].buffer; int length = tap_pending_scans[i].length; int first = tap_pending_scans[i].first; struct scan_command *command = tap_pending_scans[i].command; /* copy bits from buffer */ buf_set_buf(in_buf, first, buffer, 0, length); /* return buffer to higher level */ if (jtag_read_buffer(buffer, command) != ERROR_OK) { buspirate_tap_init(); return ERROR_JTAG_QUEUE_FAILED; } free(buffer); } tap_pending_scans_num = 0; tap_chain_index = 0; return ERROR_OK; } static void buspirate_tap_make_space(int scans, int bits) { int have_scans = BUSPIRATE_MAX_PENDING_SCANS - tap_pending_scans_num; int have_bits = BUSPIRATE_BUFFER_SIZE * 8 - tap_chain_index; if ((have_scans < scans) || (have_bits < bits)) buspirate_tap_execute(); } static void buspirate_tap_append(int tms, int tdi) { int chain_index; buspirate_tap_make_space(0, 1); chain_index = tap_chain_index / 8; if (chain_index < BUSPIRATE_BUFFER_SIZE) { int bit_index = tap_chain_index % 8; uint8_t bit = 1 << bit_index; if (tms) tms_chain[chain_index] |= bit; else tms_chain[chain_index] &= ~bit; if (tdi) tdi_chain[chain_index] |= bit; else tdi_chain[chain_index] &= ~bit; tap_chain_index++; } else LOG_ERROR("tap_chain overflow, bad things will happen"); } static void buspirate_tap_append_scan(int length, uint8_t *buffer, struct scan_command *command) { int i; tap_pending_scans[tap_pending_scans_num].length = length; tap_pending_scans[tap_pending_scans_num].buffer = buffer; tap_pending_scans[tap_pending_scans_num].command = command; tap_pending_scans[tap_pending_scans_num].first = tap_chain_index; for (i = 0; i < length; i++) { int tms = (i < length-1 ? 0 : 1); int tdi = (buffer[i/8] >> (i%8)) & 1; buspirate_tap_append(tms, tdi); } tap_pending_scans_num++; } /*************** jtag wrapper functions *********************/ /* (1) assert or (0) deassert reset lines */ static void buspirate_reset(int trst, int srst) { LOG_DEBUG("trst: %i, srst: %i", trst, srst); if (trst) buspirate_jtag_set_feature(buspirate_fd, FEATURE_TRST, ACTION_DISABLE); else buspirate_jtag_set_feature(buspirate_fd, FEATURE_TRST, ACTION_ENABLE); if (srst) buspirate_jtag_set_feature(buspirate_fd, FEATURE_SRST, ACTION_DISABLE); else buspirate_jtag_set_feature(buspirate_fd, FEATURE_SRST, ACTION_ENABLE); } /*************** jtag lowlevel functions ********************/ static void buspirate_jtag_enable(int fd) { int ret; char tmp[21] = { [0 ... 20] = 0x00 }; int done = 0; int cmd_sent = 0; LOG_DEBUG("Entering binary mode"); buspirate_serial_write(fd, tmp, 20); usleep(10000); /* reads 1 to n "BBIO1"s and one "OCD1" */ while (!done) { ret = buspirate_serial_read(fd, tmp, 4); if (ret != 4) { LOG_ERROR("Buspirate error. Is binary" "/OpenOCD support enabled?"); exit(-1); } if (strncmp(tmp, "BBIO", 4) == 0) { ret = buspirate_serial_read(fd, tmp, 1); if (ret != 1) { LOG_ERROR("Buspirate did not answer correctly! " "Do you have correct firmware?"); exit(-1); } if (tmp[0] != '1') { LOG_ERROR("Unsupported binary protocol"); exit(-1); } if (cmd_sent == 0) { cmd_sent = 1; tmp[0] = CMD_ENTER_OOCD; ret = buspirate_serial_write(fd, tmp, 1); if (ret != 1) { LOG_ERROR("error reading"); exit(-1); } } } else if (strncmp(tmp, "OCD1", 4) == 0) done = 1; else { LOG_ERROR("Buspirate did not answer correctly! " "Do you have correct firmware?"); exit(-1); } } } static void buspirate_jtag_reset(int fd) { char tmp[5]; tmp[0] = 0x00; /* exit OCD1 mode */ buspirate_serial_write(fd, tmp, 1); usleep(10000); /* We ignore the return value here purposly, nothing we can do */ buspirate_serial_read(fd, tmp, 5); if (strncmp(tmp, "BBIO1", 5) == 0) { tmp[0] = 0x0F; /* reset BP */ buspirate_serial_write(fd, tmp, 1); } else LOG_ERROR("Unable to restart buspirate!"); } static void buspirate_jtag_set_speed(int fd, char speed) { int ret; char tmp[2]; char ack[2]; ack[0] = 0xAA; ack[1] = 0x55; tmp[0] = CMD_UART_SPEED; tmp[1] = speed; buspirate_jtag_command(fd, tmp, 2); /* here the adapter changes speed, we need follow */ buspirate_serial_setspeed(fd, speed); buspirate_serial_write(fd, ack, 2); ret = buspirate_serial_read(fd, tmp, 2); if (ret != 2) { LOG_ERROR("Buspirate did not ack speed change"); exit(-1); } if ((tmp[0] != CMD_UART_SPEED) || (tmp[1] != speed)) { LOG_ERROR("Buspirate did not reply as expected"); exit(-1); } LOG_INFO("Buspirate switched to %s mode", (speed == SERIAL_NORMAL) ? "normal" : "FAST"); } static void buspirate_jtag_set_mode(int fd, char mode) { char tmp[2]; tmp[0] = CMD_PORT_MODE; tmp[1] = mode; buspirate_jtag_command(fd, tmp, 2); } static void buspirate_jtag_set_feature(int fd, char feat, char action) { char tmp[3]; tmp[0] = CMD_FEATURE; tmp[1] = feat; /* what */ tmp[2] = action; /* action */ buspirate_jtag_command(fd, tmp, 3); } static void buspirate_jtag_get_adcs(int fd) { uint8_t tmp[10]; uint16_t a, b, c, d; tmp[0] = CMD_READ_ADCS; buspirate_jtag_command(fd, (char *)tmp, 1); a = tmp[2] << 8 | tmp[3]; b = tmp[4] << 8 | tmp[5]; c = tmp[6] << 8 | tmp[7]; d = tmp[8] << 8 | tmp[9]; LOG_INFO("ADC: ADC_Pin = %.02f VPullup = %.02f V33 = %.02f " "V50 = %.02f", ((float)a)/155.1515, ((float)b)/155.1515, ((float)c)/155.1515, ((float)d)/155.1515); } static unsigned char buspirate_jtag_command(int fd, char *cmd, int cmdlen) { int res; int len = 0; res = buspirate_serial_write(fd, cmd, cmdlen); if ((cmd[0] == CMD_UART_SPEED) || (cmd[0] == CMD_PORT_MODE) || (cmd[0] == CMD_FEATURE) || (cmd[0] == CMD_JTAG_SPEED)) return 1; if (res == cmdlen) { switch (cmd[0]) { case CMD_READ_ADCS: len = 10; /* 2*sizeof(char)+4*sizeof(uint16_t) */ break; case CMD_TAP_SHIFT: len = cmdlen; break; default: LOG_INFO("Wrong !"); } res = buspirate_serial_read(fd, cmd, len); if (res > 0) return (unsigned char)cmd[1]; else return -1; } else return -1; return 0; } /* low level serial port */ /* TODO add support for WIN32 and others ! */ static int buspirate_serial_open(char *port) { int fd; fd = open(buspirate_port, O_RDWR | O_NOCTTY | O_NDELAY); return fd; } static int buspirate_serial_setspeed(int fd, char speed) { struct termios t_opt; speed_t baud = (speed == SERIAL_FAST) ? B1000000 : B115200; /* set the serial port parameters */ fcntl(fd, F_SETFL, 0); tcgetattr(fd, &t_opt); cfsetispeed(&t_opt, baud); cfsetospeed(&t_opt, baud); t_opt.c_cflag |= (CLOCAL | CREAD); t_opt.c_cflag &= ~PARENB; t_opt.c_cflag &= ~CSTOPB; t_opt.c_cflag &= ~CSIZE; t_opt.c_cflag |= CS8; t_opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); t_opt.c_iflag &= ~(IXON | IXOFF | IXANY); t_opt.c_oflag &= ~OPOST; t_opt.c_cc[VMIN] = 0; t_opt.c_cc[VTIME] = 10; tcflush(fd, TCIFLUSH); tcsetattr(fd, TCSANOW, &t_opt); return 0; } static int buspirate_serial_write(int fd, char *buf, int size) { int ret = 0; ret = write(fd, buf, size); LOG_DEBUG("size = %d ret = %d", size, ret); buspirate_print_buffer(buf, size); if (ret != size) LOG_ERROR("Error sending data"); return ret; } static int buspirate_serial_read(int fd, char *buf, int size) { int len = 0; int ret = 0; int timeout = 0; while (len < size) { ret = read(fd, buf+len, size-len); if (ret == -1) return -1; if (ret == 0) { timeout++; if (timeout >= 10) break; continue; } len += ret; } LOG_DEBUG("should have read = %d actual size = %d", size, len); buspirate_print_buffer(buf, len); if (len != size) LOG_ERROR("Error reading data"); return len; } static void buspirate_serial_close(int fd) { close(fd); } #define LINE_SIZE 81 #define BYTES_PER_LINE 16 static void buspirate_print_buffer(char *buf, int size) { char line[LINE_SIZE]; char tmp[10]; int offset = 0; line[0] = 0; while (offset < size) { snprintf(tmp, 5, "%02x ", (uint8_t)buf[offset]); offset++; strcat(line, tmp); if (offset % BYTES_PER_LINE == 0) { LOG_DEBUG("%s", line); line[0] = 0; } } if (line[0] != 0) LOG_DEBUG("%s", line); } openocd-0.7.0/src/jtag/drivers/sysfsgpio.c0000644000175000001440000003161212137151331015446 00000000000000/*************************************************************************** * Copyright (C) 2012 by Creative Product Design, marc @ cpdesign.com.au * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /** * @file * This driver implements a bitbang jtag interface using gpio lines via * sysfs. * The aim of this driver implementation is use system GPIOs but avoid the * need for a additional kernel driver. * (Note memory mapped IO is another option, however it doesn't mix well with * the kernel gpiolib driver - which makes sense I guess.) * * A gpio is required for tck, tms, tdi and tdo. One or both of srst and trst * must be also be specified. The required jtag gpios are specified via the * sysfsgpio_jtag_nums command or the relevant sysfsgpio_XXX_num commang. * The srst and trst gpios are set via the sysfsgpio_srst_num and * sysfsgpio_trst_num respectively. GPIO numbering follows the kernel * convention of starting from 0. * * The gpios should not be in use by another entity, and must not be requested * by a kernel driver without also being exported by it (otherwise they can't * be exported by sysfs). * * The sysfs gpio interface can only manipulate one gpio at a time, so the * bitbang write handler remembers the last state for tck, tms, tdi to avoid * superfluous writes. * For speed the sysfs "value" entry is opened at init and held open. * This results in considerable gains over open-write-close (45s vs 900s) * * Further work could address: * -srst and trst open drain/ push pull * -configurable active high/low for srst & trst */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "bitbang.h" /* * Helper func to determine if gpio number valid * * Assume here that there will be less than 1000 gpios on a system */ static int is_gpio_valid(int gpio) { return gpio >= 0 && gpio < 1000; } /* * Helper func to open, write to and close a file * name and valstr must be null terminated. * * Returns negative on failure. */ static int open_write_close(const char *name, const char *valstr) { int ret; int fd = open(name, O_WRONLY); if (fd < 0) return fd; ret = write(fd, valstr, strlen(valstr)); close(fd); return ret; } /* * Helper func to unexport gpio from sysfs */ static void unexport_sysfs_gpio(int gpio) { char gpiostr[4]; if (!is_gpio_valid(gpio)) return; snprintf(gpiostr, sizeof(gpiostr), "%d", gpio); if (open_write_close("/sys/class/gpio/unexport", gpiostr) < 0) LOG_ERROR("Couldn't unexport gpio %d", gpio); return; } /* * Exports and sets up direction for gpio. * If the gpio is an output, it is initialized according to init_high, * otherwise it is ignored. * * If the gpio is already exported we just show a warning and continue; if * openocd happened to crash (or was killed by user) then the gpios will not * have been cleaned up. */ static int setup_sysfs_gpio(int gpio, int is_output, int init_high) { char buf[40]; char gpiostr[4]; int ret; if (!is_gpio_valid(gpio)) return ERROR_OK; snprintf(gpiostr, sizeof(gpiostr), "%d", gpio); ret = open_write_close("/sys/class/gpio/export", gpiostr); if (ret < 0) { if (errno == EBUSY) { LOG_WARNING("gpio %d is already exported", gpio); } else { LOG_ERROR("Couldn't export gpio %d", gpio); perror("sysfsgpio: "); return ERROR_FAIL; } } snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/direction", gpio); ret = open_write_close(buf, is_output ? (init_high ? "high" : "low") : "in"); if (ret < 0) { LOG_ERROR("Couldn't set direction for gpio %d", gpio); perror("sysfsgpio: "); unexport_sysfs_gpio(gpio); return ERROR_FAIL; } snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/value", gpio); if (is_output) ret = open(buf, O_WRONLY | O_NONBLOCK | O_SYNC); else ret = open(buf, O_RDONLY | O_NONBLOCK | O_SYNC); if (ret < 0) unexport_sysfs_gpio(gpio); return ret; } /* * file descriptors for /sys/class/gpio/gpioXX/value * Set up during init. */ static int tck_fd = -1; static int tms_fd = -1; static int tdi_fd = -1; static int tdo_fd = -1; static int trst_fd = -1; static int srst_fd = -1; /* * Bitbang interface read of TDO * * The sysfs value will read back either '0' or '1'. The trick here is to call * lseek to bypass buffering in the sysfs kernel driver. */ static int sysfsgpio_read(void) { char buf[1]; /* important to seek to signal sysfs of new read */ lseek(tdo_fd, 0, SEEK_SET); int ret = read(tdo_fd, &buf, sizeof(buf)); if (ret < 0) { LOG_WARNING("reading tdo failed"); return 0; } return buf[0] == '1'; } /* * Bitbang interface write of TCK, TMS, TDI * * Seeing as this is the only function where the outputs are changed, * we can cache the old value to avoid needlessly writing it. */ static void sysfsgpio_write(int tck, int tms, int tdi) { const char one[] = "1"; const char zero[] = "0"; static int last_tck; static int last_tms; static int last_tdi; static int first_time; size_t bytes_written; if (!first_time) { last_tck = !tck; last_tms = !tms; last_tdi = !tdi; first_time = 1; } if (tdi != last_tdi) { bytes_written = write(tdi_fd, tdi ? &one : &zero, 1); if (bytes_written != 1) LOG_WARNING("writing tdi failed"); } if (tms != last_tms) { bytes_written = write(tms_fd, tms ? &one : &zero, 1); if (bytes_written != 1) LOG_WARNING("writing tms failed"); } /* write clk last */ if (tck != last_tck) { bytes_written = write(tck_fd, tck ? &one : &zero, 1); if (bytes_written != 1) LOG_WARNING("writing tck failed"); } last_tdi = tdi; last_tms = tms; last_tck = tck; } /* * Bitbang interface to manipulate reset lines SRST and TRST * * (1) assert or (0) deassert reset lines */ static void sysfsgpio_reset(int trst, int srst) { const char one[] = "1"; const char zero[] = "0"; size_t bytes_written; /* assume active low */ if (srst_fd >= 0) { bytes_written = write(srst_fd, srst ? &zero : &one, 1); if (bytes_written != 1) LOG_WARNING("writing srst failed"); } /* assume active low */ if (trst_fd >= 0) { bytes_written = write(trst_fd, trst ? &zero : &one, 1); if (bytes_written != 1) LOG_WARNING("writing trst failed"); } } /* gpio numbers for each gpio. Negative values are invalid */ static int tck_gpio = -1; static int tms_gpio = -1; static int tdi_gpio = -1; static int tdo_gpio = -1; static int trst_gpio = -1; static int srst_gpio = -1; COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionums) { if (CMD_ARGC == 4) { COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tck_gpio); COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], tms_gpio); COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], tdi_gpio); COMMAND_PARSE_NUMBER(int, CMD_ARGV[3], tdo_gpio); } else if (CMD_ARGC != 0) { return ERROR_COMMAND_SYNTAX_ERROR; } command_print(CMD_CTX, "SysfsGPIO nums: tck = %d, tms = %d, tdi = %d, tdi = %d", tck_gpio, tms_gpio, tdi_gpio, tdo_gpio); return ERROR_OK; } COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionum_tck) { if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tck_gpio); command_print(CMD_CTX, "SysfsGPIO num: tck = %d", tck_gpio); return ERROR_OK; } COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionum_tms) { if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tms_gpio); command_print(CMD_CTX, "SysfsGPIO num: tms = %d", tms_gpio); return ERROR_OK; } COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionum_tdo) { if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdo_gpio); command_print(CMD_CTX, "SysfsGPIO num: tdo = %d", tdo_gpio); return ERROR_OK; } COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionum_tdi) { if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], tdi_gpio); command_print(CMD_CTX, "SysfsGPIO num: tdi = %d", tdi_gpio); return ERROR_OK; } COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionum_srst) { if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], srst_gpio); command_print(CMD_CTX, "SysfsGPIO num: srst = %d", srst_gpio); return ERROR_OK; } COMMAND_HANDLER(sysfsgpio_handle_jtag_gpionum_trst) { if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], trst_gpio); command_print(CMD_CTX, "SysfsGPIO num: trst = %d", trst_gpio); return ERROR_OK; } static const struct command_registration sysfsgpio_command_handlers[] = { { .name = "sysfsgpio_jtag_nums", .handler = &sysfsgpio_handle_jtag_gpionums, .mode = COMMAND_CONFIG, .help = "gpio numbers for tck, tms, tdi, tdo. (in that order)", .usage = "(tck tms tdi tdo)* ", }, { .name = "sysfsgpio_tck_num", .handler = &sysfsgpio_handle_jtag_gpionum_tck, .mode = COMMAND_CONFIG, .help = "gpio number for tck.", }, { .name = "sysfsgpio_tms_num", .handler = &sysfsgpio_handle_jtag_gpionum_tms, .mode = COMMAND_CONFIG, .help = "gpio number for tms.", }, { .name = "sysfsgpio_tdo_num", .handler = &sysfsgpio_handle_jtag_gpionum_tdo, .mode = COMMAND_CONFIG, .help = "gpio number for tdo.", }, { .name = "sysfsgpio_tdi_num", .handler = &sysfsgpio_handle_jtag_gpionum_tdi, .mode = COMMAND_CONFIG, .help = "gpio number for tdi.", }, { .name = "sysfsgpio_srst_num", .handler = &sysfsgpio_handle_jtag_gpionum_srst, .mode = COMMAND_CONFIG, .help = "gpio number for srst.", }, { .name = "sysfsgpio_trst_num", .handler = &sysfsgpio_handle_jtag_gpionum_trst, .mode = COMMAND_CONFIG, .help = "gpio number for trst.", }, COMMAND_REGISTRATION_DONE }; static int sysfsgpio_init(void); static int sysfsgpio_quit(void); struct jtag_interface sysfsgpio_interface = { .name = "sysfsgpio", .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = bitbang_execute_queue, .transports = jtag_only, .commands = sysfsgpio_command_handlers, .init = sysfsgpio_init, .quit = sysfsgpio_quit, }; static struct bitbang_interface sysfsgpio_bitbang = { .read = sysfsgpio_read, .write = sysfsgpio_write, .reset = sysfsgpio_reset, .blink = 0 }; /* helper func to close and cleanup files only if they were valid/ used */ static void cleanup_fd(int fd, int gpio) { if (gpio >= 0) { if (fd >= 0) close(fd); unexport_sysfs_gpio(gpio); } } static void cleanup_all_fds(void) { cleanup_fd(tck_fd, tck_gpio); cleanup_fd(tms_fd, tms_gpio); cleanup_fd(tdi_fd, tdi_gpio); cleanup_fd(tdo_fd, tdo_gpio); cleanup_fd(trst_fd, trst_gpio); cleanup_fd(srst_fd, srst_gpio); } static int sysfsgpio_init(void) { bitbang_interface = &sysfsgpio_bitbang; LOG_INFO("SysfsGPIO JTAG bitbang driver"); if (!(is_gpio_valid(tck_gpio) && is_gpio_valid(tms_gpio) && is_gpio_valid(tdi_gpio) && is_gpio_valid(tdo_gpio))) { if (!is_gpio_valid(tck_gpio)) LOG_ERROR("gpio num for tck is invalid"); if (!is_gpio_valid(tms_gpio)) LOG_ERROR("gpio num for tms is invalid"); if (!is_gpio_valid(tdo_gpio)) LOG_ERROR("gpio num for tdo is invalid"); if (!is_gpio_valid(tdi_gpio)) LOG_ERROR("gpio num for tdi is invalid"); LOG_ERROR("Require tck, tms, tdi and tdo gpios to all be specified"); return ERROR_JTAG_INIT_FAILED; } if (!is_gpio_valid(trst_gpio) && !is_gpio_valid(srst_gpio)) { LOG_ERROR("Require at least one of trst or srst gpios to be specified"); return ERROR_JTAG_INIT_FAILED; } /* * Configure TDO as an input, and TDI, TCK, TMS, TRST, SRST * as outputs. Drive TDI and TCK low, and TMS/TRST/SRST high. */ tck_fd = setup_sysfs_gpio(tck_gpio, 1, 0); if (tck_fd < 0) goto out_error; tms_fd = setup_sysfs_gpio(tms_gpio, 1, 1); if (tms_fd < 0) goto out_error; tdi_fd = setup_sysfs_gpio(tdi_gpio, 1, 0); if (tdi_fd < 0) goto out_error; tdo_fd = setup_sysfs_gpio(tdo_gpio, 0, 0); if (tdo_fd < 0) goto out_error; /* assume active low*/ trst_fd = setup_sysfs_gpio(trst_gpio, 1, 1); if (trst_gpio > 0 && trst_fd < 0) goto out_error; /* assume active low*/ srst_fd = setup_sysfs_gpio(srst_gpio, 1, 1); if (srst_gpio > 0 && srst_fd < 0) goto out_error; return ERROR_OK; out_error: cleanup_all_fds(); return ERROR_JTAG_INIT_FAILED; } static int sysfsgpio_quit(void) { cleanup_all_fds(); return ERROR_OK; } openocd-0.7.0/src/jtag/drivers/jlink.c0000644000175000001440000013240512134336410014531 00000000000000/*************************************************************************** * Copyright (C) 2007 by Juergen Stuber * * based on Dominic Rath's and Benedikt Sauter's usbprog.c * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2011 by Jean-Christophe PLAGNIOL-VIILARD * * plagnioj@jcrosoft.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "libusb_common.h" /* See Segger's public documentation: * Reference manual for J-Link USB Protocol * Document RM08001-R6 Date: June 16, 2009 * (Or newer, with some SWD information). * http://www.segger.com/cms/admin/uploads/productDocs/RM08001_JLinkUSBProtocol.pdf */ /* * The default pid of the segger is 0x0101 * But when you change the USB Address it will also * * pid = ( usb_address > 0x4) ? 0x0101 : (0x101 + usb_address) */ #define VID 0x1366, 0x1366, 0x1366, 0x1366 #define PID 0x0101, 0x0102, 0x0103, 0x0104 #define JLINK_WRITE_ENDPOINT 0x02 #define JLINK_READ_ENDPOINT 0x81 static unsigned int jlink_write_ep = JLINK_WRITE_ENDPOINT; static unsigned int jlink_read_ep = JLINK_READ_ENDPOINT; static unsigned int jlink_hw_jtag_version = 2; #define JLINK_USB_TIMEOUT 1000 /* See Section 3.3.2 of the Segger JLink USB protocol manual */ /* 2048 is the max value we can use here */ #define JLINK_TAP_BUFFER_SIZE 2048 /*#define JLINK_TAP_BUFFER_SIZE 256*/ /*#define JLINK_TAP_BUFFER_SIZE 384*/ #define JLINK_IN_BUFFER_SIZE 2048 #define JLINK_OUT_BUFFER_SIZE (2*2048 + 4) #define JLINK_EMU_RESULT_BUFFER_SIZE 64 /* Global USB buffers */ static uint8_t usb_in_buffer[JLINK_IN_BUFFER_SIZE]; static uint8_t usb_out_buffer[JLINK_OUT_BUFFER_SIZE]; static uint8_t usb_emu_result_buffer[JLINK_EMU_RESULT_BUFFER_SIZE]; /* Constants for JLink command */ #define EMU_CMD_VERSION 0x01 #define EMU_CMD_RESET_TRST 0x02 #define EMU_CMD_RESET_TARGET 0x03 #define EMU_CMD_SET_SPEED 0x05 #define EMU_CMD_GET_STATE 0x07 #define EMU_CMD_SET_KS_POWER 0x08 #define EMU_CMD_GET_SPEEDS 0xc0 #define EMU_CMD_GET_HW_INFO 0xc1 #define EMU_CMD_GET_COUNTERS 0xc2 #define EMU_CMD_SELECT_IF 0xc7 #define EMU_CMD_HW_CLOCK 0xc8 #define EMU_CMD_HW_TMS0 0xc9 #define EMU_CMD_HW_TMS1 0xca #define EMU_CMD_HW_DATA0 0xcb #define EMU_CMD_HW_DATA1 0xcc #define EMU_CMD_HW_JTAG 0xcd #define EMU_CMD_HW_JTAG2 0xce #define EMU_CMD_HW_JTAG3 0xcf #define EMU_CMD_HW_RELEASE_RESET_STOP_EX 0xd0 #define EMU_CMD_HW_RELEASE_RESET_STOP_TIMED 0xd1 #define EMU_CMD_GET_MAX_MEM_BLOCK 0xd4 #define EMU_CMD_HW_JTAG_WRITE 0xd5 #define EMU_CMD_HW_JTAG_GET_RESULT 0xd6 #define EMU_CMD_HW_RESET0 0xdc #define EMU_CMD_HW_RESET1 0xdd #define EMU_CMD_HW_TRST0 0xde #define EMU_CMD_HW_TRST1 0xdf #define EMU_CMD_GET_CAPS 0xe8 #define EMU_CMD_GET_CPU_CAPS 0xe9 #define EMU_CMD_EXEC_CPU_CMD 0xea #define EMU_CMD_GET_CAPS_EX 0xed #define EMU_CMD_GET_HW_VERSION 0xf0 #define EMU_CMD_WRITE_DCC 0xf1 #define EMU_CMD_READ_CONFIG 0xf2 #define EMU_CMD_WRITE_CONFIG 0xf3 #define EMU_CMD_WRITE_MEM 0xf4 #define EMU_CMD_READ_MEM 0xf5 #define EMU_CMD_MEASURE_RTCK_REACT 0xf6 #define EMU_CMD_WRITE_MEM_ARM79 0xf7 #define EMU_CMD_READ_MEM_ARM79 0xf8 /* bits return from EMU_CMD_GET_CAPS */ #define EMU_CAP_RESERVED_1 0 #define EMU_CAP_GET_HW_VERSION 1 #define EMU_CAP_WRITE_DCC 2 #define EMU_CAP_ADAPTIVE_CLOCKING 3 #define EMU_CAP_READ_CONFIG 4 #define EMU_CAP_WRITE_CONFIG 5 #define EMU_CAP_TRACE 6 #define EMU_CAP_WRITE_MEM 7 #define EMU_CAP_READ_MEM 8 #define EMU_CAP_SPEED_INFO 9 #define EMU_CAP_EXEC_CODE 10 #define EMU_CAP_GET_MAX_BLOCK_SIZE 11 #define EMU_CAP_GET_HW_INFO 12 #define EMU_CAP_SET_KS_POWER 13 #define EMU_CAP_RESET_STOP_TIMED 14 #define EMU_CAP_RESERVED_2 15 #define EMU_CAP_MEASURE_RTCK_REACT 16 #define EMU_CAP_SELECT_IF 17 #define EMU_CAP_RW_MEM_ARM79 18 #define EMU_CAP_GET_COUNTERS 19 #define EMU_CAP_READ_DCC 20 #define EMU_CAP_GET_CPU_CAPS 21 #define EMU_CAP_EXEC_CPU_CMD 22 #define EMU_CAP_SWO 23 #define EMU_CAP_WRITE_DCC_EX 24 #define EMU_CAP_UPDATE_FIRMWARE_EX 25 #define EMU_CAP_FILE_IO 26 #define EMU_CAP_REGISTER 27 #define EMU_CAP_INDICATORS 28 #define EMU_CAP_TEST_NET_SPEED 29 #define EMU_CAP_RAWTRACE 30 #define EMU_CAP_RESERVED_3 31 static char *jlink_cap_str[] = { "Always 1.", "Supports command EMU_CMD_GET_HARDWARE_VERSION", "Supports command EMU_CMD_WRITE_DCC", "Supports adaptive clocking", "Supports command EMU_CMD_READ_CONFIG", "Supports command EMU_CMD_WRITE_CONFIG", "Supports trace commands", "Supports command EMU_CMD_WRITE_MEM", "Supports command EMU_CMD_READ_MEM", "Supports command EMU_CMD_GET_SPEED", "Supports command EMU_CMD_CODE_...", "Supports command EMU_CMD_GET_MAX_BLOCK_SIZE", "Supports command EMU_CMD_GET_HW_INFO", "Supports command EMU_CMD_SET_KS_POWER", "Supports command EMU_CMD_HW_RELEASE_RESET_STOP_TIMED", "Reserved", "Supports command EMU_CMD_MEASURE_RTCK_REACT", "Supports command EMU_CMD_HW_SELECT_IF", "Supports command EMU_CMD_READ/WRITE_MEM_ARM79", "Supports command EMU_CMD_GET_COUNTERS", "Supports command EMU_CMD_READ_DCC", "Supports command EMU_CMD_GET_CPU_CAPS", "Supports command EMU_CMD_EXEC_CPU_CMD", "Supports command EMU_CMD_SWO", "Supports command EMU_CMD_WRITE_DCC_EX", "Supports command EMU_CMD_UPDATE_FIRMWARE_EX", "Supports command EMU_CMD_FILE_IO", "Supports command EMU_CMD_REGISTER", "Supports command EMU_CMD_INDICATORS", "Supports command EMU_CMD_TEST_NET_SPEED", "Supports command EMU_CMD_RAWTRACE", "Reserved", }; /* max speed 12MHz v5.0 jlink */ #define JLINK_MAX_SPEED 12000 /* J-Link hardware versions */ #define JLINK_HW_TYPE_JLINK 0 #define JLINK_HW_TYPE_JTRACE 1 #define JLINK_HW_TYPE_FLASHER 2 #define JLINK_HW_TYPE_JLINK_PRO 3 #define JLINK_HW_TYPE_MAX 4 static char *jlink_hw_type_str[] = { "J-Link", "J-Trace", "Flasher", "J-Link Pro", }; /* Queue command functions */ static void jlink_end_state(tap_state_t state); static void jlink_state_move(void); static void jlink_path_move(int num_states, tap_state_t *path); static void jlink_runtest(int num_cycles); static void jlink_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command); static void jlink_reset(int trst, int srst); static void jlink_simple_command(uint8_t command); static int jlink_get_status(void); /* J-Link tap buffer functions */ static void jlink_tap_init(void); static int jlink_tap_execute(void); static void jlink_tap_ensure_space(int scans, int bits); static void jlink_tap_append_step(int tms, int tdi); static void jlink_tap_append_scan(int length, uint8_t *buffer, struct scan_command *command); /* Jlink lowlevel functions */ struct jlink { struct jtag_libusb_device_handle *usb_handle; }; static struct jlink *jlink_usb_open(void); static void jlink_usb_close(struct jlink *jlink); static int jlink_usb_message(struct jlink *jlink, int out_length, int in_length); static int jlink_usb_io(struct jlink *jlink, int out_length, int in_length); static int jlink_usb_write(struct jlink *jlink, int out_length); static int jlink_usb_read(struct jlink *jlink, int expected_size); static int jlink_usb_read_emu_result(struct jlink *jlink); /* helper functions */ static int jlink_get_version_info(void); #ifdef _DEBUG_USB_COMMS_ static void jlink_debug_buffer(uint8_t *buffer, int length); #else static inline void jlink_debug_buffer(uint8_t *buffer, int length) { } #endif static enum tap_state jlink_last_state = TAP_RESET; static struct jlink *jlink_handle; /* pid could be specified at runtime */ static uint16_t vids[] = { VID, 0 }; static uint16_t pids[] = { PID, 0 }; static uint32_t jlink_caps; static uint32_t jlink_hw_type; /* 256 byte non-volatile memory */ struct jlink_config { uint8_t usb_address; /* 0ffset 0x01 to 0x03 */ uint8_t reserved_1[3]; uint32_t kickstart_power_on_jtag_pin_19; /* 0ffset 0x08 to 0x1f */ uint8_t reserved_2[24]; /* IP only for J-Link Pro */ uint8_t ip_address[4]; uint8_t subnet_mask[4]; /* 0ffset 0x28 to 0x2f */ uint8_t reserved_3[8]; uint8_t mac_address[6]; /* 0ffset 0x36 to 0xff */ uint8_t reserved_4[202]; } __attribute__ ((packed)); struct jlink_config jlink_cfg; /***************************************************************************/ /* External interface implementation */ static void jlink_execute_runtest(struct jtag_command *cmd) { DEBUG_JTAG_IO("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); jlink_end_state(cmd->cmd.runtest->end_state); jlink_runtest(cmd->cmd.runtest->num_cycles); } static void jlink_execute_statemove(struct jtag_command *cmd) { DEBUG_JTAG_IO("statemove end in %i", cmd->cmd.statemove->end_state); jlink_end_state(cmd->cmd.statemove->end_state); jlink_state_move(); } static void jlink_execute_pathmove(struct jtag_command *cmd) { DEBUG_JTAG_IO("pathmove: %i states, end in %i", cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); jlink_path_move(cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path); } static void jlink_execute_scan(struct jtag_command *cmd) { int scan_size; enum scan_type type; uint8_t *buffer; DEBUG_JTAG_IO("scan end in %s", tap_state_name(cmd->cmd.scan->end_state)); jlink_end_state(cmd->cmd.scan->end_state); scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); DEBUG_JTAG_IO("scan input, length = %d", scan_size); jlink_debug_buffer(buffer, (scan_size + 7) / 8); type = jtag_scan_type(cmd->cmd.scan); jlink_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size, cmd->cmd.scan); } static void jlink_execute_reset(struct jtag_command *cmd) { DEBUG_JTAG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); jlink_tap_execute(); jlink_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); jlink_tap_execute(); } static void jlink_execute_sleep(struct jtag_command *cmd) { DEBUG_JTAG_IO("sleep %" PRIi32 "", cmd->cmd.sleep->us); jlink_tap_execute(); jtag_sleep(cmd->cmd.sleep->us); } static void jlink_execute_command(struct jtag_command *cmd) { switch (cmd->type) { case JTAG_RUNTEST: jlink_execute_runtest(cmd); break; case JTAG_TLR_RESET: jlink_execute_statemove(cmd); break; case JTAG_PATHMOVE: jlink_execute_pathmove(cmd); break; case JTAG_SCAN: jlink_execute_scan(cmd); break; case JTAG_RESET: jlink_execute_reset(cmd); break; case JTAG_SLEEP: jlink_execute_sleep(cmd); break; default: LOG_ERROR("BUG: unknown JTAG command type encountered"); exit(-1); } } static int jlink_execute_queue(void) { struct jtag_command *cmd = jtag_command_queue; while (cmd != NULL) { jlink_execute_command(cmd); cmd = cmd->next; } return jlink_tap_execute(); } /* Sets speed in kHz. */ static int jlink_speed(int speed) { int result; if (speed > JLINK_MAX_SPEED) { LOG_INFO("reduce speed request: %dkHz to %dkHz maximum", speed, JLINK_MAX_SPEED); speed = JLINK_MAX_SPEED; } /* check for RTCK setting */ if (speed == 0) speed = -1; usb_out_buffer[0] = EMU_CMD_SET_SPEED; usb_out_buffer[1] = (speed >> 0) & 0xff; usb_out_buffer[2] = (speed >> 8) & 0xff; result = jlink_usb_write(jlink_handle, 3); if (result != 3) { LOG_ERROR("J-Link setting speed failed (%d)", result); return ERROR_JTAG_DEVICE_ERROR; } return ERROR_OK; } static int jlink_speed_div(int speed, int *khz) { *khz = speed; return ERROR_OK; } static int jlink_khz(int khz, int *jtag_speed) { *jtag_speed = khz; return ERROR_OK; } /* * select transport interface * * @param iface [0..31] currently: 0=JTAG, 1=SWD * @returns ERROR_OK or ERROR_ code * * @pre jlink_handle must be opened * @pre function may be called only for devices, that have * EMU_CAP_SELECT_IF capability enabled */ static int jlink_select_interface(int iface) { /* According to Segger's document RM08001-R7 Date: October 8, 2010, * http://www.segger.com/admin/uploads/productDocs/RM08001_JLinkUSBProtocol.pdf * section 5.5.3 EMU_CMD_SELECT_IF * > SubCmd 1..31 to select interface (0..31) * * The table below states: * 0 TIF_JTAG * 1 TIF_SWD * * This obviosly means that to select TIF_JTAG one should write SubCmd = 1. * * In fact, JTAG interface operates when SubCmd=0 * * It looks like a typo in documentation, because interfaces 0..31 could not * be selected by 1..31 range command. */ assert(iface >= 0 && iface < 32); int result; /* get available interfaces */ usb_out_buffer[0] = EMU_CMD_SELECT_IF; usb_out_buffer[1] = 0xff; result = jlink_usb_io(jlink_handle, 2, 4); if (result != ERROR_OK) { LOG_ERROR("J-Link query interface failed (%d)", result); return ERROR_JTAG_DEVICE_ERROR; } uint32_t iface_mask = buf_get_u32(usb_in_buffer, 0, 32); if (!(iface_mask & (1<> i) & 1; jlink_tap_append_step(tms, 0); } tap_set_state(tap_get_end_state()); } static void jlink_path_move(int num_states, tap_state_t *path) { int i; for (i = 0; i < num_states; i++) { if (path[i] == tap_state_transition(tap_get_state(), false)) jlink_tap_append_step(0, 0); else if (path[i] == tap_state_transition(tap_get_state(), true)) jlink_tap_append_step(1, 0); else { LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_name(tap_get_state()), tap_state_name(path[i])); exit(-1); } tap_set_state(path[i]); } tap_set_end_state(tap_get_state()); } static void jlink_runtest(int num_cycles) { int i; tap_state_t saved_end_state = tap_get_end_state(); jlink_tap_ensure_space(1, num_cycles + 16); /* only do a state_move when we're not already in IDLE */ if (tap_get_state() != TAP_IDLE) { jlink_end_state(TAP_IDLE); jlink_state_move(); /* num_cycles--; */ } /* execute num_cycles */ for (i = 0; i < num_cycles; i++) jlink_tap_append_step(0, 0); /* finish in end_state */ jlink_end_state(saved_end_state); if (tap_get_state() != tap_get_end_state()) jlink_state_move(); } static void jlink_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command) { tap_state_t saved_end_state; jlink_tap_ensure_space(1, scan_size + 16); saved_end_state = tap_get_end_state(); /* Move to appropriate scan state */ jlink_end_state(ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT); /* Only move if we're not already there */ if (tap_get_state() != tap_get_end_state()) jlink_state_move(); jlink_end_state(saved_end_state); /* Scan */ jlink_tap_append_scan(scan_size, buffer, command); /* We are in Exit1, go to Pause */ jlink_tap_append_step(0, 0); tap_set_state(ir_scan ? TAP_IRPAUSE : TAP_DRPAUSE); if (tap_get_state() != tap_get_end_state()) jlink_state_move(); } static void jlink_reset(int trst, int srst) { LOG_DEBUG("trst: %i, srst: %i", trst, srst); /* Signals are active low */ if (srst == 0) jlink_simple_command(EMU_CMD_HW_RESET1); if (srst == 1) jlink_simple_command(EMU_CMD_HW_RESET0); if (trst == 1) jlink_simple_command(EMU_CMD_HW_TRST0); if (trst == 0) jlink_simple_command(EMU_CMD_HW_TRST1); } static void jlink_simple_command(uint8_t command) { int result; DEBUG_JTAG_IO("0x%02x", command); usb_out_buffer[0] = command; result = jlink_usb_write(jlink_handle, 1); if (result != 1) LOG_ERROR("J-Link command 0x%02x failed (%d)", command, result); } static int jlink_get_status(void) { int result; jlink_simple_command(EMU_CMD_GET_STATE); result = jlink_usb_read(jlink_handle, 8); if (result != 8) { LOG_ERROR("J-Link command EMU_CMD_GET_STATE failed (%d)", result); return ERROR_JTAG_DEVICE_ERROR; } int vref = usb_in_buffer[0] + (usb_in_buffer[1] << 8); LOG_INFO("Vref = %d.%d TCK = %d TDI = %d TDO = %d TMS = %d SRST = %d TRST = %d", \ vref / 1000, vref % 1000, \ usb_in_buffer[2], usb_in_buffer[3], usb_in_buffer[4], \ usb_in_buffer[5], usb_in_buffer[6], usb_in_buffer[7]); if (vref < 1500) LOG_ERROR("Vref too low. Check Target Power"); return ERROR_OK; } #define jlink_dump_printf(context, expr ...) \ do { \ if (context) \ command_print(context, expr); \ else \ LOG_INFO(expr); \ } while (0); static void jlink_caps_dump(struct command_context *ctx) { int i; jlink_dump_printf(ctx, "J-Link Capabilities"); for (i = 1; i < 31; i++) if (jlink_caps & (1 << i)) jlink_dump_printf(ctx, "%s", jlink_cap_str[i]); } static void jlink_config_usb_address_dump(struct command_context *ctx, struct jlink_config *cfg) { if (!cfg) return; jlink_dump_printf(ctx, "USB-Address: 0x%x", cfg->usb_address); } static void jlink_config_kickstart_dump(struct command_context *ctx, struct jlink_config *cfg) { if (!cfg) return; jlink_dump_printf(ctx, "Kickstart power on JTAG-pin 19: 0x%x", cfg->kickstart_power_on_jtag_pin_19); } static void jlink_config_mac_address_dump(struct command_context *ctx, struct jlink_config *cfg) { if (!cfg) return; jlink_dump_printf(ctx, "MAC Address: %.02x:%.02x:%.02x:%.02x:%.02x:%.02x", cfg->mac_address[5], cfg->mac_address[4], cfg->mac_address[3], cfg->mac_address[2], cfg->mac_address[1], cfg->mac_address[0]); } static void jlink_config_ip_dump(struct command_context *ctx, struct jlink_config *cfg) { if (!cfg) return; jlink_dump_printf(ctx, "IP Address: %d.%d.%d.%d", cfg->ip_address[3], cfg->ip_address[2], cfg->ip_address[1], cfg->ip_address[0]); jlink_dump_printf(ctx, "Subnet Mask: %d.%d.%d.%d", cfg->subnet_mask[3], cfg->subnet_mask[2], cfg->subnet_mask[1], cfg->subnet_mask[0]); } static void jlink_config_dump(struct command_context *ctx, struct jlink_config *cfg) { if (!cfg) return; jlink_dump_printf(ctx, "J-Link configuration"); jlink_config_usb_address_dump(ctx, cfg); jlink_config_kickstart_dump(ctx, cfg); if (jlink_hw_type == JLINK_HW_TYPE_JLINK_PRO) { jlink_config_ip_dump(ctx, cfg); jlink_config_mac_address_dump(ctx, cfg); } } static int jlink_get_config(struct jlink_config *cfg) { int result; int size = sizeof(struct jlink_config); usb_out_buffer[0] = EMU_CMD_READ_CONFIG; result = jlink_usb_io(jlink_handle, 1, size); if (result != ERROR_OK) { LOG_ERROR("jlink_usb_read failed (requested=%d, result=%d)", size, result); return ERROR_FAIL; } memcpy(cfg, usb_in_buffer, size); return ERROR_OK; } static int jlink_set_config(struct jlink_config *cfg) { int result; int size = sizeof(struct jlink_config); jlink_simple_command(EMU_CMD_WRITE_CONFIG); memcpy(usb_out_buffer, cfg, size); result = jlink_usb_write(jlink_handle, size); if (result != size) { LOG_ERROR("jlink_usb_write failed (requested=%d, result=%d)", 256, result); return ERROR_FAIL; } return ERROR_OK; } /* * List of unsupported version string markers. * * The firmware versions does not correspond directly with * "Software and documentation pack for Windows", it may be * distinguished by the "compile" date in the information string. * * For example, version string is: * "J-Link ARM V8 compiled May 3 2012 18:36:22" * Marker sould be: * "May 3 2012" * * The list must be terminated by NULL string. */ static const char * const unsupported_versions[] = { "Jan 31 2011", "JAN 31 2011", NULL /* End of list */ }; static void jlink_check_supported(const char *str) { const char * const *p = unsupported_versions; while (*p) { if (NULL != strstr(str, *p)) { LOG_WARNING( "Unsupported J-Link firmware version.\n" " Please check http://www.segger.com/j-link-older-versions.html for updates"); return; } p++; } } static int jlink_get_version_info(void) { int result; int len; uint32_t jlink_max_size; /* query hardware version */ jlink_simple_command(EMU_CMD_VERSION); result = jlink_usb_read(jlink_handle, 2); if (2 != result) { LOG_ERROR("J-Link command EMU_CMD_VERSION failed (%d)", result); return ERROR_JTAG_DEVICE_ERROR; } len = buf_get_u32(usb_in_buffer, 0, 16); if (len > JLINK_IN_BUFFER_SIZE) { LOG_ERROR("J-Link command EMU_CMD_VERSION impossible return length 0x%0x", len); len = JLINK_IN_BUFFER_SIZE; } result = jlink_usb_read(jlink_handle, len); if (result != len) { LOG_ERROR("J-Link command EMU_CMD_VERSION failed (%d)", result); return ERROR_JTAG_DEVICE_ERROR; } usb_in_buffer[result] = 0; LOG_INFO("%s", (char *)usb_in_buffer); jlink_check_supported((char *)usb_in_buffer); /* query hardware capabilities */ jlink_simple_command(EMU_CMD_GET_CAPS); result = jlink_usb_read(jlink_handle, 4); if (4 != result) { LOG_ERROR("J-Link command EMU_CMD_GET_CAPS failed (%d)", result); return ERROR_JTAG_DEVICE_ERROR; } jlink_caps = buf_get_u32(usb_in_buffer, 0, 32); LOG_INFO("J-Link caps 0x%x", (unsigned)jlink_caps); if (jlink_caps & (1 << EMU_CAP_GET_HW_VERSION)) { /* query hardware version */ jlink_simple_command(EMU_CMD_GET_HW_VERSION); result = jlink_usb_read(jlink_handle, 4); if (4 != result) { LOG_ERROR("J-Link command EMU_CMD_GET_HW_VERSION failed (%d)", result); return ERROR_JTAG_DEVICE_ERROR; } uint32_t jlink_hw_version = buf_get_u32(usb_in_buffer, 0, 32); uint32_t major_revision = (jlink_hw_version / 10000) % 100; jlink_hw_type = (jlink_hw_version / 1000000) % 100; if (major_revision >= 5) jlink_hw_jtag_version = 3; LOG_INFO("J-Link hw version %i", (int)jlink_hw_version); if (jlink_hw_type >= JLINK_HW_TYPE_MAX) LOG_INFO("J-Link hw type uknown 0x%x", jlink_hw_type); else LOG_INFO("J-Link hw type %s", jlink_hw_type_str[jlink_hw_type]); } if (jlink_caps & (1 << EMU_CAP_GET_MAX_BLOCK_SIZE)) { /* query hardware maximum memory block */ jlink_simple_command(EMU_CMD_GET_MAX_MEM_BLOCK); result = jlink_usb_read(jlink_handle, 4); if (4 != result) { LOG_ERROR("J-Link command EMU_CMD_GET_MAX_MEM_BLOCK failed (%d)", result); return ERROR_JTAG_DEVICE_ERROR; } jlink_max_size = buf_get_u32(usb_in_buffer, 0, 32); LOG_INFO("J-Link max mem block %i", (int)jlink_max_size); } if (jlink_caps & (1 << EMU_CAP_READ_CONFIG)) { if (jlink_get_config(&jlink_cfg) != ERROR_OK) return ERROR_JTAG_DEVICE_ERROR; jlink_config_dump(NULL, &jlink_cfg); } return ERROR_OK; } COMMAND_HANDLER(jlink_pid_command) { if (CMD_ARGC != 1) { LOG_ERROR("Need exactly one argument to jlink_pid"); return ERROR_FAIL; } pids[0] = strtoul(CMD_ARGV[0], NULL, 16); pids[1] = 0; vids[1] = 0; return ERROR_OK; } COMMAND_HANDLER(jlink_handle_jlink_info_command) { if (jlink_get_version_info() == ERROR_OK) { /* attempt to get status */ jlink_get_status(); } return ERROR_OK; } COMMAND_HANDLER(jlink_handle_jlink_caps_command) { jlink_caps_dump(CMD_CTX); return ERROR_OK; } COMMAND_HANDLER(jlink_handle_jlink_hw_jtag_command) { switch (CMD_ARGC) { case 0: command_print(CMD_CTX, "J-Link hw jtag %i", jlink_hw_jtag_version); break; case 1: { int request_version = atoi(CMD_ARGV[0]); switch (request_version) { case 2: case 3: jlink_hw_jtag_version = request_version; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } break; } default: return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; } COMMAND_HANDLER(jlink_handle_jlink_kickstart_command) { uint32_t kickstart; if (CMD_ARGC < 1) { jlink_config_kickstart_dump(CMD_CTX, &jlink_cfg); return ERROR_OK; } COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], kickstart); jlink_cfg.kickstart_power_on_jtag_pin_19 = kickstart; return ERROR_OK; } COMMAND_HANDLER(jlink_handle_jlink_mac_address_command) { uint8_t addr[6]; int i; char *e; const char *str; if (CMD_ARGC < 1) { jlink_config_mac_address_dump(CMD_CTX, &jlink_cfg); return ERROR_OK; } str = CMD_ARGV[0]; if ((strlen(str) != 17) || (str[2] != ':' || str[5] != ':' || str[8] != ':' || str[11] != ':' || str[14] != ':')) { command_print(CMD_CTX, "ethaddr miss format ff:ff:ff:ff:ff:ff"); return ERROR_COMMAND_SYNTAX_ERROR; } for (i = 5; i >= 0; i--) { addr[i] = strtoul(str, &e, 16); str = e + 1; } if (!(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5])) { command_print(CMD_CTX, "invalid it's zero mac_address"); return ERROR_COMMAND_SYNTAX_ERROR; } if (!(0x01 & addr[0])) { command_print(CMD_CTX, "invalid it's a multicat mac_address"); return ERROR_COMMAND_SYNTAX_ERROR; } memcpy(jlink_cfg.mac_address, addr, sizeof(addr)); return ERROR_OK; } static int string_to_ip(const char *s, uint8_t *ip, int *pos) { uint8_t lip[4]; char *e; const char *s_save = s; int i; if (!s) return -EINVAL; for (i = 0; i < 4; i++) { lip[i] = strtoul(s, &e, 10); if (*e != '.' && i != 3) return -EINVAL; s = e + 1; } *pos = e - s_save; memcpy(ip, lip, sizeof(lip)); return ERROR_OK; } static void cpy_ip(uint8_t *dst, uint8_t *src) { int i, j; for (i = 0, j = 3; i < 4; i++, j--) dst[i] = src[j]; } COMMAND_HANDLER(jlink_handle_jlink_ip_command) { uint32_t ip_address; uint32_t subnet_mask = 0; int i, len; int ret; uint8_t subnet_bits = 24; if (CMD_ARGC < 1) { jlink_config_ip_dump(CMD_CTX, &jlink_cfg); return ERROR_OK; } ret = string_to_ip(CMD_ARGV[0], (uint8_t *)&ip_address, &i); if (ret != ERROR_OK) return ret; len = strlen(CMD_ARGV[0]); /* check for this format A.B.C.D/E */ if (i < len) { if (CMD_ARGV[0][i] != '/') return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0] + i + 1, subnet_bits); } else { if (CMD_ARGC > 1) { ret = string_to_ip(CMD_ARGV[1], (uint8_t *)&subnet_mask, &i); if (ret != ERROR_OK) return ret; } } if (!subnet_mask) subnet_mask = (uint32_t)(subnet_bits < 32 ? ((1ULL << subnet_bits) - 1) : 0xffffffff); cpy_ip(jlink_cfg.ip_address, (uint8_t *)&ip_address); cpy_ip(jlink_cfg.subnet_mask, (uint8_t *)&subnet_mask); return ERROR_OK; } COMMAND_HANDLER(jlink_handle_jlink_reset_command) { memset(&jlink_cfg, 0xff, sizeof(jlink_cfg)); return ERROR_OK; } COMMAND_HANDLER(jlink_handle_jlink_save_command) { if (!(jlink_caps & (1 << EMU_CAP_WRITE_CONFIG))) { command_print(CMD_CTX, "J-Link write emulator configuration not supported"); return ERROR_OK; } command_print(CMD_CTX, "The J-Link need to be unpluged and repluged ta have the config effective"); return jlink_set_config(&jlink_cfg); } COMMAND_HANDLER(jlink_handle_jlink_usb_address_command) { uint32_t address; if (CMD_ARGC < 1) { jlink_config_usb_address_dump(CMD_CTX, &jlink_cfg); return ERROR_OK; } COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); if (address > 0x3 && address != 0xff) { command_print(CMD_CTX, "USB Address must be between 0x00 and 0x03 or 0xff"); return ERROR_COMMAND_SYNTAX_ERROR; } jlink_cfg.usb_address = address; return ERROR_OK; } COMMAND_HANDLER(jlink_handle_jlink_config_command) { struct jlink_config cfg; int ret = ERROR_OK; if (CMD_ARGC == 0) { if (!(jlink_caps & (1 << EMU_CAP_READ_CONFIG))) { command_print(CMD_CTX, "J-Link read emulator configuration not supported"); goto exit; } ret = jlink_get_config(&cfg); if (ret != ERROR_OK) command_print(CMD_CTX, "J-Link read emulator configuration failled"); else jlink_config_dump(CMD_CTX, &jlink_cfg); } exit: return ret; } static const struct command_registration jlink_config_subcommand_handlers[] = { { .name = "kickstart", .handler = &jlink_handle_jlink_kickstart_command, .mode = COMMAND_EXEC, .help = "set Kickstart power on JTAG-pin 19.", .usage = "[val]", }, { .name = "mac_address", .handler = &jlink_handle_jlink_mac_address_command, .mode = COMMAND_EXEC, .help = "set the MAC Address", .usage = "[ff:ff:ff:ff:ff:ff]", }, { .name = "ip", .handler = &jlink_handle_jlink_ip_command, .mode = COMMAND_EXEC, .help = "set the ip address of the J-Link Pro, " "where A.B.C.D is the ip, " "E the bit of the subnet mask, " "F.G.H.I the subnet mask", .usage = "[A.B.C.D[/E] [F.G.H.I]]", }, { .name = "reset", .handler = &jlink_handle_jlink_reset_command, .mode = COMMAND_EXEC, .help = "reset the current config", }, { .name = "save", .handler = &jlink_handle_jlink_save_command, .mode = COMMAND_EXEC, .help = "save the current config", }, { .name = "usb_address", .handler = &jlink_handle_jlink_usb_address_command, .mode = COMMAND_EXEC, .help = "set the USB-Address, " "This will change the product id", .usage = "[0x00 to 0x03 or 0xff]", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration jlink_subcommand_handlers[] = { { .name = "caps", .handler = &jlink_handle_jlink_caps_command, .mode = COMMAND_EXEC, .help = "show jlink capabilities", }, { .name = "info", .handler = &jlink_handle_jlink_info_command, .mode = COMMAND_EXEC, .help = "show jlink info", }, { .name = "hw_jtag", .handler = &jlink_handle_jlink_hw_jtag_command, .mode = COMMAND_EXEC, .help = "access J-Link HW JTAG command version", .usage = "[2|3]", }, { .name = "config", .handler = &jlink_handle_jlink_config_command, .mode = COMMAND_EXEC, .help = "access J-Link configuration, " "if no argument this will dump the config", .chain = jlink_config_subcommand_handlers, }, { .name = "pid", .handler = &jlink_pid_command, .mode = COMMAND_CONFIG, .help = "set the pid of the interface we want to use", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration jlink_command_handlers[] = { { .name = "jlink", .mode = COMMAND_ANY, .help = "perform jlink management", .chain = jlink_subcommand_handlers, }, COMMAND_REGISTRATION_DONE }; struct jtag_interface jlink_interface = { .name = "jlink", .commands = jlink_command_handlers, .transports = jtag_only, .execute_queue = jlink_execute_queue, .speed = jlink_speed, .speed_div = jlink_speed_div, .khz = jlink_khz, .init = jlink_init, .quit = jlink_quit, }; /***************************************************************************/ /* J-Link tap functions */ static unsigned tap_length; static uint8_t tms_buffer[JLINK_TAP_BUFFER_SIZE]; static uint8_t tdi_buffer[JLINK_TAP_BUFFER_SIZE]; static uint8_t tdo_buffer[JLINK_TAP_BUFFER_SIZE]; struct pending_scan_result { int first; /* First bit position in tdo_buffer to read */ int length; /* Number of bits to read */ struct scan_command *command; /* Corresponding scan command */ uint8_t *buffer; }; #define MAX_PENDING_SCAN_RESULTS 256 static int pending_scan_results_length; static struct pending_scan_result pending_scan_results_buffer[MAX_PENDING_SCAN_RESULTS]; static void jlink_tap_init(void) { tap_length = 0; pending_scan_results_length = 0; } static void jlink_tap_ensure_space(int scans, int bits) { int available_scans = MAX_PENDING_SCAN_RESULTS - pending_scan_results_length; int available_bits = JLINK_TAP_BUFFER_SIZE * 8 - tap_length - 32; if (scans > available_scans || bits > available_bits) jlink_tap_execute(); } static void jlink_tap_append_step(int tms, int tdi) { int index_var = tap_length / 8; if (index_var >= JLINK_TAP_BUFFER_SIZE) { LOG_ERROR("jlink_tap_append_step: overflow"); *(uint32_t *)0xFFFFFFFF = 0; exit(-1); } int bit_index = tap_length % 8; uint8_t bit = 1 << bit_index; /* we do not pad TMS, so be sure to initialize all bits */ if (0 == bit_index) tms_buffer[index_var] = tdi_buffer[index_var] = 0; if (tms) tms_buffer[index_var] |= bit; else tms_buffer[index_var] &= ~bit; if (tdi) tdi_buffer[index_var] |= bit; else tdi_buffer[index_var] &= ~bit; tap_length++; } static void jlink_tap_append_scan(int length, uint8_t *buffer, struct scan_command *command) { struct pending_scan_result *pending_scan_result = &pending_scan_results_buffer[pending_scan_results_length]; int i; pending_scan_result->first = tap_length; pending_scan_result->length = length; pending_scan_result->command = command; pending_scan_result->buffer = buffer; for (i = 0; i < length; i++) { int tms = (i < (length - 1)) ? 0 : 1; int tdi = (buffer[i / 8] & (1 << (i % 8))) != 0; jlink_tap_append_step(tms, tdi); } pending_scan_results_length++; } /* Pad and send a tap sequence to the device, and receive the answer. * For the purpose of padding we assume that we are in idle or pause state. */ static int jlink_tap_execute(void) { int byte_length; int i; int result; if (!tap_length) return ERROR_OK; /* JLink returns an extra NULL in packet when size of incoming * message is a multiple of 64, creates problems with USB comms. * WARNING: This will interfere with tap state counting. */ while ((DIV_ROUND_UP(tap_length, 8) % 64) == 0) jlink_tap_append_step((tap_get_state() == TAP_RESET) ? 1 : 0, 0); /* number of full bytes (plus one if some would be left over) */ byte_length = DIV_ROUND_UP(tap_length, 8); bool use_jtag3 = jlink_hw_jtag_version >= 3; usb_out_buffer[0] = use_jtag3 ? EMU_CMD_HW_JTAG3 : EMU_CMD_HW_JTAG2; usb_out_buffer[1] = 0; usb_out_buffer[2] = (tap_length >> 0) & 0xff; usb_out_buffer[3] = (tap_length >> 8) & 0xff; memcpy(usb_out_buffer + 4, tms_buffer, byte_length); memcpy(usb_out_buffer + 4 + byte_length, tdi_buffer, byte_length); jlink_last_state = jtag_debug_state_machine(tms_buffer, tdi_buffer, tap_length, jlink_last_state); result = jlink_usb_message(jlink_handle, 4 + 2 * byte_length, byte_length); if (result != byte_length) { LOG_ERROR("jlink_tap_execute, wrong result %d (expected %d)", result, byte_length); jlink_tap_init(); return ERROR_JTAG_QUEUE_FAILED; } memcpy(tdo_buffer, usb_in_buffer, byte_length); for (i = 0; i < pending_scan_results_length; i++) { struct pending_scan_result *pending_scan_result = &pending_scan_results_buffer[i]; uint8_t *buffer = pending_scan_result->buffer; int length = pending_scan_result->length; int first = pending_scan_result->first; struct scan_command *command = pending_scan_result->command; /* Copy to buffer */ buf_set_buf(tdo_buffer, first, buffer, 0, length); DEBUG_JTAG_IO("pending scan result, length = %d", length); jlink_debug_buffer(buffer, DIV_ROUND_UP(length, 8)); if (jtag_read_buffer(buffer, command) != ERROR_OK) { jlink_tap_init(); return ERROR_JTAG_QUEUE_FAILED; } if (pending_scan_result->buffer != NULL) free(pending_scan_result->buffer); } jlink_tap_init(); return ERROR_OK; } /*****************************************************************************/ /* JLink USB low-level functions */ static struct jlink *jlink_usb_open() { struct jtag_libusb_device_handle *devh; if (jtag_libusb_open(vids, pids, &devh) != ERROR_OK) return NULL; /* BE ***VERY CAREFUL*** ABOUT MAKING CHANGES IN THIS * AREA!!!!!!!!!!! The behavior of libusb is not completely * consistent across Windows, Linux, and Mac OS X platforms. * The actions taken in the following compiler conditionals may * not agree with published documentation for libusb, but were * found to be necessary through trials and tribulations. Even * little tweaks can break one or more platforms, so if you do * make changes test them carefully on all platforms before * committing them! */ #if IS_WIN32 == 0 jtag_libusb_reset_device(devh); #if IS_DARWIN == 0 int timeout = 5; /* reopen jlink after usb_reset * on win32 this may take a second or two to re-enumerate */ int retval; while ((retval = jtag_libusb_open(vids, pids, &devh)) != ERROR_OK) { usleep(1000); timeout--; if (!timeout) break; } if (ERROR_OK != retval) return NULL; #endif #endif /* usb_set_configuration required under win32 */ struct jtag_libusb_device *udev = jtag_libusb_get_device(devh); jtag_libusb_set_configuration(devh, 0); jtag_libusb_claim_interface(devh, 0); #if 0 /* * This makes problems under Mac OS X. And is not needed * under Windows. Hopefully this will not break a linux build */ usb_set_altinterface(result->usb_handle, 0); #endif jtag_libusb_get_endpoints(udev, &jlink_read_ep, &jlink_write_ep); struct jlink *result = malloc(sizeof(struct jlink)); result->usb_handle = devh; return result; } static void jlink_usb_close(struct jlink *jlink) { jtag_libusb_close(jlink->usb_handle); free(jlink); } /* Send a message and receive the reply. */ static int jlink_usb_message(struct jlink *jlink, int out_length, int in_length) { int result; result = jlink_usb_write(jlink, out_length); if (result != out_length) { LOG_ERROR("usb_bulk_write failed (requested=%d, result=%d)", out_length, result); return ERROR_JTAG_DEVICE_ERROR; } result = jlink_usb_read(jlink, in_length); if ((result != in_length) && (result != (in_length + 1))) { LOG_ERROR("usb_bulk_read failed (requested=%d, result=%d)", in_length, result); return ERROR_JTAG_DEVICE_ERROR; } if (jlink_hw_jtag_version < 3) return result; int result2 = ERROR_OK; if (result == in_length) { /* Must read the result from the EMU too */ result2 = jlink_usb_read_emu_result(jlink); if (1 != result2) { LOG_ERROR("jlink_usb_read_emu_result retried requested = 1, " "result=%d, in_length=%i", result2, in_length); /* Try again once, should only happen if (in_length%64 == 0) */ result2 = jlink_usb_read_emu_result(jlink); if (1 != result2) { LOG_ERROR("jlink_usb_read_emu_result failed " "(requested = 1, result=%d)", result2); return ERROR_JTAG_DEVICE_ERROR; } } /* Check the result itself */ result2 = usb_emu_result_buffer[0]; } else { /* Save the result, then remove it from return value */ result2 = usb_in_buffer[result--]; } if (result2) { LOG_ERROR("jlink_usb_message failed with result=%d)", result2); return ERROR_JTAG_DEVICE_ERROR; } return result; } /* calls the given usb_bulk_* function, allowing for the data to * trickle in with some timeouts */ static int usb_bulk_with_retries( int (*f)(jtag_libusb_device_handle *, int, char *, int, int), jtag_libusb_device_handle *dev, int ep, char *bytes, int size, int timeout) { int tries = 3, count = 0; while (tries && (count < size)) { int result = f(dev, ep, bytes + count, size - count, timeout); if (result > 0) count += result; else if ((-ETIMEDOUT != result) || !--tries) return result; } return count; } static int wrap_usb_bulk_write(jtag_libusb_device_handle *dev, int ep, char *buff, int size, int timeout) { /* usb_bulk_write() takes const char *buff */ return jtag_libusb_bulk_write(dev, ep, buff, size, timeout); } static inline int usb_bulk_write_ex(jtag_libusb_device_handle *dev, int ep, char *bytes, int size, int timeout) { return usb_bulk_with_retries(&wrap_usb_bulk_write, dev, ep, bytes, size, timeout); } static inline int usb_bulk_read_ex(jtag_libusb_device_handle *dev, int ep, char *bytes, int size, int timeout) { return usb_bulk_with_retries(&jtag_libusb_bulk_read, dev, ep, bytes, size, timeout); } /* Write data from out_buffer to USB. */ static int jlink_usb_write(struct jlink *jlink, int out_length) { int result; if (out_length > JLINK_OUT_BUFFER_SIZE) { LOG_ERROR("jlink_write illegal out_length=%d (max=%d)", out_length, JLINK_OUT_BUFFER_SIZE); return -1; } result = usb_bulk_write_ex(jlink->usb_handle, jlink_write_ep, (char *)usb_out_buffer, out_length, JLINK_USB_TIMEOUT); DEBUG_JTAG_IO("jlink_usb_write, out_length = %d, result = %d", out_length, result); jlink_debug_buffer(usb_out_buffer, out_length); return result; } /* Read data from USB into in_buffer. */ static int jlink_usb_read(struct jlink *jlink, int expected_size) { int result = usb_bulk_read_ex(jlink->usb_handle, jlink_read_ep, (char *)usb_in_buffer, expected_size, JLINK_USB_TIMEOUT); DEBUG_JTAG_IO("jlink_usb_read, result = %d", result); jlink_debug_buffer(usb_in_buffer, result); return result; } /* Read the result from the previous EMU cmd into result_buffer. */ static int jlink_usb_read_emu_result(struct jlink *jlink) { int result = usb_bulk_read_ex(jlink->usb_handle, jlink_read_ep, (char *)usb_emu_result_buffer, 1 /* JLINK_EMU_RESULT_BUFFER_SIZE */, JLINK_USB_TIMEOUT); DEBUG_JTAG_IO("jlink_usb_read_result, result = %d", result); jlink_debug_buffer(usb_emu_result_buffer, result); return result; } /* * Send a message and receive the reply - simple messages. * * @param jlink pointer to driver data * @param out_length data length in @c usb_out_buffer * @param in_length data length to be read to @c usb_in_buffer */ static int jlink_usb_io(struct jlink *jlink, int out_length, int in_length) { int result; result = jlink_usb_write(jlink, out_length); if (result != out_length) { LOG_ERROR("usb_bulk_write failed (requested=%d, result=%d)", out_length, result); return ERROR_JTAG_DEVICE_ERROR; } result = jlink_usb_read(jlink, in_length); if (result != in_length) { LOG_ERROR("usb_bulk_read failed (requested=%d, result=%d)", in_length, result); return ERROR_JTAG_DEVICE_ERROR; } /* * Section 4.2.4 IN-transaction: * read dummy 0-byte packet if transaction size is * multiple of 64 bytes but not max. size of 0x8000 */ if ((in_length % 64) == 0 && in_length != 0x8000) { char dummy_buffer; result = usb_bulk_read_ex(jlink->usb_handle, jlink_read_ep, &dummy_buffer, 1, JLINK_USB_TIMEOUT); if (result != 0) { LOG_ERROR("dummy byte read failed"); return ERROR_JTAG_DEVICE_ERROR; } } return ERROR_OK; } #ifdef _DEBUG_USB_COMMS_ #define BYTES_PER_LINE 16 static void jlink_debug_buffer(uint8_t *buffer, int length) { char line[81]; char s[4]; int i; int j; for (i = 0; i < length; i += BYTES_PER_LINE) { snprintf(line, 5, "%04x", i); for (j = i; j < i + BYTES_PER_LINE && j < length; j++) { snprintf(s, 4, " %02x", buffer[j]); strcat(line, s); } LOG_DEBUG("%s", line); } } #endif openocd-0.7.0/src/jtag/drivers/presto.c0000644000175000001440000004730712134336410014744 00000000000000/*************************************************************************** * Copyright (C) 2007 by Pavel Chromy * * chromy@asix.cz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /** * @file * Holds driver for PRESTO programmer from ASIX. * http://tools.asix.net/prg_presto.htm */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #if IS_CYGWIN == 1 #include "windows.h" #endif #include #include #include "bitq.h" /* PRESTO access library includes */ #if BUILD_PRESTO_FTD2XX == 1 #include #include "ftd2xx_common.h" #elif BUILD_PRESTO_LIBFTDI == 1 #include #else #error "BUG: either FTD2XX and LIBFTDI has to be used" #endif /* -------------------------------------------------------------------------- */ #define FT_DEVICE_NAME_LEN 64 #define FT_DEVICE_SERNUM_LEN 64 #define PRESTO_VID_PID 0x0403f1a0 #define PRESTO_VID (0x0403) #define PRESTO_PID (0xf1a0) #define BUFFER_SIZE (64*62) struct presto { #if BUILD_PRESTO_FTD2XX == 1 FT_HANDLE handle; FT_STATUS status; #elif BUILD_PRESTO_LIBFTDI == 1 struct ftdi_context ftdic; int retval; #endif char serial[FT_DEVICE_SERNUM_LEN]; uint8_t buff_out[BUFFER_SIZE]; int buff_out_pos; uint8_t buff_in[BUFFER_SIZE]; int buff_in_exp;/* expected in buffer length */ int buff_in_len;/* length of data received */ int buff_in_pos; unsigned long total_out; unsigned long total_in; int jtag_tms; /* last tms state */ int jtag_tck; /* last tck state */ int jtag_rst; /* last trst state */ int jtag_tdi_data; int jtag_tdi_count; int jtag_speed; }; static struct presto presto_state; static struct presto *presto = &presto_state; static uint8_t presto_init_seq[] = { 0x80, 0xA0, 0xA8, 0xB0, 0xC0, 0xE0 }; static int presto_write(uint8_t *buf, uint32_t size) { #if BUILD_PRESTO_FTD2XX == 1 DWORD ftbytes; presto->status = FT_Write(presto->handle, buf, size, &ftbytes); if (presto->status != FT_OK) { LOG_ERROR("FT_Write returned: %s", ftd2xx_status_string(presto->status)); return ERROR_JTAG_DEVICE_ERROR; } #elif BUILD_PRESTO_LIBFTDI == 1 uint32_t ftbytes; presto->retval = ftdi_write_data(&presto->ftdic, buf, size); if (presto->retval < 0) { LOG_ERROR("ftdi_write_data: %s", ftdi_get_error_string(&presto->ftdic)); return ERROR_JTAG_DEVICE_ERROR; } ftbytes = presto->retval; #endif if (ftbytes != size) { LOG_ERROR("couldn't write the requested number of bytes to PRESTO (%u < %u)", (unsigned)ftbytes, (unsigned)size); return ERROR_JTAG_DEVICE_ERROR; } return ERROR_OK; } static int presto_read(uint8_t *buf, uint32_t size) { #if BUILD_PRESTO_FTD2XX == 1 DWORD ftbytes; presto->status = FT_Read(presto->handle, buf, size, &ftbytes); if (presto->status != FT_OK) { LOG_ERROR("FT_Read returned: %s", ftd2xx_status_string(presto->status)); return ERROR_JTAG_DEVICE_ERROR; } #elif BUILD_PRESTO_LIBFTDI == 1 uint32_t ftbytes = 0; struct timeval timeout, now; gettimeofday(&timeout, NULL); timeval_add_time(&timeout, 1, 0); /* one second timeout */ while (ftbytes < size) { presto->retval = ftdi_read_data(&presto->ftdic, buf + ftbytes, size - ftbytes); if (presto->retval < 0) { LOG_ERROR("ftdi_read_data: %s", ftdi_get_error_string(&presto->ftdic)); return ERROR_JTAG_DEVICE_ERROR; } ftbytes += presto->retval; gettimeofday(&now, NULL); if ((now.tv_sec > timeout.tv_sec) || ((now.tv_sec == timeout.tv_sec) && (now.tv_usec > timeout.tv_usec))) break; } #endif if (ftbytes != size) { /* this is just a warning, there might have been timeout when detecting PRESTO, *which is not fatal */ LOG_WARNING("couldn't read the requested number of bytes from PRESTO (%u < %u)", (unsigned)ftbytes, (unsigned)size); return ERROR_JTAG_DEVICE_ERROR; } return ERROR_OK; } #if BUILD_PRESTO_FTD2XX == 1 static int presto_open_ftd2xx(char *req_serial) { uint32_t i; DWORD numdevs; DWORD vidpid; char devname[FT_DEVICE_NAME_LEN]; FT_DEVICE device; BYTE presto_data; DWORD ftbytes; presto->handle = (FT_HANDLE)INVALID_HANDLE_VALUE; #if IS_WIN32 == 0 /* Add non-standard Vid/Pid to the linux driver */ presto->status = FT_SetVIDPID(PRESTO_VID, PRESTO_PID); if (presto->status != FT_OK) { LOG_ERROR("couldn't add PRESTO VID/PID"); exit(-1); } #endif presto->status = FT_ListDevices(&numdevs, NULL, FT_LIST_NUMBER_ONLY); if (presto->status != FT_OK) { LOG_ERROR("FT_ListDevices failed: %s", ftd2xx_status_string(presto->status)); return ERROR_JTAG_DEVICE_ERROR; } LOG_DEBUG("FTDI devices available: %" PRIu32, (uint32_t)numdevs); for (i = 0; i < numdevs; i++) { presto->status = FT_Open(i, &(presto->handle)); if (presto->status != FT_OK) { /* this is not fatal, the device may be legitimately open by other process, *hence debug message only */ LOG_DEBUG("FT_Open failed: %s", ftd2xx_status_string(presto->status)); continue; } LOG_DEBUG("FTDI device %i open", (int)i); presto->status = FT_GetDeviceInfo(presto->handle, &device, &vidpid, presto->serial, devname, NULL); if (presto->status == FT_OK) { if (vidpid == PRESTO_VID_PID && (req_serial == NULL || !strcmp(presto->serial, req_serial))) break; } else LOG_DEBUG("FT_GetDeviceInfo failed: %s", ftd2xx_status_string( presto->status)); LOG_DEBUG("FTDI device %i does not match, closing", (int)i); FT_Close(presto->handle); presto->handle = (FT_HANDLE)INVALID_HANDLE_VALUE; } if (presto->handle == (FT_HANDLE)INVALID_HANDLE_VALUE) return ERROR_JTAG_DEVICE_ERROR; /* presto not open, return */ presto->status = FT_SetLatencyTimer(presto->handle, 1); if (presto->status != FT_OK) return ERROR_JTAG_DEVICE_ERROR; presto->status = FT_SetTimeouts(presto->handle, 100, 0); if (presto->status != FT_OK) return ERROR_JTAG_DEVICE_ERROR; presto->status = FT_Purge(presto->handle, FT_PURGE_TX | FT_PURGE_RX); if (presto->status != FT_OK) return ERROR_JTAG_DEVICE_ERROR; presto_data = 0xD0; presto->status = FT_Write(presto->handle, &presto_data, 1, &ftbytes); if (presto->status != FT_OK) return ERROR_JTAG_DEVICE_ERROR; /* delay between first write/read turnaround (after purge?) necessary * under Linux for unknown reason, * probably a bug in library threading */ usleep(100000); presto->status = FT_Read(presto->handle, &presto_data, 1, &ftbytes); if (presto->status != FT_OK) return ERROR_JTAG_DEVICE_ERROR; if (ftbytes != 1) { LOG_DEBUG("PRESTO reset"); presto->status = FT_Purge(presto->handle, FT_PURGE_TX | FT_PURGE_RX); if (presto->status != FT_OK) return ERROR_JTAG_DEVICE_ERROR; presto->status = FT_SetBitMode(presto->handle, 0x80, 1); if (presto->status != FT_OK) return ERROR_JTAG_DEVICE_ERROR; presto->status = FT_SetBaudRate(presto->handle, 9600); if (presto->status != FT_OK) return ERROR_JTAG_DEVICE_ERROR; presto_data = 0; for (i = 0; i < 4 * 62; i++) { presto->status = FT_Write(presto->handle, &presto_data, 1, &ftbytes); if (presto->status != FT_OK) return ERROR_JTAG_DEVICE_ERROR; } usleep(100000); presto->status = FT_SetBitMode(presto->handle, 0x00, 0); if (presto->status != FT_OK) return ERROR_JTAG_DEVICE_ERROR; presto->status = FT_Purge(presto->handle, FT_PURGE_TX | FT_PURGE_RX); if (presto->status != FT_OK) return ERROR_JTAG_DEVICE_ERROR; presto_data = 0xD0; presto->status = FT_Write(presto->handle, &presto_data, 1, &ftbytes); if (presto->status != FT_OK) return ERROR_JTAG_DEVICE_ERROR; /* delay between first write/read turnaround (after purge?) necessary under Linux for unknown reason, probably a bug in library threading */ usleep(100000); presto->status = FT_Read(presto->handle, &presto_data, 1, &ftbytes); if (presto->status != FT_OK) return ERROR_JTAG_DEVICE_ERROR; if (ftbytes != 1) { LOG_DEBUG("PRESTO not responding"); return ERROR_JTAG_DEVICE_ERROR; } } presto->status = FT_SetTimeouts(presto->handle, 0, 0); if (presto->status != FT_OK) return ERROR_JTAG_DEVICE_ERROR; presto->status = FT_Write(presto->handle, &presto_init_seq, sizeof(presto_init_seq), &ftbytes); if (presto->status != FT_OK || ftbytes != sizeof(presto_init_seq)) return ERROR_JTAG_DEVICE_ERROR; return ERROR_OK; } #elif BUILD_PRESTO_LIBFTDI == 1 static int presto_open_libftdi(char *req_serial) { uint8_t presto_data; LOG_DEBUG("searching for PRESTO using libftdi"); /* initialize FTDI context structure */ if (ftdi_init(&presto->ftdic) < 0) { LOG_ERROR("unable to init libftdi: %s", presto->ftdic.error_str); return ERROR_JTAG_DEVICE_ERROR; } /* context, vendor id, product id */ if (ftdi_usb_open_desc(&presto->ftdic, PRESTO_VID, PRESTO_PID, NULL, req_serial) < 0) { LOG_ERROR("unable to open PRESTO: %s", presto->ftdic.error_str); return ERROR_JTAG_DEVICE_ERROR; } if (ftdi_usb_reset(&presto->ftdic) < 0) { LOG_ERROR("unable to reset PRESTO device"); return ERROR_JTAG_DEVICE_ERROR; } if (ftdi_set_latency_timer(&presto->ftdic, 1) < 0) { LOG_ERROR("unable to set latency timer"); return ERROR_JTAG_DEVICE_ERROR; } if (ftdi_usb_purge_buffers(&presto->ftdic) < 0) { LOG_ERROR("unable to purge PRESTO buffers"); return ERROR_JTAG_DEVICE_ERROR; } presto_data = 0xD0; if (presto_write(&presto_data, 1) != ERROR_OK) { LOG_ERROR("error writing to PRESTO"); return ERROR_JTAG_DEVICE_ERROR; } if (presto_read(&presto_data, 1) != ERROR_OK) { LOG_DEBUG("no response from PRESTO, retrying"); if (ftdi_usb_purge_buffers(&presto->ftdic) < 0) return ERROR_JTAG_DEVICE_ERROR; presto_data = 0xD0; if (presto_write(&presto_data, 1) != ERROR_OK) return ERROR_JTAG_DEVICE_ERROR; if (presto_read(&presto_data, 1) != ERROR_OK) { LOG_ERROR("no response from PRESTO, giving up"); return ERROR_JTAG_DEVICE_ERROR; } } if (presto_write(presto_init_seq, sizeof(presto_init_seq)) != ERROR_OK) { LOG_ERROR("error writing PRESTO init sequence"); return ERROR_JTAG_DEVICE_ERROR; } return ERROR_OK; } #endif /* BUILD_PRESTO_LIBFTDI == 1 */ static int presto_open(char *req_serial) { presto->buff_out_pos = 0; presto->buff_in_pos = 0; presto->buff_in_len = 0; presto->buff_in_exp = 0; presto->total_out = 0; presto->total_in = 0; presto->jtag_tms = 0; presto->jtag_tck = 0; presto->jtag_rst = 0; presto->jtag_tdi_data = 0; presto->jtag_tdi_count = 0; presto->jtag_speed = 0; #if BUILD_PRESTO_FTD2XX == 1 return presto_open_ftd2xx(req_serial); #elif BUILD_PRESTO_LIBFTDI == 1 return presto_open_libftdi(req_serial); #endif } static int presto_close(void) { int result = ERROR_OK; #if BUILD_PRESTO_FTD2XX == 1 DWORD ftbytes; if (presto->handle == (FT_HANDLE)INVALID_HANDLE_VALUE) return result; presto->status = FT_Purge(presto->handle, FT_PURGE_TX | FT_PURGE_RX); if (presto->status != FT_OK) result = ERROR_JTAG_DEVICE_ERROR; presto->status = FT_Write(presto->handle, &presto_init_seq, sizeof(presto_init_seq), &ftbytes); if (presto->status != FT_OK || ftbytes != sizeof(presto_init_seq)) result = ERROR_JTAG_DEVICE_ERROR; presto->status = FT_SetLatencyTimer(presto->handle, 16); if (presto->status != FT_OK) result = ERROR_JTAG_DEVICE_ERROR; presto->status = FT_Close(presto->handle); if (presto->status != FT_OK) result = ERROR_JTAG_DEVICE_ERROR; else presto->handle = (FT_HANDLE)INVALID_HANDLE_VALUE; #elif BUILD_PRESTO_LIBFTDI == 1 presto->retval = ftdi_write_data(&presto->ftdic, presto_init_seq, sizeof(presto_init_seq)); if (presto->retval != sizeof(presto_init_seq)) result = ERROR_JTAG_DEVICE_ERROR; presto->retval = ftdi_set_latency_timer(&presto->ftdic, 16); if (presto->retval < 0) result = ERROR_JTAG_DEVICE_ERROR; presto->retval = ftdi_usb_close(&presto->ftdic); if (presto->retval < 0) result = ERROR_JTAG_DEVICE_ERROR; else ftdi_deinit(&presto->ftdic); #endif return result; } static int presto_flush(void) { if (presto->buff_out_pos == 0) return ERROR_OK; #if BUILD_PRESTO_FTD2XX == 1 if (presto->status != FT_OK) { #elif BUILD_PRESTO_LIBFTDI == 1 if (presto->retval < 0) { #endif LOG_DEBUG("error in previous communication, canceling I/O operation"); return ERROR_JTAG_DEVICE_ERROR; } if (presto_write(presto->buff_out, presto->buff_out_pos) != ERROR_OK) { presto->buff_out_pos = 0; return ERROR_JTAG_DEVICE_ERROR; } presto->total_out += presto->buff_out_pos; presto->buff_out_pos = 0; if (presto->buff_in_exp == 0) return ERROR_OK; presto->buff_in_pos = 0; presto->buff_in_len = 0; if (presto_read(presto->buff_in, presto->buff_in_exp) != ERROR_OK) { presto->buff_in_exp = 0; return ERROR_JTAG_DEVICE_ERROR; } presto->total_in += presto->buff_in_exp; presto->buff_in_len = presto->buff_in_exp; presto->buff_in_exp = 0; return ERROR_OK; } static int presto_sendbyte(int data) { if (data == EOF) return presto_flush(); if (presto->buff_out_pos < BUFFER_SIZE) { presto->buff_out[presto->buff_out_pos++] = (uint8_t)data; if (((data & 0xC0) == 0x40) || ((data & 0xD0) == 0xD0)) presto->buff_in_exp++; } else return ERROR_JTAG_DEVICE_ERROR; #if BUILD_PRESTO_FTD2XX == 1 if (presto->buff_out_pos >= BUFFER_SIZE) #elif BUILD_PRESTO_LIBFTDI == 1 /* libftdi does not do background read, be sure that USB IN buffer does not overflow (128 *bytes only!) */ if (presto->buff_out_pos >= BUFFER_SIZE || presto->buff_in_exp == 128) #endif return presto_flush(); return ERROR_OK; } #if 0 static int presto_getbyte(void) { if (presto->buff_in_pos < presto->buff_in_len) return presto->buff_in[presto->buff_in_pos++]; if (presto->buff_in_exp == 0) return -1; if (presto_flush() != ERROR_OK) return -1; if (presto->buff_in_pos < presto->buff_in_len) return presto->buff_in[presto->buff_in_pos++]; return -1; } #endif /* -------------------------------------------------------------------------- */ static int presto_tdi_flush(void) { if (presto->jtag_tdi_count == 0) return 0; if (presto->jtag_tck == 0) { LOG_ERROR("BUG: unexpected TAP condition, TCK low"); return -1; } presto->jtag_tdi_data |= (presto->jtag_tdi_count - 1) << 4; presto_sendbyte(presto->jtag_tdi_data); presto->jtag_tdi_count = 0; presto->jtag_tdi_data = 0; return 0; } static int presto_tck_idle(void) { if (presto->jtag_tck == 1) { presto_sendbyte(0xCA); presto->jtag_tck = 0; } return 0; } /* -------------------------------------------------------------------------- */ static int presto_bitq_out(int tms, int tdi, int tdo_req) { int i; unsigned char cmd; if (presto->jtag_tck == 0) presto_sendbyte(0xA4); /* LED idicator - JTAG active */ else if (presto->jtag_speed == 0 && !tdo_req && tms == presto->jtag_tms) { presto->jtag_tdi_data |= (tdi != 0) << presto->jtag_tdi_count; if (++presto->jtag_tdi_count == 4) presto_tdi_flush(); return 0; } presto_tdi_flush(); cmd = tdi ? 0xCB : 0xCA; presto_sendbyte(cmd); if (tms != presto->jtag_tms) { presto_sendbyte((tms ? 0xEC : 0xE8) | (presto->jtag_rst ? 0x02 : 0)); presto->jtag_tms = tms; } /* delay with TCK low */ for (i = presto->jtag_speed; i > 1; i--) presto_sendbyte(cmd); cmd |= 0x04; presto_sendbyte(cmd | (tdo_req ? 0x10 : 0)); /* delay with TCK high */ for (i = presto->jtag_speed; i > 1; i--) presto_sendbyte(cmd); presto->jtag_tck = 1; return 0; } static int presto_bitq_flush(void) { presto_tdi_flush(); presto_tck_idle(); presto_sendbyte(0xA0); /* LED idicator - JTAG idle */ return presto_flush(); } static int presto_bitq_in_rdy(void) { if (presto->buff_in_pos >= presto->buff_in_len) return 0; return presto->buff_in_len-presto->buff_in_pos; } static int presto_bitq_in(void) { if (presto->buff_in_pos >= presto->buff_in_len) return -1; if (presto->buff_in[presto->buff_in_pos++]&0x08) return 1; return 0; } static int presto_bitq_sleep(unsigned long us) { long waits; presto_tdi_flush(); presto_tck_idle(); if (us > 100000) { presto_bitq_flush(); jtag_sleep(us); return 0; } waits = us / 170 + 2; while (waits--) presto_sendbyte(0x80); return 0; } static int presto_bitq_reset(int trst, int srst) { presto_tdi_flush(); presto_tck_idle(); /* add a delay after possible TCK transition */ presto_sendbyte(0x80); presto_sendbyte(0x80); presto->jtag_rst = trst || srst; presto_sendbyte((presto->jtag_rst ? 0xEA : 0xE8) | (presto->jtag_tms ? 0x04 : 0)); return 0; } static struct bitq_interface presto_bitq = { .out = &presto_bitq_out, .flush = &presto_bitq_flush, .sleep = &presto_bitq_sleep, .reset = &presto_bitq_reset, .in_rdy = &presto_bitq_in_rdy, .in = &presto_bitq_in, }; /* -------------------------------------------------------------------------- */ static int presto_adapter_khz(int khz, int *jtag_speed) { if (khz < 0) { *jtag_speed = 0; return ERROR_COMMAND_SYNTAX_ERROR; } if (khz >= 3000) *jtag_speed = 0; else *jtag_speed = (1000 + khz-1)/khz; return 0; } static int presto_jtag_speed_div(int speed, int *khz) { if ((speed < 0) || (speed > 1000)) { *khz = 0; return ERROR_COMMAND_SYNTAX_ERROR; } if (speed == 0) *khz = 3000; else *khz = 1000/speed; return 0; } static int presto_jtag_speed(int speed) { int khz; if (presto_jtag_speed_div(speed, &khz)) return ERROR_COMMAND_SYNTAX_ERROR; presto->jtag_speed = speed; if (khz%1000 == 0) LOG_INFO("setting speed to %d, max. TCK freq. is %d MHz", speed, khz/1000); else LOG_INFO("setting speed to %d, max. TCK freq. is %d kHz", speed, khz); return 0; } static char *presto_serial; COMMAND_HANDLER(presto_handle_serial_command) { if (CMD_ARGC == 1) { if (presto_serial) free(presto_serial); presto_serial = strdup(CMD_ARGV[0]); } else return ERROR_COMMAND_SYNTAX_ERROR; return ERROR_OK; } static const struct command_registration presto_command_handlers[] = { { .name = "presto_serial", .handler = presto_handle_serial_command, .mode = COMMAND_CONFIG, .help = "Configure USB serial number of Presto device.", .usage = "serial_string", }, COMMAND_REGISTRATION_DONE }; static int presto_jtag_init(void) { if (presto_open(presto_serial) != ERROR_OK) { presto_close(); if (presto_serial != NULL) LOG_ERROR("Cannot open PRESTO, serial number '%s'", presto_serial); else LOG_ERROR("Cannot open PRESTO"); return ERROR_JTAG_INIT_FAILED; } LOG_INFO("PRESTO open, serial number '%s'", presto->serial); bitq_interface = &presto_bitq; return ERROR_OK; } static int presto_jtag_quit(void) { bitq_cleanup(); presto_close(); LOG_INFO("PRESTO closed"); if (presto_serial) { free(presto_serial); presto_serial = NULL; } return ERROR_OK; } struct jtag_interface presto_interface = { .name = "presto", .commands = presto_command_handlers, .execute_queue = bitq_execute_queue, .speed = presto_jtag_speed, .khz = presto_adapter_khz, .speed_div = presto_jtag_speed_div, .init = presto_jtag_init, .quit = presto_jtag_quit, }; openocd-0.7.0/src/jtag/drivers/bitbang.h0000644000175000001440000000377112134336410015040 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef BITBANG_H #define BITBANG_H struct bitbang_interface { /* low level callbacks (for bitbang) */ int (*read)(void); void (*write)(int tck, int tms, int tdi); void (*reset)(int trst, int srst); void (*blink)(int on); }; int bitbang_execute_queue(void); extern struct bitbang_interface *bitbang_interface; #endif /* BITBANG_H */ openocd-0.7.0/src/jtag/drivers/Makefile.in0000644000175000001440000010214012141414276015321 00000000000000# Makefile.in generated by automake 1.13.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ DIST_COMMON = $(top_srcdir)/common.mk $(srcdir)/Makefile.in \ $(srcdir)/Makefile.am $(top_srcdir)/depcomp \ $(am__nobase_dist_ocddata_DATA_DIST) $(noinst_HEADERS) @INTERNAL_JIMTCL_TRUE@am__append_1 = -I$(top_srcdir)/jimtcl \ @INTERNAL_JIMTCL_TRUE@ -I$(top_builddir)/jimtcl @USB_TRUE@am__append_2 = usb_common.c @USE_LIBUSB1_TRUE@am__append_3 = libusb1_common.c @USE_LIBUSB0_TRUE@@USE_LIBUSB1_FALSE@am__append_4 = libusb0_common.c @BITBANG_TRUE@am__append_5 = bitbang.c @PARPORT_TRUE@am__append_6 = parport.c @DUMMY_TRUE@am__append_7 = dummy.c @FT2232_DRIVER_TRUE@am__append_8 = ft2232.c @FTDI_DRIVER_TRUE@am__append_9 = ftdi.c mpsse.c @USB_BLASTER_DRIVER_TRUE@am__append_10 = usb_blaster.c @AMTJTAGACCEL_TRUE@am__append_11 = amt_jtagaccel.c @EP93XX_TRUE@am__append_12 = ep93xx.c @AT91RM9200_TRUE@am__append_13 = at91rm9200.c @GW16012_TRUE@am__append_14 = gw16012.c @BITQ_TRUE@am__append_15 = bitq.c @PRESTO_DRIVER_TRUE@am__append_16 = presto.c @USBPROG_TRUE@am__append_17 = usbprog.c @JLINK_TRUE@am__append_18 = jlink.c @RLINK_TRUE@am__append_19 = rlink.c rlink_speed_table.c @ULINK_TRUE@am__append_20 = ulink.c @ULINK_TRUE@am__append_21 = $(ULINK_FIRMWARE)/ulink_firmware.hex @VSLLINK_TRUE@am__append_22 = versaloon/usbtoxxx/usbtogpio.c \ @VSLLINK_TRUE@ versaloon/usbtoxxx/usbtojtagraw.c \ @VSLLINK_TRUE@ versaloon/usbtoxxx/usbtoswd.c \ @VSLLINK_TRUE@ versaloon/usbtoxxx/usbtopwr.c \ @VSLLINK_TRUE@ versaloon/usbtoxxx/usbtoxxx.c \ @VSLLINK_TRUE@ versaloon/versaloon.c vsllink.c @ARMJTAGEW_TRUE@am__append_23 = arm-jtag-ew.c @BUSPIRATE_TRUE@am__append_24 = buspirate.c @REMOTE_BITBANG_TRUE@am__append_25 = remote_bitbang.c @HLADAPTER_TRUE@am__append_26 = stlink_usb.c ti_icdi_usb.c @OSBDM_TRUE@am__append_27 = osbdm.c @OPENDOUS_TRUE@am__append_28 = opendous.c @SYSFSGPIO_TRUE@am__append_29 = sysfsgpio.c subdir = src/jtag/drivers ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/config_subdir.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libocdjtagdrivers_la_LIBADD = am__libocdjtagdrivers_la_SOURCES_DIST = driver.c usb_common.c \ libusb1_common.c libusb0_common.c bitbang.c parport.c dummy.c \ ft2232.c ftdi.c mpsse.c usb_blaster.c amt_jtagaccel.c ep93xx.c \ at91rm9200.c gw16012.c bitq.c presto.c usbprog.c jlink.c \ rlink.c rlink_speed_table.c ulink.c \ versaloon/usbtoxxx/usbtogpio.c \ versaloon/usbtoxxx/usbtojtagraw.c \ versaloon/usbtoxxx/usbtoswd.c versaloon/usbtoxxx/usbtopwr.c \ versaloon/usbtoxxx/usbtoxxx.c versaloon/versaloon.c vsllink.c \ arm-jtag-ew.c buspirate.c remote_bitbang.c stlink_usb.c \ ti_icdi_usb.c osbdm.c opendous.c sysfsgpio.c @USB_TRUE@am__objects_1 = usb_common.lo @USE_LIBUSB1_TRUE@am__objects_2 = libusb1_common.lo @USE_LIBUSB0_TRUE@@USE_LIBUSB1_FALSE@am__objects_3 = \ @USE_LIBUSB0_TRUE@@USE_LIBUSB1_FALSE@ libusb0_common.lo @BITBANG_TRUE@am__objects_4 = bitbang.lo @PARPORT_TRUE@am__objects_5 = parport.lo @DUMMY_TRUE@am__objects_6 = dummy.lo @FT2232_DRIVER_TRUE@am__objects_7 = ft2232.lo @FTDI_DRIVER_TRUE@am__objects_8 = ftdi.lo mpsse.lo @USB_BLASTER_DRIVER_TRUE@am__objects_9 = usb_blaster.lo @AMTJTAGACCEL_TRUE@am__objects_10 = amt_jtagaccel.lo @EP93XX_TRUE@am__objects_11 = ep93xx.lo @AT91RM9200_TRUE@am__objects_12 = at91rm9200.lo @GW16012_TRUE@am__objects_13 = gw16012.lo @BITQ_TRUE@am__objects_14 = bitq.lo @PRESTO_DRIVER_TRUE@am__objects_15 = presto.lo @USBPROG_TRUE@am__objects_16 = usbprog.lo @JLINK_TRUE@am__objects_17 = jlink.lo @RLINK_TRUE@am__objects_18 = rlink.lo rlink_speed_table.lo @ULINK_TRUE@am__objects_19 = ulink.lo @VSLLINK_TRUE@am__objects_20 = usbtogpio.lo usbtojtagraw.lo \ @VSLLINK_TRUE@ usbtoswd.lo usbtopwr.lo usbtoxxx.lo versaloon.lo \ @VSLLINK_TRUE@ vsllink.lo @ARMJTAGEW_TRUE@am__objects_21 = arm-jtag-ew.lo @BUSPIRATE_TRUE@am__objects_22 = buspirate.lo @REMOTE_BITBANG_TRUE@am__objects_23 = remote_bitbang.lo @HLADAPTER_TRUE@am__objects_24 = stlink_usb.lo ti_icdi_usb.lo @OSBDM_TRUE@am__objects_25 = osbdm.lo @OPENDOUS_TRUE@am__objects_26 = opendous.lo @SYSFSGPIO_TRUE@am__objects_27 = sysfsgpio.lo am__objects_28 = driver.lo $(am__objects_1) $(am__objects_2) \ $(am__objects_3) $(am__objects_4) $(am__objects_5) \ $(am__objects_6) $(am__objects_7) $(am__objects_8) \ $(am__objects_9) $(am__objects_10) $(am__objects_11) \ $(am__objects_12) $(am__objects_13) $(am__objects_14) \ $(am__objects_15) $(am__objects_16) $(am__objects_17) \ $(am__objects_18) $(am__objects_19) $(am__objects_20) \ $(am__objects_21) $(am__objects_22) $(am__objects_23) \ $(am__objects_24) $(am__objects_25) $(am__objects_26) \ $(am__objects_27) am_libocdjtagdrivers_la_OBJECTS = $(am__objects_28) libocdjtagdrivers_la_OBJECTS = $(am_libocdjtagdrivers_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libocdjtagdrivers_la_SOURCES) DIST_SOURCES = $(am__libocdjtagdrivers_la_SOURCES_DIST) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__nobase_dist_ocddata_DATA_DIST = \ $(ULINK_FIRMWARE)/ulink_firmware.hex am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(ocddatadir)" DATA = $(nobase_dist_ocddata_DATA) HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CC_FOR_BUILD = @CC_FOR_BUILD@ CFLAGS = @CFLAGS@ CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@ FGREP = @FGREP@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ doxygen_as_html = @doxygen_as_html@ doxygen_as_pdf = @doxygen_as_pdf@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ # common flags used in openocd build AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src \ -I$(top_srcdir)/src/helper -DPKGDATADIR=\"$(pkgdatadir)\" \ -DPKGLIBDIR=\"$(pkglibdir)\" $(am__append_1) noinst_LTLIBRARIES = libocdjtagdrivers.la libocdjtagdrivers_la_SOURCES = \ $(DRIVERFILES) ocddatadir = $(pkglibdir) nobase_dist_ocddata_DATA = $(am__append_21) ULINK_FIRMWARE = $(srcdir)/OpenULINK EXTRA_DIST = $(ULINK_FIRMWARE) # Standard Driver: common files DRIVERFILES = driver.c $(am__append_2) $(am__append_3) $(am__append_4) \ $(am__append_5) $(am__append_6) $(am__append_7) \ $(am__append_8) $(am__append_9) $(am__append_10) \ $(am__append_11) $(am__append_12) $(am__append_13) \ $(am__append_14) $(am__append_15) $(am__append_16) \ $(am__append_17) $(am__append_18) $(am__append_19) \ $(am__append_20) $(am__append_22) $(am__append_23) \ $(am__append_24) $(am__append_25) $(am__append_26) \ $(am__append_27) $(am__append_28) $(am__append_29) noinst_HEADERS = \ bitbang.h \ bitq.h \ ftd2xx_common.h \ libusb0_common.h \ libusb1_common.h \ libusb_common.h \ minidriver_imp.h \ mpsse.h \ rlink.h \ rlink_dtc_cmd.h \ rlink_ep1_cmd.h \ rlink_st7.h \ usb_common.h \ versaloon/usbtoxxx/usbtoxxx.h \ versaloon/usbtoxxx/usbtoxxx_internal.h \ versaloon/versaloon.h \ versaloon/versaloon_include.h \ versaloon/versaloon_internal.h MAINTAINERCLEANFILES = $(srcdir)/Makefile.in all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/common.mk $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/jtag/drivers/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/jtag/drivers/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_srcdir)/common.mk: $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libocdjtagdrivers.la: $(libocdjtagdrivers_la_OBJECTS) $(libocdjtagdrivers_la_DEPENDENCIES) $(EXTRA_libocdjtagdrivers_la_DEPENDENCIES) $(AM_V_CCLD)$(LINK) $(libocdjtagdrivers_la_OBJECTS) $(libocdjtagdrivers_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/amt_jtagaccel.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm-jtag-ew.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/at91rm9200.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bitbang.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bitq.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/buspirate.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/driver.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dummy.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ep93xx.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ft2232.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ftdi.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gw16012.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jlink.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libusb0_common.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libusb1_common.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mpsse.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/opendous.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/osbdm.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parport.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/presto.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/remote_bitbang.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rlink.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rlink_speed_table.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stlink_usb.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sysfsgpio.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ti_icdi_usb.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ulink.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/usb_blaster.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/usb_common.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/usbprog.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/usbtogpio.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/usbtojtagraw.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/usbtopwr.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/usbtoswd.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/usbtoxxx.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/versaloon.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vsllink.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< usbtogpio.lo: versaloon/usbtoxxx/usbtogpio.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT usbtogpio.lo -MD -MP -MF $(DEPDIR)/usbtogpio.Tpo -c -o usbtogpio.lo `test -f 'versaloon/usbtoxxx/usbtogpio.c' || echo '$(srcdir)/'`versaloon/usbtoxxx/usbtogpio.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/usbtogpio.Tpo $(DEPDIR)/usbtogpio.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='versaloon/usbtoxxx/usbtogpio.c' object='usbtogpio.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o usbtogpio.lo `test -f 'versaloon/usbtoxxx/usbtogpio.c' || echo '$(srcdir)/'`versaloon/usbtoxxx/usbtogpio.c usbtojtagraw.lo: versaloon/usbtoxxx/usbtojtagraw.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT usbtojtagraw.lo -MD -MP -MF $(DEPDIR)/usbtojtagraw.Tpo -c -o usbtojtagraw.lo `test -f 'versaloon/usbtoxxx/usbtojtagraw.c' || echo '$(srcdir)/'`versaloon/usbtoxxx/usbtojtagraw.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/usbtojtagraw.Tpo $(DEPDIR)/usbtojtagraw.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='versaloon/usbtoxxx/usbtojtagraw.c' object='usbtojtagraw.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o usbtojtagraw.lo `test -f 'versaloon/usbtoxxx/usbtojtagraw.c' || echo '$(srcdir)/'`versaloon/usbtoxxx/usbtojtagraw.c usbtoswd.lo: versaloon/usbtoxxx/usbtoswd.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT usbtoswd.lo -MD -MP -MF $(DEPDIR)/usbtoswd.Tpo -c -o usbtoswd.lo `test -f 'versaloon/usbtoxxx/usbtoswd.c' || echo '$(srcdir)/'`versaloon/usbtoxxx/usbtoswd.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/usbtoswd.Tpo $(DEPDIR)/usbtoswd.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='versaloon/usbtoxxx/usbtoswd.c' object='usbtoswd.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o usbtoswd.lo `test -f 'versaloon/usbtoxxx/usbtoswd.c' || echo '$(srcdir)/'`versaloon/usbtoxxx/usbtoswd.c usbtopwr.lo: versaloon/usbtoxxx/usbtopwr.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT usbtopwr.lo -MD -MP -MF $(DEPDIR)/usbtopwr.Tpo -c -o usbtopwr.lo `test -f 'versaloon/usbtoxxx/usbtopwr.c' || echo '$(srcdir)/'`versaloon/usbtoxxx/usbtopwr.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/usbtopwr.Tpo $(DEPDIR)/usbtopwr.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='versaloon/usbtoxxx/usbtopwr.c' object='usbtopwr.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o usbtopwr.lo `test -f 'versaloon/usbtoxxx/usbtopwr.c' || echo '$(srcdir)/'`versaloon/usbtoxxx/usbtopwr.c usbtoxxx.lo: versaloon/usbtoxxx/usbtoxxx.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT usbtoxxx.lo -MD -MP -MF $(DEPDIR)/usbtoxxx.Tpo -c -o usbtoxxx.lo `test -f 'versaloon/usbtoxxx/usbtoxxx.c' || echo '$(srcdir)/'`versaloon/usbtoxxx/usbtoxxx.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/usbtoxxx.Tpo $(DEPDIR)/usbtoxxx.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='versaloon/usbtoxxx/usbtoxxx.c' object='usbtoxxx.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o usbtoxxx.lo `test -f 'versaloon/usbtoxxx/usbtoxxx.c' || echo '$(srcdir)/'`versaloon/usbtoxxx/usbtoxxx.c versaloon.lo: versaloon/versaloon.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT versaloon.lo -MD -MP -MF $(DEPDIR)/versaloon.Tpo -c -o versaloon.lo `test -f 'versaloon/versaloon.c' || echo '$(srcdir)/'`versaloon/versaloon.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/versaloon.Tpo $(DEPDIR)/versaloon.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='versaloon/versaloon.c' object='versaloon.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o versaloon.lo `test -f 'versaloon/versaloon.c' || echo '$(srcdir)/'`versaloon/versaloon.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-nobase_dist_ocddataDATA: $(nobase_dist_ocddata_DATA) @$(NORMAL_INSTALL) @list='$(nobase_dist_ocddata_DATA)'; test -n "$(ocddatadir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(ocddatadir)'"; \ $(MKDIR_P) "$(DESTDIR)$(ocddatadir)" || exit 1; \ fi; \ $(am__nobase_list) | while read dir files; do \ xfiles=; for file in $$files; do \ if test -f "$$file"; then xfiles="$$xfiles $$file"; \ else xfiles="$$xfiles $(srcdir)/$$file"; fi; done; \ test -z "$$xfiles" || { \ test "x$$dir" = x. || { \ echo " $(MKDIR_P) '$(DESTDIR)$(ocddatadir)/$$dir'"; \ $(MKDIR_P) "$(DESTDIR)$(ocddatadir)/$$dir"; }; \ echo " $(INSTALL_DATA) $$xfiles '$(DESTDIR)$(ocddatadir)/$$dir'"; \ $(INSTALL_DATA) $$xfiles "$(DESTDIR)$(ocddatadir)/$$dir" || exit $$?; }; \ done uninstall-nobase_dist_ocddataDATA: @$(NORMAL_UNINSTALL) @list='$(nobase_dist_ocddata_DATA)'; test -n "$(ocddatadir)" || list=; \ $(am__nobase_strip_setup); files=`$(am__nobase_strip)`; \ dir='$(DESTDIR)$(ocddatadir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(DATA) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(ocddatadir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-nobase_dist_ocddataDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-nobase_dist_ocddataDATA .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-nobase_dist_ocddataDATA \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \ uninstall-nobase_dist_ocddataDATA # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: openocd-0.7.0/src/jtag/drivers/opendous.c0000644000175000001440000005635312137151331015265 00000000000000/*************************************************************************** * * * Copyright (C) 2009 by Cahya Wirawan * * Based on opendous driver by Vladimir Fonov * * * * Copyright (C) 2009 by Vladimir Fonov * * Based on J-link driver by Juergen Stuber * * * * Copyright (C) 2007 by Juergen Stuber * * based on Dominic Rath's and Benedikt Sauter's usbprog.c * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "libusb_common.h" #include #include #include #define OPENDOUS_MAX_VIDS_PIDS 4 /* define some probes with similar interface */ struct opendous_probe { char *name; uint16_t VID[OPENDOUS_MAX_VIDS_PIDS]; uint16_t PID[OPENDOUS_MAX_VIDS_PIDS]; uint8_t READ_EP; uint8_t WRITE_EP; uint8_t CONTROL_TRANSFER; int BUFFERSIZE; }; static struct opendous_probe opendous_probes[] = { {"usbprog-jtag", {0x1781, 0}, {0x0C63, 0}, 0x82, 0x02, 0x00, 510 }, {"opendous", {0x1781, 0x03EB, 0}, {0xC0C0, 0x204F, 0}, 0x81, 0x02, 0x00, 360 }, {"usbvlab", {0x16C0, 0}, {0x05DC, 0}, 0x81, 0x02, 0x01, 360 }, {NULL, {0x0000}, {0x0000}, 0x00, 0x00, 0x00, 0 } }; #define OPENDOUS_WRITE_ENDPOINT (opendous_probe->WRITE_EP) #define OPENDOUS_READ_ENDPOINT (opendous_probe->READ_EP) static unsigned int opendous_hw_jtag_version = 1; #define OPENDOUS_USB_TIMEOUT 1000 #define OPENDOUS_USB_BUFFER_SIZE (opendous_probe->BUFFERSIZE) #define OPENDOUS_IN_BUFFER_SIZE (OPENDOUS_USB_BUFFER_SIZE) #define OPENDOUS_OUT_BUFFER_SIZE (OPENDOUS_USB_BUFFER_SIZE) /* Global USB buffers */ static uint8_t *usb_in_buffer; static uint8_t *usb_out_buffer; /* Constants for OPENDOUS command */ #define OPENDOUS_MAX_SPEED 66 #define OPENDOUS_MAX_TAP_TRANSMIT ((opendous_probe->BUFFERSIZE)-10) #define OPENDOUS_MAX_INPUT_DATA (OPENDOUS_MAX_TAP_TRANSMIT*4) /* TAP */ #define OPENDOUS_TAP_BUFFER_SIZE 65536 struct pending_scan_result { int first; /* First bit position in tdo_buffer to read */ int length; /* Number of bits to read */ struct scan_command *command; /* Corresponding scan command */ uint8_t *buffer; }; static int pending_scan_results_length; static struct pending_scan_result *pending_scan_results_buffer; #define MAX_PENDING_SCAN_RESULTS (OPENDOUS_MAX_INPUT_DATA) /* JTAG usb commands */ #define JTAG_CMD_TAP_OUTPUT 0x0 #define JTAG_CMD_SET_TRST 0x1 #define JTAG_CMD_SET_SRST 0x2 #define JTAG_CMD_READ_INPUT 0x3 #define JTAG_CMD_TAP_OUTPUT_EMU 0x4 #define JTAG_CMD_SET_DELAY 0x5 #define JTAG_CMD_SET_SRST_TRST 0x6 #define JTAG_CMD_READ_CONFIG 0x7 /* usbvlab control transfer */ #define FUNC_START_BOOTLOADER 30 #define FUNC_WRITE_DATA 0x50 #define FUNC_READ_DATA 0x51 static char *opendous_type; static struct opendous_probe *opendous_probe; /* External interface functions */ static int opendous_execute_queue(void); static int opendous_init(void); static int opendous_quit(void); /* Queue command functions */ static void opendous_end_state(tap_state_t state); static void opendous_state_move(void); static void opendous_path_move(int num_states, tap_state_t *path); static void opendous_runtest(int num_cycles); static void opendous_scan(int ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command); static void opendous_reset(int trst, int srst); static void opendous_simple_command(uint8_t command, uint8_t _data); static int opendous_get_status(void); /* opendous tap buffer functions */ static void opendous_tap_init(void); static int opendous_tap_execute(void); static void opendous_tap_ensure_space(int scans, int bits); static void opendous_tap_append_step(int tms, int tdi); static void opendous_tap_append_scan(int length, uint8_t *buffer, struct scan_command *command); /* opendous lowlevel functions */ struct opendous_jtag { struct jtag_libusb_device_handle *usb_handle; }; static struct opendous_jtag *opendous_usb_open(void); static void opendous_usb_close(struct opendous_jtag *opendous_jtag); static int opendous_usb_message(struct opendous_jtag *opendous_jtag, int out_length, int in_length); static int opendous_usb_write(struct opendous_jtag *opendous_jtag, int out_length); static int opendous_usb_read(struct opendous_jtag *opendous_jtag); /* helper functions */ int opendous_get_version_info(void); #ifdef _DEBUG_USB_COMMS_ char time_str[50]; static void opendous_debug_buffer(uint8_t *buffer, int length); char *opendous_get_time(char *); #endif static struct opendous_jtag *opendous_jtag_handle; /***************************************************************************/ /* External interface implementation */ COMMAND_HANDLER(opendous_handle_opendous_type_command) { if (CMD_ARGC == 0) return ERROR_OK; /* only if the cable name wasn't overwritten by cmdline */ if (opendous_type == NULL) { /* REVISIT first verify that it's listed in cables[] ... */ opendous_type = strdup(CMD_ARGV[0]); } /* REVISIT it's probably worth returning the current value ... */ return ERROR_OK; } COMMAND_HANDLER(opendous_handle_opendous_info_command) { if (opendous_get_version_info() == ERROR_OK) { /* attempt to get status */ opendous_get_status(); } return ERROR_OK; } COMMAND_HANDLER(opendous_handle_opendous_hw_jtag_command) { switch (CMD_ARGC) { case 0: command_print(CMD_CTX, "opendous hw jtag %i", opendous_hw_jtag_version); break; case 1: { int request_version = atoi(CMD_ARGV[0]); switch (request_version) { case 2: case 3: opendous_hw_jtag_version = request_version; break; default: return ERROR_COMMAND_SYNTAX_ERROR; } break; } default: return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; } static const struct command_registration opendous_command_handlers[] = { { .name = "opendous_info", .handler = &opendous_handle_opendous_info_command, .mode = COMMAND_EXEC, .help = "show opendous info", }, { .name = "opendous_hw_jtag", .handler = &opendous_handle_opendous_hw_jtag_command, .mode = COMMAND_EXEC, .help = "access opendous HW JTAG command version", .usage = "[2|3]", }, { .name = "opendous_type", .handler = &opendous_handle_opendous_type_command, .mode = COMMAND_CONFIG, .help = "set opendous type", .usage = "[usbvlab|usbprog-jtag|opendous]", }, COMMAND_REGISTRATION_DONE }; struct jtag_interface opendous_interface = { .name = "opendous", .commands = opendous_command_handlers, .execute_queue = opendous_execute_queue, .init = opendous_init, .quit = opendous_quit, }; static int opendous_execute_queue(void) { struct jtag_command *cmd = jtag_command_queue; int scan_size; enum scan_type type; uint8_t *buffer; while (cmd != NULL) { switch (cmd->type) { case JTAG_RUNTEST: DEBUG_JTAG_IO("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, \ cmd->cmd.runtest->end_state); if (cmd->cmd.runtest->end_state != -1) opendous_end_state(cmd->cmd.runtest->end_state); opendous_runtest(cmd->cmd.runtest->num_cycles); break; case JTAG_TLR_RESET: DEBUG_JTAG_IO("statemove end in %i", cmd->cmd.statemove->end_state); if (cmd->cmd.statemove->end_state != -1) opendous_end_state(cmd->cmd.statemove->end_state); opendous_state_move(); break; case JTAG_PATHMOVE: DEBUG_JTAG_IO("pathmove: %i states, end in %i", \ cmd->cmd.pathmove->num_states, \ cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); opendous_path_move(cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path); break; case JTAG_SCAN: DEBUG_JTAG_IO("scan end in %i", cmd->cmd.scan->end_state); if (cmd->cmd.scan->end_state != -1) opendous_end_state(cmd->cmd.scan->end_state); scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); DEBUG_JTAG_IO("scan input, length = %d", scan_size); #ifdef _DEBUG_USB_COMMS_ opendous_debug_buffer(buffer, (scan_size + 7) / 8); #endif type = jtag_scan_type(cmd->cmd.scan); opendous_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size, cmd->cmd.scan); break; case JTAG_RESET: DEBUG_JTAG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); opendous_tap_execute(); if (cmd->cmd.reset->trst == 1) tap_set_state(TAP_RESET); opendous_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); break; case JTAG_SLEEP: DEBUG_JTAG_IO("sleep %i", cmd->cmd.sleep->us); opendous_tap_execute(); jtag_sleep(cmd->cmd.sleep->us); break; default: LOG_ERROR("BUG: unknown JTAG command type encountered"); exit(-1); } cmd = cmd->next; } return opendous_tap_execute(); } static int opendous_init(void) { int check_cnt; struct opendous_probe *cur_opendous_probe; cur_opendous_probe = opendous_probes; if (opendous_type == NULL) { opendous_type = strdup("opendous"); LOG_WARNING("No opendous_type specified, using default 'opendous'"); } while (cur_opendous_probe->name) { if (strcmp(cur_opendous_probe->name, opendous_type) == 0) { opendous_probe = cur_opendous_probe; break; } cur_opendous_probe++; } if (!opendous_probe) { LOG_ERROR("No matching cable found for %s", opendous_type); return ERROR_JTAG_INIT_FAILED; } usb_in_buffer = malloc(opendous_probe->BUFFERSIZE); usb_out_buffer = malloc(opendous_probe->BUFFERSIZE); pending_scan_results_buffer = (struct pending_scan_result *) malloc(MAX_PENDING_SCAN_RESULTS * sizeof(struct pending_scan_result)); opendous_jtag_handle = opendous_usb_open(); if (opendous_jtag_handle == 0) { LOG_ERROR("Cannot find opendous Interface! Please check connection and permissions."); return ERROR_JTAG_INIT_FAILED; } check_cnt = 0; while (check_cnt < 3) { if (opendous_get_version_info() == ERROR_OK) { /* attempt to get status */ opendous_get_status(); break; } check_cnt++; } LOG_INFO("opendous JTAG Interface ready"); opendous_reset(0, 0); opendous_tap_init(); return ERROR_OK; } static int opendous_quit(void) { opendous_usb_close(opendous_jtag_handle); if (usb_out_buffer) { free(usb_out_buffer); usb_out_buffer = NULL; } if (usb_in_buffer) { free(usb_in_buffer); usb_in_buffer = NULL; } if (pending_scan_results_buffer) { free(pending_scan_results_buffer); pending_scan_results_buffer = NULL; } if (opendous_type) { free(opendous_type); opendous_type = NULL; } return ERROR_OK; } /***************************************************************************/ /* Queue command implementations */ void opendous_end_state(tap_state_t state) { if (tap_is_state_stable(state)) tap_set_end_state(state); else { LOG_ERROR("BUG: %i is not a valid end state", state); exit(-1); } } /* Goes to the end state. */ void opendous_state_move(void) { int i; int tms = 0; uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state()); uint8_t tms_scan_bits = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); for (i = 0; i < tms_scan_bits; i++) { tms = (tms_scan >> i) & 1; opendous_tap_append_step(tms, 0); } tap_set_state(tap_get_end_state()); } void opendous_path_move(int num_states, tap_state_t *path) { int i; for (i = 0; i < num_states; i++) { if (path[i] == tap_state_transition(tap_get_state(), false)) opendous_tap_append_step(0, 0); else if (path[i] == tap_state_transition(tap_get_state(), true)) opendous_tap_append_step(1, 0); else { LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_name(tap_get_state()), tap_state_name(path[i])); exit(-1); } tap_set_state(path[i]); } tap_set_end_state(tap_get_state()); } void opendous_runtest(int num_cycles) { int i; tap_state_t saved_end_state = tap_get_end_state(); /* only do a state_move when we're not already in IDLE */ if (tap_get_state() != TAP_IDLE) { opendous_end_state(TAP_IDLE); opendous_state_move(); } /* execute num_cycles */ for (i = 0; i < num_cycles; i++) opendous_tap_append_step(0, 0); /* finish in end_state */ opendous_end_state(saved_end_state); if (tap_get_state() != tap_get_end_state()) opendous_state_move(); } void opendous_scan(int ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command) { tap_state_t saved_end_state; opendous_tap_ensure_space(1, scan_size + 8); saved_end_state = tap_get_end_state(); /* Move to appropriate scan state */ opendous_end_state(ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT); if (tap_get_state() != tap_get_end_state()) opendous_state_move(); opendous_end_state(saved_end_state); /* Scan */ opendous_tap_append_scan(scan_size, buffer, command); /* We are in Exit1, go to Pause */ opendous_tap_append_step(0, 0); tap_set_state(ir_scan ? TAP_IRPAUSE : TAP_DRPAUSE); if (tap_get_state() != tap_get_end_state()) opendous_state_move(); } void opendous_reset(int trst, int srst) { LOG_DEBUG("trst: %i, srst: %i", trst, srst); /* Signals are active low */ #if 0 if (srst == 0) opendous_simple_command(JTAG_CMD_SET_SRST, 1); else if (srst == 1) opendous_simple_command(JTAG_CMD_SET_SRST, 0); if (trst == 0) opendous_simple_command(JTAG_CMD_SET_TRST, 1); else if (trst == 1) opendous_simple_command(JTAG_CMD_SET_TRST, 0); #endif srst = srst ? 0 : 1; trst = trst ? 0 : 2; opendous_simple_command(JTAG_CMD_SET_SRST_TRST, srst | trst); } void opendous_simple_command(uint8_t command, uint8_t _data) { int result; DEBUG_JTAG_IO("0x%02x 0x%02x", command, _data); usb_out_buffer[0] = 2; usb_out_buffer[1] = 0; usb_out_buffer[2] = command; usb_out_buffer[3] = _data; result = opendous_usb_message(opendous_jtag_handle, 4, 1); if (result != 1) LOG_ERROR("opendous command 0x%02x failed (%d)", command, result); } int opendous_get_status(void) { return ERROR_OK; } int opendous_get_version_info(void) { return ERROR_OK; } /***************************************************************************/ /* Estick tap functions */ static int tap_length; static uint8_t tms_buffer[OPENDOUS_TAP_BUFFER_SIZE]; static uint8_t tdo_buffer[OPENDOUS_TAP_BUFFER_SIZE]; static int last_tms; void opendous_tap_init(void) { tap_length = 0; pending_scan_results_length = 0; } void opendous_tap_ensure_space(int scans, int bits) { int available_scans = MAX_PENDING_SCAN_RESULTS - pending_scan_results_length; int available_bits = OPENDOUS_TAP_BUFFER_SIZE / 2 - tap_length; if ((scans > available_scans) || (bits > available_bits)) opendous_tap_execute(); } void opendous_tap_append_step(int tms, int tdi) { last_tms = tms; unsigned char _tms = tms ? 1 : 0; unsigned char _tdi = tdi ? 1 : 0; opendous_tap_ensure_space(0, 1); int tap_index = tap_length / 4; int bits = (tap_length % 4) * 2; if (tap_length < OPENDOUS_TAP_BUFFER_SIZE) { if (!bits) tms_buffer[tap_index] = 0; tms_buffer[tap_index] |= (_tdi << bits)|(_tms << (bits + 1)) ; tap_length++; } else LOG_ERROR("opendous_tap_append_step, overflow"); } void opendous_tap_append_scan(int length, uint8_t *buffer, struct scan_command *command) { DEBUG_JTAG_IO("append scan, length = %d", length); struct pending_scan_result *pending_scan_result = &pending_scan_results_buffer[pending_scan_results_length]; int i; pending_scan_result->first = tap_length; pending_scan_result->length = length; pending_scan_result->command = command; pending_scan_result->buffer = buffer; for (i = 0; i < length; i++) opendous_tap_append_step((i < length-1 ? 0 : 1), (buffer[i / 8] >> (i % 8)) & 1); pending_scan_results_length++; } /* Pad and send a tap sequence to the device, and receive the answer. * For the purpose of padding we assume that we are in idle or pause state. */ int opendous_tap_execute(void) { int byte_length; int i, j; int result; #ifdef _DEBUG_USB_COMMS_ int byte_length_out; #endif if (tap_length > 0) { /* memset(tdo_buffer,0,OPENDOUS_TAP_BUFFER_SIZE); */ /* LOG_INFO("OPENDOUS tap execute %d",tap_length); */ byte_length = (tap_length + 3) / 4; #ifdef _DEBUG_USB_COMMS_ byte_length_out = (tap_length + 7) / 8; LOG_DEBUG("opendous is sending %d bytes", byte_length); #endif for (j = 0, i = 0; j < byte_length;) { int receive; int transmit = byte_length - j; if (transmit > OPENDOUS_MAX_TAP_TRANSMIT) { transmit = OPENDOUS_MAX_TAP_TRANSMIT; receive = (OPENDOUS_MAX_TAP_TRANSMIT) / 2; usb_out_buffer[2] = JTAG_CMD_TAP_OUTPUT; } else { usb_out_buffer[2] = JTAG_CMD_TAP_OUTPUT | ((tap_length % 4) << 4); receive = (transmit + 1) / 2; } usb_out_buffer[0] = (transmit + 1) & 0xff; usb_out_buffer[1] = ((transmit + 1) >> 8) & 0xff; memmove(usb_out_buffer + 3, tms_buffer + j, transmit); result = opendous_usb_message(opendous_jtag_handle, 3 + transmit, receive); if (result != receive) { LOG_ERROR("opendous_tap_execute, wrong result %d, expected %d", result, receive); return ERROR_JTAG_QUEUE_FAILED; } memmove(tdo_buffer + i, usb_in_buffer, receive); i += receive; j += transmit; } #ifdef _DEBUG_USB_COMMS_ LOG_DEBUG("opendous tap result %d", byte_length_out); opendous_debug_buffer(tdo_buffer, byte_length_out); #endif /* LOG_INFO("eStick tap execute %d",tap_length); */ for (i = 0; i < pending_scan_results_length; i++) { struct pending_scan_result *pending_scan_result = &pending_scan_results_buffer[i]; uint8_t *buffer = pending_scan_result->buffer; int length = pending_scan_result->length; int first = pending_scan_result->first; struct scan_command *command = pending_scan_result->command; /* Copy to buffer */ buf_set_buf(tdo_buffer, first, buffer, 0, length); DEBUG_JTAG_IO("pending scan result, length = %d", length); #ifdef _DEBUG_USB_COMMS_ opendous_debug_buffer(buffer, byte_length_out); #endif if (jtag_read_buffer(buffer, command) != ERROR_OK) { opendous_tap_init(); return ERROR_JTAG_QUEUE_FAILED; } if (pending_scan_result->buffer != NULL) free(pending_scan_result->buffer); } opendous_tap_init(); } return ERROR_OK; } /*****************************************************************************/ /* Estick USB low-level functions */ struct opendous_jtag *opendous_usb_open(void) { struct opendous_jtag *result; struct jtag_libusb_device_handle *devh; if (jtag_libusb_open(opendous_probe->VID, opendous_probe->PID, &devh) != ERROR_OK) return NULL; jtag_libusb_set_configuration(devh, 0); jtag_libusb_claim_interface(devh, 0); result = (struct opendous_jtag *) malloc(sizeof(struct opendous_jtag)); result->usb_handle = devh; return result; } void opendous_usb_close(struct opendous_jtag *opendous_jtag) { jtag_libusb_close(opendous_jtag->usb_handle); free(opendous_jtag); } /* Send a message and receive the reply. */ int opendous_usb_message(struct opendous_jtag *opendous_jtag, int out_length, int in_length) { int result; result = opendous_usb_write(opendous_jtag, out_length); if (result == out_length) { result = opendous_usb_read(opendous_jtag); if (result == in_length) return result; else { LOG_ERROR("usb_bulk_read failed (requested=%d, result=%d)", in_length, result); return -1; } } else { LOG_ERROR("usb_bulk_write failed (requested=%d, result=%d)", out_length, result); return -1; } } /* Write data from out_buffer to USB. */ int opendous_usb_write(struct opendous_jtag *opendous_jtag, int out_length) { int result; if (out_length > OPENDOUS_OUT_BUFFER_SIZE) { LOG_ERROR("opendous_jtag_write illegal out_length=%d (max=%d)", out_length, OPENDOUS_OUT_BUFFER_SIZE); return -1; } #ifdef _DEBUG_USB_COMMS_ LOG_DEBUG("%s: USB write begin", opendous_get_time(time_str)); #endif if (opendous_probe->CONTROL_TRANSFER) { result = jtag_libusb_control_transfer(opendous_jtag->usb_handle, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT, FUNC_WRITE_DATA, 0, 0, (char *) usb_out_buffer, out_length, OPENDOUS_USB_TIMEOUT); } else { result = jtag_libusb_bulk_write(opendous_jtag->usb_handle, OPENDOUS_WRITE_ENDPOINT, \ (char *)usb_out_buffer, out_length, OPENDOUS_USB_TIMEOUT); } #ifdef _DEBUG_USB_COMMS_ LOG_DEBUG("%s: USB write end: %d bytes", opendous_get_time(time_str), result); #endif DEBUG_JTAG_IO("opendous_usb_write, out_length = %d, result = %d", out_length, result); #ifdef _DEBUG_USB_COMMS_ opendous_debug_buffer(usb_out_buffer, out_length); #endif return result; } /* Read data from USB into in_buffer. */ int opendous_usb_read(struct opendous_jtag *opendous_jtag) { #ifdef _DEBUG_USB_COMMS_ LOG_DEBUG("%s: USB read begin", opendous_get_time(time_str)); #endif int result; if (opendous_probe->CONTROL_TRANSFER) { result = jtag_libusb_control_transfer(opendous_jtag->usb_handle, LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN, FUNC_READ_DATA, 0, 0, (char *) usb_in_buffer, OPENDOUS_IN_BUFFER_SIZE, OPENDOUS_USB_TIMEOUT); } else { result = jtag_libusb_bulk_read(opendous_jtag->usb_handle, OPENDOUS_READ_ENDPOINT, (char *)usb_in_buffer, OPENDOUS_IN_BUFFER_SIZE, OPENDOUS_USB_TIMEOUT); } #ifdef _DEBUG_USB_COMMS_ LOG_DEBUG("%s: USB read end: %d bytes", opendous_get_time(time_str), result); #endif DEBUG_JTAG_IO("opendous_usb_read, result = %d", result); #ifdef _DEBUG_USB_COMMS_ opendous_debug_buffer(usb_in_buffer, result); #endif return result; } #ifdef _DEBUG_USB_COMMS_ #define BYTES_PER_LINE 16 void opendous_debug_buffer(uint8_t *buffer, int length) { char line[81]; char s[4]; int i; int j; for (i = 0; i < length; i += BYTES_PER_LINE) { snprintf(line, 5, "%04x", i); for (j = i; j < i + BYTES_PER_LINE && j < length; j++) { snprintf(s, 4, " %02x", buffer[j]); strcat(line, s); } LOG_DEBUG("%s", line); } } char *opendous_get_time(char *str) { struct timeb timebuffer; char *timeline; ftime(&timebuffer); timeline = ctime(&(timebuffer.time)); snprintf(str, 49, "%.8s.%hu", &timeline[11], timebuffer.millitm); return str; } #endif openocd-0.7.0/src/jtag/drivers/usb_blaster.c0000644000175000001440000004160512137151331015730 00000000000000/*************************************************************************** * Driver for USB-JTAG, Altera USB-Blaster and compatibles * * Original code from Kolja Waschk's USB-JTAG project * * (http://www.ixo.de/info/usb_jtag/). * * Some updates by Anthony Liu (2006). * * Minor updates and cleanup by Catalin Patulea (2009). * * Speed updates by Ali Lown (2011). * * * * Copyright (C) 2011 Ali Lown * * ali@lown.me.uk * * * * Copyright (C) 2009 Catalin Patulea * * cat@vv.carleton.ca * * * * Copyright (C) 2006 Kolja Waschk * * usbjtag@ixo.de * * * * Based on ft2232.c and bitbang.c, * * Copyright (C) 2004,2006 by Dominic Rath * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /* * The following information is originally from Kolja Waschk's USB-JTAG, * where it was obtained by reverse engineering an Altera USB-Blaster. * See http://www.ixo.de/info/usb_jtag/ for USB-Blaster block diagram and * usb_jtag-20080705-1200.zip#usb_jtag/host/openocd for protocol. * * The same information is also on the UrJTAG mediawiki, with some additional * notes on bits marked as "unknown" by usb_jtag. * (http://sourceforge.net/apps/mediawiki/urjtag/index.php? * title=Cable_Altera_USB-Blaster) * * USB-JTAG, Altera USB-Blaster and compatibles are typically implemented as * an FTDIChip FT245 followed by a CPLD which handles a two-mode protocol: * * _________ * | | * | AT93C46 | * |_________| * __|__________ _________ * | | | | * USB__| FTDI 245BM |__| EPM7064 |__JTAG (B_TDO,B_TDI,B_TMS,B_TCK) * |_____________| |_________| * __|__________ _|___________ * | | | | * | 6 MHz XTAL | | 24 MHz Osc. | * |_____________| |_____________| * * Protocol details are given in the code below. * * It is also possible to emulate this configuration using a single-chip USB * controller like the Cypress FX2 (again, see usb_jtag for details). */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #if IS_CYGWIN == 1 #include "windows.h" #undef LOG_ERROR #endif /* project specific includes */ #include #include #include /* system includes */ #include #include #include #include "bitbang.h" #if (BUILD_USB_BLASTER_FTD2XX == 1 && BUILD_USB_BLASTER_LIBFTDI == 1) #error "BUILD_USB_BLASTER_FTD2XX && BUILD_USB_BLASTER_LIBFTDI " "are mutually exclusive" #elif (BUILD_USB_BLASTER_FTD2XX != 1 && BUILD_USB_BLASTER_LIBFTDI != 1) #error "BUILD_USB_BLASTER_FTD2XX || BUILD_USB_BLASTER_LIBFTDI must be chosen" #endif /* USB_BLASTER access library includes */ #if BUILD_USB_BLASTER_FTD2XX == 1 #include #include "ftd2xx_common.h" #elif BUILD_USB_BLASTER_LIBFTDI == 1 #include #endif #include #include static char *usb_blaster_device_desc; static uint16_t usb_blaster_vid = 0x09fb; /* Altera */ static uint16_t usb_blaster_pid = 0x6001; /* USB-Blaster */ /* last output byte in simple bit banging (legacy) mode */ static uint8_t out_value; /* global output buffer for bit banging */ #define BUF_LEN 64 /* Size of EP1 */ static uint8_t out_buffer[BUF_LEN]; static uint16_t out_count; #if BUILD_USB_BLASTER_FTD2XX == 1 static FT_HANDLE ftdih; #elif BUILD_USB_BLASTER_LIBFTDI == 1 static struct ftdi_context ftdic; #endif static int usb_blaster_buf_write( uint8_t *buf, int size, uint32_t *bytes_written) { #if BUILD_USB_BLASTER_FTD2XX == 1 FT_STATUS status; DWORD dw_bytes_written; #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("usb_blaster_buf_write %02X (%d)", buf[0], size); #endif status = FT_Write(ftdih, buf, size, &dw_bytes_written); if (status != FT_OK) { *bytes_written = dw_bytes_written; LOG_ERROR("FT_Write returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } *bytes_written = dw_bytes_written; return ERROR_OK; #elif BUILD_USB_BLASTER_LIBFTDI == 1 int retval; #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("usb_blaster_buf_write %02X (%d)", buf[0], size); #endif retval = ftdi_write_data(&ftdic, buf, size); if (retval < 0) { *bytes_written = 0; LOG_ERROR("ftdi_write_data: %s", ftdi_get_error_string(&ftdic)); return ERROR_JTAG_DEVICE_ERROR; } *bytes_written = retval; return ERROR_OK; #endif } static int usb_blaster_buf_read(uint8_t *buf, unsigned size, uint32_t *bytes_read) { #if BUILD_USB_BLASTER_FTD2XX == 1 DWORD dw_bytes_read; FT_STATUS status; status = FT_Read(ftdih, buf, size, &dw_bytes_read); if (status != FT_OK) { *bytes_read = dw_bytes_read; LOG_ERROR("FT_Read returned: %s", ftd2xx_status_string(status)); return ERROR_JTAG_DEVICE_ERROR; } #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("usb_blaster_buf_read %02X (%" PRIu32 ")", buf[0], dw_bytes_read); #endif *bytes_read = dw_bytes_read; return ERROR_OK; #elif BUILD_USB_BLASTER_LIBFTDI == 1 int retval; int timeout = 100; *bytes_read = 0; while ((*bytes_read < size) && timeout--) { retval = ftdi_read_data(&ftdic, buf + *bytes_read, size - *bytes_read); if (retval < 0) { *bytes_read = 0; LOG_ERROR("ftdi_read_data: %s", ftdi_get_error_string(&ftdic)); return ERROR_JTAG_DEVICE_ERROR; } *bytes_read += retval; } #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("usb_blaster_buf_read %02X (%d)", buf[0], *bytes_read); #endif return ERROR_OK; #endif } /* The following code doesn't fully utilize the possibilities of the * USB-Blaster. It only buffers data up to the maximum packet size of 64 bytes. * * Actually, the USB-Blaster offers a byte-shift mode to transmit up to 504 data * bits (bidirectional) in a single USB packet. A header byte has to be sent as * the first byte in a packet with the following meaning: * * Bit 7 (0x80): Must be set to indicate byte-shift mode. * Bit 6 (0x40): If set, the USB-Blaster will also read data, not just write. * Bit 5..0: Define the number N of following bytes * * All N following bytes will then be clocked out serially on TDI. If Bit 6 was * set, it will afterwards return N bytes with TDO data read while clocking out * the TDI data. LSB of the first byte after the header byte will appear first * on TDI. */ /* Simple bit banging mode: * * Bit 7 (0x80): Must be zero (see byte-shift mode above) * Bit 6 (0x40): If set, you will receive a byte indicating the state of TDO * in return. * Bit 5 (0x20): Output Enable/LED. * Bit 4 (0x10): TDI Output. * Bit 3 (0x08): nCS Output (not used in JTAG mode). * Bit 2 (0x04): nCE Output (not used in JTAG mode). * Bit 1 (0x02): TMS Output. * Bit 0 (0x01): TCK Output. * * For transmitting a single data bit, you need to write two bytes. Up to 64 * bytes can be combined in a single USB packet. * It isn't possible to read a data without transmitting data. */ #define TCK (1 << 0) #define TMS (1 << 1) #define NCE (1 << 2) #define NCS (1 << 3) #define TDI (1 << 4) #define LED (1 << 5) #define READ (1 << 6) #define SHMODE (1 << 7) #define OTHERS ((1 << 2) | (1 << 3) | (1 << 5)) #define READ_TDO (1 << 0) static void usb_blaster_write_databuffer(uint8_t *buf, uint16_t len) { uint32_t bytes_written; usb_blaster_buf_write(buf, len, &bytes_written); out_count = 0; #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("---- WROTE %d", bytes_written); #endif } static void usb_blaster_addtowritebuffer(uint8_t value, bool forcewrite) { out_buffer[out_count] = value; out_count += 1; if (out_count == BUF_LEN || forcewrite) usb_blaster_write_databuffer(out_buffer, out_count); } static int usb_blaster_read_data(void) { int status; uint8_t buf[1]; uint32_t bytes_read; if (out_count > 0) usb_blaster_write_databuffer(out_buffer, out_count); out_value |= READ; usb_blaster_addtowritebuffer(out_value, true); out_value &= ~READ; status = usb_blaster_buf_read(buf, 1, &bytes_read); if (status < 0) return 0; return !!(buf[0] & READ_TDO); } static void usb_blaster_write(int tck, int tms, int tdi) { #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("---- usb_blaster_write(%d,%d,%d)", tck, tms, tdi); #endif out_value &= ~(TCK | TMS | TDI); if (tck) out_value |= TCK; if (tms) out_value |= TMS; if (tdi) out_value |= TDI; usb_blaster_addtowritebuffer(out_value, false); } static void usb_blaster_reset(int trst, int srst) { LOG_DEBUG("TODO: usb_blaster_reset(%d,%d) isn't implemented!", trst, srst); } static void usb_blaster_blink(int state) { out_value = 0x00; if (state) out_value |= LED; usb_blaster_addtowritebuffer(out_value, true); } static struct bitbang_interface usb_blaster_bitbang = { .read = usb_blaster_read_data, .write = usb_blaster_write, .reset = usb_blaster_reset, .blink = usb_blaster_blink, }; static int usb_blaster_init(void) { uint8_t latency_timer; #if BUILD_USB_BLASTER_FTD2XX == 1 FT_STATUS status; #endif #if BUILD_USB_BLASTER_FTD2XX == 1 LOG_DEBUG("'usb_blaster' interface using FTD2XX"); #elif BUILD_USB_BLASTER_LIBFTDI == 1 LOG_DEBUG("'usb_blaster' interface using libftdi"); #endif #if BUILD_USB_BLASTER_FTD2XX == 1 /* Open by device description */ if (usb_blaster_device_desc == NULL) { LOG_WARNING("no usb_blaster device description specified, " "using default 'USB-Blaster'"); usb_blaster_device_desc = strdup("USB-Blaster"); } #if IS_WIN32 == 0 /* Add non-standard Vid/Pid to the linux driver */ status = FT_SetVIDPID(usb_blaster_vid, usb_blaster_pid); if (status != FT_OK) { LOG_WARNING("couldn't add %4.4x:%4.4x", usb_blaster_vid, usb_blaster_pid); } #endif status = FT_OpenEx(usb_blaster_device_desc, FT_OPEN_BY_DESCRIPTION, &ftdih); if (status != FT_OK) { DWORD num_devices; LOG_ERROR("unable to open ftdi device: %s", ftd2xx_status_string(status)); status = FT_ListDevices(&num_devices, NULL, FT_LIST_NUMBER_ONLY); if (status == FT_OK) { char **desc_array = malloc(sizeof(char *) * (num_devices + 1)); unsigned int i; for (i = 0; i < num_devices; i++) desc_array[i] = malloc(64); desc_array[num_devices] = NULL; status = FT_ListDevices(desc_array, &num_devices, FT_LIST_ALL | FT_OPEN_BY_DESCRIPTION); if (status == FT_OK) { LOG_ERROR("ListDevices: %" PRIu32, (uint32_t)num_devices); for (i = 0; i < num_devices; i++) LOG_ERROR("%i: %s", i, desc_array[i]); } for (i = 0; i < num_devices; i++) free(desc_array[i]); free(desc_array); } else printf("ListDevices: NONE\n"); return ERROR_JTAG_INIT_FAILED; } status = FT_SetLatencyTimer(ftdih, 2); if (status != FT_OK) { LOG_ERROR("unable to set latency timer: %s", ftd2xx_status_string(status)); return ERROR_JTAG_INIT_FAILED; } status = FT_GetLatencyTimer(ftdih, &latency_timer); if (status != FT_OK) { LOG_ERROR("unable to get latency timer: %s", ftd2xx_status_string(status)); return ERROR_JTAG_INIT_FAILED; } LOG_DEBUG("current latency timer: %i", latency_timer); status = FT_SetBitMode(ftdih, 0x00, 0); if (status != FT_OK) { LOG_ERROR("unable to disable bit i/o mode: %s", ftd2xx_status_string(status)); return ERROR_JTAG_INIT_FAILED; } #elif BUILD_USB_BLASTER_LIBFTDI == 1 if (ftdi_init(&ftdic) < 0) return ERROR_JTAG_INIT_FAILED; /* context, vendor id, product id */ if (ftdi_usb_open(&ftdic, usb_blaster_vid, usb_blaster_pid) < 0) { LOG_ERROR("unable to open ftdi device: %s", ftdic.error_str); return ERROR_JTAG_INIT_FAILED; } if (ftdi_usb_reset(&ftdic) < 0) { LOG_ERROR("unable to reset ftdi device"); return ERROR_JTAG_INIT_FAILED; } if (ftdi_set_latency_timer(&ftdic, 2) < 0) { LOG_ERROR("unable to set latency timer"); return ERROR_JTAG_INIT_FAILED; } if (ftdi_get_latency_timer(&ftdic, &latency_timer) < 0) { LOG_ERROR("unable to get latency timer"); return ERROR_JTAG_INIT_FAILED; } LOG_DEBUG("current latency timer: %u", latency_timer); ftdi_disable_bitbang(&ftdic); #endif bitbang_interface = &usb_blaster_bitbang; #if 0 #if BUILD_USB_BLASTER_FTD2XX == 1 status = FT_Purge(ftdih, FT_PURGE_RX | FT_PURGE_TX); if (status != FT_OK) { LOG_ERROR("error purging ftd2xx device: %i", status); return ERROR_JTAG_INIT_FAILED; } #elif BUILD_USB_BLASTER_LIBFTDI == 1 if (ftdi_usb_purge_buffers(&ftdic) < 0) { LOG_ERROR("ftdi_purge_buffers: %s", ftdic.error_str); return ERROR_JTAG_INIT_FAILED; } #endif #endif return ERROR_OK; } static int usb_blaster_quit(void) { if (out_count > 0) usb_blaster_write_databuffer(out_buffer, out_count); #if BUILD_USB_BLASTER_FTD2XX == 1 FT_STATUS status; status = FT_Close(ftdih); #elif BUILD_USB_BLASTER_LIBFTDI == 1 ftdi_usb_close(&ftdic); ftdi_deinit(&ftdic); #endif if (usb_blaster_device_desc) { free(usb_blaster_device_desc); usb_blaster_device_desc = NULL; } return ERROR_OK; } COMMAND_HANDLER(usb_blaster_handle_device_desc_command) { if (CMD_ARGC == 1) usb_blaster_device_desc = strdup(CMD_ARGV[0]); else LOG_ERROR("require exactly one argument to " "usb_blaster_device_desc "); return ERROR_OK; } COMMAND_HANDLER(usb_blaster_handle_vid_pid_command) { if (CMD_ARGC > 2) { LOG_WARNING("ignoring extra IDs in usb_blaster_vid_pid " "(maximum is 1 pair)"); CMD_ARGC = 2; } if (CMD_ARGC == 2) { COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], usb_blaster_vid); COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], usb_blaster_pid); } else LOG_WARNING("incomplete usb_blaster_vid_pid configuration"); return ERROR_OK; } COMMAND_HANDLER(usb_blaster_handle_pin_command) { if (CMD_ARGC == 2) { const char *const pin_name = CMD_ARGV[0]; uint8_t mask; unsigned int state; if (!strcmp(pin_name, "pin6")) mask = NCE; else if (!strcmp(pin_name, "pin8")) mask = NCS; else { LOG_ERROR("%s: pin name must be \"pin6\" or \"pin8\"", CMD_NAME); return ERROR_COMMAND_SYNTAX_ERROR; } COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], state); if (state == 0) { out_value &= ~mask; usb_blaster_addtowritebuffer(out_value, true); } else if (state == 1) { out_value |= mask; usb_blaster_addtowritebuffer(out_value, true); } else { LOG_ERROR("%s: pin state must be 0 or 1", CMD_NAME); return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; } else { LOG_ERROR("%s takes exactly two arguments", CMD_NAME); return ERROR_COMMAND_SYNTAX_ERROR; } } static const struct command_registration usb_blaster_command_handlers[] = { { .name = "usb_blaster_device_desc", .handler = usb_blaster_handle_device_desc_command, .mode = COMMAND_CONFIG, .help = "set the USB device description of the USB-Blaster", .usage = "description-string", }, { .name = "usb_blaster_vid_pid", .handler = usb_blaster_handle_vid_pid_command, .mode = COMMAND_CONFIG, .help = "the vendor ID and product ID of the USB-Blaster", .usage = "vid pid", }, { .name = "usb_blaster", .handler = usb_blaster_handle_pin_command, .mode = COMMAND_ANY, .help = "set pin state for the unused GPIO pins", .usage = "(pin6|pin8) (0|1)", }, COMMAND_REGISTRATION_DONE }; struct jtag_interface usb_blaster_interface = { .name = "usb_blaster", .commands = usb_blaster_command_handlers, .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = bitbang_execute_queue, .init = usb_blaster_init, .quit = usb_blaster_quit, }; openocd-0.7.0/src/jtag/drivers/vsllink.c0000644000175000001440000005206712137151331015111 00000000000000/*************************************************************************** * Copyright (C) 2009-2010 by Simon Qian * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /* Versaloon is a programming tool for multiple MCUs. * It's distributed under GPLv3. * You can find it at http://www.Versaloon.com/. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "usb_common.h" #include "versaloon/versaloon_include.h" #include "versaloon/versaloon.h" static int vsllink_tms_offset; struct pending_scan_result { int src_offset; int dest_offset; int length; /* Number of bits to read */ struct scan_command *command; /* Corresponding scan command */ uint8_t *ack; uint8_t *buffer; bool last; /* indicate the last scan pending */ }; #define MAX_PENDING_SCAN_RESULTS 256 static int pending_scan_results_length; static struct pending_scan_result pending_scan_results_buffer[MAX_PENDING_SCAN_RESULTS]; /* Queue command functions */ static void vsllink_end_state(tap_state_t state); static void vsllink_state_move(void); static void vsllink_path_move(int num_states, tap_state_t *path); static void vsllink_tms(int num_bits, const uint8_t *bits); static void vsllink_runtest(int num_cycles); static void vsllink_stableclocks(int num_cycles, int tms); static void vsllink_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command); static void vsllink_reset(int trst, int srst); /* VSLLink tap buffer functions */ static void vsllink_tap_append_step(int tms, int tdi); static void vsllink_tap_init(void); static int vsllink_tap_execute(void); static void vsllink_tap_ensure_pending(int scans); static void vsllink_tap_append_scan(int length, uint8_t *buffer, struct scan_command *command); /* VSLLink lowlevel functions */ struct vsllink { struct usb_dev_handle *usb_handle; }; static struct vsllink *vsllink_usb_open(void); static void vsllink_usb_close(struct vsllink *vsllink); #if defined _DEBUG_JTAG_IO_ static void vsllink_debug_buffer(uint8_t *buffer, int length); #endif static int tap_length; static int tap_buffer_size; static uint8_t *tms_buffer; static uint8_t *tdi_buffer; static uint8_t *tdo_buffer; struct vsllink *vsllink_handle; static int vsllink_execute_queue(void) { struct jtag_command *cmd = jtag_command_queue; int scan_size; enum scan_type type; uint8_t *buffer; DEBUG_JTAG_IO("-------------------------------------" " vsllink " "-------------------------------------"); while (cmd != NULL) { switch (cmd->type) { case JTAG_RUNTEST: DEBUG_JTAG_IO("runtest %i cycles, end in %s", cmd->cmd.runtest->num_cycles, tap_state_name(cmd->cmd.runtest->end_state)); vsllink_end_state(cmd->cmd.runtest->end_state); vsllink_runtest(cmd->cmd.runtest->num_cycles); break; case JTAG_TLR_RESET: DEBUG_JTAG_IO("statemove end in %s", tap_state_name(cmd->cmd.statemove->end_state)); vsllink_end_state(cmd->cmd.statemove->end_state); vsllink_state_move(); break; case JTAG_PATHMOVE: DEBUG_JTAG_IO("pathmove: %i states, end in %s", cmd->cmd.pathmove->num_states, tap_state_name(cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1])); vsllink_path_move(cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path); break; case JTAG_SCAN: DEBUG_JTAG_IO("JTAG Scan..."); vsllink_end_state(cmd->cmd.scan->end_state); scan_size = jtag_build_buffer( cmd->cmd.scan, &buffer); if (cmd->cmd.scan->ir_scan) DEBUG_JTAG_IO( "JTAG Scan write IR(%d bits), " "end in %s:", scan_size, tap_state_name(cmd->cmd.scan->end_state)); else DEBUG_JTAG_IO( "JTAG Scan write DR(%d bits), " "end in %s:", scan_size, tap_state_name(cmd->cmd.scan->end_state)); #ifdef _DEBUG_JTAG_IO_ vsllink_debug_buffer(buffer, DIV_ROUND_UP(scan_size, 8)); #endif type = jtag_scan_type(cmd->cmd.scan); vsllink_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size, cmd->cmd.scan); break; case JTAG_RESET: DEBUG_JTAG_IO("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); vsllink_tap_execute(); if (cmd->cmd.reset->trst == 1) tap_set_state(TAP_RESET); vsllink_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); break; case JTAG_SLEEP: DEBUG_JTAG_IO("sleep %i", cmd->cmd.sleep->us); vsllink_tap_execute(); jtag_sleep(cmd->cmd.sleep->us); break; case JTAG_STABLECLOCKS: DEBUG_JTAG_IO("add %d clocks", cmd->cmd.stableclocks->num_cycles); switch (tap_get_state()) { case TAP_RESET: /* tms must be '1' to stay * n TAP_RESET mode */ scan_size = 1; break; case TAP_DRSHIFT: case TAP_IDLE: case TAP_DRPAUSE: case TAP_IRSHIFT: case TAP_IRPAUSE: /* else, tms should be '0' */ scan_size = 0; break; /* above stable states are OK */ default: LOG_ERROR("jtag_add_clocks() " "in non-stable state \"%s\"", tap_state_name(tap_get_state()) ); exit(-1); } vsllink_stableclocks(cmd->cmd.stableclocks->num_cycles, scan_size); break; case JTAG_TMS: DEBUG_JTAG_IO("add %d jtag tms", cmd->cmd.tms->num_bits); vsllink_tms(cmd->cmd.tms->num_bits, cmd->cmd.tms->bits); break; default: LOG_ERROR("BUG: unknown JTAG command type " "encountered: %d", cmd->type); exit(-1); } cmd = cmd->next; } return vsllink_tap_execute(); } static int vsllink_speed(int speed) { versaloon_interface.adaptors.jtag_raw.config(0, (uint16_t)speed); return versaloon_interface.adaptors.peripheral_commit(); } static int vsllink_khz(int khz, int *jtag_speed) { *jtag_speed = khz; return ERROR_OK; } static int vsllink_speed_div(int jtag_speed, int *khz) { *khz = jtag_speed; return ERROR_OK; } static void vsllink_free_buffer(void) { if (tdi_buffer != NULL) { free(tdi_buffer); tdi_buffer = NULL; } if (tdo_buffer != NULL) { free(tdo_buffer); tdo_buffer = NULL; } if (tms_buffer != NULL) { free(tms_buffer); tms_buffer = NULL; } } static int vsllink_quit(void) { versaloon_interface.adaptors.gpio.config(0, GPIO_SRST | GPIO_TRST, 0, 0, GPIO_SRST | GPIO_TRST); versaloon_interface.adaptors.gpio.fini(0); versaloon_interface.adaptors.jtag_raw.fini(0); versaloon_interface.adaptors.peripheral_commit(); versaloon_interface.fini(); vsllink_free_buffer(); vsllink_usb_close(vsllink_handle); return ERROR_OK; } static int vsllink_init(void) { vsllink_handle = vsllink_usb_open(); if (vsllink_handle == 0) { LOG_ERROR("Can't find USB JTAG Interface!" \ "Please check connection and permissions."); return ERROR_JTAG_INIT_FAILED; } LOG_DEBUG("vsllink found on %04X:%04X", versaloon_interface.usb_setting.vid, versaloon_interface.usb_setting.pid); versaloon_usb_device_handle = vsllink_handle->usb_handle; if (ERROR_OK != versaloon_interface.init()) return ERROR_FAIL; if (versaloon_interface.usb_setting.buf_size < 32) { versaloon_interface.fini(); return ERROR_FAIL; } /* malloc buffer size for tap */ tap_buffer_size = versaloon_interface.usb_setting.buf_size / 2 - 32; vsllink_free_buffer(); tdi_buffer = (uint8_t *)malloc(tap_buffer_size); tdo_buffer = (uint8_t *)malloc(tap_buffer_size); tms_buffer = (uint8_t *)malloc(tap_buffer_size); if ((NULL == tdi_buffer) || (NULL == tdo_buffer) || (NULL == tms_buffer)) { vsllink_quit(); return ERROR_FAIL; } versaloon_interface.adaptors.jtag_raw.init(0); versaloon_interface.adaptors.jtag_raw.config(0, jtag_get_speed_khz()); versaloon_interface.adaptors.gpio.init(0); versaloon_interface.adaptors.gpio.config(0, GPIO_SRST | GPIO_TRST, GPIO_TRST, GPIO_SRST, GPIO_SRST); if (ERROR_OK != versaloon_interface.adaptors.peripheral_commit()) return ERROR_FAIL; vsllink_reset(0, 0); vsllink_tap_init(); return ERROR_OK; } /************************************************************************** * Queue command implementations */ static void vsllink_end_state(tap_state_t state) { if (tap_is_state_stable(state)) tap_set_end_state(state); else { LOG_ERROR("BUG: %i is not a valid end state", state); exit(-1); } } /* Goes to the end state. */ static void vsllink_state_move(void) { int i; uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state()); uint8_t tms_scan_bits = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); for (i = 0; i < tms_scan_bits; i++) vsllink_tap_append_step((tms_scan >> i) & 1, 0); tap_set_state(tap_get_end_state()); } static void vsllink_path_move(int num_states, tap_state_t *path) { for (int i = 0; i < num_states; i++) { if (path[i] == tap_state_transition(tap_get_state(), false)) vsllink_tap_append_step(0, 0); else if (path[i] == tap_state_transition(tap_get_state(), true)) vsllink_tap_append_step(1, 0); else { LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_name(tap_get_state()), tap_state_name(path[i])); exit(-1); } tap_set_state(path[i]); } tap_set_end_state(tap_get_state()); } static void vsllink_tms(int num_bits, const uint8_t *bits) { for (int i = 0; i < num_bits; i++) vsllink_tap_append_step((bits[i / 8] >> (i % 8)) & 1, 0); } static void vsllink_stableclocks(int num_cycles, int tms) { while (num_cycles > 0) { vsllink_tap_append_step(tms, 0); num_cycles--; } } static void vsllink_runtest(int num_cycles) { tap_state_t saved_end_state = tap_get_end_state(); if (tap_get_state() != TAP_IDLE) { /* enter IDLE state */ vsllink_end_state(TAP_IDLE); vsllink_state_move(); } vsllink_stableclocks(num_cycles, 0); /* post-process */ /* set end_state */ vsllink_end_state(saved_end_state); if (tap_get_end_state() != tap_get_end_state()) vsllink_state_move(); } static void vsllink_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size, struct scan_command *command) { tap_state_t saved_end_state; saved_end_state = tap_get_end_state(); /* Move to appropriate scan state */ vsllink_end_state(ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT); if (tap_get_state() != tap_get_end_state()) vsllink_state_move(); vsllink_end_state(saved_end_state); /* Scan */ vsllink_tap_append_scan(scan_size, buffer, command); /* Goto Pause and record position to insert tms:0 */ vsllink_tap_append_step(0, 0); vsllink_tms_offset = tap_length; tap_set_state(ir_scan ? TAP_IRPAUSE : TAP_DRPAUSE); if (tap_get_state() != tap_get_end_state()) vsllink_state_move(); } static void vsllink_reset(int trst, int srst) { LOG_DEBUG("trst: %i, srst: %i", trst, srst); if (!srst) versaloon_interface.adaptors.gpio.config(0, GPIO_SRST, 0, GPIO_SRST, GPIO_SRST); else versaloon_interface.adaptors.gpio.config(0, GPIO_SRST, GPIO_SRST, 0, 0); if (!trst) versaloon_interface.adaptors.gpio.out(0, GPIO_TRST, GPIO_TRST); else versaloon_interface.adaptors.gpio.out(0, GPIO_TRST, 0); versaloon_interface.adaptors.peripheral_commit(); } COMMAND_HANDLER(vsllink_handle_usb_vid_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], versaloon_interface.usb_setting.vid); return ERROR_OK; } COMMAND_HANDLER(vsllink_handle_usb_pid_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], versaloon_interface.usb_setting.pid); return ERROR_OK; } COMMAND_HANDLER(vsllink_handle_usb_bulkin_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], versaloon_interface.usb_setting.ep_in); versaloon_interface.usb_setting.ep_in |= 0x80; return ERROR_OK; } COMMAND_HANDLER(vsllink_handle_usb_bulkout_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], versaloon_interface.usb_setting.ep_out); versaloon_interface.usb_setting.ep_out &= ~0x80; return ERROR_OK; } COMMAND_HANDLER(vsllink_handle_usb_interface_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], versaloon_interface.usb_setting.interface); return ERROR_OK; } /************************************************************************** * VSLLink tap functions */ static void vsllink_tap_init(void) { tap_length = 0; pending_scan_results_length = 0; vsllink_tms_offset = 0; } static void vsllink_tap_ensure_pending(int scans) { int available_scans = MAX_PENDING_SCAN_RESULTS - pending_scan_results_length; if (scans > available_scans) vsllink_tap_execute(); } static void vsllink_tap_append_step(int tms, int tdi) { int index_var = tap_length / 8; int bit_index = tap_length % 8; uint8_t bit = 1 << bit_index; if (tms) tms_buffer[index_var] |= bit; else tms_buffer[index_var] &= ~bit; if (tdi) tdi_buffer[index_var] |= bit; else tdi_buffer[index_var] &= ~bit; tap_length++; if (tap_buffer_size * 8 <= tap_length) vsllink_tap_execute(); } static void vsllink_tap_append_scan(int length, uint8_t *buffer, struct scan_command *command) { struct pending_scan_result *pending_scan_result; int len_tmp, len_all, i; len_all = 0; while (len_all < length) { vsllink_tap_ensure_pending(1); pending_scan_result = &pending_scan_results_buffer[ pending_scan_results_length]; if ((length - len_all) > (tap_buffer_size * 8 - tap_length)) { /* Use all memory available vsllink_tap_append_step will commit automatically */ len_tmp = tap_buffer_size * 8 - tap_length; pending_scan_result->last = false; } else { len_tmp = length - len_all; pending_scan_result->last = true; } pending_scan_result->src_offset = tap_length; pending_scan_result->dest_offset = len_all; pending_scan_result->length = len_tmp; pending_scan_result->command = command; pending_scan_result->buffer = buffer; pending_scan_results_length++; for (i = 0; i < len_tmp; i++) { vsllink_tap_append_step(((len_all + i) < length-1 ? 0 : 1), (buffer[(len_all + i)/8] >> ((len_all + i)%8)) & 1); } len_all += len_tmp; } } static int vsllink_jtag_execute(void) { int i; int result; if (tap_length <= 0) return ERROR_OK; versaloon_interface.adaptors.jtag_raw.execute(0, tdi_buffer, tms_buffer, tdo_buffer, tap_length); result = versaloon_interface.adaptors.peripheral_commit(); if (result == ERROR_OK) { for (i = 0; i < pending_scan_results_length; i++) { struct pending_scan_result *pending_scan_result = &pending_scan_results_buffer[i]; uint8_t *buffer = pending_scan_result->buffer; int length = pending_scan_result->length; int src_first = pending_scan_result->src_offset; int dest_first = pending_scan_result->dest_offset; bool last = pending_scan_result->last; struct scan_command *command; command = pending_scan_result->command; buf_set_buf(tdo_buffer, src_first, buffer, dest_first, length); #ifdef _DEBUG_JTAG_IO_ DEBUG_JTAG_IO( "JTAG scan read(%d bits, from src %d bits to dest %d bits):", length, src_first, dest_first); vsllink_debug_buffer(buffer + dest_first / 8, DIV_ROUND_UP(length, 7)); #endif if (last) { if (jtag_read_buffer(buffer, command) != ERROR_OK) { vsllink_tap_init(); return ERROR_JTAG_QUEUE_FAILED; } if (pending_scan_result->buffer != NULL) free(pending_scan_result->buffer); } } } else { LOG_ERROR("vsllink_jtag_execute failure"); return ERROR_JTAG_QUEUE_FAILED; } vsllink_tap_init(); return ERROR_OK; } static int vsllink_tap_execute(void) { return vsllink_jtag_execute(); } /**************************************************************************** * VSLLink USB low-level functions */ static uint8_t usb_check_string(usb_dev_handle *usb, uint8_t stringidx, char *string, char *buff, uint16_t buf_size) { int len; uint8_t alloced = 0; uint8_t ret = 1; if (NULL == buff) { buf_size = 256; buff = (char *)malloc(buf_size); if (NULL == buff) { ret = 0; goto free_and_return; } alloced = 1; } strcpy(buff, ""); len = usb_get_string_simple(usb, stringidx, (char *)buff, buf_size); if ((len < 0) || (len != ((int)strlen((const char *)buff)))) { ret = 0; goto free_and_return; } buff[len] = '\0'; if ((string != NULL) && strcmp((const char *)buff, string)) { ret = 0; goto free_and_return; } free_and_return: if (alloced && (buff != NULL)) { free(buff); buff = NULL; } return ret; } static usb_dev_handle *find_usb_device(uint16_t VID, uint16_t PID, uint8_t interface, int8_t serialindex, char *serialstring, int8_t productindex, char *productstring) { usb_dev_handle *dev_handle = NULL; struct usb_bus *busses; struct usb_bus *bus; struct usb_device *dev; usb_init(); usb_find_busses(); usb_find_devices(); busses = usb_get_busses(); for (bus = busses; bus; bus = bus->next) { for (dev = bus->devices; dev; dev = dev->next) { if ((dev->descriptor.idVendor == VID) && (dev->descriptor.idProduct == PID)) { dev_handle = usb_open(dev); if (NULL == dev_handle) { LOG_ERROR("failed to open %04X:%04X, %s", VID, PID, usb_strerror()); continue; } /* check description string */ if (((productstring != NULL) && (productindex >= 0) && !usb_check_string(dev_handle, productindex, productstring, NULL, 0)) || ((serialstring != NULL) && (serialindex >= 0) && !usb_check_string(dev_handle, serialindex, serialstring, NULL, 0))) { usb_close(dev_handle); dev_handle = NULL; continue; } if (usb_claim_interface(dev_handle, interface) != 0) { LOG_ERROR(ERRMSG_FAILURE_OPERATION_MESSAGE, "claim interface", usb_strerror()); usb_close(dev_handle); dev_handle = NULL; continue; } if (dev_handle != NULL) return dev_handle; } } } return dev_handle; } static struct vsllink *vsllink_usb_open(void) { usb_init(); struct usb_dev_handle *dev; dev = find_usb_device(versaloon_interface.usb_setting.vid, versaloon_interface.usb_setting.pid, versaloon_interface.usb_setting.interface, 0, NULL, 2, "Versaloon"); if (NULL == dev) return NULL; struct vsllink *result = malloc(sizeof(struct vsllink)); result->usb_handle = dev; return result; } static void vsllink_usb_close(struct vsllink *vsllink) { int ret; ret = usb_release_interface(vsllink->usb_handle, versaloon_interface.usb_setting.interface); if (ret != 0) { LOG_ERROR("fail to release interface %d, %d returned", versaloon_interface.usb_setting.interface, ret); exit(-1); } ret = usb_close(vsllink->usb_handle); if (ret != 0) { LOG_ERROR("fail to close usb, %d returned", ret); exit(-1); } free(vsllink); } #define BYTES_PER_LINE 16 #if defined _DEBUG_JTAG_IO_ static void vsllink_debug_buffer(uint8_t *buffer, int length) { char line[81]; char s[4]; int i; int j; for (i = 0; i < length; i += BYTES_PER_LINE) { snprintf(line, 5, "%04x", i); for (j = i; j < i + BYTES_PER_LINE && j < length; j++) { snprintf(s, 4, " %02x", buffer[j]); strcat(line, s); } LOG_DEBUG("%s", line); } } #endif /* _DEBUG_JTAG_IO_ */ static const struct command_registration vsllink_command_handlers[] = { { .name = "vsllink_usb_vid", .handler = &vsllink_handle_usb_vid_command, .mode = COMMAND_CONFIG, }, { .name = "vsllink_usb_pid", .handler = &vsllink_handle_usb_pid_command, .mode = COMMAND_CONFIG, }, { .name = "vsllink_usb_bulkin", .handler = &vsllink_handle_usb_bulkin_command, .mode = COMMAND_CONFIG, }, { .name = "vsllink_usb_bulkout", .handler = &vsllink_handle_usb_bulkout_command, .mode = COMMAND_CONFIG, }, { .name = "vsllink_usb_interface", .handler = &vsllink_handle_usb_interface_command, .mode = COMMAND_CONFIG, }, COMMAND_REGISTRATION_DONE }; static const char *vsllink_transports[] = {"jtag", "swd", NULL}; struct jtag_interface vsllink_interface = { .name = "vsllink", .supported = DEBUG_CAP_TMS_SEQ, .commands = vsllink_command_handlers, .transports = vsllink_transports, .init = vsllink_init, .quit = vsllink_quit, .khz = vsllink_khz, .speed = vsllink_speed, .speed_div = vsllink_speed_div, .execute_queue = vsllink_execute_queue, }; openocd-0.7.0/src/jtag/drivers/versaloon/0000755000175000001440000000000012141414412015336 500000000000000openocd-0.7.0/src/jtag/drivers/versaloon/usbtoxxx/0000755000175000001440000000000012141414412017242 500000000000000openocd-0.7.0/src/jtag/drivers/versaloon/usbtoxxx/usbtojtagraw.c0000644000175000001440000000541012134336410022045 00000000000000/*************************************************************************** * Copyright (C) 2009 - 2010 by Simon Qian * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "../versaloon_include.h" #include "../versaloon.h" #include "../versaloon_internal.h" #include "usbtoxxx.h" #include "usbtoxxx_internal.h" RESULT usbtojtagraw_init(uint8_t interface_index) { return usbtoxxx_init_command(USB_TO_JTAG_RAW, interface_index); } RESULT usbtojtagraw_fini(uint8_t interface_index) { return usbtoxxx_fini_command(USB_TO_JTAG_RAW, interface_index); } RESULT usbtojtagraw_config(uint8_t interface_index, uint32_t kHz) { uint8_t cfg_buf[4]; #if PARAM_CHECK if (interface_index > 7) { LOG_BUG(ERRMSG_INVALID_INTERFACE_NUM, interface_index); return ERROR_FAIL; } #endif SET_LE_U32(&cfg_buf[0], kHz); return usbtoxxx_conf_command(USB_TO_JTAG_RAW, interface_index, cfg_buf, 4); } RESULT usbtojtagraw_execute(uint8_t interface_index, uint8_t *tdi, uint8_t *tms, uint8_t *tdo, uint32_t bitlen) { uint16_t bytelen; #if PARAM_CHECK if (interface_index > 7) { LOG_BUG(ERRMSG_INVALID_INTERFACE_NUM, interface_index); return ERROR_FAIL; } #endif if (bitlen > 8 * 0xFFFF) return ERROR_FAIL; bytelen = (uint16_t)((bitlen + 7) >> 3); SET_LE_U32(&versaloon_cmd_buf[0], bitlen); memcpy(versaloon_cmd_buf + 4, tdi, bytelen); memcpy(versaloon_cmd_buf + 4 + bytelen, tms, bytelen); return usbtoxxx_inout_command(USB_TO_JTAG_RAW, interface_index, versaloon_cmd_buf, 4 + bytelen * 2, bytelen, tdo, 0, bytelen, 0); } openocd-0.7.0/src/jtag/drivers/versaloon/usbtoxxx/usbtoswd.c0000644000175000001440000001024512134336410021205 00000000000000/*************************************************************************** * Copyright (C) 2009 - 2010 by Simon Qian * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "../versaloon_include.h" #include "../versaloon.h" #include "../versaloon_internal.h" #include "usbtoxxx.h" #include "usbtoxxx_internal.h" RESULT usbtoswd_callback(void *p, uint8_t *src, uint8_t *processed) { struct versaloon_pending_t *pending = (struct versaloon_pending_t *)p; processed = processed; if (pending->extra_data != NULL) *((uint8_t *)pending->extra_data) = src[0]; return ERROR_OK; } RESULT usbtoswd_init(uint8_t interface_index) { return usbtoxxx_init_command(USB_TO_SWD, interface_index); } RESULT usbtoswd_fini(uint8_t interface_index) { return usbtoxxx_fini_command(USB_TO_SWD, interface_index); } RESULT usbtoswd_config(uint8_t interface_index, uint8_t trn, uint16_t retry, uint16_t dly) { uint8_t cfg_buf[5]; #if PARAM_CHECK if (interface_index > 7) { LOG_BUG(ERRMSG_INVALID_INTERFACE_NUM, interface_index); return ERROR_FAIL; } #endif cfg_buf[0] = trn; SET_LE_U16(&cfg_buf[1], retry); SET_LE_U16(&cfg_buf[3], dly); return usbtoxxx_conf_command(USB_TO_SWD, interface_index, cfg_buf, 5); } RESULT usbtoswd_seqout(uint8_t interface_index, uint8_t *data, uint16_t bitlen) { uint16_t bytelen = (bitlen + 7) >> 3; #if PARAM_CHECK if (interface_index > 7) { LOG_BUG(ERRMSG_INVALID_INTERFACE_NUM, interface_index); return ERROR_FAIL; } #endif SET_LE_U16(&versaloon_cmd_buf[0], bitlen); memcpy(versaloon_cmd_buf + 2, data, bytelen); return usbtoxxx_out_command(USB_TO_SWD, interface_index, versaloon_cmd_buf, bytelen + 2, 0); } RESULT usbtoswd_seqin(uint8_t interface_index, uint8_t *data, uint16_t bitlen) { uint16_t bytelen = (bitlen + 7) >> 3; uint8_t buff[2]; #if PARAM_CHECK if (interface_index > 7) { LOG_BUG(ERRMSG_INVALID_INTERFACE_NUM, interface_index); return ERROR_FAIL; } #endif SET_LE_U16(&buff[0], bitlen); return usbtoxxx_in_command(USB_TO_SWD, interface_index, buff, 2, bytelen, data, 0, bytelen, 0); } RESULT usbtoswd_transact(uint8_t interface_index, uint8_t request, uint32_t *data, uint8_t *ack) { uint8_t parity; uint8_t buff[5]; #if PARAM_CHECK if (interface_index > 7) { LOG_BUG(ERRMSG_INVALID_INTERFACE_NUM, interface_index); return ERROR_FAIL; } #endif parity = (request >> 1) & 1; parity += (request >> 2) & 1; parity += (request >> 3) & 1; parity += (request >> 4) & 1; parity &= 1; buff[0] = (request | 0x81 | (parity << 5)) & ~0x40; if (data != NULL) SET_LE_U32(&buff[1], *data); else memset(buff + 1, 0, 4); versaloon_set_extra_data(ack); versaloon_set_callback(usbtoswd_callback); if (request & 0x04) { /* read */ return usbtoxxx_inout_command(USB_TO_SWD, interface_index, buff, 5, 5, (uint8_t *)data, 1, 4, 0); } else { /* write */ return usbtoxxx_inout_command(USB_TO_SWD, interface_index, buff, 5, 5, NULL, 0, 0, 0); } } openocd-0.7.0/src/jtag/drivers/versaloon/usbtoxxx/usbtogpio.c0000644000175000001440000000602312134336410021345 00000000000000/*************************************************************************** * Copyright (C) 2009 - 2010 by Simon Qian * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "../versaloon_include.h" #include "../versaloon.h" #include "../versaloon_internal.h" #include "usbtoxxx.h" #include "usbtoxxx_internal.h" RESULT usbtogpio_init(uint8_t interface_index) { return usbtoxxx_init_command(USB_TO_GPIO, interface_index); } RESULT usbtogpio_fini(uint8_t interface_index) { return usbtoxxx_fini_command(USB_TO_GPIO, interface_index); } RESULT usbtogpio_config(uint8_t interface_index, uint32_t mask, uint32_t dir_mask, uint32_t pull_en_mask, uint32_t input_pull_mask) { uint8_t conf[8]; #if PARAM_CHECK if (interface_index > 7) { LOG_BUG(ERRMSG_INVALID_INTERFACE_NUM, interface_index); return ERROR_FAIL; } #endif dir_mask &= mask; SET_LE_U16(&conf[0], mask); SET_LE_U16(&conf[2], dir_mask); SET_LE_U16(&conf[4], pull_en_mask); SET_LE_U16(&conf[6], input_pull_mask); return usbtoxxx_conf_command(USB_TO_GPIO, interface_index, conf, sizeof(conf)); } RESULT usbtogpio_in(uint8_t interface_index, uint32_t mask, uint32_t *value) { uint8_t buf[2]; #if PARAM_CHECK if (interface_index > 7) { LOG_BUG(ERRMSG_INVALID_INTERFACE_NUM, interface_index); return ERROR_FAIL; } #endif SET_LE_U16(&buf[0], mask); return usbtoxxx_in_command(USB_TO_GPIO, interface_index, buf, 2, 2, (uint8_t *)value, 0, 2, 0); } RESULT usbtogpio_out(uint8_t interface_index, uint32_t mask, uint32_t value) { uint8_t buf[4]; #if PARAM_CHECK if (interface_index > 7) { LOG_BUG(ERRMSG_INVALID_INTERFACE_NUM, interface_index); return ERROR_FAIL; } #endif SET_LE_U16(&buf[0], mask); SET_LE_U16(&buf[2], value); return usbtoxxx_out_command(USB_TO_GPIO, interface_index, buf, 4, 0); } openocd-0.7.0/src/jtag/drivers/versaloon/usbtoxxx/usbtopwr.c0000644000175000001440000000450712134336410021224 00000000000000/*************************************************************************** * Copyright (C) 2009 - 2010 by Simon Qian * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "../versaloon_include.h" #include "../versaloon.h" #include "../versaloon_internal.h" #include "usbtoxxx.h" #include "usbtoxxx_internal.h" RESULT usbtopwr_init(uint8_t interface_index) { return usbtoxxx_init_command(USB_TO_POWER, interface_index); } RESULT usbtopwr_fini(uint8_t interface_index) { return usbtoxxx_fini_command(USB_TO_POWER, interface_index); } RESULT usbtopwr_config(uint8_t interface_index) { #if PARAM_CHECK if (interface_index > 7) { LOG_BUG(ERRMSG_INVALID_INTERFACE_NUM, interface_index); return ERROR_FAIL; } #endif return usbtoxxx_conf_command(USB_TO_POWER, interface_index, NULL, 0); } RESULT usbtopwr_output(uint8_t interface_index, uint16_t mV) { #if PARAM_CHECK if (interface_index > 7) { LOG_BUG(ERRMSG_INVALID_INTERFACE_NUM, interface_index); return ERROR_FAIL; } #endif return usbtoxxx_out_command(USB_TO_POWER, interface_index, (uint8_t *)&mV, 2, 0); } openocd-0.7.0/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx.h0000644000175000001440000002612412134336410021247 00000000000000/*************************************************************************** * Copyright (C) 2009 - 2010 by Simon Qian * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef __USBTOXXX_H_INCLUDED__ #define __USBTOXXX_H_INCLUDED__ RESULT usbtoxxx_init(void); RESULT usbtoxxx_fini(void); RESULT usbtoxxx_execute_command(void); #define USB_TO_XXX_ABILITIES_LEN 12 extern uint8_t usbtoxxx_abilities[USB_TO_XXX_ABILITIES_LEN]; bool usbtoxxx_interface_supported(uint8_t cmd); /* USB_TO_INFO */ RESULT usbtoinfo_get_abilities(uint8_t abilities[USB_TO_XXX_ABILITIES_LEN]); /* USB_TO_DELAY */ RESULT usbtodelay_delay(uint16_t dly); RESULT usbtodelay_delayms(uint16_t ms); RESULT usbtodelay_delayus(uint16_t us); /* USB_TO_USART */ RESULT usbtousart_init(uint8_t interface_index); RESULT usbtousart_fini(uint8_t interface_index); RESULT usbtousart_config(uint8_t interface_index, uint32_t baudrate, uint8_t datalength, uint8_t mode); RESULT usbtousart_send(uint8_t interface_index, uint8_t *buf, uint16_t len); RESULT usbtousart_receive(uint8_t interface_index, uint8_t *buf, uint16_t len); RESULT usbtousart_status(uint8_t interface_index, struct usart_status_t *status); /* USB_TO_SPI */ RESULT usbtospi_init(uint8_t interface_index); RESULT usbtospi_fini(uint8_t interface_index); RESULT usbtospi_config(uint8_t interface_index, uint32_t kHz, uint8_t mode); RESULT usbtospi_io(uint8_t interface_index, uint8_t *out, uint8_t *in, uint16_t bytelen); /* USB_TO_GPIO */ RESULT usbtogpio_init(uint8_t interface_index); RESULT usbtogpio_fini(uint8_t interface_index); RESULT usbtogpio_config(uint8_t interface_index, uint32_t mask, uint32_t dir_mask, uint32_t pull_en_mask, uint32_t input_pull_mask); RESULT usbtogpio_in(uint8_t interface_index, uint32_t mask, uint32_t *value); RESULT usbtogpio_out(uint8_t interface_index, uint32_t mask, uint32_t value); /* USB_TO_ISSP */ RESULT usbtoissp_init(uint8_t interface_index); RESULT usbtoissp_fini(uint8_t interface_index); RESULT usbtoissp_enter_program_mode(uint8_t interface_index, uint8_t mode); RESULT usbtoissp_leave_program_mode(uint8_t interface_index, uint8_t mode); RESULT usbtoissp_wait_and_poll(uint8_t interface_index); RESULT usbtoissp_vector(uint8_t interface_index, uint8_t operate, uint8_t addr, uint8_t data, uint8_t *buf); /* USB_TO_LPCICP */ RESULT usbtolpcicp_init(uint8_t interface_index); RESULT usbtolpcicp_fini(uint8_t interface_index); RESULT usbtolpcicp_config(uint8_t interface_index); RESULT usbtolpcicp_enter_program_mode(uint8_t interface_index); RESULT usbtolpcicp_in(uint8_t interface_index, uint8_t *buff, uint16_t len); RESULT usbtolpcicp_out(uint8_t interface_index, uint8_t *buff, uint16_t len); RESULT usbtolpcicp_poll_ready(uint8_t interface_index, uint8_t data, uint8_t *ret, uint8_t setmask, uint8_t clearmask, uint16_t pollcnt); /* USB_TO_JTAG_LL */ RESULT usbtojtagll_init(uint8_t interface_index); RESULT usbtojtagll_fini(uint8_t interface_index); RESULT usbtojtagll_config(uint8_t interface_index, uint32_t kHz); RESULT usbtojtagll_tms(uint8_t interface_index, uint8_t *tms, uint8_t bytelen); RESULT usbtojtagll_tms_clocks(uint8_t interface_index, uint32_t bytelen, uint8_t tms); RESULT usbtojtagll_scan(uint8_t interface_index, uint8_t *data, uint16_t bitlen, uint8_t tms_before_valid, uint8_t tms_before, uint8_t tms_after0, uint8_t tms_after1); /* USB_TO_JTAG_HL */ RESULT usbtojtaghl_init(uint8_t interface_index); RESULT usbtojtaghl_fini(uint8_t interface_index); RESULT usbtojtaghl_config(uint8_t interface_index, uint32_t kHz, uint8_t ub, uint8_t ua, uint16_t bb, uint16_t ba); RESULT usbtojtaghl_ir(uint8_t interface_index, uint8_t *ir, uint16_t bitlen, uint8_t idle, uint8_t want_ret); RESULT usbtojtaghl_dr(uint8_t interface_index, uint8_t *dr, uint16_t bitlen, uint8_t idle, uint8_t want_ret); RESULT usbtojtaghl_tms(uint8_t interface_index, uint8_t *tms, uint16_t bitlen); RESULT usbtojtaghl_runtest(uint8_t interface_index, uint32_t cycles); RESULT usbtojtaghl_register_callback(uint8_t index, jtag_callback_t send_callback, jtag_callback_t receive_callback); /* USB_TO_JTAG_RAW */ RESULT usbtojtagraw_init(uint8_t interface_index); RESULT usbtojtagraw_fini(uint8_t interface_index); RESULT usbtojtagraw_config(uint8_t interface_index, uint32_t kHz); RESULT usbtojtagraw_execute(uint8_t interface_index, uint8_t *tdi, uint8_t *tms, uint8_t *tdo, uint32_t bitlen); /* USB_TO_C2 */ RESULT usbtoc2_init(uint8_t interface_index); RESULT usbtoc2_fini(uint8_t interface_index); RESULT usbtoc2_writeaddr(uint8_t interface_index, uint8_t addr); RESULT usbtoc2_readaddr(uint8_t interface_index, uint8_t *data); RESULT usbtoc2_writedata(uint8_t interface_index, uint8_t *buf, uint8_t len); RESULT usbtoc2_readdata(uint8_t interface_index, uint8_t *buf, uint8_t len); /* USB_TO_I2C */ RESULT usbtoi2c_init(uint8_t interface_index); RESULT usbtoi2c_fini(uint8_t interface_index); RESULT usbtoi2c_config(uint8_t interface_index, uint16_t kHz, uint16_t byte_interval, uint16_t max_dly); RESULT usbtoi2c_read(uint8_t interface_index, uint16_t chip_addr, uint8_t *data, uint16_t data_len, uint8_t stop, bool nacklast); RESULT usbtoi2c_write(uint8_t interface_index, uint16_t chip_addr, uint8_t *data, uint16_t data_len, uint8_t stop); /* USB_TO_MSP430_JTAG */ RESULT usbtomsp430jtag_init(uint8_t interface_index); RESULT usbtomsp430jtag_fini(uint8_t interface_index); RESULT usbtomsp430jtag_config(uint8_t interface_index, uint8_t has_test); RESULT usbtomsp430jtag_ir(uint8_t interface_index, uint8_t *ir, uint8_t want_ret); RESULT usbtomsp430jtag_dr(uint8_t interface_index, uint32_t *dr, uint8_t bitlen, uint8_t want_ret); RESULT usbtomsp430jtag_tclk(uint8_t interface_index, uint8_t value); RESULT usbtomsp430jtag_tclk_strobe(uint8_t interface_index, uint16_t cnt); RESULT usbtomsp430jtag_reset(uint8_t interface_index); RESULT usbtomsp430jtag_poll(uint8_t interface_index, uint32_t dr, uint32_t mask, uint32_t value, uint8_t len, uint16_t poll_cnt, uint8_t toggle_tclk); /* USB_TO_MSP430_SBW */ RESULT usbtomsp430sbw_init(uint8_t interface_index); RESULT usbtomsp430sbw_fini(uint8_t interface_index); RESULT usbtomsp430sbw_config(uint8_t interface_index, uint8_t has_test); RESULT usbtomsp430sbw_ir(uint8_t interface_index, uint8_t *ir, uint8_t want_ret); RESULT usbtomsp430sbw_dr(uint8_t interface_index, uint32_t *dr, uint8_t bitlen, uint8_t want_ret); RESULT usbtomsp430sbw_tclk(uint8_t interface_index, uint8_t value); RESULT usbtomsp430sbw_tclk_strobe(uint8_t interface_index, uint16_t cnt); RESULT usbtomsp430sbw_reset(uint8_t interface_index); RESULT usbtomsp430sbw_poll(uint8_t interface_index, uint32_t dr, uint32_t mask, uint32_t value, uint8_t len, uint16_t poll_cnt, uint8_t toggle_tclk); /* USB_TO_POWER */ RESULT usbtopwr_init(uint8_t interface_index); RESULT usbtopwr_fini(uint8_t interface_index); RESULT usbtopwr_config(uint8_t interface_index); RESULT usbtopwr_output(uint8_t interface_index, uint16_t mV); /* USB_TO_POLL */ RESULT usbtopoll_start(uint16_t retry_cnt, uint16_t interval_us); RESULT usbtopoll_end(void); RESULT usbtopoll_checkok(uint8_t equ, uint16_t offset, uint8_t size, uint32_t mask, uint32_t value); RESULT usbtopoll_checkfail(uint8_t equ, uint16_t offset, uint8_t size, uint32_t mask, uint32_t value); RESULT usbtopoll_verifybuff(uint16_t offset, uint16_t size, uint8_t *buff); /* USB_TO_SWD */ RESULT usbtoswd_init(uint8_t interface_index); RESULT usbtoswd_fini(uint8_t interface_index); RESULT usbtoswd_config(uint8_t interface_index, uint8_t trn, uint16_t retry, uint16_t dly); RESULT usbtoswd_seqout(uint8_t interface_index, uint8_t *data, uint16_t bitlen); RESULT usbtoswd_seqin(uint8_t interface_index, uint8_t *data, uint16_t bitlen); RESULT usbtoswd_transact(uint8_t interface_index, uint8_t request, uint32_t *data, uint8_t *ack); /* USB_TO_SWIM */ RESULT usbtoswim_init(uint8_t interface_index); RESULT usbtoswim_fini(uint8_t interface_index); RESULT usbtoswim_config(uint8_t interface_index, uint8_t mHz, uint8_t cnt0, uint8_t cnt1); RESULT usbtoswim_srst(uint8_t interface_index); RESULT usbtoswim_wotf(uint8_t interface_index, uint8_t *data, uint16_t bytelen, uint32_t addr); RESULT usbtoswim_rotf(uint8_t interface_index, uint8_t *data, uint16_t bytelen, uint32_t addr); RESULT usbtoswim_sync(uint8_t interface_index, uint8_t mHz); RESULT usbtoswim_enable(uint8_t interface_index); /* USB_TO_BDM */ RESULT usbtobdm_init(uint8_t interface_index); RESULT usbtobdm_fini(uint8_t interface_index); RESULT usbtobdm_sync(uint8_t interface_index, uint16_t *khz); RESULT usbtobdm_transact(uint8_t interface_index, uint8_t *out, uint8_t outlen, uint8_t *in, uint8_t inlen, uint8_t delay, uint8_t ack); /* USB_TO_DUSI */ RESULT usbtodusi_init(uint8_t interface_index); RESULT usbtodusi_fini(uint8_t interface_index); RESULT usbtodusi_config(uint8_t interface_index, uint32_t kHz, uint8_t mode); RESULT usbtodusi_io(uint8_t interface_index, uint8_t *mo, uint8_t *mi, uint8_t *so, uint8_t *si, uint32_t bitlen); /* USB_TO_MICROWIRE */ RESULT usbtomicrowire_init(uint8_t interface_index); RESULT usbtomicrowire_fini(uint8_t interface_index); RESULT usbtomicrowire_config(uint8_t interface_index, uint16_t kHz, uint8_t sel_polarity); RESULT usbtomicrowire_transport(uint8_t interface_index, uint32_t opcode, uint8_t opcode_bitlen, uint32_t addr, uint8_t addr_bitlen, uint32_t data, uint8_t data_bitlen, uint8_t *reply, uint8_t reply_bitlen); RESULT usbtomicrowire_poll(uint8_t interface_index, uint16_t interval_us, uint16_t retry_cnt); /* USB_TO_PWM */ RESULT usbtopwm_init(uint8_t interface_index); RESULT usbtopwm_fini(uint8_t interface_index); RESULT usbtopwm_config(uint8_t interface_index, uint16_t kHz, uint8_t mode); RESULT usbtopwm_out(uint8_t interface_index, uint16_t count, uint16_t *rate); RESULT usbtopwm_in(uint8_t interface_index, uint16_t count, uint16_t *rate); #endif /* __USBTOXXX_H_INCLUDED__ */ openocd-0.7.0/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx.c0000644000175000001440000004071712134336410021246 00000000000000/*************************************************************************** * Copyright (C) 2009 - 2010 by Simon Qian * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "../versaloon_include.h" #include "../versaloon.h" #include "../versaloon_internal.h" #include "usbtoxxx.h" #include "usbtoxxx_internal.h" #define N_A "n/a" const char *types_name[96] = { "usbtousart", "usbtospi", "usbtoi2c", "usbtogpio", "usbtocan", "usbtopwm", "usbtoadc", "usbtodac", "usbtomicrowire", "usbtoswim", "usbtodusi", N_A, N_A, N_A, "usbtopower", "usbtodelay", N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, "usbtojtagll", "usbtojtaghl", "usbtoissp", "usbtoc2", "usbtosbw", "usbtolpcicp", "usbtoswd", "usbtojtagraw", "usbtobdm", N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, "usbtomsp430jtag", N_A, N_A, N_A, N_A, N_A, N_A, N_A, "usbtopower", "usbtodelay", "usbtopoll", N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, N_A, "usbtoall" }; uint8_t usbtoxxx_abilities[USB_TO_XXX_ABILITIES_LEN]; #define usbtoxxx_get_type_name(type) \ types_name[((type) - VERSALOON_USB_TO_XXX_CMD_START) \ % (sizeof(types_name) / sizeof(types_name[0]))] static uint8_t type_pre; static uint16_t usbtoxxx_buffer_index; static uint16_t usbtoxxx_current_cmd_index; static uint8_t *usbtoxxx_buffer; uint16_t collect_index; uint8_t collect_cmd; static uint8_t poll_nesting; struct usbtoxxx_context_t { uint8_t type_pre; uint8_t *usbtoxxx_buffer; uint16_t usbtoxxx_current_cmd_index; uint16_t usbtoxxx_buffer_index; uint16_t versaloon_pending_idx; }; static struct usbtoxxx_context_t poll_context; static void usbtoxxx_save_context(struct usbtoxxx_context_t *c) { c->type_pre = type_pre; c->usbtoxxx_buffer = usbtoxxx_buffer; c->usbtoxxx_buffer_index = usbtoxxx_buffer_index; c->usbtoxxx_current_cmd_index = usbtoxxx_current_cmd_index; c->versaloon_pending_idx = versaloon_pending_idx; } static void usbtoxxx_pop_context(struct usbtoxxx_context_t *c) { type_pre = c->type_pre; usbtoxxx_buffer = c->usbtoxxx_buffer; usbtoxxx_buffer_index = c->usbtoxxx_buffer_index; usbtoxxx_current_cmd_index = c->usbtoxxx_current_cmd_index; versaloon_pending_idx = c->versaloon_pending_idx; } RESULT usbtoxxx_validate_current_command_type(void) { if (type_pre > 0) { /* not the first command */ if (NULL == usbtoxxx_buffer) { LOG_BUG(ERRMSG_INVALID_BUFFER, TO_STR(usbtoxxx_buffer)); return ERRCODE_INVALID_BUFFER; } usbtoxxx_buffer[0] = type_pre; SET_LE_U16(&usbtoxxx_buffer[1], usbtoxxx_current_cmd_index); usbtoxxx_buffer_index += usbtoxxx_current_cmd_index; } else { /* first command */ usbtoxxx_buffer_index = 3; } /* prepare for next command */ usbtoxxx_current_cmd_index = 3; usbtoxxx_buffer = versaloon_buf + usbtoxxx_buffer_index; collect_index = 0; collect_cmd = 0; return ERROR_OK; } RESULT usbtoxxx_execute_command(void) { uint16_t i; uint16_t inlen; RESULT result = ERROR_OK; if (poll_nesting) { LOG_BUG(ERRMSG_INVALID_USAGE, "USB_TO_POLL"); versaloon_free_want_pos(); return ERROR_FAIL; } if (ERROR_OK != usbtoxxx_validate_current_command_type()) { LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands"); versaloon_free_want_pos(); return ERRCODE_FAILURE_OPERATION; } if (3 == usbtoxxx_buffer_index) { versaloon_free_want_pos(); return ERROR_OK; } versaloon_buf[0] = USB_TO_ALL; SET_LE_U16(&versaloon_buf[1], usbtoxxx_buffer_index); if (ERROR_OK != versaloon_send_command(usbtoxxx_buffer_index, &inlen)) { versaloon_free_want_pos(); return ERROR_FAIL; } /* process return data */ usbtoxxx_buffer_index = 0; for (i = 0; i < versaloon_pending_idx; i++) { /* check result */ if ((0 == i) || !((versaloon_pending[i].collect) && (versaloon_pending[i - 1].collect) && (versaloon_pending[i].cmd == versaloon_pending[i - 1].cmd))) { if (USB_TO_XXX_CMD_NOT_SUPPORT == versaloon_buf[usbtoxxx_buffer_index]) { LOG_ERROR(ERRMSG_NOT_SUPPORT_BY, usbtoxxx_get_type_name(versaloon_pending[i].type), "current dongle"); result = ERROR_FAIL; break; } else if (USB_TO_XXX_OK != versaloon_buf[usbtoxxx_buffer_index]) { LOG_ERROR("%s command 0x%02x failed with 0x%02x", usbtoxxx_get_type_name(versaloon_pending[i].type), versaloon_pending[i].cmd, versaloon_buf[usbtoxxx_buffer_index]); result = ERROR_FAIL; break; } usbtoxxx_buffer_index++; } /* get result data */ if (versaloon_pending[i].pos != NULL) { uint8_t processed = 0; if (versaloon_pending[i].callback != NULL) { versaloon_pending[i].callback(&versaloon_pending[i], versaloon_buf + usbtoxxx_buffer_index, &processed); } if (!processed) { struct versaloon_want_pos_t *tmp; tmp = versaloon_pending[i].pos; while (tmp != NULL) { if ((tmp->buff != NULL) && (tmp->size > 0)) { memcpy(tmp->buff, versaloon_buf + usbtoxxx_buffer_index + tmp->offset, tmp->size); } struct versaloon_want_pos_t *free_tmp; free_tmp = tmp; tmp = tmp->next; free(free_tmp); } versaloon_pending[i].pos = NULL; } } else if ((versaloon_pending[i].want_data_size > 0) && (versaloon_pending[i].data_buffer != NULL)) { uint8_t processed = 0; if (versaloon_pending[i].callback != NULL) { versaloon_pending[i].callback(&versaloon_pending[i], versaloon_buf + usbtoxxx_buffer_index, &processed); } if (!processed) { memcpy(versaloon_pending[i].data_buffer, versaloon_buf + usbtoxxx_buffer_index + versaloon_pending[i].want_data_pos, versaloon_pending[i].want_data_size); } } usbtoxxx_buffer_index += versaloon_pending[i].actual_data_size; if (usbtoxxx_buffer_index > inlen) { LOG_BUG("%s command 0x%02x process error", usbtoxxx_get_type_name(versaloon_pending[i].type), versaloon_pending[i].cmd); result = ERROR_FAIL; break; } } /* data is not the right size */ if (inlen != usbtoxxx_buffer_index) { LOG_ERROR(ERRMSG_INVALID_TARGET, "length of return data"); result = ERROR_FAIL; } if (versaloon_pending_idx > 0) versaloon_pending_idx = 0; else { /* no receive data, avoid collision */ sleep_ms(10); } type_pre = 0; collect_cmd = 0; collect_index = 0; versaloon_free_want_pos(); return result; } RESULT usbtoxxx_init(void) { versaloon_pending_idx = 0; if ((ERROR_OK != usbtoinfo_get_abilities(usbtoxxx_abilities)) || (ERROR_OK != usbtoxxx_execute_command())) return ERROR_FAIL; LOG_INFO("USB_TO_XXX abilities: 0x%08X:0x%08X:0x%08X", GET_LE_U32(&usbtoxxx_abilities[0]), GET_LE_U32(&usbtoxxx_abilities[4]), GET_LE_U32(&usbtoxxx_abilities[8])); return ERROR_OK; } RESULT usbtoxxx_fini(void) { usbtoxxx_buffer = NULL; type_pre = 0; return ERROR_OK; } bool usbtoxxx_interface_supported(uint8_t cmd) { if ((cmd < VERSALOON_USB_TO_XXX_CMD_START) || (cmd > VERSALOON_USB_TO_XXX_CMD_END)) return false; cmd -= VERSALOON_USB_TO_XXX_CMD_START; return (usbtoxxx_abilities[cmd / 8] & (1 << (cmd % 8))) > 0; } RESULT usbtoxxx_ensure_buffer_size(uint16_t cmdlen) { /* check free space, commit if not enough */ if (((usbtoxxx_buffer_index + usbtoxxx_current_cmd_index + cmdlen) >= versaloon_buf_size) || (versaloon_pending_idx >= VERSALOON_MAX_PENDING_NUMBER)) { struct usbtoxxx_context_t context_tmp; uint8_t poll_nesting_tmp = 0; memset(&context_tmp, 0, sizeof(context_tmp)); if (poll_nesting) { if (0 == poll_context.type_pre) { LOG_BUG("USB_TO_POLL toooooo long"); return ERROR_OK; } usbtoxxx_save_context(&context_tmp); usbtoxxx_pop_context(&poll_context); poll_nesting_tmp = poll_nesting; poll_nesting = 0; } if (usbtoxxx_execute_command() != ERROR_OK) return ERROR_FAIL; if (poll_nesting_tmp) { uint16_t newlen, oldlen; newlen = context_tmp.versaloon_pending_idx - poll_context.versaloon_pending_idx; memcpy(&versaloon_pending[0], &versaloon_pending[poll_context.versaloon_pending_idx], sizeof(versaloon_pending[0]) * newlen); context_tmp.versaloon_pending_idx = newlen; oldlen = poll_context.usbtoxxx_buffer_index + poll_context.usbtoxxx_current_cmd_index; newlen = context_tmp.usbtoxxx_buffer_index + context_tmp.usbtoxxx_current_cmd_index; memcpy(versaloon_buf + 3, versaloon_buf + oldlen, newlen - oldlen); oldlen -= 3; context_tmp.usbtoxxx_buffer -= oldlen; context_tmp.usbtoxxx_buffer_index -= oldlen; usbtoxxx_pop_context(&context_tmp); poll_nesting = poll_nesting_tmp; } } return ERROR_OK; } RESULT usbtoxxx_add_command(uint8_t type, uint8_t cmd, uint8_t *cmdbuf, uint16_t cmdlen, uint16_t retlen, uint8_t *wantbuf, uint16_t wantpos, uint16_t wantlen, uint8_t collect) { uint16_t len_tmp; /* 3 more bytes by usbtoxxx_validate_current_command_type */ /* 3 more bytes when ((0 == collect_index) || (collect_cmd != cmd)) */ if (ERROR_OK != usbtoxxx_ensure_buffer_size(cmdlen + 6)) return ERROR_FAIL; if ((type_pre != type) || (NULL == usbtoxxx_buffer)) { if (ERROR_OK != usbtoxxx_validate_current_command_type()) { LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands"); return ERRCODE_FAILURE_OPERATION; } type_pre = type; } if ((0 == collect_index) || (collect_cmd != cmd)) { usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = cmd; if (collect) { collect_index = usbtoxxx_current_cmd_index; collect_cmd = cmd; } else { collect_index = 0; collect_cmd = 0; } SET_LE_U16(&usbtoxxx_buffer[usbtoxxx_current_cmd_index], cmdlen); usbtoxxx_current_cmd_index += 2; } else { len_tmp = GET_LE_U16(&usbtoxxx_buffer[collect_index]) + cmdlen; SET_LE_U16(&usbtoxxx_buffer[collect_index], len_tmp); } if (cmdbuf != NULL) { memcpy(usbtoxxx_buffer + usbtoxxx_current_cmd_index, cmdbuf, cmdlen); usbtoxxx_current_cmd_index += cmdlen; } return versaloon_add_pending(type, cmd, retlen, wantpos, wantlen, wantbuf, collect); } RESULT usbtoinfo_get_abilities(uint8_t abilities[USB_TO_XXX_ABILITIES_LEN]) { if (ERROR_OK != usbtoxxx_ensure_buffer_size(3)) return ERROR_FAIL; if (ERROR_OK != usbtoxxx_validate_current_command_type()) { LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands"); return ERRCODE_FAILURE_OPERATION; } type_pre = USB_TO_INFO; return versaloon_add_pending(USB_TO_INFO, 0, USB_TO_XXX_ABILITIES_LEN, 0, USB_TO_XXX_ABILITIES_LEN, abilities, 0); } RESULT usbtopoll_start(uint16_t retry_cnt, uint16_t interval_us) { if (ERROR_OK != usbtoxxx_ensure_buffer_size(3 + 5)) return ERROR_FAIL; if (!poll_nesting) usbtoxxx_save_context(&poll_context); if (ERROR_OK != usbtoxxx_validate_current_command_type()) { LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands"); return ERRCODE_FAILURE_OPERATION; } poll_nesting++; type_pre = USB_TO_POLL; usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = USB_TO_POLL_START; SET_LE_U16(&usbtoxxx_buffer[usbtoxxx_current_cmd_index], retry_cnt); usbtoxxx_current_cmd_index += 2; SET_LE_U16(&usbtoxxx_buffer[usbtoxxx_current_cmd_index], interval_us); usbtoxxx_current_cmd_index += 2; return versaloon_add_pending(USB_TO_POLL, 0, 0, 0, 0, NULL, 0); } RESULT usbtopoll_end(void) { if (!poll_nesting) { LOG_BUG(ERRMSG_FAILURE_OPERATION, "check poll nesting"); return ERRCODE_FAILURE_OPERATION; } if (ERROR_OK != usbtoxxx_ensure_buffer_size(3 + 1)) return ERROR_FAIL; if (ERROR_OK != usbtoxxx_validate_current_command_type()) { LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands"); return ERRCODE_FAILURE_OPERATION; } poll_nesting--; type_pre = USB_TO_POLL; usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = USB_TO_POLL_END; return versaloon_add_pending(USB_TO_POLL, 0, 0, 0, 0, NULL, 0); } RESULT usbtopoll_checkok(uint8_t equ, uint16_t offset, uint8_t size, uint32_t mask, uint32_t value) { uint8_t i; if (size > 4) { LOG_BUG(ERRMSG_INVALID_PARAMETER, __func__); return ERRCODE_INVALID_PARAMETER; } if (!poll_nesting) { LOG_BUG(ERRMSG_FAILURE_OPERATION, "check poll nesting"); return ERRCODE_FAILURE_OPERATION; } if (ERROR_OK != usbtoxxx_ensure_buffer_size(3 + 4 + 2 * size)) return ERROR_FAIL; if (ERROR_OK != usbtoxxx_validate_current_command_type()) { LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands"); return ERRCODE_FAILURE_OPERATION; } type_pre = USB_TO_POLL; usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = USB_TO_POLL_CHECKOK; SET_LE_U16(&usbtoxxx_buffer[usbtoxxx_current_cmd_index], offset); usbtoxxx_current_cmd_index += 2; usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = size; usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = equ; for (i = 0; i < size; i++) usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = (mask >> (8 * i)) & 0xFF; for (i = 0; i < size; i++) usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = (value >> (8 * i)) & 0xFF; return ERROR_OK; } RESULT usbtopoll_checkfail(uint8_t equ, uint16_t offset, uint8_t size, uint32_t mask, uint32_t value) { uint8_t i; if (size > 4) { LOG_BUG(ERRMSG_INVALID_PARAMETER, __func__); return ERRCODE_INVALID_PARAMETER; } if (!poll_nesting) { LOG_BUG(ERRMSG_FAILURE_OPERATION, "check poll nesting"); return ERRCODE_FAILURE_OPERATION; } if (ERROR_OK != usbtoxxx_ensure_buffer_size(3 + 4 + 2 * size)) return ERROR_FAIL; if (ERROR_OK != usbtoxxx_validate_current_command_type()) { LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands"); return ERRCODE_FAILURE_OPERATION; } type_pre = USB_TO_POLL; usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = USB_TO_POLL_CHECKFAIL; SET_LE_U16(&usbtoxxx_buffer[usbtoxxx_current_cmd_index], offset); usbtoxxx_current_cmd_index += 2; usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = size; usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = equ; for (i = 0; i < size; i++) usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = (mask >> (8 * i)) & 0xFF; for (i = 0; i < size; i++) usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = (value >> (8 * i)) & 0xFF; return ERROR_OK; } RESULT usbtopoll_verifybuff(uint16_t offset, uint16_t size, uint8_t *buff) { if (!poll_nesting) { LOG_BUG(ERRMSG_FAILURE_OPERATION, "check poll nesting"); return ERRCODE_FAILURE_OPERATION; } if (ERROR_OK != usbtoxxx_ensure_buffer_size(3 + 5 + size)) return ERROR_FAIL; if (ERROR_OK != usbtoxxx_validate_current_command_type()) { LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands"); return ERRCODE_FAILURE_OPERATION; } type_pre = USB_TO_POLL; usbtoxxx_buffer[usbtoxxx_current_cmd_index++] = USB_TO_POLL_VERIFYBUFF; SET_LE_U16(&usbtoxxx_buffer[usbtoxxx_current_cmd_index], offset); usbtoxxx_current_cmd_index += 2; SET_LE_U16(&usbtoxxx_buffer[usbtoxxx_current_cmd_index], size); usbtoxxx_current_cmd_index += 2; memcpy(&usbtoxxx_buffer[usbtoxxx_current_cmd_index], buff, size); usbtoxxx_current_cmd_index += size; return ERROR_OK; } RESULT usbtodelay_delay(uint16_t dly) { if (ERROR_OK != usbtoxxx_ensure_buffer_size(3 + 2)) return ERROR_FAIL; if (ERROR_OK != usbtoxxx_validate_current_command_type()) { LOG_BUG(ERRMSG_FAILURE_OPERATION, "validate previous commands"); return ERRCODE_FAILURE_OPERATION; } type_pre = USB_TO_DELAY; SET_LE_U16(&usbtoxxx_buffer[usbtoxxx_current_cmd_index], dly); usbtoxxx_current_cmd_index += 2; return versaloon_add_pending(USB_TO_DELAY, 0, 0, 0, 0, NULL, 0); } RESULT usbtodelay_delayms(uint16_t ms) { return usbtodelay_delay(ms | 0x8000); } RESULT usbtodelay_delayus(uint16_t us) { return usbtodelay_delay(us & 0x7FFF); } openocd-0.7.0/src/jtag/drivers/versaloon/usbtoxxx/usbtoxxx_internal.h0000644000175000001440000002150212134336410023136 00000000000000/*************************************************************************** * Copyright (C) 2009 - 2010 by Simon Qian * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef __USBTOXXX_INTERNAL_H_INCLUDED__ #define __USBTOXXX_INTERNAL_H_INCLUDED__ /* USB_TO_XXX USB Commands */ /* Page0 */ #define USB_TO_USART (VERSALOON_USB_TO_XXX_CMD_START + 0x00) #define USB_TO_SPI (VERSALOON_USB_TO_XXX_CMD_START + 0x01) #define USB_TO_I2C (VERSALOON_USB_TO_XXX_CMD_START + 0x02) #define USB_TO_GPIO (VERSALOON_USB_TO_XXX_CMD_START + 0x03) #define USB_TO_CAN (VERSALOON_USB_TO_XXX_CMD_START + 0x04) #define USB_TO_PWM (VERSALOON_USB_TO_XXX_CMD_START + 0x05) #define USB_TO_ADC (VERSALOON_USB_TO_XXX_CMD_START + 0x06) #define USB_TO_DAC (VERSALOON_USB_TO_XXX_CMD_START + 0x07) #define USB_TO_MICROWIRE (VERSALOON_USB_TO_XXX_CMD_START + 0x08) #define USB_TO_SWIM (VERSALOON_USB_TO_XXX_CMD_START + 0x09) #define USB_TO_DUSI (VERSALOON_USB_TO_XXX_CMD_START + 0x0A) /* Page1 */ #define USB_TO_JTAG_LL (VERSALOON_USB_TO_XXX_CMD_START + 0x20) #define USB_TO_JTAG_HL (VERSALOON_USB_TO_XXX_CMD_START + 0x21) #define USB_TO_ISSP (VERSALOON_USB_TO_XXX_CMD_START + 0x22) #define USB_TO_C2 (VERSALOON_USB_TO_XXX_CMD_START + 0x23) #define USB_TO_SBW (VERSALOON_USB_TO_XXX_CMD_START + 0x24) #define USB_TO_LPCICP (VERSALOON_USB_TO_XXX_CMD_START + 0x25) #define USB_TO_SWD (VERSALOON_USB_TO_XXX_CMD_START + 0x26) #define USB_TO_JTAG_RAW (VERSALOON_USB_TO_XXX_CMD_START + 0x27) #define USB_TO_BDM (VERSALOON_USB_TO_XXX_CMD_START + 0x28) #define USB_TO_MSP430_JTAG (VERSALOON_USB_TO_XXX_CMD_START + 0x38) /* Page2 */ #define USB_TO_POWER (VERSALOON_USB_TO_XXX_CMD_START + 0x40) #define USB_TO_DELAY (VERSALOON_USB_TO_XXX_CMD_START + 0x41) #define USB_TO_POLL (VERSALOON_USB_TO_XXX_CMD_START + 0x42) #define USB_TO_INFO (VERSALOON_USB_TO_XXX_CMD_START + 0x5E) #define USB_TO_ALL (VERSALOON_USB_TO_XXX_CMD_START + 0x5F) /* USB_TO_XXX Masks */ #define USB_TO_XXX_CMDMASK 0xF8 #define USB_TO_XXX_CMDSHIFT 3 #define USB_TO_XXX_IDXMASK 0x07 /* USB_TO_XXX Sub Commands */ /* Common Sub Commands */ #define USB_TO_XXX_INIT (0x00 << USB_TO_XXX_CMDSHIFT) #define USB_TO_XXX_FINI (0x01 << USB_TO_XXX_CMDSHIFT) #define USB_TO_XXX_CONFIG (0x02 << USB_TO_XXX_CMDSHIFT) #define USB_TO_XXX_GETHWINFO (0x03 << USB_TO_XXX_CMDSHIFT) #define USB_TO_XXX_STATUS (0X04 << USB_TO_XXX_CMDSHIFT) #define USB_TO_XXX_IN_OUT (0x05 << USB_TO_XXX_CMDSHIFT) #define USB_TO_XXX_IN (0x06 << USB_TO_XXX_CMDSHIFT) #define USB_TO_XXX_OUT (0x07 << USB_TO_XXX_CMDSHIFT) #define USB_TO_XXX_POLL (0x08 << USB_TO_XXX_CMDSHIFT) #define USB_TO_XXX_SPECIAL (0x09 << USB_TO_XXX_CMDSHIFT) #define USB_TO_XXX_RESET (0x0A << USB_TO_XXX_CMDSHIFT) #define USB_TO_XXX_SYNC (0x0B << USB_TO_XXX_CMDSHIFT) #define USB_TO_XXX_ENABLE (0x0C << USB_TO_XXX_CMDSHIFT) #define USB_TO_XXX_DISABLE (0x0D << USB_TO_XXX_CMDSHIFT) /* USB_TO_POLL */ #define USB_TO_POLL_START 0x00 #define USB_TO_POLL_END 0x01 #define USB_TO_POLL_CHECKOK 0x02 #define USB_TO_POLL_CHECKFAIL 0x03 #define USB_TO_POLL_VERIFYBUFF 0x04 /* USB_TO_XXX Replys */ #define USB_TO_XXX_OK 0x00 #define USB_TO_XXX_FAILED 0x01 #define USB_TO_XXX_TIME_OUT 0x02 #define USB_TO_XXX_INVALID_INDEX 0x03 #define USB_TO_XXX_INVALID_PARA 0x04 #define USB_TO_XXX_INVALID_CMD 0x05 #define USB_TO_XXX_CMD_NOT_SUPPORT 0x06 /* USB_TO_XXX */ RESULT usbtoxxx_add_pending(uint8_t type, uint8_t cmd, uint16_t actual_szie, uint16_t want_pos, uint16_t want_size, uint8_t *buffer); RESULT usbtoxxx_add_command(uint8_t type, uint8_t cmd, uint8_t *cmdbuf, uint16_t cmdlen, uint16_t retlen, uint8_t *wantbuf, uint16_t wantpos, uint16_t wantlen, uint8_t collect); #define usbtoxxx_init_command(type, port) \ usbtoxxx_add_command((type), (USB_TO_XXX_INIT | (port)), \ NULL, 0, 0, NULL, 0, 0, 0) #define usbtoxxx_fini_command(type, port) \ usbtoxxx_add_command((type), (USB_TO_XXX_FINI | (port)), \ NULL, 0, 0, NULL, 0, 0, 0) #define usbtoxxx_conf_command(type, port, cmdbuf, cmdlen) \ usbtoxxx_add_command((type), (USB_TO_XXX_CONFIG | (port)), \ (cmdbuf), (cmdlen), 0, NULL, 0, 0, 0) #define usbtoxxx_inout_command(type, port, cmdbuf, cmdlen, retlen, wantbuf, \ wantpos, wantlen, c) \ usbtoxxx_add_command((type), (USB_TO_XXX_IN_OUT | (port)), \ (cmdbuf), (cmdlen), (retlen), (wantbuf), \ (wantpos), (wantlen), (c)) #define usbtoxxx_in_command(type, port, cmdbuf, cmdlen, retlen, wantbuf, \ wantpos, wantlen, c) \ usbtoxxx_add_command((type), (USB_TO_XXX_IN | (port)), (cmdbuf), \ (cmdlen), (retlen), (wantbuf), (wantpos), \ (wantlen), (c)) #define usbtoxxx_out_command(type, port, cmdbuf, cmdlen, c) \ usbtoxxx_add_command((type), (USB_TO_XXX_OUT | (port)), (cmdbuf), \ (cmdlen), 0, NULL, 0, 0, (c)) #define usbtoxxx_poll_command(type, port, cmdbuf, cmdlen, retbuf, retlen) \ usbtoxxx_add_command((type), (USB_TO_XXX_POLL | (port)), (cmdbuf), \ (cmdlen), (retlen), (retbuf), 0, (retlen), 0) #define usbtoxxx_status_command(type, port, retlen, wantbuf, wantpos, wantlen, c) \ usbtoxxx_add_command((type), (USB_TO_XXX_STATUS | (port)), \ NULL, 0, (retlen), (wantbuf), (wantpos), \ (wantlen), (c)) #define usbtoxxx_special_command(type, port, cmdbuf, cmdlen, retlen, wantbuf, \ wantpos, wantlen, c) \ usbtoxxx_add_command((type), (USB_TO_XXX_SPECIAL | (port)), \ (cmdbuf), (cmdlen), retlen, wantbuf, \ wantpos, wantlen, (c)) #define usbtoxxx_reset_command(type, port, cmdbuf, cmdlen) \ usbtoxxx_add_command((type), (USB_TO_XXX_RESET | (port)), \ (cmdbuf), (cmdlen), 0, NULL, 0, 0, 0) #define usbtoxxx_sync_command(type, port, cmdbuf, cmdlen, retlen, wantbuf) \ usbtoxxx_add_command((type), (USB_TO_XXX_SYNC | (port)), \ (cmdbuf), (cmdlen), (retlen), (wantbuf), 0, \ (retlen), 0) #define usbtoxxx_enable_command(type, port, cmdbuf, cmdlen) \ usbtoxxx_add_command((type), (USB_TO_XXX_ENABLE | (port)), \ (cmdbuf), (cmdlen), 0, NULL, 0, 0, 0) #define usbtoxxx_disable_command(type, port, cmdbuf, cmdlen) \ usbtoxxx_add_command((type), (USB_TO_XXX_DISABLE | (port)), \ (cmdbuf), (cmdlen), 0, NULL, 0, 0, 0) /* USB_TO_SPI */ #define USB_TO_SPI_BAUDRATE_MSK 0x1F #define USB_TO_SPI_CPOL_MSK 0x20 #define USB_TO_SPI_CPHA_MSK 0x40 #define USB_TO_SPI_MSB_FIRST 0x80 /* USB_TO_DUSI */ #define USB_TO_DUSI_BAUDRATE_MSK 0x1F #define USB_TO_DUSI_CPOL_MSK 0x20 #define USB_TO_DUSI_CPHA_MSK 0x40 #define USB_TO_DUSI_MSB_FIRST 0x80 /* USB_TO_GPIO */ #define USB_TO_GPIO_DIR_MSK 0x01 #endif /* __USBTOXXX_INTERNAL_H_INCLUDED__ */ openocd-0.7.0/src/jtag/drivers/versaloon/versaloon.c0000644000175000001440000002374312134336410017446 00000000000000/*************************************************************************** * Copyright (C) 2009 - 2010 by Simon Qian * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "versaloon_include.h" #include "versaloon.h" #include "versaloon_internal.h" #include "usbtoxxx/usbtoxxx.h" uint8_t *versaloon_buf; uint8_t *versaloon_cmd_buf; uint16_t versaloon_buf_size; struct versaloon_pending_t versaloon_pending[VERSALOON_MAX_PENDING_NUMBER]; uint16_t versaloon_pending_idx; usb_dev_handle *versaloon_usb_device_handle; static uint32_t versaloon_usb_to = VERSALOON_TIMEOUT; RESULT versaloon_init(void); RESULT versaloon_fini(void); RESULT versaloon_get_target_voltage(uint16_t *voltage); RESULT versaloon_set_target_voltage(uint16_t voltage); RESULT versaloon_delay_ms(uint16_t ms); RESULT versaloon_delay_us(uint16_t us); struct versaloon_interface_t versaloon_interface = { .init = versaloon_init, .fini = versaloon_fini, { /* adaptors */ { /* target_voltage */ .get = versaloon_get_target_voltage, .set = versaloon_set_target_voltage, }, { /* gpio */ .init = usbtogpio_init, .fini = usbtogpio_fini, .config = usbtogpio_config, .out = usbtogpio_out, .in = usbtogpio_in, }, { /* delay */ .delayms = versaloon_delay_ms, .delayus = versaloon_delay_us, }, { /* swd */ .init = usbtoswd_init, .fini = usbtoswd_fini, .config = usbtoswd_config, .seqout = usbtoswd_seqout, .seqin = usbtoswd_seqin, .transact = usbtoswd_transact, }, { /* jtag_raw */ .init = usbtojtagraw_init, .fini = usbtojtagraw_fini, .config = usbtojtagraw_config, .execute = usbtojtagraw_execute, }, .peripheral_commit = usbtoxxx_execute_command, }, { /* usb_setting */ .vid = VERSALOON_VID, .pid = VERSALOON_PID, .ep_out = VERSALOON_OUTP, .ep_in = VERSALOON_INP, .interface = VERSALOON_IFACE, .serialstring = NULL, .buf_size = 256, } }; /* programmer_cmd */ static uint32_t versaloon_pending_id; static versaloon_callback_t versaloon_callback; static void *versaloon_extra_data; static struct versaloon_want_pos_t *versaloon_want_pos; void versaloon_set_pending_id(uint32_t id) { versaloon_pending_id = id; } void versaloon_set_callback(versaloon_callback_t callback) { versaloon_callback = callback; } void versaloon_set_extra_data(void *p) { versaloon_extra_data = p; } void versaloon_free_want_pos(void) { uint16_t i; struct versaloon_want_pos_t *tmp, *free_tmp; tmp = versaloon_want_pos; while (tmp != NULL) { free_tmp = tmp; tmp = tmp->next; free(free_tmp); } versaloon_want_pos = NULL; for (i = 0; i < dimof(versaloon_pending); i++) { tmp = versaloon_pending[i].pos; while (tmp != NULL) { free_tmp = tmp; tmp = tmp->next; free(free_tmp); } versaloon_pending[i].pos = NULL; } } RESULT versaloon_add_want_pos(uint16_t offset, uint16_t size, uint8_t *buff) { struct versaloon_want_pos_t *new_pos = NULL; new_pos = (struct versaloon_want_pos_t *)malloc(sizeof(*new_pos)); if (NULL == new_pos) { LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY); return ERRCODE_NOT_ENOUGH_MEMORY; } new_pos->offset = offset; new_pos->size = size; new_pos->buff = buff; new_pos->next = NULL; if (NULL == versaloon_want_pos) versaloon_want_pos = new_pos; else { struct versaloon_want_pos_t *tmp = versaloon_want_pos; while (tmp->next != NULL) tmp = tmp->next; tmp->next = new_pos; } return ERROR_OK; } RESULT versaloon_add_pending(uint8_t type, uint8_t cmd, uint16_t actual_szie, uint16_t want_pos, uint16_t want_size, uint8_t *buffer, uint8_t collect) { #if PARAM_CHECK if (versaloon_pending_idx >= VERSALOON_MAX_PENDING_NUMBER) { LOG_BUG(ERRMSG_INVALID_INDEX, versaloon_pending_idx, "versaloon pending data"); return ERROR_FAIL; } #endif versaloon_pending[versaloon_pending_idx].type = type; versaloon_pending[versaloon_pending_idx].cmd = cmd; versaloon_pending[versaloon_pending_idx].actual_data_size = actual_szie; versaloon_pending[versaloon_pending_idx].want_data_pos = want_pos; versaloon_pending[versaloon_pending_idx].want_data_size = want_size; versaloon_pending[versaloon_pending_idx].data_buffer = buffer; versaloon_pending[versaloon_pending_idx].collect = collect; versaloon_pending[versaloon_pending_idx].id = versaloon_pending_id; versaloon_pending_id = 0; versaloon_pending[versaloon_pending_idx].extra_data = versaloon_extra_data; versaloon_extra_data = NULL; versaloon_pending[versaloon_pending_idx].callback = versaloon_callback; versaloon_callback = NULL; versaloon_pending[versaloon_pending_idx].pos = versaloon_want_pos; versaloon_want_pos = NULL; versaloon_pending_idx++; return ERROR_OK; } RESULT versaloon_send_command(uint16_t out_len, uint16_t *inlen) { int ret; #if PARAM_CHECK if (NULL == versaloon_buf) { LOG_BUG(ERRMSG_INVALID_BUFFER, TO_STR(versaloon_buf)); return ERRCODE_INVALID_BUFFER; } if ((0 == out_len) || (out_len > versaloon_interface.usb_setting.buf_size)) { LOG_BUG(ERRMSG_INVALID_PARAMETER, __func__); return ERRCODE_INVALID_PARAMETER; } #endif ret = usb_bulk_write(versaloon_usb_device_handle, versaloon_interface.usb_setting.ep_out, (char *)versaloon_buf, out_len, versaloon_usb_to); if (ret != out_len) { LOG_ERROR(ERRMSG_FAILURE_OPERATION_ERRSTRING, "send usb data", usb_strerror()); return ERRCODE_FAILURE_OPERATION; } if (inlen != NULL) { ret = usb_bulk_read(versaloon_usb_device_handle, versaloon_interface.usb_setting.ep_in, (char *)versaloon_buf, versaloon_interface.usb_setting.buf_size, versaloon_usb_to); if (ret > 0) { *inlen = (uint16_t)ret; return ERROR_OK; } else { LOG_ERROR(ERRMSG_FAILURE_OPERATION_ERRSTRING, "receive usb data", usb_strerror()); return ERROR_FAIL; } } else return ERROR_OK; } #define VERSALOON_RETRY_CNT 10 RESULT versaloon_init(void) { uint16_t ret = 0; uint8_t retry; uint32_t timeout_tmp; /* malloc temporary buffer */ versaloon_buf = (uint8_t *)malloc(versaloon_interface.usb_setting.buf_size); if (NULL == versaloon_buf) { LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY); return ERRCODE_NOT_ENOUGH_MEMORY; } /* connect to versaloon */ timeout_tmp = versaloon_usb_to; /* not output error message when connectting */ /* 100ms delay when connect */ versaloon_usb_to = 100; for (retry = 0; retry < VERSALOON_RETRY_CNT; retry++) { versaloon_buf[0] = VERSALOON_GET_INFO; if ((ERROR_OK == versaloon_send_command(1, &ret)) && (ret >= 3)) break; } versaloon_usb_to = timeout_tmp; if (VERSALOON_RETRY_CNT == retry) { versaloon_fini(); LOG_ERROR(ERRMSG_FAILURE_OPERATION, "communicate with versaloon"); return ERRCODE_FAILURE_OPERATION; } versaloon_buf[ret] = 0; versaloon_buf_size = versaloon_buf[0] + (versaloon_buf[1] << 8); versaloon_interface.usb_setting.buf_size = versaloon_buf_size; LOG_INFO("%s", versaloon_buf + 2); /* free temporary buffer */ free(versaloon_buf); versaloon_buf = NULL; versaloon_buf = (uint8_t *)malloc(versaloon_interface.usb_setting.buf_size); if (NULL == versaloon_buf) { versaloon_fini(); LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY); return ERRCODE_NOT_ENOUGH_MEMORY; } versaloon_cmd_buf = (uint8_t *)malloc(versaloon_interface.usb_setting.buf_size - 3); if (NULL == versaloon_cmd_buf) { versaloon_fini(); LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY); return ERRCODE_NOT_ENOUGH_MEMORY; } if (ERROR_OK != usbtoxxx_init()) { LOG_ERROR(ERRMSG_FAILURE_OPERATION, "initialize usbtoxxx"); return ERROR_FAIL; } return versaloon_get_target_voltage(&ret); } RESULT versaloon_fini(void) { if (versaloon_usb_device_handle != NULL) { usbtoxxx_fini(); versaloon_free_want_pos(); versaloon_usb_device_handle = NULL; if (versaloon_buf != NULL) { free(versaloon_buf); versaloon_buf = NULL; } if (versaloon_cmd_buf != NULL) { free(versaloon_cmd_buf); versaloon_cmd_buf = NULL; } } return ERROR_OK; } RESULT versaloon_set_target_voltage(uint16_t voltage) { usbtopwr_init(0); usbtopwr_config(0); usbtopwr_output(0, voltage); usbtopwr_fini(0); return usbtoxxx_execute_command(); } RESULT versaloon_get_target_voltage(uint16_t *voltage) { uint16_t inlen; #if PARAM_CHECK if (NULL == versaloon_buf) { LOG_BUG(ERRMSG_INVALID_BUFFER, TO_STR(versaloon_buf)); return ERRCODE_INVALID_BUFFER; } if (NULL == voltage) { LOG_BUG(ERRMSG_INVALID_PARAMETER, __func__); return ERRCODE_INVALID_PARAMETER; } #endif versaloon_buf[0] = VERSALOON_GET_TVCC; if ((ERROR_OK != versaloon_send_command(1, &inlen)) || (inlen != 2)) { LOG_ERROR(ERRMSG_FAILURE_OPERATION, "communicate with versaloon"); return ERRCODE_FAILURE_OPERATION; } else { *voltage = versaloon_buf[0] + (versaloon_buf[1] << 8); return ERROR_OK; } } RESULT versaloon_delay_ms(uint16_t ms) { return usbtodelay_delay(ms | 0x8000); } RESULT versaloon_delay_us(uint16_t us) { return usbtodelay_delay(us & 0x7FFF); } openocd-0.7.0/src/jtag/drivers/versaloon/versaloon_internal.h0000644000175000001440000001000212134336410021327 00000000000000/*************************************************************************** * Copyright (C) 2009 - 2010 by Simon Qian * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef __VERSALOON_INTERNAL_H_INCLUDED__ #define __VERSALOON_INTERNAL_H_INCLUDED__ #define VERSALOON_PRODUCTSTRING_INDEX 2 #define VERSALOON_SERIALSTRING_INDEX 3 #define VERSALOON_PRODUCTSTRING "Versaloon" #define VERSALOON_VID 0x0483 #define VERSALOON_PID 0xA038 #define VERSALOON_INP 0x82 #define VERSALOON_OUTP 0x03 #define VERSALOON_IFACE 0x00 #define VERSALOON_FULL 1 #define VERSALOON_MINI 2 #define VERSALOON_NANO 3 #define VERSALOON_TIMEOUT 5000 #define VERSALOON_TIMEOUT_LONG 60000 /* USB Commands */ /* Common Commands */ #define VERSALOON_COMMON_CMD_START 0x00 #define VERSALOON_COMMON_CMD_END 0x0F #define VERSALOON_GET_INFO 0x00 #define VERSALOON_GET_TVCC 0x01 #define VERSALOON_GET_HARDWARE 0x02 #define VERSALOON_GET_OFFLINE_SIZE 0x08 #define VERSALOON_ERASE_OFFLINE_DATA 0x09 #define VERSALOON_WRITE_OFFLINE_DATA 0x0A #define VERSALOON_GET_OFFLINE_CHECKSUM 0x0B #define VERSALOON_FW_UPDATE 0x0F #define VERSALOON_FW_UPDATE_KEY 0xAA /* MCU Command */ #define VERSALOON_MCU_CMD_START 0x10 #define VERSALOON_MCU_CMD_END 0x1F /* USB_TO_XXX Command */ #define VERSALOON_USB_TO_XXX_CMD_START 0x20 #define VERSALOON_USB_TO_XXX_CMD_END 0x7F /* VSLLink Command */ #define VERSALOON_VSLLINK_CMD_START 0x80 #define VERSALOON_VSLLINK_CMD_END 0xFF /* Mass-product */ #define MP_OK 0x00 #define MP_FAIL 0x01 #define MP_ISSP 0x11 /* pending struct */ #define VERSALOON_MAX_PENDING_NUMBER 4096 typedef RESULT(*versaloon_callback_t)(void *, uint8_t *, uint8_t *); struct versaloon_want_pos_t { uint16_t offset; uint16_t size; uint8_t *buff; struct versaloon_want_pos_t *next; }; struct versaloon_pending_t { uint8_t type; uint8_t cmd; uint16_t want_data_pos; uint16_t want_data_size; uint16_t actual_data_size; uint8_t *data_buffer; uint8_t collect; uint32_t id; struct versaloon_want_pos_t *pos; void *extra_data; versaloon_callback_t callback; }; extern struct versaloon_pending_t \ versaloon_pending[VERSALOON_MAX_PENDING_NUMBER]; extern uint16_t versaloon_pending_idx; void versaloon_set_pending_id(uint32_t id); void versaloon_set_callback(versaloon_callback_t callback); void versaloon_set_extra_data(void *p); RESULT versaloon_add_want_pos(uint16_t offset, uint16_t size, uint8_t *buff); RESULT versaloon_add_pending(uint8_t type, uint8_t cmd, uint16_t actual_szie, uint16_t want_pos, uint16_t want_size, uint8_t *buffer, uint8_t collect); void versaloon_free_want_pos(void); RESULT versaloon_send_command(uint16_t out_len, uint16_t *inlen); extern uint8_t *versaloon_buf; extern uint8_t *versaloon_cmd_buf; extern uint16_t versaloon_buf_size; #endif /* __VERSALOON_INTERNAL_H_INCLUDED__ */ openocd-0.7.0/src/jtag/drivers/versaloon/versaloon_include.h0000644000175000001440000001101512134336410021143 00000000000000/*************************************************************************** * Copyright (C) 2009 by Simon Qian * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /* This file is used to include different header and macros */ /* according to different platform */ #include #include #include "usb_common.h" #define PARAM_CHECK 1 #define sleep_ms(ms) jtag_sleep((ms) * 1000) #define dimof(arr) (sizeof(arr) / sizeof((arr)[0])) #define TO_STR(name) #name #define RESULT int #define LOG_BUG LOG_ERROR /* Common error messages */ #define ERRMSG_NOT_ENOUGH_MEMORY "Lack of memory." #define ERRCODE_NOT_ENOUGH_MEMORY ERROR_FAIL #define ERRMSG_INVALID_VALUE "%d is invalid for %s." #define ERRMSG_INVALID_INDEX "Index %d is invalid for %s." #define ERRMSG_INVALID_USAGE "Invalid usage of %s" #define ERRMSG_INVALID_TARGET "Invalid %s" #define ERRMSG_INVALID_PARAMETER "Invalid parameter of %s." #define ERRMSG_INVALID_INTERFACE_NUM "invalid inteface %d" #define ERRMSG_INVALID_BUFFER "Buffer %s is not valid." #define ERRCODE_INVALID_BUFFER ERROR_FAIL #define ERRCODE_INVALID_PARAMETER ERROR_FAIL #define ERRMSG_NOT_SUPPORT_BY "%s is not supported by %s." #define ERRMSG_FAILURE_OPERATION "Fail to %s." #define ERRMSG_FAILURE_OPERATION_ERRSTRING "Fail to %s, error string is %s." #define ERRMSG_FAILURE_OPERATION_MESSAGE "Fail to %s, %s" #define ERRCODE_FAILURE_OPERATION ERROR_FAIL #define GET_U16_MSBFIRST(p) (((*((uint8_t *)(p) + 0)) << 8) | \ ((*((uint8_t *)(p) + 1)) << 0)) #define GET_U32_MSBFIRST(p) (((*((uint8_t *)(p) + 0)) << 24) | \ ((*((uint8_t *)(p) + 1)) << 16) | \ ((*((uint8_t *)(p) + 2)) << 8) | \ ((*((uint8_t *)(p) + 3)) << 0)) #define GET_U16_LSBFIRST(p) (((*((uint8_t *)(p) + 0)) << 0) | \ ((*((uint8_t *)(p) + 1)) << 8)) #define GET_U32_LSBFIRST(p) (((*((uint8_t *)(p) + 0)) << 0) | \ ((*((uint8_t *)(p) + 1)) << 8) | \ ((*((uint8_t *)(p) + 2)) << 16) | \ ((*((uint8_t *)(p) + 3)) << 24)) #define SET_U16_MSBFIRST(p, v) \ do {\ *((uint8_t *)(p) + 0) = (((uint16_t)(v)) >> 8) & 0xFF;\ *((uint8_t *)(p) + 1) = (((uint16_t)(v)) >> 0) & 0xFF;\ } while (0) #define SET_U32_MSBFIRST(p, v) \ do {\ *((uint8_t *)(p) + 0) = (((uint32_t)(v)) >> 24) & 0xFF;\ *((uint8_t *)(p) + 1) = (((uint32_t)(v)) >> 16) & 0xFF;\ *((uint8_t *)(p) + 2) = (((uint32_t)(v)) >> 8) & 0xFF;\ *((uint8_t *)(p) + 3) = (((uint32_t)(v)) >> 0) & 0xFF;\ } while (0) #define SET_U16_LSBFIRST(p, v) \ do {\ *((uint8_t *)(p) + 0) = (((uint16_t)(v)) >> 0) & 0xFF;\ *((uint8_t *)(p) + 1) = (((uint16_t)(v)) >> 8) & 0xFF;\ } while (0) #define SET_U32_LSBFIRST(p, v) \ do {\ *((uint8_t *)(p) + 0) = (((uint32_t)(v)) >> 0) & 0xFF;\ *((uint8_t *)(p) + 1) = (((uint32_t)(v)) >> 8) & 0xFF;\ *((uint8_t *)(p) + 2) = (((uint32_t)(v)) >> 16) & 0xFF;\ *((uint8_t *)(p) + 3) = (((uint32_t)(v)) >> 24) & 0xFF;\ } while (0) #define GET_LE_U16(p) GET_U16_LSBFIRST(p) #define GET_LE_U32(p) GET_U32_LSBFIRST(p) #define GET_BE_U16(p) GET_U16_MSBFIRST(p) #define GET_BE_U32(p) GET_U32_MSBFIRST(p) #define SET_LE_U16(p, v) SET_U16_LSBFIRST(p, v) #define SET_LE_U32(p, v) SET_U32_LSBFIRST(p, v) #define SET_BE_U16(p, v) SET_U16_MSBFIRST(p, v) #define SET_BE_U32(p, v) SET_U32_MSBFIRST(p, v) openocd-0.7.0/src/jtag/drivers/versaloon/versaloon.h0000644000175000001440000000753512134336410017454 00000000000000/*************************************************************************** * Copyright (C) 2009 by Simon Qian * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef __VERSALOON_H_INCLUDED__ #define __VERSALOON_H_INCLUDED__ struct usart_status_t { uint32_t tx_buff_avail; uint32_t tx_buff_size; uint32_t rx_buff_avail; uint32_t rx_buff_size; }; #include "usbtoxxx/usbtoxxx.h" /* GPIO pins */ #define GPIO_SRST (1 << 0) #define GPIO_TRST (1 << 1) #define GPIO_USR1 (1 << 2) #define GPIO_USR2 (1 << 3) #define GPIO_TCK (1 << 4) #define GPIO_TDO (1 << 5) #define GPIO_TDI (1 << 6) #define GPIO_RTCK (1 << 7) #define GPIO_TMS (1 << 8) struct interface_gpio_t { RESULT(*init)(uint8_t interface_index); RESULT(*fini)(uint8_t interface_index); RESULT(*config)(uint8_t interface_index, uint32_t pin_mask, uint32_t io, uint32_t pull_en_mask, uint32_t input_pull_mask); RESULT(*out)(uint8_t interface_index, uint32_t pin_mask, uint32_t value); RESULT(*in)(uint8_t interface_index, uint32_t pin_mask, uint32_t *value); }; struct interface_delay_t { RESULT(*delayms)(uint16_t ms); RESULT(*delayus)(uint16_t us); }; struct interface_swd_t { RESULT(*init)(uint8_t interface_index); RESULT(*fini)(uint8_t interface_index); RESULT(*config)(uint8_t interface_index, uint8_t trn, uint16_t retry, uint16_t dly); RESULT(*seqout)(uint8_t interface_index, uint8_t *data, uint16_t bitlen); RESULT(*seqin)(uint8_t interface_index, uint8_t *data, uint16_t bitlen); RESULT(*transact)(uint8_t interface_index, uint8_t request, uint32_t *data, uint8_t *ack); }; struct interface_jtag_raw_t { RESULT(*init)(uint8_t interface_index); RESULT(*fini)(uint8_t interface_index); RESULT(*config)(uint8_t interface_index, uint32_t kHz); RESULT(*execute)(uint8_t interface_index, uint8_t *tdi, uint8_t *tms, uint8_t *tdo, uint32_t bitlen); }; struct interface_target_voltage_t { RESULT(*get)(uint16_t *voltage); RESULT(*set)(uint16_t voltage); }; struct versaloon_adaptors_t { struct interface_target_voltage_t target_voltage; struct interface_gpio_t gpio; struct interface_delay_t delay; struct interface_swd_t swd; struct interface_jtag_raw_t jtag_raw; RESULT(*peripheral_commit)(void); }; struct versaloon_usb_setting_t { uint16_t vid; uint16_t pid; uint8_t ep_out; uint8_t ep_in; uint8_t interface; char *serialstring; uint16_t buf_size; }; struct versaloon_interface_t { RESULT(*init)(void); RESULT(*fini)(void); struct versaloon_adaptors_t adaptors; struct versaloon_usb_setting_t usb_setting; }; extern struct versaloon_interface_t versaloon_interface; extern usb_dev_handle *versaloon_usb_device_handle; #endif /* __VERSALOON_H_INCLUDED__ */ openocd-0.7.0/src/jtag/drivers/ulink.c0000644000175000001440000020173712134336410014551 00000000000000/*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include "usb_common.h" #include "OpenULINK/include/msgtypes.h" /** USB Vendor ID of ULINK device in unconfigured state (no firmware loaded * yet) or with OpenULINK firmware. */ #define ULINK_VID 0xC251 /** USB Product ID of ULINK device in unconfigured state (no firmware loaded * yet) or with OpenULINK firmware. */ #define ULINK_PID 0x2710 /** Address of EZ-USB CPU Control & Status register. This register can be * written by issuing a Control EP0 vendor request. */ #define CPUCS_REG 0x7F92 /** USB Control EP0 bRequest: "Firmware Load". */ #define REQUEST_FIRMWARE_LOAD 0xA0 /** Value to write into CPUCS to put EZ-USB into reset. */ #define CPU_RESET 0x01 /** Value to write into CPUCS to put EZ-USB out of reset. */ #define CPU_START 0x00 /** Base address of firmware in EZ-USB code space. */ #define FIRMWARE_ADDR 0x0000 /** USB interface number */ #define USB_INTERFACE 0 /** libusb timeout in ms */ #define USB_TIMEOUT 5000 /** Delay (in microseconds) to wait while EZ-USB performs ReNumeration. */ #define ULINK_RENUMERATION_DELAY 1500000 /** Default location of OpenULINK firmware image. */ #define ULINK_FIRMWARE_FILE PKGLIBDIR "/OpenULINK/ulink_firmware.hex" /** Maximum size of a single firmware section. Entire EZ-USB code space = 8kB */ #define SECTION_BUFFERSIZE 8192 /** Tuning of OpenOCD SCAN commands split into multiple OpenULINK commands. */ #define SPLIT_SCAN_THRESHOLD 10 /** ULINK hardware type */ enum ulink_type { /** Original ULINK adapter, based on Cypress EZ-USB (AN2131): * Full JTAG support, no SWD support. */ ULINK_1, /** Newer ULINK adapter, based on NXP LPC2148. Currently unsupported. */ ULINK_2, /** Newer ULINK adapter, based on EZ-USB FX2 + FPGA. Currently unsupported. */ ULINK_PRO, /** Newer ULINK adapter, possibly based on ULINK 2. Currently unsupported. */ ULINK_ME }; enum ulink_payload_direction { PAYLOAD_DIRECTION_OUT, PAYLOAD_DIRECTION_IN }; enum ulink_delay_type { DELAY_CLOCK_TCK, DELAY_CLOCK_TMS, DELAY_SCAN_IN, DELAY_SCAN_OUT, DELAY_SCAN_IO }; /** * OpenULINK command (OpenULINK command queue element). * * For the OUT direction payload, things are quite easy: Payload is stored * in a rather small array (up to 63 bytes), the payload is always allocated * by the function generating the command and freed by ulink_clear_queue(). * * For the IN direction payload, things get a little bit more complicated: * The maximum IN payload size for a single command is 64 bytes. Assume that * a single OpenOCD command needs to scan 256 bytes. This results in the * generation of four OpenULINK commands. The function generating these * commands shall allocate an uint8_t[256] array. Each command's #payload_in * pointer shall point to the corresponding offset where IN data shall be * placed, while #payload_in_start shall point to the first element of the 256 * byte array. * - first command: #payload_in_start + 0 * - second command: #payload_in_start + 64 * - third command: #payload_in_start + 128 * - fourth command: #payload_in_start + 192 * * The last command sets #needs_postprocessing to true. */ struct ulink_cmd { uint8_t id; /* /< ULINK command ID */ uint8_t *payload_out; /* /< OUT direction payload data */ uint8_t payload_out_size; /* /< OUT direction payload size for this command */ uint8_t *payload_in_start; /* /< Pointer to first element of IN payload array */ uint8_t *payload_in; /* /< Pointer where IN payload shall be stored */ uint8_t payload_in_size;/* /< IN direction payload size for this command */ /** Indicates if this command needs post-processing */ bool needs_postprocessing; /** Indicates if ulink_clear_queue() should free payload_in_start */ bool free_payload_in_start; /** Pointer to corresponding OpenOCD command for post-processing */ struct jtag_command *cmd_origin; struct ulink_cmd *next; /* /< Pointer to next command (linked list) */ }; /** Describes one driver instance */ struct ulink { struct usb_dev_handle *usb_handle; enum ulink_type type; int delay_scan_in; /* /< Delay value for SCAN_IN commands */ int delay_scan_out; /* /< Delay value for SCAN_OUT commands */ int delay_scan_io; /* /< Delay value for SCAN_IO commands */ int delay_clock_tck; /* /< Delay value for CLOCK_TMS commands */ int delay_clock_tms; /* /< Delay value for CLOCK_TCK commands */ int commands_in_queue; /* /< Number of commands in queue */ struct ulink_cmd *queue_start; /* /< Pointer to first command in queue */ struct ulink_cmd *queue_end; /* /< Pointer to last command in queue */ }; /**************************** Function Prototypes *****************************/ /* USB helper functions */ int ulink_usb_open(struct ulink **device); int ulink_usb_close(struct ulink **device); /* ULINK MCU (Cypress EZ-USB) specific functions */ int ulink_cpu_reset(struct ulink *device, char reset_bit); int ulink_load_firmware_and_renumerate(struct ulink **device, char *filename, uint32_t delay); int ulink_load_firmware(struct ulink *device, char *filename); int ulink_write_firmware_section(struct ulink *device, struct image *firmware_image, int section_index); /* Generic helper functions */ void ulink_print_signal_states(uint8_t input_signals, uint8_t output_signals); /* OpenULINK command generation helper functions */ int ulink_allocate_payload(struct ulink_cmd *ulink_cmd, int size, enum ulink_payload_direction direction); /* OpenULINK command queue helper functions */ int ulink_get_queue_size(struct ulink *device, enum ulink_payload_direction direction); void ulink_clear_queue(struct ulink *device); int ulink_append_queue(struct ulink *device, struct ulink_cmd *ulink_cmd); int ulink_execute_queued_commands(struct ulink *device, int timeout); #ifdef _DEBUG_JTAG_IO_ const char *ulink_cmd_id_string(uint8_t id); void ulink_print_command(struct ulink_cmd *ulink_cmd); void ulink_print_queue(struct ulink *device); #endif int ulink_append_scan_cmd(struct ulink *device, enum scan_type scan_type, int scan_size_bits, uint8_t *tdi, uint8_t *tdo_start, uint8_t *tdo, uint8_t tms_count_start, uint8_t tms_sequence_start, uint8_t tms_count_end, uint8_t tms_sequence_end, struct jtag_command *origin, bool postprocess); int ulink_append_clock_tms_cmd(struct ulink *device, uint8_t count, uint8_t sequence); int ulink_append_clock_tck_cmd(struct ulink *device, uint16_t count); int ulink_append_get_signals_cmd(struct ulink *device); int ulink_append_set_signals_cmd(struct ulink *device, uint8_t low, uint8_t high); int ulink_append_sleep_cmd(struct ulink *device, uint32_t us); int ulink_append_configure_tck_cmd(struct ulink *device, int delay_scan_in, int delay_scan_out, int delay_scan_io, int delay_tck, int delay_tms); int ulink_append_led_cmd(struct ulink *device, uint8_t led_state); int ulink_append_test_cmd(struct ulink *device); /* OpenULINK TCK frequency helper functions */ int ulink_calculate_delay(enum ulink_delay_type type, long f, int *delay); int ulink_calculate_frequency(enum ulink_delay_type type, int delay, long *f); /* Interface between OpenULINK and OpenOCD */ static void ulink_set_end_state(tap_state_t endstate); int ulink_queue_statemove(struct ulink *device); int ulink_queue_scan(struct ulink *device, struct jtag_command *cmd); int ulink_queue_tlr_reset(struct ulink *device, struct jtag_command *cmd); int ulink_queue_runtest(struct ulink *device, struct jtag_command *cmd); int ulink_queue_reset(struct ulink *device, struct jtag_command *cmd); int ulink_queue_pathmove(struct ulink *device, struct jtag_command *cmd); int ulink_queue_sleep(struct ulink *device, struct jtag_command *cmd); int ulink_queue_stableclocks(struct ulink *device, struct jtag_command *cmd); int ulink_post_process_scan(struct ulink_cmd *ulink_cmd); int ulink_post_process_queue(struct ulink *device); /* JTAG driver functions (registered in struct jtag_interface) */ static int ulink_execute_queue(void); static int ulink_khz(int khz, int *jtag_speed); static int ulink_speed(int speed); static int ulink_speed_div(int speed, int *khz); static int ulink_init(void); static int ulink_quit(void); /****************************** Global Variables ******************************/ struct ulink *ulink_handle; /**************************** USB helper functions ****************************/ /** * Opens the ULINK device and claims its USB interface. * * @param device pointer to struct ulink identifying ULINK driver instance. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ int ulink_usb_open(struct ulink **device) { int ret; struct usb_dev_handle *usb_handle; /* Currently, only original ULINK is supported */ uint16_t vids[] = { ULINK_VID, 0 }; uint16_t pids[] = { ULINK_PID, 0 }; ret = jtag_usb_open(vids, pids, &usb_handle); if (ret != ERROR_OK) return ret; ret = usb_claim_interface(usb_handle, 0); if (ret != 0) return ret; (*device)->usb_handle = usb_handle; (*device)->type = ULINK_1; return ERROR_OK; } /** * Releases the ULINK interface and closes the USB device handle. * * @param device pointer to struct ulink identifying ULINK driver instance. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ int ulink_usb_close(struct ulink **device) { if (usb_release_interface((*device)->usb_handle, 0) != 0) return ERROR_FAIL; if (usb_close((*device)->usb_handle) != 0) return ERROR_FAIL; (*device)->usb_handle = NULL; return ERROR_OK; } /******************* ULINK CPU (EZ-USB) specific functions ********************/ /** * Writes '0' or '1' to the CPUCS register, putting the EZ-USB CPU into reset * or out of reset. * * @param device pointer to struct ulink identifying ULINK driver instance. * @param reset_bit 0 to put CPU into reset, 1 to put CPU out of reset. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ int ulink_cpu_reset(struct ulink *device, char reset_bit) { int ret; ret = usb_control_msg(device->usb_handle, (USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE), REQUEST_FIRMWARE_LOAD, CPUCS_REG, 0, &reset_bit, 1, USB_TIMEOUT); /* usb_control_msg() returns the number of bytes transferred during the * DATA stage of the control transfer - must be exactly 1 in this case! */ if (ret != 1) return ERROR_FAIL; return ERROR_OK; } /** * Puts the ULINK's EZ-USB microcontroller into reset state, downloads * the firmware image, resumes the microcontroller and re-enumerates * USB devices. * * @param device pointer to struct ulink identifying ULINK driver instance. * The usb_handle member will be modified during re-enumeration. * @param filename path to the Intel HEX file containing the firmware image. * @param delay the delay to wait for the device to re-enumerate. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ int ulink_load_firmware_and_renumerate(struct ulink **device, char *filename, uint32_t delay) { int ret; /* Basic process: After downloading the firmware, the ULINK will disconnect * itself and re-connect after a short amount of time so we have to close * the handle and re-enumerate USB devices */ ret = ulink_load_firmware(*device, filename); if (ret != ERROR_OK) return ret; ret = ulink_usb_close(device); if (ret != ERROR_OK) return ret; usleep(delay); ret = ulink_usb_open(device); if (ret != ERROR_OK) return ret; return ERROR_OK; } /** * Downloads a firmware image to the ULINK's EZ-USB microcontroller * over the USB bus. * * @param device pointer to struct ulink identifying ULINK driver instance. * @param filename an absolute or relative path to the Intel HEX file * containing the firmware image. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ int ulink_load_firmware(struct ulink *device, char *filename) { struct image ulink_firmware_image; int ret, i; ret = ulink_cpu_reset(device, CPU_RESET); if (ret != ERROR_OK) { LOG_ERROR("Could not halt ULINK CPU"); return ret; } ulink_firmware_image.base_address = 0; ulink_firmware_image.base_address_set = 0; ret = image_open(&ulink_firmware_image, filename, "ihex"); if (ret != ERROR_OK) { LOG_ERROR("Could not load firmware image"); return ret; } /* Download all sections in the image to ULINK */ for (i = 0; i < ulink_firmware_image.num_sections; i++) { ret = ulink_write_firmware_section(device, &ulink_firmware_image, i); if (ret != ERROR_OK) return ret; } image_close(&ulink_firmware_image); ret = ulink_cpu_reset(device, CPU_START); if (ret != ERROR_OK) { LOG_ERROR("Could not restart ULINK CPU"); return ret; } return ERROR_OK; } /** * Send one contiguous firmware section to the ULINK's EZ-USB microcontroller * over the USB bus. * * @param device pointer to struct ulink identifying ULINK driver instance. * @param firmware_image pointer to the firmware image that contains the section * which should be sent to the ULINK's EZ-USB microcontroller. * @param section_index index of the section within the firmware image. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ int ulink_write_firmware_section(struct ulink *device, struct image *firmware_image, int section_index) { uint16_t addr, size, bytes_remaining, chunk_size; uint8_t data[SECTION_BUFFERSIZE]; uint8_t *data_ptr = data; size_t size_read; int ret; size = (uint16_t)firmware_image->sections[section_index].size; addr = (uint16_t)firmware_image->sections[section_index].base_address; LOG_DEBUG("section %02i at addr 0x%04x (size 0x%04x)", section_index, addr, size); if (data == NULL) return ERROR_FAIL; /* Copy section contents to local buffer */ ret = image_read_section(firmware_image, section_index, 0, size, data, &size_read); if ((ret != ERROR_OK) || (size_read != size)) { /* Propagating the return code would return '0' (misleadingly indicating * successful execution of the function) if only the size check fails. */ return ERROR_FAIL; } bytes_remaining = size; /* Send section data in chunks of up to 64 bytes to ULINK */ while (bytes_remaining > 0) { if (bytes_remaining > 64) chunk_size = 64; else chunk_size = bytes_remaining; ret = usb_control_msg(device->usb_handle, (USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE), REQUEST_FIRMWARE_LOAD, addr, FIRMWARE_ADDR, (char *)data_ptr, chunk_size, USB_TIMEOUT); if (ret != (int)chunk_size) { /* Abort if libusb sent less data than requested */ return ERROR_FAIL; } bytes_remaining -= chunk_size; addr += chunk_size; data_ptr += chunk_size; } return ERROR_OK; } /************************** Generic helper functions **************************/ /** * Print state of interesting signals via LOG_INFO(). * * @param input_signals input signal states as returned by CMD_GET_SIGNALS * @param output_signals output signal states as returned by CMD_GET_SIGNALS */ void ulink_print_signal_states(uint8_t input_signals, uint8_t output_signals) { LOG_INFO("ULINK signal states: TDI: %i, TDO: %i, TMS: %i, TCK: %i, TRST: %i," " SRST: %i", (output_signals & SIGNAL_TDI ? 1 : 0), (input_signals & SIGNAL_TDO ? 1 : 0), (output_signals & SIGNAL_TMS ? 1 : 0), (output_signals & SIGNAL_TCK ? 1 : 0), (output_signals & SIGNAL_TRST ? 0 : 1),/* TRST and RESET are inverted */ (output_signals & SIGNAL_RESET ? 0 : 1)); /* by hardware */ } /**************** OpenULINK command generation helper functions ***************/ /** * Allocate and initialize space in memory for OpenULINK command payload. * * @param ulink_cmd pointer to command whose payload should be allocated. * @param size the amount of memory to allocate (bytes). * @param direction which payload to allocate. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ int ulink_allocate_payload(struct ulink_cmd *ulink_cmd, int size, enum ulink_payload_direction direction) { uint8_t *payload; payload = calloc(size, sizeof(uint8_t)); if (payload == NULL) { LOG_ERROR("Could not allocate OpenULINK command payload: out of memory"); return ERROR_FAIL; } switch (direction) { case PAYLOAD_DIRECTION_OUT: if (ulink_cmd->payload_out != NULL) { LOG_ERROR("BUG: Duplicate payload allocation for OpenULINK command"); free(payload); return ERROR_FAIL; } else { ulink_cmd->payload_out = payload; ulink_cmd->payload_out_size = size; } break; case PAYLOAD_DIRECTION_IN: if (ulink_cmd->payload_in_start != NULL) { LOG_ERROR("BUG: Duplicate payload allocation for OpenULINK command"); free(payload); return ERROR_FAIL; } else { ulink_cmd->payload_in_start = payload; ulink_cmd->payload_in = payload; ulink_cmd->payload_in_size = size; /* By default, free payload_in_start in ulink_clear_queue(). Commands * that do not want this behavior (e. g. split scans) must turn it off * separately! */ ulink_cmd->free_payload_in_start = true; } break; } return ERROR_OK; } /****************** OpenULINK command queue helper functions ******************/ /** * Get the current number of bytes in the queue, including command IDs. * * @param device pointer to struct ulink identifying ULINK driver instance. * @param direction the transfer direction for which to get byte count. * @return the number of bytes currently stored in the queue for the specified * direction. */ int ulink_get_queue_size(struct ulink *device, enum ulink_payload_direction direction) { struct ulink_cmd *current = device->queue_start; int sum = 0; while (current != NULL) { switch (direction) { case PAYLOAD_DIRECTION_OUT: sum += current->payload_out_size + 1; /* + 1 byte for Command ID */ break; case PAYLOAD_DIRECTION_IN: sum += current->payload_in_size; break; } current = current->next; } return sum; } /** * Clear the OpenULINK command queue. * * @param device pointer to struct ulink identifying ULINK driver instance. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ void ulink_clear_queue(struct ulink *device) { struct ulink_cmd *current = device->queue_start; struct ulink_cmd *next = NULL; while (current != NULL) { /* Save pointer to next element */ next = current->next; /* Free payloads: OUT payload can be freed immediately */ free(current->payload_out); current->payload_out = NULL; /* IN payload MUST be freed ONLY if no other commands use the * payload_in_start buffer */ if (current->free_payload_in_start == true) { free(current->payload_in_start); current->payload_in_start = NULL; current->payload_in = NULL; } /* Free queue element */ free(current); /* Proceed with next element */ current = next; } device->commands_in_queue = 0; device->queue_start = NULL; device->queue_end = NULL; } /** * Add a command to the OpenULINK command queue. * * @param device pointer to struct ulink identifying ULINK driver instance. * @param ulink_cmd pointer to command that shall be appended to the OpenULINK * command queue. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ int ulink_append_queue(struct ulink *device, struct ulink_cmd *ulink_cmd) { int newsize_out, newsize_in; int ret; newsize_out = ulink_get_queue_size(device, PAYLOAD_DIRECTION_OUT) + 1 + ulink_cmd->payload_out_size; newsize_in = ulink_get_queue_size(device, PAYLOAD_DIRECTION_IN) + ulink_cmd->payload_in_size; /* Check if the current command can be appended to the queue */ if ((newsize_out > 64) || (newsize_in > 64)) { /* New command does not fit. Execute all commands in queue before starting * new queue with the current command as first entry. */ ret = ulink_execute_queued_commands(device, USB_TIMEOUT); if (ret != ERROR_OK) return ret; ret = ulink_post_process_queue(device); if (ret != ERROR_OK) return ret; ulink_clear_queue(device); } if (device->queue_start == NULL) { /* Queue was empty */ device->commands_in_queue = 1; device->queue_start = ulink_cmd; device->queue_end = ulink_cmd; } else { /* There are already commands in the queue */ device->commands_in_queue++; device->queue_end->next = ulink_cmd; device->queue_end = ulink_cmd; } return ERROR_OK; } /** * Sends all queued OpenULINK commands to the ULINK for execution. * * @param device pointer to struct ulink identifying ULINK driver instance. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ int ulink_execute_queued_commands(struct ulink *device, int timeout) { struct ulink_cmd *current; int ret, i, index_out, index_in, count_out, count_in; uint8_t buffer[64]; #ifdef _DEBUG_JTAG_IO_ ulink_print_queue(device); #endif index_out = 0; count_out = 0; count_in = 0; for (current = device->queue_start; current; current = current->next) { /* Add command to packet */ buffer[index_out] = current->id; index_out++; count_out++; for (i = 0; i < current->payload_out_size; i++) buffer[index_out + i] = current->payload_out[i]; index_out += current->payload_out_size; count_in += current->payload_in_size; count_out += current->payload_out_size; } /* Send packet to ULINK */ ret = usb_bulk_write(device->usb_handle, (2 | USB_ENDPOINT_OUT), (char *)buffer, count_out, timeout); if (ret < 0) return ERROR_FAIL; if (ret != count_out) return ERROR_FAIL; /* Wait for response if commands contain IN payload data */ if (count_in > 0) { ret = usb_bulk_read(device->usb_handle, (2 | USB_ENDPOINT_IN), (char *)buffer, 64, timeout); if (ret < 0) return ERROR_FAIL; if (ret != count_in) return ERROR_FAIL; /* Write back IN payload data */ index_in = 0; for (current = device->queue_start; current; current = current->next) { for (i = 0; i < current->payload_in_size; i++) { current->payload_in[i] = buffer[index_in]; index_in++; } } } return ERROR_OK; } #ifdef _DEBUG_JTAG_IO_ /** * Convert an OpenULINK command ID (\a id) to a human-readable string. * * @param id the OpenULINK command ID. * @return the corresponding human-readable string. */ const char *ulink_cmd_id_string(uint8_t id) { switch (id) { case CMD_SCAN_IN: return "CMD_SCAN_IN"; break; case CMD_SLOW_SCAN_IN: return "CMD_SLOW_SCAN_IN"; break; case CMD_SCAN_OUT: return "CMD_SCAN_OUT"; break; case CMD_SLOW_SCAN_OUT: return "CMD_SLOW_SCAN_OUT"; break; case CMD_SCAN_IO: return "CMD_SCAN_IO"; break; case CMD_SLOW_SCAN_IO: return "CMD_SLOW_SCAN_IO"; break; case CMD_CLOCK_TMS: return "CMD_CLOCK_TMS"; break; case CMD_SLOW_CLOCK_TMS: return "CMD_SLOW_CLOCK_TMS"; break; case CMD_CLOCK_TCK: return "CMD_CLOCK_TCK"; break; case CMD_SLOW_CLOCK_TCK: return "CMD_SLOW_CLOCK_TCK"; break; case CMD_SLEEP_US: return "CMD_SLEEP_US"; break; case CMD_SLEEP_MS: return "CMD_SLEEP_MS"; break; case CMD_GET_SIGNALS: return "CMD_GET_SIGNALS"; break; case CMD_SET_SIGNALS: return "CMD_SET_SIGNALS"; break; case CMD_CONFIGURE_TCK_FREQ: return "CMD_CONFIGURE_TCK_FREQ"; break; case CMD_SET_LEDS: return "CMD_SET_LEDS"; break; case CMD_TEST: return "CMD_TEST"; break; default: return "CMD_UNKNOWN"; break; } } /** * Print one OpenULINK command to stdout. * * @param ulink_cmd pointer to OpenULINK command. */ void ulink_print_command(struct ulink_cmd *ulink_cmd) { int i; printf(" %-22s | OUT size = %i, bytes = 0x", ulink_cmd_id_string(ulink_cmd->id), ulink_cmd->payload_out_size); for (i = 0; i < ulink_cmd->payload_out_size; i++) printf("%02X ", ulink_cmd->payload_out[i]); printf("\n | IN size = %i\n", ulink_cmd->payload_in_size); } /** * Print the OpenULINK command queue to stdout. * * @param device pointer to struct ulink identifying ULINK driver instance. */ void ulink_print_queue(struct ulink *device) { struct ulink_cmd *current; printf("OpenULINK command queue:\n"); for (current = device->queue_start; current; current = current->next) ulink_print_command(current); } #endif /* _DEBUG_JTAG_IO_ */ /** * Perform JTAG scan * * Creates and appends a JTAG scan command to the OpenULINK command queue. * A JTAG scan consists of three steps: * - Move to the desired SHIFT state, depending on scan type (IR/DR scan). * - Shift TDI data into the JTAG chain, optionally reading the TDO pin. * - Move to the desired end state. * * @param device pointer to struct ulink identifying ULINK driver instance. * @param scan_type the type of the scan (IN, OUT, IO (bidirectional)). * @param scan_size_bits number of bits to shift into the JTAG chain. * @param tdi pointer to array containing TDI data. * @param tdo_start pointer to first element of array where TDO data shall be * stored. See #ulink_cmd for details. * @param tdo pointer to array where TDO data shall be stored * @param tms_count_start number of TMS state transitions to perform BEFORE * shifting data into the JTAG chain. * @param tms_sequence_start sequence of TMS state transitions that will be * performed BEFORE shifting data into the JTAG chain. * @param tms_count_end number of TMS state transitions to perform AFTER * shifting data into the JTAG chain. * @param tms_sequence_end sequence of TMS state transitions that will be * performed AFTER shifting data into the JTAG chain. * @param origin pointer to OpenOCD command that generated this scan command. * @param postprocess whether this command needs to be post-processed after * execution. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ int ulink_append_scan_cmd(struct ulink *device, enum scan_type scan_type, int scan_size_bits, uint8_t *tdi, uint8_t *tdo_start, uint8_t *tdo, uint8_t tms_count_start, uint8_t tms_sequence_start, uint8_t tms_count_end, uint8_t tms_sequence_end, struct jtag_command *origin, bool postprocess) { struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd)); int ret, i, scan_size_bytes; uint8_t bits_last_byte; if (cmd == NULL) return ERROR_FAIL; /* Check size of command. USB buffer can hold 64 bytes, 1 byte is command ID, * 5 bytes are setup data -> 58 remaining payload bytes for TDI data */ if (scan_size_bits > (58 * 8)) { LOG_ERROR("BUG: Tried to create CMD_SCAN_IO OpenULINK command with too" " large payload"); free(cmd); return ERROR_FAIL; } scan_size_bytes = DIV_ROUND_UP(scan_size_bits, 8); bits_last_byte = scan_size_bits % 8; if (bits_last_byte == 0) bits_last_byte = 8; /* Allocate out_payload depending on scan type */ switch (scan_type) { case SCAN_IN: if (device->delay_scan_in < 0) cmd->id = CMD_SCAN_IN; else cmd->id = CMD_SLOW_SCAN_IN; ret = ulink_allocate_payload(cmd, 5, PAYLOAD_DIRECTION_OUT); break; case SCAN_OUT: if (device->delay_scan_out < 0) cmd->id = CMD_SCAN_OUT; else cmd->id = CMD_SLOW_SCAN_OUT; ret = ulink_allocate_payload(cmd, scan_size_bytes + 5, PAYLOAD_DIRECTION_OUT); break; case SCAN_IO: if (device->delay_scan_io < 0) cmd->id = CMD_SCAN_IO; else cmd->id = CMD_SLOW_SCAN_IO; ret = ulink_allocate_payload(cmd, scan_size_bytes + 5, PAYLOAD_DIRECTION_OUT); break; default: LOG_ERROR("BUG: ulink_append_scan_cmd() encountered an unknown scan type"); ret = ERROR_FAIL; break; } if (ret != ERROR_OK) { free(cmd); return ret; } /* Build payload_out that is common to all scan types */ cmd->payload_out[0] = scan_size_bytes & 0xFF; cmd->payload_out[1] = bits_last_byte & 0xFF; cmd->payload_out[2] = ((tms_count_start & 0x0F) << 4) | (tms_count_end & 0x0F); cmd->payload_out[3] = tms_sequence_start; cmd->payload_out[4] = tms_sequence_end; /* Setup payload_out for types with OUT transfer */ if ((scan_type == SCAN_OUT) || (scan_type == SCAN_IO)) { for (i = 0; i < scan_size_bytes; i++) cmd->payload_out[i + 5] = tdi[i]; } /* Setup payload_in pointers for types with IN transfer */ if ((scan_type == SCAN_IN) || (scan_type == SCAN_IO)) { cmd->payload_in_start = tdo_start; cmd->payload_in = tdo; cmd->payload_in_size = scan_size_bytes; } cmd->needs_postprocessing = postprocess; cmd->cmd_origin = origin; /* For scan commands, we free payload_in_start only when the command is * the last in a series of split commands or a stand-alone command */ cmd->free_payload_in_start = postprocess; return ulink_append_queue(device, cmd); } /** * Perform TAP state transitions * * @param device pointer to struct ulink identifying ULINK driver instance. * @param count defines the number of TCK clock cycles generated (up to 8). * @param sequence defines the TMS pin levels for each state transition. The * Least-Significant Bit is read first. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ int ulink_append_clock_tms_cmd(struct ulink *device, uint8_t count, uint8_t sequence) { struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd)); int ret; if (cmd == NULL) return ERROR_FAIL; if (device->delay_clock_tms < 0) cmd->id = CMD_CLOCK_TMS; else cmd->id = CMD_SLOW_CLOCK_TMS; /* CMD_CLOCK_TMS has two OUT payload bytes and zero IN payload bytes */ ret = ulink_allocate_payload(cmd, 2, PAYLOAD_DIRECTION_OUT); if (ret != ERROR_OK) { free(cmd); return ret; } cmd->payload_out[0] = count; cmd->payload_out[1] = sequence; return ulink_append_queue(device, cmd); } /** * Generate a defined amount of TCK clock cycles * * All other JTAG signals are left unchanged. * * @param device pointer to struct ulink identifying ULINK driver instance. * @param count the number of TCK clock cycles to generate. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ int ulink_append_clock_tck_cmd(struct ulink *device, uint16_t count) { struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd)); int ret; if (cmd == NULL) return ERROR_FAIL; if (device->delay_clock_tck < 0) cmd->id = CMD_CLOCK_TCK; else cmd->id = CMD_SLOW_CLOCK_TCK; /* CMD_CLOCK_TCK has two OUT payload bytes and zero IN payload bytes */ ret = ulink_allocate_payload(cmd, 2, PAYLOAD_DIRECTION_OUT); if (ret != ERROR_OK) { free(cmd); return ret; } cmd->payload_out[0] = count & 0xff; cmd->payload_out[1] = (count >> 8) & 0xff; return ulink_append_queue(device, cmd); } /** * Read JTAG signals. * * @param device pointer to struct ulink identifying ULINK driver instance. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ int ulink_append_get_signals_cmd(struct ulink *device) { struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd)); int ret; if (cmd == NULL) return ERROR_FAIL; cmd->id = CMD_GET_SIGNALS; cmd->needs_postprocessing = true; /* CMD_GET_SIGNALS has two IN payload bytes */ ret = ulink_allocate_payload(cmd, 2, PAYLOAD_DIRECTION_IN); if (ret != ERROR_OK) { free(cmd); return ret; } return ulink_append_queue(device, cmd); } /** * Arbitrarily set JTAG output signals. * * @param device pointer to struct ulink identifying ULINK driver instance. * @param low defines which signals will be de-asserted. Each bit corresponds * to a JTAG signal: * - SIGNAL_TDI * - SIGNAL_TMS * - SIGNAL_TCK * - SIGNAL_TRST * - SIGNAL_BRKIN * - SIGNAL_RESET * - SIGNAL_OCDSE * @param high defines which signals will be asserted. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ int ulink_append_set_signals_cmd(struct ulink *device, uint8_t low, uint8_t high) { struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd)); int ret; if (cmd == NULL) return ERROR_FAIL; cmd->id = CMD_SET_SIGNALS; /* CMD_SET_SIGNALS has two OUT payload bytes and zero IN payload bytes */ ret = ulink_allocate_payload(cmd, 2, PAYLOAD_DIRECTION_OUT); if (ret != ERROR_OK) { free(cmd); return ret; } cmd->payload_out[0] = low; cmd->payload_out[1] = high; return ulink_append_queue(device, cmd); } /** * Sleep for a pre-defined number of microseconds * * @param device pointer to struct ulink identifying ULINK driver instance. * @param us the number microseconds to sleep. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ int ulink_append_sleep_cmd(struct ulink *device, uint32_t us) { struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd)); int ret; if (cmd == NULL) return ERROR_FAIL; cmd->id = CMD_SLEEP_US; /* CMD_SLEEP_US has two OUT payload bytes and zero IN payload bytes */ ret = ulink_allocate_payload(cmd, 2, PAYLOAD_DIRECTION_OUT); if (ret != ERROR_OK) { free(cmd); return ret; } cmd->payload_out[0] = us & 0x00ff; cmd->payload_out[1] = (us >> 8) & 0x00ff; return ulink_append_queue(device, cmd); } /** * Set TCK delay counters * * @param device pointer to struct ulink identifying ULINK driver instance. * @param delay_scan_in delay count top value in jtag_slow_scan_in() function. * @param delay_scan_out delay count top value in jtag_slow_scan_out() function. * @param delay_scan_io delay count top value in jtag_slow_scan_io() function. * @param delay_tck delay count top value in jtag_clock_tck() function. * @param delay_tms delay count top value in jtag_slow_clock_tms() function. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ int ulink_append_configure_tck_cmd(struct ulink *device, int delay_scan_in, int delay_scan_out, int delay_scan_io, int delay_tck, int delay_tms) { struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd)); int ret; if (cmd == NULL) return ERROR_FAIL; cmd->id = CMD_CONFIGURE_TCK_FREQ; /* CMD_CONFIGURE_TCK_FREQ has five OUT payload bytes and zero * IN payload bytes */ ret = ulink_allocate_payload(cmd, 5, PAYLOAD_DIRECTION_OUT); if (ret != ERROR_OK) { free(cmd); return ret; } if (delay_scan_in < 0) cmd->payload_out[0] = 0; else cmd->payload_out[0] = (uint8_t)delay_scan_in; if (delay_scan_out < 0) cmd->payload_out[1] = 0; else cmd->payload_out[1] = (uint8_t)delay_scan_out; if (delay_scan_io < 0) cmd->payload_out[2] = 0; else cmd->payload_out[2] = (uint8_t)delay_scan_io; if (delay_tck < 0) cmd->payload_out[3] = 0; else cmd->payload_out[3] = (uint8_t)delay_tck; if (delay_tms < 0) cmd->payload_out[4] = 0; else cmd->payload_out[4] = (uint8_t)delay_tms; return ulink_append_queue(device, cmd); } /** * Turn on/off ULINK LEDs. * * @param device pointer to struct ulink identifying ULINK driver instance. * @param led_state which LED(s) to turn on or off. The following bits * influence the LEDS: * - Bit 0: Turn COM LED on * - Bit 1: Turn RUN LED on * - Bit 2: Turn COM LED off * - Bit 3: Turn RUN LED off * If both the on-bit and the off-bit for the same LED is set, the LED is * turned off. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ int ulink_append_led_cmd(struct ulink *device, uint8_t led_state) { struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd)); int ret; if (cmd == NULL) return ERROR_FAIL; cmd->id = CMD_SET_LEDS; /* CMD_SET_LEDS has one OUT payload byte and zero IN payload bytes */ ret = ulink_allocate_payload(cmd, 1, PAYLOAD_DIRECTION_OUT); if (ret != ERROR_OK) { free(cmd); return ret; } cmd->payload_out[0] = led_state; return ulink_append_queue(device, cmd); } /** * Test command. Used to check if the ULINK device is ready to accept new * commands. * * @param device pointer to struct ulink identifying ULINK driver instance. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ int ulink_append_test_cmd(struct ulink *device) { struct ulink_cmd *cmd = calloc(1, sizeof(struct ulink_cmd)); int ret; if (cmd == NULL) return ERROR_FAIL; cmd->id = CMD_TEST; /* CMD_TEST has one OUT payload byte and zero IN payload bytes */ ret = ulink_allocate_payload(cmd, 1, PAYLOAD_DIRECTION_OUT); if (ret != ERROR_OK) { free(cmd); return ret; } cmd->payload_out[0] = 0xAA; return ulink_append_queue(device, cmd); } /****************** OpenULINK TCK frequency helper functions ******************/ /** * Calculate delay values for a given TCK frequency. * * The OpenULINK firmware uses five different speed values for different * commands. These speed values are calculated in these functions. * * The five different commands which support variable TCK frequency are * implemented twice in the firmware: * 1. Maximum possible frequency without any artificial delay * 2. Variable frequency with artificial linear delay loop * * To set the ULINK to maximum frequency, it is only neccessary to use the * corresponding command IDs. To set the ULINK to a lower frequency, the * delay loop top values have to be calculated first. Then, a * CMD_CONFIGURE_TCK_FREQ command needs to be sent to the ULINK device. * * The delay values are described by linear equations: * t = k * x + d * (t = period, k = constant, x = delay value, d = constant) * * Thus, the delay can be calculated as in the following equation: * x = (t - d) / k * * The constants in these equations have been determined and validated by * measuring the frequency resulting from different delay values. * * @param type for which command to calculate the delay value. * @param f TCK frequency for which to calculate the delay value in Hz. * @param delay where to store resulting delay value. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ int ulink_calculate_delay(enum ulink_delay_type type, long f, int *delay) { float t, x, x_ceil; /* Calculate period of requested TCK frequency */ t = 1.0 / (float)(f); switch (type) { case DELAY_CLOCK_TCK: x = (t - (float)(6E-6)) / (float)(4E-6); break; case DELAY_CLOCK_TMS: x = (t - (float)(8.5E-6)) / (float)(4E-6); break; case DELAY_SCAN_IN: x = (t - (float)(8.8308E-6)) / (float)(4E-6); break; case DELAY_SCAN_OUT: x = (t - (float)(1.0527E-5)) / (float)(4E-6); break; case DELAY_SCAN_IO: x = (t - (float)(1.3132E-5)) / (float)(4E-6); break; default: return ERROR_FAIL; break; } /* Check if the delay value is negative. This happens when a frequency is * requested that is too high for the delay loop implementation. In this * case, set delay value to zero. */ if (x < 0) x = 0; /* We need to convert the exact delay value to an integer. Therefore, we * round the exact value UP to ensure that the resulting frequency is NOT * higher than the requested frequency. */ x_ceil = ceilf(x); /* Check if the value is within limits */ if (x_ceil > 255) return ERROR_FAIL; *delay = (int)x_ceil; return ERROR_OK; } /** * Calculate frequency for a given delay value. * * Similar to the #ulink_calculate_delay function, this function calculates the * TCK frequency for a given delay value by using linear equations of the form: * t = k * x + d * (t = period, k = constant, x = delay value, d = constant) * * @param type for which command to calculate the delay value. * @param delay delay value for which to calculate the resulting TCK frequency. * @param f where to store the resulting TCK frequency. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ int ulink_calculate_frequency(enum ulink_delay_type type, int delay, long *f) { float t, f_float, f_rounded; if (delay > 255) return ERROR_FAIL; switch (type) { case DELAY_CLOCK_TCK: if (delay < 0) t = (float)(2.666E-6); else t = (float)(4E-6) * (float)(delay) + (float)(6E-6); break; case DELAY_CLOCK_TMS: if (delay < 0) t = (float)(5.666E-6); else t = (float)(4E-6) * (float)(delay) + (float)(8.5E-6); break; case DELAY_SCAN_IN: if (delay < 0) t = (float)(5.5E-6); else t = (float)(4E-6) * (float)(delay) + (float)(8.8308E-6); break; case DELAY_SCAN_OUT: if (delay < 0) t = (float)(7.0E-6); else t = (float)(4E-6) * (float)(delay) + (float)(1.0527E-5); break; case DELAY_SCAN_IO: if (delay < 0) t = (float)(9.926E-6); else t = (float)(4E-6) * (float)(delay) + (float)(1.3132E-5); break; default: return ERROR_FAIL; break; } f_float = 1.0 / t; f_rounded = roundf(f_float); *f = (long)f_rounded; return ERROR_OK; } /******************* Interface between OpenULINK and OpenOCD ******************/ /** * Sets the end state follower (see interface.h) if \a endstate is a stable * state. * * @param endstate the state the end state follower should be set to. */ static void ulink_set_end_state(tap_state_t endstate) { if (tap_is_state_stable(endstate)) tap_set_end_state(endstate); else { LOG_ERROR("BUG: %s is not a valid end state", tap_state_name(endstate)); exit(EXIT_FAILURE); } } /** * Move from the current TAP state to the current TAP end state. * * @param device pointer to struct ulink identifying ULINK driver instance. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ int ulink_queue_statemove(struct ulink *device) { uint8_t tms_sequence, tms_count; int ret; if (tap_get_state() == tap_get_end_state()) { /* Do nothing if we are already there */ return ERROR_OK; } tms_sequence = tap_get_tms_path(tap_get_state(), tap_get_end_state()); tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); ret = ulink_append_clock_tms_cmd(device, tms_count, tms_sequence); if (ret == ERROR_OK) tap_set_state(tap_get_end_state()); return ret; } /** * Perform a scan operation on a JTAG register. * * @param device pointer to struct ulink identifying ULINK driver instance. * @param cmd pointer to the command that shall be executed. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ int ulink_queue_scan(struct ulink *device, struct jtag_command *cmd) { uint32_t scan_size_bits, scan_size_bytes, bits_last_scan; uint32_t scans_max_payload, bytecount; uint8_t *tdi_buffer_start = NULL, *tdi_buffer = NULL; uint8_t *tdo_buffer_start = NULL, *tdo_buffer = NULL; uint8_t first_tms_count, first_tms_sequence; uint8_t last_tms_count, last_tms_sequence; uint8_t tms_count_pause, tms_sequence_pause; uint8_t tms_count_resume, tms_sequence_resume; uint8_t tms_count_start, tms_sequence_start; uint8_t tms_count_end, tms_sequence_end; enum scan_type type; int ret; /* Determine scan size */ scan_size_bits = jtag_scan_size(cmd->cmd.scan); scan_size_bytes = DIV_ROUND_UP(scan_size_bits, 8); /* Determine scan type (IN/OUT/IO) */ type = jtag_scan_type(cmd->cmd.scan); /* Determine number of scan commands with maximum payload */ scans_max_payload = scan_size_bytes / 58; /* Determine size of last shift command */ bits_last_scan = scan_size_bits - (scans_max_payload * 58 * 8); /* Allocate TDO buffer if required */ if ((type == SCAN_IN) || (type == SCAN_IO)) { tdo_buffer_start = calloc(sizeof(uint8_t), scan_size_bytes); if (tdo_buffer_start == NULL) return ERROR_FAIL; tdo_buffer = tdo_buffer_start; } /* Fill TDI buffer if required */ if ((type == SCAN_OUT) || (type == SCAN_IO)) { jtag_build_buffer(cmd->cmd.scan, &tdi_buffer_start); tdi_buffer = tdi_buffer_start; } /* Get TAP state transitions */ if (cmd->cmd.scan->ir_scan) { ulink_set_end_state(TAP_IRSHIFT); first_tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); first_tms_sequence = tap_get_tms_path(tap_get_state(), tap_get_end_state()); tap_set_state(TAP_IRSHIFT); tap_set_end_state(cmd->cmd.scan->end_state); last_tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); last_tms_sequence = tap_get_tms_path(tap_get_state(), tap_get_end_state()); /* TAP state transitions for split scans */ tms_count_pause = tap_get_tms_path_len(TAP_IRSHIFT, TAP_IRPAUSE); tms_sequence_pause = tap_get_tms_path(TAP_IRSHIFT, TAP_IRPAUSE); tms_count_resume = tap_get_tms_path_len(TAP_IRPAUSE, TAP_IRSHIFT); tms_sequence_resume = tap_get_tms_path(TAP_IRPAUSE, TAP_IRSHIFT); } else { ulink_set_end_state(TAP_DRSHIFT); first_tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); first_tms_sequence = tap_get_tms_path(tap_get_state(), tap_get_end_state()); tap_set_state(TAP_DRSHIFT); tap_set_end_state(cmd->cmd.scan->end_state); last_tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); last_tms_sequence = tap_get_tms_path(tap_get_state(), tap_get_end_state()); /* TAP state transitions for split scans */ tms_count_pause = tap_get_tms_path_len(TAP_DRSHIFT, TAP_DRPAUSE); tms_sequence_pause = tap_get_tms_path(TAP_DRSHIFT, TAP_DRPAUSE); tms_count_resume = tap_get_tms_path_len(TAP_DRPAUSE, TAP_DRSHIFT); tms_sequence_resume = tap_get_tms_path(TAP_DRPAUSE, TAP_DRSHIFT); } /* Generate scan commands */ bytecount = scan_size_bytes; while (bytecount > 0) { if (bytecount == scan_size_bytes) { /* This is the first scan */ tms_count_start = first_tms_count; tms_sequence_start = first_tms_sequence; } else { /* Resume from previous scan */ tms_count_start = tms_count_resume; tms_sequence_start = tms_sequence_resume; } if (bytecount > 58) { /* Full scan, at least one scan will follow */ tms_count_end = tms_count_pause; tms_sequence_end = tms_sequence_pause; ret = ulink_append_scan_cmd(device, type, 58 * 8, tdi_buffer, tdo_buffer_start, tdo_buffer, tms_count_start, tms_sequence_start, tms_count_end, tms_sequence_end, cmd, false); bytecount -= 58; /* Update TDI and TDO buffer pointers */ if (tdi_buffer_start != NULL) tdi_buffer += 58; if (tdo_buffer_start != NULL) tdo_buffer += 58; } else if (bytecount == 58) { /* Full scan, no further scans */ tms_count_end = last_tms_count; tms_sequence_end = last_tms_sequence; ret = ulink_append_scan_cmd(device, type, 58 * 8, tdi_buffer, tdo_buffer_start, tdo_buffer, tms_count_start, tms_sequence_start, tms_count_end, tms_sequence_end, cmd, true); bytecount = 0; } else {/* Scan with less than maximum payload, no further scans */ tms_count_end = last_tms_count; tms_sequence_end = last_tms_sequence; ret = ulink_append_scan_cmd(device, type, bits_last_scan, tdi_buffer, tdo_buffer_start, tdo_buffer, tms_count_start, tms_sequence_start, tms_count_end, tms_sequence_end, cmd, true); bytecount = 0; } if (ret != ERROR_OK) { free(tdi_buffer_start); return ret; } } free(tdi_buffer_start); /* Set current state to the end state requested by the command */ tap_set_state(cmd->cmd.scan->end_state); return ERROR_OK; } /** * Move the TAP into the Test Logic Reset state. * * @param device pointer to struct ulink identifying ULINK driver instance. * @param cmd pointer to the command that shall be executed. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ int ulink_queue_tlr_reset(struct ulink *device, struct jtag_command *cmd) { int ret; ret = ulink_append_clock_tms_cmd(device, 5, 0xff); if (ret == ERROR_OK) tap_set_state(TAP_RESET); return ret; } /** * Run Test. * * Generate TCK clock cycles while remaining * in the Run-Test/Idle state. * * @param device pointer to struct ulink identifying ULINK driver instance. * @param cmd pointer to the command that shall be executed. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ int ulink_queue_runtest(struct ulink *device, struct jtag_command *cmd) { int ret; /* Only perform statemove if the TAP currently isn't in the TAP_IDLE state */ if (tap_get_state() != TAP_IDLE) { ulink_set_end_state(TAP_IDLE); ulink_queue_statemove(device); } /* Generate the clock cycles */ ret = ulink_append_clock_tck_cmd(device, cmd->cmd.runtest->num_cycles); if (ret != ERROR_OK) return ret; /* Move to end state specified in command */ if (cmd->cmd.runtest->end_state != tap_get_state()) { tap_set_end_state(cmd->cmd.runtest->end_state); ulink_queue_statemove(device); } return ERROR_OK; } /** * Execute a JTAG_RESET command * * @param cmd pointer to the command that shall be executed. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ int ulink_queue_reset(struct ulink *device, struct jtag_command *cmd) { uint8_t low = 0, high = 0; if (cmd->cmd.reset->trst) { tap_set_state(TAP_RESET); high |= SIGNAL_TRST; } else low |= SIGNAL_TRST; if (cmd->cmd.reset->srst) high |= SIGNAL_RESET; else low |= SIGNAL_RESET; return ulink_append_set_signals_cmd(device, low, high); } /** * Move to one TAP state or several states in succession. * * @param device pointer to struct ulink identifying ULINK driver instance. * @param cmd pointer to the command that shall be executed. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ int ulink_queue_pathmove(struct ulink *device, struct jtag_command *cmd) { int ret, i, num_states, batch_size, state_count; tap_state_t *path; uint8_t tms_sequence; num_states = cmd->cmd.pathmove->num_states; path = cmd->cmd.pathmove->path; state_count = 0; while (num_states > 0) { tms_sequence = 0; /* Determine batch size */ if (num_states >= 8) batch_size = 8; else batch_size = num_states; for (i = 0; i < batch_size; i++) { if (tap_state_transition(tap_get_state(), false) == path[state_count]) { /* Append '0' transition: clear bit 'i' in tms_sequence */ buf_set_u32(&tms_sequence, i, 1, 0x0); } else if (tap_state_transition(tap_get_state(), true) == path[state_count]) { /* Append '1' transition: set bit 'i' in tms_sequence */ buf_set_u32(&tms_sequence, i, 1, 0x1); } else { /* Invalid state transition */ LOG_ERROR("BUG: %s -> %s isn't a valid TAP state transition", tap_state_name(tap_get_state()), tap_state_name(path[state_count])); return ERROR_FAIL; } tap_set_state(path[state_count]); state_count++; num_states--; } /* Append CLOCK_TMS command to OpenULINK command queue */ LOG_INFO( "pathmove batch: count = %i, sequence = 0x%x", batch_size, tms_sequence); ret = ulink_append_clock_tms_cmd(ulink_handle, batch_size, tms_sequence); if (ret != ERROR_OK) return ret; } return ERROR_OK; } /** * Sleep for a specific amount of time. * * @param device pointer to struct ulink identifying ULINK driver instance. * @param cmd pointer to the command that shall be executed. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ int ulink_queue_sleep(struct ulink *device, struct jtag_command *cmd) { /* IMPORTANT! Due to the time offset in command execution introduced by * command queueing, this needs to be implemented in the ULINK device */ return ulink_append_sleep_cmd(device, cmd->cmd.sleep->us); } /** * Generate TCK cycles while remaining in a stable state. * * @param device pointer to struct ulink identifying ULINK driver instance. * @param cmd pointer to the command that shall be executed. */ int ulink_queue_stableclocks(struct ulink *device, struct jtag_command *cmd) { int ret; unsigned num_cycles; if (!tap_is_state_stable(tap_get_state())) { LOG_ERROR("JTAG_STABLECLOCKS: state not stable"); return ERROR_FAIL; } num_cycles = cmd->cmd.stableclocks->num_cycles; /* TMS stays either high (Test Logic Reset state) or low (all other states) */ if (tap_get_state() == TAP_RESET) ret = ulink_append_set_signals_cmd(device, 0, SIGNAL_TMS); else ret = ulink_append_set_signals_cmd(device, SIGNAL_TMS, 0); if (ret != ERROR_OK) return ret; while (num_cycles > 0) { if (num_cycles > 0xFFFF) { /* OpenULINK CMD_CLOCK_TCK can generate up to 0xFFFF (uint16_t) cycles */ ret = ulink_append_clock_tck_cmd(device, 0xFFFF); num_cycles -= 0xFFFF; } else { ret = ulink_append_clock_tck_cmd(device, num_cycles); num_cycles = 0; } if (ret != ERROR_OK) return ret; } return ERROR_OK; } /** * Post-process JTAG_SCAN command * * @param ulink_cmd pointer to OpenULINK command that shall be processed. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ int ulink_post_process_scan(struct ulink_cmd *ulink_cmd) { struct jtag_command *cmd = ulink_cmd->cmd_origin; int ret; switch (jtag_scan_type(cmd->cmd.scan)) { case SCAN_IN: case SCAN_IO: ret = jtag_read_buffer(ulink_cmd->payload_in_start, cmd->cmd.scan); break; case SCAN_OUT: /* Nothing to do for OUT scans */ ret = ERROR_OK; break; default: LOG_ERROR("BUG: ulink_post_process_scan() encountered an unknown" " JTAG scan type"); ret = ERROR_FAIL; break; } return ret; } /** * Perform post-processing of commands after OpenULINK queue has been executed. * * @param device pointer to struct ulink identifying ULINK driver instance. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ int ulink_post_process_queue(struct ulink *device) { struct ulink_cmd *current; struct jtag_command *openocd_cmd; int ret; current = device->queue_start; while (current != NULL) { openocd_cmd = current->cmd_origin; /* Check if a corresponding OpenOCD command is stored for this * OpenULINK command */ if ((current->needs_postprocessing == true) && (openocd_cmd != NULL)) { switch (openocd_cmd->type) { case JTAG_SCAN: ret = ulink_post_process_scan(current); break; case JTAG_TLR_RESET: case JTAG_RUNTEST: case JTAG_RESET: case JTAG_PATHMOVE: case JTAG_SLEEP: case JTAG_STABLECLOCKS: /* Nothing to do for these commands */ ret = ERROR_OK; break; default: ret = ERROR_FAIL; LOG_ERROR("BUG: ulink_post_process_queue() encountered unknown JTAG " "command type"); break; } if (ret != ERROR_OK) return ret; } current = current->next; } return ERROR_OK; } /**************************** JTAG driver functions ***************************/ /** * Executes the JTAG Command Queue. * * This is done in three stages: First, all OpenOCD commands are processed into * queued OpenULINK commands. Next, the OpenULINK command queue is sent to the * ULINK device and data received from the ULINK device is cached. Finally, * the post-processing function writes back data to the corresponding OpenOCD * commands. * * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_execute_queue(void) { struct jtag_command *cmd = jtag_command_queue; int ret; while (cmd) { switch (cmd->type) { case JTAG_SCAN: ret = ulink_queue_scan(ulink_handle, cmd); break; case JTAG_TLR_RESET: ret = ulink_queue_tlr_reset(ulink_handle, cmd); break; case JTAG_RUNTEST: ret = ulink_queue_runtest(ulink_handle, cmd); break; case JTAG_RESET: ret = ulink_queue_reset(ulink_handle, cmd); break; case JTAG_PATHMOVE: ret = ulink_queue_pathmove(ulink_handle, cmd); break; case JTAG_SLEEP: ret = ulink_queue_sleep(ulink_handle, cmd); break; case JTAG_STABLECLOCKS: ret = ulink_queue_stableclocks(ulink_handle, cmd); break; default: ret = ERROR_FAIL; LOG_ERROR("BUG: encountered unknown JTAG command type"); break; } if (ret != ERROR_OK) return ret; cmd = cmd->next; } if (ulink_handle->commands_in_queue > 0) { ret = ulink_execute_queued_commands(ulink_handle, USB_TIMEOUT); if (ret != ERROR_OK) return ret; ret = ulink_post_process_queue(ulink_handle); if (ret != ERROR_OK) return ret; ulink_clear_queue(ulink_handle); } return ERROR_OK; } /** * Set the TCK frequency of the ULINK adapter. * * @param khz desired JTAG TCK frequency. * @param jtag_speed where to store corresponding adapter-specific speed value. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_khz(int khz, int *jtag_speed) { int ret; if (khz == 0) { LOG_ERROR("RCLK not supported"); return ERROR_FAIL; } /* CLOCK_TCK commands are decoupled from others. Therefore, the frequency * setting can be done independently from all other commands. */ if (khz >= 375) ulink_handle->delay_clock_tck = -1; else { ret = ulink_calculate_delay(DELAY_CLOCK_TCK, khz * 1000, &ulink_handle->delay_clock_tck); if (ret != ERROR_OK) return ret; } /* SCAN_{IN,OUT,IO} commands invoke CLOCK_TMS commands. Therefore, if the * requested frequency goes below the maximum frequency for SLOW_CLOCK_TMS * commands, all SCAN commands MUST also use the variable frequency * implementation! */ if (khz >= 176) { ulink_handle->delay_clock_tms = -1; ulink_handle->delay_scan_in = -1; ulink_handle->delay_scan_out = -1; ulink_handle->delay_scan_io = -1; } else { ret = ulink_calculate_delay(DELAY_CLOCK_TMS, khz * 1000, &ulink_handle->delay_clock_tms); if (ret != ERROR_OK) return ret; ret = ulink_calculate_delay(DELAY_SCAN_IN, khz * 1000, &ulink_handle->delay_scan_in); if (ret != ERROR_OK) return ret; ret = ulink_calculate_delay(DELAY_SCAN_OUT, khz * 1000, &ulink_handle->delay_scan_out); if (ret != ERROR_OK) return ret; ret = ulink_calculate_delay(DELAY_SCAN_IO, khz * 1000, &ulink_handle->delay_scan_io); if (ret != ERROR_OK) return ret; } #ifdef _DEBUG_JTAG_IO_ long f_tck, f_tms, f_scan_in, f_scan_out, f_scan_io; ulink_calculate_frequency(DELAY_CLOCK_TCK, ulink_handle->delay_clock_tck, &f_tck); ulink_calculate_frequency(DELAY_CLOCK_TMS, ulink_handle->delay_clock_tms, &f_tms); ulink_calculate_frequency(DELAY_SCAN_IN, ulink_handle->delay_scan_in, &f_scan_in); ulink_calculate_frequency(DELAY_SCAN_OUT, ulink_handle->delay_scan_out, &f_scan_out); ulink_calculate_frequency(DELAY_SCAN_IO, ulink_handle->delay_scan_io, &f_scan_io); DEBUG_JTAG_IO("ULINK TCK setup: delay_tck = %i (%li Hz),", ulink_handle->delay_clock_tck, f_tck); DEBUG_JTAG_IO(" delay_tms = %i (%li Hz),", ulink_handle->delay_clock_tms, f_tms); DEBUG_JTAG_IO(" delay_scan_in = %i (%li Hz),", ulink_handle->delay_scan_in, f_scan_in); DEBUG_JTAG_IO(" delay_scan_out = %i (%li Hz),", ulink_handle->delay_scan_out, f_scan_out); DEBUG_JTAG_IO(" delay_scan_io = %i (%li Hz),", ulink_handle->delay_scan_io, f_scan_io); #endif /* Configure the ULINK device with the new delay values */ ret = ulink_append_configure_tck_cmd(ulink_handle, ulink_handle->delay_scan_in, ulink_handle->delay_scan_out, ulink_handle->delay_scan_io, ulink_handle->delay_clock_tck, ulink_handle->delay_clock_tms); if (ret != ERROR_OK) return ret; *jtag_speed = khz; return ERROR_OK; } /** * Set the TCK frequency of the ULINK adapter. * * Because of the way the TCK frequency is set up in the OpenULINK firmware, * there are five different speed settings. To simplify things, the * adapter-specific speed setting value is identical to the TCK frequency in * khz. * * @param speed desired adapter-specific speed value. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_speed(int speed) { int dummy; return ulink_khz(speed, &dummy); } /** * Convert adapter-specific speed value to corresponding TCK frequency in kHz. * * Because of the way the TCK frequency is set up in the OpenULINK firmware, * there are five different speed settings. To simplify things, the * adapter-specific speed setting value is identical to the TCK frequency in * khz. * * @param speed adapter-specific speed value. * @param khz where to store corresponding TCK frequency in kHz. * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_speed_div(int speed, int *khz) { *khz = speed; return ERROR_OK; } /** * Initiates the firmware download to the ULINK adapter and prepares * the USB handle. * * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_init(void) { int ret; char str_manufacturer[20]; bool download_firmware = false; uint8_t *dummy; uint8_t input_signals, output_signals; ulink_handle = calloc(1, sizeof(struct ulink)); if (ulink_handle == NULL) return ERROR_FAIL; usb_init(); ret = ulink_usb_open(&ulink_handle); if (ret != ERROR_OK) { LOG_ERROR("Could not open ULINK device"); free(ulink_handle); ulink_handle = NULL; return ret; } /* Get String Descriptor to determine if firmware needs to be loaded */ ret = usb_get_string_simple(ulink_handle->usb_handle, 1, str_manufacturer, 20); if (ret < 0) { /* Could not get descriptor -> Unconfigured or original Keil firmware */ download_firmware = true; } else { /* We got a String Descriptor, check if it is the correct one */ if (strncmp(str_manufacturer, "OpenULINK", 9) != 0) download_firmware = true; } if (download_firmware == true) { LOG_INFO("Loading OpenULINK firmware. This is reversible by power-cycling" " ULINK device."); ret = ulink_load_firmware_and_renumerate(&ulink_handle, ULINK_FIRMWARE_FILE, ULINK_RENUMERATION_DELAY); if (ret != ERROR_OK) { LOG_ERROR("Could not download firmware and re-numerate ULINK"); free(ulink_handle); ulink_handle = NULL; return ret; } } else LOG_INFO("ULINK device is already running OpenULINK firmware"); /* Initialize OpenULINK command queue */ ulink_clear_queue(ulink_handle); /* Issue one test command with short timeout */ ret = ulink_append_test_cmd(ulink_handle); if (ret != ERROR_OK) return ret; ret = ulink_execute_queued_commands(ulink_handle, 200); if (ret != ERROR_OK) { /* Sending test command failed. The ULINK device may be forever waiting for * the host to fetch an USB Bulk IN packet (e. g. OpenOCD crashed or was * shut down by the user via Ctrl-C. Try to retrieve this Bulk IN packet. */ dummy = calloc(64, sizeof(uint8_t)); ret = usb_bulk_read(ulink_handle->usb_handle, (2 | USB_ENDPOINT_IN), (char *)dummy, 64, 200); free(dummy); if (ret < 0) { /* Bulk IN transfer failed -> unrecoverable error condition */ LOG_ERROR("Cannot communicate with ULINK device. Disconnect ULINK from " "the USB port and re-connect, then re-run OpenOCD"); free(ulink_handle); ulink_handle = NULL; return ERROR_FAIL; } #ifdef _DEBUG_USB_COMMS_ else { /* Successfully received Bulk IN packet -> continue */ LOG_INFO("Recovered from lost Bulk IN packet"); } #endif } ulink_clear_queue(ulink_handle); ulink_append_get_signals_cmd(ulink_handle); ulink_execute_queued_commands(ulink_handle, 200); /* Post-process the single CMD_GET_SIGNALS command */ input_signals = ulink_handle->queue_start->payload_in[0]; output_signals = ulink_handle->queue_start->payload_in[1]; ulink_print_signal_states(input_signals, output_signals); ulink_clear_queue(ulink_handle); return ERROR_OK; } /** * Closes the USB handle for the ULINK device. * * @return on success: ERROR_OK * @return on failure: ERROR_FAIL */ static int ulink_quit(void) { int ret; ret = ulink_usb_close(&ulink_handle); free(ulink_handle); return ret; } /** * Set a custom path to ULINK firmware image and force downloading to ULINK. */ COMMAND_HANDLER(ulink_download_firmware_handler) { int ret; if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; LOG_INFO("Downloading ULINK firmware image %s", CMD_ARGV[0]); /* Download firmware image in CMD_ARGV[0] */ ret = ulink_load_firmware_and_renumerate(&ulink_handle, (char *)CMD_ARGV[0], ULINK_RENUMERATION_DELAY); return ret; } /*************************** Command Registration **************************/ static const struct command_registration ulink_command_handlers[] = { { .name = "ulink_download_firmware", .handler = &ulink_download_firmware_handler, .mode = COMMAND_EXEC, .help = "download firmware image to ULINK device", .usage = "path/to/ulink_firmware.hex", }, COMMAND_REGISTRATION_DONE, }; struct jtag_interface ulink_interface = { .name = "ulink", .commands = ulink_command_handlers, .transports = jtag_only, .execute_queue = ulink_execute_queue, .khz = ulink_khz, .speed = ulink_speed, .speed_div = ulink_speed_div, .init = ulink_init, .quit = ulink_quit }; openocd-0.7.0/src/jtag/drivers/libusb_common.h0000644000175000001440000000270512134336410016256 00000000000000/*************************************************************************** * Copyright (C) 2011 by Mauro Gamba * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_LIBUSB1 #include #else #include #endif openocd-0.7.0/src/jtag/drivers/libusb0_common.c0000644000175000001440000000765312137151331016340 00000000000000/*************************************************************************** * Copyright (C) 2009 by Zachary T Welch * * * * Copyright (C) 2011 by Mauro Gamba * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "log.h" #include "libusb0_common.h" static bool jtag_libusb_match(struct jtag_libusb_device *dev, const uint16_t vids[], const uint16_t pids[]) { for (unsigned i = 0; vids[i]; i++) { if (dev->descriptor.idVendor == vids[i] && dev->descriptor.idProduct == pids[i]) { return true; } } return false; } int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[], struct jtag_libusb_device_handle **out) { usb_init(); usb_find_busses(); usb_find_devices(); struct usb_bus *busses = usb_get_busses(); for (struct usb_bus *bus = busses; bus; bus = bus->next) { for (struct usb_device *dev = bus->devices; dev; dev = dev->next) { if (!jtag_libusb_match(dev, vids, pids)) continue; *out = usb_open(dev); if (NULL == *out) return -errno; return 0; } } return -ENODEV; } void jtag_libusb_close(jtag_libusb_device_handle *dev) { /* Close device */ usb_close(dev); } int jtag_libusb_control_transfer(jtag_libusb_device_handle *dev, uint8_t requestType, uint8_t request, uint16_t wValue, uint16_t wIndex, char *bytes, uint16_t size, unsigned int timeout) { int transferred = 0; transferred = usb_control_msg(dev, requestType, request, wValue, wIndex, bytes, size, timeout); if (transferred < 0) transferred = 0; return transferred; } int jtag_libusb_bulk_write(jtag_libusb_device_handle *dev, int ep, char *bytes, int size, int timeout) { return usb_bulk_write(dev, ep, bytes, size, timeout); } int jtag_libusb_bulk_read(jtag_libusb_device_handle *dev, int ep, char *bytes, int size, int timeout) { return usb_bulk_read(dev, ep, bytes, size, timeout); } int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh, int configuration) { struct jtag_libusb_device *udev = jtag_libusb_get_device(devh); return usb_set_configuration(devh, udev->config[configuration].bConfigurationValue); } int jtag_libusb_get_endpoints(struct jtag_libusb_device *udev, unsigned int *usb_read_ep, unsigned int *usb_write_ep) { struct usb_interface *iface = udev->config->interface; struct usb_interface_descriptor *desc = iface->altsetting; for (int i = 0; i < desc->bNumEndpoints; i++) { uint8_t epnum = desc->endpoint[i].bEndpointAddress; bool is_input = epnum & 0x80; LOG_DEBUG("usb ep %s %02x", is_input ? "in" : "out", epnum); if (is_input) *usb_read_ep = epnum; else *usb_write_ep = epnum; } return 0; } openocd-0.7.0/src/jtag/drivers/driver.c0000644000175000001440000003635412134336410014723 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2009 SoftPLC Corporation * * http://softplc.com * * dick@softplc.com * * * * Copyright (C) 2009 Zachary T Welch * * zw@superlucidity.net * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include struct jtag_callback_entry { struct jtag_callback_entry *next; jtag_callback_t callback; jtag_callback_data_t data0; jtag_callback_data_t data1; jtag_callback_data_t data2; jtag_callback_data_t data3; }; static struct jtag_callback_entry *jtag_callback_queue_head; static struct jtag_callback_entry *jtag_callback_queue_tail; static void jtag_callback_queue_reset(void) { jtag_callback_queue_head = NULL; jtag_callback_queue_tail = NULL; } /** * Copy a struct scan_field for insertion into the queue. * * This allocates a new copy of out_value using cmd_queue_alloc. */ static void cmd_queue_scan_field_clone(struct scan_field *dst, const struct scan_field *src) { dst->num_bits = src->num_bits; dst->out_value = buf_cpy(src->out_value, cmd_queue_alloc(DIV_ROUND_UP(src->num_bits, 8)), src->num_bits); dst->in_value = src->in_value; } /** * see jtag_add_ir_scan() * */ int interface_jtag_add_ir_scan(struct jtag_tap *active, const struct scan_field *in_fields, tap_state_t state) { size_t num_taps = jtag_tap_count_enabled(); struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command)); struct scan_command *scan = cmd_queue_alloc(sizeof(struct scan_command)); struct scan_field *out_fields = cmd_queue_alloc(num_taps * sizeof(struct scan_field)); jtag_queue_command(cmd); cmd->type = JTAG_SCAN; cmd->cmd.scan = scan; scan->ir_scan = true; scan->num_fields = num_taps; /* one field per device */ scan->fields = out_fields; scan->end_state = state; struct scan_field *field = out_fields; /* keep track where we insert data */ /* loop over all enabled TAPs */ for (struct jtag_tap *tap = jtag_tap_next_enabled(NULL); tap != NULL; tap = jtag_tap_next_enabled(tap)) { /* search the input field list for fields for the current TAP */ if (tap == active) { /* if TAP is listed in input fields, copy the value */ tap->bypass = 0; cmd_queue_scan_field_clone(field, in_fields); } else { /* if a TAP isn't listed in input fields, set it to BYPASS */ tap->bypass = 1; field->num_bits = tap->ir_length; field->out_value = buf_set_ones(cmd_queue_alloc(DIV_ROUND_UP(tap->ir_length, 8)), tap->ir_length); field->in_value = NULL; /* do not collect input for tap's in bypass */ } /* update device information */ buf_cpy(field->out_value, tap->cur_instr, tap->ir_length); field++; } /* paranoia: jtag_tap_count_enabled() and jtag_tap_next_enabled() not in sync */ assert(field == out_fields + num_taps); return ERROR_OK; } /** * see jtag_add_dr_scan() * */ int interface_jtag_add_dr_scan(struct jtag_tap *active, int in_num_fields, const struct scan_field *in_fields, tap_state_t state) { /* count devices in bypass */ size_t bypass_devices = 0; for (struct jtag_tap *tap = jtag_tap_next_enabled(NULL); tap != NULL; tap = jtag_tap_next_enabled(tap)) { if (tap->bypass) bypass_devices++; } struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command)); struct scan_command *scan = cmd_queue_alloc(sizeof(struct scan_command)); struct scan_field *out_fields = cmd_queue_alloc((in_num_fields + bypass_devices) * sizeof(struct scan_field)); jtag_queue_command(cmd); cmd->type = JTAG_SCAN; cmd->cmd.scan = scan; scan->ir_scan = false; scan->num_fields = in_num_fields + bypass_devices; scan->fields = out_fields; scan->end_state = state; struct scan_field *field = out_fields; /* keep track where we insert data */ /* loop over all enabled TAPs */ for (struct jtag_tap *tap = jtag_tap_next_enabled(NULL); tap != NULL; tap = jtag_tap_next_enabled(tap)) { /* if TAP is not bypassed insert matching input fields */ if (!tap->bypass) { assert(active == tap); #ifndef NDEBUG /* remember initial position for assert() */ struct scan_field *start_field = field; #endif /* NDEBUG */ for (int j = 0; j < in_num_fields; j++) { cmd_queue_scan_field_clone(field, in_fields + j); field++; } assert(field > start_field); /* must have at least one input field per not bypassed TAP */ } /* if a TAP is bypassed, generated a dummy bit*/ else { field->num_bits = 1; field->out_value = NULL; field->in_value = NULL; field++; } } assert(field == out_fields + scan->num_fields); /* no superfluous input fields permitted */ return ERROR_OK; } /** * Generate a DR SCAN using the array of output values passed to the function * * This function assumes that the parameter target_tap specifies the one TAP * that is not bypassed. All other TAPs must be bypassed and the function will * generate a dummy 1bit field for them. * * For the target_tap a sequence of output-only fields will be generated where * each field has the size num_bits and the field's values are taken from * the array value. * * The bypass status of TAPs is set by jtag_add_ir_scan(). * */ void interface_jtag_add_dr_out(struct jtag_tap *target_tap, int in_num_fields, const int *num_bits, const uint32_t *value, tap_state_t end_state) { /* count devices in bypass */ size_t bypass_devices = 0; for (struct jtag_tap *tap = jtag_tap_next_enabled(NULL); tap != NULL; tap = jtag_tap_next_enabled(tap)) { if (tap->bypass) bypass_devices++; } struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command)); struct scan_command *scan = cmd_queue_alloc(sizeof(struct scan_command)); struct scan_field *out_fields = cmd_queue_alloc((in_num_fields + bypass_devices) * sizeof(struct scan_field)); jtag_queue_command(cmd); cmd->type = JTAG_SCAN; cmd->cmd.scan = scan; scan->ir_scan = false; scan->num_fields = in_num_fields + bypass_devices; scan->fields = out_fields; scan->end_state = end_state; bool target_tap_match = false; struct scan_field *field = out_fields; /* keep track where we insert data */ /* loop over all enabled TAPs */ for (struct jtag_tap *tap = jtag_tap_next_enabled(NULL); tap != NULL; tap = jtag_tap_next_enabled(tap)) { /* if TAP is not bypassed insert matching input fields */ if (!tap->bypass) { assert(tap == target_tap); /* target_tap must match the one not bypassed TAP */ target_tap_match = true; for (int j = 0; j < in_num_fields; j++) { uint8_t out_value[4]; size_t scan_size = num_bits[j]; buf_set_u32(out_value, 0, scan_size, value[j]); field->num_bits = scan_size; field->out_value = buf_cpy(out_value, cmd_queue_alloc(DIV_ROUND_UP(scan_size, 8)), scan_size); field->in_value = NULL; field++; } } /* if a TAP is bypassed, generated a dummy bit*/ else { field->num_bits = 1; field->out_value = NULL; field->in_value = NULL; field++; } } assert(target_tap_match); /* target_tap should be enabled and not bypassed */ } static int jtag_add_plain_scan(int num_bits, const uint8_t *out_bits, uint8_t *in_bits, tap_state_t state, bool ir_scan) { struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command)); struct scan_command *scan = cmd_queue_alloc(sizeof(struct scan_command)); struct scan_field *out_fields = cmd_queue_alloc(sizeof(struct scan_field)); jtag_queue_command(cmd); cmd->type = JTAG_SCAN; cmd->cmd.scan = scan; scan->ir_scan = ir_scan; scan->num_fields = 1; scan->fields = out_fields; scan->end_state = state; out_fields->num_bits = num_bits; out_fields->out_value = buf_cpy(out_bits, cmd_queue_alloc(DIV_ROUND_UP(num_bits, 8)), num_bits); out_fields->in_value = in_bits; return ERROR_OK; } int interface_jtag_add_plain_dr_scan(int num_bits, const uint8_t *out_bits, uint8_t *in_bits, tap_state_t state) { return jtag_add_plain_scan(num_bits, out_bits, in_bits, state, false); } int interface_jtag_add_plain_ir_scan(int num_bits, const uint8_t *out_bits, uint8_t *in_bits, tap_state_t state) { return jtag_add_plain_scan(num_bits, out_bits, in_bits, state, true); } int interface_jtag_add_tlr(void) { tap_state_t state = TAP_RESET; /* allocate memory for a new list member */ struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command)); jtag_queue_command(cmd); cmd->type = JTAG_TLR_RESET; cmd->cmd.statemove = cmd_queue_alloc(sizeof(struct statemove_command)); cmd->cmd.statemove->end_state = state; return ERROR_OK; } int interface_add_tms_seq(unsigned num_bits, const uint8_t *seq, enum tap_state state) { struct jtag_command *cmd; cmd = cmd_queue_alloc(sizeof(struct jtag_command)); if (cmd == NULL) return ERROR_FAIL; cmd->type = JTAG_TMS; cmd->cmd.tms = cmd_queue_alloc(sizeof(*cmd->cmd.tms)); if (!cmd->cmd.tms) return ERROR_FAIL; /* copy the bits; our caller doesn't guarantee they'll persist */ cmd->cmd.tms->num_bits = num_bits; cmd->cmd.tms->bits = buf_cpy(seq, cmd_queue_alloc(DIV_ROUND_UP(num_bits, 8)), num_bits); if (!cmd->cmd.tms->bits) return ERROR_FAIL; jtag_queue_command(cmd); return ERROR_OK; } int interface_jtag_add_pathmove(int num_states, const tap_state_t *path) { /* allocate memory for a new list member */ struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command)); jtag_queue_command(cmd); cmd->type = JTAG_PATHMOVE; cmd->cmd.pathmove = cmd_queue_alloc(sizeof(struct pathmove_command)); cmd->cmd.pathmove->num_states = num_states; cmd->cmd.pathmove->path = cmd_queue_alloc(sizeof(tap_state_t) * num_states); for (int i = 0; i < num_states; i++) cmd->cmd.pathmove->path[i] = path[i]; return ERROR_OK; } int interface_jtag_add_runtest(int num_cycles, tap_state_t state) { /* allocate memory for a new list member */ struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command)); jtag_queue_command(cmd); cmd->type = JTAG_RUNTEST; cmd->cmd.runtest = cmd_queue_alloc(sizeof(struct runtest_command)); cmd->cmd.runtest->num_cycles = num_cycles; cmd->cmd.runtest->end_state = state; return ERROR_OK; } int interface_jtag_add_clocks(int num_cycles) { /* allocate memory for a new list member */ struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command)); jtag_queue_command(cmd); cmd->type = JTAG_STABLECLOCKS; cmd->cmd.stableclocks = cmd_queue_alloc(sizeof(struct stableclocks_command)); cmd->cmd.stableclocks->num_cycles = num_cycles; return ERROR_OK; } int interface_jtag_add_reset(int req_trst, int req_srst) { /* allocate memory for a new list member */ struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command)); jtag_queue_command(cmd); cmd->type = JTAG_RESET; cmd->cmd.reset = cmd_queue_alloc(sizeof(struct reset_command)); cmd->cmd.reset->trst = req_trst; cmd->cmd.reset->srst = req_srst; return ERROR_OK; } int interface_jtag_add_sleep(uint32_t us) { /* allocate memory for a new list member */ struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command)); jtag_queue_command(cmd); cmd->type = JTAG_SLEEP; cmd->cmd.sleep = cmd_queue_alloc(sizeof(struct sleep_command)); cmd->cmd.sleep->us = us; return ERROR_OK; } /* add callback to end of queue */ void interface_jtag_add_callback4(jtag_callback_t callback, jtag_callback_data_t data0, jtag_callback_data_t data1, jtag_callback_data_t data2, jtag_callback_data_t data3) { struct jtag_callback_entry *entry = cmd_queue_alloc(sizeof(struct jtag_callback_entry)); entry->next = NULL; entry->callback = callback; entry->data0 = data0; entry->data1 = data1; entry->data2 = data2; entry->data3 = data3; if (jtag_callback_queue_head == NULL) { jtag_callback_queue_head = entry; jtag_callback_queue_tail = entry; } else { jtag_callback_queue_tail->next = entry; jtag_callback_queue_tail = entry; } } int interface_jtag_execute_queue(void) { static int reentry; assert(reentry == 0); reentry++; int retval = default_interface_jtag_execute_queue(); if (retval == ERROR_OK) { struct jtag_callback_entry *entry; for (entry = jtag_callback_queue_head; entry != NULL; entry = entry->next) { retval = entry->callback(entry->data0, entry->data1, entry->data2, entry->data3); if (retval != ERROR_OK) break; } } jtag_command_queue_reset(); jtag_callback_queue_reset(); reentry--; return retval; } static int jtag_convert_to_callback4(jtag_callback_data_t data0, jtag_callback_data_t data1, jtag_callback_data_t data2, jtag_callback_data_t data3) { ((jtag_callback1_t)data1)(data0); return ERROR_OK; } void interface_jtag_add_callback(jtag_callback1_t callback, jtag_callback_data_t data0) { jtag_add_callback4(jtag_convert_to_callback4, data0, (jtag_callback_data_t)callback, 0, 0); } /* A minidriver can use use an inline versions of this API level fn */ void jtag_add_dr_out(struct jtag_tap *tap, int num_fields, const int *num_bits, const uint32_t *value, tap_state_t end_state) { assert(end_state != TAP_RESET); assert(end_state != TAP_INVALID); cmd_queue_cur_state = end_state; interface_jtag_add_dr_out(tap, num_fields, num_bits, value, end_state); } void jtag_add_callback(jtag_callback1_t f, jtag_callback_data_t data0) { interface_jtag_add_callback(f, data0); } void jtag_add_callback4(jtag_callback_t f, jtag_callback_data_t data0, jtag_callback_data_t data1, jtag_callback_data_t data2, jtag_callback_data_t data3) { interface_jtag_add_callback4(f, data0, data1, data2, data3); } openocd-0.7.0/src/jtag/drivers/bitbang.c0000644000175000001440000002421512134336410015027 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "bitbang.h" #include #include /** * Function bitbang_stableclocks * issues a number of clock cycles while staying in a stable state. * Because the TMS value required to stay in the RESET state is a 1, whereas * the TMS value required to stay in any of the other stable states is a 0, * this function checks the current stable state to decide on the value of TMS * to use. */ static void bitbang_stableclocks(int num_cycles); struct bitbang_interface *bitbang_interface; /* DANGER!!!! clock absolutely *MUST* be 0 in idle or reset won't work! * * Set this to 1 and str912 reset halt will fail. * * If someone can submit a patch with an explanation it will be greatly * appreciated, but as far as I can tell (ØH) DCLK is generated upon * clk = 0 in TAP_IDLE. Good luck deducing that from the ARM documentation! * The ARM documentation uses the term "DCLK is asserted while in the TAP_IDLE * state". With hardware there is no such thing as *while* in a state. There * are only edges. So clk => 0 is in fact a very subtle state transition that * happens *while* in the TAP_IDLE state. "#&¤"#¤&"#&"#& * * For "reset halt" the last thing that happens before srst is asserted * is that the breakpoint is set up. If DCLK is not wiggled one last * time before the reset, then the breakpoint is not set up and * "reset halt" will fail to halt. * */ #define CLOCK_IDLE() 0 /* The bitbang driver leaves the TCK 0 when in idle */ static void bitbang_end_state(tap_state_t state) { if (tap_is_state_stable(state)) tap_set_end_state(state); else { LOG_ERROR("BUG: %i is not a valid end state", state); exit(-1); } } static void bitbang_state_move(int skip) { int i = 0, tms = 0; uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state()); int tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); for (i = skip; i < tms_count; i++) { tms = (tms_scan >> i) & 1; bitbang_interface->write(0, tms, 0); bitbang_interface->write(1, tms, 0); } bitbang_interface->write(CLOCK_IDLE(), tms, 0); tap_set_state(tap_get_end_state()); } /** * Clock a bunch of TMS (or SWDIO) transitions, to change the JTAG * (or SWD) state machine. */ static int bitbang_execute_tms(struct jtag_command *cmd) { unsigned num_bits = cmd->cmd.tms->num_bits; const uint8_t *bits = cmd->cmd.tms->bits; DEBUG_JTAG_IO("TMS: %d bits", num_bits); int tms = 0; for (unsigned i = 0; i < num_bits; i++) { tms = ((bits[i/8] >> (i % 8)) & 1); bitbang_interface->write(0, tms, 0); bitbang_interface->write(1, tms, 0); } bitbang_interface->write(CLOCK_IDLE(), tms, 0); return ERROR_OK; } static void bitbang_path_move(struct pathmove_command *cmd) { int num_states = cmd->num_states; int state_count; int tms = 0; state_count = 0; while (num_states) { if (tap_state_transition(tap_get_state(), false) == cmd->path[state_count]) tms = 0; else if (tap_state_transition(tap_get_state(), true) == cmd->path[state_count]) tms = 1; else { LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_name(tap_get_state()), tap_state_name(cmd->path[state_count])); exit(-1); } bitbang_interface->write(0, tms, 0); bitbang_interface->write(1, tms, 0); tap_set_state(cmd->path[state_count]); state_count++; num_states--; } bitbang_interface->write(CLOCK_IDLE(), tms, 0); tap_set_end_state(tap_get_state()); } static void bitbang_runtest(int num_cycles) { int i; tap_state_t saved_end_state = tap_get_end_state(); /* only do a state_move when we're not already in IDLE */ if (tap_get_state() != TAP_IDLE) { bitbang_end_state(TAP_IDLE); bitbang_state_move(0); } /* execute num_cycles */ for (i = 0; i < num_cycles; i++) { bitbang_interface->write(0, 0, 0); bitbang_interface->write(1, 0, 0); } bitbang_interface->write(CLOCK_IDLE(), 0, 0); /* finish in end_state */ bitbang_end_state(saved_end_state); if (tap_get_state() != tap_get_end_state()) bitbang_state_move(0); } static void bitbang_stableclocks(int num_cycles) { int tms = (tap_get_state() == TAP_RESET ? 1 : 0); int i; /* send num_cycles clocks onto the cable */ for (i = 0; i < num_cycles; i++) { bitbang_interface->write(1, tms, 0); bitbang_interface->write(0, tms, 0); } } static void bitbang_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size) { tap_state_t saved_end_state = tap_get_end_state(); int bit_cnt; if (!((!ir_scan && (tap_get_state() == TAP_DRSHIFT)) || (ir_scan && (tap_get_state() == TAP_IRSHIFT)))) { if (ir_scan) bitbang_end_state(TAP_IRSHIFT); else bitbang_end_state(TAP_DRSHIFT); bitbang_state_move(0); bitbang_end_state(saved_end_state); } for (bit_cnt = 0; bit_cnt < scan_size; bit_cnt++) { int val = 0; int tms = (bit_cnt == scan_size-1) ? 1 : 0; int tdi; int bytec = bit_cnt/8; int bcval = 1 << (bit_cnt % 8); /* if we're just reading the scan, but don't care about the output * default to outputting 'low', this also makes valgrind traces more readable, * as it removes the dependency on an uninitialised value */ tdi = 0; if ((type != SCAN_IN) && (buffer[bytec] & bcval)) tdi = 1; bitbang_interface->write(0, tms, tdi); if (type != SCAN_OUT) val = bitbang_interface->read(); bitbang_interface->write(1, tms, tdi); if (type != SCAN_OUT) { if (val) buffer[bytec] |= bcval; else buffer[bytec] &= ~bcval; } } if (tap_get_state() != tap_get_end_state()) { /* we *KNOW* the above loop transitioned out of * the shift state, so we skip the first state * and move directly to the end state. */ bitbang_state_move(1); } } int bitbang_execute_queue(void) { struct jtag_command *cmd = jtag_command_queue; /* currently processed command */ int scan_size; enum scan_type type; uint8_t *buffer; int retval; if (!bitbang_interface) { LOG_ERROR("BUG: Bitbang interface called, but not yet initialized"); exit(-1); } /* return ERROR_OK, unless a jtag_read_buffer returns a failed check * that wasn't handled by a caller-provided error handler */ retval = ERROR_OK; if (bitbang_interface->blink) bitbang_interface->blink(1); while (cmd) { switch (cmd->type) { case JTAG_RESET: #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); #endif if ((cmd->cmd.reset->trst == 1) || (cmd->cmd.reset->srst && (jtag_get_reset_config() & RESET_SRST_PULLS_TRST))) tap_set_state(TAP_RESET); bitbang_interface->reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); break; case JTAG_RUNTEST: #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("runtest %i cycles, end in %s", cmd->cmd.runtest->num_cycles, tap_state_name(cmd->cmd.runtest->end_state)); #endif bitbang_end_state(cmd->cmd.runtest->end_state); bitbang_runtest(cmd->cmd.runtest->num_cycles); break; case JTAG_STABLECLOCKS: /* this is only allowed while in a stable state. A check for a stable * state was done in jtag_add_clocks() */ bitbang_stableclocks(cmd->cmd.stableclocks->num_cycles); break; case JTAG_TLR_RESET: #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("statemove end in %s", tap_state_name(cmd->cmd.statemove->end_state)); #endif bitbang_end_state(cmd->cmd.statemove->end_state); bitbang_state_move(0); break; case JTAG_PATHMOVE: #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("pathmove: %i states, end in %s", cmd->cmd.pathmove->num_states, tap_state_name(cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1])); #endif bitbang_path_move(cmd->cmd.pathmove); break; case JTAG_SCAN: #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("%s scan end in %s", (cmd->cmd.scan->ir_scan) ? "IR" : "DR", tap_state_name(cmd->cmd.scan->end_state)); #endif bitbang_end_state(cmd->cmd.scan->end_state); scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); type = jtag_scan_type(cmd->cmd.scan); bitbang_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size); if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) retval = ERROR_JTAG_QUEUE_FAILED; if (buffer) free(buffer); break; case JTAG_SLEEP: #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("sleep %" PRIi32, cmd->cmd.sleep->us); #endif jtag_sleep(cmd->cmd.sleep->us); break; case JTAG_TMS: retval = bitbang_execute_tms(cmd); break; default: LOG_ERROR("BUG: unknown JTAG command type encountered"); exit(-1); } cmd = cmd->next; } if (bitbang_interface->blink) bitbang_interface->blink(0); return retval; } openocd-0.7.0/src/jtag/drivers/libusb0_common.h0000644000175000001440000000641312137151331016336 00000000000000/*************************************************************************** * Copyright (C) 2009 by Zachary T Welch * * * * Copyright (C) 2011 by Mauro Gamba * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef JTAG_LIBUSB_COMMON_H #define JTAG_LIBUSB_COMMON_H #include #define jtag_libusb_device usb_device #define jtag_libusb_device_handle usb_dev_handle #define jtag_libusb_device_descriptor usb_device_descriptor #define jtag_libusb_interface usb_interface #define jtag_libusb_interface_descriptor usb_interface_descriptor #define jtag_libusb_endpoint_descriptor usb_endpoint_descriptor #define jtag_libusb_config_descriptor usb_config_descriptor #define jtag_libusb_reset_device(dev) usb_reset(dev) #define jtag_libusb_get_device(devh) usb_device(devh) /* make some defines compatible to libusb1 */ #define LIBUSB_REQUEST_TYPE_VENDOR USB_TYPE_VENDOR #define LIBUSB_RECIPIENT_DEVICE USB_RECIP_DEVICE #define LIBUSB_ENDPOINT_OUT USB_ENDPOINT_OUT #define LIBUSB_ENDPOINT_IN USB_ENDPOINT_IN static inline int jtag_libusb_claim_interface(jtag_libusb_device_handle *devh, int iface) { return usb_claim_interface(devh, iface); }; int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[], struct jtag_libusb_device_handle **out); void jtag_libusb_close(jtag_libusb_device_handle *dev); int jtag_libusb_control_transfer(jtag_libusb_device_handle *dev, uint8_t requestType, uint8_t request, uint16_t wValue, uint16_t wIndex, char *bytes, uint16_t size, unsigned int timeout); int jtag_libusb_bulk_write(struct jtag_libusb_device_handle *dev, int ep, char *bytes, int size, int timeout); int jtag_libusb_bulk_read(struct jtag_libusb_device_handle *dev, int ep, char *bytes, int size, int timeout); int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh, int configuration); int jtag_libusb_get_endpoints(struct jtag_libusb_device *udev, unsigned int *usb_read_ep, unsigned int *usb_write_ep); #endif /* JTAG_USB_COMMON_H */ openocd-0.7.0/src/jtag/drivers/usb_common.h0000644000175000001440000000306312134336410015565 00000000000000/*************************************************************************** * Copyright (C) 2009 by Zachary T Welch * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef JTAG_USB_COMMON_H #define JTAG_USB_COMMON_H #include int jtag_usb_open(const uint16_t vids[], const uint16_t pids[], struct usb_dev_handle **out); #endif /* JTAG_USB_COMMON_H */ openocd-0.7.0/src/jtag/drivers/ftd2xx_common.h0000644000175000001440000000565212134336410016221 00000000000000/*************************************************************************** * Copyright (C) 2011 by Spencer Oliver * * * * Written by Arnim Laeuger, 2008 (from urjtag) * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef _FTD2XX_COMMON_H #define _FTD2XX_COMMON_H #if ((BUILD_FT2232_FTD2XX == 1) || (BUILD_PRESTO_FTD2XX == 1) || (BUILD_USB_BLASTER_FTD2XX == 1)) #include static const char *ftd2xx_status_string(FT_STATUS status) { switch (status) { case FT_OK: return "OK"; case FT_INVALID_HANDLE: return "invalid handle"; case FT_DEVICE_NOT_FOUND: return "device not found"; case FT_DEVICE_NOT_OPENED: return "device not opened"; case FT_IO_ERROR: return "io error"; case FT_INSUFFICIENT_RESOURCES: return "insufficient resources"; case FT_INVALID_PARAMETER: return "invalid parameter"; case FT_INVALID_BAUD_RATE: return "invalid baud rate"; case FT_DEVICE_NOT_OPENED_FOR_ERASE: return "device not opened for erase"; case FT_DEVICE_NOT_OPENED_FOR_WRITE: return "device not opened for write"; case FT_FAILED_TO_WRITE_DEVICE: return "failed to write device"; case FT_EEPROM_READ_FAILED: return "eeprom read failed"; case FT_EEPROM_WRITE_FAILED: return "eeprom write failed"; case FT_EEPROM_ERASE_FAILED: return "eeprom erase failed"; case FT_EEPROM_NOT_PRESENT: return "eeprom not present"; case FT_EEPROM_NOT_PROGRAMMED: return "eeprom not programmed"; case FT_INVALID_ARGS: return "invalid args"; case FT_NOT_SUPPORTED: return "not supported"; case FT_OTHER_ERROR: return "other error"; } return "undefined FTD2xx error"; } #endif #endif /* _FTD2XX_COMMON_H */ openocd-0.7.0/src/jtag/drivers/bitq.c0000644000175000001440000002132212134336410014354 00000000000000/*************************************************************************** * Copyright (C) 2007 by Pavel Chromy * * chromy@asix.cz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "bitq.h" #include struct bitq_interface *bitq_interface; /* low level bit queue interface */ /* state of input queue */ struct bitq_state { struct jtag_command *cmd; /* command currently processed */ int field_idx; /* index of field currently being processed */ int bit_pos; /* position of bit currently being processed */ int status; /* processing status */ }; static struct bitq_state bitq_in_state; /* * input queue processing does not use jtag_read_buffer() to avoid unnecessary overhead * no parameters, makes use of stored state information */ static void bitq_in_proc(void) { /* loop through the queue */ while (bitq_in_state.cmd) { /* only JTAG_SCAN command may return data */ if (bitq_in_state.cmd->type == JTAG_SCAN) { /* loop through the fields */ while (bitq_in_state.field_idx < bitq_in_state.cmd->cmd.scan->num_fields) { struct scan_field *field; field = &bitq_in_state.cmd->cmd.scan->fields[bitq_in_state.field_idx]; if (field->in_value) { /* field scanning */ while (bitq_in_state.bit_pos < field->num_bits) { /* index of byte being scanned */ int in_idx = bitq_in_state.bit_pos / 8; /* mask of next bit to be scanned */ uint8_t in_mask = 1 << (bitq_in_state.bit_pos % 8); int tdo = bitq_interface->in(); if (tdo < 0) { #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("bitq in EOF"); #endif return; } if (in_mask == 0x01) field->in_value[in_idx] = 0; if (tdo) field->in_value[in_idx] |= in_mask; bitq_in_state.bit_pos++; } } bitq_in_state.field_idx++; /* advance to next field */ bitq_in_state.bit_pos = 0; /* start next field from the first bit */ } } bitq_in_state.cmd = bitq_in_state.cmd->next; /* advance to next command */ bitq_in_state.field_idx = 0; /* preselect first field */ } } static void bitq_io(int tms, int tdi, int tdo_req) { bitq_interface->out(tms, tdi, tdo_req); /* check and process the input queue */ if (bitq_interface->in_rdy()) bitq_in_proc(); } static void bitq_end_state(tap_state_t state) { if (!tap_is_state_stable(state)) { LOG_ERROR("BUG: %i is not a valid end state", state); exit(-1); } tap_set_end_state(state); } static void bitq_state_move(tap_state_t new_state) { int i = 0; uint8_t tms_scan; if (!tap_is_state_stable(tap_get_state()) || !tap_is_state_stable(new_state)) { LOG_ERROR("TAP move from or to unstable state"); exit(-1); } tms_scan = tap_get_tms_path(tap_get_state(), new_state); int tms_count = tap_get_tms_path_len(tap_get_state(), new_state); for (i = 0; i < tms_count; i++) { bitq_io(tms_scan & 1, 0, 0); tms_scan >>= 1; } tap_set_state(new_state); } static void bitq_path_move(struct pathmove_command *cmd) { int i; for (i = 0; i <= cmd->num_states; i++) { if (tap_state_transition(tap_get_state(), false) == cmd->path[i]) bitq_io(0, 0, 0); else if (tap_state_transition(tap_get_state(), true) == cmd->path[i]) bitq_io(1, 0, 0); else { LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_name( tap_get_state()), tap_state_name(cmd->path[i])); exit(-1); } tap_set_state(cmd->path[i]); } tap_set_end_state(tap_get_state()); } static void bitq_runtest(int num_cycles) { int i; /* only do a state_move when we're not already in IDLE */ if (tap_get_state() != TAP_IDLE) bitq_state_move(TAP_IDLE); /* execute num_cycles */ for (i = 0; i < num_cycles; i++) bitq_io(0, 0, 0); /* finish in end_state */ if (tap_get_state() != tap_get_end_state()) bitq_state_move(tap_get_end_state()); } static void bitq_scan_field(struct scan_field *field, int do_pause) { int bit_cnt; int tdo_req; const uint8_t *out_ptr; uint8_t out_mask; if (field->in_value) tdo_req = 1; else tdo_req = 0; if (field->out_value == NULL) { /* just send zeros and request data from TDO */ for (bit_cnt = field->num_bits; bit_cnt > 1; bit_cnt--) bitq_io(0, 0, tdo_req); bitq_io(do_pause, 0, tdo_req); } else { /* send data, and optionally request TDO */ out_mask = 0x01; out_ptr = field->out_value; for (bit_cnt = field->num_bits; bit_cnt > 1; bit_cnt--) { bitq_io(0, ((*out_ptr) & out_mask) != 0, tdo_req); if (out_mask == 0x80) { out_mask = 0x01; out_ptr++; } else out_mask <<= 1; } bitq_io(do_pause, ((*out_ptr) & out_mask) != 0, tdo_req); } if (do_pause) { bitq_io(0, 0, 0); if (tap_get_state() == TAP_IRSHIFT) tap_set_state(TAP_IRPAUSE); else if (tap_get_state() == TAP_DRSHIFT) tap_set_state(TAP_DRPAUSE); } } static void bitq_scan(struct scan_command *cmd) { int i; if (cmd->ir_scan) bitq_state_move(TAP_IRSHIFT); else bitq_state_move(TAP_DRSHIFT); for (i = 0; i < cmd->num_fields - 1; i++) bitq_scan_field(&cmd->fields[i], 0); bitq_scan_field(&cmd->fields[i], 1); } int bitq_execute_queue(void) { struct jtag_command *cmd = jtag_command_queue; /* currently processed command */ bitq_in_state.cmd = jtag_command_queue; bitq_in_state.field_idx = 0; bitq_in_state.bit_pos = 0; bitq_in_state.status = ERROR_OK; while (cmd) { switch (cmd->type) { case JTAG_RESET: #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); #endif if ((cmd->cmd.reset->trst == 1) || (cmd->cmd.reset->srst && (jtag_get_reset_config() & RESET_SRST_PULLS_TRST))) tap_set_state(TAP_RESET); bitq_interface->reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); if (bitq_interface->in_rdy()) bitq_in_proc(); break; case JTAG_RUNTEST: #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); #endif bitq_end_state(cmd->cmd.runtest->end_state); bitq_runtest(cmd->cmd.runtest->num_cycles); break; case JTAG_TLR_RESET: #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("statemove end in %i", cmd->cmd.statemove->end_state); #endif bitq_end_state(cmd->cmd.statemove->end_state); bitq_state_move(tap_get_end_state()); /* uncoditional TAP move */ break; case JTAG_PATHMOVE: #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("pathmove: %i states, end in %i", cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); #endif bitq_path_move(cmd->cmd.pathmove); break; case JTAG_SCAN: #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("scan end in %i", cmd->cmd.scan->end_state); if (cmd->cmd.scan->ir_scan) LOG_DEBUG("scan ir"); else LOG_DEBUG("scan dr"); #endif bitq_end_state(cmd->cmd.scan->end_state); bitq_scan(cmd->cmd.scan); if (tap_get_state() != tap_get_end_state()) bitq_state_move(tap_get_end_state()); break; case JTAG_SLEEP: #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("sleep %i", cmd->cmd.sleep->us); #endif bitq_interface->sleep(cmd->cmd.sleep->us); if (bitq_interface->in_rdy()) bitq_in_proc(); break; default: LOG_ERROR("BUG: unknown JTAG command type encountered"); exit(-1); } cmd = cmd->next; } bitq_interface->flush(); bitq_in_proc(); if (bitq_in_state.cmd) { LOG_ERROR("missing data from bitq interface"); return ERROR_JTAG_QUEUE_FAILED; } if (bitq_interface->in() >= 0) { LOG_ERROR("extra data from bitq interface"); return ERROR_JTAG_QUEUE_FAILED; } return bitq_in_state.status; } void bitq_cleanup(void) { } openocd-0.7.0/src/jtag/drivers/rlink_st7.h0000644000175000001440000000775512134336410015354 00000000000000/*************************************************************************** * Copyright (C) 2008 Lou Deluxe * * lou.openocd012@fixit.nospammail.net * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #define ST7_FOSC (12 * 1000000) /* This is not a complete enumeration of ST7 registers, but it is sufficient for this interface driver. */ #define ST7_PADR (0x0000) #define ST7_PADDR (ST7_PADR + 1) #define ST7_PAOR (ST7_PADR + 2) #define ST7_PBDR (0x0003) #define ST7_PBDDR (ST7_PBDR + 1) #define ST7_PCDR (0x0006) #define ST7_PCDDR (ST7_PCDR + 1) #define ST7_PCOR (ST7_PCDR + 2) #define ST7_PDDR (0x0009) #define ST7_PDDDR (ST7_PDDR + 1) #define ST7_PDOR (ST7_PDDR + 2) #define ST7_PEDR (0x000c) #define ST7_PEDDR (ST7_PEDR + 1) #define ST7_PEOR (ST7_PEDR + 2) #define ST7_PFDR (0x000f) #define ST7_PFDDR (ST7_PFDR + 1) #define ST7_ADCDR (0x0012) #define ST7_ADCCSR (ST7_ADCDR + 1) #define ST7_EP2TXR (0x003e) #define ST7_EP2TXR_STAT_TX0 (1 << 0) #define ST7_EP2TXR_STAT_TX1 (1 << 1) #define ST7_EP2TXR_STAT_DISABLED (0) #define ST7_EP2TXR_STAT_STALL (ST7_EP2TXR_STAT_TX0) #define ST7_EP2TXR_STAT_VALID (ST7_EP2TXR_STAT_TX1 | ST7_EP2TXR_STAT_TX0) #define ST7_EP2TXR_STAT_NAK (ST7_EP2TXR_STAT_TX1) #define ST7_EP2TXR_DTOG_TX (1 << 2) #define ST7_EP2TXR_CTR_TX (1 << 3) #define ST7_USB_BUF_EP0OUT (0x1550) #define ST7_USB_BUF_EP0IN (0x1560) #define ST7_USB_BUF_EP1OUT (0x1570) #define ST7_USB_BUF_EP1IN (0x1580) #define ST7_USB_BUF_EP2UODI (0x1590) #define ST7_USB_BUF_EP2UIDO (0x1650) #define ST7_PA0 (1 << 0) #define ST7_PA1 (1 << 1) #define ST7_PA2 (1 << 2) #define ST7_PA3 (1 << 3) #define ST7_PA4 (1 << 4) #define ST7_PA5 (1 << 5) #define ST7_PA6 (1 << 6) #define ST7_PA7 (1 << 7) #define ST7_PB0 (1 << 0) #define ST7_PB1 (1 << 1) #define ST7_PB2 (1 << 2) #define ST7_PB3 (1 << 3) #define ST7_PB4 (1 << 4) #define ST7_PB5 (1 << 5) #define ST7_PB6 (1 << 6) #define ST7_PB7 (1 << 7) #define ST7_PC0 (1 << 0) #define ST7_PC1 (1 << 1) #define ST7_PC2 (1 << 2) #define ST7_PC3 (1 << 3) #define ST7_PC4 (1 << 4) #define ST7_PC5 (1 << 5) #define ST7_PC6 (1 << 6) #define ST7_PC7 (1 << 7) #define ST7_PD0 (1 << 0) #define ST7_PD1 (1 << 1) #define ST7_PD2 (1 << 2) #define ST7_PD3 (1 << 3) #define ST7_PD4 (1 << 4) #define ST7_PD5 (1 << 5) #define ST7_PD6 (1 << 6) #define ST7_PD7 (1 << 7) #define ST7_PE0 (1 << 0) #define ST7_PE1 (1 << 1) #define ST7_PE2 (1 << 2) #define ST7_PE3 (1 << 3) #define ST7_PE4 (1 << 4) #define ST7_PE5 (1 << 5) #define ST7_PE6 (1 << 6) #define ST7_PE7 (1 << 7) #define ST7_PF0 (1 << 0) #define ST7_PF1 (1 << 1) #define ST7_PF2 (1 << 2) #define ST7_PF3 (1 << 3) #define ST7_PF4 (1 << 4) #define ST7_PF5 (1 << 5) #define ST7_PF6 (1 << 6) #define ST7_PF7 (1 << 7) openocd-0.7.0/src/jtag/drivers/ep93xx.c0000644000175000001440000001302012137151331014551 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "bitbang.h" #define TDO_BIT 1 #define TDI_BIT 2 #define TCK_BIT 4 #define TMS_BIT 8 #define TRST_BIT 16 #define SRST_BIT 32 #define VCC_BIT 64 #include static uint8_t output_value; static int dev_mem_fd; static void *gpio_controller; static volatile uint8_t *gpio_data_register; static volatile uint8_t *gpio_data_direction_register; /* low level command set */ static int ep93xx_read(void); static void ep93xx_write(int tck, int tms, int tdi); static void ep93xx_reset(int trst, int srst); static int ep93xx_init(void); static int ep93xx_quit(void); struct timespec ep93xx_zzzz; struct jtag_interface ep93xx_interface = { .name = "ep93xx", .supported = DEBUG_CAP_TMS_SEQ, .execute_queue = bitbang_execute_queue, .init = ep93xx_init, .quit = ep93xx_quit, }; static struct bitbang_interface ep93xx_bitbang = { .read = ep93xx_read, .write = ep93xx_write, .reset = ep93xx_reset, .blink = 0, }; static int ep93xx_read(void) { return !!(*gpio_data_register & TDO_BIT); } static void ep93xx_write(int tck, int tms, int tdi) { if (tck) output_value |= TCK_BIT; else output_value &= ~TCK_BIT; if (tms) output_value |= TMS_BIT; else output_value &= ~TMS_BIT; if (tdi) output_value |= TDI_BIT; else output_value &= ~TDI_BIT; *gpio_data_register = output_value; nanosleep(&ep93xx_zzzz, NULL); } /* (1) assert or (0) deassert reset lines */ static void ep93xx_reset(int trst, int srst) { if (trst == 0) output_value |= TRST_BIT; else if (trst == 1) output_value &= ~TRST_BIT; if (srst == 0) output_value |= SRST_BIT; else if (srst == 1) output_value &= ~SRST_BIT; *gpio_data_register = output_value; nanosleep(&ep93xx_zzzz, NULL); } static int set_gonk_mode(void) { void *syscon; uint32_t devicecfg; syscon = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, dev_mem_fd, 0x80930000); if (syscon == MAP_FAILED) { perror("mmap"); return ERROR_JTAG_INIT_FAILED; } devicecfg = *((volatile int *)(syscon + 0x80)); *((volatile int *)(syscon + 0xc0)) = 0xaa; *((volatile int *)(syscon + 0x80)) = devicecfg | 0x08000000; munmap(syscon, 4096); return ERROR_OK; } static int ep93xx_init(void) { int ret; bitbang_interface = &ep93xx_bitbang; ep93xx_zzzz.tv_sec = 0; ep93xx_zzzz.tv_nsec = 10000000; dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC); if (dev_mem_fd < 0) { perror("open"); return ERROR_JTAG_INIT_FAILED; } gpio_controller = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, dev_mem_fd, 0x80840000); if (gpio_controller == MAP_FAILED) { perror("mmap"); close(dev_mem_fd); return ERROR_JTAG_INIT_FAILED; } ret = set_gonk_mode(); if (ret != ERROR_OK) { munmap(gpio_controller, 4096); close(dev_mem_fd); return ret; } #if 0 /* Use GPIO port A. */ gpio_data_register = gpio_controller + 0x00; gpio_data_direction_register = gpio_controller + 0x10; /* Use GPIO port B. */ gpio_data_register = gpio_controller + 0x04; gpio_data_direction_register = gpio_controller + 0x14; /* Use GPIO port C. */ gpio_data_register = gpio_controller + 0x08; gpio_data_direction_register = gpio_controller + 0x18; /* Use GPIO port D. */ gpio_data_register = gpio_controller + 0x0c; gpio_data_direction_register = gpio_controller + 0x1c; #endif /* Use GPIO port C. */ gpio_data_register = gpio_controller + 0x08; gpio_data_direction_register = gpio_controller + 0x18; LOG_INFO("gpio_data_register = %p", gpio_data_register); LOG_INFO("gpio_data_direction_reg = %p", gpio_data_direction_register); /* * Configure bit 0 (TDO) as an input, and bits 1-5 (TDI, TCK * TMS, TRST, SRST) as outputs. Drive TDI and TCK low, and * TMS/TRST/SRST high. */ output_value = TMS_BIT | TRST_BIT | SRST_BIT | VCC_BIT; *gpio_data_register = output_value; nanosleep(&ep93xx_zzzz, NULL); /* * Configure the direction register. 1 = output, 0 = input. */ *gpio_data_direction_register = TDI_BIT | TCK_BIT | TMS_BIT | TRST_BIT | SRST_BIT | VCC_BIT; nanosleep(&ep93xx_zzzz, NULL); return ERROR_OK; } static int ep93xx_quit(void) { return ERROR_OK; } openocd-0.7.0/src/jtag/drivers/osbdm.c0000644000175000001440000004063612137151331014532 00000000000000/*************************************************************************** * Copyright (C) 2012 by Jan Dakinevich * * jan.dakinevich@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include "libusb_common.h" struct sequence { int len; void *tms; void *tdo; const void *tdi; struct sequence *next; }; struct queue { struct sequence *head; struct sequence *tail; }; static struct sequence *queue_add_tail(struct queue *queue, int len) { if (len <= 0) { LOG_ERROR("BUG: sequences with zero length are not allowed"); return NULL; } struct sequence *next; next = (struct sequence *)malloc(sizeof(*next)); if (next) { next->tms = calloc(1, DIV_ROUND_UP(len, 8)); if (next->tms) { next->len = len; next->tdo = NULL; next->tdi = NULL; next->next = NULL; if (!queue->head) { /* Queue is empty at the moment */ queue->head = next; } else { /* Queue already contains at least one sequence */ queue->tail->next = next; } queue->tail = next; } else { free(next); next = NULL; } } if (!next) LOG_ERROR("Not enough memory"); return next; } static void queue_drop_head(struct queue *queue) { struct sequence *head = queue->head->next; /* New head */ free(queue->head->tms); free(queue->head); queue->head = head; } static void queue_free(struct queue *queue) { if (queue) { while (queue->head) queue_drop_head(queue); free(queue); } } static struct queue *queue_alloc(void) { struct queue *queue = (struct queue *)malloc(sizeof(struct queue)); if (queue) queue->head = NULL; else LOG_ERROR("Not enough memory"); return queue; } /* Size of usb communnication buffer */ #define OSBDM_USB_BUFSIZE 64 /* Timeout for USB transfer, ms */ #define OSBDM_USB_TIMEOUT 1000 /* Write end point */ #define OSBDM_USB_EP_WRITE 0x01 /* Read end point */ #define OSBDM_USB_EP_READ 0x82 /* Initialize OSBDM device */ #define OSBDM_CMD_INIT 0x11 /* Execute special, not-BDM command. But only this * command is used for JTAG operation */ #define OSBDM_CMD_SPECIAL 0x27 /* Execute JTAG swap (tms/tdi -> tdo) */ #define OSBDM_CMD_SPECIAL_SWAP 0x05 /* Reset control */ #define OSBDM_CMD_SPECIAL_SRST 0x01 /* Maximum bit-length in one swap */ #define OSBDM_SWAP_MAX (((OSBDM_USB_BUFSIZE - 6) / 5) * 16) /* Lists of valid VID/PID pairs */ static const uint16_t osbdm_vid[] = { 0x15a2, 0x15a2, 0x15a2, 0 }; static const uint16_t osbdm_pid[] = { 0x0042, 0x0058, 0x005e, 0 }; struct osbdm { struct jtag_libusb_device_handle *devh; /* USB handle */ uint8_t buffer[OSBDM_USB_BUFSIZE]; /* Data to send and receive */ int count; /* Count data to send and to read */ }; /* osbdm instance */ static struct osbdm osbdm_context; static int osbdm_send_and_recv(struct osbdm *osbdm) { /* Send request */ int count = jtag_libusb_bulk_write(osbdm->devh, OSBDM_USB_EP_WRITE, (char *)osbdm->buffer, osbdm->count, OSBDM_USB_TIMEOUT); if (count != osbdm->count) { LOG_ERROR("OSBDM communnication error: can't write"); return ERROR_FAIL; } /* Save command code for next checking */ uint8_t cmd_saved = osbdm->buffer[0]; /* Reading answer */ osbdm->count = jtag_libusb_bulk_read(osbdm->devh, OSBDM_USB_EP_READ, (char *)osbdm->buffer, OSBDM_USB_BUFSIZE, OSBDM_USB_TIMEOUT); /* Now perform basic checks for data sent by BDM device */ if (osbdm->count < 0) { LOG_ERROR("OSBDM communnication error: can't read"); return ERROR_FAIL; } if (osbdm->count < 2) { LOG_ERROR("OSBDM communnication error: answer too small"); return ERROR_FAIL; } if (osbdm->count != osbdm->buffer[1]) { LOG_ERROR("OSBDM communnication error: answer size mismatch"); return ERROR_FAIL; } if (cmd_saved != osbdm->buffer[0]) { LOG_ERROR("OSBDM communnication error: answer command mismatch"); return ERROR_FAIL; } return ERROR_OK; } static int osbdm_srst(struct osbdm *osbdm, int srst) { osbdm->count = 0; (void)memset(osbdm->buffer, 0, OSBDM_USB_BUFSIZE); /* Composing request */ osbdm->buffer[osbdm->count++] = OSBDM_CMD_SPECIAL; /* Command */ osbdm->buffer[osbdm->count++] = OSBDM_CMD_SPECIAL_SRST; /* Subcommand */ /* Length in bytes - not used */ osbdm->buffer[osbdm->count++] = 0; osbdm->buffer[osbdm->count++] = 0; /* SRST state */ osbdm->buffer[osbdm->count++] = (srst ? 0 : 0x08); /* Sending data */ if (osbdm_send_and_recv(osbdm) != ERROR_OK) return ERROR_FAIL; return ERROR_OK; } static int osbdm_swap(struct osbdm *osbdm, void *tms, void *tdi, void *tdo, int length) { if (length > OSBDM_SWAP_MAX) { LOG_ERROR("BUG: bit sequence too long"); return ERROR_FAIL; } if (length <= 0) { LOG_ERROR("BUG: bit sequence equal or less to 0"); return ERROR_FAIL; } int swap_count = DIV_ROUND_UP(length, 16); /* cleanup */ osbdm->count = 0; (void)memset(osbdm->buffer, 0, OSBDM_USB_BUFSIZE); /* Composing request */ osbdm->buffer[osbdm->count++] = OSBDM_CMD_SPECIAL; /* Command */ osbdm->buffer[osbdm->count++] = OSBDM_CMD_SPECIAL_SWAP; /* Subcommand */ /* Length in bytes - not used */ osbdm->buffer[osbdm->count++] = 0; osbdm->buffer[osbdm->count++] = 0; /* Swap count */ osbdm->buffer[osbdm->count++] = 0; osbdm->buffer[osbdm->count++] = (uint8_t)swap_count; for (int bit_idx = 0; bit_idx < length; ) { /* Bit count in swap */ int bit_count = length - bit_idx; if (bit_count > 16) bit_count = 16; osbdm->buffer[osbdm->count++] = (uint8_t)bit_count; /* Copying TMS and TDI data to output buffer */ uint32_t tms_data = buf_get_u32(tms, bit_idx, bit_count); uint32_t tdi_data = buf_get_u32(tdi, bit_idx, bit_count); osbdm->buffer[osbdm->count++] = (uint8_t)(tdi_data >> 8); osbdm->buffer[osbdm->count++] = (uint8_t)tdi_data; osbdm->buffer[osbdm->count++] = (uint8_t)(tms_data >> 8); osbdm->buffer[osbdm->count++] = (uint8_t)tms_data; /* Next bit offset */ bit_idx += bit_count; } assert(osbdm->count <= OSBDM_USB_BUFSIZE); /* Sending data */ if (osbdm_send_and_recv(osbdm) != ERROR_OK) return ERROR_FAIL; /* Extra check */ if (((osbdm->buffer[2] << 8) | osbdm->buffer[3]) != 2 * swap_count) { LOG_ERROR("OSBDM communnication error: not proper answer to swap command"); return ERROR_FAIL; } /* Copy TDO responce */ uint8_t *buffer = (uint8_t *)osbdm->buffer + 4; for (int bit_idx = 0; bit_idx < length; ) { int bit_count = length - bit_idx; if (bit_count > 16) bit_count = 16; /* Prepare data */ uint32_t tdo_data = 0; tdo_data |= (*buffer++) << 8; tdo_data |= (*buffer++); tdo_data >>= (16 - bit_count); /* Copy TDO to return */ buf_set_u32(tdo, bit_idx, bit_count, tdo_data); bit_idx += bit_count; } return ERROR_OK; } static int osbdm_flush(struct osbdm *osbdm, struct queue* queue) { uint8_t tms[DIV_ROUND_UP(OSBDM_SWAP_MAX, 8)]; uint8_t tdi[DIV_ROUND_UP(OSBDM_SWAP_MAX, 8)]; uint8_t tdo[DIV_ROUND_UP(OSBDM_SWAP_MAX, 8)]; int seq_back_len = 0; while (queue->head) { (void)memset(tms, 0, sizeof(tms)); (void)memset(tdi, 0, sizeof(tdi)); (void)memset(tdo, 0, sizeof(tdo)); int seq_len; int swap_len; struct sequence *seq; /* Copy from queue to tms/tdi streams */ seq = queue->head; seq_len = seq_back_len; swap_len = 0; while (seq && swap_len != OSBDM_SWAP_MAX) { /* Count bit for copy at this iteration. * len should fit into remaining space * in tms/tdo bitstreams */ int len = seq->len - seq_len; if (len > OSBDM_SWAP_MAX - swap_len) len = OSBDM_SWAP_MAX - swap_len; /* Set tms data */ buf_set_buf(seq->tms, seq_len, tms, swap_len, len); /* Set tdi data if they exists */ if (seq->tdi) buf_set_buf(seq->tdi, seq_len, tdi, swap_len, len); swap_len += len; seq_len += len; if (seq_len == seq->len) { seq = seq->next; /* Move to next sequence */ seq_len = 0; } } if (osbdm_swap(osbdm, tms, tdi, tdo, swap_len)) return ERROR_FAIL; /* Copy from tdo stream to queue */ for (int swap_back_len = 0; swap_back_len < swap_len; ) { int len = queue->head->len - seq_back_len; if (len > swap_len - swap_back_len) len = swap_len - swap_back_len; if (queue->head->tdo) buf_set_buf(tdo, swap_back_len, queue->head->tdo, seq_back_len, len); swap_back_len += len; seq_back_len += len; if (seq_back_len == queue->head->len) { queue_drop_head(queue); seq_back_len = 0; } } } return ERROR_OK; } /* Basic operation for opening USB device */ static int osbdm_open(struct osbdm *osbdm) { (void)memset(osbdm, 0, sizeof(*osbdm)); if (jtag_libusb_open(osbdm_vid, osbdm_pid, &osbdm->devh) != ERROR_OK) return ERROR_FAIL; if (jtag_libusb_claim_interface(osbdm->devh, 0) != ERROR_OK) return ERROR_FAIL; return ERROR_OK; } static int osbdm_quit(void) { jtag_libusb_close(osbdm_context.devh); return ERROR_OK; } static int osbdm_add_pathmove( struct queue *queue, tap_state_t *path, int num_states) { assert(num_states <= 32); struct sequence *next = queue_add_tail(queue, num_states); if (!next) { LOG_ERROR("BUG: can't allocate bit sequence"); return ERROR_FAIL; } uint32_t tms = 0; for (int i = 0; i < num_states; i++) { if (tap_state_transition(tap_get_state(), 1) == path[i]) { tms |= (1 << i); } else if (tap_state_transition(tap_get_state(), 0) == path[i]) { tms &= ~(1 << i); /* This line not so needed */ } else { LOG_ERROR("BUG: %s -> %s isn't a valid TAP state transition", tap_state_name(tap_get_state()), tap_state_name(path[i])); return ERROR_FAIL; } tap_set_state(path[i]); } buf_set_u32(next->tms, 0, num_states, tms); tap_set_end_state(tap_get_state()); return ERROR_OK; } static int osbdm_add_statemove( struct queue *queue, tap_state_t new_state, int skip_first) { int len = 0; int tms; tap_set_end_state(new_state); if (tap_get_end_state() == TAP_RESET) { /* Ignore current state */ tms = 0xff; len = 5; } else if (tap_get_state() != tap_get_end_state()) { tms = tap_get_tms_path(tap_get_state(), new_state); len = tap_get_tms_path_len(tap_get_state(), new_state); } if (len && skip_first) { len--; tms >>= 1; } if (len) { struct sequence *next = queue_add_tail(queue, len); if (!next) { LOG_ERROR("BUG: can't allocate bit sequence"); return ERROR_FAIL; } buf_set_u32(next->tms, 0, len, tms); } tap_set_state(tap_get_end_state()); return ERROR_OK; } static int osbdm_add_stableclocks( struct queue *queue, int count) { if (!tap_is_state_stable(tap_get_state())) { LOG_ERROR("BUG: current state (%s) is not stable", tap_state_name(tap_get_state())); return ERROR_FAIL; } struct sequence *next = queue_add_tail(queue, count); if (!next) { LOG_ERROR("BUG: can't allocate bit sequence"); return ERROR_FAIL; } if (tap_get_state() == TAP_RESET) (void)memset(next->tms, 0xff, DIV_ROUND_UP(count, 8)); return ERROR_OK; } static int osbdm_add_tms( struct queue *queue, const uint8_t *tms, int num_bits) { struct sequence *next = queue_add_tail(queue, num_bits); if (!next) { LOG_ERROR("BUG: can't allocate bit sequence"); return ERROR_FAIL; } buf_set_buf(tms, 0, next->tms, 0, num_bits); return ERROR_OK; } static int osbdm_add_scan( struct queue *queue, struct scan_field *fields, int num_fields, tap_state_t end_state, bool ir_scan) { /* Move to desired shift state */ if (ir_scan) { if (tap_get_state() != TAP_IRSHIFT) { if (osbdm_add_statemove(queue, TAP_IRSHIFT, 0) != ERROR_OK) return ERROR_FAIL; } } else { if (tap_get_state() != TAP_DRSHIFT) { if (osbdm_add_statemove(queue, TAP_DRSHIFT, 0) != ERROR_OK) return ERROR_FAIL; } } /* Add scan */ tap_set_end_state(end_state); for (int idx = 0; idx < num_fields; idx++) { struct sequence *next = queue_add_tail(queue, fields[idx].num_bits); if (!next) { LOG_ERROR("Can't allocate bit sequence"); return ERROR_FAIL; } (void)memset(next->tms, 0, DIV_ROUND_UP(fields[idx].num_bits, 8)); next->tdi = fields[idx].out_value; next->tdo = fields[idx].in_value; } /* Move to end state */ if (tap_get_state() != tap_get_end_state()) { /* Exit from IRSHIFT/DRSHIFT */ buf_set_u32(queue->tail->tms, queue->tail->len - 1, 1, 1); /* Move with skip_first flag */ if (osbdm_add_statemove(queue, tap_get_end_state(), 1) != ERROR_OK) return ERROR_FAIL; } return ERROR_OK; } static int osbdm_add_runtest( struct queue *queue, int num_cycles, tap_state_t end_state) { if (osbdm_add_statemove(queue, TAP_IDLE, 0) != ERROR_OK) return ERROR_FAIL; if (osbdm_add_stableclocks(queue, num_cycles) != ERROR_OK) return ERROR_FAIL; if (osbdm_add_statemove(queue, end_state, 0) != ERROR_OK) return ERROR_FAIL; return ERROR_OK; } static int osbdm_execute_command( struct osbdm *osbdm, struct queue *queue, struct jtag_command *cmd) { int retval = ERROR_OK; switch (cmd->type) { case JTAG_RESET: if (cmd->cmd.reset->trst) { LOG_ERROR("BUG: nTRST signal is not supported"); retval = ERROR_FAIL; } else { retval = osbdm_flush(osbdm, queue); if (retval == ERROR_OK) retval = osbdm_srst(osbdm, cmd->cmd.reset->srst); } break; case JTAG_PATHMOVE: retval = osbdm_add_pathmove( queue, cmd->cmd.pathmove->path, cmd->cmd.pathmove->num_states); break; case JTAG_TLR_RESET: retval = osbdm_add_statemove( queue, cmd->cmd.statemove->end_state, 0); break; case JTAG_STABLECLOCKS: retval = osbdm_add_stableclocks( queue, cmd->cmd.stableclocks->num_cycles); break; case JTAG_TMS: retval = osbdm_add_tms( queue, cmd->cmd.tms->bits, cmd->cmd.tms->num_bits); break; case JTAG_SCAN: retval = osbdm_add_scan( queue, cmd->cmd.scan->fields, cmd->cmd.scan->num_fields, cmd->cmd.scan->end_state, cmd->cmd.scan->ir_scan); break; case JTAG_SLEEP: retval = osbdm_flush(osbdm, queue); if (retval == ERROR_OK) jtag_sleep(cmd->cmd.sleep->us); break; case JTAG_RUNTEST: retval = osbdm_add_runtest( queue, cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); break; default: LOG_ERROR("BUG: unknown JTAG command type encountered"); retval = ERROR_FAIL; break; } return retval; } static int osbdm_execute_queue(void) { int retval = ERROR_OK; struct queue *queue = queue_alloc(); if (!queue) { LOG_ERROR("BUG: can't allocate bit queue"); retval = ERROR_FAIL; } else { struct jtag_command *cmd = jtag_command_queue; while (retval == ERROR_OK && cmd) { retval = osbdm_execute_command(&osbdm_context, queue, cmd); cmd = cmd->next; } if (retval == ERROR_OK) retval = osbdm_flush(&osbdm_context, queue); queue_free(queue); } if (retval != ERROR_OK) { LOG_ERROR("FATAL: can't execute jtag command"); exit(-1); } return retval; } static int osbdm_init(void) { /* Open device */ if (osbdm_open(&osbdm_context) != ERROR_OK) { LOG_ERROR("Can't open OSBDM device"); return ERROR_FAIL; } else { /* Device successfully opened */ LOG_INFO("OSBDM has opened"); } /* Perform initialize command */ osbdm_context.count = 0; osbdm_context.buffer[osbdm_context.count++] = OSBDM_CMD_INIT; if (osbdm_send_and_recv(&osbdm_context) != ERROR_OK) return ERROR_FAIL; return ERROR_OK; } struct jtag_interface osbdm_interface = { .name = "osbdm", .transports = jtag_only, .execute_queue = osbdm_execute_queue, .init = osbdm_init, .quit = osbdm_quit }; openocd-0.7.0/src/jtag/drivers/mpsse.c0000644000175000001440000005746612137151331014566 00000000000000/************************************************************************** * Copyright (C) 2012 by Andreas Fritiofson * * andreas.fritiofson@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "mpsse.h" #include "helper/log.h" #include /* Compatibility define for older libusb-1.0 */ #ifndef LIBUSB_CALL #define LIBUSB_CALL #endif #ifdef _DEBUG_JTAG_IO_ #define DEBUG_IO(expr...) LOG_DEBUG(expr) #define DEBUG_PRINT_BUF(buf, len) \ do { \ char buf_string[32 * 3 + 1]; \ int buf_string_pos = 0; \ for (int i = 0; i < len; i++) { \ buf_string_pos += sprintf(buf_string + buf_string_pos, " %02x", buf[i]); \ if (i % 32 == 32 - 1) { \ LOG_DEBUG("%s", buf_string); \ buf_string_pos = 0; \ } \ } \ if (buf_string_pos > 0) \ LOG_DEBUG("%s", buf_string);\ } while (0) #else #define DEBUG_IO(expr...) do {} while (0) #define DEBUG_PRINT_BUF(buf, len) do {} while (0) #endif #define FTDI_DEVICE_OUT_REQTYPE (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE) #define FTDI_DEVICE_IN_REQTYPE (0x80 | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE) #define BITMODE_MPSSE 0x02 #define SIO_RESET_REQUEST 0x00 #define SIO_SET_LATENCY_TIMER_REQUEST 0x09 #define SIO_GET_LATENCY_TIMER_REQUEST 0x0A #define SIO_SET_BITMODE_REQUEST 0x0B #define SIO_RESET_SIO 0 #define SIO_RESET_PURGE_RX 1 #define SIO_RESET_PURGE_TX 2 struct mpsse_ctx { libusb_context *usb_ctx; libusb_device_handle *usb_dev; unsigned int usb_write_timeout; unsigned int usb_read_timeout; uint8_t in_ep; uint8_t out_ep; uint16_t max_packet_size; uint16_t index; uint8_t interface; enum ftdi_chip_type type; uint8_t *write_buffer; unsigned write_size; unsigned write_count; uint8_t *read_buffer; unsigned read_size; unsigned read_count; uint8_t *read_chunk; unsigned read_chunk_size; struct bit_copy_queue read_queue; }; /* Returns true if the string descriptor indexed by str_index in device matches string */ static bool string_descriptor_equal(libusb_device_handle *device, uint8_t str_index, const char *string) { int retval; char desc_string[256]; /* Max size of string descriptor */ retval = libusb_get_string_descriptor_ascii(device, str_index, (unsigned char *)desc_string, sizeof(desc_string)); if (retval < 0) { LOG_ERROR("libusb_get_string_descriptor_ascii() failed with %d", retval); return false; } return strncmp(string, desc_string, sizeof(desc_string)) == 0; } /* Helper to open a libusb device that matches vid, pid, product string and/or serial string. * Set any field to 0 as a wildcard. If the device is found true is returned, with ctx containing * the already opened handle. ctx->interface must be set to the desired interface (channel) number * prior to calling this function. */ static bool open_matching_device(struct mpsse_ctx *ctx, const uint16_t *vid, const uint16_t *pid, const char *product, const char *serial) { libusb_device **list; struct libusb_device_descriptor desc; struct libusb_config_descriptor *config0; int err; bool found = false; ssize_t cnt = libusb_get_device_list(ctx->usb_ctx, &list); if (cnt < 0) LOG_ERROR("libusb_get_device_list() failed with %zi", cnt); for (ssize_t i = 0; i < cnt; i++) { libusb_device *device = list[i]; err = libusb_get_device_descriptor(device, &desc); if (err != LIBUSB_SUCCESS) { LOG_ERROR("libusb_get_device_descriptor() failed with %d", err); continue; } if (vid && *vid != desc.idVendor) continue; if (pid && *pid != desc.idProduct) continue; err = libusb_open(device, &ctx->usb_dev); if (err != LIBUSB_SUCCESS) { LOG_ERROR("libusb_open() failed with %d", err); continue; } if (product && !string_descriptor_equal(ctx->usb_dev, desc.iProduct, product)) { libusb_close(ctx->usb_dev); continue; } if (serial && !string_descriptor_equal(ctx->usb_dev, desc.iSerialNumber, serial)) { libusb_close(ctx->usb_dev); continue; } found = true; break; } libusb_free_device_list(list, 1); if (!found) { LOG_ERROR("no device found"); return false; } err = libusb_get_config_descriptor(libusb_get_device(ctx->usb_dev), 0, &config0); if (err != LIBUSB_SUCCESS) { LOG_ERROR("libusb_get_config_descriptor() failed with %d", err); libusb_close(ctx->usb_dev); return false; } /* Make sure the first configuration is selected */ int cfg; err = libusb_get_configuration(ctx->usb_dev, &cfg); if (err != LIBUSB_SUCCESS) { LOG_ERROR("libusb_get_configuration() failed with %d", err); goto error; } if (desc.bNumConfigurations > 0 && cfg != config0->bConfigurationValue) { err = libusb_set_configuration(ctx->usb_dev, config0->bConfigurationValue); if (err != LIBUSB_SUCCESS) { LOG_ERROR("libusb_set_configuration() failed with %d", err); goto error; } } /* Try to detach ftdi_sio kernel module */ err = libusb_detach_kernel_driver(ctx->usb_dev, ctx->interface); if (err != LIBUSB_SUCCESS && err != LIBUSB_ERROR_NOT_FOUND && err != LIBUSB_ERROR_NOT_SUPPORTED) { LOG_ERROR("libusb_detach_kernel_driver() failed with %d", err); goto error; } err = libusb_claim_interface(ctx->usb_dev, ctx->interface); if (err != LIBUSB_SUCCESS) { LOG_ERROR("libusb_claim_interface() failed with %d", err); goto error; } /* Reset FTDI device */ err = libusb_control_transfer(ctx->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST, SIO_RESET_SIO, ctx->index, NULL, 0, ctx->usb_write_timeout); if (err < 0) { LOG_ERROR("failed to reset FTDI device: %d", err); goto error; } switch (desc.bcdDevice) { case 0x500: ctx->type = TYPE_FT2232C; break; case 0x700: ctx->type = TYPE_FT2232H; break; case 0x800: ctx->type = TYPE_FT4232H; break; case 0x900: ctx->type = TYPE_FT232H; break; default: LOG_ERROR("unsupported FTDI chip type: 0x%04x", desc.bcdDevice); goto error; } /* Determine maximum packet size and endpoint addresses */ if (!(desc.bNumConfigurations > 0 && ctx->interface < config0->bNumInterfaces && config0->interface[ctx->interface].num_altsetting > 0)) goto desc_error; const struct libusb_interface_descriptor *descriptor; descriptor = &config0->interface[ctx->interface].altsetting[0]; if (descriptor->bNumEndpoints != 2) goto desc_error; ctx->in_ep = 0; ctx->out_ep = 0; for (int i = 0; i < descriptor->bNumEndpoints; i++) { if (descriptor->endpoint[i].bEndpointAddress & 0x80) { ctx->in_ep = descriptor->endpoint[i].bEndpointAddress; ctx->max_packet_size = descriptor->endpoint[i].wMaxPacketSize; } else { ctx->out_ep = descriptor->endpoint[i].bEndpointAddress; } } if (ctx->in_ep == 0 || ctx->out_ep == 0) goto desc_error; libusb_free_config_descriptor(config0); return true; desc_error: LOG_ERROR("unrecognized USB device descriptor"); error: libusb_free_config_descriptor(config0); libusb_close(ctx->usb_dev); return false; } struct mpsse_ctx *mpsse_open(const uint16_t *vid, const uint16_t *pid, const char *description, const char *serial, int channel) { struct mpsse_ctx *ctx = calloc(1, sizeof(*ctx)); int err; if (!ctx) return 0; bit_copy_queue_init(&ctx->read_queue); ctx->read_chunk_size = 16384; ctx->read_size = 16384; ctx->write_size = 16384; ctx->read_chunk = malloc(ctx->read_chunk_size); ctx->read_buffer = malloc(ctx->read_size); ctx->write_buffer = malloc(ctx->write_size); if (!ctx->read_chunk || !ctx->read_buffer || !ctx->write_buffer) goto error; ctx->interface = channel; ctx->index = channel + 1; ctx->usb_read_timeout = 5000; ctx->usb_write_timeout = 5000; err = libusb_init(&ctx->usb_ctx); if (err != LIBUSB_SUCCESS) { LOG_ERROR("libusb_init() failed with %d", err); goto error; } if (!open_matching_device(ctx, vid, pid, description, serial)) { /* Four hex digits plus terminating zero each */ char vidstr[5]; char pidstr[5]; LOG_ERROR("unable to open ftdi device with vid %s, pid %s, description '%s' and " "serial '%s'", vid ? sprintf(vidstr, "%04x", *vid), vidstr : "*", pid ? sprintf(pidstr, "%04x", *pid), pidstr : "*", description ? description : "*", serial ? serial : "*"); ctx->usb_dev = 0; goto error; } err = libusb_control_transfer(ctx->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_SET_LATENCY_TIMER_REQUEST, 255, ctx->index, NULL, 0, ctx->usb_write_timeout); if (err < 0) { LOG_ERROR("unable to set latency timer: %d", err); goto error; } err = libusb_control_transfer(ctx->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_SET_BITMODE_REQUEST, 0x0b | (BITMODE_MPSSE << 8), ctx->index, NULL, 0, ctx->usb_write_timeout); if (err < 0) { LOG_ERROR("unable to set MPSSE bitmode: %d", err); goto error; } mpsse_purge(ctx); return ctx; error: mpsse_close(ctx); return 0; } void mpsse_close(struct mpsse_ctx *ctx) { if (ctx->usb_dev) libusb_close(ctx->usb_dev); if (ctx->usb_ctx) libusb_exit(ctx->usb_ctx); bit_copy_discard(&ctx->read_queue); if (ctx->write_buffer) free(ctx->write_buffer); if (ctx->read_buffer) free(ctx->read_buffer); if (ctx->read_chunk) free(ctx->read_chunk); free(ctx); } bool mpsse_is_high_speed(struct mpsse_ctx *ctx) { return ctx->type != TYPE_FT2232C; } void mpsse_purge(struct mpsse_ctx *ctx) { int err; LOG_DEBUG("-"); ctx->write_count = 0; ctx->read_count = 0; bit_copy_discard(&ctx->read_queue); err = libusb_control_transfer(ctx->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST, SIO_RESET_PURGE_RX, ctx->index, NULL, 0, ctx->usb_write_timeout); if (err < 0) { LOG_ERROR("unable to purge ftdi rx buffers: %d", err); return; } err = libusb_control_transfer(ctx->usb_dev, FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST, SIO_RESET_PURGE_TX, ctx->index, NULL, 0, ctx->usb_write_timeout); if (err < 0) { LOG_ERROR("unable to purge ftdi tx buffers: %d", err); return; } } static unsigned buffer_write_space(struct mpsse_ctx *ctx) { /* Reserve one byte for SEND_IMMEDIATE */ return ctx->write_size - ctx->write_count - 1; } static unsigned buffer_read_space(struct mpsse_ctx *ctx) { return ctx->read_size - ctx->read_count; } static void buffer_write_byte(struct mpsse_ctx *ctx, uint8_t data) { DEBUG_IO("%02x", data); assert(ctx->write_count < ctx->write_size); ctx->write_buffer[ctx->write_count++] = data; } static unsigned buffer_write(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, unsigned bit_count) { DEBUG_IO("%d bits", bit_count); assert(ctx->write_count + DIV_ROUND_UP(bit_count, 8) <= ctx->write_size); bit_copy(ctx->write_buffer + ctx->write_count, 0, out, out_offset, bit_count); ctx->write_count += DIV_ROUND_UP(bit_count, 8); return bit_count; } static unsigned buffer_add_read(struct mpsse_ctx *ctx, uint8_t *in, unsigned in_offset, unsigned bit_count, unsigned offset) { DEBUG_IO("%d bits, offset %d", bit_count, offset); assert(ctx->read_count + DIV_ROUND_UP(bit_count, 8) <= ctx->read_size); bit_copy_queued(&ctx->read_queue, in, in_offset, ctx->read_buffer + ctx->read_count, offset, bit_count); ctx->read_count += DIV_ROUND_UP(bit_count, 8); return bit_count; } int mpsse_clock_data_out(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, unsigned length, uint8_t mode) { return mpsse_clock_data(ctx, out, out_offset, 0, 0, length, mode); } int mpsse_clock_data_in(struct mpsse_ctx *ctx, uint8_t *in, unsigned in_offset, unsigned length, uint8_t mode) { return mpsse_clock_data(ctx, 0, 0, in, in_offset, length, mode); } int mpsse_clock_data(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, uint8_t *in, unsigned in_offset, unsigned length, uint8_t mode) { /* TODO: Fix MSB first modes */ DEBUG_IO("%s%s %d bits", in ? "in" : "", out ? "out" : "", length); int retval = ERROR_OK; /* TODO: On H chips, use command 0x8E/0x8F if in and out are both 0 */ if (out || (!out && !in)) mode |= 0x10; if (in) mode |= 0x20; while (length > 0) { /* Guarantee buffer space enough for a minimum size transfer */ if (buffer_write_space(ctx) + (length < 8) < (out || (!out && !in) ? 4 : 3) || (in && buffer_read_space(ctx) < 1)) retval = mpsse_flush(ctx); if (length < 8) { /* Transfer remaining bits in bit mode */ buffer_write_byte(ctx, 0x02 | mode); buffer_write_byte(ctx, length - 1); if (out) out_offset += buffer_write(ctx, out, out_offset, length); if (in) in_offset += buffer_add_read(ctx, in, in_offset, length, 8 - length); if (!out && !in) buffer_write_byte(ctx, 0x00); length = 0; } else { /* Byte transfer */ unsigned this_bytes = length / 8; /* MPSSE command limit */ if (this_bytes > 65536) this_bytes = 65536; /* Buffer space limit. We already made sure there's space for the minimum * transfer. */ if ((out || (!out && !in)) && this_bytes + 3 > buffer_write_space(ctx)) this_bytes = buffer_write_space(ctx) - 3; if (in && this_bytes > buffer_read_space(ctx)) this_bytes = buffer_read_space(ctx); if (this_bytes > 0) { buffer_write_byte(ctx, mode); buffer_write_byte(ctx, (this_bytes - 1) & 0xff); buffer_write_byte(ctx, (this_bytes - 1) >> 8); if (out) out_offset += buffer_write(ctx, out, out_offset, this_bytes * 8); if (in) in_offset += buffer_add_read(ctx, in, in_offset, this_bytes * 8, 0); if (!out && !in) for (unsigned n = 0; n < this_bytes; n++) buffer_write_byte(ctx, 0x00); length -= this_bytes * 8; } } } return retval; } int mpsse_clock_tms_cs_out(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, unsigned length, bool tdi, uint8_t mode) { return mpsse_clock_tms_cs(ctx, out, out_offset, 0, 0, length, tdi, mode); } int mpsse_clock_tms_cs(struct mpsse_ctx *ctx, const uint8_t *out, unsigned out_offset, uint8_t *in, unsigned in_offset, unsigned length, bool tdi, uint8_t mode) { DEBUG_IO("%sout %d bits, tdi=%d", in ? "in" : "", length, tdi); assert(out); int retval = ERROR_OK; mode |= 0x42; if (in) mode |= 0x20; while (length > 0) { /* Guarantee buffer space enough for a minimum size transfer */ if (buffer_write_space(ctx) < 3 || (in && buffer_read_space(ctx) < 1)) retval = mpsse_flush(ctx); /* Byte transfer */ unsigned this_bits = length; /* MPSSE command limit */ /* NOTE: there's a report of an FT2232 bug in this area, where shifting * exactly 7 bits can make problems with TMS signaling for the last * clock cycle: * * http://developer.intra2net.com/mailarchive/html/libftdi/2009/msg00292.html */ if (this_bits > 7) this_bits = 7; if (this_bits > 0) { buffer_write_byte(ctx, mode); buffer_write_byte(ctx, this_bits - 1); uint8_t data = 0; /* TODO: Fix MSB first, if allowed in MPSSE */ bit_copy(&data, 0, out, out_offset, this_bits); out_offset += this_bits; buffer_write_byte(ctx, data | (tdi ? 0x80 : 0x00)); if (in) in_offset += buffer_add_read(ctx, in, in_offset, this_bits, 8 - this_bits); length -= this_bits; } } return retval; } int mpsse_set_data_bits_low_byte(struct mpsse_ctx *ctx, uint8_t data, uint8_t dir) { DEBUG_IO("-"); int retval = ERROR_OK; if (buffer_write_space(ctx) < 3) retval = mpsse_flush(ctx); buffer_write_byte(ctx, 0x80); buffer_write_byte(ctx, data); buffer_write_byte(ctx, dir); return retval; } int mpsse_set_data_bits_high_byte(struct mpsse_ctx *ctx, uint8_t data, uint8_t dir) { DEBUG_IO("-"); int retval = ERROR_OK; if (buffer_write_space(ctx) < 3) retval = mpsse_flush(ctx); buffer_write_byte(ctx, 0x82); buffer_write_byte(ctx, data); buffer_write_byte(ctx, dir); return retval; } int mpsse_read_data_bits_low_byte(struct mpsse_ctx *ctx, uint8_t *data) { DEBUG_IO("-"); int retval = ERROR_OK; if (buffer_write_space(ctx) < 1) retval = mpsse_flush(ctx); buffer_write_byte(ctx, 0x81); buffer_add_read(ctx, data, 0, 8, 0); return retval; } int mpsse_read_data_bits_high_byte(struct mpsse_ctx *ctx, uint8_t *data) { DEBUG_IO("-"); int retval = ERROR_OK; if (buffer_write_space(ctx) < 1) retval = mpsse_flush(ctx); buffer_write_byte(ctx, 0x83); buffer_add_read(ctx, data, 0, 8, 0); return retval; } static int single_byte_boolean_helper(struct mpsse_ctx *ctx, bool var, uint8_t val_if_true, uint8_t val_if_false) { int retval = ERROR_OK; if (buffer_write_space(ctx) < 1) retval = mpsse_flush(ctx); buffer_write_byte(ctx, var ? val_if_true : val_if_false); return retval; } int mpsse_loopback_config(struct mpsse_ctx *ctx, bool enable) { LOG_DEBUG("%s", enable ? "on" : "off"); return single_byte_boolean_helper(ctx, enable, 0x84, 0x85); } int mpsse_set_divisor(struct mpsse_ctx *ctx, uint16_t divisor) { LOG_DEBUG("%d", divisor); int retval = ERROR_OK; if (buffer_write_space(ctx) < 3) retval = mpsse_flush(ctx); buffer_write_byte(ctx, 0x86); buffer_write_byte(ctx, divisor & 0xff); buffer_write_byte(ctx, divisor >> 8); return retval; } int mpsse_divide_by_5_config(struct mpsse_ctx *ctx, bool enable) { if (!mpsse_is_high_speed(ctx)) return ERROR_FAIL; LOG_DEBUG("%s", enable ? "on" : "off"); return single_byte_boolean_helper(ctx, enable, 0x8b, 0x8a); } int mpsse_rtck_config(struct mpsse_ctx *ctx, bool enable) { if (!mpsse_is_high_speed(ctx)) return ERROR_FAIL; LOG_DEBUG("%s", enable ? "on" : "off"); return single_byte_boolean_helper(ctx, enable, 0x96, 0x97); } int mpsse_set_frequency(struct mpsse_ctx *ctx, int frequency) { LOG_DEBUG("target %d Hz", frequency); assert(frequency >= 0); int base_clock; if (frequency == 0) return mpsse_rtck_config(ctx, true); mpsse_rtck_config(ctx, false); /* just try */ if (frequency > 60000000 / 2 / 65536 && mpsse_is_high_speed(ctx)) { int retval = mpsse_divide_by_5_config(ctx, false); if (retval != ERROR_OK) return retval; base_clock = 60000000; } else { mpsse_divide_by_5_config(ctx, true); /* just try */ base_clock = 12000000; } int divisor = (base_clock / 2 + frequency - 1) / frequency - 1; if (divisor > 65535) divisor = 65535; assert(divisor >= 0); int retval = mpsse_set_divisor(ctx, divisor); if (retval != ERROR_OK) return retval; frequency = base_clock / 2 / (1 + divisor); LOG_DEBUG("actually %d Hz", frequency); return frequency; } /* Context needed by the callbacks */ struct transfer_result { struct mpsse_ctx *ctx; bool done; unsigned transferred; }; static LIBUSB_CALL void read_cb(struct libusb_transfer *transfer) { struct transfer_result *res = (struct transfer_result *)transfer->user_data; struct mpsse_ctx *ctx = res->ctx; unsigned packet_size = ctx->max_packet_size; DEBUG_PRINT_BUF(transfer->buffer, transfer->actual_length); /* Strip the two status bytes sent at the beginning of each USB packet * while copying the chunk buffer to the read buffer */ unsigned num_packets = DIV_ROUND_UP(transfer->actual_length, packet_size); unsigned chunk_remains = transfer->actual_length; for (unsigned i = 0; i < num_packets && chunk_remains > 2; i++) { unsigned this_size = packet_size - 2; if (this_size > chunk_remains - 2) this_size = chunk_remains - 2; if (this_size > ctx->read_count - res->transferred) this_size = ctx->read_count - res->transferred; memcpy(ctx->read_buffer + res->transferred, ctx->read_chunk + packet_size * i + 2, this_size); res->transferred += this_size; chunk_remains -= this_size + 2; if (res->transferred == ctx->read_count) { res->done = true; break; } } DEBUG_IO("raw chunk %d, transferred %d of %d", transfer->actual_length, res->transferred, ctx->read_count); if (!res->done) if (libusb_submit_transfer(transfer) != LIBUSB_SUCCESS) res->done = true; } static LIBUSB_CALL void write_cb(struct libusb_transfer *transfer) { struct transfer_result *res = (struct transfer_result *)transfer->user_data; struct mpsse_ctx *ctx = res->ctx; res->transferred += transfer->actual_length; DEBUG_IO("transferred %d of %d", res->transferred, ctx->write_count); DEBUG_PRINT_BUF(transfer->buffer, transfer->actual_length); if (res->transferred == ctx->write_count) res->done = true; else { transfer->length = ctx->write_count - res->transferred; transfer->buffer = ctx->write_buffer + res->transferred; if (libusb_submit_transfer(transfer) != LIBUSB_SUCCESS) res->done = true; } } int mpsse_flush(struct mpsse_ctx *ctx) { DEBUG_IO("write %d%s, read %d", ctx->write_count, ctx->read_count ? "+1" : "", ctx->read_count); assert(ctx->write_count > 0 || ctx->read_count == 0); /* No read data without write data */ int retval = ERROR_OK; if (ctx->write_count == 0) return retval; struct libusb_transfer *read_transfer = 0; struct transfer_result read_result = { .ctx = ctx, .done = true }; if (ctx->read_count) { buffer_write_byte(ctx, 0x87); /* SEND_IMMEDIATE */ read_result.done = false; /* delay read transaction to ensure the FTDI chip can support us with data immediately after processing the MPSSE commands in the write transaction */ } struct transfer_result write_result = { .ctx = ctx, .done = false }; struct libusb_transfer *write_transfer = libusb_alloc_transfer(0); libusb_fill_bulk_transfer(write_transfer, ctx->usb_dev, ctx->out_ep, ctx->write_buffer, ctx->write_count, write_cb, &write_result, ctx->usb_write_timeout); retval = libusb_submit_transfer(write_transfer); if (ctx->read_count) { read_transfer = libusb_alloc_transfer(0); libusb_fill_bulk_transfer(read_transfer, ctx->usb_dev, ctx->in_ep, ctx->read_chunk, ctx->read_chunk_size, read_cb, &read_result, ctx->usb_read_timeout); retval = libusb_submit_transfer(read_transfer); } /* Polling loop, more or less taken from libftdi */ while (!write_result.done || !read_result.done) { retval = libusb_handle_events(ctx->usb_ctx); keep_alive(); if (retval != LIBUSB_SUCCESS && retval != LIBUSB_ERROR_INTERRUPTED) { libusb_cancel_transfer(write_transfer); if (read_transfer) libusb_cancel_transfer(read_transfer); while (!write_result.done || !read_result.done) if (libusb_handle_events(ctx->usb_ctx) != LIBUSB_SUCCESS) break; } } if (retval != LIBUSB_SUCCESS) { LOG_ERROR("libusb_handle_events() failed with %d", retval); retval = ERROR_FAIL; } else if (write_result.transferred < ctx->write_count) { LOG_ERROR("ftdi device did not accept all data: %d, tried %d", write_result.transferred, ctx->write_count); retval = ERROR_FAIL; } else if (read_result.transferred < ctx->read_count) { LOG_ERROR("ftdi device did not return all data: %d, expected %d", read_result.transferred, ctx->read_count); retval = ERROR_FAIL; } else if (ctx->read_count) { ctx->write_count = 0; ctx->read_count = 0; bit_copy_execute(&ctx->read_queue); retval = ERROR_OK; } else { ctx->write_count = 0; bit_copy_discard(&ctx->read_queue); retval = ERROR_OK; } libusb_free_transfer(write_transfer); if (read_transfer) libusb_free_transfer(read_transfer); if (retval != ERROR_OK) mpsse_purge(ctx); return retval; } openocd-0.7.0/src/jtag/drivers/gw16012.c0000644000175000001440000003302312137151331014425 00000000000000/*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #if 1 #define _DEBUG_GW16012_IO_ #endif /* system includes */ /* -ino: 060521-1036 */ #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #include #include #define ioperm(startport, length, enable) \ 386_set_ioperm((startport), (length), (enable)) #else #endif /* __FreeBSD__, __FreeBSD_kernel__ */ #if PARPORT_USE_PPDEV == 1 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #include #include #define PPRSTATUS PPIGSTATUS #define PPWDATA PPISDATA #else #include #include #endif #include #include #else /* not PARPORT_USE_PPDEV */ #ifndef _WIN32 #include #endif #endif #if PARPORT_USE_GIVEIO == 1 && IS_CYGWIN == 1 #include #endif /* configuration */ uint16_t gw16012_port; /* interface variables */ static uint8_t gw16012_msb; static uint8_t gw16012_control_value; #if PARPORT_USE_PPDEV == 1 static int device_handle; #endif static void gw16012_data(uint8_t value) { value = (value & 0x7f) | gw16012_msb; gw16012_msb ^= 0x80; /* toggle MSB */ #ifdef _DEBUG_GW16012_IO_ LOG_DEBUG("%2.2x", value); #endif #if PARPORT_USE_PPDEV == 1 ioctl(device_handle, PPWDATA, &value); #else #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) outb(gw16012_port, value); #else outb(value, gw16012_port); #endif #endif } static void gw16012_control(uint8_t value) { if (value != gw16012_control_value) { gw16012_control_value = value; #ifdef _DEBUG_GW16012_IO_ LOG_DEBUG("%2.2x", gw16012_control_value); #endif #if PARPORT_USE_PPDEV == 1 ioctl(device_handle, PPWCONTROL, &gw16012_control_value); #else #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) outb(gw16012_port + 2, gw16012_control_value); #else outb(gw16012_control_value, gw16012_port + 2); #endif #endif } } static void gw16012_input(uint8_t *value) { #if PARPORT_USE_PPDEV == 1 ioctl(device_handle, PPRSTATUS, value); #else *value = inb(gw16012_port + 1); #endif #ifdef _DEBUG_GW16012_IO_ LOG_DEBUG("%2.2x", *value); #endif } /* (1) assert or (0) deassert reset lines */ static void gw16012_reset(int trst, int srst) { LOG_DEBUG("trst: %i, srst: %i", trst, srst); if (trst == 0) gw16012_control(0x0d); else if (trst == 1) gw16012_control(0x0c); if (srst == 0) gw16012_control(0x0a); else if (srst == 1) gw16012_control(0x0b); } static void gw16012_end_state(tap_state_t state) { if (tap_is_state_stable(state)) tap_set_end_state(state); else { LOG_ERROR("BUG: %i is not a valid end state", state); exit(-1); } } static void gw16012_state_move(void) { int i = 0, tms = 0; uint8_t tms_scan = tap_get_tms_path(tap_get_state(), tap_get_end_state()); int tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); gw16012_control(0x0); /* single-bit mode */ for (i = 0; i < tms_count; i++) { tms = (tms_scan >> i) & 1; gw16012_data(tms << 1); /* output next TMS bit */ } tap_set_state(tap_get_end_state()); } static void gw16012_path_move(struct pathmove_command *cmd) { int num_states = cmd->num_states; int state_count; state_count = 0; while (num_states) { gw16012_control(0x0); /* single-bit mode */ if (tap_state_transition(tap_get_state(), false) == cmd->path[state_count]) gw16012_data(0x0); /* TCK cycle with TMS low */ else if (tap_state_transition(tap_get_state(), true) == cmd->path[state_count]) gw16012_data(0x2); /* TCK cycle with TMS high */ else { LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_name(tap_get_state()), tap_state_name(cmd->path[state_count])); exit(-1); } tap_set_state(cmd->path[state_count]); state_count++; num_states--; } tap_set_end_state(tap_get_state()); } static void gw16012_runtest(int num_cycles) { tap_state_t saved_end_state = tap_get_end_state(); int i; /* only do a state_move when we're not already in IDLE */ if (tap_get_state() != TAP_IDLE) { gw16012_end_state(TAP_IDLE); gw16012_state_move(); } for (i = 0; i < num_cycles; i++) { gw16012_control(0x0); /* single-bit mode */ gw16012_data(0x0); /* TMS cycle with TMS low */ } gw16012_end_state(saved_end_state); if (tap_get_state() != tap_get_end_state()) gw16012_state_move(); } static void gw16012_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size) { int bits_left = scan_size; int bit_count = 0; tap_state_t saved_end_state = tap_get_end_state(); uint8_t scan_out, scan_in; /* only if we're not already in the correct Shift state */ if (!((!ir_scan && (tap_get_state() == TAP_DRSHIFT)) || (ir_scan && (tap_get_state() == TAP_IRSHIFT)))) { if (ir_scan) gw16012_end_state(TAP_IRSHIFT); else gw16012_end_state(TAP_DRSHIFT); gw16012_state_move(); gw16012_end_state(saved_end_state); } while (type == SCAN_OUT && ((bits_left - 1) > 7)) { gw16012_control(0x2); /* seven-bit mode */ scan_out = buf_get_u32(buffer, bit_count, 7); gw16012_data(scan_out); bit_count += 7; bits_left -= 7; } gw16012_control(0x0); /* single-bit mode */ while (bits_left-- > 0) { uint8_t tms = 0; scan_out = buf_get_u32(buffer, bit_count, 1); if (bits_left == 0) /* last bit */ { if ((ir_scan && (tap_get_end_state() == TAP_IRSHIFT)) || (!ir_scan && (tap_get_end_state() == TAP_DRSHIFT))) tms = 0; else tms = 2; } gw16012_data(scan_out | tms); if (type != SCAN_OUT) { gw16012_input(&scan_in); buf_set_u32(buffer, bit_count, 1, ((scan_in & 0x08) >> 3)); } bit_count++; } if (!((ir_scan && (tap_get_end_state() == TAP_IRSHIFT)) || (!ir_scan && (tap_get_end_state() == TAP_DRSHIFT)))) { gw16012_data(0x0); if (ir_scan) tap_set_state(TAP_IRPAUSE); else tap_set_state(TAP_DRPAUSE); if (tap_get_state() != tap_get_end_state()) gw16012_state_move(); } } static int gw16012_execute_queue(void) { struct jtag_command *cmd = jtag_command_queue; /* currently processed command */ int scan_size; enum scan_type type; uint8_t *buffer; int retval; /* return ERROR_OK, unless a jtag_read_buffer returns a failed check * that wasn't handled by a caller-provided error handler */ retval = ERROR_OK; while (cmd) { switch (cmd->type) { case JTAG_RESET: #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); #endif if (cmd->cmd.reset->trst == 1) tap_set_state(TAP_RESET); gw16012_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); break; case JTAG_RUNTEST: #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); #endif gw16012_end_state(cmd->cmd.runtest->end_state); gw16012_runtest(cmd->cmd.runtest->num_cycles); break; case JTAG_TLR_RESET: #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("statemove end in %i", cmd->cmd.statemove->end_state); #endif gw16012_end_state(cmd->cmd.statemove->end_state); gw16012_state_move(); break; case JTAG_PATHMOVE: #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("pathmove: %i states, end in %i", cmd->cmd.pathmove->num_states, cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]); #endif gw16012_path_move(cmd->cmd.pathmove); break; case JTAG_SCAN: gw16012_end_state(cmd->cmd.scan->end_state); scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); type = jtag_scan_type(cmd->cmd.scan); #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("%s scan (%i) %i bit end in %i", (cmd->cmd.scan->ir_scan) ? "ir" : "dr", type, scan_size, cmd->cmd.scan->end_state); #endif gw16012_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size); if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) retval = ERROR_JTAG_QUEUE_FAILED; if (buffer) free(buffer); break; case JTAG_SLEEP: #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("sleep %i", cmd->cmd.sleep->us); #endif jtag_sleep(cmd->cmd.sleep->us); break; default: LOG_ERROR("BUG: unknown JTAG command type encountered"); exit(-1); } cmd = cmd->next; } return retval; } #if PARPORT_USE_GIVEIO == 1 static int gw16012_get_giveio_access(void) { HANDLE h; OSVERSIONINFO version; version.dwOSVersionInfoSize = sizeof version; if (!GetVersionEx(&version)) { errno = EINVAL; return -1; } if (version.dwPlatformId != VER_PLATFORM_WIN32_NT) return 0; h = CreateFile("\\\\.\\giveio", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (h == INVALID_HANDLE_VALUE) { errno = ENODEV; return -1; } CloseHandle(h); return 0; } #endif #if PARPORT_USE_PPDEV == 1 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #define GW16012_PPDEV_NAME "ppi" static int gw16012_init_ioctls(void) { int temp = 0; temp = ioctl(device_handle, PPCLAIM); if (temp < 0) { LOG_ERROR("cannot claim device"); return ERROR_JTAG_INIT_FAILED; } temp = PARPORT_MODE_COMPAT; temp = ioctl(device_handle, PPSETMODE, &temp); if (temp < 0) { LOG_ERROR(" cannot set compatible mode to device"); return ERROR_JTAG_INIT_FAILED; } temp = IEEE1284_MODE_COMPAT; temp = ioctl(device_handle, PPNEGOT, &temp); if (temp < 0) { LOG_ERROR("cannot set compatible 1284 mode to device"); return ERROR_JTAG_INIT_FAILED; } return ERROR_OK; } #else #define GW16012_PPDEV_NAME "parport" static int gw16012_init_ioctls(void) { return ERROR_OK; } #endif /* defined(__FreeBSD__) || defined(__FreeBSD_kernel__) */ static int gw16012_init_device(void) { const char *device_name = GW16012_PPDEV_NAME; char buffer[256]; if (device_handle > 0) { LOG_ERROR("device is already opened"); return ERROR_JTAG_INIT_FAILED; } snprintf(buffer, 256, "/dev/%s%d", device_name, gw16012_port); LOG_DEBUG("opening %s...", buffer); device_handle = open(buffer, O_WRONLY); if (device_handle < 0) { LOG_ERROR("cannot open device. check it exists and that user read and write rights are set"); return ERROR_JTAG_INIT_FAILED; } LOG_DEBUG("...open"); if (gw16012_init_ioctls() != ERROR_OK) return ERROR_JTAG_INIT_FAILED; return ERROR_OK; } #else /* PARPORT_USE_PPDEV */ static int gw16012_init_device(void) { if (gw16012_port == 0) { gw16012_port = 0x378; LOG_WARNING("No gw16012 port specified, using default '0x378' (LPT1)"); } LOG_DEBUG("requesting privileges for parallel port 0x%lx...", (long unsigned)(gw16012_port)); #if PARPORT_USE_GIVEIO == 1 if (gw16012_get_giveio_access() != 0) { #else /* PARPORT_USE_GIVEIO */ if (ioperm(gw16012_port, 3, 1) != 0) { #endif /* PARPORT_USE_GIVEIO */ LOG_ERROR("missing privileges for direct i/o"); return ERROR_JTAG_INIT_FAILED; } LOG_DEBUG("...privileges granted"); /* make sure parallel port is in right mode (clear tristate and interrupt */ #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) outb(gw16012_port + 2, 0x0); #else outb(0x0, gw16012_port + 2); #endif return ERROR_OK; } #endif /* PARPORT_USE_PPDEV */ static int gw16012_init(void) { uint8_t status_port; if (gw16012_init_device() != ERROR_OK) return ERROR_JTAG_INIT_FAILED; gw16012_input(&status_port); gw16012_msb = (status_port & 0x80) ^ 0x80; gw16012_reset(0, 0); return ERROR_OK; } static int gw16012_quit(void) { return ERROR_OK; } COMMAND_HANDLER(gw16012_handle_parport_port_command) { if (CMD_ARGC == 1) { /* only if the port wasn't overwritten by cmdline */ if (gw16012_port == 0) COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], gw16012_port); else { LOG_ERROR("The parport port was already configured!"); return ERROR_FAIL; } } command_print(CMD_CTX, "parport port = %u", gw16012_port); return ERROR_OK; } static const struct command_registration gw16012_command_handlers[] = { { .name = "parport_port", .handler = gw16012_handle_parport_port_command, .mode = COMMAND_CONFIG, .help = "Display the address of the I/O port (e.g. 0x378) " "or the number of the '/dev/parport' device used. " "If a parameter is provided, first change that port.", .usage = "[port_number]", }, COMMAND_REGISTRATION_DONE }; struct jtag_interface gw16012_interface = { .name = "gw16012", .commands = gw16012_command_handlers, .init = gw16012_init, .quit = gw16012_quit, .execute_queue = gw16012_execute_queue, }; openocd-0.7.0/src/jtag/drivers/OpenULINK/0000755000175000001440000000000012134336410015035 500000000000000openocd-0.7.0/src/jtag/drivers/OpenULINK/Makefile0000644000175000001440000000706112134336410016421 00000000000000############################################################################ # Copyright (C) 2011 by Martin Schmoelzer # # # # # # This program is free software; you can redistribute it and/or modify # # it under the terms of the GNU General Public License as published by # # the Free Software Foundation; either version 2 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. # ############################################################################ # Define the name of our tools. Some distributions (e. g. Fedora) prefix # the SDCC executables, change this accordingly! PREFIX = # Small Device C Compiler: http://sdcc.sourceforge.net/ CC = $(PREFIX)-sdcc # 8051 assembler, part of the SDCC software package. AS = $(PREFIX)-sdas8051 # SDCC produces quite messy Intel HEX files. This tool is be used to re-format # those files. It is not required for the firmware download functionality in # the OpenOCD driver, but the resulting file is smaller. PACKIHX = $(PREFIX)-packihx # GNU binutils size. Used to print the size of the IHX file generated by SDCC. SIZE = size # Source and header directories. SRC_DIR = src INCLUDE_DIR = include CODE_SIZE = 0x1B00 # Starting address of __xdata variables. Since the OpenULINK firmware does not # use any of the isochronous interrupts, we can use the isochronous buffer space # as XDATA memory. XRAM_LOC = 0x2000 XRAM_SIZE = 0x0800 CFLAGS = --std-sdcc99 --opt-code-size --model-small LDFLAGS = --code-loc 0x0000 --code-size $(CODE_SIZE) --xram-loc $(XRAM_LOC) \ --xram-size $(XRAM_SIZE) --iram-size 256 --model-small # list of base object files OBJECTS = main.rel usb.rel protocol.rel jtag.rel delay.rel USBJmpTb.rel HEADERS = $(INCLUDE_DIR)/main.h \ $(INCLUDE_DIR)/usb.h \ $(INCLUDE_DIR)/protocol.h \ $(INCLUDE_DIR)/jtag.h \ $(INCLUDE_DIR)/delay.h \ $(INCLUDE_DIR)/reg_ezusb.h \ $(INCLUDE_DIR)/io.h \ $(INCLUDE_DIR)/msgtypes.h # Disable all built-in rules. .SUFFIXES: # Targets which are executed even when identically named file is present. .PHONY: all, clean all: ulink_firmware.ihx $(SIZE) ulink_firmware.ihx ulink_firmware.ihx: $(OBJECTS) $(CC) -mmcs51 $(LDFLAGS) -o $@ $^ # Rebuild every C module (there are only 5 of them) if any header changes. %.rel: $(SRC_DIR)/%.c $(HEADERS) $(CC) -c $(CFLAGS) -mmcs51 -I$(INCLUDE_DIR) -o $@ $< %.rel: $(SRC_DIR)/%.a51 $(AS) -lsgo $@ $< clean: rm -f *.asm *.lst *.rel *.rst *.sym *.ihx *.lnk *.map *.mem hex: ulink_firmware.ihx $(PACKIHX) ulink_firmware.ihx > ulink_firmware.hex openocd-0.7.0/src/jtag/drivers/OpenULINK/src/0000755000175000001440000000000012134336410015624 500000000000000openocd-0.7.0/src/jtag/drivers/OpenULINK/src/jtag.c0000644000175000001440000004704412134336410016646 00000000000000/*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #include "jtag.h" #include "io.h" #include "msgtypes.h" #include "common.h" #include /** Delay value for SCAN_IN operations with less than maximum TCK frequency */ uint8_t delay_scan_in; /** Delay value for SCAN_OUT operations with less than maximum TCK frequency */ uint8_t delay_scan_out; /** Delay value for SCAN_IO operations with less than maximum TCK frequency */ uint8_t delay_scan_io; /** Delay value for CLOCK_TCK operations with less than maximum frequency */ uint8_t delay_tck; /** Delay value for CLOCK_TMS operations with less than maximum frequency */ uint8_t delay_tms; /** * Perform JTAG SCAN-IN operation at maximum TCK frequency. * * Dummy data is shifted into the JTAG chain via TDI, TDO data is sampled and * stored in the EP2 IN buffer. * * Maximum achievable TCK frequency is 182 kHz for ULINK clocked at 24 MHz. * * @param out_offset offset in OUT2BUF where payload data starts */ void jtag_scan_in(uint8_t out_offset, uint8_t in_offset) { uint8_t scan_size_bytes, bits_last_byte; uint8_t tms_count_start, tms_count_end; uint8_t tms_sequence_start, tms_sequence_end; uint8_t tdo_data, i, j; uint8_t outb_buffer; /* Get parameters from OUT2BUF */ scan_size_bytes = OUT2BUF[out_offset]; bits_last_byte = OUT2BUF[out_offset + 1]; tms_count_start = (OUT2BUF[out_offset + 2] >> 4) & 0x0F; tms_count_end = OUT2BUF[out_offset + 2] & 0x0F; tms_sequence_start = OUT2BUF[out_offset + 3]; tms_sequence_end = OUT2BUF[out_offset + 4]; if (tms_count_start > 0) jtag_clock_tms(tms_count_start, tms_sequence_start); outb_buffer = OUTB & ~(PIN_TDI | PIN_TCK | PIN_TMS); /* Shift all bytes except the last byte */ for (i = 0; i < scan_size_bytes - 1; i++) { tdo_data = 0; for (j = 0; j < 8; j++) { OUTB = outb_buffer; /* TCK changes here */ tdo_data = tdo_data >> 1; OUTB = (outb_buffer | PIN_TCK); if (GET_TDO()) tdo_data |= 0x80; } /* Copy TDO data to IN2BUF */ IN2BUF[i + in_offset] = tdo_data; } tdo_data = 0; /* Shift the last byte */ for (j = 0; j < bits_last_byte; j++) { /* Assert TMS signal if requested and this is the last bit */ if ((j == bits_last_byte - 1) && (tms_count_end > 0)) { outb_buffer |= PIN_TMS; tms_count_end--; tms_sequence_end = tms_sequence_end >> 1; } OUTB = outb_buffer; /* TCK change here */ tdo_data = tdo_data >> 1; OUTB = (outb_buffer | PIN_TCK); if (GET_TDO()) tdo_data |= 0x80; } tdo_data = tdo_data >> (8 - bits_last_byte); /* Copy TDO data to IN2BUF */ IN2BUF[i + in_offset] = tdo_data; /* Move to correct end state */ if (tms_count_end > 0) jtag_clock_tms(tms_count_end, tms_sequence_end); } /** * Perform JTAG SCAN-IN operation at variable TCK frequency. * * Dummy data is shifted into the JTAG chain via TDI, TDO data is sampled and * stored in the EP2 IN buffer. * * Maximum achievable TCK frequency is 113 kHz for ULINK clocked at 24 MHz. * * @param out_offset offset in OUT2BUF where payload data starts */ void jtag_slow_scan_in(uint8_t out_offset, uint8_t in_offset) { uint8_t scan_size_bytes, bits_last_byte; uint8_t tms_count_start, tms_count_end; uint8_t tms_sequence_start, tms_sequence_end; uint8_t tdo_data, i, j, k; uint8_t outb_buffer; /* Get parameters from OUT2BUF */ scan_size_bytes = OUT2BUF[out_offset]; bits_last_byte = OUT2BUF[out_offset + 1]; tms_count_start = (OUT2BUF[out_offset + 2] >> 4) & 0x0F; tms_count_end = OUT2BUF[out_offset + 2] & 0x0F; tms_sequence_start = OUT2BUF[out_offset + 3]; tms_sequence_end = OUT2BUF[out_offset + 4]; if (tms_count_start > 0) jtag_slow_clock_tms(tms_count_start, tms_sequence_start); outb_buffer = OUTB & ~(PIN_TDI | PIN_TCK | PIN_TMS); /* Shift all bytes except the last byte */ for (i = 0; i < scan_size_bytes - 1; i++) { tdo_data = 0; for (j = 0; j < 8; j++) { OUTB = outb_buffer; /* TCK changes here */ for (k = 0; k < delay_scan_in; k++) ; tdo_data = tdo_data >> 1; OUTB = (outb_buffer | PIN_TCK); for (k = 0; k < delay_scan_in; k++) ; if (GET_TDO()) tdo_data |= 0x80; } /* Copy TDO data to IN2BUF */ IN2BUF[i + in_offset] = tdo_data; } tdo_data = 0; /* Shift the last byte */ for (j = 0; j < bits_last_byte; j++) { /* Assert TMS signal if requested and this is the last bit */ if ((j == bits_last_byte - 1) && (tms_count_end > 0)) { outb_buffer |= PIN_TMS; tms_count_end--; tms_sequence_end = tms_sequence_end >> 1; } OUTB = outb_buffer; /* TCK change here */ for (k = 0; k < delay_scan_in; k++) ; tdo_data = tdo_data >> 1; OUTB = (outb_buffer | PIN_TCK); for (k = 0; k < delay_scan_in; k++) ; if (GET_TDO()) tdo_data |= 0x80; } tdo_data = tdo_data >> (8 - bits_last_byte); /* Copy TDO data to IN2BUF */ IN2BUF[i + in_offset] = tdo_data; /* Move to correct end state */ if (tms_count_end > 0) jtag_slow_clock_tms(tms_count_end, tms_sequence_end); } /** * Perform JTAG SCAN-OUT operation at maximum TCK frequency. * * Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO * data is not sampled. * The TAP-FSM state is alyways left in the PAUSE-DR/PAUSE-IR state. * * Maximum achievable TCK frequency is 142 kHz for ULINK clocked at 24 MHz. * * @param out_offset offset in OUT2BUF where payload data starts */ void jtag_scan_out(uint8_t out_offset) { uint8_t scan_size_bytes, bits_last_byte; uint8_t tms_count_start, tms_count_end; uint8_t tms_sequence_start, tms_sequence_end; uint8_t tdi_data, i, j; uint8_t outb_buffer; /* Get parameters from OUT2BUF */ scan_size_bytes = OUT2BUF[out_offset]; bits_last_byte = OUT2BUF[out_offset + 1]; tms_count_start = (OUT2BUF[out_offset + 2] >> 4) & 0x0F; tms_count_end = OUT2BUF[out_offset + 2] & 0x0F; tms_sequence_start = OUT2BUF[out_offset + 3]; tms_sequence_end = OUT2BUF[out_offset + 4]; if (tms_count_start > 0) jtag_clock_tms(tms_count_start, tms_sequence_start); outb_buffer = OUTB & ~(PIN_TCK | PIN_TMS); /* Shift all bytes except the last byte */ for (i = 0; i < scan_size_bytes - 1; i++) { tdi_data = OUT2BUF[i + out_offset + 5]; for (j = 0; j < 8; j++) { if (tdi_data & 0x01) outb_buffer |= PIN_TDI; else outb_buffer &= ~PIN_TDI; OUTB = outb_buffer; /* TDI and TCK change here */ tdi_data = tdi_data >> 1; OUTB = (outb_buffer | PIN_TCK); } } tdi_data = OUT2BUF[i + out_offset + 5]; /* Shift the last byte */ for (j = 0; j < bits_last_byte; j++) { if (tdi_data & 0x01) outb_buffer |= PIN_TDI; else outb_buffer &= ~PIN_TDI; /* Assert TMS signal if requested and this is the last bit */ if ((j == bits_last_byte - 1) && (tms_count_end > 0)) { outb_buffer |= PIN_TMS; tms_count_end--; tms_sequence_end = tms_sequence_end >> 1; } OUTB = outb_buffer; /* TDI and TCK change here */ tdi_data = tdi_data >> 1; OUTB = (outb_buffer | PIN_TCK); } /* Move to correct end state */ if (tms_count_end > 0) jtag_clock_tms(tms_count_end, tms_sequence_end); } /** * Perform JTAG SCAN-OUT operation at maximum TCK frequency. * * Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO * data is not sampled. * The TAP-FSM state is alyways left in the PAUSE-DR/PAUSE-IR state. * * Maximum achievable TCK frequency is 97 kHz for ULINK clocked at 24 MHz. * * @param out_offset offset in OUT2BUF where payload data starts */ void jtag_slow_scan_out(uint8_t out_offset) { uint8_t scan_size_bytes, bits_last_byte; uint8_t tms_count_start, tms_count_end; uint8_t tms_sequence_start, tms_sequence_end; uint8_t tdi_data, i, j, k; uint8_t outb_buffer; /* Get parameters from OUT2BUF */ scan_size_bytes = OUT2BUF[out_offset]; bits_last_byte = OUT2BUF[out_offset + 1]; tms_count_start = (OUT2BUF[out_offset + 2] >> 4) & 0x0F; tms_count_end = OUT2BUF[out_offset + 2] & 0x0F; tms_sequence_start = OUT2BUF[out_offset + 3]; tms_sequence_end = OUT2BUF[out_offset + 4]; if (tms_count_start > 0) jtag_slow_clock_tms(tms_count_start, tms_sequence_start); outb_buffer = OUTB & ~(PIN_TCK | PIN_TMS); /* Shift all bytes except the last byte */ for (i = 0; i < scan_size_bytes - 1; i++) { tdi_data = OUT2BUF[i + out_offset + 5]; for (j = 0; j < 8; j++) { if (tdi_data & 0x01) outb_buffer |= PIN_TDI; else outb_buffer &= ~PIN_TDI; OUTB = outb_buffer; /* TDI and TCK change here */ for (k = 0; k < delay_scan_out; k++) ; tdi_data = tdi_data >> 1; OUTB = (outb_buffer | PIN_TCK); for (k = 0; k < delay_scan_out; k++) ; } } tdi_data = OUT2BUF[i + out_offset + 5]; /* Shift the last byte */ for (j = 0; j < bits_last_byte; j++) { if (tdi_data & 0x01) outb_buffer |= PIN_TDI; else outb_buffer &= ~PIN_TDI; /* Assert TMS signal if requested and this is the last bit */ if ((j == bits_last_byte - 1) && (tms_count_end > 0)) { outb_buffer |= PIN_TMS; tms_count_end--; tms_sequence_end = tms_sequence_end >> 1; } OUTB = outb_buffer; /* TDI and TCK change here */ for (k = 0; k < delay_scan_out; k++) ; tdi_data = tdi_data >> 1; OUTB = (outb_buffer | PIN_TCK); for (k = 0; k < delay_scan_out; k++) ; } /* Move to correct end state */ if (tms_count_end > 0) jtag_slow_clock_tms(tms_count_end, tms_sequence_end); } /** * Perform bidirectional JTAG SCAN operation at maximum TCK frequency. * * Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO * data is sampled and stored in the EP2 IN buffer. * The TAP-FSM state is alyways left in the PAUSE-DR/PAUSE-IR state. * * Maximum achievable TCK frequency is 100 kHz for ULINK clocked at 24 MHz. * * @param out_offset offset in OUT2BUF where payload data starts */ void jtag_scan_io(uint8_t out_offset, uint8_t in_offset) { uint8_t scan_size_bytes, bits_last_byte; uint8_t tms_count_start, tms_count_end; uint8_t tms_sequence_start, tms_sequence_end; uint8_t tdi_data, tdo_data, i, j; uint8_t outb_buffer; /* Get parameters from OUT2BUF */ scan_size_bytes = OUT2BUF[out_offset]; bits_last_byte = OUT2BUF[out_offset + 1]; tms_count_start = (OUT2BUF[out_offset + 2] >> 4) & 0x0F; tms_count_end = OUT2BUF[out_offset + 2] & 0x0F; tms_sequence_start = OUT2BUF[out_offset + 3]; tms_sequence_end = OUT2BUF[out_offset + 4]; if (tms_count_start > 0) jtag_clock_tms(tms_count_start, tms_sequence_start); outb_buffer = OUTB & ~(PIN_TCK | PIN_TMS); /* Shift all bytes except the last byte */ for (i = 0; i < scan_size_bytes - 1; i++) { tdi_data = OUT2BUF[i + out_offset + 5]; tdo_data = 0; for (j = 0; j < 8; j++) { if (tdi_data & 0x01) outb_buffer |= PIN_TDI; else outb_buffer &= ~PIN_TDI; OUTB = outb_buffer; /* TDI and TCK change here */ tdi_data = tdi_data >> 1; OUTB = (outb_buffer | PIN_TCK); tdo_data = tdo_data >> 1; if (GET_TDO()) tdo_data |= 0x80; } /* Copy TDO data to IN2BUF */ IN2BUF[i + in_offset] = tdo_data; } tdi_data = OUT2BUF[i + out_offset + 5]; tdo_data = 0; /* Shift the last byte */ for (j = 0; j < bits_last_byte; j++) { if (tdi_data & 0x01) outb_buffer |= PIN_TDI; else outb_buffer &= ~PIN_TDI; /* Assert TMS signal if requested and this is the last bit */ if ((j == bits_last_byte - 1) && (tms_count_end > 0)) { outb_buffer |= PIN_TMS; tms_count_end--; tms_sequence_end = tms_sequence_end >> 1; } OUTB = outb_buffer; /* TDI and TCK change here */ tdi_data = tdi_data >> 1; OUTB = (outb_buffer | PIN_TCK); tdo_data = tdo_data >> 1; if (GET_TDO()) tdo_data |= 0x80; } tdo_data = tdo_data >> (8 - bits_last_byte); /* Copy TDO data to IN2BUF */ IN2BUF[i + in_offset] = tdo_data; /* Move to correct end state */ if (tms_count_end > 0) jtag_clock_tms(tms_count_end, tms_sequence_end); } /** * Perform bidirectional JTAG SCAN operation at maximum TCK frequency. * * Data stored in EP2 OUT buffer is shifted into the JTAG chain via TDI, TDO * data is sampled and stored in the EP2 IN buffer. * The TAP-FSM state is alyways left in the PAUSE-DR/PAUSE-IR state. * * Maximum achievable TCK frequency is 78 kHz for ULINK clocked at 24 MHz. * * @param out_offset offset in OUT2BUF where payload data starts */ void jtag_slow_scan_io(uint8_t out_offset, uint8_t in_offset) { uint8_t scan_size_bytes, bits_last_byte; uint8_t tms_count_start, tms_count_end; uint8_t tms_sequence_start, tms_sequence_end; uint8_t tdi_data, tdo_data, i, j, k; uint8_t outb_buffer; /* Get parameters from OUT2BUF */ scan_size_bytes = OUT2BUF[out_offset]; bits_last_byte = OUT2BUF[out_offset + 1]; tms_count_start = (OUT2BUF[out_offset + 2] >> 4) & 0x0F; tms_count_end = OUT2BUF[out_offset + 2] & 0x0F; tms_sequence_start = OUT2BUF[out_offset + 3]; tms_sequence_end = OUT2BUF[out_offset + 4]; if (tms_count_start > 0) jtag_slow_clock_tms(tms_count_start, tms_sequence_start); outb_buffer = OUTB & ~(PIN_TCK | PIN_TMS); /* Shift all bytes except the last byte */ for (i = 0; i < scan_size_bytes - 1; i++) { tdi_data = OUT2BUF[i + out_offset + 5]; tdo_data = 0; for (j = 0; j < 8; j++) { if (tdi_data & 0x01) outb_buffer |= PIN_TDI; else outb_buffer &= ~PIN_TDI; OUTB = outb_buffer; /* TDI and TCK change here */ for (k = 0; k < delay_scan_io; k++) ; tdi_data = tdi_data >> 1; OUTB = (outb_buffer | PIN_TCK); for (k = 0; k < delay_scan_io; k++) ; tdo_data = tdo_data >> 1; if (GET_TDO()) tdo_data |= 0x80; } /* Copy TDO data to IN2BUF */ IN2BUF[i + in_offset] = tdo_data; } tdi_data = OUT2BUF[i + out_offset + 5]; tdo_data = 0; /* Shift the last byte */ for (j = 0; j < bits_last_byte; j++) { if (tdi_data & 0x01) outb_buffer |= PIN_TDI; else outb_buffer &= ~PIN_TDI; /* Assert TMS signal if requested and this is the last bit */ if ((j == bits_last_byte - 1) && (tms_count_end > 0)) { outb_buffer |= PIN_TMS; tms_count_end--; tms_sequence_end = tms_sequence_end >> 1; } OUTB = outb_buffer; /* TDI and TCK change here */ for (k = 0; k < delay_scan_io; k++) ; tdi_data = tdi_data >> 1; OUTB = (outb_buffer | PIN_TCK); for (k = 0; k < delay_scan_io; k++) ; tdo_data = tdo_data >> 1; if (GET_TDO()) tdo_data |= 0x80; } tdo_data = tdo_data >> (8 - bits_last_byte); /* Copy TDO data to IN2BUF */ IN2BUF[i + in_offset] = tdo_data; /* Move to correct end state */ if (tms_count_end > 0) jtag_slow_clock_tms(tms_count_end, tms_sequence_end); } /** * Generate TCK clock cycles. * * Maximum achievable TCK frequency is 375 kHz for ULINK clocked at 24 MHz. * * @param count number of TCK clock cyclces to generate. */ void jtag_clock_tck(uint16_t count) { uint16_t i; uint8_t outb_buffer = OUTB & ~(PIN_TCK); for (i = 0; i < count; i++) { OUTB = outb_buffer; OUTB = outb_buffer | PIN_TCK; } } /** * Generate TCK clock cycles at variable frequency. * * Maximum achieveable TCK frequency is 166.6 kHz for ULINK clocked at 24 MHz. * * @param count number of TCK clock cyclces to generate. */ void jtag_slow_clock_tck(uint16_t count) { uint16_t i; uint8_t j; uint8_t outb_buffer = OUTB & ~(PIN_TCK); for (i = 0; i < count; i++) { OUTB = outb_buffer; for (j = 0; j < delay_tck; j++) ; OUTB = outb_buffer | PIN_TCK; for (j = 0; j < delay_tck; j++) ; } } /** * Perform TAP FSM state transitions at maximum TCK frequency. * * Maximum achievable TCK frequency is 176 kHz for ULINK clocked at 24 MHz. * * @param count the number of state transitions to perform. * @param sequence the TMS pin levels for each state transition, starting with * the least-significant bit. */ void jtag_clock_tms(uint8_t count, uint8_t sequence) { uint8_t outb_buffer = OUTB & ~(PIN_TCK); uint8_t i; for (i = 0; i < count; i++) { /* Set TMS pin according to sequence parameter */ if (sequence & 0x1) outb_buffer |= PIN_TMS; else outb_buffer &= ~PIN_TMS; OUTB = outb_buffer; sequence = sequence >> 1; OUTB = outb_buffer | PIN_TCK; } } /** * Perform TAP-FSM state transitions at less than maximum TCK frequency. * * Maximum achievable TCK frequency is 117 kHz for ULINK clocked at 24 MHz. * * @param count the number of state transitions to perform. * @param sequence the TMS pin levels for each state transition, starting with * the least-significant bit. */ void jtag_slow_clock_tms(uint8_t count, uint8_t sequence) { uint8_t outb_buffer = OUTB & ~(PIN_TCK); uint8_t i, j; for (i = 0; i < count; i++) { /* Set TMS pin according to sequence parameter */ if (sequence & 0x1) outb_buffer |= PIN_TMS; else outb_buffer &= ~PIN_TMS; OUTB = outb_buffer; for (j = 0; j < delay_tms; j++) ; sequence = sequence >> 1; OUTB = outb_buffer | PIN_TCK; for (j = 0; j < delay_tms; j++) ; } } /** * Get current JTAG signal states. * * @return a 16-bit integer where the most-significant byte contains the state * of the JTAG input signals and the least-significant byte cotains the state * of the JTAG output signals. */ uint16_t jtag_get_signals(void) { uint8_t input_signal_state, output_signal_state; input_signal_state = 0; output_signal_state = 0; /* Get states of input pins */ if (GET_TDO()) input_signal_state |= SIGNAL_TDO; if (GET_BRKOUT()) input_signal_state |= SIGNAL_BRKOUT; if (GET_TRAP()) input_signal_state |= SIGNAL_TRAP; if (GET_RTCK()) { /* Using RTCK this way would be extremely slow, * implemented only for the sake of completeness */ input_signal_state |= SIGNAL_RTCK; } /* Get states of output pins */ output_signal_state = PINSB & MASK_PORTB_DIRECTION_OUT; return ((uint16_t)input_signal_state << 8) | ((uint16_t)output_signal_state); } /** * Set state of JTAG output signals. * * @param low signals which should be de-asserted. * @param high signals which should be asserted. */ void jtag_set_signals(uint8_t low, uint8_t high) { OUTB &= ~(low & MASK_PORTB_DIRECTION_OUT); OUTB |= (high & MASK_PORTB_DIRECTION_OUT); } /** * Configure TCK delay parameters. * * @param scan_in number of delay cycles in scan_in operations. * @param scan_out number of delay cycles in scan_out operations. * @param scan_io number of delay cycles in scan_io operations. * @param tck number of delay cycles in clock_tck operations. * @param tms number of delay cycles in clock_tms operations. */ void jtag_configure_tck_delay(uint8_t scan_in, uint8_t scan_out, uint8_t scan_io, uint8_t tck, uint8_t tms) { delay_scan_in = scan_in; delay_scan_out = scan_out; delay_scan_io = scan_io; delay_tck = tck; delay_tms = tms; } openocd-0.7.0/src/jtag/drivers/OpenULINK/src/USBJmpTb.a510000644000175000001440000000664712134336410017457 00000000000000;--------------------------------------------------------------------------; ; Copyright (C) 2011 by Martin Schmoelzer ; ; ; ; ; ; This program is free software; you can redistribute it and/or modify ; ; it under the terms of the GNU General Public License as published by ; ; the Free Software Foundation; either version 2 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. ; ;--------------------------------------------------------------------------; .module JUMPTABLE .globl USB_AutoVector .globl USB_Jump_Table ;--------------------------------------------------------------------------; ; Interrupt Vectors ; ;--------------------------------------------------------------------------; .area USB_JV (ABS,OVR) ; Absolute, Overlay .org 0x43 ; USB interrupt (INT2) jumps here USB_AutoVector = #. + 2 ljmp USB_jump_table ;--------------------------------------------------------------------------; ; USB Jump Table ; ;--------------------------------------------------------------------------; .area USB_JT (ABS) ; Absolute placement .org 0x1B00 ; Place jump table at 0x1B00 USB_jump_table: ; autovector jump table ljmp _sudav_isr ; Setup Data Available .db 0 ljmp _sof_isr ; Start of Frame .db 0 ljmp _sutok_isr ; Setup Data Loading .db 0 ljmp _suspend_isr ; Global Suspend .db 0 ljmp _usbreset_isr ; USB Reset .db 0 ljmp _ibn_isr ; IN Bulk NAK interrupt .db 0 ljmp _ep0in_isr ; Endpoint 0 IN .db 0 ljmp _ep0out_isr ; Endpoint 0 OUT .db 0 ljmp _ep1in_isr ; Endpoint 1 IN .db 0 ljmp _ep1out_isr ; Endpoint 1 OUT .db 0 ljmp _ep2in_isr ; Endpoint 2 IN .db 0 ljmp _ep2out_isr ; Endpoint 2 OUT .db 0 ljmp _ep3in_isr ; Endpoint 3 IN .db 0 ljmp _ep3out_isr ; Endpoint 3 OUT .db 0 ljmp _ep4in_isr ; Endpoint 4 IN .db 0 ljmp _ep4out_isr ; Endpoint 4 OUT .db 0 ljmp _ep5in_isr ; Endpoint 5 IN .db 0 ljmp _ep5out_isr ; Endpoint 5 OUT .db 0 ljmp _ep6in_isr ; Endpoint 6 IN .db 0 ljmp _ep6out_isr ; Endpoint 6 OUT .db 0 ljmp _ep7in_isr ; Endpoint 7 IN .db 0 ljmp _ep7out_isr ; Endpoint 7 OUT .db 0 openocd-0.7.0/src/jtag/drivers/OpenULINK/src/main.c0000644000175000001440000000676612134336410016653 00000000000000/*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #include "main.h" #include "io.h" #include "usb.h" #include "protocol.h" extern void sudav_isr(void) __interrupt SUDAV_ISR; extern void sof_isr(void) __interrupt; extern void sutok_isr(void) __interrupt; extern void suspend_isr(void) __interrupt; extern void usbreset_isr(void) __interrupt; extern void ibn_isr(void) __interrupt; extern void ep0in_isr(void) __interrupt; extern void ep0out_isr(void) __interrupt; extern void ep1in_isr(void) __interrupt; extern void ep1out_isr(void) __interrupt; extern void ep2in_isr(void) __interrupt; extern void ep2out_isr(void) __interrupt; extern void ep3in_isr(void) __interrupt; extern void ep3out_isr(void) __interrupt; extern void ep4in_isr(void) __interrupt; extern void ep4out_isr(void) __interrupt; extern void ep5in_isr(void) __interrupt; extern void ep5out_isr(void) __interrupt; extern void ep6in_isr(void) __interrupt; extern void ep6out_isr(void) __interrupt; extern void ep7in_isr(void) __interrupt; extern void ep7out_isr(void) __interrupt; void io_init(void) { /* PORTxCFG register bits select alternate functions (1 == alternate function, * 0 == standard I/O) * OEx register bits turn on/off output buffer (1 == output, 0 == input) * OUTx register bits determine pin state of output * PINx register bits reflect pin state (high == 1, low == 0) */ /* PORT A */ PORTACFG = PIN_OE; OEA = PIN_U_OE | PIN_OE | PIN_RUN_LED | PIN_COM_LED; OUTA = PIN_RUN_LED | PIN_COM_LED; /* PORT B */ PORTBCFG = 0x00; OEB = PIN_TDI | PIN_TMS | PIN_TCK | PIN_TRST | PIN_BRKIN | PIN_RESET | PIN_OCDSE; /* TRST and RESET signals are low-active but inverted by hardware, so we clear * these signals here! */ OUTB = 0x00; /* PORT C */ PORTCCFG = PIN_WR; OEC = PIN_TXD0 | PIN_WR; OUTC = 0x00; } int main(void) { io_init(); usb_init(); /* Enable Interrupts */ EA = 1; /* Begin executing command(s). This function never returns. */ command_loop(); /* Never reached, but SDCC complains about missing return statement */ return 0; } openocd-0.7.0/src/jtag/drivers/OpenULINK/src/delay.c0000644000175000001440000000342212134336410017007 00000000000000/*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #include "delay.h" void delay_5us(void) { NOP; } void delay_1ms(void) { uint16_t i; for (i = 0; i < 598; i++) ; } void delay_us(uint16_t delay) { uint16_t i; uint16_t maxcount = (delay / 5); for (i = 0; i < maxcount; i++) delay_5us(); } void delay_ms(uint16_t delay) { uint16_t i; for (i = 0; i < delay; i++) delay_1ms(); } openocd-0.7.0/src/jtag/drivers/OpenULINK/src/protocol.c0000644000175000001440000001667312134336410017566 00000000000000/*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #include "protocol.h" #include "jtag.h" #include "delay.h" #include "usb.h" #include "io.h" #include "msgtypes.h" #include "reg_ezusb.h" /** * @file * Implementation of the OpenULINK communication protocol. * * The OpenULINK protocol uses one OUT and one IN endpoint. These two endpoints * are configured to use the maximum packet size for full-speed transfers, * 64 bytes. Commands always start with a command ID (see msgtypes.h for * command ID definitions) and contain zero or more payload data bytes in both * transfer directions (IN and OUT). The payload * * Almost all commands contain a fixed number of payload data bytes. The number * of payload data bytes for the IN and OUT direction does not need to be the * same. * * Multiple commands may be sent in one EP2 Bulk-OUT packet. Because the * OpenULINK firmware does not perform bounds checking for EP2 Bulk-IN packets, * the host MUST ensure that the commands sent in the OUT packet require a * maximum of 64 bytes of IN data. */ /** Index in EP2 Bulk-OUT data buffer that contains the current command ID */ volatile uint8_t cmd_id_index; /** Number of data bytes already in EP2 Bulk-IN buffer */ volatile uint8_t payload_index_in; /** * Execute a SET_LEDS command. */ void execute_set_led_command(void) { uint8_t led_state = OUT2BUF[cmd_id_index + 1]; if (led_state & RUN_LED_ON) SET_RUN_LED(); if (led_state & COM_LED_ON) SET_COM_LED(); if (led_state & RUN_LED_OFF) CLEAR_RUN_LED(); if (led_state & COM_LED_OFF) CLEAR_COM_LED(); } /** * Executes one command and updates global command indexes. * * @return true if this command was the last command. * @return false if there are more commands within the current contents of the * Bulk EP2-OUT data buffer. */ bool execute_command(void) { uint8_t usb_out_bytecount, usb_in_bytecount; uint16_t signal_state; uint16_t count; /* Most commands do not transfer IN data. To save code space, we write 0 to * usb_in_bytecount here, then modify it in the switch statement below where * neccessary */ usb_in_bytecount = 0; switch (OUT2BUF[cmd_id_index] /* Command ID */) { case CMD_SCAN_IN: usb_out_bytecount = 5; usb_in_bytecount = OUT2BUF[cmd_id_index + 1]; jtag_scan_in(cmd_id_index + 1, payload_index_in); break; case CMD_SCAN_OUT: usb_out_bytecount = OUT2BUF[cmd_id_index + 1] + 5; jtag_scan_out(cmd_id_index + 1); break; case CMD_SCAN_IO: usb_in_bytecount = OUT2BUF[cmd_id_index + 1]; usb_out_bytecount = usb_in_bytecount + 5; jtag_scan_io(cmd_id_index + 1, payload_index_in); break; case CMD_CLOCK_TMS: usb_out_bytecount = 2; jtag_clock_tms(OUT2BUF[cmd_id_index + 1], OUT2BUF[cmd_id_index + 2]); break; case CMD_CLOCK_TCK: usb_out_bytecount = 2; count = (uint16_t)OUT2BUF[cmd_id_index + 1]; count |= ((uint16_t)OUT2BUF[cmd_id_index + 2]) << 8; jtag_clock_tck(count); break; case CMD_SLOW_SCAN_IN: usb_out_bytecount = 5; usb_in_bytecount = OUT2BUF[cmd_id_index + 1]; jtag_slow_scan_in(cmd_id_index + 1, payload_index_in); break; case CMD_SLOW_SCAN_OUT: usb_out_bytecount = OUT2BUF[cmd_id_index + 1] + 5; jtag_slow_scan_out(cmd_id_index + 1); break; case CMD_SLOW_SCAN_IO: usb_in_bytecount = OUT2BUF[cmd_id_index + 1]; usb_out_bytecount = usb_in_bytecount + 5; jtag_slow_scan_io(cmd_id_index + 1, payload_index_in); break; case CMD_SLOW_CLOCK_TMS: usb_out_bytecount = 2; jtag_slow_clock_tms(OUT2BUF[cmd_id_index + 1], OUT2BUF[cmd_id_index + 2]); break; case CMD_SLOW_CLOCK_TCK: usb_out_bytecount = 2; count = (uint16_t)OUT2BUF[cmd_id_index + 1]; count |= ((uint16_t)OUT2BUF[cmd_id_index + 2]) << 8; jtag_slow_clock_tck(count); break; case CMD_SLEEP_US: usb_out_bytecount = 2; count = (uint16_t)OUT2BUF[cmd_id_index + 1]; count |= ((uint16_t)OUT2BUF[cmd_id_index + 2]) << 8; delay_us(count); break; case CMD_SLEEP_MS: usb_out_bytecount = 2; count = (uint16_t)OUT2BUF[cmd_id_index + 1]; count |= ((uint16_t)OUT2BUF[cmd_id_index + 2]) << 8; delay_ms(count); break; case CMD_GET_SIGNALS: usb_out_bytecount = 0; usb_in_bytecount = 2; signal_state = jtag_get_signals(); IN2BUF[payload_index_in] = (signal_state >> 8) & 0x00FF; IN2BUF[payload_index_in + 1] = signal_state & 0x00FF; break; case CMD_SET_SIGNALS: usb_out_bytecount = 2; jtag_set_signals(OUT2BUF[cmd_id_index + 1], OUT2BUF[cmd_id_index + 2]); break; case CMD_CONFIGURE_TCK_FREQ: usb_out_bytecount = 5; jtag_configure_tck_delay( OUT2BUF[cmd_id_index + 1], /* scan_in */ OUT2BUF[cmd_id_index + 2], /* scan_out */ OUT2BUF[cmd_id_index + 3], /* scan_io */ OUT2BUF[cmd_id_index + 4], /* clock_tck */ OUT2BUF[cmd_id_index + 5]); /* clock_tms */ break; case CMD_SET_LEDS: usb_out_bytecount = 1; execute_set_led_command(); break; case CMD_TEST: usb_out_bytecount = 1; /* Do nothing... This command is only used to test if the device is ready * to accept new commands */ break; default: /* Should never be reached */ usb_out_bytecount = 0; break; } /* Update EP2 Bulk-IN data byte count */ payload_index_in += usb_in_bytecount; /* Determine if this was the last command */ if ((cmd_id_index + usb_out_bytecount + 1) >= OUT2BC) return true; else { /* Not the last command, update cmd_id_index */ cmd_id_index += (usb_out_bytecount + 1); return false; } } /** * Forever wait for commands and execute them as they arrive. */ void command_loop(void) { bool last_command; while (1) { cmd_id_index = 0; payload_index_in = 0; /* Wait until host sends EP2 Bulk-OUT packet */ while (!EP2_out) ; EP2_out = 0; /* Turn on COM LED to indicate command execution */ SET_COM_LED(); /* Execute the commands */ last_command = false; while (last_command == false) last_command = execute_command(); CLEAR_COM_LED(); /* Send back EP2 Bulk-IN packet if required */ if (payload_index_in > 0) { IN2BC = payload_index_in; while (!EP2_in) ; EP2_in = 0; } /* Re-arm EP2-OUT after command execution */ OUT2BC = 0; } } openocd-0.7.0/src/jtag/drivers/OpenULINK/src/usb.c0000644000175000001440000003507612134336410016514 00000000000000/*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /** * @file * Defines USB descriptors, interrupt routines and helper functions. * To minimize code size, we make the following assumptions: * - The OpenULINK has exactly one configuration * - and exactly one alternate setting * * Therefore, we do not have to support the Set Configuration USB request. */ #include "usb.h" #include "delay.h" #include "io.h" /* Also update external declarations in "include/usb.h" if making changes to * these variables! */ volatile bool EP2_out; volatile bool EP2_in; volatile __xdata __at 0x7FE8 struct setup_data setup_data; /* Define number of endpoints (except Control Endpoint 0) in a central place. * Be sure to include the neccessary endpoint descriptors! */ #define NUM_ENDPOINTS 2 /* * Normally, we would initialize the descriptor structures in C99 style: * * __code usb_device_descriptor_t device_descriptor = { * .bLength = foo, * .bDescriptorType = bar, * .bcdUSB = 0xABCD, * ... * }; * * But SDCC currently does not support this, so we have to do it the * old-fashioned way... */ __code struct usb_device_descriptor device_descriptor = { /* .bLength = */ sizeof(struct usb_device_descriptor), /* .bDescriptorType = */ DESCRIPTOR_TYPE_DEVICE, /* .bcdUSB = */ 0x0110, /* BCD: 01.00 (Version 1.0 USB spec) */ /* .bDeviceClass = */ 0xFF, /* 0xFF = vendor-specific */ /* .bDeviceSubClass = */ 0xFF, /* .bDeviceProtocol = */ 0xFF, /* .bMaxPacketSize0 = */ 64, /* .idVendor = */ 0xC251, /* .idProduct = */ 0x2710, /* .bcdDevice = */ 0x0100, /* .iManufacturer = */ 1, /* .iProduct = */ 2, /* .iSerialNumber = */ 3, /* .bNumConfigurations = */ 1 }; /* WARNING: ALL config, interface and endpoint descriptors MUST be adjacent! */ __code struct usb_config_descriptor config_descriptor = { /* .bLength = */ sizeof(struct usb_config_descriptor), /* .bDescriptorType = */ DESCRIPTOR_TYPE_CONFIGURATION, /* .wTotalLength = */ sizeof(struct usb_config_descriptor) + sizeof(struct usb_interface_descriptor) + (NUM_ENDPOINTS * sizeof(struct usb_endpoint_descriptor)), /* .bNumInterfaces = */ 1, /* .bConfigurationValue = */ 1, /* .iConfiguration = */ 4, /* String describing this configuration */ /* .bmAttributes = */ 0x80, /* Only MSB set according to USB spec */ /* .MaxPower = */ 50 /* 100 mA */ }; __code struct usb_interface_descriptor interface_descriptor00 = { /* .bLength = */ sizeof(struct usb_interface_descriptor), /* .bDescriptorType = */ DESCRIPTOR_TYPE_INTERFACE, /* .bInterfaceNumber = */ 0, /* .bAlternateSetting = */ 0, /* .bNumEndpoints = */ NUM_ENDPOINTS, /* .bInterfaceClass = */ 0xFF, /* .bInterfaceSubclass = */ 0xFF, /* .bInterfaceProtocol = */ 0xFF, /* .iInterface = */ 0 }; __code struct usb_endpoint_descriptor Bulk_EP2_IN_Endpoint_Descriptor = { /* .bLength = */ sizeof(struct usb_endpoint_descriptor), /* .bDescriptorType = */ 0x05, /* .bEndpointAddress = */ 2 | USB_DIR_IN, /* .bmAttributes = */ 0x02, /* .wMaxPacketSize = */ 64, /* .bInterval = */ 0 }; __code struct usb_endpoint_descriptor Bulk_EP2_OUT_Endpoint_Descriptor = { /* .bLength = */ sizeof(struct usb_endpoint_descriptor), /* .bDescriptorType = */ 0x05, /* .bEndpointAddress = */ 2 | USB_DIR_OUT, /* .bmAttributes = */ 0x02, /* .wMaxPacketSize = */ 64, /* .bInterval = */ 0 }; __code struct usb_language_descriptor language_descriptor = { /* .bLength = */ 4, /* .bDescriptorType = */ DESCRIPTOR_TYPE_STRING, /* .wLANGID = */ {0x0409 /* US English */} }; __code struct usb_string_descriptor strManufacturer = STR_DESCR(9, 'O', 'p', 'e', 'n', 'U', 'L', 'I', 'N', 'K'); __code struct usb_string_descriptor strProduct = STR_DESCR(9, 'O', 'p', 'e', 'n', 'U', 'L', 'I', 'N', 'K'); __code struct usb_string_descriptor strSerialNumber = STR_DESCR(6, '0', '0', '0', '0', '0', '1'); __code struct usb_string_descriptor strConfigDescr = STR_DESCR(12, 'J', 'T', 'A', 'G', ' ', 'A', 'd', 'a', 'p', 't', 'e', 'r'); /* Table containing pointers to string descriptors */ __code struct usb_string_descriptor *__code en_string_descriptors[4] = { &strManufacturer, &strProduct, &strSerialNumber, &strConfigDescr }; void sudav_isr(void) __interrupt SUDAV_ISR { CLEAR_IRQ(); usb_handle_setup_data(); USBIRQ = SUDAVIR; EP0CS |= HSNAK; } void sof_isr(void) __interrupt SOF_ISR { } void sutok_isr(void) __interrupt SUTOK_ISR { } void suspend_isr(void) __interrupt SUSPEND_ISR { } void usbreset_isr(void) __interrupt USBRESET_ISR { } void ibn_isr(void) __interrupt IBN_ISR { } void ep0in_isr(void) __interrupt EP0IN_ISR { } void ep0out_isr(void) __interrupt EP0OUT_ISR { } void ep1in_isr(void) __interrupt EP1IN_ISR { } void ep1out_isr(void) __interrupt EP1OUT_ISR { } /** * EP2 IN: called after the transfer from uC->Host has finished: we sent data */ void ep2in_isr(void) __interrupt EP2IN_ISR { EP2_in = 1; CLEAR_IRQ(); IN07IRQ = IN2IR;/* Clear OUT2 IRQ */ } /** * EP2 OUT: called after the transfer from Host->uC has finished: we got data */ void ep2out_isr(void) __interrupt EP2OUT_ISR { EP2_out = 1; CLEAR_IRQ(); OUT07IRQ = OUT2IR; /* Clear OUT2 IRQ */ } void ep3in_isr(void) __interrupt EP3IN_ISR { } void ep3out_isr(void) __interrupt EP3OUT_ISR { } void ep4in_isr(void) __interrupt EP4IN_ISR { } void ep4out_isr(void) __interrupt EP4OUT_ISR { } void ep5in_isr(void) __interrupt EP5IN_ISR { } void ep5out_isr(void) __interrupt EP5OUT_ISR { } void ep6in_isr(void) __interrupt EP6IN_ISR { } void ep6out_isr(void) __interrupt EP6OUT_ISR { } void ep7in_isr(void) __interrupt EP7IN_ISR { } void ep7out_isr(void) __interrupt EP7OUT_ISR { } /** * Return the control/status register for an endpoint * * @param ep endpoint address * @return on success: pointer to Control & Status register for endpoint * specified in \a ep * @return on failure: NULL */ __xdata uint8_t *usb_get_endpoint_cs_reg(uint8_t ep) { /* Mask direction bit */ uint8_t ep_num = ep & 0x7F; switch (ep_num) { case 0: return &EP0CS; break; case 1: return ep & 0x80 ? &IN1CS : &OUT1CS; break; case 2: return ep & 0x80 ? &IN2CS : &OUT2CS; break; case 3: return ep & 0x80 ? &IN3CS : &OUT3CS; break; case 4: return ep & 0x80 ? &IN4CS : &OUT4CS; break; case 5: return ep & 0x80 ? &IN5CS : &OUT5CS; break; case 6: return ep & 0x80 ? &IN6CS : &OUT6CS; break; case 7: return ep & 0x80 ? &IN7CS : &OUT7CS; break; } return NULL; } void usb_reset_data_toggle(uint8_t ep) { /* TOGCTL register: +----+-----+-----+------+-----+-------+-------+-------+ | Q | S | R | IO | 0 | EP2 | EP1 | EP0 | +----+-----+-----+------+-----+-------+-------+-------+ To reset data toggle bits, we have to write the endpoint direction (IN/OUT) to the IO bit and the endpoint number to the EP2..EP0 bits. Then, in a separate write cycle, the R bit needs to be set. */ uint8_t togctl_value = (ep & 0x80 >> 3) | (ep & 0x7); /* First step: Write EP number and direction bit */ TOGCTL = togctl_value; /* Second step: Set R bit */ togctl_value |= TOG_R; TOGCTL = togctl_value; } /** * Handle GET_STATUS request. * * @return on success: true * @return on failure: false */ bool usb_handle_get_status(void) { uint8_t *ep_cs; switch (setup_data.bmRequestType) { case GS_DEVICE: /* Two byte response: Byte 0, Bit 0 = self-powered, Bit 1 = remote wakeup. * Byte 1: reserved, reset to zero */ IN0BUF[0] = 0; IN0BUF[1] = 0; /* Send response */ IN0BC = 2; break; case GS_INTERFACE: /* Always return two zero bytes according to USB 1.1 spec, p. 191 */ IN0BUF[0] = 0; IN0BUF[1] = 0; /* Send response */ IN0BC = 2; break; case GS_ENDPOINT: /* Get stall bit for endpoint specified in low byte of wIndex */ ep_cs = usb_get_endpoint_cs_reg(setup_data.wIndex & 0xff); if (*ep_cs & EPSTALL) IN0BUF[0] = 0x01; else IN0BUF[0] = 0x00; /* Second byte sent has to be always zero */ IN0BUF[1] = 0; /* Send response */ IN0BC = 2; break; default: return false; break; } return true; } /** * Handle CLEAR_FEATURE request. * * @return on success: true * @return on failure: false */ bool usb_handle_clear_feature(void) { __xdata uint8_t *ep_cs; switch (setup_data.bmRequestType) { case CF_DEVICE: /* Clear remote wakeup not supported: stall EP0 */ STALL_EP0(); break; case CF_ENDPOINT: if (setup_data.wValue == 0) { /* Unstall the endpoint specified in wIndex */ ep_cs = usb_get_endpoint_cs_reg(setup_data.wIndex); if (!ep_cs) return false; *ep_cs &= ~EPSTALL; } else { /* Unsupported feature, stall EP0 */ STALL_EP0(); } break; default: /* Vendor commands... */ } return true; } /** * Handle SET_FEATURE request. * * @return on success: true * @return on failure: false */ bool usb_handle_set_feature(void) { __xdata uint8_t *ep_cs; switch (setup_data.bmRequestType) { case SF_DEVICE: if (setup_data.wValue == 2) return true; break; case SF_ENDPOINT: if (setup_data.wValue == 0) { /* Stall the endpoint specified in wIndex */ ep_cs = usb_get_endpoint_cs_reg(setup_data.wIndex); if (!ep_cs) return false; *ep_cs |= EPSTALL; } else { /* Unsupported endpoint feature */ return false; } break; default: /* Vendor commands... */ break; } return true; } /** * Handle GET_DESCRIPTOR request. * * @return on success: true * @return on failure: false */ bool usb_handle_get_descriptor(void) { __xdata uint8_t descriptor_type; __xdata uint8_t descriptor_index; descriptor_type = (setup_data.wValue & 0xff00) >> 8; descriptor_index = setup_data.wValue & 0x00ff; switch (descriptor_type) { case DESCRIPTOR_TYPE_DEVICE: SUDPTRH = HI8(&device_descriptor); SUDPTRL = LO8(&device_descriptor); break; case DESCRIPTOR_TYPE_CONFIGURATION: SUDPTRH = HI8(&config_descriptor); SUDPTRL = LO8(&config_descriptor); break; case DESCRIPTOR_TYPE_STRING: if (setup_data.wIndex == 0) { /* Supply language descriptor */ SUDPTRH = HI8(&language_descriptor); SUDPTRL = LO8(&language_descriptor); } else if (setup_data.wIndex == 0x0409 /* US English */) { /* Supply string descriptor */ SUDPTRH = HI8(en_string_descriptors[descriptor_index - 1]); SUDPTRL = LO8(en_string_descriptors[descriptor_index - 1]); } else return false; break; default: /* Unsupported descriptor type */ return false; break; } return true; } /** * Handle SET_INTERFACE request. */ void usb_handle_set_interface(void) { /* Reset Data Toggle */ usb_reset_data_toggle(USB_DIR_IN | 2); usb_reset_data_toggle(USB_DIR_OUT | 2); /* Unstall & clear busy flag of all valid IN endpoints */ IN2CS = 0 | EPBSY; /* Unstall all valid OUT endpoints, reset bytecounts */ OUT2CS = 0; OUT2BC = 0; } /** * Handle the arrival of a USB Control Setup Packet. */ void usb_handle_setup_data(void) { switch (setup_data.bRequest) { case GET_STATUS: if (!usb_handle_get_status()) STALL_EP0(); break; case CLEAR_FEATURE: if (!usb_handle_clear_feature()) STALL_EP0(); break; case 2: case 4: /* Reserved values */ STALL_EP0(); break; case SET_FEATURE: if (!usb_handle_set_feature()) STALL_EP0(); break; case SET_ADDRESS: /* Handled by USB core */ break; case SET_DESCRIPTOR: /* Set Descriptor not supported. */ STALL_EP0(); break; case GET_DESCRIPTOR: if (!usb_handle_get_descriptor()) STALL_EP0(); break; case GET_CONFIGURATION: /* OpenULINK has only one configuration, return its index */ IN0BUF[0] = config_descriptor.bConfigurationValue; IN0BC = 1; break; case SET_CONFIGURATION: /* OpenULINK has only one configuration -> nothing to do */ break; case GET_INTERFACE: /* OpenULINK only has one interface, return its number */ IN0BUF[0] = interface_descriptor00.bInterfaceNumber; IN0BC = 1; break; case SET_INTERFACE: usb_handle_set_interface(); break; case SYNCH_FRAME: /* Isochronous endpoints not used -> nothing to do */ break; default: /* Any other requests: do nothing */ break; } } /** * USB initialization. Configures USB interrupts, endpoints and performs * ReNumeration. */ void usb_init(void) { /* Mark endpoint 2 IN & OUT as valid */ IN07VAL = IN2VAL; OUT07VAL = OUT2VAL; /* Make sure no isochronous endpoints are marked valid */ INISOVAL = 0; OUTISOVAL = 0; /* Disable isochronous endpoints. This makes the isochronous data buffers * available as 8051 XDATA memory at address 0x2000 - 0x27FF */ ISOCTL = ISODISAB; /* Enable USB Autovectoring */ USBBAV |= AVEN; /* Enable SUDAV interrupt */ USBIEN |= SUDAVIE; /* Enable EP2 OUT & IN interrupts */ OUT07IEN = OUT2IEN; IN07IEN = IN2IEN; /* Enable USB interrupt (EIE register) */ EUSB = 1; /* Perform ReNumeration */ USBCS = DISCON | RENUM; delay_ms(200); USBCS = DISCOE | RENUM; } openocd-0.7.0/src/jtag/drivers/OpenULINK/ulink_firmware.hex0000644000175000001440000003513212134336410020505 00000000000000:040000000200733255 :01000B0032C2 :0100130032BA :01001B0032B2 :0100230032AA :01002B0032A2 :01003300329A :01003B003292 :01004300328A :01004B003282 :01005300327A :01005B003272 :01006300326A :03006B000201256A :0300DF0002006EAE :05006E0012011680FEE6 :1000E200907F937404F0907F9C7495F0907F967447 :1000F20090F0907F94E4F0907F9D747FF0907F97D2 :10010200E4F0907F957440F0907F9E7442F0907F6F :1001120098E4F0221200E2120502D2AF12093590E1 :03012200000022B8 :0400CC00C200C201AB :10012500C021C0E0C0F0C082C083C002C003C004CB :10013500C005C006C007C000C001C0D075D00053BF :1001450091EF12045B907FAB7401F0907FB4E044B3 :1001550002F0D0D0D001D000D007D006D005D00411 :10016500D003D002D083D082D0F0D0E0D02132327B :100175003232323232323232C0E0C082C083D201F2 :100185005391EF907FA97404F0D083D082D0E032F0 :10019500C0E0C082C083D2005391EF907FAA74045F :1001A500F0D083D082D0E032323232323232323243 :1001B5003232AA82747F5AFB7407B50300500302DA :1001C500026FEB2B2B9001CE730201E60201EA02CE :1001D50001FD020210020223020236020249020256 :1001E5005C907FB422EA30E7067BB67C7F80047B97 :1001F500C67C7F8B828C8322EA30E7067BB87C7FC6 :1002050080047BC87C7F8B828C8322EA30E7067B67 :10021500BA7C7F80047BCA7C7F8B828C8322EA3008 :10022500E7067BBC7C7F80047BCC7C7F8B828C83C8 :1002350022EA30E7067BBE7C7F80047BCE7C7F8B09 :10024500828C8322EA30E7067BC07C7F80047BD0EA :100255007C7F8B828C8322EA30E7067AC27B7F80A3 :10026500047AD27B7F8A828B832290000022AA8225 :1002750074105AFB74075A4203907FD7EBF0742031 :100285004BF022907FE8E0FABA8002800ABA810238 :100295008016BA825D8022907F00E4F0907F01F0A5 :1002A500907FB57402F0804C907F00E4F0907F0160 :1002B500F0907FB57402F0803B907FECE0FAA3E00C :1002C5008A821201B7AA82AB837C008A828B838CD7 :1002D500F0121427FA30E008907F007401F08005D1 :1002E500907F00E4F0907F01E4F0907FB57402F018 :1002F5008002C322D322907FE8E0FA6005BA024665 :10030500800A907FB4E0FA4401F0803A907FEAE0F9 :10031500FAA3E0FB4A7027907FECE0FAA3E08A821B :100325001201B7AA82AB83EA4B7002C3228A828B81 :1003350083E0FC5304FE8A828B83ECF08008907F77 :10034500B4E0FA4401F0D322907FE8E0FA6005BA00 :1003550002468010907FEAE0FAA3E0FBBA0239BBBF :100365000036D322907FEAE0FAA3E0FB4A7027909B :100375007FECE0FAA3E08A821201B7AA82AB83EA96 :100385004B7002C3228A828B83E0FC4304018A827C :100395008B83ECF08002C322D322907FEAE0A3E0B6 :1003A500FA907FEAE0FBA3E07C00BA0102800CBA78 :1003B5000202801DBA0302802E807B7A477C14904E :1003C5007FD4ECF07A477C147C00907FD5EAF080EE :1003D500677A597C14907FD4ECF07A597C147C00B0 :1003E500907FD5EAF08051907FECE0FAA3E0FC4ADB :1003F50070167A797C14907FD4ECF07A797C147C31 :1004050000907FD5EAF08030907FECE0FAA3E0FC25 :10041500BA0921BC041E1BEB2BFA9014CD93CAA379 :1004250093FB8A048B05907FD4EDF07B00907FD5FC :10043500EAF08004C322C322D3227582821202739A :10044500758202120273907FB87402F0907FC8E43F :10045500F0907FC9F022907FE9E0FA740CB50200B4 :10046500500122EA2A2A90046F730204960204A41A :100475000204B20204BA0204B20204C70204D002A2 :1004850004C80204DD0204ED0204EE0204FE0205C6 :1004950001120288500122907FB4E04401F022123B :1004A50002FB500122907FB4E04401F022907FB41A :1004B500E04401F02212034D4042907FB4E0440134 :1004C500F02222907FB4E04401F02212039F402CD9 :1004D500907FB4E04401F02290145EE493907F0095 :1004E500F0907FB57401F02222901464E493907F1C :1004F50000F0907FB57401F02212043F22907FDE58 :100505007404F0907FDF7404F0907FE0E4F0907F56 :10051500E1F0907FA17401F0907FAFE04401F0908D :100525007FAEE04401F0907FAD7404F0907FAC7431 :1005350004F0D2E8907FD6740AF09000C81213D464 :07054500907FD67406F0223E :1014470012011001FFFFFF4051C2102700010102E6 :10145700030109022000010104803209040000028F :10146700FFFFFF0007058202400000070502024058 :1014770000000403090414034F00700065006E00A8 :1014870055004C0049004E004B0014034F007000FC :1014970065006E0055004C0049004E004B000E03DE :1014A7003000300030003000300031001A034A00AD :1014B70054004100470020004100640061007000B3 :0E14C7007400650072007D149114A514B31416 :10054C00E5080424C0F582E4347DF583E0FA30E15B :10055C0008907F96E0FB54EFF0EA30E008907F962D :10056C00E0FB547FF0EA30E308907F96E0FB441008 :10057C00F0EA30E208907F96E0FA4480F0227A00AC :10058C00E50824C0F582E4347DF583E0FB742AB5DC :10059C00030050030208FBEB240983C0E0EB242E7C :1005AC0083C0E02206DF2C054F28FBFBFBFBFBFB8B :1005BC00FBFBFBFBFBFBFBFBFBFBFBFBFBFBFBFB7F :1005CC00FBFBFBFB764FA67FB8F12A5A89E8F706AE :1005DC000606070607080808080808080808080897 :1005EC000808080808080808080808080808080681 :1005FC00070607070708080808087B05E508042410 :10060C00C0F582E4347DF583E0FAE50804F58285D3 :10061C000927C002C003120972D003D0020208FDE0 :10062C00E5080424C0F582E4347DF583E02405FB61 :10063C00E50804F582C002C003120C42D003D002BC :10064C000208FDE5080424C0F582E4347DF583E05E :10065C00FA2405FBE50804F58285093BC002C003BA :10066C00120ED2D003D0020208FD7B02E50804244E :10067C00C0F582E4347DF583E0FC7402250824C0C7 :10068C00F582E4347DF583E0F50A8C82C002C00368 :10069C001212A6D003D0020208FD7B02E508042446 :1006AC00C0F582E4347DF583E0FC7D0074022508FE :1006BC0024C0F582E4347DF583E0FFE44204EF428C :1006CC00058C828D83C002C003121239D003D00274 :1006DC000208FD7B05E5080424C0F582E4347DF5B1 :1006EC0083E0FAE50804F58285092DC002C00312E7 :1006FC000AC4D003D0020208FDE5080424C0F58228 :10070C00E4347DF583E02405FBE50804F582C002A2 :10071C00C003120D74D003D0020208FDE5080424B6 :10072C00C0F582E4347DF583E0FA2405FBE508048A :10073C00F582850943C002C00312106FD003D002AA :10074C000208FD7B02E5080424C0F582E4347DF543 :10075C0083E0FE7402250824C0F582E4347DF58321 :10076C00E0F50A8E82C002C0031212DBD003D00265 :10077C000208FD7B02E5080424C0F582E4347DF513 :10078C0083E0FC7D007402250824C0F582E4347DEE :10079C00F583E0FFE44204EF42058C828D83C002B6 :1007AC00C003121263D003D0020208FD7B02E508DD :1007BC000424C0F582E4347DF583E0FC7D007402F2 :1007CC00250824C0F582E4347DF583E0FFE442047F :1007DC00EF42058C828D83C002C0031213A1D0039B :1007EC00D0020208FD7B02E5080424C0F582E43443 :1007FC007DF583E0FC7D007402250824C0F582E4BD :10080C00347DF583E0FFE44204EF42058C828D8356 :10081C00C002C0031213D4D003D0020208FD7B0027 :10082C007A02C002C003121326AC82AD83D003D06F :10083C000285098275837E8D06EEF0E5090424009D :10084C00F582E4347EF5837D00ECF00208FD7B023A :10085C00E5080424C0F582E4347DF583E0FC7402E1 :10086C00250824C0F582E4347DF583E0F50A8C82FA :10087C00C002C003121369D003D00280747B05E55B :10088C00080424C0F582E4347DF583E0FC74022571 :10089C000824C0F582E4347DF583E0F50A74032561 :1008AC000824C0F582E4347DF583E0F50B7404254F :1008BC000824C0F582E4347DF583E0F50C7405253D :1008CC000824C0F582E4347DF583E0F50D8C82C0FC :1008DC0002C003121381D003D00280157B01C00229 :1008EC00C00312054CD003D00280067B0180027B32 :1008FC0000EA2509F509AA087C008B057E00ED2A83 :10090C00FAEE3CFC0ABA00010C907FC9E0FD7E00B7 :10091C00C3EA9DEC64808EF063F08095F04002D3C6 :10092C0022EB042508F508C3227508007509001090 :10093C00000280FB907F96E0FA547FF0C202200206 :10094C000712058A920280F6907F96E0FA4480F0B6 :10095C00E509600B907FB9E509F010010280FB906E :06096C007FC9E4F080C326 :0F00D00075220075230075240075250075260024 :10097200E582FA24C0F582E4347DF583E0F528EAC5 :100982000424C0F582E4347DF583E0F52974022A5B :10099200FD24C0F582E4347DF583E0C4540FFE5398 :1009A200060FED24C0F582E4347DF583E0FD740F7B :1009B2005DF52A74032A24C0F582E4347DF583E0D0 :1009C200FF74042A24C0F582E4347DF583E0F52B1C :1009D200EE60078F0A8E821212A6907F97E0FE5376 :1009E20006F87F0074044EF87900AD287B001DBD27 :1009F200FF011B89027C00C3EA9DEC64808BF063DB :100A0200F08095F050387A007B00BB0800501C90B3 :100A12007F97EEF0EAC313FA907F97E8F0907F9900 :100A2200E0FC30E5034302800B80DFE52729240048 :100A3200F582E4347EF583EAF009890780AC890700 :100A42007A00AB2A752C00E52CB529005041AD295E :100A520078001DBDFF0118A92C7C00E9B50511EC39 :100A6200B5000DEB600A4306021BE52BC313F52B01 :100A7200907F97EEF0EAC313FA907F9774044EF0DA :100A8200907F99E0FC30E503430280052C80B8ACEE :100A9200297D007408C39CFCE49DFD8CF005F0EAFE :100AA2008002C313D5F0FBFAE5272F2400F582E478 :100AB200347EF583EAF0EB6008852B0A8B82021202 :100AC200A622E582FA24C0F582E4347DF583E0F5BE :100AD2002EEA0424C0F582E4347DF583E0F52F7418 :100AE200022AFD24C0F582E4347DF583E0C4540F6C :100AF200FE53060FED24C0F582E4347DF583E0FD5C :100B0200740F5DF53074032A24C0F582E4347DF558 :100B120083E0FF74042A24C0F582E4347DF583E087 :100B2200F531EE60078F0A8E821212DB907F97E01A :100B3200FE5306F87F0074044EF87900AD2E7B0058 :100B42001DBDFF011B89027C00C3EA9DEC64808B02 :100B5200F063F08095F0504E7A007B00BB080050A5 :100B620032907F97EEF07C00ECB5220050030C80AF :100B7200F7EAC313FA907F97E8F07C00ECB5220005 :100B820050030C80F7907F99E0FC30E5034302802C :100B92000B80C9E52D292400F582E4347EF583EA31 :100BA200F0098907809689077A00AB30753200E533 :100BB20032B52F005057AD2F78001DBDFF0118A987 :100BC200327C00E9B50511ECB5000DEB600A430675 :100BD200021BE531C313F531907F97EEF07C00ECF8 :100BE200B5220050030C80F7EAC313FA907F977482 :100BF200044EF07C00ECB5220050030C80F7907F8D :100C020099E0FC30E503430280053280A2AC2F7DDF :100C1200007408C39CFCE49DFD8CF005F0EA8002A0 :100C2200C313D5F0FBFAE52D2F2400F582E4347EC0 :100C3200F583EAF0EB600885310A8B820212DB222F :100C4200E582FA24C0F582E4347DF583E0F533EAE7 :100C52000424C0F582E4347DF583E0F53474022A7D :100C6200FD24C0F582E4347DF583E0C4540FFE53C5 :100C7200060FED24C0F582E4347DF583E0FD740FA8 :100C82005DF53574032A24C0F582E4347DF583E0F2 :100C9200FF74042A24C0F582E4347DF583E0F5363E :100CA200EE600B8F0A8E82C0021212A6D002907FD3 :100CB20097E0FE5306F97F00A9337D0019B9FF01C1 :100CC2001D8F037800C3EB99E864808DF063F08098 :100CD20095F05038EA2F240524C0F582E4347DF5DE :100CE20083E0FB7D00BD0800501FEB30E0054306AA :100CF2000180035306FE907F97EEF0EBC313FB9047 :100D02007F9774044EF00D80DC0F80ACEA2F24052F :100D120024C0F582E4347DF583E0FBAA357D00ED45 :100D2200B534005041EB30E0054306018003530621 :100D3200FEAF3478001FBFFF01188D017C00E9B5BA :100D42000711ECB5000DEA600A4306021AE536C344 :100D520013F536907F97EEF0EBC313FB907F9774F9 :100D6200044EF00D80B9EA600885360A8A820212C2 :100D7200A622E582FA24C0F582E4347DF583E0F50B :100D820037EA0424C0F582E4347DF583E0F5387453 :100D9200022AFD24C0F582E4347DF583E0C4540FB9 :100DA200FE53060FED24C0F582E4347DF583E0FDA9 :100DB200740F5DF53974032A24C0F582E4347DF59D :100DC20083E0FF74042A24C0F582E4347DF583E0D5 :100DD200F53AEE600B8F0A8E82C0021212DBD0024D :100DE200907F97E0FE5306F97F00A9377D0019B97D :100DF200FF011D8F037800C3EB99E864808DF063D7 :100E0200F08095F0504EEA2F240524C0F582E43498 :100E12007DF583E0FB7D00BD08005035EB30E00539 :100E220043060180035306FE907F97EEF07800E8B8 :100E3200B5230050030880F7EBC313FB907F977430 :100E4200044EF07800E8B5230050030880F70D80C7 :100E5200C60F8096EA2F240524C0F582E4347DF57E :100E620083E0FBAA397D00EDB538005057EB30E046 :100E72000543060180035306FEAF3878001FBFFF0B :100E820001188D017C00E9B50711ECB5000DEA608F :100E92000A4306021AE53AC313F53A907F97EEF039 :100EA2007C00ECB5230050030C80F7EBC313FB90DE :100EB2007F9774044EF07C00ECB5230050030C8045 :100EC200F70D80A3EA6008853A0A8A820212DB22C1 :100ED200E582F53C24C0F582E4347DF583E0F53DFE :100EE200E53C0424C0F582E4347DF583E0F53E74EC :100EF20002253CFD24C0F582E4347DF583E0C45430 :100F02000FFE53060FED24C0F582E4347DF583E035 :100F1200FD740F5DF53F7403253C24C0F582E43473 :100F22007DF583E0FF7404253C24C0F582E4347D22 :100F3200F583E0F540EE60078F0A8E821212A690CA :100F42007F97E0FE5306F97F007900AD3D7B001DDF :100F5200BDFF011B89007A00C3E89DEA64808BF023 :100F620063F08095F0505EE53C29240524C0F582AB :100F7200E4347DF583E0F5417B007D00BD0800503F :100F820031E54130E00543060180035306FE907FC0 :100F920097EEF0E541C313F541907F9774044EF04C :100FA200EBC313FB907F99E0F830E5034303800D18 :100FB20080CAE53B292400F582E4347EF583EBF018 :100FC20009890780868907E53C29240524C0F58222 :100FD200E4347DF583E0F5417B00AD3F754200E5E9 :100FE20042B53E005054E54130E00543060180031E :100FF2005306FEA93E7C0019B9FF011CA8427A00E3 :10100200E8B50111EAB5040DED600A4306021DE5DB :1010120040C313F540907F97EEF0E541C313F541CD :10102200907F9774044EF0EBC313FB907F99E0FA24 :1010320030E503430380054280A5AC3E7A00740884 :10104200C39CFCE49AFA8CF005F0EB8002C313D542 :10105200F0FBFBE53B2F2400F582E4347EF583EBC5 :10106200F0ED600885400A8D820212A622E582F523 :101072004424C0F582E4347DF583E0F545E544047B :1010820024C0F582E4347DF583E0F54674022544FC :10109200FD24C0F582E4347DF583E0C4540FFE5391 :1010A200060FED24C0F582E4347DF583E0FD740F74 :1010B2005DF5477403254424C0F582E4347DF5834D :1010C200E0FF7404254424C0F582E4347DF583E016 :1010D200F548EE60078F0A8E821212DB907F97E04E :1010E200FE5306F97F007900AD457B001DBDFF016F :1010F2001B89007A00C3E89DEA64808BF063F0806C :1011020095F05075E54429240524C0F582E4347D28 :10111200F583E0F5497B007D00BD08005047E549B5 :1011220030E00543060180035306FE907F97EEF000 :101132007800E8B5240050030880F7E549C313F5A9 :1011420049907F9774044EF07800E8B5240050036C :101152000880F7EBC313FB907F99E0F830E5034377 :1011620003800D80B4E543292400F582E4347EF542 :1011720083EBF00989070210EA8907E5442924056F :1011820024C0F582E4347DF583E0F5497B00AD4768 :10119200754A00E54AB54600506AE54930E0054324 :1011A200060180035306FEA9467C0019B9FF011C03 :1011B200A84A7A00E8B50111EAB5040DED600A43C8 :1011C20006021DE548C313F548907F97EEF07A00BA :1011D200EAB5240050030A80F7E549C313F54990A4 :1011E2007F9774044EF07A00EAB5240050030A8017 :1011F200F7EBC313FB907F99E0FA30E503430380DA :10120200054A808FAC467A007408C39CFCE49AFAC3 :101212008CF005F0EB8002C313D5F0FBFBE5432F06 :101222002400F582E4347EF583EBF0ED6008854816 :101232000A8D820212DB22AA82AB83907F97E0FCA6 :101242005304FB74044CFD7E007F00C3EE9AEF9BB7 :10125200500E907F97ECF0EDF00EBE00EE0F80EB9B :1012620022AA82AB83907F97E0FC5304FB74044C68 :10127200FD7E007F00C3EE9AEF9B5027907F97EC94 :10128200F07800E8B5250050030880F7907F97EDCD :10129200F07800E8B5250050030880F70EBE00D5AF :1012A2000F80D222AA82907F97E0FB5303FB7C003F :1012B200ECB502005022E50A30E005430302800348 :1012C2005303FD907F97EBF0E50AC313F50A907F75 :1012D2009774044BF00C80D822AA82907F97E0FB8F :1012E2005303FB7C00ECB502005038E50A30E00500 :1012F20043030280035303FD907F97EBF07D00EDE3 :10130200B5260050030D80F7E50AC313F50A907F56 :101312009774044BF07D00EDB5260050030D80F765 :101322000C80C2227A00907F99E0FB30E5027A01BC :10133200907F99E0FB30E603430202907F9AE0FB44 :1013420030E703430204907F9BE0FB30E503430256 :1013520008907F9AE0FB53037F8A04E4FAFDEB4A8C :10136200F582ED4CF58322E582547FF4FA907F9763 :10137200E05AF0747F550AFA907F97E04AF022858E :101382008222850A23850B24850C25850D262200C1 :10139200227A567B021ABAFF011BEA4B70F72275BA :1013A2000A05750B001213FEAA82AB837C007D0036 :1013B200C3EC9AED9B501AC002C003C004C00512D0 :1013C2001391D005D004D003D0020CBC00E20D80F2 :1013D200DF22AA82AB837C007D00C3EC9AED9B5096 :1013E2001AC002C003C004C005121393D005D00472 :0C13F200D003D0020CBC00E20D80DF2212 :03004300021B009D :101B00000201250002017400020175000201760045 :101B100002017700020178000201790002017A00D7 :101B200002017B0002017C0002017D0002019500A0 :101B30000201AD000201AE000201AF000201B000DF :101B40000201B1000201B2000201B3000201B400BF :081B50000201B5000201B6001C :1013FE007A10E4FBFCE58225E0F582E58333F58384 :10140E00EB33FBEC33FCEB950AF5F0EC950B400659 :09141E00FCABF0438201DADD228F :0600A200E478FFF6D8FD32 :100080007900E94400601B7A009014D578007592DD :1000900020E493F2A308B800020592D9F4DAF275CD :0200A00092FFCD :1000A8007800E84400600A7900759220E4F309D8E2 :1000B800FC7800E84400600C7900902000E4F0A38C :0400C800D8FCD9FA8D :0D00730075814A121443E582600302006E9D :1014270020F71430F6148883A88220F507E6A883EE :1014370075830022E280F7E49322E022758200227E :00000001FF openocd-0.7.0/src/jtag/drivers/OpenULINK/include/0000755000175000001440000000000012134336410016460 500000000000000openocd-0.7.0/src/jtag/drivers/OpenULINK/include/io.h0000644000175000001440000001277212134336410017171 00000000000000/*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef __IO_H #define __IO_H #include "reg_ezusb.h" /*************************************************************************** * JTAG Signals: * *************************************************************************** * TMS ....... Test Mode Select * * TCK ....... Test Clock * * TDI ....... Test Data Input (from device point of view, not JTAG * * adapter point of view!) * * TDO ....... Test Data Output (from device point of view, not JTAG * * adapter point of view!) * * TRST ...... Test Reset: Used to reset the TAP Finite State Machine * * into the Test Logic Reset state * * RTCK ...... Return Test Clock * * OCDSE ..... Enable/Disable OCDS interface (Infineon specific) - shared * * with /JEN * * TRAP ...... Trap Condition (Infineon specific) - shared with TSTAT * * BRKIN ..... Hardware Break-In (Infineon specific) * * BRKOUT .... Hardware Break-Out (Infineon specific) * * /JEN ...... JTAG-Enable (STMicroelectronics specific) - shared * * with OCDSE * * TSTAT ..... JTAG ISP Status (STMicroelectronics specific) - shared * * with TRAP * * RESET ..... Chip Reset (STMicroelectronics specific) * * /TERR ..... JTAG ISP Error (STMicroelectronics specific) - shared * * with BRKOUT * ***************************************************************************/ /* PORT A */ #define PIN_U_OE OUTA0 /* PA1 Not Connected */ #define PIN_OE OUTA2 /* PA3 Not Connected */ #define PIN_RUN_LED OUTA4 #define PIN_TDO PINA5 #define PIN_BRKOUT PINA6 #define PIN_COM_LED OUTA7 /* PORT B */ #define PIN_TDI OUTB0 #define PIN_TMS OUTB1 #define PIN_TCK OUTB2 #define PIN_TRST OUTB3 #define PIN_BRKIN OUTB4 #define PIN_RESET OUTB5 #define PIN_OCDSE OUTB6 #define PIN_TRAP PINB7 /* JTAG Signals with direction 'OUT' on port B */ #define MASK_PORTB_DIRECTION_OUT (PIN_TDI | PIN_TMS | PIN_TCK | PIN_TRST | PIN_BRKIN | PIN_RESET | PIN_OCDSE) /* PORT C */ #define PIN_RXD0 PINC0 #define PIN_TXD0 OUTC1 #define PIN_RESET_2 PINC2 /* PC3 Not Connecte */ /* PC4 Not Connected */ #define PIN_RTCK PINC5 #define PIN_WR OUTC6 /* PC7 Not Connected */ /* LED Macros */ #define SET_RUN_LED() (OUTA &= ~PIN_RUN_LED) #define CLEAR_RUN_LED() (OUTA |= PIN_RUN_LED) #define SET_COM_LED() (OUTA &= ~PIN_COM_LED) #define CLEAR_COM_LED() (OUTA |= PIN_COM_LED) /* JTAG Pin Macros */ #define GET_TMS() (PINSB & PIN_TMS) #define GET_TCK() (PINSB & PIN_TCK) #define GET_TDO() (PINSA & PIN_TDO) #define GET_BRKOUT() (PINSA & PIN_BRKOUT) #define GET_TRAP() (PINSB & PIN_TRAP) #define GET_RTCK() (PINSC & PIN_RTCK) #define SET_TMS_HIGH() (OUTB |= PIN_TMS) #define SET_TMS_LOW() (OUTB &= ~PIN_TMS) #define SET_TCK_HIGH() (OUTB |= PIN_TCK) #define SET_TCK_LOW() (OUTB &= ~PIN_TCK) #define SET_TDI_HIGH() (OUTB |= PIN_TDI) #define SET_TDI_LOW() (OUTB &= ~PIN_TDI) /* TRST and RESET are low-active and inverted by hardware. SET_HIGH de-asserts * the signal (enabling reset), SET_LOW asserts the signal (disabling reset) */ #define SET_TRST_HIGH() (OUTB |= PIN_TRST) #define SET_TRST_LOW() (OUTB &= ~PIN_TRST) #define SET_RESET_HIGH() (OUTB |= PIN_RESET) #define SET_RESET_LOW() (OUTB &= ~PIN_RESET) #define SET_OCDSE_HIGH() (OUTB |= PIN_OCDSE) #define SET_OCDSE_LOW() (OUTB &= ~PIN_OCDSE) #define SET_BRKIN_HIGH() (OUTB |= PIN_BRKIN) #define SET_BRKIN_LOW() (OUTB &= ~PIN_BRKIN) #endif openocd-0.7.0/src/jtag/drivers/OpenULINK/include/jtag.h0000644000175000001440000000435512134336410017505 00000000000000/*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef __JTAG_H #define __JTAG_H #include #define NOP { __asm nop __endasm; } void jtag_scan_in(uint8_t out_offset, uint8_t in_offset); void jtag_slow_scan_in(uint8_t out_offset, uint8_t in_offset); void jtag_scan_out(uint8_t out_offset); void jtag_slow_scan_out(uint8_t out_offset); void jtag_scan_io(uint8_t out_offset, uint8_t in_offset); void jtag_slow_scan_io(uint8_t out_offset, uint8_t in_offset); void jtag_clock_tck(uint16_t count); void jtag_slow_clock_tck(uint16_t count); void jtag_clock_tms(uint8_t count, uint8_t sequence); void jtag_slow_clock_tms(uint8_t count, uint8_t sequence); uint16_t jtag_get_signals(void); void jtag_set_signals(uint8_t low, uint8_t high); void jtag_configure_tck_delay(uint8_t scan_in, uint8_t scan_out, uint8_t scan_io, uint8_t tck, uint8_t tms); #endif openocd-0.7.0/src/jtag/drivers/OpenULINK/include/common.h0000644000175000001440000000303412134336410020041 00000000000000/*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef __COMMON_H #define __COMMON_H #define DIV_ROUND_UP(m, n) (((m) + (n) - 1) / (n)) #endif openocd-0.7.0/src/jtag/drivers/OpenULINK/include/delay.h0000644000175000001440000000321312134336410017646 00000000000000/*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef __DELAY_H #define __DELAY_H #include #define NOP { __asm nop __endasm; } void delay_5us(void); void delay_1ms(void); void delay_us(uint16_t delay); void delay_ms(uint16_t delay); #endif openocd-0.7.0/src/jtag/drivers/OpenULINK/include/msgtypes.h0000644000175000001440000002601112134336410020424 00000000000000/*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /** * @file * Definition of the commands supported by the OpenULINK firmware. * * Basically, two types of commands can be distinguished: * - Commands with fixed payload size * - Commands with variable payload size * * SCAN commands (in all variations) carry payloads of variable size, all * other commands carry payloads of fixed size. * * In the case of SCAN commands, the payload size (n) is calculated by * dividing the scan_size_bits variable by 8, rounding up the result. * * Offset zero always contains the command ID. * **************************************************************************** * CMD_SCAN_IN, CMD_SLOW_SCAN_IN: * * * * OUT: * * offset 1: scan_size_bytes * * offset 2: bits_last_byte * * offset 3: tms_count_start + tms_count_end * * offset 4: tms_sequence_start * * offset 5: tms_sequence_end * * * * IN: * * offset 0..n: TDO data * **************************************************************************** * CMD_SCAN_OUT, CMD_SLOW_SCAN_OUT: * * * * OUT: * * offset 1: scan_size_bytes * * offset 2: bits_last_byte * * offset 3: tms_count_start + tms_count_end * * offset 4: tms_sequence_start * * offset 5: tms_sequence_end * * offset 6..x: TDI data * **************************************************************************** * CMD_SCAN_IO, CMD_SLOW_SCAN_IO: * * * * OUT: * * offset 1: scan_size_bytes * * offset 2: bits_last_byte * * offset 3: tms_count_start + tms_count_end * * offset 4: tms_sequence_start * * offset 5: tms_sequence_end * * offset 6..x: TDI data * * * * IN: * * offset 0..n: TDO data * **************************************************************************** * CMD_CLOCK_TMS, CMD_SLOW_CLOCK_TMS: * * * * OUT: * * offset 1: tms_count * * offset 2: tms_sequence * **************************************************************************** * CMD_CLOCK_TCK, CMD_SLOW_CLOCK_TCK: * * * * OUT: * * offset 1: low byte of tck_count * * offset 2: high byte of tck_count * **************************************************************************** * CMD_CLOCK_SLEEP_US: * * * * OUT: * * offset 1: low byte of sleep_us * * offset 2: high byte of sleep_us * **************************************************************************** * CMD_CLOCK_SLEEP_MS: * * * * OUT: * * offset 1: low byte of sleep_ms * * offset 2: high byte of sleep_ms * **************************************************************************** * CMD_GET_SIGNALS: * * * * IN: * * offset 0: current state of input signals * * offset 1: current state of output signals * **************************************************************************** * CMD_SET_SIGNALS: * * * * OUT: * * offset 1: signals that should be de-asserted * * offset 2: signals that should be asserted * **************************************************************************** * CMD_CONFIGURE_TCK_FREQ: * * * * OUT: * * offset 1: delay value for scan_in function * * offset 2: delay value for scan_out function * * offset 3: delay value for scan_io function * * offset 4: delay value for clock_tck function * * offset 5: delay value for clock_tms function * **************************************************************************** * CMD_SET_LEDS: * * * * OUT: * * offset 1: LED states: * * Bit 0: turn COM LED on * * Bit 1: turn RUN LED on * * Bit 2: turn COM LED off * * Bit 3: turn RUN LED off * * Bits 7..4: Reserved * **************************************************************************** * CMD_TEST: * * * * OUT: * * offset 1: unused dummy value * **************************************************************************** */ #ifndef __MSGTYPES_H #define __MSGTYPES_H /* * Command IDs: * * Bits 7..6: Reserved, should always be zero * Bits 5..0: Command ID. There are 62 usable IDs. Of this 63 available IDs, * the IDs 0x00..0x1F are commands with variable payload size, * the IDs 0x20..0x3F are commands with fixed payload size. */ #define CMD_ID_MASK 0x3F /* Commands with variable payload size */ #define CMD_SCAN_IN 0x00 #define CMD_SLOW_SCAN_IN 0x01 #define CMD_SCAN_OUT 0x02 #define CMD_SLOW_SCAN_OUT 0x03 #define CMD_SCAN_IO 0x04 #define CMD_SLOW_SCAN_IO 0x05 /* Commands with fixed payload size */ #define CMD_CLOCK_TMS 0x20 #define CMD_SLOW_CLOCK_TMS 0x21 #define CMD_CLOCK_TCK 0x22 #define CMD_SLOW_CLOCK_TCK 0x23 #define CMD_SLEEP_US 0x24 #define CMD_SLEEP_MS 0x25 #define CMD_GET_SIGNALS 0x26 #define CMD_SET_SIGNALS 0x27 #define CMD_CONFIGURE_TCK_FREQ 0x28 #define CMD_SET_LEDS 0x29 #define CMD_TEST 0x2A /* JTAG signal definition for jtag_get_signals() -- Input signals! */ #define SIGNAL_TDO (1<<0) #define SIGNAL_BRKOUT (1<<1) #define SIGNAL_TRAP (1<<2) #define SIGNAL_RTCK (1<<3) /* JTAG signal definition for jtag_get_signals() -- Output signals! */ #define SIGNAL_TDI (1<<0) #define SIGNAL_TMS (1<<1) #define SIGNAL_TCK (1<<2) #define SIGNAL_TRST (1<<3) #define SIGNAL_BRKIN (1<<4) #define SIGNAL_RESET (1<<5) #define SIGNAL_OCDSE (1<<6) /* LED definitions for CMD_SET_LEDS and CMD_CLEAR_LEDS commands */ #define COM_LED_ON (1<<0) #define RUN_LED_ON (1<<1) #define COM_LED_OFF (1<<2) #define RUN_LED_OFF (1<<3) #endif openocd-0.7.0/src/jtag/drivers/OpenULINK/include/usb.h0000644000175000001440000002417112134336410017347 00000000000000/*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef __USB_H #define __USB_H #include "reg_ezusb.h" #include #include #define NULL (void *)0; /* High and Low byte of a word (uint16_t) */ #define HI8(word) (uint8_t)(((uint16_t)word >> 8) & 0xff) #define LO8(word) (uint8_t)((uint16_t)word & 0xff) /* Convenience functions */ #define STALL_EP0() (EP0CS |= EP0STALL) #define CLEAR_IRQ() (EXIF &= ~USBINT) /*********** USB descriptors. See section 9.5 of the USB 1.1 spec **********/ /* USB Descriptor Types. See USB 1.1 spec, page 187, table 9-5 */ #define DESCRIPTOR_TYPE_DEVICE 0x01 #define DESCRIPTOR_TYPE_CONFIGURATION 0x02 #define DESCRIPTOR_TYPE_STRING 0x03 #define DESCRIPTOR_TYPE_INTERFACE 0x04 #define DESCRIPTOR_TYPE_ENDPOINT 0x05 #define STR_DESCR(len, ...) { len * 2 + 2, DESCRIPTOR_TYPE_STRING, { __VA_ARGS__ } } /** USB Device Descriptor. See USB 1.1 spec, pp. 196 - 198 */ struct usb_device_descriptor { uint8_t bLength; /* /< Size of this descriptor in bytes. */ uint8_t bDescriptorType;/* /< DEVICE Descriptor Type. */ uint16_t bcdUSB; /* /< USB specification release number (BCD). */ uint8_t bDeviceClass; /* /< Class code. */ uint8_t bDeviceSubClass;/* /< Subclass code. */ uint8_t bDeviceProtocol;/* /< Protocol code. */ uint8_t bMaxPacketSize0;/* /< Maximum packet size for EP0 (8, 16, 32, 64). */ uint16_t idVendor; /* /< USB Vendor ID. */ uint16_t idProduct; /* /< USB Product ID. */ uint16_t bcdDevice; /* /< Device Release Number (BCD). */ uint8_t iManufacturer; /* /< Index of manufacturer string descriptor. */ uint8_t iProduct; /* /< Index of product string descriptor. */ uint8_t iSerialNumber; /* /< Index of string descriptor containing serial #. */ uint8_t bNumConfigurations; /* /< Number of possible configurations. */ }; /** USB Configuration Descriptor. See USB 1.1 spec, pp. 199 - 200 */ struct usb_config_descriptor { uint8_t bLength; /* /< Size of this descriptor in bytes. */ uint8_t bDescriptorType;/* /< CONFIGURATION descriptor type. */ uint16_t wTotalLength; /* /< Combined total length of all descriptors. */ uint8_t bNumInterfaces; /* /< Number of interfaces in this configuration. */ uint8_t bConfigurationValue; /* /< Value used to select this configuration. */ uint8_t iConfiguration; /* /< Index of configuration string descriptor. */ uint8_t bmAttributes; /* /< Configuration characteristics. */ uint8_t MaxPower; /* /< Maximum power consumption in 2 mA units. */ }; /** USB Interface Descriptor. See USB 1.1 spec, pp. 201 - 203 */ struct usb_interface_descriptor { uint8_t bLength; /* /< Size of this descriptor in bytes. */ uint8_t bDescriptorType;/* /< INTERFACE descriptor type. */ uint8_t bInterfaceNumber; /* /< Interface number. */ uint8_t bAlternateSetting; /* /< Value used to select alternate setting. */ uint8_t bNumEndpoints; /* /< Number of endpoints used by this interface. */ uint8_t bInterfaceClass;/* /< Class code. */ uint8_t bInterfaceSubclass; /* /< Subclass code. */ uint8_t bInterfaceProtocol; /* /< Protocol code. */ uint8_t iInterface; /* /< Index of interface string descriptor. */ }; /** USB Endpoint Descriptor. See USB 1.1 spec, pp. 203 - 204 */ struct usb_endpoint_descriptor { uint8_t bLength; /* /< Size of this descriptor in bytes. */ uint8_t bDescriptorType;/* /< ENDPOINT descriptor type. */ uint8_t bEndpointAddress; /* /< Endpoint Address: USB 1.1 spec, table 9-10. */ uint8_t bmAttributes; /* /< Endpoint Attributes: USB 1.1 spec, table 9-10. */ uint16_t wMaxPacketSize;/* /< Maximum packet size for this endpoint. */ uint8_t bInterval; /* /< Polling interval (in ms) for this endpoint. */ }; /** USB Language Descriptor. See USB 1.1 spec, pp. 204 - 205 */ struct usb_language_descriptor { uint8_t bLength; /* /< Size of this descriptor in bytes. */ uint8_t bDescriptorType;/* /< STRING descriptor type. */ uint16_t wLANGID[]; /* /< LANGID codes. */ }; /** USB String Descriptor. See USB 1.1 spec, pp. 204 - 205 */ struct usb_string_descriptor { uint8_t bLength; /* /< Size of this descriptor in bytes. */ uint8_t bDescriptorType;/* /< STRING descriptor type. */ uint16_t bString[]; /* /< UNICODE encoded string. */ }; /********************** USB Control Endpoint 0 related *********************/ /** USB Control Setup Data. See USB 1.1 spec, pp. 183 - 185 */ struct setup_data { uint8_t bmRequestType; /* /< Characteristics of a request. */ uint8_t bRequest; /* /< Specific request. */ uint16_t wValue; /* /< Field that varies according to request. */ uint16_t wIndex; /* /< Field that varies according to request. */ uint16_t wLength; /* /< Number of bytes to transfer in data stage. */ }; /* External declarations for variables that need to be accessed outside of * the USB module */ extern volatile bool EP2_out; extern volatile bool EP2_in; extern volatile __xdata __at 0x7FE8 struct setup_data setup_data; /* * USB Request Types (bmRequestType): See USB 1.1 spec, page 183, table 9-2 * * Bit 7: Data transfer direction * 0 = Host-to-device * 1 = Device-to-host * Bit 6...5: Type * 0 = Standard * 1 = Class * 2 = Vendor * 3 = Reserved * Bit 4...0: Recipient * 0 = Device * 1 = Interface * 2 = Endpoint * 3 = Other * 4...31 = Reserved */ #define USB_DIR_OUT 0x00 #define USB_DIR_IN 0x80 #define USB_REQ_TYPE_STANDARD (0x00 << 5) #define USB_REQ_TYPE_CLASS (0x01 << 5) #define USB_REQ_TYPE_VENDOR (0x02 << 5) #define USB_REQ_TYPE_RESERVED (0x03 << 5) #define USB_RECIP_DEVICE 0x00 #define USB_RECIP_INTERFACE 0x01 #define USB_RECIP_ENDPOINT 0x02 #define USB_RECIP_OTHER 0x03 /* bmRequestType for USB Standard Requests */ /* Clear Interface Request */ #define CF_DEVICE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE) #define CF_INTERFACE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_INTERFACE) #define CF_ENDPOINT (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_ENDPOINT) /* Get Configuration Request */ #define GC_DEVICE (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE) /* Get Descriptor Request */ #define GD_DEVICE (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE) /* Get Interface Request */ #define GI_INTERFACE (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_INTERFACE) /* Get Status Request: See USB 1.1 spec, page 190 */ #define GS_DEVICE (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE) #define GS_INTERFACE (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_INTERFACE) #define GS_ENDPOINT (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_ENDPOINT) /* Set Address Request is handled by EZ-USB core */ /* Set Configuration Request */ #define SC_DEVICE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE) /* Set Descriptor Request */ #define SD_DEVICE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE) /* Set Feature Request */ #define SF_DEVICE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_DEVICE) #define SF_INTERFACE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_INTERFACE) #define SF_ENDPOINT (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_ENDPOINT) /* Set Interface Request */ #define SI_INTERFACE (USB_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_RECIP_INTERFACE) /* Synch Frame Request */ #define SY_ENDPOINT (USB_DIR_IN | USB_REQ_TYPE_STANDARD | USB_RECIP_ENDPOINT) /* USB Requests (bRequest): See USB 1.1 spec, table 9-4 on page 187 */ #define GET_STATUS 0 #define CLEAR_FEATURE 1 /* Value '2' is reserved for future use */ #define SET_FEATURE 3 /* Value '4' is reserved for future use */ #define SET_ADDRESS 5 #define GET_DESCRIPTOR 6 #define SET_DESCRIPTOR 7 #define GET_CONFIGURATION 8 #define SET_CONFIGURATION 9 #define GET_INTERFACE 10 #define SET_INTERFACE 11 #define SYNCH_FRAME 12 /* Standard Feature Selectors: See USB 1.1 spec, table 9-6 on page 188 */ #define DEVICE_REMOTE_WAKEUP 1 #define ENDPOINT_HALT 0 /************************** EZ-USB specific stuff **************************/ /** USB Interrupts. See AN2131-TRM, page 9-4 for details */ enum usb_isr { SUDAV_ISR = 13, SOF_ISR, SUTOK_ISR, SUSPEND_ISR, USBRESET_ISR, IBN_ISR, EP0IN_ISR, EP0OUT_ISR, EP1IN_ISR, EP1OUT_ISR, EP2IN_ISR, EP2OUT_ISR, EP3IN_ISR, EP3OUT_ISR, EP4IN_ISR, EP4OUT_ISR, EP5IN_ISR, EP5OUT_ISR, EP6IN_ISR, EP6OUT_ISR, EP7IN_ISR, EP7OUT_ISR }; /*************************** Function Prototypes ***************************/ __xdata uint8_t *usb_get_endpoint_cs_reg(uint8_t ep); void usb_reset_data_toggle(uint8_t ep); bool usb_handle_get_status(void); bool usb_handle_clear_feature(void); bool usb_handle_set_feature(void); bool usb_handle_get_descriptor(void); void usb_handle_set_interface(void); void usb_handle_setup_data(void); void usb_init(void); #endif openocd-0.7.0/src/jtag/drivers/OpenULINK/include/reg_ezusb.h0000644000175000001440000005077612134336410020555 00000000000000/*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef REG_EZUSB_H #define REG_EZUSB_H /** * @file * All information in this file was taken from the EZ-USB Technical * Reference Manual, Cypress Semiconductor, 3901 North First Street * San Jose, CA 95134 (www.cypress.com). * * The EZ-USB Technical Reference Manual is called "EZ-USB TRM" hereafter. * * The following bit name definitions differ from those in the EZ-USB TRM: * - All lowercase characters in the EZ-USB TRM bit names have been converted * to capitals (e. g. "WakeSRC" converted to "WAKESRC"). * - CPUCS: 8051RES is named "RES8051". * - ISOCTL: Two MBZ ("Must Be Zero") bits are named "MBZ0" and "MBZ1". * - I2CS: STOP and START bits are preceded by "I2C_" * - INxCS, OUTxCS: the busy and stall bits are named "EPBSY" and "EPSTALL". * - TOGCTL: EZ-USB TRM bit names are preceded by "TOG_". */ /* Compiler-specific definitions of SBIT, SFR, SFRX, ... macros */ #include /* Bit vectors */ #define bmBit0 0x01 #define bmBit1 0x02 #define bmBit2 0x04 #define bmBit3 0x08 #define bmBit4 0x10 #define bmBit5 0x20 #define bmBit6 0x40 #define bmBit7 0x80 /************************************************************************** ************************ Special Function Registers ********************** ***************************************************************************/ /* See EZ-USB TRM, pp. A-9 - A-10 */ SFR(SP, 0x81); SFR(DPL0, 0x82); SFR(DPH0, 0x83); SFR(DPL1, 0x84); SFR(DPL2, 0x85); SFR(DPS, 0x86); #define SEL bmBit0 /* Bit 1 read-only, always reads '0' */ /* Bit 2 read-only, always reads '0' */ /* Bit 3 read-only, always reads '0' */ /* Bit 4 read-only, always reads '0' */ /* Bit 5 read-only, always reads '0' */ /* Bit 6 read-only, always reads '0' */ /* Bit 7 read-only, always reads '0' */ SFR(PCON, 0x87); #define IDLE bmBit0 #define STOP bmBit1 #define GF0 bmBit2 #define GF1 bmBit3 /* Bit 4 read-only, always reads '1' */ /* Bit 5 read-only, always reads '1' */ /* Bit 6 unused */ #define SMOD0 bmBit7 SFR(TCON, 0x88); SBIT(IT0, 0x88, 0); SBIT(IE0, 0x88, 1); SBIT(IT1, 0x88, 2); SBIT(IE1, 0x88, 3); SBIT(TR0, 0x88, 4); SBIT(TF0, 0x88, 5); SBIT(TR1, 0x88, 6); SBIT(TF1, 0x88, 7); SFR(TMOD, 0x89); /* Some bits in this register share the same name in the EZ-USB TRM. Therefore, * we add a '0'/'1' to distinguish them */ #define M00 bmBit0 #define M01 bmBit1 #define CT0 bmBit2 #define GATE0 bmBit3 #define M10 bmBit4 #define M11 bmBit5 #define CT1 bmBit6 #define GATE1 bmBit7 SFR(TL0, 0x8A); SFR(TL1, 0x8B); SFR(TH0, 0x8C); SFR(TH1, 0x8D); SFR(CKCON, 0x8E); #define MD0 bmBit0 #define MD1 bmBit1 #define MD2 bmBit2 #define T0M bmBit3 #define T1M bmBit4 #define T2M bmBit5 /* Bit 6 unused */ /* Bit 7 unused */ SFR(SPC_FNC, 0x8D); #define bmWRS bmBit0 /* Bit 1 read-only, always reads '0' */ /* Bit 2 read-only, always reads '0' */ /* Bit 3 read-only, always reads '0' */ /* Bit 4 read-only, always reads '0' */ /* Bit 5 read-only, always reads '0' */ /* Bit 6 read-only, always reads '0' */ /* Bit 7 read-only, always reads '0' */ SFR(EXIF, 0x91); /* Bit 0 read-only, always reads '0' */ /* Bit 1 read-only, always reads '0' */ /* Bit 2 read-only, always reads '0' */ /* Bit 3 read-only, always reads '1' */ #define USBINT bmBit4 #define I2CINT bmBit5 #define IE4 bmBit6 #define IE5 bmBit7 /* Definition of the _XPAGE register, according to SDCC Compiler User Guide, * Version 3.0.1, Chapter 4, p. 61. Also see EZ-USB TRM, p. 2-4. */ SFR(MPAGE, 0x92); SFR(_XPAGE, 0x92); SFR(SCON0, 0x98); SBIT(RI_0, 0x98, 0); SBIT(TI_0, 0x98, 1); SBIT(RB8_0, 0x98, 2); SBIT(TB8_0, 0x98, 3); SBIT(REN_0, 0x98, 4); SBIT(SM2_0, 0x98, 5); SBIT(SM1_0, 0x98, 6); SBIT(SM0_0, 0x98, 7); SFR(SBUF0, 0x99); SFR(IE, 0xA8); SBIT(EX0, 0xA8, 0); SBIT(ET0, 0xA8, 1); SBIT(EX1, 0xA8, 2); SBIT(ET1, 0xA8, 3); SBIT(ES0, 0xA8, 4); SBIT(ET2, 0xA8, 5); SBIT(ES1, 0xA8, 6); SBIT(EA, 0xA8, 7); SFR(IP, 0xB8); SBIT(PX0, 0xB8, 0); SBIT(PT0, 0xB8, 1); SBIT(PX1, 0xB8, 2); SBIT(PT1, 0xB8, 3); SBIT(PS0, 0xB8, 4); SBIT(PT2, 0xB8, 5); SBIT(PS1, 0xB8, 6); /* Bit 7 read-only, always reads '1' */ SFR(SCON1, 0xC0); SBIT(RI_1, 0xC0, 0); SBIT(TI_1, 0xC0, 1); SBIT(RB8_1, 0xC0, 2); SBIT(TB8_1, 0xC0, 3); SBIT(REN_1, 0xC0, 4); SBIT(SM2_1, 0xC0, 5); SBIT(SM1_1, 0xC0, 6); SBIT(SM0_1, 0xC0, 7); SFR(SBUF1, 0xC1); SFR(T2CON, 0xC8); SBIT(CPRL2, 0xC8, 0); SBIT(CT2, 0xC8, 1); SBIT(TR2, 0xC8, 2); SBIT(EXEN2, 0xC8, 3); SBIT(TCLK, 0xC8, 4); SBIT(RCLK, 0xC8, 5); SBIT(EXF2, 0xC8, 6); SBIT(TF2, 0xC8, 7); SFR(RCAP2L, 0xCA); SFR(RCAP2H, 0xCB); SFR(TL2, 0xCC); SFR(TH2, 0xCD); SFR(PSW, 0xD0); SBIT(P, 0xD0, 0); SBIT(F1, 0xD0, 1); SBIT(OV, 0xD0, 2); SBIT(RS0, 0xD0, 3); SBIT(RS1, 0xD0, 4); SBIT(F0, 0xD0, 5); SBIT(AC, 0xD0, 6); SBIT(CY, 0xD0, 7); SFR(EICON, 0xD8); /* Bit 0 read-only, always reads '0' */ /* Bit 1 read-only, always reads '0' */ /* Bit 2 read-only, always reads '0' */ SBIT(INT6, 0xD8, 3); SBIT(RESI, 0xD8, 4); SBIT(ERESI, 0xD8, 5); /* Bit 6 read-only, always reads '1' */ SBIT(SMOD1, 0xD8, 7); SFR(ACC, 0xE0); SFR(EIE, 0xE8); SBIT(EUSB, 0xE8, 0); SBIT(EI2C, 0xE8, 1); SBIT(EX4, 0xE8, 2); SBIT(EX5, 0xE8, 3); SBIT(EWDI, 0xE8, 4); /* Bit 5 read-only, always reads '1' */ /* Bit 6 read-only, always reads '1' */ /* Bit 7 read-only, always reads '1' */ SFR(B, 0xF0); SFR(EIP, 0xF8); SBIT(PUSB, 0xF8, 0); SBIT(PI2C, 0xF8, 1); SBIT(PX4, 0xF8, 2); SBIT(PX5, 0xF8, 3); SBIT(PX6, 0xF8, 4); /* Bit 5 read-only, always reads '1' */ /* Bit 6 read-only, always reads '1' */ /* Bit 7 read-only, always reads '1' */ /************************************************************************** ***************************** XDATA Registers **************************** ***************************************************************************/ /************************ Endpoint 0-7 Data Buffers ************************/ SFRX(OUT7BUF[64], 0x7B40); SFRX(IN7BUF[64], 0x7B80); SFRX(OUT6BUF[64], 0x7BC0); SFRX(IN6BUF[64], 0x7C00); SFRX(OUT5BUF[64], 0x7C40); SFRX(IN5BUF[64], 0x7C80); SFRX(OUT4BUF[64], 0x7CC0); SFRX(IN4BUF[64], 0x7D00); SFRX(OUT3BUF[64], 0x7D40); SFRX(IN3BUF[64], 0x7D80); SFRX(OUT2BUF[64], 0x7DC0); SFRX(IN2BUF[64], 0x7E00); SFRX(OUT1BUF[64], 0x7E40); SFRX(IN1BUF[64], 0x7E80); SFRX(OUT0BUF[64], 0x7EC0); SFRX(IN0BUF[64], 0x7F00); /* 0x7F40 - 0x7F5F reserved */ /**************************** Isochronous Data *****************************/ SFRX(OUT8DATA, 0x7F60); SFRX(OUT9DATA, 0x7F61); SFRX(OUT10DATA, 0x7F62); SFRX(OUT11DATA, 0x7F63); SFRX(OUT12DATA, 0x7F64); SFRX(OUT13DATA, 0x7F65); SFRX(OUT14DATA, 0x7F66); SFRX(OUT15DATA, 0x7F67); SFRX(IN8DATA, 0x7F68); SFRX(IN9DATA, 0x7F69); SFRX(IN10DATA, 0x7F6A); SFRX(IN11DATA, 0x7F6B); SFRX(IN12DATA, 0x7F6C); SFRX(IN13DATA, 0x7F6D); SFRX(IN14DATA, 0x7F6E); SFRX(IN15DATA, 0x7F6F); /************************* Isochronous Byte Counts *************************/ SFRX(OUT8BCH, 0x7F70); SFRX(OUT8BCL, 0x7F71); SFRX(OUT9BCH, 0x7F72); SFRX(OUT9BCL, 0x7F73); SFRX(OUT10BCH, 0x7F74); SFRX(OUT10BCL, 0x7F75); SFRX(OUT11BCH, 0x7F76); SFRX(OUT11BCL, 0x7F77); SFRX(OUT12BCH, 0x7F78); SFRX(OUT12BCL, 0x7F79); SFRX(OUT13BCH, 0x7F7A); SFRX(OUT13BCL, 0x7F7B); SFRX(OUT14BCH, 0x7F7C); SFRX(OUT14BCL, 0x7F7D); SFRX(OUT15BCH, 0x7F7E); SFRX(OUT16BCL, 0x7F7F); /****************************** CPU Registers ******************************/ SFRX(CPUCS, 0x7F92); #define RES8051 bmBit0 #define CLK24OE bmBit1 /* Bit 2 read-only, always reads '0' */ /* Bit 3 read-only, always reads '0' */ /* Bits 4...7: Chip Revision */ SFRX(PORTACFG, 0x7F93); #define T0OUT bmBit0 #define T1OUT bmBit1 #define OE bmBit2 #define CS bmBit3 #define FWR bmBit4 #define FRD bmBit5 #define RXD0OUT bmBit6 #define RXD1OUT bmBit7 SFRX(PORTBCFG, 0x7F94); #define T2 bmBit0 #define T2EX bmBit1 #define RXD1 bmBit2 #define TXD1 bmBit3 #define INT4 bmBit4 #define INT5 bmBit5 #define INT6 bmBit6 #define T2OUT bmBit7 SFRX(PORTCCFG, 0x7F95); #define RXD0 bmBit0 #define TXD0 bmBit1 #define INT0 bmBit2 #define INT1 bmBit3 #define T0 bmBit4 #define T1 bmBit5 #define WR bmBit6 #define RD bmBit7 /*********************** Input-Output Port Registers ***********************/ SFRX(OUTA, 0x7F96); #define OUTA0 bmBit0 #define OUTA1 bmBit1 #define OUTA2 bmBit2 #define OUTA3 bmBit3 #define OUTA4 bmBit4 #define OUTA5 bmBit5 #define OUTA6 bmBit6 #define OUTA7 bmBit7 SFRX(OUTB, 0x7F97); #define OUTB0 bmBit0 #define OUTB1 bmBit1 #define OUTB2 bmBit2 #define OUTB3 bmBit3 #define OUTB4 bmBit4 #define OUTB5 bmBit5 #define OUTB6 bmBit6 #define OUTB7 bmBit7 SFRX(OUTC, 0x7F98); #define OUTC0 bmBit0 #define OUTC1 bmBit1 #define OUTC2 bmBit2 #define OUTC3 bmBit3 #define OUTC4 bmBit4 #define OUTC5 bmBit5 #define OUTC6 bmBit6 #define OUTC7 bmBit7 SFRX(PINSA, 0x7F99); #define PINA0 bmBit0 #define PINA1 bmBit1 #define PINA2 bmBit2 #define PINA3 bmBit3 #define PINA4 bmBit4 #define PINA5 bmBit5 #define PINA6 bmBit6 #define PINA7 bmBit7 SFRX(PINSB, 0x7F9A); #define PINB0 bmBit0 #define PINB1 bmBit1 #define PINB2 bmBit2 #define PINB3 bmBit3 #define PINB4 bmBit4 #define PINB5 bmBit5 #define PINB6 bmBit6 #define PINB7 bmBit7 SFRX(PINSC, 0x7F9B); #define PINC0 bmBit0 #define PINC1 bmBit1 #define PINC2 bmBit2 #define PINC3 bmBit3 #define PINC4 bmBit4 #define PINC5 bmBit5 #define PINC6 bmBit6 #define PINC7 bmBit7 SFRX(OEA, 0x7F9C); #define OEA0 bmBit0 #define OEA1 bmBit1 #define OEA2 bmBit2 #define OEA3 bmBit3 #define OEA4 bmBit4 #define OEA5 bmBit5 #define OEA6 bmBit6 #define OEA7 bmBit7 SFRX(OEB, 0x7F9D); #define OEB0 bmBit0 #define OEB1 bmBit1 #define OEB2 bmBit2 #define OEB3 bmBit3 #define OEB4 bmBit4 #define OEB5 bmBit5 #define OEB6 bmBit6 #define OEB7 bmBit7 SFRX(OEC, 0x7F9E); #define OEC0 bmBit0 #define OEC1 bmBit1 #define OEC2 bmBit2 #define OEC3 bmBit3 #define OEC4 bmBit4 #define OEC5 bmBit5 #define OEC6 bmBit6 #define OEC7 bmBit7 /* 0x7F9F reserved */ /****************** Isochronous Control/Status Registers *******************/ SFRX(ISOERR, 0x7FA0); #define ISO8ERR bmBit0 #define ISO9ERR bmBit1 #define ISO10ERR bmBit2 #define ISO11ERR bmBit3 #define ISO12ERR bmBit4 #define ISO13ERR bmBit5 #define ISO14ERR bmBit6 #define ISO15ERR bmBit7 SFRX(ISOCTL, 0x7FA1); #define ISODISAB bmBit0 #define MBZ0 bmBit1 #define MBZ1 bmBit2 #define PPSTAT bmBit3 /* Bit 4 unused */ /* Bit 5 unused */ /* Bit 6 unused */ /* Bit 7 unused */ SFRX(ZBCOUT, 0x7FA2); #define EP8 bmBit0 #define EP9 bmBit1 #define EP10 bmBit2 #define EP11 bmBit3 #define EP12 bmBit4 #define EP13 bmBit5 #define EP14 bmBit6 #define EP15 bmBit7 /* 0x7FA3 reserved */ /* 0x7FA4 reserved */ /****************************** I2C Registers ******************************/ SFRX(I2CS, 0x7FA5); #define DONE bmBit0 #define ACK bmBit1 #define BERR bmBit2 #define ID0 bmBit3 #define ID1 bmBit4 #define LASTRD bmBit5 #define I2C_STOP bmBit6 #define I2C_START bmBit7 SFRX(I2DAT, 0x7FA6); /* 0x7FA7 reserved */ /******************************* Interrupts ********************************/ SFRX(IVEC, 0x7FA8); /* Bit 0 read-only, always reads '0' */ /* Bit 1 read-only, always reads '0' */ #define IV0 bmBit2 #define IV1 bmBit3 #define IV2 bmBit4 #define IV3 bmBit5 #define IV4 bmBit6 /* Bit 7 read-only, always reads '0' */ SFRX(IN07IRQ, 0x7FA9); #define IN0IR bmBit0 #define IN1IR bmBit1 #define IN2IR bmBit2 #define IN3IR bmBit3 #define IN4IR bmBit4 #define IN5IR bmBit5 #define IN6IR bmBit6 #define IN7IR bmBit7 SFRX(OUT07IRQ, 0x7FAA); #define OUT0IR bmBit0 #define OUT1IR bmBit1 #define OUT2IR bmBit2 #define OUT3IR bmBit3 #define OUT4IR bmBit4 #define OUT5IR bmBit5 #define OUT6IR bmBit6 #define OUT7IR bmBit7 SFRX(USBIRQ, 0x7FAB); #define SUDAVIR bmBit0 #define SOFIR bmBit1 #define SUTOKIR bmBit2 #define SUSPIR bmBit3 #define URESIR bmBit4 /* Bit 5 unused */ /* Bit 6 unused */ /* Bit 7 unused */ SFRX(IN07IEN, 0x7FAC); #define IN0IEN bmBit0 #define IN1IEN bmBit1 #define IN2IEN bmBit2 #define IN3IEN bmBit3 #define IN4IEN bmBit4 #define IN5IEN bmBit5 #define IN6IEN bmBit6 #define IN7IEN bmBit7 SFRX(OUT07IEN, 0x7FAD); #define OUT0IEN bmBit0 #define OUT1IEN bmBit1 #define OUT2IEN bmBit2 #define OUT3IEN bmBit3 #define OUT4IEN bmBit4 #define OUT5IEN bmBit5 #define OUT6IEN bmBit6 #define OUT7IEN bmBit7 SFRX(USBIEN, 0x7FAE); #define SUDAVIE bmBit0 #define SOFIE bmBit1 #define SUTOKIE bmBit2 #define SUSPIE bmBit3 #define URESIE bmBit4 /* Bit 5 unused */ /* Bit 6 unused */ /* Bit 7 unused */ SFRX(USBBAV, 0x7FAF); #define AVEN bmBit0 #define BPEN bmBit1 #define BPPULSE bmBit2 #define BREAK bmBit3 /* Bit 4 unused */ /* Bit 5 unused */ /* Bit 6 unused */ /* Bit 7 unused */ /* 0x7FB0 reserved */ /* 0x7FB1 reserved */ SFRX(BPADDRH, 0x7FB2); SFRX(BPADDRL, 0x7FB3); /****************************** Endpoints 0-7 ******************************/ SFRX(EP0CS, 0x7FB4); #define EP0STALL bmBit0 #define HSNAK bmBit1 #define IN0BSY bmBit2 #define OUT0BSY bmBit3 /* Bit 4 unused */ /* Bit 5 unused */ /* Bit 6 unused */ /* Bit 7 unused */ SFRX(IN0BC, 0x7FB5); SFRX(IN1CS, 0x7FB6); SFRX(IN1BC, 0x7FB7); SFRX(IN2CS, 0x7FB8); SFRX(IN2BC, 0x7FB9); SFRX(IN3CS, 0x7FBA); SFRX(IN3BC, 0x7FBB); SFRX(IN4CS, 0x7FBC); SFRX(IN4BC, 0x7FBD); SFRX(IN5CS, 0x7FBE); SFRX(IN5BC, 0x7FBF); SFRX(IN6CS, 0x7FC0); SFRX(IN6BC, 0x7FC1); SFRX(IN7CS, 0x7FC2); SFRX(IN7BC, 0x7FC3); /* 0x7FC4 reserved */ SFRX(OUT0BC, 0x7FC5); SFRX(OUT1CS, 0x7FC6); SFRX(OUT1BC, 0x7FC7); SFRX(OUT2CS, 0x7FC8); SFRX(OUT2BC, 0x7FC9); SFRX(OUT3CS, 0x7FCA); SFRX(OUT3BC, 0x7FCB); SFRX(OUT4CS, 0x7FCC); SFRX(OUT4BC, 0x7FCD); SFRX(OUT5CS, 0x7FCE); SFRX(OUT5BC, 0x7FCF); SFRX(OUT6CS, 0x7FD0); SFRX(OUT6BC, 0x7FD1); SFRX(OUT7CS, 0x7FD2); SFRX(OUT7BC, 0x7FD3); /* The INxSTALL, OUTxSTALL, INxBSY and OUTxBSY bits are the same for all * INxCS/OUTxCS registers. For better readability, we define them only once */ #define EPSTALL bmBit0 #define EPBSY bmBit1 /************************** Global USB Registers ***************************/ SFRX(SUDPTRH, 0x7FD4); SFRX(SUDPTRL, 0x7FD5); SFRX(USBCS, 0x7FD6); #define SIGRSUME bmBit0 #define RENUM bmBit1 #define DISCOE bmBit2 #define DISCON bmBit3 /* Bit 4 unused */ /* Bit 5 unused */ /* Bit 6 unused */ #define WAKESRC bmBit7 SFRX(TOGCTL, 0x7FD7); #define TOG_EP0 bmBit0 #define TOG_EP1 bmBit1 #define TOG_EP2 bmBit2 /* Bit 3 is read-only, always reads '0' */ #define TOG_IO bmBit4 #define TOG_R bmBit5 #define TOG_S bmBit6 #define TOG_Q bmBit7 SFRX(USBFRAMEL, 0x7FD8); SFRX(USBFRAMEH, 0x7FD9); /* 0x7FDA reserved */ SFRX(FNADDR, 0x7FDB); /* 0x7FDC reserved */ SFRX(USBPAIR, 0x7FDD); #define PR2IN bmBit0 #define PR4IN bmBit1 #define PR6IN bmBit2 #define PR2OUT bmBit3 #define PR4OUT bmBit4 #define PR6OUT bmBit5 /* Bit 6 unused */ #define ISOSEND0 bmBit7 SFRX(IN07VAL, 0x7FDE); /* Bit 0 is read-only, always reads '1' */ #define IN1VAL bmBit1 #define IN2VAL bmBit2 #define IN3VAL bmBit3 #define IN4VAL bmBit4 #define IN5VAL bmBit5 #define IN6VAL bmBit6 #define IN7VAL bmBit7 SFRX(OUT07VAL, 0x7FDF); /* Bit 0 is read-only, always reads '1' */ #define OUT1VAL bmBit1 #define OUT2VAL bmBit2 #define OUT3VAL bmBit3 #define OUT4VAL bmBit4 #define OUT5VAL bmBit5 #define OUT6VAL bmBit6 #define OUT7VAL bmBit7 SFRX(INISOVAL, 0x7FE0); #define IN8VAL bmBit0 #define IN9VAL bmBit1 #define IN10VAL bmBit2 #define IN11VAL bmBit3 #define IN12VAL bmBit4 #define IN13VAL bmBit5 #define IN14VAL bmBit6 #define IN15VAL bmBit7 SFRX(OUTISOVAL, 0x7FE1); #define OUT8VAL bmBit0 #define OUT9VAL bmBit1 #define OUT10VAL bmBit2 #define OUT11VAL bmBit3 #define OUT12VAL bmBit4 #define OUT13VAL bmBit5 #define OUT14VAL bmBit6 #define OUT15VAL bmBit7 SFRX(FASTXFR, 0x7FE2); #define WMOD0 bmBit0 #define WMOD1 bmBit1 #define WPOL bmBit2 #define RMOD0 bmBit3 #define RMOD1 bmBit4 #define RPOL bmBit5 #define FBLK bmBit6 #define FISO bmBit7 SFRX(AUTOPTRH, 0x7FE3); SFRX(AUTOPTRL, 0x7FE4); SFRX(AUTODATA, 0x7FE5); /* 0x7FE6 reserved */ /* 0x7FE7 reserved */ /******************************* Setup Data ********************************/ SFRX(SETUPDAT[8], 0x7FE8); /************************* Isochronous FIFO sizes **************************/ SFRX(OUT8ADDR, 0x7FF0); SFRX(OUT9ADDR, 0x7FF1); SFRX(OUT10ADDR, 0x7FF2); SFRX(OUT11ADDR, 0x7FF3); SFRX(OUT12ADDR, 0x7FF4); SFRX(OUT13ADDR, 0x7FF5); SFRX(OUT14ADDR, 0x7FF6); SFRX(OUT15ADDR, 0x7FF7); SFRX(IN8ADDR, 0x7FF8); SFRX(IN9ADDR, 0x7FF9); SFRX(IN10ADDR, 0x7FFA); SFRX(IN11ADDR, 0x7FFB); SFRX(IN12ADDR, 0x7FFC); SFRX(IN13ADDR, 0x7FFD); SFRX(IN14ADDR, 0x7FFE); SFRX(IN15ADDR, 0x7FFF); #endif openocd-0.7.0/src/jtag/drivers/OpenULINK/include/main.h0000644000175000001440000000277012134336410017503 00000000000000/*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef __MAIN_H #define __MAIN_H void io_init(void); #endif openocd-0.7.0/src/jtag/drivers/OpenULINK/include/protocol.h0000644000175000001440000000316012134336410020412 00000000000000/*************************************************************************** * Copyright (C) 2011 by Martin Schmoelzer * * * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef __PROTOCOL_H #define __PROTOCOL_H #include "common.h" #include void execute_set_led_command(void); bool execute_command(void); void command_loop(void); #endif openocd-0.7.0/src/jtag/drivers/OpenULINK/README0000644000175000001440000000361012134336410015635 00000000000000This is the OpenULINK firmware for the Keil ULINK JTAG adapter. The main components of the Keil ULINK adapter are: - Cypress EZ-USB microcontroller: enhanced 8051 CPU + USB core (1.1 Full-Speed) - SRAM memory chip - Level shifters to support different JTAG signal voltage levels - Pin headers for various JTAG pin assignments This firmware can only be run on the ORIGINAL Keil ULINK adapter, not on the newer ULINK2, ULINK-ME or ULINK-PRO, as these adapters are based on different hardware. To compile the firmware, the SDCC compiler package is required. Most Linux distributions include SDCC in their official package repositories. The SDCC source code can be found at http://sdcc.sourceforge.net/ Simply type "make hex" in the OpenULINK directory to compile the firmware. "make clean" will remove all generated files except the Intel HEX file required for downloading the firmware to the ULINK adapter. Note that the EZ-USB microcontroller does not have on-chip flash, nor does the Keil ULINK include on-board memory to store the firmware program of the EZ-USB. Instead, upon initial connection of the ULINK adapter to the host PC via USB, the EZ-USB core has enough intelligence to act as a stand-alone USB device, responding to USB control requests and allowing firmware download via a special VENDOR-type control request. Then, the EZ-USB microcontroller simulates a disconnect and re-connect to the USB bus. It may take up to two seconds for the host to recognize the newly connected device before OpenOCD can proceed to execute JTAG commands. This delay is only visible when OpenOCD first uses a blank (unconfigured) ULINK device. Once the user disconnects the ULINK adapter, all its memory contents are lost and the firmware download process has to be executed again. This also maintains compatibility with the original Keil uVision IDE, which will happily download its own firmware image to a blank ULINK adapter. openocd-0.7.0/src/jtag/drivers/dummy.c0000644000175000001440000001030312134336410014545 00000000000000/*************************************************************************** * Copyright (C) 2008 by Øyvind Harboe * * oyvind.harboe@zylin.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "bitbang.h" #include "hello.h" /* my private tap controller state, which tracks state for calling code */ static tap_state_t dummy_state = TAP_RESET; static int dummy_clock; /* edge detector */ static int clock_count; /* count clocks in any stable state, only stable states */ static uint32_t dummy_data; static int dummy_read(void) { int data = 1 & dummy_data; dummy_data = (dummy_data >> 1) | (1 << 31); return data; } static void dummy_write(int tck, int tms, int tdi) { /* TAP standard: "state transitions occur on rising edge of clock" */ if (tck != dummy_clock) { if (tck) { tap_state_t old_state = dummy_state; dummy_state = tap_state_transition(old_state, tms); if (old_state != dummy_state) { if (clock_count) { LOG_DEBUG("dummy_tap: %d stable clocks", clock_count); clock_count = 0; } LOG_DEBUG("dummy_tap: %s", tap_state_name(dummy_state)); #if defined(DEBUG) if (dummy_state == TAP_DRCAPTURE) dummy_data = 0x01255043; #endif } else { /* this is a stable state clock edge, no change of state here, * simply increment clock_count for subsequent logging */ ++clock_count; } } dummy_clock = tck; } } static void dummy_reset(int trst, int srst) { dummy_clock = 0; if (trst || (srst && (jtag_get_reset_config() & RESET_SRST_PULLS_TRST))) dummy_state = TAP_RESET; LOG_DEBUG("reset to: %s", tap_state_name(dummy_state)); } static void dummy_led(int on) { } static struct bitbang_interface dummy_bitbang = { .read = &dummy_read, .write = &dummy_write, .reset = &dummy_reset, .blink = &dummy_led, }; static int dummy_khz(int khz, int *jtag_speed) { if (khz == 0) *jtag_speed = 0; else *jtag_speed = 64000/khz; return ERROR_OK; } static int dummy_speed_div(int speed, int *khz) { if (speed == 0) *khz = 0; else *khz = 64000/speed; return ERROR_OK; } static int dummy_speed(int speed) { return ERROR_OK; } static int dummy_init(void) { bitbang_interface = &dummy_bitbang; return ERROR_OK; } static int dummy_quit(void) { return ERROR_OK; } static const struct command_registration dummy_command_handlers[] = { { .name = "dummy", .mode = COMMAND_ANY, .help = "dummy interface driver commands", .chain = hello_command_handlers, }, COMMAND_REGISTRATION_DONE, }; /* The dummy driver is used to easily check the code path * where the target is unresponsive. */ struct jtag_interface dummy_interface = { .name = "dummy", .supported = DEBUG_CAP_TMS_SEQ, .commands = dummy_command_handlers, .transports = jtag_only, .execute_queue = &bitbang_execute_queue, .speed = &dummy_speed, .khz = &dummy_khz, .speed_div = &dummy_speed_div, .init = &dummy_init, .quit = &dummy_quit, }; openocd-0.7.0/src/jtag/drivers/bitq.h0000644000175000001440000000374012134336410014365 00000000000000/*************************************************************************** * Copyright (C) 2007 by Pavel Chromy * * chromy@asix.cz * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef BITQ_H #define BITQ_H #include struct bitq_interface { /* function to enqueueing low level IO requests */ int (*out)(int tms, int tdi, int tdo_req); int (*flush)(void); int (*sleep)(unsigned long us); int (*reset)(int trst, int srst); /* delayed read of requested TDO data, * the input shall be checked after call to any enqueuing function */ int (*in_rdy)(void); int (*in)(void); }; extern struct bitq_interface *bitq_interface; int bitq_execute_queue(void); void bitq_cleanup(void); #endif /* BITQ_H */ openocd-0.7.0/src/jtag/drivers/parport.c0000644000175000001440000003342412137151331015112 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "bitbang.h" /* -ino: 060521-1036 */ #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #include #include #define ioperm(startport, length, enable)\ i386_set_ioperm((startport), (length), (enable)) #endif /* __FreeBSD__ */ #if PARPORT_USE_PPDEV == 1 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #include #include #define PPRSTATUS PPIGSTATUS #define PPWDATA PPISDATA #else #include #include #endif #include #else /* not PARPORT_USE_PPDEV */ #ifndef _WIN32 #include #endif #endif #if PARPORT_USE_GIVEIO == 1 && IS_CYGWIN == 1 #include #endif /* parallel port cable description */ struct cable { char *name; uint8_t TDO_MASK; /* status port bit containing current TDO value */ uint8_t TRST_MASK; /* data port bit for TRST */ uint8_t TMS_MASK; /* data port bit for TMS */ uint8_t TCK_MASK; /* data port bit for TCK */ uint8_t TDI_MASK; /* data port bit for TDI */ uint8_t SRST_MASK; /* data port bit for SRST */ uint8_t OUTPUT_INVERT; /* data port bits that should be inverted */ uint8_t INPUT_INVERT; /* status port that should be inverted */ uint8_t PORT_INIT; /* initialize data port with this value */ uint8_t PORT_EXIT; /* de-initialize data port with this value */ uint8_t LED_MASK; /* data port bit for LED */ }; static struct cable cables[] = { /* name tdo trst tms tck tdi srst o_inv i_inv init exit led */ { "wiggler", 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x01, 0x80, 0x80, 0x80, 0x00 }, { "wiggler2", 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x01, 0x80, 0x80, 0x00, 0x20 }, { "wiggler_ntrst_inverted", 0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x11, 0x80, 0x80, 0x80, 0x00 }, { "old_amt_wiggler", 0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x11, 0x80, 0x80, 0x80, 0x00 }, { "arm-jtag", 0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x01, 0x80, 0x80, 0x80, 0x00 }, { "chameleon", 0x80, 0x00, 0x04, 0x01, 0x02, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00 }, { "dlc5", 0x10, 0x00, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00 }, { "triton", 0x80, 0x08, 0x04, 0x01, 0x02, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00 }, { "lattice", 0x40, 0x10, 0x04, 0x02, 0x01, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00 }, { "flashlink", 0x20, 0x10, 0x02, 0x01, 0x04, 0x20, 0x30, 0x20, 0x00, 0x00, 0x00 }, /* Altium Universal JTAG cable. Set the cable to Xilinx Mode and wire to target as follows: HARD TCK - Target TCK HARD TMS - Target TMS HARD TDI - Target TDI HARD TDO - Target TDO SOFT TCK - Target TRST SOFT TDI - Target SRST */ { "altium", 0x10, 0x20, 0x04, 0x02, 0x01, 0x80, 0x00, 0x00, 0x10, 0x00, 0x08 }, { NULL, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }; /* configuration */ static char *parport_cable; static uint16_t parport_port; static bool parport_exit; static uint32_t parport_toggling_time_ns = 1000; static int wait_states; /* interface variables */ static struct cable *cable; static uint8_t dataport_value; #if PARPORT_USE_PPDEV == 1 static int device_handle; #else static unsigned long dataport; static unsigned long statusport; #endif static int parport_read(void) { int data = 0; #if PARPORT_USE_PPDEV == 1 ioctl(device_handle, PPRSTATUS, &data); #else data = inb(statusport); #endif if ((data ^ cable->INPUT_INVERT) & cable->TDO_MASK) return 1; else return 0; } static inline void parport_write_data(void) { uint8_t output; output = dataport_value ^ cable->OUTPUT_INVERT; #if PARPORT_USE_PPDEV == 1 ioctl(device_handle, PPWDATA, &output); #else #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) outb(dataport, output); #else outb(output, dataport); #endif #endif } static void parport_write(int tck, int tms, int tdi) { int i = wait_states + 1; if (tck) dataport_value |= cable->TCK_MASK; else dataport_value &= ~cable->TCK_MASK; if (tms) dataport_value |= cable->TMS_MASK; else dataport_value &= ~cable->TMS_MASK; if (tdi) dataport_value |= cable->TDI_MASK; else dataport_value &= ~cable->TDI_MASK; while (i-- > 0) parport_write_data(); } /* (1) assert or (0) deassert reset lines */ static void parport_reset(int trst, int srst) { LOG_DEBUG("trst: %i, srst: %i", trst, srst); if (trst == 0) dataport_value |= cable->TRST_MASK; else if (trst == 1) dataport_value &= ~cable->TRST_MASK; if (srst == 0) dataport_value |= cable->SRST_MASK; else if (srst == 1) dataport_value &= ~cable->SRST_MASK; parport_write_data(); } /* turn LED on parport adapter on (1) or off (0) */ static void parport_led(int on) { if (on) dataport_value |= cable->LED_MASK; else dataport_value &= ~cable->LED_MASK; parport_write_data(); } static int parport_speed(int speed) { wait_states = speed; return ERROR_OK; } static int parport_khz(int khz, int *jtag_speed) { if (khz == 0) { LOG_DEBUG("RCLK not supported"); return ERROR_FAIL; } *jtag_speed = 499999 / (khz * parport_toggling_time_ns); return ERROR_OK; } static int parport_speed_div(int speed, int *khz) { uint32_t denominator = (speed + 1) * parport_toggling_time_ns; *khz = (499999 + denominator) / denominator; return ERROR_OK; } #if PARPORT_USE_GIVEIO == 1 static int parport_get_giveio_access(void) { HANDLE h; OSVERSIONINFO version; version.dwOSVersionInfoSize = sizeof version; if (!GetVersionEx(&version)) { errno = EINVAL; return -1; } if (version.dwPlatformId != VER_PLATFORM_WIN32_NT) return 0; h = CreateFile("\\\\.\\giveio", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (h == INVALID_HANDLE_VALUE) { errno = ENODEV; return -1; } CloseHandle(h); return 0; } #endif static struct bitbang_interface parport_bitbang = { .read = &parport_read, .write = &parport_write, .reset = &parport_reset, .blink = &parport_led, }; static int parport_init(void) { struct cable *cur_cable; #if PARPORT_USE_PPDEV == 1 char buffer[256]; #endif cur_cable = cables; if (parport_cable == NULL) { parport_cable = strdup("wiggler"); LOG_WARNING("No parport cable specified, using default 'wiggler'"); } while (cur_cable->name) { if (strcmp(cur_cable->name, parport_cable) == 0) { cable = cur_cable; break; } cur_cable++; } if (!cable) { LOG_ERROR("No matching cable found for %s", parport_cable); return ERROR_JTAG_INIT_FAILED; } dataport_value = cable->PORT_INIT; #if PARPORT_USE_PPDEV == 1 if (device_handle > 0) { LOG_ERROR("device is already opened"); return ERROR_JTAG_INIT_FAILED; } #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) LOG_DEBUG("opening /dev/ppi%d...", parport_port); snprintf(buffer, 256, "/dev/ppi%d", parport_port); device_handle = open(buffer, O_WRONLY); #else /* not __FreeBSD__, __FreeBSD_kernel__ */ LOG_DEBUG("opening /dev/parport%d...", parport_port); snprintf(buffer, 256, "/dev/parport%d", parport_port); device_handle = open(buffer, O_WRONLY); #endif /* __FreeBSD__, __FreeBSD_kernel__ */ if (device_handle < 0) { int err = errno; LOG_ERROR("cannot open device. check it exists and that user read and write rights are set. errno=%d", err); return ERROR_JTAG_INIT_FAILED; } LOG_DEBUG("...open"); #if !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) int i = ioctl(device_handle, PPCLAIM); if (i < 0) { LOG_ERROR("cannot claim device"); return ERROR_JTAG_INIT_FAILED; } i = PARPORT_MODE_COMPAT; i = ioctl(device_handle, PPSETMODE, &i); if (i < 0) { LOG_ERROR(" cannot set compatible mode to device"); return ERROR_JTAG_INIT_FAILED; } i = IEEE1284_MODE_COMPAT; i = ioctl(device_handle, PPNEGOT, &i); if (i < 0) { LOG_ERROR("cannot set compatible 1284 mode to device"); return ERROR_JTAG_INIT_FAILED; } #endif /* not __FreeBSD__, __FreeBSD_kernel__ */ #else /* not PARPORT_USE_PPDEV */ if (parport_port == 0) { parport_port = 0x378; LOG_WARNING("No parport port specified, using default '0x378' (LPT1)"); } dataport = parport_port; statusport = parport_port + 1; LOG_DEBUG("requesting privileges for parallel port 0x%lx...", dataport); #if PARPORT_USE_GIVEIO == 1 if (parport_get_giveio_access() != 0) { #else /* PARPORT_USE_GIVEIO */ if (ioperm(dataport, 3, 1) != 0) { #endif /* PARPORT_USE_GIVEIO */ LOG_ERROR("missing privileges for direct i/o"); return ERROR_JTAG_INIT_FAILED; } LOG_DEBUG("...privileges granted"); /* make sure parallel port is in right mode (clear tristate and interrupt */ #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) outb(parport_port + 2, 0x0); #else outb(0x0, parport_port + 2); #endif #endif /* PARPORT_USE_PPDEV */ parport_reset(0, 0); parport_write(0, 0, 0); parport_led(1); bitbang_interface = &parport_bitbang; return ERROR_OK; } static int parport_quit(void) { parport_led(0); if (parport_exit) { dataport_value = cable->PORT_EXIT; parport_write_data(); } if (parport_cable) { free(parport_cable); parport_cable = NULL; } return ERROR_OK; } COMMAND_HANDLER(parport_handle_parport_port_command) { if (CMD_ARGC == 1) { /* only if the port wasn't overwritten by cmdline */ if (parport_port == 0) COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], parport_port); else { LOG_ERROR("The parport port was already configured!"); return ERROR_FAIL; } } command_print(CMD_CTX, "parport port = 0x%" PRIx16 "", parport_port); return ERROR_OK; } COMMAND_HANDLER(parport_handle_parport_cable_command) { if (CMD_ARGC == 0) return ERROR_OK; /* only if the cable name wasn't overwritten by cmdline */ if (parport_cable == 0) { /* REVISIT first verify that it's listed in cables[] ... */ parport_cable = malloc(strlen(CMD_ARGV[0]) + sizeof(char)); strcpy(parport_cable, CMD_ARGV[0]); } /* REVISIT it's probably worth returning the current value ... */ return ERROR_OK; } COMMAND_HANDLER(parport_handle_write_on_exit_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_ON_OFF(CMD_ARGV[0], parport_exit); return ERROR_OK; } COMMAND_HANDLER(parport_handle_parport_toggling_time_command) { if (CMD_ARGC == 1) { uint32_t ns; int retval = parse_u32(CMD_ARGV[0], &ns); if (ERROR_OK != retval) return retval; if (ns == 0) { LOG_ERROR("0 ns is not a valid parport toggling time"); return ERROR_FAIL; } parport_toggling_time_ns = ns; retval = jtag_get_speed(&wait_states); if (retval != ERROR_OK) { /* if jtag_get_speed fails then the clock_mode * has not been configured, this happens if parport_toggling_time is * called before the adapter speed is set */ LOG_INFO("no parport speed set - defaulting to zero wait states"); wait_states = 0; } } command_print(CMD_CTX, "parport toggling time = %" PRIu32 " ns", parport_toggling_time_ns); return ERROR_OK; } static const struct command_registration parport_command_handlers[] = { { .name = "parport_port", .handler = parport_handle_parport_port_command, .mode = COMMAND_CONFIG, .help = "Display the address of the I/O port (e.g. 0x378) " "or the number of the '/dev/parport' device used. " "If a parameter is provided, first change that port.", .usage = "[port_number]", }, { .name = "parport_cable", .handler = parport_handle_parport_cable_command, .mode = COMMAND_CONFIG, .help = "Set the layout of the parallel port cable " "used to connect to the target.", /* REVISIT there's no way to list layouts we know ... */ .usage = "[layout]", }, { .name = "parport_write_on_exit", .handler = parport_handle_write_on_exit_command, .mode = COMMAND_CONFIG, .help = "Configure the parallel driver to write " "a known value to the parallel interface on exit.", .usage = "('on'|'off')", }, { .name = "parport_toggling_time", .handler = parport_handle_parport_toggling_time_command, .mode = COMMAND_CONFIG, .help = "Displays or assigns how many nanoseconds it " "takes for the hardware to toggle TCK.", .usage = "[nanoseconds]", }, COMMAND_REGISTRATION_DONE }; struct jtag_interface parport_interface = { .name = "parport", .supported = DEBUG_CAP_TMS_SEQ, .commands = parport_command_handlers, .init = parport_init, .quit = parport_quit, .khz = parport_khz, .speed_div = parport_speed_div, .speed = parport_speed, .execute_queue = bitbang_execute_queue, }; openocd-0.7.0/src/jtag/drivers/usb_common.c0000644000175000001440000000424012134336410015556 00000000000000/*************************************************************************** * Copyright (C) 2009 by Zachary T Welch * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "usb_common.h" static bool jtag_usb_match(struct usb_device *dev, const uint16_t vids[], const uint16_t pids[]) { for (unsigned i = 0; vids[i] && pids[i]; i++) { if (dev->descriptor.idVendor == vids[i] && dev->descriptor.idProduct == pids[i]) return true; } return false; } int jtag_usb_open(const uint16_t vids[], const uint16_t pids[], struct usb_dev_handle **out) { usb_find_busses(); usb_find_devices(); struct usb_bus *busses = usb_get_busses(); for (struct usb_bus *bus = busses; bus; bus = bus->next) { for (struct usb_device *dev = bus->devices; dev; dev = dev->next) { if (!jtag_usb_match(dev, vids, pids)) continue; *out = usb_open(dev); if (NULL == *out) return -errno; return 0; } } return -ENODEV; } openocd-0.7.0/src/jtag/drivers/stlink_usb.c0000644000175000001440000007775112137151331015613 00000000000000/*************************************************************************** * Copyright (C) 2011-2012 by Mathias Kuester * * Mathias Kuester * * * * Copyright (C) 2012 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This code is based on https://github.com/texane/stlink * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* project specific includes */ #include #include #include #include #include #include #include #include "libusb_common.h" #define ENDPOINT_IN 0x80 #define ENDPOINT_OUT 0x00 #define STLINK_NULL_EP 0 #define STLINK_RX_EP (1|ENDPOINT_IN) #define STLINK_TX_EP (2|ENDPOINT_OUT) #define STLINK_SG_SIZE (31) #define STLINK_DATA_SIZE (4*128) #define STLINK_CMD_SIZE_V2 (16) #define STLINK_CMD_SIZE_V1 (10) enum stlink_jtag_api_version { STLINK_JTAG_API_V1 = 1, STLINK_JTAG_API_V2, }; /** */ struct stlink_usb_version { /** */ int stlink; /** */ int jtag; /** */ int swim; /** highest supported jtag api version */ enum stlink_jtag_api_version jtag_api_max; }; /** */ struct stlink_usb_handle_s { /** */ struct jtag_libusb_device_handle *fd; /** */ struct libusb_transfer *trans; /** */ uint8_t cmdbuf[STLINK_SG_SIZE]; /** */ uint8_t cmdidx; /** */ uint8_t direction; /** */ uint8_t databuf[STLINK_DATA_SIZE]; /** */ enum hl_transports transport; /** */ struct stlink_usb_version version; /** */ uint16_t vid; /** */ uint16_t pid; /** this is the currently used jtag api */ enum stlink_jtag_api_version jtag_api; }; #define STLINK_DEBUG_ERR_OK 0x80 #define STLINK_DEBUG_ERR_FAULT 0x81 #define STLINK_SWD_AP_WAIT 0x10 #define STLINK_SWD_DP_WAIT 0x14 #define STLINK_CORE_RUNNING 0x80 #define STLINK_CORE_HALTED 0x81 #define STLINK_CORE_STAT_UNKNOWN -1 #define STLINK_GET_VERSION 0xF1 #define STLINK_DEBUG_COMMAND 0xF2 #define STLINK_DFU_COMMAND 0xF3 #define STLINK_SWIM_COMMAND 0xF4 #define STLINK_GET_CURRENT_MODE 0xF5 #define STLINK_GET_TARGET_VOLTAGE 0xF7 #define STLINK_DEV_DFU_MODE 0x00 #define STLINK_DEV_MASS_MODE 0x01 #define STLINK_DEV_DEBUG_MODE 0x02 #define STLINK_DEV_SWIM_MODE 0x03 #define STLINK_DEV_BOOTLOADER_MODE 0x04 #define STLINK_DEV_UNKNOWN_MODE -1 #define STLINK_DFU_EXIT 0x07 #define STLINK_SWIM_ENTER 0x00 #define STLINK_SWIM_EXIT 0x01 #define STLINK_DEBUG_ENTER_JTAG 0x00 #define STLINK_DEBUG_GETSTATUS 0x01 #define STLINK_DEBUG_FORCEDEBUG 0x02 #define STLINK_DEBUG_APIV1_RESETSYS 0x03 #define STLINK_DEBUG_APIV1_READALLREGS 0x04 #define STLINK_DEBUG_APIV1_READREG 0x05 #define STLINK_DEBUG_APIV1_WRITEREG 0x06 #define STLINK_DEBUG_READMEM_32BIT 0x07 #define STLINK_DEBUG_WRITEMEM_32BIT 0x08 #define STLINK_DEBUG_RUNCORE 0x09 #define STLINK_DEBUG_STEPCORE 0x0a #define STLINK_DEBUG_APIV1_SETFP 0x0b #define STLINK_DEBUG_READMEM_8BIT 0x0c #define STLINK_DEBUG_WRITEMEM_8BIT 0x0d #define STLINK_DEBUG_APIV1_CLEARFP 0x0e #define STLINK_DEBUG_APIV1_WRITEDEBUGREG 0x0f #define STLINK_DEBUG_APIV1_SETWATCHPOINT 0x10 #define STLINK_DEBUG_ENTER_JTAG 0x00 #define STLINK_DEBUG_ENTER_SWD 0xa3 #define STLINK_DEBUG_APIV1_ENTER 0x20 #define STLINK_DEBUG_EXIT 0x21 #define STLINK_DEBUG_READCOREID 0x22 #define STLINK_DEBUG_APIV2_ENTER 0x30 #define STLINK_DEBUG_APIV2_READ_IDCODES 0x31 #define STLINK_DEBUG_APIV2_RESETSYS 0x32 #define STLINK_DEBUG_APIV2_READREG 0x33 #define STLINK_DEBUG_APIV2_WRITEREG 0x34 #define STLINK_DEBUG_APIV2_WRITEDEBUGREG 0x35 #define STLINK_DEBUG_APIV2_READDEBUGREG 0x36 #define STLINK_DEBUG_APIV2_READALLREGS 0x3A #define STLINK_DEBUG_APIV2_GETLASTRWSTATUS 0x3B #define STLINK_DEBUG_APIV2_DRIVE_NRST 0x3C #define STLINK_DEBUG_APIV2_DRIVE_NRST_LOW 0x00 #define STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH 0x01 #define STLINK_DEBUG_APIV2_DRIVE_NRST_PULSE 0x02 /** */ enum stlink_mode { STLINK_MODE_UNKNOWN = 0, STLINK_MODE_DFU, STLINK_MODE_MASS, STLINK_MODE_DEBUG_JTAG, STLINK_MODE_DEBUG_SWD, STLINK_MODE_DEBUG_SWIM }; #define REQUEST_SENSE 0x03 #define REQUEST_SENSE_LENGTH 18 static void stlink_usb_init_buffer(void *handle, uint8_t direction, uint32_t size); /** */ static int stlink_usb_xfer_v1_get_status(void *handle) { struct stlink_usb_handle_s *h; assert(handle != NULL); h = (struct stlink_usb_handle_s *)handle; /* read status */ memset(h->cmdbuf, 0, STLINK_SG_SIZE); if (jtag_libusb_bulk_read(h->fd, STLINK_RX_EP, (char *)h->cmdbuf, 13, 1000) != 13) return ERROR_FAIL; uint32_t t1; t1 = buf_get_u32(h->cmdbuf, 0, 32); /* check for USBS */ if (t1 != 0x53425355) return ERROR_FAIL; /* * CSW status: * 0 success * 1 command failure * 2 phase error */ if (h->cmdbuf[12] != 0) return ERROR_FAIL; return ERROR_OK; } /** */ static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, int size) { struct stlink_usb_handle_s *h; assert(handle != NULL); h = (struct stlink_usb_handle_s *)handle; if (jtag_libusb_bulk_write(h->fd, STLINK_TX_EP, (char *)h->cmdbuf, cmdsize, 1000) != cmdsize) { return ERROR_FAIL; } if (h->direction == STLINK_TX_EP && size) { if (jtag_libusb_bulk_write(h->fd, STLINK_TX_EP, (char *)buf, size, 1000) != size) { LOG_DEBUG("bulk write failed"); return ERROR_FAIL; } } else if (h->direction == STLINK_RX_EP && size) { if (jtag_libusb_bulk_read(h->fd, STLINK_RX_EP, (char *)buf, size, 1000) != size) { LOG_DEBUG("bulk read failed"); return ERROR_FAIL; } } return ERROR_OK; } /** */ static int stlink_usb_xfer_v1_get_sense(void *handle) { int res; struct stlink_usb_handle_s *h; assert(handle != NULL); h = (struct stlink_usb_handle_s *)handle; stlink_usb_init_buffer(handle, STLINK_RX_EP, 16); h->cmdbuf[h->cmdidx++] = REQUEST_SENSE; h->cmdbuf[h->cmdidx++] = 0; h->cmdbuf[h->cmdidx++] = 0; h->cmdbuf[h->cmdidx++] = 0; h->cmdbuf[h->cmdidx++] = REQUEST_SENSE_LENGTH; res = stlink_usb_xfer_rw(handle, REQUEST_SENSE_LENGTH, h->databuf, 16); if (res != ERROR_OK) return res; if (stlink_usb_xfer_v1_get_status(handle) != ERROR_OK) return ERROR_FAIL; return ERROR_OK; } /** */ static int stlink_usb_xfer(void *handle, const uint8_t *buf, int size) { int err, cmdsize = STLINK_CMD_SIZE_V2; struct stlink_usb_handle_s *h; assert(handle != NULL); h = (struct stlink_usb_handle_s *)handle; if (h->version.stlink == 1) cmdsize = STLINK_SG_SIZE; err = stlink_usb_xfer_rw(handle, cmdsize, buf, size); if (err != ERROR_OK) return err; if (h->version.stlink == 1) { if (stlink_usb_xfer_v1_get_status(handle) != ERROR_OK) { /* check csw status */ if (h->cmdbuf[12] == 1) { LOG_DEBUG("get sense"); if (stlink_usb_xfer_v1_get_sense(handle) != ERROR_OK) return ERROR_FAIL; } return ERROR_FAIL; } } return ERROR_OK; } /** */ static void stlink_usb_xfer_v1_create_cmd(void *handle, uint8_t direction, uint32_t size) { struct stlink_usb_handle_s *h; h = (struct stlink_usb_handle_s *)handle; /* fill the send buffer */ strcpy((char *)h->cmdbuf, "USBC"); h->cmdidx += 4; /* csw tag not used */ h->cmdidx += 4; buf_set_u32(h->cmdbuf+h->cmdidx, 0, 32, size); h->cmdidx += 4; h->cmdbuf[h->cmdidx++] = (direction == STLINK_RX_EP ? ENDPOINT_IN : ENDPOINT_OUT); h->cmdbuf[h->cmdidx++] = 0; /* lun */ h->cmdbuf[h->cmdidx++] = STLINK_CMD_SIZE_V1; } /** */ static void stlink_usb_init_buffer(void *handle, uint8_t direction, uint32_t size) { struct stlink_usb_handle_s *h; h = (struct stlink_usb_handle_s *)handle; h->direction = direction; h->cmdidx = 0; memset(h->cmdbuf, 0, STLINK_SG_SIZE); memset(h->databuf, 0, STLINK_DATA_SIZE); if (h->version.stlink == 1) stlink_usb_xfer_v1_create_cmd(handle, direction, size); } static const char * const stlink_usb_error_msg[] = { "unknown" }; /** */ static int stlink_usb_error_check(void *handle) { int res; const char *err_msg = 0; struct stlink_usb_handle_s *h; assert(handle != NULL); h = (struct stlink_usb_handle_s *)handle; /* TODO: no error checking yet on api V1 */ if (h->jtag_api == STLINK_JTAG_API_V1) h->databuf[0] = STLINK_DEBUG_ERR_OK; switch (h->databuf[0]) { case STLINK_DEBUG_ERR_OK: res = ERROR_OK; break; case STLINK_DEBUG_ERR_FAULT: default: err_msg = stlink_usb_error_msg[0]; res = ERROR_FAIL; break; } if (res != ERROR_OK) LOG_DEBUG("status error: %d ('%s')", h->databuf[0], err_msg); return res; } /** */ static int stlink_usb_version(void *handle) { int res; uint16_t v; struct stlink_usb_handle_s *h; assert(handle != NULL); h = (struct stlink_usb_handle_s *)handle; stlink_usb_init_buffer(handle, STLINK_RX_EP, 6); h->cmdbuf[h->cmdidx++] = STLINK_GET_VERSION; res = stlink_usb_xfer(handle, h->databuf, 6); if (res != ERROR_OK) return res; v = (h->databuf[0] << 8) | h->databuf[1]; h->version.stlink = (v >> 12) & 0x0f; h->version.jtag = (v >> 6) & 0x3f; h->version.swim = v & 0x3f; h->vid = buf_get_u32(h->databuf, 16, 16); h->pid = buf_get_u32(h->databuf, 32, 16); /* set the supported jtag api version * API V2 is supported since JTAG V11 */ if (h->version.jtag >= 11) h->version.jtag_api_max = STLINK_JTAG_API_V2; else h->version.jtag_api_max = STLINK_JTAG_API_V1; LOG_INFO("STLINK v%d JTAG v%d API v%d SWIM v%d VID 0x%04X PID 0x%04X", h->version.stlink, h->version.jtag, (h->version.jtag_api_max == STLINK_JTAG_API_V1) ? 1 : 2, h->version.swim, h->vid, h->pid); return ERROR_OK; } static int stlink_usb_check_voltage(void *handle, float *target_voltage) { struct stlink_usb_handle_s *h; uint32_t adc_results[2]; h = (struct stlink_usb_handle_s *)handle; /* only supported by stlink/v2 and for firmware >= 13 */ if (h->version.stlink == 1 || h->version.jtag < 13) return ERROR_COMMAND_NOTFOUND; stlink_usb_init_buffer(handle, STLINK_RX_EP, 8); h->cmdbuf[h->cmdidx++] = STLINK_GET_TARGET_VOLTAGE; int result = stlink_usb_xfer(handle, h->databuf, 8); if (result != ERROR_OK) return result; /* convert result */ adc_results[0] = le_to_h_u32(h->databuf); adc_results[1] = le_to_h_u32(h->databuf + 4); *target_voltage = 0; if (adc_results[0]) *target_voltage = 2 * ((float)adc_results[1]) * (float)(1.2 / adc_results[0]); LOG_INFO("Target voltage: %f", (double)*target_voltage); return ERROR_OK; } /** */ static int stlink_usb_current_mode(void *handle, uint8_t *mode) { int res; struct stlink_usb_handle_s *h; assert(handle != NULL); h = (struct stlink_usb_handle_s *)handle; stlink_usb_init_buffer(handle, STLINK_RX_EP, 2); h->cmdbuf[h->cmdidx++] = STLINK_GET_CURRENT_MODE; res = stlink_usb_xfer(handle, h->databuf, 2); if (res != ERROR_OK) return res; *mode = h->databuf[0]; return ERROR_OK; } /** */ static int stlink_usb_mode_enter(void *handle, enum stlink_mode type) { int res; int rx_size = 0; struct stlink_usb_handle_s *h; assert(handle != NULL); h = (struct stlink_usb_handle_s *)handle; /* on api V2 we are able the read the latest command * status * TODO: we need the test on api V1 too */ if (h->jtag_api == STLINK_JTAG_API_V2) rx_size = 2; stlink_usb_init_buffer(handle, STLINK_RX_EP, rx_size); switch (type) { case STLINK_MODE_DEBUG_JTAG: h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; if (h->jtag_api == STLINK_JTAG_API_V1) h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_ENTER; else h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_ENTER; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_ENTER_JTAG; break; case STLINK_MODE_DEBUG_SWD: h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; if (h->jtag_api == STLINK_JTAG_API_V1) h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_ENTER; else h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_ENTER; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_ENTER_SWD; break; case STLINK_MODE_DEBUG_SWIM: h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_SWIM_ENTER; break; case STLINK_MODE_DFU: case STLINK_MODE_MASS: default: return ERROR_FAIL; } res = stlink_usb_xfer(handle, h->databuf, rx_size); if (res != ERROR_OK) return res; res = stlink_usb_error_check(h); return res; } /** */ static int stlink_usb_mode_leave(void *handle, enum stlink_mode type) { int res; struct stlink_usb_handle_s *h; assert(handle != NULL); h = (struct stlink_usb_handle_s *)handle; stlink_usb_init_buffer(handle, STLINK_NULL_EP, 0); switch (type) { case STLINK_MODE_DEBUG_JTAG: case STLINK_MODE_DEBUG_SWD: h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_EXIT; break; case STLINK_MODE_DEBUG_SWIM: h->cmdbuf[h->cmdidx++] = STLINK_SWIM_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_SWIM_EXIT; break; case STLINK_MODE_DFU: h->cmdbuf[h->cmdidx++] = STLINK_DFU_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DFU_EXIT; break; case STLINK_MODE_MASS: default: return ERROR_FAIL; } res = stlink_usb_xfer(handle, 0, 0); if (res != ERROR_OK) return res; return ERROR_OK; } static int stlink_usb_assert_srst(void *handle, int srst); /** */ static int stlink_usb_init_mode(void *handle, bool connect_under_reset) { int res; uint8_t mode; enum stlink_mode emode; struct stlink_usb_handle_s *h; assert(handle != NULL); h = (struct stlink_usb_handle_s *)handle; res = stlink_usb_current_mode(handle, &mode); if (res != ERROR_OK) return res; LOG_DEBUG("MODE: 0x%02X", mode); /* try to exit current mode */ switch (mode) { case STLINK_DEV_DFU_MODE: emode = STLINK_MODE_DFU; break; case STLINK_DEV_DEBUG_MODE: emode = STLINK_MODE_DEBUG_SWD; break; case STLINK_DEV_SWIM_MODE: emode = STLINK_MODE_DEBUG_SWIM; break; case STLINK_DEV_BOOTLOADER_MODE: case STLINK_DEV_MASS_MODE: default: emode = STLINK_MODE_UNKNOWN; break; } if (emode != STLINK_MODE_UNKNOWN) { res = stlink_usb_mode_leave(handle, emode); if (res != ERROR_OK) return res; } res = stlink_usb_current_mode(handle, &mode); if (res != ERROR_OK) return res; /* we check the target voltage here as an aid to debugging connection problems. * the stlink requires the target Vdd to be connected for reliable debugging. * this cmd is supported in all modes except DFU */ if (mode != STLINK_DEV_DFU_MODE) { float target_voltage; /* check target voltage (if supported) */ res = stlink_usb_check_voltage(h, &target_voltage); if (res != ERROR_OK) { if (res != ERROR_COMMAND_NOTFOUND) LOG_ERROR("voltage check failed"); /* attempt to continue as it is not a catastrophic failure */ } else { /* check for a sensible target voltage, operating range is 1.65-5.5v * according to datasheet */ if (target_voltage < 1.5) LOG_ERROR("target voltage may be too low for reliable debugging"); } } LOG_DEBUG("MODE: 0x%02X", mode); /* set selected mode */ switch (h->transport) { case HL_TRANSPORT_SWD: emode = STLINK_MODE_DEBUG_SWD; break; case HL_TRANSPORT_JTAG: emode = STLINK_MODE_DEBUG_JTAG; break; case HL_TRANSPORT_SWIM: emode = STLINK_MODE_DEBUG_SWIM; break; default: emode = STLINK_MODE_UNKNOWN; break; } if (emode == STLINK_MODE_UNKNOWN) { LOG_ERROR("selected mode (transport) not supported"); return ERROR_FAIL; } if (connect_under_reset) { res = stlink_usb_assert_srst(handle, 0); if (res != ERROR_OK) return res; } res = stlink_usb_mode_enter(handle, emode); if (res != ERROR_OK) return res; res = stlink_usb_current_mode(handle, &mode); if (res != ERROR_OK) return res; LOG_DEBUG("MODE: 0x%02X", mode); return ERROR_OK; } /** */ static int stlink_usb_idcode(void *handle, uint32_t *idcode) { int res; struct stlink_usb_handle_s *h; assert(handle != NULL); h = (struct stlink_usb_handle_s *)handle; stlink_usb_init_buffer(handle, STLINK_RX_EP, 4); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_READCOREID; res = stlink_usb_xfer(handle, h->databuf, 4); if (res != ERROR_OK) return res; *idcode = le_to_h_u32(h->databuf); LOG_DEBUG("IDCODE: 0x%08X", *idcode); return ERROR_OK; } static int stlink_usb_v2_read_debug_reg(void *handle, uint32_t addr, uint32_t *val) { struct stlink_usb_handle_s *h; int res; assert(handle != NULL); h = (struct stlink_usb_handle_s *)handle; stlink_usb_init_buffer(handle, STLINK_RX_EP, 8); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_READDEBUGREG; h_u32_to_le(h->cmdbuf+h->cmdidx, addr); h->cmdidx += 4; res = stlink_usb_xfer(handle, h->databuf, 8); if (res != ERROR_OK) return res; *val = le_to_h_u32(h->databuf + 4); return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : ERROR_FAIL; } static int stlink_usb_write_debug_reg(void *handle, uint32_t addr, uint32_t val) { int res; struct stlink_usb_handle_s *h; assert(handle != NULL); h = (struct stlink_usb_handle_s *)handle; stlink_usb_init_buffer(handle, STLINK_RX_EP, 2); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; if (h->jtag_api == STLINK_JTAG_API_V1) h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_WRITEDEBUGREG; else h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_WRITEDEBUGREG; h_u32_to_le(h->cmdbuf+h->cmdidx, addr); h->cmdidx += 4; h_u32_to_le(h->cmdbuf+h->cmdidx, val); h->cmdidx += 4; res = stlink_usb_xfer(handle, h->databuf, 2); if (res != ERROR_OK) return res; return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : ERROR_FAIL; } static enum target_state stlink_usb_v2_get_status(void *handle) { int result; uint32_t status; result = stlink_usb_v2_read_debug_reg(handle, DCB_DHCSR, &status); if (result != ERROR_OK) return TARGET_UNKNOWN; if (status & S_HALT) return TARGET_HALTED; else if (status & S_RESET_ST) return TARGET_RESET; return TARGET_RUNNING; } /** */ static enum target_state stlink_usb_state(void *handle) { int res; struct stlink_usb_handle_s *h; assert(handle != NULL); h = (struct stlink_usb_handle_s *)handle; if (h->jtag_api == STLINK_JTAG_API_V2) return stlink_usb_v2_get_status(handle); stlink_usb_init_buffer(handle, STLINK_RX_EP, 2); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_GETSTATUS; res = stlink_usb_xfer(handle, h->databuf, 2); if (res != ERROR_OK) return TARGET_UNKNOWN; if (h->databuf[0] == STLINK_CORE_RUNNING) return TARGET_RUNNING; if (h->databuf[0] == STLINK_CORE_HALTED) return TARGET_HALTED; return TARGET_UNKNOWN; } /** */ static int stlink_usb_reset(void *handle) { int res; struct stlink_usb_handle_s *h; assert(handle != NULL); h = (struct stlink_usb_handle_s *)handle; stlink_usb_init_buffer(handle, STLINK_RX_EP, 2); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; if (h->jtag_api == STLINK_JTAG_API_V1) h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_RESETSYS; else h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_RESETSYS; res = stlink_usb_xfer(handle, h->databuf, 2); if (res != ERROR_OK) return res; LOG_DEBUG("RESET: 0x%08X", h->databuf[0]); /* the following is not a error under swd (using hardware srst), so return success */ if (h->databuf[0] == STLINK_SWD_AP_WAIT || h->databuf[0] == STLINK_SWD_DP_WAIT) return ERROR_OK; return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : ERROR_FAIL; } static int stlink_usb_assert_srst(void *handle, int srst) { int res; struct stlink_usb_handle_s *h; assert(handle != NULL); h = (struct stlink_usb_handle_s *)handle; if (h->jtag_api == STLINK_JTAG_API_V1) return ERROR_COMMAND_NOTFOUND; stlink_usb_init_buffer(handle, STLINK_RX_EP, 2); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_DRIVE_NRST; h->cmdbuf[h->cmdidx++] = srst; res = stlink_usb_xfer(handle, h->databuf, 2); if (res != ERROR_OK) return res; return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : ERROR_FAIL; } /** */ static int stlink_usb_run(void *handle) { int res; struct stlink_usb_handle_s *h; assert(handle != NULL); h = (struct stlink_usb_handle_s *)handle; if (h->jtag_api == STLINK_JTAG_API_V2) return stlink_usb_write_debug_reg(handle, DCB_DHCSR, DBGKEY|C_DEBUGEN); stlink_usb_init_buffer(handle, STLINK_RX_EP, 2); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_RUNCORE; res = stlink_usb_xfer(handle, h->databuf, 2); if (res != ERROR_OK) return res; return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : ERROR_FAIL; } /** */ static int stlink_usb_halt(void *handle) { int res; struct stlink_usb_handle_s *h; assert(handle != NULL); h = (struct stlink_usb_handle_s *)handle; if (h->jtag_api == STLINK_JTAG_API_V2) return stlink_usb_write_debug_reg(handle, DCB_DHCSR, DBGKEY|C_HALT|C_DEBUGEN); stlink_usb_init_buffer(handle, STLINK_RX_EP, 2); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_FORCEDEBUG; res = stlink_usb_xfer(handle, h->databuf, 2); if (res != ERROR_OK) return res; return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : ERROR_FAIL; } /** */ static int stlink_usb_step(void *handle) { int res; struct stlink_usb_handle_s *h; assert(handle != NULL); h = (struct stlink_usb_handle_s *)handle; if (h->jtag_api == STLINK_JTAG_API_V2) { /* TODO: this emulates the v1 api, it should really use a similar auto mask isr * that the cortex-m3 currently does. */ stlink_usb_write_debug_reg(handle, DCB_DHCSR, DBGKEY|C_HALT|C_MASKINTS|C_DEBUGEN); stlink_usb_write_debug_reg(handle, DCB_DHCSR, DBGKEY|C_STEP|C_MASKINTS|C_DEBUGEN); return stlink_usb_write_debug_reg(handle, DCB_DHCSR, DBGKEY|C_HALT|C_DEBUGEN); } stlink_usb_init_buffer(handle, STLINK_RX_EP, 2); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_STEPCORE; res = stlink_usb_xfer(handle, h->databuf, 2); if (res != ERROR_OK) return res; return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : ERROR_FAIL; } /** */ static int stlink_usb_read_regs(void *handle) { int res; struct stlink_usb_handle_s *h; assert(handle != NULL); h = (struct stlink_usb_handle_s *)handle; stlink_usb_init_buffer(handle, STLINK_RX_EP, 84); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; if (h->jtag_api == STLINK_JTAG_API_V1) h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_READALLREGS; else h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_READALLREGS; res = stlink_usb_xfer(handle, h->databuf, 84); if (res != ERROR_OK) return res; return ERROR_OK; } /** */ static int stlink_usb_read_reg(void *handle, int num, uint32_t *val) { int res; struct stlink_usb_handle_s *h; assert(handle != NULL); h = (struct stlink_usb_handle_s *)handle; stlink_usb_init_buffer(handle, STLINK_RX_EP, h->jtag_api == STLINK_JTAG_API_V1 ? 4 : 8); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; if (h->jtag_api == STLINK_JTAG_API_V1) h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_READREG; else h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_READREG; h->cmdbuf[h->cmdidx++] = num; res = stlink_usb_xfer(handle, h->databuf, h->jtag_api == STLINK_JTAG_API_V1 ? 4 : 8); if (res != ERROR_OK) return res; if (h->jtag_api == STLINK_JTAG_API_V1) *val = le_to_h_u32(h->databuf); else { *val = le_to_h_u32(h->databuf + 4); return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : ERROR_FAIL; } return ERROR_OK; } /** */ static int stlink_usb_write_reg(void *handle, int num, uint32_t val) { int res; struct stlink_usb_handle_s *h; assert(handle != NULL); h = (struct stlink_usb_handle_s *)handle; stlink_usb_init_buffer(handle, STLINK_RX_EP, 2); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; if (h->jtag_api == STLINK_JTAG_API_V1) h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV1_WRITEREG; else h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_WRITEREG; h->cmdbuf[h->cmdidx++] = num; h_u32_to_le(h->cmdbuf+h->cmdidx, val); h->cmdidx += 4; res = stlink_usb_xfer(handle, h->databuf, 2); if (res != ERROR_OK) return res; return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : ERROR_FAIL; } static int stlink_usb_get_rw_status(void *handle) { int res; struct stlink_usb_handle_s *h; assert(handle != NULL); h = (struct stlink_usb_handle_s *)handle; if (h->jtag_api == STLINK_JTAG_API_V1) return ERROR_OK; stlink_usb_init_buffer(handle, STLINK_RX_EP, 2); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_GETLASTRWSTATUS; res = stlink_usb_xfer(handle, h->databuf, 2); if (res != ERROR_OK) return res; return h->databuf[0] == STLINK_DEBUG_ERR_OK ? ERROR_OK : res; } /** */ static int stlink_usb_read_mem8(void *handle, uint32_t addr, uint16_t len, uint8_t *buffer) { int res; uint16_t read_len = len; struct stlink_usb_handle_s *h; assert(handle != NULL); h = (struct stlink_usb_handle_s *)handle; stlink_usb_init_buffer(handle, STLINK_RX_EP, read_len); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_READMEM_8BIT; h_u32_to_le(h->cmdbuf+h->cmdidx, addr); h->cmdidx += 4; h_u16_to_le(h->cmdbuf+h->cmdidx, len); h->cmdidx += 2; /* we need to fix read length for single bytes */ if (read_len == 1) read_len++; res = stlink_usb_xfer(handle, h->databuf, read_len); if (res != ERROR_OK) return res; memcpy(buffer, h->databuf, len); return stlink_usb_get_rw_status(handle); } /** */ static int stlink_usb_write_mem8(void *handle, uint32_t addr, uint16_t len, const uint8_t *buffer) { int res; struct stlink_usb_handle_s *h; assert(handle != NULL); h = (struct stlink_usb_handle_s *)handle; stlink_usb_init_buffer(handle, STLINK_TX_EP, len); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_WRITEMEM_8BIT; h_u32_to_le(h->cmdbuf+h->cmdidx, addr); h->cmdidx += 4; h_u16_to_le(h->cmdbuf+h->cmdidx, len); h->cmdidx += 2; res = stlink_usb_xfer(handle, buffer, len); if (res != ERROR_OK) return res; return stlink_usb_get_rw_status(handle); } /** */ static int stlink_usb_read_mem32(void *handle, uint32_t addr, uint16_t len, uint8_t *buffer) { int res; struct stlink_usb_handle_s *h; assert(handle != NULL); h = (struct stlink_usb_handle_s *)handle; len *= 4; stlink_usb_init_buffer(handle, STLINK_RX_EP, len); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_READMEM_32BIT; h_u32_to_le(h->cmdbuf+h->cmdidx, addr); h->cmdidx += 4; h_u16_to_le(h->cmdbuf+h->cmdidx, len); h->cmdidx += 2; res = stlink_usb_xfer(handle, h->databuf, len); if (res != ERROR_OK) return res; memcpy(buffer, h->databuf, len); return stlink_usb_get_rw_status(handle); } /** */ static int stlink_usb_write_mem32(void *handle, uint32_t addr, uint16_t len, const uint8_t *buffer) { int res; struct stlink_usb_handle_s *h; assert(handle != NULL); h = (struct stlink_usb_handle_s *)handle; len *= 4; stlink_usb_init_buffer(handle, STLINK_TX_EP, len); h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND; h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_WRITEMEM_32BIT; h_u32_to_le(h->cmdbuf+h->cmdidx, addr); h->cmdidx += 4; h_u16_to_le(h->cmdbuf+h->cmdidx, len); h->cmdidx += 2; res = stlink_usb_xfer(handle, buffer, len); if (res != ERROR_OK) return res; return stlink_usb_get_rw_status(handle); } /** */ static int stlink_usb_close(void *fd) { struct stlink_usb_handle_s *h; h = (struct stlink_usb_handle_s *)fd; if (h->fd) jtag_libusb_close(h->fd); free(fd); return ERROR_OK; } /** */ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd) { int err; struct stlink_usb_handle_s *h; enum stlink_jtag_api_version api; LOG_DEBUG("stlink_usb_open"); h = calloc(1, sizeof(struct stlink_usb_handle_s)); if (h == 0) { LOG_DEBUG("malloc failed"); return ERROR_FAIL; } h->transport = param->transport; /* set max read/write buffer size in bytes */ param->max_buffer = 512; const uint16_t vids[] = { param->vid, 0 }; const uint16_t pids[] = { param->pid, 0 }; LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x", param->transport, param->vid, param->pid); if (jtag_libusb_open(vids, pids, &h->fd) != ERROR_OK) { LOG_ERROR("open failed"); goto error_open; } jtag_libusb_set_configuration(h->fd, 0); if (jtag_libusb_claim_interface(h->fd, 0) != ERROR_OK) { LOG_DEBUG("claim interface failed"); goto error_open; } /* wrap version for first read */ switch (param->pid) { case 0x3744: h->version.stlink = 1; break; default: h->version.stlink = 2; break; } /* get the device version */ err = stlink_usb_version(h); if (err != ERROR_OK) { LOG_ERROR("read version failed"); goto error_open; } /* compare usb vid/pid */ if ((param->vid != h->vid) || (param->pid != h->pid)) LOG_INFO("vid/pid are not identical: 0x%04X/0x%04X 0x%04X/0x%04X", param->vid, param->pid, h->vid, h->pid); /* check if mode is supported */ err = ERROR_OK; switch (h->transport) { case HL_TRANSPORT_SWD: case HL_TRANSPORT_JTAG: if (h->version.jtag == 0) err = ERROR_FAIL; break; case HL_TRANSPORT_SWIM: if (h->version.swim == 0) err = ERROR_FAIL; break; default: err = ERROR_FAIL; break; } if (err != ERROR_OK) { LOG_ERROR("mode (transport) not supported by device"); goto error_open; } api = h->version.jtag_api_max; /* check that user has not requested certain api version * and if they have check it is supported */ if ((param->api != 0) && (param->api <= h->version.jtag_api_max)) { api = param->api; LOG_INFO("using stlink api v%d", api); } /* set the used jtag api, this will default to the newest supported version */ h->jtag_api = api; /* initialize the debug hardware */ err = stlink_usb_init_mode(h, param->connect_under_reset); if (err != ERROR_OK) { LOG_ERROR("init mode failed"); goto error_open; } *fd = h; return ERROR_OK; error_open: stlink_usb_close(h); return ERROR_FAIL; } /** */ struct hl_layout_api_s stlink_usb_layout_api = { /** */ .open = stlink_usb_open, /** */ .close = stlink_usb_close, /** */ .idcode = stlink_usb_idcode, /** */ .state = stlink_usb_state, /** */ .reset = stlink_usb_reset, /** */ .assert_srst = stlink_usb_assert_srst, /** */ .run = stlink_usb_run, /** */ .halt = stlink_usb_halt, /** */ .step = stlink_usb_step, /** */ .read_regs = stlink_usb_read_regs, /** */ .read_reg = stlink_usb_read_reg, /** */ .write_reg = stlink_usb_write_reg, /** */ .read_mem8 = stlink_usb_read_mem8, /** */ .write_mem8 = stlink_usb_write_mem8, /** */ .read_mem32 = stlink_usb_read_mem32, /** */ .write_mem32 = stlink_usb_write_mem32, /** */ .write_debug_reg = stlink_usb_write_debug_reg }; openocd-0.7.0/src/jtag/drivers/rlink_dtc_cmd.h0000644000175000001440000000751712134336410016230 00000000000000/*************************************************************************** * Copyright (C) 2008 Lou Deluxe * * lou.openocd012@fixit.nospammail.net * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /* A command position with the high nybble of 0x0 is reserved for an error condition. * If executed, it stops the DTC and raises the ERROR flag */ #define DTC_CMD_SHIFT_TMS_BYTES(bytes) ((0x1 << 4) | ((bytes) - 1)) /* Shift 1-16 bytes out TMS. TDI is 0. */ /* Bytes to shift follow. */ #define DTC_CMD_SHIFT_TDI_BYTES(bytes) ((0x2 << 4) | ((bytes) - 1)) /* Shift 1-16 bytes out TDI. TMS is 0. */ /* Bytes to shift follow. */ #define DTC_CMD_SHIFT_TDI_AND_TMS_BYTES(bytes) ((0x3 << 4) | ((bytes) - 1)) /* Shift 1-16 byte pairs out TDI and TMS. */ /* Byte pairs to shift follow in TDI, TMS order. */ #define DTC_CMD_SHIFT_TDO_BYTES(bytes) ((0x4 << 4) | ((bytes) - 1)) /* Shift 1-16 bytes in TDO. TMS is unaffected. */ /* Reply buffer contains bytes shifted in. */ #define DTC_CMD_SHIFT_TDIO_BYTES(bytes) ((0x6 << 4) | ((bytes) - 1)) /* Shift 1-16 bytes out TDI and in TDO. TMS is unaffected. */ #define DTC_CMD_SHIFT_TMS_TDI_BIT_PAIR(tms, tdi, tdo) ((0x8 << 4) | (\ (tms) ? (1 << 0) : 0 \ ) | (\ (tdi) ? (1 << 1) : 0 \ ) | (\ (tdo) ? (1 << 3) : 0 \ )) /* Single bit shift. * tms and tdi are the levels shifted out on TMS and TDI, respectively. * tdo indicates whether a byte will be returned in the reply buffer with its * least significant bit set to reflect TDO * Care should be taken when tdo is zero, as the underlying code actually does put * that byte in the reply buffer. Setting tdo to zero just moves the pointer back. * The result is that if this command is executed when the reply buffer is already full, * a byte will be written erroneously to memory not belonging to the reply buffer. * This could be worked around at the expense of DTC code space and speed. */ #define DTC_CMD_SHIFT_TMS_BITS(bits) ((0x9 << 4) | ((bits) - 1)) /* Shift 1-8 bits out TMS. */ /* Bits to be shifted out are left justified in the following byte. */ #define DTC_CMD_SHIFT_TDIO_BITS(bits) ((0xe << 4) | ((bits) - 1)) /* Shift 1-8 bits out TDI and in TDO, TMS is unaffected. */ /* Bits to be shifted out are left justified in the following byte. */ /* Bits shifted in are right justified in the byte placed in the reply buffer. */ #define DTC_CMD_STOP (0xf << 4) /* Stop processing the command buffer and wait for the next one. */ /* A shared status byte is updated with bit 0 set when this has happened, * and it is cleared when a new command buffer becomes ready. * The host can poll that byte to see when it is safe to read a reply. */ openocd-0.7.0/src/jtag/drivers/Makefile.am0000644000175000001440000000450012134336410015304 00000000000000include $(top_srcdir)/common.mk noinst_LTLIBRARIES = libocdjtagdrivers.la libocdjtagdrivers_la_SOURCES = \ $(DRIVERFILES) ocddatadir = $(pkglibdir) nobase_dist_ocddata_DATA = ULINK_FIRMWARE = $(srcdir)/OpenULINK EXTRA_DIST = $(ULINK_FIRMWARE) DRIVERFILES = # Standard Driver: common files DRIVERFILES += driver.c if USB DRIVERFILES += usb_common.c endif if USE_LIBUSB1 DRIVERFILES += libusb1_common.c else if USE_LIBUSB0 DRIVERFILES += libusb0_common.c endif endif if BITBANG DRIVERFILES += bitbang.c endif if PARPORT DRIVERFILES += parport.c endif if DUMMY DRIVERFILES += dummy.c endif if FT2232_DRIVER DRIVERFILES += ft2232.c endif if FTDI_DRIVER DRIVERFILES += ftdi.c mpsse.c endif if USB_BLASTER_DRIVER DRIVERFILES += usb_blaster.c endif if AMTJTAGACCEL DRIVERFILES += amt_jtagaccel.c endif if EP93XX DRIVERFILES += ep93xx.c endif if AT91RM9200 DRIVERFILES += at91rm9200.c endif if GW16012 DRIVERFILES += gw16012.c endif if BITQ DRIVERFILES += bitq.c endif if PRESTO_DRIVER DRIVERFILES += presto.c endif if USBPROG DRIVERFILES += usbprog.c endif if JLINK DRIVERFILES += jlink.c endif if RLINK DRIVERFILES += rlink.c rlink_speed_table.c endif if ULINK DRIVERFILES += ulink.c nobase_dist_ocddata_DATA += $(ULINK_FIRMWARE)/ulink_firmware.hex endif if VSLLINK DRIVERFILES += versaloon/usbtoxxx/usbtogpio.c DRIVERFILES += versaloon/usbtoxxx/usbtojtagraw.c DRIVERFILES += versaloon/usbtoxxx/usbtoswd.c DRIVERFILES += versaloon/usbtoxxx/usbtopwr.c DRIVERFILES += versaloon/usbtoxxx/usbtoxxx.c DRIVERFILES += versaloon/versaloon.c DRIVERFILES += vsllink.c endif if ARMJTAGEW DRIVERFILES += arm-jtag-ew.c endif if BUSPIRATE DRIVERFILES += buspirate.c endif if REMOTE_BITBANG DRIVERFILES += remote_bitbang.c endif if HLADAPTER DRIVERFILES += stlink_usb.c DRIVERFILES += ti_icdi_usb.c endif if OSBDM DRIVERFILES += osbdm.c endif if OPENDOUS DRIVERFILES += opendous.c endif if SYSFSGPIO DRIVERFILES += sysfsgpio.c endif noinst_HEADERS = \ bitbang.h \ bitq.h \ ftd2xx_common.h \ libusb0_common.h \ libusb1_common.h \ libusb_common.h \ minidriver_imp.h \ mpsse.h \ rlink.h \ rlink_dtc_cmd.h \ rlink_ep1_cmd.h \ rlink_st7.h \ usb_common.h \ versaloon/usbtoxxx/usbtoxxx.h \ versaloon/usbtoxxx/usbtoxxx_internal.h \ versaloon/versaloon.h \ versaloon/versaloon_include.h \ versaloon/versaloon_internal.h MAINTAINERCLEANFILES = $(srcdir)/Makefile.in openocd-0.7.0/src/jtag/drivers/amt_jtagaccel.c0000644000175000001440000003745212134336410016206 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #if PARPORT_USE_PPDEV == 1 #include #include #include #else /* not PARPORT_USE_PPDEV */ #ifndef _WIN32 #include #endif #endif #if PARPORT_USE_GIVEIO == 1 #if IS_CYGWIN == 1 #include #endif #endif /** * @file * Support the Amontec Chameleon POD with JTAG Accelerator support. * This is a parallel port JTAG adapter with a CPLD between the * parallel port and the JTAG connection. VHDL code running in the * CPLD significantly accelerates JTAG operations compared to the * bitbanging "Wiggler" style of most parallel port adapters. */ /* configuration */ static uint16_t amt_jtagaccel_port; /* interface variables */ static uint8_t aw_control_rst; static uint8_t aw_control_fsm = 0x10; static uint8_t aw_control_baudrate = 0x20; static int rtck_enabled; #if PARPORT_USE_PPDEV == 1 static int device_handle; static const int addr_mode = IEEE1284_MODE_EPP | IEEE1284_ADDR; /* FIXME do something sane when these ioctl/read/write calls fail. */ #define AMT_AW(val) \ do { \ int __retval; \ \ __retval = ioctl(device_handle, PPSETMODE, &addr_mode); \ assert(__retval >= 0); \ __retval = write(device_handle, &val, 1); \ assert(__retval >= 0); \ } while (0) #define AMT_AR(val) \ do { \ int __retval; \ \ __retval = ioctl(device_handle, PPSETMODE, &addr_mode); \ assert(__retval >= 0); \ __retval = read(device_handle, &val, 1); \ assert(__retval >= 0); \ } while (0) static const int data_mode = IEEE1284_MODE_EPP | IEEE1284_DATA; #define AMT_DW(val) \ do { \ int __retval; \ \ __retval = ioctl(device_handle, PPSETMODE, &data_mode); \ assert(__retval >= 0); \ __retval = write(device_handle, &val, 1); \ assert(__retval >= 0); \ } while (0) #define AMT_DR(val) \ do { \ int __retval; \ \ __retval = ioctl(device_handle, PPSETMODE, &data_mode); \ assert(__retval >= 0); \ __retval = read(device_handle, &val, 1); \ assert(__retval >= 0); \ } while (0) #else #define AMT_AW(val) do { outb(val, amt_jtagaccel_port + 3); } while (0) #define AMT_AR(val) do { val = inb(amt_jtagaccel_port + 3); } while (0) #define AMT_DW(val) do { outb(val, amt_jtagaccel_port + 4); } while (0) #define AMT_DR(val) do { val = inb(amt_jtagaccel_port + 4); } while (0) #endif /* PARPORT_USE_PPDEV */ /* tap_move[i][j]: tap movement command to go from state i to state j * 0: Test-Logic-Reset * 1: Run-Test/Idle * 2: Shift-DR * 3: Pause-DR * 4: Shift-IR * 5: Pause-IR */ static uint8_t amt_jtagaccel_tap_move[6][6][2] = { /* RESET IDLE DRSHIFT DRPAUSE IRSHIFT IRPAUSE */ { {0x1f, 0x00}, {0x0f, 0x00}, {0x05, 0x00}, {0x0a, 0x00}, {0x06, 0x00}, {0x96, 0x00} }, /* RESET */ { {0x1f, 0x00}, {0x00, 0x00}, {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x0b, 0x00} }, /* IDLE */ { {0x1f, 0x00}, {0x0d, 0x00}, {0x00, 0x00}, {0x01, 0x00}, {0x8f, 0x09}, {0x8f, 0x01} }, /* DRSHIFT */ { {0x1f, 0x00}, {0x0c, 0x00}, {0x08, 0x00}, {0x00, 0x00}, {0x8f, 0x09}, {0x8f, 0x01} }, /* DRPAUSE */ { {0x1f, 0x00}, {0x0d, 0x00}, {0x07, 0x00}, {0x97, 0x00}, {0x00, 0x00}, {0x01, 0x00} }, /* IRSHIFT */ { {0x1f, 0x00}, {0x0c, 0x00}, {0x07, 0x00}, {0x97, 0x00}, {0x08, 0x00}, {0x00, 0x00} }, /* IRPAUSE */ }; static void amt_jtagaccel_reset(int trst, int srst) { if (trst == 1) aw_control_rst |= 0x4; else if (trst == 0) aw_control_rst &= ~0x4; if (srst == 1) aw_control_rst |= 0x1; else if (srst == 0) aw_control_rst &= ~0x1; AMT_AW(aw_control_rst); } static int amt_jtagaccel_speed(int speed) { aw_control_baudrate &= 0xf0; aw_control_baudrate |= speed & 0x0f; AMT_AW(aw_control_baudrate); return ERROR_OK; } static void amt_jtagaccel_end_state(tap_state_t state) { if (tap_is_state_stable(state)) tap_set_end_state(state); else { LOG_ERROR("BUG: %i is not a valid end state", state); exit(-1); } } static void amt_wait_scan_busy(void) { int timeout = 4096; uint8_t ar_status; AMT_AR(ar_status); while (((ar_status) & 0x80) && (timeout-- > 0)) AMT_AR(ar_status); if (ar_status & 0x80) { LOG_ERROR( "amt_jtagaccel timed out while waiting for end of scan, rtck was %s, last AR_STATUS: 0x%2.2x", (rtck_enabled) ? "enabled" : "disabled", ar_status); exit(-1); } } static void amt_jtagaccel_state_move(void) { uint8_t aw_scan_tms_5; uint8_t tms_scan[2]; tap_state_t cur_state = tap_get_state(); tap_state_t end_state = tap_get_end_state(); tms_scan[0] = amt_jtagaccel_tap_move[tap_move_ndx(cur_state)][tap_move_ndx(end_state)][0]; tms_scan[1] = amt_jtagaccel_tap_move[tap_move_ndx(cur_state)][tap_move_ndx(end_state)][1]; aw_scan_tms_5 = 0x40 | (tms_scan[0] & 0x1f); AMT_AW(aw_scan_tms_5); int jtag_speed = 0; int retval = jtag_get_speed(&jtag_speed); assert(retval == ERROR_OK); if (jtag_speed > 3 || rtck_enabled) amt_wait_scan_busy(); if (tms_scan[0] & 0x80) { aw_scan_tms_5 = 0x40 | (tms_scan[1] & 0x1f); AMT_AW(aw_scan_tms_5); if (jtag_speed > 3 || rtck_enabled) amt_wait_scan_busy(); } tap_set_state(end_state); } static void amt_jtagaccel_runtest(int num_cycles) { int i = 0; uint8_t aw_scan_tms_5; uint8_t aw_scan_tms_1to4; tap_state_t saved_end_state = tap_get_end_state(); /* only do a state_move when we're not already in IDLE */ if (tap_get_state() != TAP_IDLE) { amt_jtagaccel_end_state(TAP_IDLE); amt_jtagaccel_state_move(); } while (num_cycles - i >= 5) { aw_scan_tms_5 = 0x40; AMT_AW(aw_scan_tms_5); i += 5; } if (num_cycles - i > 0) { aw_scan_tms_1to4 = 0x80 | ((num_cycles - i - 1) & 0x3) << 4; AMT_AW(aw_scan_tms_1to4); } amt_jtagaccel_end_state(saved_end_state); if (tap_get_state() != tap_get_end_state()) amt_jtagaccel_state_move(); } static void amt_jtagaccel_scan(bool ir_scan, enum scan_type type, uint8_t *buffer, int scan_size) { int bits_left = scan_size; int bit_count = 0; tap_state_t saved_end_state = tap_get_end_state(); uint8_t aw_tdi_option; uint8_t dw_tdi_scan; uint8_t dr_tdo; uint8_t aw_tms_scan; uint8_t tms_scan[2]; int jtag_speed_var; int retval = jtag_get_speed(&jtag_speed_var); assert(retval == ERROR_OK); if (ir_scan) amt_jtagaccel_end_state(TAP_IRSHIFT); else amt_jtagaccel_end_state(TAP_DRSHIFT); /* Only move if we're not already there */ if (tap_get_state() != tap_get_end_state()) amt_jtagaccel_state_move(); amt_jtagaccel_end_state(saved_end_state); /* handle unaligned bits at the beginning */ if ((scan_size - 1) % 8) { aw_tdi_option = 0x30 | (((scan_size - 1) % 8) - 1); AMT_AW(aw_tdi_option); dw_tdi_scan = buf_get_u32(buffer, bit_count, (scan_size - 1) % 8) & 0xff; AMT_DW(dw_tdi_scan); if (jtag_speed_var > 3 || rtck_enabled) amt_wait_scan_busy(); if ((type == SCAN_IN) || (type == SCAN_IO)) { AMT_DR(dr_tdo); dr_tdo = dr_tdo >> (8 - ((scan_size - 1) % 8)); buf_set_u32(buffer, bit_count, (scan_size - 1) % 8, dr_tdo); } bit_count += (scan_size - 1) % 8; bits_left -= (scan_size - 1) % 8; } while (bits_left - 1 >= 8) { dw_tdi_scan = buf_get_u32(buffer, bit_count, 8) & 0xff; AMT_DW(dw_tdi_scan); if (jtag_speed_var > 3 || rtck_enabled) amt_wait_scan_busy(); if ((type == SCAN_IN) || (type == SCAN_IO)) { AMT_DR(dr_tdo); buf_set_u32(buffer, bit_count, 8, dr_tdo); } bit_count += 8; bits_left -= 8; } tms_scan[0] = amt_jtagaccel_tap_move[tap_move_ndx(tap_get_state())][tap_move_ndx(tap_get_end_state())][0]; tms_scan[1] = amt_jtagaccel_tap_move[tap_move_ndx(tap_get_state())][tap_move_ndx(tap_get_end_state())][1]; aw_tms_scan = 0x40 | (tms_scan[0] & 0x1f) | (buf_get_u32(buffer, bit_count, 1) << 5); AMT_AW(aw_tms_scan); if (jtag_speed_var > 3 || rtck_enabled) amt_wait_scan_busy(); if ((type == SCAN_IN) || (type == SCAN_IO)) { AMT_DR(dr_tdo); dr_tdo = dr_tdo >> 7; buf_set_u32(buffer, bit_count, 1, dr_tdo); } if (tms_scan[0] & 0x80) { aw_tms_scan = 0x40 | (tms_scan[1] & 0x1f); AMT_AW(aw_tms_scan); if (jtag_speed_var > 3 || rtck_enabled) amt_wait_scan_busy(); } tap_set_state(tap_get_end_state()); } static int amt_jtagaccel_execute_queue(void) { struct jtag_command *cmd = jtag_command_queue; /* currently processed command */ int scan_size; enum scan_type type; uint8_t *buffer; int retval; /* return ERROR_OK, unless a jtag_read_buffer returns a failed check * that wasn't handled by a caller-provided error handler */ retval = ERROR_OK; while (cmd) { switch (cmd->type) { case JTAG_RESET: #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("reset trst: %i srst %i", cmd->cmd.reset->trst, cmd->cmd.reset->srst); #endif if (cmd->cmd.reset->trst == 1) tap_set_state(TAP_RESET); amt_jtagaccel_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst); break; case JTAG_RUNTEST: #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("runtest %i cycles, end in %i", cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state); #endif amt_jtagaccel_end_state(cmd->cmd.runtest->end_state); amt_jtagaccel_runtest(cmd->cmd.runtest->num_cycles); break; case JTAG_TLR_RESET: #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("statemove end in %i", cmd->cmd.statemove->end_state); #endif amt_jtagaccel_end_state(cmd->cmd.statemove->end_state); amt_jtagaccel_state_move(); break; case JTAG_SCAN: #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("scan end in %i", cmd->cmd.scan->end_state); #endif amt_jtagaccel_end_state(cmd->cmd.scan->end_state); scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer); type = jtag_scan_type(cmd->cmd.scan); amt_jtagaccel_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size); if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK) retval = ERROR_JTAG_QUEUE_FAILED; if (buffer) free(buffer); break; case JTAG_SLEEP: #ifdef _DEBUG_JTAG_IO_ LOG_DEBUG("sleep %" PRIi32, cmd->cmd.sleep->us); #endif jtag_sleep(cmd->cmd.sleep->us); break; default: LOG_ERROR("BUG: unknown JTAG command type encountered"); exit(-1); } cmd = cmd->next; } return retval; } #if PARPORT_USE_GIVEIO == 1 int amt_jtagaccel_get_giveio_access(void) { HANDLE h; OSVERSIONINFO version; version.dwOSVersionInfoSize = sizeof version; if (!GetVersionEx(&version)) { errno = EINVAL; return -1; } if (version.dwPlatformId != VER_PLATFORM_WIN32_NT) return 0; h = CreateFile("\\\\.\\giveio", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (h == INVALID_HANDLE_VALUE) { errno = ENODEV; return -1; } CloseHandle(h); return 0; } #endif static int amt_jtagaccel_init(void) { #if PARPORT_USE_PPDEV == 1 char buffer[256]; int i = 0; uint8_t control_port; #else uint8_t status_port; #endif uint8_t ar_status; #if PARPORT_USE_PPDEV == 1 if (device_handle > 0) { LOG_ERROR("device is already opened"); return ERROR_JTAG_INIT_FAILED; } snprintf(buffer, 256, "/dev/parport%d", amt_jtagaccel_port); device_handle = open(buffer, O_RDWR); if (device_handle < 0) { LOG_ERROR( "cannot open device. check it exists and that user read and write rights are set"); return ERROR_JTAG_INIT_FAILED; } i = ioctl(device_handle, PPCLAIM); if (i < 0) { LOG_ERROR("cannot claim device"); return ERROR_JTAG_INIT_FAILED; } i = IEEE1284_MODE_EPP; i = ioctl(device_handle, PPSETMODE, &i); if (i < 0) { LOG_ERROR(" cannot set compatible mode to device"); return ERROR_JTAG_INIT_FAILED; } control_port = 0x00; i = ioctl(device_handle, PPWCONTROL, &control_port); control_port = 0x04; i = ioctl(device_handle, PPWCONTROL, &control_port); #else if (amt_jtagaccel_port == 0) { amt_jtagaccel_port = 0x378; LOG_WARNING("No parport port specified, using default '0x378' (LPT1)"); } #if PARPORT_USE_GIVEIO == 1 if (amt_jtagaccel_get_giveio_access() != 0) { #else /* PARPORT_USE_GIVEIO */ if (ioperm(amt_jtagaccel_port, 5, 1) != 0) { #endif /* PARPORT_USE_GIVEIO */ LOG_ERROR("missing privileges for direct i/o"); return ERROR_JTAG_INIT_FAILED; } /* prepare epp port * clear timeout */ status_port = inb(amt_jtagaccel_port + 1); outb(status_port | 0x1, amt_jtagaccel_port + 1); /* reset epp port */ outb(0x00, amt_jtagaccel_port + 2); outb(0x04, amt_jtagaccel_port + 2); #endif if (rtck_enabled) { /* set RTCK enable bit */ aw_control_fsm |= 0x02; } /* enable JTAG port */ aw_control_fsm |= 0x04; AMT_AW(aw_control_fsm); enum reset_types jtag_reset_config = jtag_get_reset_config(); if (jtag_reset_config & RESET_TRST_OPEN_DRAIN) aw_control_rst &= ~0x8; else aw_control_rst |= 0x8; if (jtag_reset_config & RESET_SRST_PUSH_PULL) aw_control_rst &= ~0x2; else aw_control_rst |= 0x2; amt_jtagaccel_reset(0, 0); /* read status register */ AMT_AR(ar_status); LOG_DEBUG("AR_STATUS: 0x%2.2x", ar_status); return ERROR_OK; } static int amt_jtagaccel_quit(void) { return ERROR_OK; } COMMAND_HANDLER(amt_jtagaccel_handle_parport_port_command) { if (CMD_ARGC == 1) { /* only if the port wasn't overwritten by cmdline */ if (amt_jtagaccel_port == 0) { uint16_t port; COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], port); amt_jtagaccel_port = port; } else { LOG_ERROR("The parport port was already configured!"); return ERROR_FAIL; } } command_print(CMD_CTX, "parport port = %u", amt_jtagaccel_port); return ERROR_OK; } COMMAND_HANDLER(amt_jtagaccel_handle_rtck_command) { if (CMD_ARGC == 0) { command_print(CMD_CTX, "amt_jtagaccel RTCK feature %s", (rtck_enabled) ? "enabled" : "disabled"); return ERROR_OK; } else { if (strcmp(CMD_ARGV[0], "enabled") == 0) rtck_enabled = 1; else rtck_enabled = 0; } return ERROR_OK; } static const struct command_registration amtjtagaccel_command_handlers[] = { { .name = "parport_port", .handler = &amt_jtagaccel_handle_parport_port_command, .mode = COMMAND_CONFIG, .help = "configure or display the parallel port to use", .usage = "[port_num]", }, { /** * @todo Remove this "rtck" command; just use the standard * mechanism to enable/disable adaptive clocking. First * implement the standard mechanism and deprecate "rtck"; * after a year or so, it'll be safe to remove this. */ .name = "rtck", .handler = &amt_jtagaccel_handle_rtck_command, .mode = COMMAND_CONFIG, .help = "configure or display RTCK support", .usage = "[enable|disable]", }, COMMAND_REGISTRATION_DONE }; struct jtag_interface amt_jtagaccel_interface = { .name = "amt_jtagaccel", .commands = amtjtagaccel_command_handlers, .init = amt_jtagaccel_init, .quit = amt_jtagaccel_quit, .speed = amt_jtagaccel_speed, .execute_queue = amt_jtagaccel_execute_queue, }; openocd-0.7.0/src/jtag/drivers/libusb1_common.c0000644000175000001440000001173112137151331016331 00000000000000/*************************************************************************** * Copyright (C) 2009 by Zachary T Welch * * * * Copyright (C) 2011 by Mauro Gamba * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "log.h" #include "libusb1_common.h" static struct libusb_context *jtag_libusb_context; /**< Libusb context **/ static libusb_device **devs; /**< The usb device list **/ static bool jtag_libusb_match(struct jtag_libusb_device *dev, const uint16_t vids[], const uint16_t pids[]) { struct libusb_device_descriptor dev_desc; for (unsigned i = 0; vids[i]; i++) { if (libusb_get_device_descriptor(dev, &dev_desc) == 0) { if (dev_desc.idVendor == vids[i] && dev_desc.idProduct == pids[i]) return true; } } return false; } int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[], struct jtag_libusb_device_handle **out) { int cnt, idx, errCode; if (libusb_init(&jtag_libusb_context) < 0) return -ENODEV; cnt = libusb_get_device_list(jtag_libusb_context, &devs); for (idx = 0; idx < cnt; idx++) { if (!jtag_libusb_match(devs[idx], vids, pids)) continue; errCode = libusb_open(devs[idx], out); /** Free the device list **/ libusb_free_device_list(devs, 1); if (errCode < 0) return errCode; return 0; } return -ENODEV; } void jtag_libusb_close(jtag_libusb_device_handle *dev) { /* Close device */ libusb_close(dev); libusb_exit(jtag_libusb_context); } int jtag_libusb_control_transfer(jtag_libusb_device_handle *dev, uint8_t requestType, uint8_t request, uint16_t wValue, uint16_t wIndex, char *bytes, uint16_t size, unsigned int timeout) { int transferred = 0; transferred = libusb_control_transfer(dev, requestType, request, wValue, wIndex, (unsigned char *)bytes, size, timeout); if (transferred < 0) transferred = 0; return transferred; } int jtag_libusb_bulk_write(jtag_libusb_device_handle *dev, int ep, char *bytes, int size, int timeout) { int transferred = 0; libusb_bulk_transfer(dev, ep, (unsigned char *)bytes, size, &transferred, timeout); return transferred; } int jtag_libusb_bulk_read(jtag_libusb_device_handle *dev, int ep, char *bytes, int size, int timeout) { int transferred = 0; libusb_bulk_transfer(dev, ep, (unsigned char *)bytes, size, &transferred, timeout); return transferred; } int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh, int configuration) { struct jtag_libusb_device *udev = jtag_libusb_get_device(devh); int retCode = -99; struct libusb_config_descriptor *config = NULL; libusb_get_config_descriptor(udev, configuration, &config); retCode = libusb_set_configuration(devh, config->bConfigurationValue); libusb_free_config_descriptor(config); return retCode; } int jtag_libusb_get_endpoints(struct jtag_libusb_device *udev, unsigned int *usb_read_ep, unsigned int *usb_write_ep) { const struct libusb_interface *inter; const struct libusb_interface_descriptor *interdesc; const struct libusb_endpoint_descriptor *epdesc; struct libusb_config_descriptor *config; libusb_get_config_descriptor(udev, 0, &config); for (int i = 0; i < (int)config->bNumInterfaces; i++) { inter = &config->interface[i]; for (int j = 0; j < inter->num_altsetting; j++) { interdesc = &inter->altsetting[j]; for (int k = 0; k < (int)interdesc->bNumEndpoints; k++) { epdesc = &interdesc->endpoint[k]; uint8_t epnum = epdesc->bEndpointAddress; bool is_input = epnum & 0x80; LOG_DEBUG("usb ep %s %02x", is_input ? "in" : "out", epnum); if (is_input) *usb_read_ep = epnum; else *usb_write_ep = epnum; } } } libusb_free_config_descriptor(config); return 0; } openocd-0.7.0/src/jtag/tcl.h0000644000175000001440000000461712134336410012536 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2009 SoftPLC Corporation * * http://softplc.com * * dick@softplc.com * * * * Copyright (C) 2009 Zachary T Welch * * zw@superlucidity.net * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef _JTAG_TCL_H_ #define _JTAG_TCL_H_ int jim_jtag_configure(Jim_Interp *interp, int argc, Jim_Obj * const *argv); int jim_jtag_tap_enabler(Jim_Interp *interp, int argc, Jim_Obj * const *argv); #endif openocd-0.7.0/src/jtag/swd.h0000644000175000001440000001150012134336410012536 00000000000000/*************************************************************************** * Copyright (C) 2009-2010 by David Brownell * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef SWD_H #define SWD_H /* Bits in SWD command packets, written from host to target * first bit on the wire is START */ #define SWD_CMD_START (1 << 0) /* always set */ #define SWD_CMD_APnDP (1 << 1) /* set only for AP access */ #define SWD_CMD_RnW (1 << 2) /* set only for read access */ #define SWD_CMD_A32 (3 << 3) /* bits A[3:2] of register addr */ #define SWD_CMD_PARITY (1 << 5) /* parity of APnDP|RnW|A32 */ #define SWD_CMD_STOP (0 << 6) /* always clear for synch SWD */ #define SWD_CMD_PARK (0 << 7) /* not driven by host (pull high) */ /* followed by TRN, 3-bits of ACK, TRN */ /* pbit16 holds precomputed parity bits for each nibble */ #define pbit(parity, nibble) (parity << nibble) static const uint16_t pbit16 = pbit(0, 0) | pbit(1, 1) | pbit(1, 2) | pbit(0, 3) | pbit(1, 4) | pbit(0, 5) | pbit(0, 6) | pbit(1, 7) | pbit(1, 8) | pbit(0, 9) | pbit(0, 0xa) | pbit(1, 0xb) | pbit(0, 0xc) | pbit(1, 0xd) | pbit(1, 0xe) | pbit(0, 0xf); #define nibble_parity(nibble) (pbit16 & pbit(1, nibble)) /** * Construct a "cmd" byte, in lSB bit order, which swd_driver.read_reg() * and swd_driver.write_reg() methods will use directly. */ static inline uint8_t swd_cmd(bool is_read, bool is_ap, uint8_t regnum) { uint8_t cmd = (is_ap ? SWD_CMD_APnDP : 0) | (is_read ? SWD_CMD_RnW : 0) | ((regnum & 0xc) << 1); /* 8 cmd bits 4:1 may be set */ if (nibble_parity(cmd >> 1)) cmd |= SWD_CMD_PARITY; /* driver handles START, STOP, and TRN */ return cmd; } /* SWD_ACK_* bits are defined in */ /* * FOR NOW ... SWD driver ops are synchronous and return ACK * status ... no quueueing. * * Individual ops are request/response, and fast-fail permits much * better fault handling. Upper layers may queue if desired. */ struct swd_driver { /** * Initialize the debug link so it can perform * synchronous SWD operations. * @param trn value from WCR: how many clocks * to not drive the SWDIO line at certain points in * the SWD protocol (at least 1 clock). * * As an example, this would switch a dual-mode debug adapter * into SWD mode and out of JTAG mode. * * @return ERROR_OK on success, else a negative fault code. */ int (*init)(uint8_t trn); /** * Synchronous read of an AP or DP register. * * @param cmd with APnDP/RnW/addr/parity bits * @param where to store value to read from register * * @return SWD_ACK_* code for the transaction * or (negative) fault code */ int (*read_reg)(uint8_t cmd, uint32_t *value); /** * Synchronous write of an AP or DP register. * * @param cmd with APnDP/RnW/addr/parity bits * @param value to be written to the register * * @return SWD_ACK_* code for the transaction * or (negative) fault code */ int (*write_reg)(uint8_t cmd, uint32_t value); /* XXX START WITH enough to: * init (synch mode, WCR) * for async, TRN > 1 * read IDCODE from DP */ /** * Configures data collection from the Single-wire * trace (SWO) signal. * @param swo true if SWO data collection should be routed. * * For example, some debug adapters include a UART which * is normally connected to a microcontroller's UART TX, * but which may instead be connected to SWO for use in * collecting ITM (and possibly ETM) trace data. * * @return ERROR_OK on success, else a negative fault code. */ int *(*trace)(bool swo); }; int swd_init_reset(struct command_context *cmd_ctx); void swd_add_reset(int req_srst); bool transport_is_swd(void); #endif /* SWD_H */ openocd-0.7.0/src/jtag/Makefile.in0000644000175000001440000006270212141414276013654 00000000000000# Makefile.in generated by automake 1.13.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ DIST_COMMON = $(top_srcdir)/common.mk $(srcdir)/Makefile.in \ $(srcdir)/Makefile.am $(top_srcdir)/depcomp $(noinst_HEADERS) @INTERNAL_JIMTCL_TRUE@am__append_1 = -I$(top_srcdir)/jimtcl \ @INTERNAL_JIMTCL_TRUE@ -I$(top_builddir)/jimtcl @MINIDRIVER_TRUE@@ZY1000_TRUE@am__append_2 = zy1000/zy1000.c @MINIDRIVER_DUMMY_TRUE@@MINIDRIVER_TRUE@am__append_3 = minidummy/minidummy.c commands.c @MINIDRIVER_TRUE@am__append_4 = jtag_minidriver.h @MINIDRIVER_TRUE@am__append_5 = jtag_minidriver.h @MINIDRIVER_FALSE@am__append_6 = commands.c @HLADAPTER_TRUE@@MINIDRIVER_FALSE@am__append_7 = hla @HLADAPTER_TRUE@@MINIDRIVER_FALSE@am__append_8 = $(top_builddir)/src/jtag/hla/libocdhla.la @MINIDRIVER_FALSE@am__append_9 = drivers @MINIDRIVER_FALSE@am__append_10 = $(top_builddir)/src/jtag/drivers/libocdjtagdrivers.la subdir = src/jtag ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/config_subdir.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libjtag_la_DEPENDENCIES = $(am__append_8) $(am__append_10) am__libjtag_la_SOURCES_DIST = adapter.c core.c interface.c \ interfaces.c tcl.c zy1000/zy1000.c minidummy/minidummy.c \ commands.c @MINIDRIVER_TRUE@@ZY1000_TRUE@am__objects_1 = zy1000.lo @MINIDRIVER_DUMMY_TRUE@@MINIDRIVER_TRUE@am__objects_2 = minidummy.lo \ @MINIDRIVER_DUMMY_TRUE@@MINIDRIVER_TRUE@ commands.lo @MINIDRIVER_FALSE@am__objects_3 = commands.lo am__objects_4 = $(am__objects_1) $(am__objects_2) $(am__objects_3) am_libjtag_la_OBJECTS = adapter.lo core.lo interface.lo interfaces.lo \ tcl.lo $(am__objects_4) libjtag_la_OBJECTS = $(am_libjtag_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libjtag_la_SOURCES) DIST_SOURCES = $(am__libjtag_la_SOURCES_DIST) RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(noinst_HEADERS) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = hla drivers DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CC_FOR_BUILD = @CC_FOR_BUILD@ CFLAGS = @CFLAGS@ CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@ FGREP = @FGREP@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ doxygen_as_html = @doxygen_as_html@ doxygen_as_pdf = @doxygen_as_pdf@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ # common flags used in openocd build AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src \ -I$(top_srcdir)/src/helper -DPKGDATADIR=\"$(pkgdatadir)\" \ -DPKGLIBDIR=\"$(pkglibdir)\" $(am__append_1) METASOURCES = AUTO noinst_LTLIBRARIES = libjtag.la SUBDIRS = $(am__append_7) $(am__append_9) DRIVERFILES = $(am__append_2) $(am__append_3) $(am__append_6) libjtag_la_LIBADD = $(am__append_8) $(am__append_10) CLEANFILES = minidriver_imp.h $(am__append_5) BUILT_SOURCES = minidriver_imp.h $(am__append_4) @MINIDRIVER_DUMMY_TRUE@@MINIDRIVER_TRUE@JTAG_MINIDRIVER_DIR = $(srcdir)/minidummy @MINIDRIVER_TRUE@@ZY1000_TRUE@JTAG_MINIDRIVER_DIR = $(srcdir)/zy1000 @MINIDRIVER_FALSE@MINIDRIVER_IMP_DIR = $(srcdir)/drivers @MINIDRIVER_TRUE@MINIDRIVER_IMP_DIR = $(srcdir)/minidriver libjtag_la_SOURCES = \ adapter.c \ core.c \ interface.c \ interfaces.c \ tcl.c \ $(DRIVERFILES) noinst_HEADERS = \ commands.h \ driver.h \ interface.h \ interfaces.h \ minidriver.h \ jtag.h \ minidriver/minidriver_imp.h \ minidummy/jtag_minidriver.h \ swd.h \ tcl.h EXTRA_DIST = startup.tcl MAINTAINERCLEANFILES = $(srcdir)/Makefile.in all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-recursive .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/common.mk $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/jtag/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/jtag/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_srcdir)/common.mk: $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libjtag.la: $(libjtag_la_OBJECTS) $(libjtag_la_DEPENDENCIES) $(EXTRA_libjtag_la_DEPENDENCIES) $(AM_V_CCLD)$(LINK) $(libjtag_la_OBJECTS) $(libjtag_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/adapter.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/commands.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/core.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interface.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interfaces.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/minidummy.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tcl.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zy1000.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< zy1000.lo: zy1000/zy1000.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT zy1000.lo -MD -MP -MF $(DEPDIR)/zy1000.Tpo -c -o zy1000.lo `test -f 'zy1000/zy1000.c' || echo '$(srcdir)/'`zy1000/zy1000.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/zy1000.Tpo $(DEPDIR)/zy1000.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='zy1000/zy1000.c' object='zy1000.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o zy1000.lo `test -f 'zy1000/zy1000.c' || echo '$(srcdir)/'`zy1000/zy1000.c minidummy.lo: minidummy/minidummy.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT minidummy.lo -MD -MP -MF $(DEPDIR)/minidummy.Tpo -c -o minidummy.lo `test -f 'minidummy/minidummy.c' || echo '$(srcdir)/'`minidummy/minidummy.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/minidummy.Tpo $(DEPDIR)/minidummy.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='minidummy/minidummy.c' object='minidummy.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o minidummy.lo `test -f 'minidummy/minidummy.c' || echo '$(srcdir)/'`minidummy/minidummy.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-recursive all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: installdirs-recursive installdirs-am: install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-recursive clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) all check install install-am \ install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-libtool \ clean-noinstLTLIBRARIES cscopelist-am ctags ctags-am distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am @MINIDRIVER_TRUE@jtag_minidriver.h: $(JTAG_MINIDRIVER_DIR)/jtag_minidriver.h @MINIDRIVER_TRUE@ cp $< $@ # endif // MINIDRIVER minidriver_imp.h: $(MINIDRIVER_IMP_DIR)/minidriver_imp.h cp $< $@ # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: openocd-0.7.0/src/jtag/commands.h0000644000175000001440000001351612134336410013553 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2009 Zachary T Welch * * zw@superlucidity.net * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef JTAG_COMMANDS_H #define JTAG_COMMANDS_H /** * The inferred type of a scan_command_s structure, indicating whether * the command has the host scan in from the device, the host scan out * to the device, or both. */ enum scan_type { /** From device to host, */ SCAN_IN = 1, /** From host to device, */ SCAN_OUT = 2, /** Full-duplex scan. */ SCAN_IO = 3 }; /** * The scan_command provide a means of encapsulating a set of scan_field_s * structures that should be scanned in/out to the device. */ struct scan_command { /** instruction/not data scan */ bool ir_scan; /** number of fields in *fields array */ int num_fields; /** pointer to an array of data scan fields */ struct scan_field *fields; /** state in which JTAG commands should finish */ tap_state_t end_state; }; struct statemove_command { /** state in which JTAG commands should finish */ tap_state_t end_state; }; struct pathmove_command { /** number of states in *path */ int num_states; /** states that have to be passed */ tap_state_t *path; }; struct runtest_command { /** number of cycles to spend in Run-Test/Idle state */ int num_cycles; /** state in which JTAG commands should finish */ tap_state_t end_state; }; struct stableclocks_command { /** number of clock cycles that should be sent */ int num_cycles; }; struct reset_command { /** Set TRST output: 0 = deassert, 1 = assert, -1 = no change */ int trst; /** Set SRST output: 0 = deassert, 1 = assert, -1 = no change */ int srst; }; struct end_state_command { /** state in which JTAG commands should finish */ tap_state_t end_state; }; struct sleep_command { /** number of microseconds to sleep */ uint32_t us; }; /** * Encapsulates a series of bits to be clocked out, affecting state * and mode of the interface. * * In JTAG mode these are clocked out on TMS, using TCK. They may be * used for link resets, transitioning between JTAG and SWD modes, or * to implement JTAG state machine transitions (implementing pathmove * or statemove operations). * * In SWD mode these are clocked out on SWDIO, using SWCLK, and are * used for link resets and transitioning between SWD and JTAG modes. */ struct tms_command { /** How many bits should be clocked out. */ unsigned num_bits; /** The bits to clock out; the LSB is bit 0 of bits[0]. */ const uint8_t *bits; }; /** * Defines a container type that hold a pointer to a JTAG command * structure of any defined type. */ union jtag_command_container { struct scan_command *scan; struct statemove_command *statemove; struct pathmove_command *pathmove; struct runtest_command *runtest; struct stableclocks_command *stableclocks; struct reset_command *reset; struct end_state_command *end_state; struct sleep_command *sleep; struct tms_command *tms; }; /** * The type of the @c jtag_command_container contained by a * @c jtag_command_s structure. */ enum jtag_command_type { JTAG_SCAN = 1, /* JTAG_TLR_RESET's non-minidriver implementation is a * vestige from a statemove cmd. The statemove command * is obsolete and replaced by pathmove. * * pathmove does not support reset as one of it's states, * hence the need for an explicit statemove command. */ JTAG_TLR_RESET = 2, JTAG_RUNTEST = 3, JTAG_RESET = 4, JTAG_PATHMOVE = 6, JTAG_SLEEP = 7, JTAG_STABLECLOCKS = 8, JTAG_TMS = 9, }; struct jtag_command { union jtag_command_container cmd; enum jtag_command_type type; struct jtag_command *next; }; /** The current queue of jtag_command_s structures. */ extern struct jtag_command *jtag_command_queue; void *cmd_queue_alloc(size_t size); void jtag_queue_command(struct jtag_command *cmd); void jtag_command_queue_reset(void); enum scan_type jtag_scan_type(const struct scan_command *cmd); int jtag_scan_size(const struct scan_command *cmd); int jtag_read_buffer(uint8_t *buffer, const struct scan_command *cmd); int jtag_build_buffer(const struct scan_command *cmd, uint8_t **buffer); #endif /* JTAG_COMMANDS_H */ openocd-0.7.0/src/jtag/interfaces.h0000644000175000001440000000522012134336410014066 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2009 SoftPLC Corporation * * http://softplc.com * * dick@softplc.com * * * * Copyright (C) 2009 Zachary T Welch * * zw@superlucidity.net * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef OPENOCD_JTAG_INTERFACES_H #define OPENOCD_JTAG_INTERFACES_H /** @file * Exports the list of JTAG interface drivers, along with routines * for loading and unloading them dynamically from shared libraries. */ #include /** Dynamically load all JTAG interface modules from specified directory. */ void jtag_interface_modules_load(const char *path); extern struct jtag_interface *jtag_interfaces[]; #endif /* OPENOCD_JTAG_INTERFACES_H */ openocd-0.7.0/src/jtag/minidriver.h0000644000175000001440000001024012134336410014111 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2009 Zachary T Welch * * zw@superlucidity.net * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef MINIDRIVER_H #define MINIDRIVER_H /** * @page jtagminidriver JTAG Mini-Driver * * The JTAG minidriver interface allows the definition of alternate * interface functions, instead of the built-in asynchronous driver * module that is used by the standard JTAG interface drivers. * * In addtion to the functions defined in the @c minidriver.h file, the * @c jtag_minidriver.h file must declare the following functions (or * define static inline versions of them): * - jtag_add_callback * - jtag_add_callback4 * - interface_jtag_add_dr_out * * The following core functions are declared in this file for use by * the minidriver and do @b not need to be defined by an implementation: * - default_interface_jtag_execute_queue() */ /* this header will be provided by the minidriver implementation, */ /* and it may provide additional declarations that must be defined. */ #include int interface_jtag_add_ir_scan(struct jtag_tap *active, const struct scan_field *fields, tap_state_t endstate); int interface_jtag_add_plain_ir_scan( int num_bits, const uint8_t *out_bits, uint8_t *in_bits, tap_state_t endstate); int interface_jtag_add_dr_scan(struct jtag_tap *active, int num_fields, const struct scan_field *fields, tap_state_t endstate); int interface_jtag_add_plain_dr_scan( int num_bits, const uint8_t *out_bits, uint8_t *in_bits, tap_state_t endstate); int interface_jtag_add_tlr(void); int interface_jtag_add_pathmove(int num_states, const tap_state_t *path); int interface_jtag_add_runtest(int num_cycles, tap_state_t endstate); int interface_add_tms_seq(unsigned num_bits, const uint8_t *bits, enum tap_state state); /** * This drives the actual srst and trst pins. srst will always be 0 * if jtag_reset_config & RESET_SRST_PULLS_TRST != 0 and ditto for * trst. * * the higher level jtag_add_reset will invoke jtag_add_tlr() if * approperiate */ int interface_jtag_add_reset(int trst, int srst); int interface_jtag_add_sleep(uint32_t us); int interface_jtag_add_clocks(int num_cycles); int interface_jtag_execute_queue(void); /** * Calls the interface callback to execute the queue. This routine * is used by the JTAG driver layer and should not be called directly. */ int default_interface_jtag_execute_queue(void); #endif /* MINIDRIVER_H */ openocd-0.7.0/src/jtag/minidummy/0000755000175000001440000000000012141414412013660 500000000000000openocd-0.7.0/src/jtag/minidummy/minidummy.c0000644000175000001440000001102112134336410015752 00000000000000/*************************************************************************** * Copyright (C) 2007-2008 by Øyvind Harboe * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include struct jtag_interface minidummy_interface = { .name = "minidummy", .execute_queue = NULL, .speed = NULL, .commands = NULL, .init = NULL, .quit = NULL, .khz = NULL, .speed_div = NULL, .power_dropout = NULL, .srst_asserted = NULL, }; int interface_jtag_execute_queue(void) { /* synchronously do the operation here */ return ERROR_OK; } int interface_jtag_add_ir_scan(struct jtag_tap *active, const struct scan_field *fields, tap_state_t state) { /* synchronously do the operation here */ return ERROR_OK; } int interface_jtag_add_plain_ir_scan(int num_bits, const uint8_t *out_bits, uint8_t *in_bits, tap_state_t state) { /* synchronously do the operation here */ return ERROR_OK; } int interface_jtag_add_dr_scan(struct jtag_tap *active, int num_fields, const struct scan_field *fields, tap_state_t state) { /* synchronously do the operation here */ return ERROR_OK; } int interface_jtag_add_plain_dr_scan(int num_bits, const uint8_t *out_bits, uint8_t *in_bits, tap_state_t state) { /* synchronously do the operation here */ return ERROR_OK; } int interface_jtag_add_tlr() { /* synchronously do the operation here */ return ERROR_OK; } int interface_jtag_add_reset(int req_trst, int req_srst) { /* synchronously do the operation here */ return ERROR_OK; } int interface_jtag_add_runtest(int num_cycles, tap_state_t state) { /* synchronously do the operation here */ return ERROR_OK; } int interface_jtag_add_clocks(int num_cycles) { /* synchronously do the operation here */ return ERROR_OK; } int interface_jtag_add_sleep(uint32_t us) { jtag_sleep(us); return ERROR_OK; } int interface_jtag_add_pathmove(int num_states, const tap_state_t *path) { int state_count; int tms = 0; state_count = 0; tap_state_t cur_state = cmd_queue_cur_state; while (num_states) { if (tap_state_transition(cur_state, false) == path[state_count]) tms = 0; else if (tap_state_transition(cur_state, true) == path[state_count]) tms = 1; else { LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_name(cur_state), tap_state_name(path[state_count])); exit(-1); } /* synchronously do the operation here */ cur_state = path[state_count]; state_count++; num_states--; } /* synchronously do the operation here */ return ERROR_OK; } int interface_add_tms_seq(unsigned num_bits, const uint8_t *seq, enum tap_state state) { /* synchronously do the operation here */ return ERROR_OK; } void embeddedice_write_dcc(struct jtag_tap *tap, int reg_addr, const uint8_t *buffer, int little, int count) { int i; for (i = 0; i < count; i++) { embeddedice_write_reg_inner(tap, reg_addr, fast_target_buffer_get_u32(buffer, little)); buffer += 4; } } int arm11_run_instr_data_to_core_noack_inner(struct jtag_tap *tap, uint32_t opcode, uint32_t *data, size_t count) { int arm11_run_instr_data_to_core_noack_inner_default(struct jtag_tap *tap, \ uint32_t opcode, uint32_t *data, size_t count); return arm11_run_instr_data_to_core_noack_inner_default(tap, opcode, data, count); } openocd-0.7.0/src/jtag/minidummy/jtag_minidriver.h0000644000175000001440000000373512134336410017141 00000000000000/*************************************************************************** * Copyright (C) 2007-2008 by Øyvind Harboe * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ static inline void interface_jtag_add_dr_out_core(struct jtag_tap *targettap, int num_fields, const int *num_bits, const uint32_t *value, enum tap_state end_state) { /* synchronously do the operation here */ } static inline void interface_jtag_add_dr_out(struct jtag_tap *targettap, int num_fields, const int *num_bits, const uint32_t *value, enum tap_state end_state) { /* synchronously do the operation here */ } #define interface_jtag_add_callback(callback, in) callback(in) #define interface_jtag_add_callback4(callback, in, data1, data2, data3) \ jtag_set_error(callback(in, data1, data2, data3)) openocd-0.7.0/src/jtag/core.c0000644000175000001440000014146012137151331012675 00000000000000/*************************************************************************** * Copyright (C) 2009 Zachary T Welch * * zw@superlucidity.net * * * * Copyright (C) 2007,2008,2009 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2009 SoftPLC Corporation * * http://softplc.com * * dick@softplc.com * * * * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "jtag.h" #include "swd.h" #include "interface.h" #include #ifdef HAVE_STRINGS_H #include #endif /* SVF and XSVF are higher level JTAG command sets (for boundary scan) */ #include "svf/svf.h" #include "xsvf/xsvf.h" /** The number of JTAG queue flushes (for profiling and debugging purposes). */ static int jtag_flush_queue_count; /* Sleep this # of ms after flushing the queue */ static int jtag_flush_queue_sleep; static void jtag_add_scan_check(struct jtag_tap *active, void (*jtag_add_scan)(struct jtag_tap *active, int in_num_fields, const struct scan_field *in_fields, tap_state_t state), int in_num_fields, struct scan_field *in_fields, tap_state_t state); /** * The jtag_error variable is set when an error occurs while executing * the queue. Application code may set this using jtag_set_error(), * when an error occurs during processing that should be reported during * jtag_execute_queue(). * * The value is set and cleared, but never read by normal application code. * * This value is returned (and cleared) by jtag_execute_queue(). */ static int jtag_error = ERROR_OK; static const char *jtag_event_strings[] = { [JTAG_TRST_ASSERTED] = "TAP reset", [JTAG_TAP_EVENT_SETUP] = "TAP setup", [JTAG_TAP_EVENT_ENABLE] = "TAP enabled", [JTAG_TAP_EVENT_DISABLE] = "TAP disabled", }; /* * JTAG adapters must initialize with TRST and SRST de-asserted * (they're negative logic, so that means *high*). But some * hardware doesn't necessarily work that way ... so set things * up so that jtag_init() always forces that state. */ static int jtag_trst = -1; static int jtag_srst = -1; /** * List all TAPs that have been created. */ static struct jtag_tap *__jtag_all_taps; /** * The number of TAPs in the __jtag_all_taps list, used to track the * assigned chain position to new TAPs */ static unsigned jtag_num_taps; static enum reset_types jtag_reset_config = RESET_NONE; tap_state_t cmd_queue_cur_state = TAP_RESET; static bool jtag_verify_capture_ir = true; static int jtag_verify = 1; /* how long the OpenOCD should wait before attempting JTAG communication after reset lines *deasserted (in ms) */ static int adapter_nsrst_delay; /* default to no nSRST delay */ static int jtag_ntrst_delay;/* default to no nTRST delay */ static int adapter_nsrst_assert_width; /* width of assertion */ static int jtag_ntrst_assert_width; /* width of assertion */ /** * Contains a single callback along with a pointer that will be passed * when an event occurs. */ struct jtag_event_callback { /** a event callback */ jtag_event_handler_t callback; /** the private data to pass to the callback */ void *priv; /** the next callback */ struct jtag_event_callback *next; }; /* callbacks to inform high-level handlers about JTAG state changes */ static struct jtag_event_callback *jtag_event_callbacks; /* speed in kHz*/ static int speed_khz; /* speed to fallback to when RCLK is requested but not supported */ static int rclk_fallback_speed_khz; static enum {CLOCK_MODE_UNSELECTED, CLOCK_MODE_KHZ, CLOCK_MODE_RCLK} clock_mode; static int jtag_speed; static struct jtag_interface *jtag; const struct swd_driver *swd; /* configuration */ struct jtag_interface *jtag_interface; void jtag_set_flush_queue_sleep(int ms) { jtag_flush_queue_sleep = ms; } void jtag_set_error(int error) { if ((error == ERROR_OK) || (jtag_error != ERROR_OK)) return; jtag_error = error; } int jtag_error_clear(void) { int temp = jtag_error; jtag_error = ERROR_OK; return temp; } /************/ static bool jtag_poll = 1; bool is_jtag_poll_safe(void) { /* Polling can be disabled explicitly with set_enabled(false). * It is also implicitly disabled while TRST is active and * while SRST is gating the JTAG clock. */ if (!jtag_poll || jtag_trst != 0) return false; return jtag_srst == 0 || (jtag_reset_config & RESET_SRST_NO_GATING); } bool jtag_poll_get_enabled(void) { return jtag_poll; } void jtag_poll_set_enabled(bool value) { jtag_poll = value; } /************/ struct jtag_tap *jtag_all_taps(void) { return __jtag_all_taps; }; unsigned jtag_tap_count(void) { return jtag_num_taps; } unsigned jtag_tap_count_enabled(void) { struct jtag_tap *t = jtag_all_taps(); unsigned n = 0; while (t) { if (t->enabled) n++; t = t->next_tap; } return n; } /** Append a new TAP to the chain of all taps. */ void jtag_tap_add(struct jtag_tap *t) { t->abs_chain_position = jtag_num_taps++; struct jtag_tap **tap = &__jtag_all_taps; while (*tap != NULL) tap = &(*tap)->next_tap; *tap = t; } /* returns a pointer to the n-th device in the scan chain */ struct jtag_tap *jtag_tap_by_position(unsigned n) { struct jtag_tap *t = jtag_all_taps(); while (t && n-- > 0) t = t->next_tap; return t; } struct jtag_tap *jtag_tap_by_string(const char *s) { /* try by name first */ struct jtag_tap *t = jtag_all_taps(); while (t) { if (0 == strcmp(t->dotted_name, s)) return t; t = t->next_tap; } /* no tap found by name, so try to parse the name as a number */ unsigned n; if (parse_uint(s, &n) != ERROR_OK) return NULL; /* FIXME remove this numeric fallback code late June 2010, along * with all info in the User's Guide that TAPs have numeric IDs. * Also update "scan_chain" output to not display the numbers. */ t = jtag_tap_by_position(n); if (t) LOG_WARNING("Specify TAP '%s' by name, not number %u", t->dotted_name, n); return t; } struct jtag_tap *jtag_tap_next_enabled(struct jtag_tap *p) { p = p ? p->next_tap : jtag_all_taps(); while (p) { if (p->enabled) return p; p = p->next_tap; } return NULL; } const char *jtag_tap_name(const struct jtag_tap *tap) { return (tap == NULL) ? "(unknown)" : tap->dotted_name; } int jtag_register_event_callback(jtag_event_handler_t callback, void *priv) { struct jtag_event_callback **callbacks_p = &jtag_event_callbacks; if (callback == NULL) return ERROR_COMMAND_SYNTAX_ERROR; if (*callbacks_p) { while ((*callbacks_p)->next) callbacks_p = &((*callbacks_p)->next); callbacks_p = &((*callbacks_p)->next); } (*callbacks_p) = malloc(sizeof(struct jtag_event_callback)); (*callbacks_p)->callback = callback; (*callbacks_p)->priv = priv; (*callbacks_p)->next = NULL; return ERROR_OK; } int jtag_unregister_event_callback(jtag_event_handler_t callback, void *priv) { struct jtag_event_callback **p = &jtag_event_callbacks, *temp; if (callback == NULL) return ERROR_COMMAND_SYNTAX_ERROR; while (*p) { if (((*p)->priv != priv) || ((*p)->callback != callback)) { p = &(*p)->next; continue; } temp = *p; *p = (*p)->next; free(temp); } return ERROR_OK; } int jtag_call_event_callbacks(enum jtag_event event) { struct jtag_event_callback *callback = jtag_event_callbacks; LOG_DEBUG("jtag event: %s", jtag_event_strings[event]); while (callback) { struct jtag_event_callback *next; /* callback may remove itself */ next = callback->next; callback->callback(event, callback->priv); callback = next; } return ERROR_OK; } static void jtag_checks(void) { assert(jtag_trst == 0); } static void jtag_prelude(tap_state_t state) { jtag_checks(); assert(state != TAP_INVALID); cmd_queue_cur_state = state; } void jtag_add_ir_scan_noverify(struct jtag_tap *active, const struct scan_field *in_fields, tap_state_t state) { jtag_prelude(state); int retval = interface_jtag_add_ir_scan(active, in_fields, state); jtag_set_error(retval); } static void jtag_add_ir_scan_noverify_callback(struct jtag_tap *active, int dummy, const struct scan_field *in_fields, tap_state_t state) { jtag_add_ir_scan_noverify(active, in_fields, state); } /* If fields->in_value is filled out, then the captured IR value will be checked */ void jtag_add_ir_scan(struct jtag_tap *active, struct scan_field *in_fields, tap_state_t state) { assert(state != TAP_RESET); if (jtag_verify && jtag_verify_capture_ir) { /* 8 x 32 bit id's is enough for all invocations */ /* if we are to run a verification of the ir scan, we need to get the input back. * We may have to allocate space if the caller didn't ask for the input back. */ in_fields->check_value = active->expected; in_fields->check_mask = active->expected_mask; jtag_add_scan_check(active, jtag_add_ir_scan_noverify_callback, 1, in_fields, state); } else jtag_add_ir_scan_noverify(active, in_fields, state); } void jtag_add_plain_ir_scan(int num_bits, const uint8_t *out_bits, uint8_t *in_bits, tap_state_t state) { assert(out_bits != NULL); assert(state != TAP_RESET); jtag_prelude(state); int retval = interface_jtag_add_plain_ir_scan( num_bits, out_bits, in_bits, state); jtag_set_error(retval); } static int jtag_check_value_inner(uint8_t *captured, uint8_t *in_check_value, uint8_t *in_check_mask, int num_bits); static int jtag_check_value_mask_callback(jtag_callback_data_t data0, jtag_callback_data_t data1, jtag_callback_data_t data2, jtag_callback_data_t data3) { return jtag_check_value_inner((uint8_t *)data0, (uint8_t *)data1, (uint8_t *)data2, (int)data3); } static void jtag_add_scan_check(struct jtag_tap *active, void (*jtag_add_scan)( struct jtag_tap *active, int in_num_fields, const struct scan_field *in_fields, tap_state_t state), int in_num_fields, struct scan_field *in_fields, tap_state_t state) { jtag_add_scan(active, in_num_fields, in_fields, state); for (int i = 0; i < in_num_fields; i++) { if ((in_fields[i].check_value != NULL) && (in_fields[i].in_value != NULL)) { /* this is synchronous for a minidriver */ jtag_add_callback4(jtag_check_value_mask_callback, (jtag_callback_data_t)in_fields[i].in_value, (jtag_callback_data_t)in_fields[i].check_value, (jtag_callback_data_t)in_fields[i].check_mask, (jtag_callback_data_t)in_fields[i].num_bits); } } } void jtag_add_dr_scan_check(struct jtag_tap *active, int in_num_fields, struct scan_field *in_fields, tap_state_t state) { if (jtag_verify) jtag_add_scan_check(active, jtag_add_dr_scan, in_num_fields, in_fields, state); else jtag_add_dr_scan(active, in_num_fields, in_fields, state); } void jtag_add_dr_scan(struct jtag_tap *active, int in_num_fields, const struct scan_field *in_fields, tap_state_t state) { assert(state != TAP_RESET); jtag_prelude(state); int retval; retval = interface_jtag_add_dr_scan(active, in_num_fields, in_fields, state); jtag_set_error(retval); } void jtag_add_plain_dr_scan(int num_bits, const uint8_t *out_bits, uint8_t *in_bits, tap_state_t state) { assert(out_bits != NULL); assert(state != TAP_RESET); jtag_prelude(state); int retval; retval = interface_jtag_add_plain_dr_scan(num_bits, out_bits, in_bits, state); jtag_set_error(retval); } void jtag_add_tlr(void) { jtag_prelude(TAP_RESET); jtag_set_error(interface_jtag_add_tlr()); /* NOTE: order here matches TRST path in jtag_add_reset() */ jtag_call_event_callbacks(JTAG_TRST_ASSERTED); jtag_notify_event(JTAG_TRST_ASSERTED); } /** * If supported by the underlying adapter, this clocks a raw bit sequence * onto TMS for switching betwen JTAG and SWD modes. * * DO NOT use this to bypass the integrity checks and logging provided * by the jtag_add_pathmove() and jtag_add_statemove() calls. * * @param nbits How many bits to clock out. * @param seq The bit sequence. The LSB is bit 0 of seq[0]. * @param state The JTAG tap state to record on completion. Use * TAP_INVALID to represent being in in SWD mode. * * @todo Update naming conventions to stop assuming everything is JTAG. */ int jtag_add_tms_seq(unsigned nbits, const uint8_t *seq, enum tap_state state) { int retval; if (!(jtag->supported & DEBUG_CAP_TMS_SEQ)) return ERROR_JTAG_NOT_IMPLEMENTED; jtag_checks(); cmd_queue_cur_state = state; retval = interface_add_tms_seq(nbits, seq, state); jtag_set_error(retval); return retval; } void jtag_add_pathmove(int num_states, const tap_state_t *path) { tap_state_t cur_state = cmd_queue_cur_state; /* the last state has to be a stable state */ if (!tap_is_state_stable(path[num_states - 1])) { LOG_ERROR("BUG: TAP path doesn't finish in a stable state"); jtag_set_error(ERROR_JTAG_NOT_STABLE_STATE); return; } for (int i = 0; i < num_states; i++) { if (path[i] == TAP_RESET) { LOG_ERROR("BUG: TAP_RESET is not a valid state for pathmove sequences"); jtag_set_error(ERROR_JTAG_STATE_INVALID); return; } if (tap_state_transition(cur_state, true) != path[i] && tap_state_transition(cur_state, false) != path[i]) { LOG_ERROR("BUG: %s -> %s isn't a valid TAP transition", tap_state_name(cur_state), tap_state_name(path[i])); jtag_set_error(ERROR_JTAG_TRANSITION_INVALID); return; } cur_state = path[i]; } jtag_checks(); jtag_set_error(interface_jtag_add_pathmove(num_states, path)); cmd_queue_cur_state = path[num_states - 1]; } int jtag_add_statemove(tap_state_t goal_state) { tap_state_t cur_state = cmd_queue_cur_state; if (goal_state != cur_state) { LOG_DEBUG("cur_state=%s goal_state=%s", tap_state_name(cur_state), tap_state_name(goal_state)); } /* If goal is RESET, be paranoid and force that that transition * (e.g. five TCK cycles, TMS high). Else trust "cur_state". */ if (goal_state == TAP_RESET) jtag_add_tlr(); else if (goal_state == cur_state) /* nothing to do */; else if (tap_is_state_stable(cur_state) && tap_is_state_stable(goal_state)) { unsigned tms_bits = tap_get_tms_path(cur_state, goal_state); unsigned tms_count = tap_get_tms_path_len(cur_state, goal_state); tap_state_t moves[8]; assert(tms_count < ARRAY_SIZE(moves)); for (unsigned i = 0; i < tms_count; i++, tms_bits >>= 1) { bool bit = tms_bits & 1; cur_state = tap_state_transition(cur_state, bit); moves[i] = cur_state; } jtag_add_pathmove(tms_count, moves); } else if (tap_state_transition(cur_state, true) == goal_state || tap_state_transition(cur_state, false) == goal_state) jtag_add_pathmove(1, &goal_state); else return ERROR_FAIL; return ERROR_OK; } void jtag_add_runtest(int num_cycles, tap_state_t state) { jtag_prelude(state); jtag_set_error(interface_jtag_add_runtest(num_cycles, state)); } void jtag_add_clocks(int num_cycles) { if (!tap_is_state_stable(cmd_queue_cur_state)) { LOG_ERROR("jtag_add_clocks() called with TAP in unstable state \"%s\"", tap_state_name(cmd_queue_cur_state)); jtag_set_error(ERROR_JTAG_NOT_STABLE_STATE); return; } if (num_cycles > 0) { jtag_checks(); jtag_set_error(interface_jtag_add_clocks(num_cycles)); } } void swd_add_reset(int req_srst) { if (req_srst) { if (!(jtag_reset_config & RESET_HAS_SRST)) { LOG_ERROR("BUG: can't assert SRST"); jtag_set_error(ERROR_FAIL); return; } req_srst = 1; } /* Maybe change SRST signal state */ if (jtag_srst != req_srst) { int retval; retval = interface_jtag_add_reset(0, req_srst); if (retval != ERROR_OK) jtag_set_error(retval); else retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("TRST/SRST error"); return; } /* SRST resets everything hooked up to that signal */ jtag_srst = req_srst; if (jtag_srst) { LOG_DEBUG("SRST line asserted"); if (adapter_nsrst_assert_width) jtag_add_sleep(adapter_nsrst_assert_width * 1000); } else { LOG_DEBUG("SRST line released"); if (adapter_nsrst_delay) jtag_add_sleep(adapter_nsrst_delay * 1000); } } } void jtag_add_reset(int req_tlr_or_trst, int req_srst) { int trst_with_tlr = 0; int new_srst = 0; int new_trst = 0; /* Without SRST, we must use target-specific JTAG operations * on each target; callers should not be requesting SRST when * that signal doesn't exist. * * RESET_SRST_PULLS_TRST is a board or chip level quirk, which * can kick in even if the JTAG adapter can't drive TRST. */ if (req_srst) { if (!(jtag_reset_config & RESET_HAS_SRST)) { LOG_ERROR("BUG: can't assert SRST"); jtag_set_error(ERROR_FAIL); return; } if ((jtag_reset_config & RESET_SRST_PULLS_TRST) != 0 && !req_tlr_or_trst) { LOG_ERROR("BUG: can't assert only SRST"); jtag_set_error(ERROR_FAIL); return; } new_srst = 1; } /* JTAG reset (entry to TAP_RESET state) can always be achieved * using TCK and TMS; that may go through a TAP_{IR,DR}UPDATE * state first. TRST accelerates it, and bypasses those states. * * RESET_TRST_PULLS_SRST is a board or chip level quirk, which * can kick in even if the JTAG adapter can't drive SRST. */ if (req_tlr_or_trst) { if (!(jtag_reset_config & RESET_HAS_TRST)) trst_with_tlr = 1; else if ((jtag_reset_config & RESET_TRST_PULLS_SRST) != 0 && !req_srst) trst_with_tlr = 1; else new_trst = 1; } /* Maybe change TRST and/or SRST signal state */ if (jtag_srst != new_srst || jtag_trst != new_trst) { int retval; retval = interface_jtag_add_reset(new_trst, new_srst); if (retval != ERROR_OK) jtag_set_error(retval); else retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("TRST/SRST error"); return; } } /* SRST resets everything hooked up to that signal */ if (jtag_srst != new_srst) { jtag_srst = new_srst; if (jtag_srst) { LOG_DEBUG("SRST line asserted"); if (adapter_nsrst_assert_width) jtag_add_sleep(adapter_nsrst_assert_width * 1000); } else { LOG_DEBUG("SRST line released"); if (adapter_nsrst_delay) jtag_add_sleep(adapter_nsrst_delay * 1000); } } /* Maybe enter the JTAG TAP_RESET state ... * - using only TMS, TCK, and the JTAG state machine * - or else more directly, using TRST * * TAP_RESET should be invisible to non-debug parts of the system. */ if (trst_with_tlr) { LOG_DEBUG("JTAG reset with TLR instead of TRST"); jtag_add_tlr(); } else if (jtag_trst != new_trst) { jtag_trst = new_trst; if (jtag_trst) { LOG_DEBUG("TRST line asserted"); tap_set_state(TAP_RESET); if (jtag_ntrst_assert_width) jtag_add_sleep(jtag_ntrst_assert_width * 1000); } else { LOG_DEBUG("TRST line released"); if (jtag_ntrst_delay) jtag_add_sleep(jtag_ntrst_delay * 1000); /* We just asserted nTRST, so we're now in TAP_RESET. * Inform possible listeners about this, now that * JTAG instructions and data can be shifted. This * sequence must match jtag_add_tlr(). */ jtag_call_event_callbacks(JTAG_TRST_ASSERTED); jtag_notify_event(JTAG_TRST_ASSERTED); } } } void jtag_add_sleep(uint32_t us) { /** @todo Here, keep_alive() appears to be a layering violation!!! */ keep_alive(); jtag_set_error(interface_jtag_add_sleep(us)); } static int jtag_check_value_inner(uint8_t *captured, uint8_t *in_check_value, uint8_t *in_check_mask, int num_bits) { int retval = ERROR_OK; int compare_failed; if (in_check_mask) compare_failed = buf_cmp_mask(captured, in_check_value, in_check_mask, num_bits); else compare_failed = buf_cmp(captured, in_check_value, num_bits); if (compare_failed) { char *captured_str, *in_check_value_str; int bits = (num_bits > DEBUG_JTAG_IOZ) ? DEBUG_JTAG_IOZ : num_bits; /* NOTE: we've lost diagnostic context here -- 'which tap' */ captured_str = buf_to_str(captured, bits, 16); in_check_value_str = buf_to_str(in_check_value, bits, 16); LOG_WARNING("Bad value '%s' captured during DR or IR scan:", captured_str); LOG_WARNING(" check_value: 0x%s", in_check_value_str); free(captured_str); free(in_check_value_str); if (in_check_mask) { char *in_check_mask_str; in_check_mask_str = buf_to_str(in_check_mask, bits, 16); LOG_WARNING(" check_mask: 0x%s", in_check_mask_str); free(in_check_mask_str); } retval = ERROR_JTAG_QUEUE_FAILED; } return retval; } void jtag_check_value_mask(struct scan_field *field, uint8_t *value, uint8_t *mask) { assert(field->in_value != NULL); if (value == NULL) { /* no checking to do */ return; } jtag_execute_queue_noclear(); int retval = jtag_check_value_inner(field->in_value, value, mask, field->num_bits); jtag_set_error(retval); } int default_interface_jtag_execute_queue(void) { if (NULL == jtag) { LOG_ERROR("No JTAG interface configured yet. " "Issue 'init' command in startup scripts " "before communicating with targets."); return ERROR_FAIL; } return jtag->execute_queue(); } void jtag_execute_queue_noclear(void) { jtag_flush_queue_count++; jtag_set_error(interface_jtag_execute_queue()); if (jtag_flush_queue_sleep > 0) { /* For debug purposes it can be useful to test performance * or behavior when delaying after flushing the queue, * e.g. to simulate long roundtrip times. */ usleep(jtag_flush_queue_sleep * 1000); } } int jtag_get_flush_queue_count(void) { return jtag_flush_queue_count; } int jtag_execute_queue(void) { jtag_execute_queue_noclear(); return jtag_error_clear(); } static int jtag_reset_callback(enum jtag_event event, void *priv) { struct jtag_tap *tap = priv; if (event == JTAG_TRST_ASSERTED) { tap->enabled = !tap->disabled_after_reset; /* current instruction is either BYPASS or IDCODE */ buf_set_ones(tap->cur_instr, tap->ir_length); tap->bypass = 1; } return ERROR_OK; } /* sleep at least us microseconds. When we sleep more than 1000ms we * do an alive sleep, i.e. keep GDB alive. Note that we could starve * GDB if we slept for <1000ms many times. */ void jtag_sleep(uint32_t us) { if (us < 1000) usleep(us); else alive_sleep((us+999)/1000); } /* Maximum number of enabled JTAG devices we expect in the scan chain, * plus one (to detect garbage at the end). Devices that don't support * IDCODE take up fewer bits, possibly allowing a few more devices. */ #define JTAG_MAX_CHAIN_SIZE 20 #define EXTRACT_MFG(X) (((X) & 0xffe) >> 1) #define EXTRACT_PART(X) (((X) & 0xffff000) >> 12) #define EXTRACT_VER(X) (((X) & 0xf0000000) >> 28) /* A reserved manufacturer ID is used in END_OF_CHAIN_FLAG, so we * know that no valid TAP will have it as an IDCODE value. */ #define END_OF_CHAIN_FLAG 0xffffffff /* a larger IR length than we ever expect to autoprobe */ #define JTAG_IRLEN_MAX 60 static int jtag_examine_chain_execute(uint8_t *idcode_buffer, unsigned num_idcode) { struct scan_field field = { .num_bits = num_idcode * 32, .out_value = idcode_buffer, .in_value = idcode_buffer, }; /* initialize to the end of chain ID value */ for (unsigned i = 0; i < JTAG_MAX_CHAIN_SIZE; i++) buf_set_u32(idcode_buffer, i * 32, 32, END_OF_CHAIN_FLAG); jtag_add_plain_dr_scan(field.num_bits, field.out_value, field.in_value, TAP_DRPAUSE); jtag_add_tlr(); return jtag_execute_queue(); } static bool jtag_examine_chain_check(uint8_t *idcodes, unsigned count) { uint8_t zero_check = 0x0; uint8_t one_check = 0xff; for (unsigned i = 0; i < count * 4; i++) { zero_check |= idcodes[i]; one_check &= idcodes[i]; } /* if there wasn't a single non-zero bit or if all bits were one, * the scan is not valid. We wrote a mix of both values; either * * - There's a hardware issue (almost certainly): * + all-zeroes can mean a target stuck in JTAG reset * + all-ones tends to mean no target * - The scan chain is WAY longer than we can handle, *AND* either * + there are several hundreds of TAPs in bypass, or * + at least a few dozen TAPs all have an all-ones IDCODE */ if (zero_check == 0x00 || one_check == 0xff) { LOG_ERROR("JTAG scan chain interrogation failed: all %s", (zero_check == 0x00) ? "zeroes" : "ones"); LOG_ERROR("Check JTAG interface, timings, target power, etc."); return false; } return true; } static void jtag_examine_chain_display(enum log_levels level, const char *msg, const char *name, uint32_t idcode) { log_printf_lf(level, __FILE__, __LINE__, __func__, "JTAG tap: %s %16.16s: 0x%08x " "(mfg: 0x%3.3x, part: 0x%4.4x, ver: 0x%1.1x)", name, msg, (unsigned int)idcode, (unsigned int)EXTRACT_MFG(idcode), (unsigned int)EXTRACT_PART(idcode), (unsigned int)EXTRACT_VER(idcode)); } static bool jtag_idcode_is_final(uint32_t idcode) { /* * Some devices, such as AVR8, will output all 1's instead * of TDI input value at end of chain. Allow those values * instead of failing. */ return idcode == END_OF_CHAIN_FLAG; } /** * This helper checks that remaining bits in the examined chain data are * all as expected, but a single JTAG device requires only 64 bits to be * read back correctly. This can help identify and diagnose problems * with the JTAG chain earlier, gives more helpful/explicit error messages. * Returns TRUE iff garbage was found. */ static bool jtag_examine_chain_end(uint8_t *idcodes, unsigned count, unsigned max) { bool triggered = false; for (; count < max - 31; count += 32) { uint32_t idcode = buf_get_u32(idcodes, count, 32); /* do not trigger the warning if the data looks good */ if (jtag_idcode_is_final(idcode)) continue; LOG_WARNING("Unexpected idcode after end of chain: %d 0x%08x", count, (unsigned int)idcode); triggered = true; } return triggered; } static bool jtag_examine_chain_match_tap(const struct jtag_tap *tap) { uint32_t idcode = tap->idcode; /* ignore expected BYPASS codes; warn otherwise */ if (0 == tap->expected_ids_cnt && !idcode) return true; /* optionally ignore the JTAG version field - bits 28-31 of IDCODE */ uint32_t mask = tap->ignore_version ? ~(0xf << 28) : ~0; idcode &= mask; /* Loop over the expected identification codes and test for a match */ unsigned ii, limit = tap->expected_ids_cnt; for (ii = 0; ii < limit; ii++) { uint32_t expected = tap->expected_ids[ii] & mask; if (idcode == expected) return true; /* treat "-expected-id 0" as a "don't-warn" wildcard */ if (0 == tap->expected_ids[ii]) return true; } /* If none of the expected ids matched, warn */ jtag_examine_chain_display(LOG_LVL_WARNING, "UNEXPECTED", tap->dotted_name, tap->idcode); for (ii = 0; ii < limit; ii++) { char msg[32]; snprintf(msg, sizeof(msg), "expected %u of %u", ii + 1, limit); jtag_examine_chain_display(LOG_LVL_ERROR, msg, tap->dotted_name, tap->expected_ids[ii]); } return false; } /* Try to examine chain layout according to IEEE 1149.1 §12 * This is called a "blind interrogation" of the scan chain. */ static int jtag_examine_chain(void) { uint8_t idcode_buffer[JTAG_MAX_CHAIN_SIZE * 4]; unsigned bit_count; int retval; int tapcount = 0; bool autoprobe = false; /* DR scan to collect BYPASS or IDCODE register contents. * Then make sure the scan data has both ones and zeroes. */ LOG_DEBUG("DR scan interrogation for IDCODE/BYPASS"); retval = jtag_examine_chain_execute(idcode_buffer, JTAG_MAX_CHAIN_SIZE); if (retval != ERROR_OK) return retval; if (!jtag_examine_chain_check(idcode_buffer, JTAG_MAX_CHAIN_SIZE)) return ERROR_JTAG_INIT_FAILED; /* point at the 1st tap */ struct jtag_tap *tap = jtag_tap_next_enabled(NULL); if (!tap) autoprobe = true; for (bit_count = 0; tap && bit_count < (JTAG_MAX_CHAIN_SIZE * 32) - 31; tap = jtag_tap_next_enabled(tap)) { uint32_t idcode = buf_get_u32(idcode_buffer, bit_count, 32); if ((idcode & 1) == 0) { /* Zero for LSB indicates a device in bypass */ LOG_INFO("TAP %s does not have IDCODE", tap->dotted_name); idcode = 0; tap->hasidcode = false; bit_count += 1; } else { /* Friendly devices support IDCODE */ tap->hasidcode = true; jtag_examine_chain_display(LOG_LVL_INFO, "tap/device found", tap->dotted_name, idcode); bit_count += 32; } tap->idcode = idcode; /* ensure the TAP ID matches what was expected */ if (!jtag_examine_chain_match_tap(tap)) retval = ERROR_JTAG_INIT_SOFT_FAIL; } /* Fail if too many TAPs were enabled for us to verify them all. */ if (tap) { LOG_ERROR("Too many TAPs enabled; '%s' ignored.", tap->dotted_name); return ERROR_JTAG_INIT_FAILED; } /* if autoprobing, the tap list is still empty ... populate it! */ while (autoprobe && bit_count < (JTAG_MAX_CHAIN_SIZE * 32) - 31) { uint32_t idcode; char buf[12]; /* Is there another TAP? */ idcode = buf_get_u32(idcode_buffer, bit_count, 32); if (jtag_idcode_is_final(idcode)) break; /* Default everything in this TAP except IR length. * * REVISIT create a jtag_alloc(chip, tap) routine, and * share it with jim_newtap_cmd(). */ tap = calloc(1, sizeof *tap); if (!tap) return ERROR_FAIL; sprintf(buf, "auto%d", tapcount++); tap->chip = strdup(buf); tap->tapname = strdup("tap"); sprintf(buf, "%s.%s", tap->chip, tap->tapname); tap->dotted_name = strdup(buf); /* tap->ir_length == 0 ... signifying irlen autoprobe */ tap->ir_capture_mask = 0x03; tap->ir_capture_value = 0x01; tap->enabled = true; if ((idcode & 1) == 0) { bit_count += 1; tap->hasidcode = false; } else { bit_count += 32; tap->hasidcode = true; tap->idcode = idcode; tap->expected_ids_cnt = 1; tap->expected_ids = malloc(sizeof(uint32_t)); tap->expected_ids[0] = idcode; } LOG_WARNING("AUTO %s - use \"jtag newtap " "%s %s -expected-id 0x%8.8" PRIx32 " ...\"", tap->dotted_name, tap->chip, tap->tapname, tap->idcode); jtag_tap_init(tap); } /* After those IDCODE or BYPASS register values should be * only the data we fed into the scan chain. */ if (jtag_examine_chain_end(idcode_buffer, bit_count, 8 * sizeof(idcode_buffer))) { LOG_ERROR("double-check your JTAG setup (interface, " "speed, missing TAPs, ...)"); return ERROR_JTAG_INIT_FAILED; } /* Return success or, for backwards compatibility if only * some IDCODE values mismatched, a soft/continuable fault. */ return retval; } /* * Validate the date loaded by entry to the Capture-IR state, to help * find errors related to scan chain configuration (wrong IR lengths) * or communication. * * Entry state can be anything. On non-error exit, all TAPs are in * bypass mode. On error exits, the scan chain is reset. */ static int jtag_validate_ircapture(void) { struct jtag_tap *tap; int total_ir_length = 0; uint8_t *ir_test = NULL; struct scan_field field; int val; int chain_pos = 0; int retval; /* when autoprobing, accomodate huge IR lengths */ for (tap = NULL, total_ir_length = 0; (tap = jtag_tap_next_enabled(tap)) != NULL; total_ir_length += tap->ir_length) { if (tap->ir_length == 0) total_ir_length += JTAG_IRLEN_MAX; } /* increase length to add 2 bit sentinel after scan */ total_ir_length += 2; ir_test = malloc(DIV_ROUND_UP(total_ir_length, 8)); if (ir_test == NULL) return ERROR_FAIL; /* after this scan, all TAPs will capture BYPASS instructions */ buf_set_ones(ir_test, total_ir_length); field.num_bits = total_ir_length; field.out_value = ir_test; field.in_value = ir_test; jtag_add_plain_ir_scan(field.num_bits, field.out_value, field.in_value, TAP_IDLE); LOG_DEBUG("IR capture validation scan"); retval = jtag_execute_queue(); if (retval != ERROR_OK) goto done; tap = NULL; chain_pos = 0; for (;; ) { tap = jtag_tap_next_enabled(tap); if (tap == NULL) break; /* If we're autoprobing, guess IR lengths. They must be at * least two bits. Guessing will fail if (a) any TAP does * not conform to the JTAG spec; or (b) when the upper bits * captured from some conforming TAP are nonzero. Or if * (c) an IR length is longer than 32 bits -- which is only * an implementation limit, which could someday be raised. * * REVISIT optimization: if there's a *single* TAP we can * lift restrictions (a) and (b) by scanning a recognizable * pattern before the all-ones BYPASS. Check for where the * pattern starts in the result, instead of an 0...01 value. * * REVISIT alternative approach: escape to some tcl code * which could provide more knowledge, based on IDCODE; and * only guess when that has no success. */ if (tap->ir_length == 0) { tap->ir_length = 2; while ((val = buf_get_u32(ir_test, chain_pos, tap->ir_length + 1)) == 1 && tap->ir_length <= 32) { tap->ir_length++; } LOG_WARNING("AUTO %s - use \"... -irlen %d\"", jtag_tap_name(tap), tap->ir_length); } /* Validate the two LSBs, which must be 01 per JTAG spec. * * Or ... more bits could be provided by TAP declaration. * Plus, some taps (notably in i.MX series chips) violate * this part of the JTAG spec, so their capture mask/value * attributes might disable this test. */ val = buf_get_u32(ir_test, chain_pos, tap->ir_length); if ((val & tap->ir_capture_mask) != tap->ir_capture_value) { LOG_ERROR("%s: IR capture error; saw 0x%0*x not 0x%0*x", jtag_tap_name(tap), (tap->ir_length + 7) / tap->ir_length, val, (tap->ir_length + 7) / tap->ir_length, (unsigned) tap->ir_capture_value); retval = ERROR_JTAG_INIT_FAILED; goto done; } LOG_DEBUG("%s: IR capture 0x%0*x", jtag_tap_name(tap), (tap->ir_length + 7) / tap->ir_length, val); chain_pos += tap->ir_length; } /* verify the '11' sentinel we wrote is returned at the end */ val = buf_get_u32(ir_test, chain_pos, 2); if (val != 0x3) { char *cbuf = buf_to_str(ir_test, total_ir_length, 16); LOG_ERROR("IR capture error at bit %d, saw 0x%s not 0x...3", chain_pos, cbuf); free(cbuf); retval = ERROR_JTAG_INIT_FAILED; } done: free(ir_test); if (retval != ERROR_OK) { jtag_add_tlr(); jtag_execute_queue(); } return retval; } void jtag_tap_init(struct jtag_tap *tap) { unsigned ir_len_bits; unsigned ir_len_bytes; /* if we're autoprobing, cope with potentially huge ir_length */ ir_len_bits = tap->ir_length ? : JTAG_IRLEN_MAX; ir_len_bytes = DIV_ROUND_UP(ir_len_bits, 8); tap->expected = calloc(1, ir_len_bytes); tap->expected_mask = calloc(1, ir_len_bytes); tap->cur_instr = malloc(ir_len_bytes); /** @todo cope better with ir_length bigger than 32 bits */ if (ir_len_bits > 32) ir_len_bits = 32; buf_set_u32(tap->expected, 0, ir_len_bits, tap->ir_capture_value); buf_set_u32(tap->expected_mask, 0, ir_len_bits, tap->ir_capture_mask); /* TAP will be in bypass mode after jtag_validate_ircapture() */ tap->bypass = 1; buf_set_ones(tap->cur_instr, tap->ir_length); /* register the reset callback for the TAP */ jtag_register_event_callback(&jtag_reset_callback, tap); jtag_tap_add(tap); LOG_DEBUG("Created Tap: %s @ abs position %d, " "irlen %d, capture: 0x%x mask: 0x%x", tap->dotted_name, tap->abs_chain_position, tap->ir_length, (unsigned) tap->ir_capture_value, (unsigned) tap->ir_capture_mask); } void jtag_tap_free(struct jtag_tap *tap) { jtag_unregister_event_callback(&jtag_reset_callback, tap); /** @todo is anything missing? no memory leaks please */ free((void *)tap->expected); free((void *)tap->expected_ids); free((void *)tap->chip); free((void *)tap->tapname); free((void *)tap->dotted_name); free(tap); } /** * Do low-level setup like initializing registers, output signals, * and clocking. */ int adapter_init(struct command_context *cmd_ctx) { if (jtag) return ERROR_OK; if (!jtag_interface) { /* nothing was previously specified by "interface" command */ LOG_ERROR("Debug Adapter has to be specified, " "see \"interface\" command"); return ERROR_JTAG_INVALID_INTERFACE; } int retval; retval = jtag_interface->init(); if (retval != ERROR_OK) return retval; jtag = jtag_interface; /* LEGACY SUPPORT ... adapter drivers must declare what * transports they allow. Until they all do so, assume * the legacy drivers are JTAG-only */ if (!transports_are_declared()) { LOG_ERROR("Adapter driver '%s' did not declare " "which transports it allows; assuming " "JTAG-only", jtag->name); retval = allow_transports(cmd_ctx, jtag_only); if (retval != ERROR_OK) return retval; } if (jtag->speed == NULL) { LOG_INFO("This adapter doesn't support configurable speed"); return ERROR_OK; } if (CLOCK_MODE_UNSELECTED == clock_mode) { LOG_ERROR("An adapter speed is not selected in the init script." " Insert a call to adapter_khz or jtag_rclk to proceed."); return ERROR_JTAG_INIT_FAILED; } int requested_khz = jtag_get_speed_khz(); int actual_khz = requested_khz; int jtag_speed_var = 0; retval = jtag_get_speed(&jtag_speed_var); if (retval != ERROR_OK) return retval; retval = jtag->speed(jtag_speed_var); if (retval != ERROR_OK) return retval; retval = jtag_get_speed_readable(&actual_khz); if (ERROR_OK != retval) LOG_INFO("adapter-specific clock speed value %d", jtag_speed_var); else if (actual_khz) { /* Adaptive clocking -- JTAG-specific */ if ((CLOCK_MODE_RCLK == clock_mode) || ((CLOCK_MODE_KHZ == clock_mode) && !requested_khz)) { LOG_INFO("RCLK (adaptive clock speed) not supported - fallback to %d kHz" , actual_khz); } else LOG_INFO("clock speed %d kHz", actual_khz); } else LOG_INFO("RCLK (adaptive clock speed)"); return ERROR_OK; } int jtag_init_inner(struct command_context *cmd_ctx) { struct jtag_tap *tap; int retval; bool issue_setup = true; LOG_DEBUG("Init JTAG chain"); tap = jtag_tap_next_enabled(NULL); if (tap == NULL) { /* Once JTAG itself is properly set up, and the scan chain * isn't absurdly large, IDCODE autoprobe should work fine. * * But ... IRLEN autoprobe can fail even on systems which * are fully conformant to JTAG. Also, JTAG setup can be * quite finicky on some systems. * * REVISIT: if TAP autoprobe works OK, then in many cases * we could escape to tcl code and set up targets based on * the TAP's IDCODE values. */ LOG_WARNING("There are no enabled taps. " "AUTO PROBING MIGHT NOT WORK!!"); /* REVISIT default clock will often be too fast ... */ } jtag_add_tlr(); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; /* Examine DR values first. This discovers problems which will * prevent communication ... hardware issues like TDO stuck, or * configuring the wrong number of (enabled) TAPs. */ retval = jtag_examine_chain(); switch (retval) { case ERROR_OK: /* complete success */ break; default: /* For backward compatibility reasons, try coping with * configuration errors involving only ID mismatches. * We might be able to talk to the devices. * * Also the device might be powered down during startup. * * After OpenOCD starts, we can try to power on the device * and run a reset. */ LOG_ERROR("Trying to use configured scan chain anyway..."); issue_setup = false; break; } /* Now look at IR values. Problems here will prevent real * communication. They mostly mean that the IR length is * wrong ... or that the IR capture value is wrong. (The * latter is uncommon, but easily worked around: provide * ircapture/irmask values during TAP setup.) */ retval = jtag_validate_ircapture(); if (retval != ERROR_OK) { /* The target might be powered down. The user * can power it up and reset it after firing * up OpenOCD. */ issue_setup = false; } if (issue_setup) jtag_notify_event(JTAG_TAP_EVENT_SETUP); else LOG_WARNING("Bypassing JTAG setup events due to errors"); return ERROR_OK; } int adapter_quit(void) { if (!jtag || !jtag->quit) return ERROR_OK; /* close the JTAG interface */ int result = jtag->quit(); if (ERROR_OK != result) LOG_ERROR("failed: %d", result); return ERROR_OK; } int swd_init_reset(struct command_context *cmd_ctx) { int retval = adapter_init(cmd_ctx); if (retval != ERROR_OK) return retval; LOG_DEBUG("Initializing with hard SRST reset"); if (jtag_reset_config & RESET_HAS_SRST) swd_add_reset(1); swd_add_reset(0); retval = jtag_execute_queue(); return retval; } int jtag_init_reset(struct command_context *cmd_ctx) { int retval = adapter_init(cmd_ctx); if (retval != ERROR_OK) return retval; LOG_DEBUG("Initializing with hard TRST+SRST reset"); /* * This procedure is used by default when OpenOCD triggers a reset. * It's now done through an overridable Tcl "init_reset" wrapper. * * This started out as a more powerful "get JTAG working" reset than * jtag_init_inner(), applying TRST because some chips won't activate * JTAG without a TRST cycle (presumed to be async, though some of * those chips synchronize JTAG activation using TCK). * * But some chips only activate JTAG as part of an SRST cycle; SRST * got mixed in. So it became a hard reset routine, which got used * in more places, and which coped with JTAG reset being forced as * part of SRST (srst_pulls_trst). * * And even more corner cases started to surface: TRST and/or SRST * assertion timings matter; some chips need other JTAG operations; * TRST/SRST sequences can need to be different from these, etc. * * Systems should override that wrapper to support system-specific * requirements that this not-fully-generic code doesn't handle. * * REVISIT once Tcl code can read the reset_config modes, this won't * need to be a C routine at all... */ jtag_add_reset(1, 0); /* TAP_RESET, using TMS+TCK or TRST */ if (jtag_reset_config & RESET_HAS_SRST) { jtag_add_reset(1, 1); if ((jtag_reset_config & RESET_SRST_PULLS_TRST) == 0) jtag_add_reset(0, 1); } /* some targets enable us to connect with srst asserted */ if (jtag_reset_config & RESET_CNCT_UNDER_SRST) { if (jtag_reset_config & RESET_SRST_NO_GATING) jtag_add_reset(0, 1); else { LOG_WARNING("\'srst_nogate\' reset_config option is required"); jtag_add_reset(0, 0); } } else jtag_add_reset(0, 0); retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; /* Check that we can communication on the JTAG chain + eventually we want to * be able to perform enumeration only after OpenOCD has started * telnet and GDB server * * That would allow users to more easily perform any magic they need to before * reset happens. */ return jtag_init_inner(cmd_ctx); } int jtag_init(struct command_context *cmd_ctx) { int retval = adapter_init(cmd_ctx); if (retval != ERROR_OK) return retval; /* guard against oddball hardware: force resets to be inactive */ jtag_add_reset(0, 0); /* some targets enable us to connect with srst asserted */ if (jtag_reset_config & RESET_CNCT_UNDER_SRST) { if (jtag_reset_config & RESET_SRST_NO_GATING) jtag_add_reset(0, 1); else LOG_WARNING("\'srst_nogate\' reset_config option is required"); } retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; if (Jim_Eval_Named(cmd_ctx->interp, "jtag_init", __FILE__, __LINE__) != JIM_OK) return ERROR_FAIL; return ERROR_OK; } unsigned jtag_get_speed_khz(void) { return speed_khz; } static int adapter_khz_to_speed(unsigned khz, int *speed) { LOG_DEBUG("convert khz to interface specific speed value"); speed_khz = khz; if (jtag != NULL) { LOG_DEBUG("have interface set up"); int speed_div1; int retval = jtag->khz(jtag_get_speed_khz(), &speed_div1); if (ERROR_OK != retval) return retval; *speed = speed_div1; } return ERROR_OK; } static int jtag_rclk_to_speed(unsigned fallback_speed_khz, int *speed) { int retval = adapter_khz_to_speed(0, speed); if ((ERROR_OK != retval) && fallback_speed_khz) { LOG_DEBUG("trying fallback speed..."); retval = adapter_khz_to_speed(fallback_speed_khz, speed); } return retval; } static int jtag_set_speed(int speed) { jtag_speed = speed; /* this command can be called during CONFIG, * in which case jtag isn't initialized */ return jtag ? jtag->speed(speed) : ERROR_OK; } int jtag_config_khz(unsigned khz) { LOG_DEBUG("handle jtag khz"); clock_mode = CLOCK_MODE_KHZ; int speed = 0; int retval = adapter_khz_to_speed(khz, &speed); return (ERROR_OK != retval) ? retval : jtag_set_speed(speed); } int jtag_config_rclk(unsigned fallback_speed_khz) { LOG_DEBUG("handle jtag rclk"); clock_mode = CLOCK_MODE_RCLK; rclk_fallback_speed_khz = fallback_speed_khz; int speed = 0; int retval = jtag_rclk_to_speed(fallback_speed_khz, &speed); return (ERROR_OK != retval) ? retval : jtag_set_speed(speed); } int jtag_get_speed(int *speed) { switch (clock_mode) { case CLOCK_MODE_KHZ: adapter_khz_to_speed(jtag_get_speed_khz(), speed); break; case CLOCK_MODE_RCLK: jtag_rclk_to_speed(rclk_fallback_speed_khz, speed); break; default: LOG_ERROR("BUG: unknown jtag clock mode"); return ERROR_FAIL; } return ERROR_OK; } int jtag_get_speed_readable(int *khz) { int jtag_speed_var = 0; int retval = jtag_get_speed(&jtag_speed_var); if (retval != ERROR_OK) return retval; return jtag ? jtag->speed_div(jtag_speed_var, khz) : ERROR_OK; } void jtag_set_verify(bool enable) { jtag_verify = enable; } bool jtag_will_verify() { return jtag_verify; } void jtag_set_verify_capture_ir(bool enable) { jtag_verify_capture_ir = enable; } bool jtag_will_verify_capture_ir() { return jtag_verify_capture_ir; } int jtag_power_dropout(int *dropout) { if (jtag == NULL) { /* TODO: as the jtag interface is not valid all * we can do at the moment is exit OpenOCD */ LOG_ERROR("No Valid JTAG Interface Configured."); exit(-1); } return jtag->power_dropout(dropout); } int jtag_srst_asserted(int *srst_asserted) { return jtag->srst_asserted(srst_asserted); } enum reset_types jtag_get_reset_config(void) { return jtag_reset_config; } void jtag_set_reset_config(enum reset_types type) { jtag_reset_config = type; } int jtag_get_trst(void) { return jtag_trst; } int jtag_get_srst(void) { return jtag_srst; } void jtag_set_nsrst_delay(unsigned delay) { adapter_nsrst_delay = delay; } unsigned jtag_get_nsrst_delay(void) { return adapter_nsrst_delay; } void jtag_set_ntrst_delay(unsigned delay) { jtag_ntrst_delay = delay; } unsigned jtag_get_ntrst_delay(void) { return jtag_ntrst_delay; } void jtag_set_nsrst_assert_width(unsigned delay) { adapter_nsrst_assert_width = delay; } unsigned jtag_get_nsrst_assert_width(void) { return adapter_nsrst_assert_width; } void jtag_set_ntrst_assert_width(unsigned delay) { jtag_ntrst_assert_width = delay; } unsigned jtag_get_ntrst_assert_width(void) { return jtag_ntrst_assert_width; } static int jtag_select(struct command_context *ctx) { int retval; /* NOTE: interface init must already have been done. * That works with only C code ... no Tcl glue required. */ retval = jtag_register_commands(ctx); if (retval != ERROR_OK) return retval; retval = svf_register_commands(ctx); if (retval != ERROR_OK) return retval; return xsvf_register_commands(ctx); } static struct transport jtag_transport = { .name = "jtag", .select = jtag_select, .init = jtag_init, }; static void jtag_constructor(void) __attribute__((constructor)); static void jtag_constructor(void) { transport_register(&jtag_transport); } /** Returns true if the current debug session * is using JTAG as its transport. */ bool transport_is_jtag(void) { return get_current_transport() == &jtag_transport; } void adapter_assert_reset(void) { if (transport_is_jtag()) { if (jtag_reset_config & RESET_SRST_PULLS_TRST) jtag_add_reset(1, 1); else jtag_add_reset(0, 1); } else if (transport_is_swd()) swd_add_reset(1); else if (get_current_transport() != NULL) LOG_ERROR("reset is not supported on %s", get_current_transport()->name); else LOG_ERROR("transport is not selected"); } void adapter_deassert_reset(void) { if (transport_is_jtag()) jtag_add_reset(0, 0); else if (transport_is_swd()) swd_add_reset(0); else if (get_current_transport() != NULL) LOG_ERROR("reset is not supported on %s", get_current_transport()->name); else LOG_ERROR("transport is not selected"); } openocd-0.7.0/src/jtag/tcl.c0000644000175000001440000010656612134336410012537 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2009 SoftPLC Corporation * * http://softplc.com * * dick@softplc.com * * * * Copyright (C) 2009 Zachary T Welch * * zw@superlucidity.net * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "jtag.h" #include "swd.h" #include "minidriver.h" #include "interface.h" #include "interfaces.h" #include "tcl.h" #ifdef HAVE_STRINGS_H #include #endif #include /** * @file * Holds support for accessing JTAG-specific mechanisms from TCl scripts. */ static const Jim_Nvp nvp_jtag_tap_event[] = { { .value = JTAG_TRST_ASSERTED, .name = "post-reset" }, { .value = JTAG_TAP_EVENT_SETUP, .name = "setup" }, { .value = JTAG_TAP_EVENT_ENABLE, .name = "tap-enable" }, { .value = JTAG_TAP_EVENT_DISABLE, .name = "tap-disable" }, { .name = NULL, .value = -1 } }; extern struct jtag_interface *jtag_interface; struct jtag_tap *jtag_tap_by_jim_obj(Jim_Interp *interp, Jim_Obj *o) { const char *cp = Jim_GetString(o, NULL); struct jtag_tap *t = cp ? jtag_tap_by_string(cp) : NULL; if (NULL == cp) cp = "(unknown)"; if (NULL == t) Jim_SetResultFormatted(interp, "Tap '%s' could not be found", cp); return t; } static bool scan_is_safe(tap_state_t state) { switch (state) { case TAP_RESET: case TAP_IDLE: case TAP_DRPAUSE: case TAP_IRPAUSE: return true; default: return false; } } static int Jim_Command_drscan(Jim_Interp *interp, int argc, Jim_Obj *const *args) { int retval; struct scan_field *fields; int num_fields; int field_count = 0; int i, e; struct jtag_tap *tap; tap_state_t endstate; /* args[1] = device * args[2] = num_bits * args[3] = hex string * ... repeat num bits and hex string ... * * .. optionally: * args[N-2] = "-endstate" * args[N-1] = statename */ if ((argc < 4) || ((argc % 2) != 0)) { Jim_WrongNumArgs(interp, 1, args, "wrong arguments"); return JIM_ERR; } endstate = TAP_IDLE; script_debug(interp, "drscan", argc, args); /* validate arguments as numbers */ e = JIM_OK; for (i = 2; i < argc; i += 2) { long bits; const char *cp; e = Jim_GetLong(interp, args[i], &bits); /* If valid - try next arg */ if (e == JIM_OK) continue; /* Not valid.. are we at the end? */ if (((i + 2) != argc)) { /* nope, then error */ return e; } /* it could be: "-endstate FOO" * e.g. DRPAUSE so we can issue more instructions * before entering RUN/IDLE and executing them. */ /* get arg as a string. */ cp = Jim_GetString(args[i], NULL); /* is it the magic? */ if (0 == strcmp("-endstate", cp)) { /* is the statename valid? */ cp = Jim_GetString(args[i + 1], NULL); /* see if it is a valid state name */ endstate = tap_state_by_name(cp); if (endstate < 0) { /* update the error message */ Jim_SetResultFormatted(interp, "endstate: %s invalid", cp); } else { if (!scan_is_safe(endstate)) LOG_WARNING("drscan with unsafe " "endstate \"%s\"", cp); /* valid - so clear the error */ e = JIM_OK; /* and remove the last 2 args */ argc -= 2; } } /* Still an error? */ if (e != JIM_OK) return e; /* too bad */ } /* validate args */ assert(e == JIM_OK); tap = jtag_tap_by_jim_obj(interp, args[1]); if (tap == NULL) return JIM_ERR; num_fields = (argc-2)/2; assert(num_fields > 0); fields = malloc(sizeof(struct scan_field) * num_fields); for (i = 2; i < argc; i += 2) { long bits; int len; const char *str; Jim_GetLong(interp, args[i], &bits); str = Jim_GetString(args[i + 1], &len); fields[field_count].num_bits = bits; void *t = malloc(DIV_ROUND_UP(bits, 8)); fields[field_count].out_value = t; str_to_buf(str, len, t, bits, 0); fields[field_count].in_value = t; field_count++; } jtag_add_dr_scan(tap, num_fields, fields, endstate); retval = jtag_execute_queue(); if (retval != ERROR_OK) { Jim_SetResultString(interp, "drscan: jtag execute failed", -1); return JIM_ERR; } field_count = 0; Jim_Obj *list = Jim_NewListObj(interp, NULL, 0); for (i = 2; i < argc; i += 2) { long bits; char *str; Jim_GetLong(interp, args[i], &bits); str = buf_to_str(fields[field_count].in_value, bits, 16); free((void *)fields[field_count].out_value); Jim_ListAppendElement(interp, list, Jim_NewStringObj(interp, str, strlen(str))); free(str); field_count++; } Jim_SetResult(interp, list); free(fields); return JIM_OK; } static int Jim_Command_pathmove(Jim_Interp *interp, int argc, Jim_Obj *const *args) { tap_state_t states[8]; if ((argc < 2) || ((size_t)argc > (ARRAY_SIZE(states) + 1))) { Jim_WrongNumArgs(interp, 1, args, "wrong arguments"); return JIM_ERR; } script_debug(interp, "pathmove", argc, args); int i; for (i = 0; i < argc-1; i++) { const char *cp; cp = Jim_GetString(args[i + 1], NULL); states[i] = tap_state_by_name(cp); if (states[i] < 0) { /* update the error message */ Jim_SetResultFormatted(interp, "endstate: %s invalid", cp); return JIM_ERR; } } if ((jtag_add_statemove(states[0]) != ERROR_OK) || (jtag_execute_queue() != ERROR_OK)) { Jim_SetResultString(interp, "pathmove: jtag execute failed", -1); return JIM_ERR; } jtag_add_pathmove(argc - 2, states + 1); if (jtag_execute_queue() != ERROR_OK) { Jim_SetResultString(interp, "pathmove: failed", -1); return JIM_ERR; } return JIM_OK; } static int Jim_Command_flush_count(Jim_Interp *interp, int argc, Jim_Obj *const *args) { script_debug(interp, "flush_count", argc, args); Jim_SetResult(interp, Jim_NewIntObj(interp, jtag_get_flush_queue_count())); return JIM_OK; } /* REVISIT Just what about these should "move" ... ? * These registrations, into the main JTAG table? * * There's a minor compatibility issue, these all show up twice; * that's not desirable: * - jtag drscan ... NOT DOCUMENTED! * - drscan ... * * The "irscan" command (for example) doesn't show twice. */ static const struct command_registration jtag_command_handlers_to_move[] = { { .name = "drscan", .mode = COMMAND_EXEC, .jim_handler = Jim_Command_drscan, .help = "Execute Data Register (DR) scan for one TAP. " "Other TAPs must be in BYPASS mode.", .usage = "tap_name [num_bits value]* ['-endstate' state_name]", }, { .name = "flush_count", .mode = COMMAND_EXEC, .jim_handler = Jim_Command_flush_count, .help = "Returns the number of times the JTAG queue " "has been flushed.", }, { .name = "pathmove", .mode = COMMAND_EXEC, .jim_handler = Jim_Command_pathmove, .usage = "start_state state1 [state2 [state3 ...]]", .help = "Move JTAG state machine from current state " "(start_state) to state1, then state2, state3, etc.", }, COMMAND_REGISTRATION_DONE }; enum jtag_tap_cfg_param { JCFG_EVENT }; static Jim_Nvp nvp_config_opts[] = { { .name = "-event", .value = JCFG_EVENT }, { .name = NULL, .value = -1 } }; static int jtag_tap_configure_event(Jim_GetOptInfo *goi, struct jtag_tap *tap) { if (goi->argc == 0) { Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ..."); return JIM_ERR; } Jim_Nvp *n; int e = Jim_GetOpt_Nvp(goi, nvp_jtag_tap_event, &n); if (e != JIM_OK) { Jim_GetOpt_NvpUnknown(goi, nvp_jtag_tap_event, 1); return e; } if (goi->isconfigure) { if (goi->argc != 1) { Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event "); return JIM_ERR; } } else { if (goi->argc != 0) { Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event "); return JIM_ERR; } } struct jtag_tap_event_action *jteap = tap->event_action; /* replace existing event body */ bool found = false; while (jteap) { if (jteap->event == (enum jtag_event)n->value) { found = true; break; } jteap = jteap->next; } Jim_SetEmptyResult(goi->interp); if (goi->isconfigure) { if (!found) jteap = calloc(1, sizeof(*jteap)); else if (NULL != jteap->body) Jim_DecrRefCount(goi->interp, jteap->body); jteap->interp = goi->interp; jteap->event = n->value; Jim_Obj *o; Jim_GetOpt_Obj(goi, &o); jteap->body = Jim_DuplicateObj(goi->interp, o); Jim_IncrRefCount(jteap->body); if (!found) { /* add to head of event list */ jteap->next = tap->event_action; tap->event_action = jteap; } } else if (found) { jteap->interp = goi->interp; Jim_SetResult(goi->interp, Jim_DuplicateObj(goi->interp, jteap->body)); } return JIM_OK; } static int jtag_tap_configure_cmd(Jim_GetOptInfo *goi, struct jtag_tap *tap) { /* parse config or cget options */ while (goi->argc > 0) { Jim_SetEmptyResult(goi->interp); Jim_Nvp *n; int e = Jim_GetOpt_Nvp(goi, nvp_config_opts, &n); if (e != JIM_OK) { Jim_GetOpt_NvpUnknown(goi, nvp_config_opts, 0); return e; } switch (n->value) { case JCFG_EVENT: e = jtag_tap_configure_event(goi, tap); if (e != JIM_OK) return e; break; default: Jim_SetResultFormatted(goi->interp, "unknown event: %s", n->name); return JIM_ERR; } } return JIM_OK; } static int is_bad_irval(int ir_length, jim_wide w) { jim_wide v = 1; v <<= ir_length; v -= 1; v = ~v; return (w & v) != 0; } static int jim_newtap_expected_id(Jim_Nvp *n, Jim_GetOptInfo *goi, struct jtag_tap *pTap) { jim_wide w; int e = Jim_GetOpt_Wide(goi, &w); if (e != JIM_OK) { Jim_SetResultFormatted(goi->interp, "option: %s bad parameter", n->name); return e; } unsigned expected_len = sizeof(uint32_t) * pTap->expected_ids_cnt; uint32_t *new_expected_ids = malloc(expected_len + sizeof(uint32_t)); if (new_expected_ids == NULL) { Jim_SetResultFormatted(goi->interp, "no memory"); return JIM_ERR; } memcpy(new_expected_ids, pTap->expected_ids, expected_len); new_expected_ids[pTap->expected_ids_cnt] = w; free(pTap->expected_ids); pTap->expected_ids = new_expected_ids; pTap->expected_ids_cnt++; return JIM_OK; } #define NTAP_OPT_IRLEN 0 #define NTAP_OPT_IRMASK 1 #define NTAP_OPT_IRCAPTURE 2 #define NTAP_OPT_ENABLED 3 #define NTAP_OPT_DISABLED 4 #define NTAP_OPT_EXPECTED_ID 5 #define NTAP_OPT_VERSION 6 static int jim_newtap_ir_param(Jim_Nvp *n, Jim_GetOptInfo *goi, struct jtag_tap *pTap) { jim_wide w; int e = Jim_GetOpt_Wide(goi, &w); if (e != JIM_OK) { Jim_SetResultFormatted(goi->interp, "option: %s bad parameter", n->name); free((void *)pTap->dotted_name); return e; } switch (n->value) { case NTAP_OPT_IRLEN: if (w > (jim_wide) (8 * sizeof(pTap->ir_capture_value))) { LOG_WARNING("%s: huge IR length %d", pTap->dotted_name, (int) w); } pTap->ir_length = w; break; case NTAP_OPT_IRMASK: if (is_bad_irval(pTap->ir_length, w)) { LOG_ERROR("%s: IR mask %x too big", pTap->dotted_name, (int) w); return JIM_ERR; } if ((w & 3) != 3) LOG_WARNING("%s: nonstandard IR mask", pTap->dotted_name); pTap->ir_capture_mask = w; break; case NTAP_OPT_IRCAPTURE: if (is_bad_irval(pTap->ir_length, w)) { LOG_ERROR("%s: IR capture %x too big", pTap->dotted_name, (int) w); return JIM_ERR; } if ((w & 3) != 1) LOG_WARNING("%s: nonstandard IR value", pTap->dotted_name); pTap->ir_capture_value = w; break; default: return JIM_ERR; } return JIM_OK; } static int jim_newtap_cmd(Jim_GetOptInfo *goi) { struct jtag_tap *pTap; int x; int e; Jim_Nvp *n; char *cp; const Jim_Nvp opts[] = { { .name = "-irlen", .value = NTAP_OPT_IRLEN }, { .name = "-irmask", .value = NTAP_OPT_IRMASK }, { .name = "-ircapture", .value = NTAP_OPT_IRCAPTURE }, { .name = "-enable", .value = NTAP_OPT_ENABLED }, { .name = "-disable", .value = NTAP_OPT_DISABLED }, { .name = "-expected-id", .value = NTAP_OPT_EXPECTED_ID }, { .name = "-ignore-version", .value = NTAP_OPT_VERSION }, { .name = NULL, .value = -1 }, }; pTap = calloc(1, sizeof(struct jtag_tap)); if (!pTap) { Jim_SetResultFormatted(goi->interp, "no memory"); return JIM_ERR; } /* * we expect CHIP + TAP + OPTIONS * */ if (goi->argc < 3) { Jim_SetResultFormatted(goi->interp, "Missing CHIP TAP OPTIONS ...."); free(pTap); return JIM_ERR; } Jim_GetOpt_String(goi, &cp, NULL); pTap->chip = strdup(cp); Jim_GetOpt_String(goi, &cp, NULL); pTap->tapname = strdup(cp); /* name + dot + name + null */ x = strlen(pTap->chip) + 1 + strlen(pTap->tapname) + 1; cp = malloc(x); sprintf(cp, "%s.%s", pTap->chip, pTap->tapname); pTap->dotted_name = cp; LOG_DEBUG("Creating New Tap, Chip: %s, Tap: %s, Dotted: %s, %d params", pTap->chip, pTap->tapname, pTap->dotted_name, goi->argc); /* IEEE specifies that the two LSBs of an IR scan are 01, so make * that the default. The "-irlen" and "-irmask" options are only * needed to cope with nonstandard TAPs, or to specify more bits. */ pTap->ir_capture_mask = 0x03; pTap->ir_capture_value = 0x01; while (goi->argc) { e = Jim_GetOpt_Nvp(goi, opts, &n); if (e != JIM_OK) { Jim_GetOpt_NvpUnknown(goi, opts, 0); free((void *)pTap->dotted_name); free(pTap); return e; } LOG_DEBUG("Processing option: %s", n->name); switch (n->value) { case NTAP_OPT_ENABLED: pTap->disabled_after_reset = false; break; case NTAP_OPT_DISABLED: pTap->disabled_after_reset = true; break; case NTAP_OPT_EXPECTED_ID: e = jim_newtap_expected_id(n, goi, pTap); if (JIM_OK != e) { free((void *)pTap->dotted_name); free(pTap); return e; } break; case NTAP_OPT_IRLEN: case NTAP_OPT_IRMASK: case NTAP_OPT_IRCAPTURE: e = jim_newtap_ir_param(n, goi, pTap); if (JIM_OK != e) { free((void *)pTap->dotted_name); free(pTap); return e; } break; case NTAP_OPT_VERSION: pTap->ignore_version = true; break; } /* switch (n->value) */ } /* while (goi->argc) */ /* default is enabled-after-reset */ pTap->enabled = !pTap->disabled_after_reset; /* Did all the required option bits get cleared? */ if (pTap->ir_length != 0) { jtag_tap_init(pTap); return JIM_OK; } Jim_SetResultFormatted(goi->interp, "newtap: %s missing IR length", pTap->dotted_name); jtag_tap_free(pTap); return JIM_ERR; } static void jtag_tap_handle_event(struct jtag_tap *tap, enum jtag_event e) { struct jtag_tap_event_action *jteap; for (jteap = tap->event_action; jteap != NULL; jteap = jteap->next) { if (jteap->event != e) continue; Jim_Nvp *nvp = Jim_Nvp_value2name_simple(nvp_jtag_tap_event, e); LOG_DEBUG("JTAG tap: %s event: %d (%s)\n\taction: %s", tap->dotted_name, e, nvp->name, Jim_GetString(jteap->body, NULL)); if (Jim_EvalObj(jteap->interp, jteap->body) != JIM_OK) { Jim_MakeErrorMessage(jteap->interp); LOG_USER("%s", Jim_GetString(Jim_GetResult(jteap->interp), NULL)); continue; } switch (e) { case JTAG_TAP_EVENT_ENABLE: case JTAG_TAP_EVENT_DISABLE: /* NOTE: we currently assume the handlers * can't fail. Right here is where we should * really be verifying the scan chains ... */ tap->enabled = (e == JTAG_TAP_EVENT_ENABLE); LOG_INFO("JTAG tap: %s %s", tap->dotted_name, tap->enabled ? "enabled" : "disabled"); break; default: break; } } } static int jim_jtag_arp_init(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_GetOptInfo goi; Jim_GetOpt_Setup(&goi, interp, argc-1, argv + 1); if (goi.argc != 0) { Jim_WrongNumArgs(goi.interp, 1, goi.argv-1, "(no params)"); return JIM_ERR; } struct command_context *context = current_command_context(interp); int e = jtag_init_inner(context); if (e != ERROR_OK) { Jim_Obj *eObj = Jim_NewIntObj(goi.interp, e); Jim_SetResultFormatted(goi.interp, "error: %#s", eObj); Jim_FreeNewObj(goi.interp, eObj); return JIM_ERR; } return JIM_OK; } static int jim_jtag_arp_init_reset(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int e = ERROR_OK; Jim_GetOptInfo goi; Jim_GetOpt_Setup(&goi, interp, argc-1, argv + 1); if (goi.argc != 0) { Jim_WrongNumArgs(goi.interp, 1, goi.argv-1, "(no params)"); return JIM_ERR; } struct command_context *context = current_command_context(interp); if (transport_is_jtag()) e = jtag_init_reset(context); else if (transport_is_swd()) e = swd_init_reset(context); if (e != ERROR_OK) { Jim_Obj *eObj = Jim_NewIntObj(goi.interp, e); Jim_SetResultFormatted(goi.interp, "error: %#s", eObj); Jim_FreeNewObj(goi.interp, eObj); return JIM_ERR; } return JIM_OK; } int jim_jtag_newtap(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_GetOptInfo goi; Jim_GetOpt_Setup(&goi, interp, argc-1, argv + 1); return jim_newtap_cmd(&goi); } static bool jtag_tap_enable(struct jtag_tap *t) { if (t->enabled) return false; jtag_tap_handle_event(t, JTAG_TAP_EVENT_ENABLE); if (!t->enabled) return false; /* FIXME add JTAG sanity checks, w/o TLR * - scan chain length grew by one (this) * - IDs and IR lengths are as expected */ jtag_call_event_callbacks(JTAG_TAP_EVENT_ENABLE); return true; } static bool jtag_tap_disable(struct jtag_tap *t) { if (!t->enabled) return false; jtag_tap_handle_event(t, JTAG_TAP_EVENT_DISABLE); if (t->enabled) return false; /* FIXME add JTAG sanity checks, w/o TLR * - scan chain length shrank by one (this) * - IDs and IR lengths are as expected */ jtag_call_event_callbacks(JTAG_TAP_EVENT_DISABLE); return true; } int jim_jtag_tap_enabler(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { const char *cmd_name = Jim_GetString(argv[0], NULL); Jim_GetOptInfo goi; Jim_GetOpt_Setup(&goi, interp, argc-1, argv + 1); if (goi.argc != 1) { Jim_SetResultFormatted(goi.interp, "usage: %s ", cmd_name); return JIM_ERR; } struct jtag_tap *t; t = jtag_tap_by_jim_obj(goi.interp, goi.argv[0]); if (t == NULL) return JIM_ERR; if (strcasecmp(cmd_name, "tapisenabled") == 0) { /* do nothing, just return the value */ } else if (strcasecmp(cmd_name, "tapenable") == 0) { if (!jtag_tap_enable(t)) { LOG_WARNING("failed to enable tap %s", t->dotted_name); return JIM_ERR; } } else if (strcasecmp(cmd_name, "tapdisable") == 0) { if (!jtag_tap_disable(t)) { LOG_WARNING("failed to disable tap %s", t->dotted_name); return JIM_ERR; } } else { LOG_ERROR("command '%s' unknown", cmd_name); return JIM_ERR; } bool e = t->enabled; Jim_SetResult(goi.interp, Jim_NewIntObj(goi.interp, e)); return JIM_OK; } int jim_jtag_configure(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { const char *cmd_name = Jim_GetString(argv[0], NULL); Jim_GetOptInfo goi; Jim_GetOpt_Setup(&goi, interp, argc-1, argv + 1); goi.isconfigure = !strcmp(cmd_name, "configure"); if (goi.argc < 2 + goi.isconfigure) { Jim_WrongNumArgs(goi.interp, 0, NULL, " ..."); return JIM_ERR; } struct jtag_tap *t; Jim_Obj *o; Jim_GetOpt_Obj(&goi, &o); t = jtag_tap_by_jim_obj(goi.interp, o); if (t == NULL) return JIM_ERR; return jtag_tap_configure_cmd(&goi, t); } static int jim_jtag_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_GetOptInfo goi; Jim_GetOpt_Setup(&goi, interp, argc-1, argv + 1); if (goi.argc != 0) { Jim_WrongNumArgs(goi.interp, 1, goi.argv, "Too many parameters"); return JIM_ERR; } Jim_SetResult(goi.interp, Jim_NewListObj(goi.interp, NULL, 0)); struct jtag_tap *tap; for (tap = jtag_all_taps(); tap; tap = tap->next_tap) { Jim_ListAppendElement(goi.interp, Jim_GetResult(goi.interp), Jim_NewStringObj(goi.interp, tap->dotted_name, -1)); } return JIM_OK; } COMMAND_HANDLER(handle_jtag_init_command) { if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; static bool jtag_initialized; if (jtag_initialized) { LOG_INFO("'jtag init' has already been called"); return ERROR_OK; } jtag_initialized = true; LOG_DEBUG("Initializing jtag devices..."); return jtag_init(CMD_CTX); } static const struct command_registration jtag_subcommand_handlers[] = { { .name = "init", .mode = COMMAND_ANY, .handler = handle_jtag_init_command, .help = "initialize jtag scan chain", .usage = "" }, { .name = "arp_init", .mode = COMMAND_ANY, .jim_handler = jim_jtag_arp_init, .help = "Validates JTAG scan chain against the list of " "declared TAPs using just the four standard JTAG " "signals.", }, { .name = "arp_init-reset", .mode = COMMAND_ANY, .jim_handler = jim_jtag_arp_init_reset, .help = "Uses TRST and SRST to try resetting everything on " "the JTAG scan chain, then performs 'jtag arp_init'." }, { .name = "newtap", .mode = COMMAND_CONFIG, .jim_handler = jim_jtag_newtap, .help = "Create a new TAP instance named basename.tap_type, " "and appends it to the scan chain.", .usage = "basename tap_type '-irlen' count " "['-enable'|'-disable'] " "['-expected_id' number] " "['-ignore-version'] " "['-ircapture' number] " "['-mask' number] ", }, { .name = "tapisenabled", .mode = COMMAND_EXEC, .jim_handler = jim_jtag_tap_enabler, .help = "Returns a Tcl boolean (0/1) indicating whether " "the TAP is enabled (1) or not (0).", .usage = "tap_name", }, { .name = "tapenable", .mode = COMMAND_EXEC, .jim_handler = jim_jtag_tap_enabler, .help = "Try to enable the specified TAP using the " "'tap-enable' TAP event.", .usage = "tap_name", }, { .name = "tapdisable", .mode = COMMAND_EXEC, .jim_handler = jim_jtag_tap_enabler, .help = "Try to disable the specified TAP using the " "'tap-disable' TAP event.", .usage = "tap_name", }, { .name = "configure", .mode = COMMAND_EXEC, .jim_handler = jim_jtag_configure, .help = "Provide a Tcl handler for the specified " "TAP event.", .usage = "tap_name '-event' event_name handler", }, { .name = "cget", .mode = COMMAND_EXEC, .jim_handler = jim_jtag_configure, .help = "Return any Tcl handler for the specified " "TAP event.", .usage = "tap_name '-event' event_name", }, { .name = "names", .mode = COMMAND_ANY, .jim_handler = jim_jtag_names, .help = "Returns list of all JTAG tap names.", }, { .chain = jtag_command_handlers_to_move, }, COMMAND_REGISTRATION_DONE }; void jtag_notify_event(enum jtag_event event) { struct jtag_tap *tap; for (tap = jtag_all_taps(); tap; tap = tap->next_tap) jtag_tap_handle_event(tap, event); } COMMAND_HANDLER(handle_scan_chain_command) { struct jtag_tap *tap; char expected_id[12]; tap = jtag_all_taps(); command_print(CMD_CTX, " TapName Enabled IdCode Expected IrLen IrCap IrMask"); command_print(CMD_CTX, "-- ------------------- -------- ---------- ---------- ----- ----- ------"); while (tap) { uint32_t expected, expected_mask, ii; snprintf(expected_id, sizeof expected_id, "0x%08x", (unsigned)((tap->expected_ids_cnt > 0) ? tap->expected_ids[0] : 0)); if (tap->ignore_version) expected_id[2] = '*'; expected = buf_get_u32(tap->expected, 0, tap->ir_length); expected_mask = buf_get_u32(tap->expected_mask, 0, tap->ir_length); command_print(CMD_CTX, "%2d %-18s %c 0x%08x %s %5d 0x%02x 0x%02x", tap->abs_chain_position, tap->dotted_name, tap->enabled ? 'Y' : 'n', (unsigned int)(tap->idcode), expected_id, (unsigned int)(tap->ir_length), (unsigned int)(expected), (unsigned int)(expected_mask)); for (ii = 1; ii < tap->expected_ids_cnt; ii++) { snprintf(expected_id, sizeof expected_id, "0x%08x", (unsigned) tap->expected_ids[ii]); if (tap->ignore_version) expected_id[2] = '*'; command_print(CMD_CTX, " %s", expected_id); } tap = tap->next_tap; } return ERROR_OK; } COMMAND_HANDLER(handle_jtag_ntrst_delay_command) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC == 1) { unsigned delay; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], delay); jtag_set_ntrst_delay(delay); } command_print(CMD_CTX, "jtag_ntrst_delay: %u", jtag_get_ntrst_delay()); return ERROR_OK; } COMMAND_HANDLER(handle_jtag_ntrst_assert_width_command) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC == 1) { unsigned delay; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], delay); jtag_set_ntrst_assert_width(delay); } command_print(CMD_CTX, "jtag_ntrst_assert_width: %u", jtag_get_ntrst_assert_width()); return ERROR_OK; } COMMAND_HANDLER(handle_jtag_rclk_command) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; int retval = ERROR_OK; if (CMD_ARGC == 1) { unsigned khz = 0; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], khz); retval = jtag_config_rclk(khz); if (ERROR_OK != retval) return retval; } int cur_khz = jtag_get_speed_khz(); retval = jtag_get_speed_readable(&cur_khz); if (ERROR_OK != retval) return retval; if (cur_khz) command_print(CMD_CTX, "RCLK not supported - fallback to %d kHz", cur_khz); else command_print(CMD_CTX, "RCLK - adaptive"); return retval; } COMMAND_HANDLER(handle_jtag_reset_command) { if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; int trst = -1; if (CMD_ARGV[0][0] == '1') trst = 1; else if (CMD_ARGV[0][0] == '0') trst = 0; else return ERROR_COMMAND_SYNTAX_ERROR; int srst = -1; if (CMD_ARGV[1][0] == '1') srst = 1; else if (CMD_ARGV[1][0] == '0') srst = 0; else return ERROR_COMMAND_SYNTAX_ERROR; if (adapter_init(CMD_CTX) != ERROR_OK) return ERROR_JTAG_INIT_FAILED; jtag_add_reset(trst, srst); return jtag_execute_queue(); } COMMAND_HANDLER(handle_runtest_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; unsigned num_clocks; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num_clocks); jtag_add_runtest(num_clocks, TAP_IDLE); return jtag_execute_queue(); } /* * For "irscan" or "drscan" commands, the "end" (really, "next") state * should be stable ... and *NOT* a shift state, otherwise free-running * jtag clocks could change the values latched by the update state. * Not surprisingly, this is the same constraint as SVF; the "irscan" * and "drscan" commands are a write-only subset of what SVF provides. */ COMMAND_HANDLER(handle_irscan_command) { int i; struct scan_field *fields; struct jtag_tap *tap = NULL; tap_state_t endstate; if ((CMD_ARGC < 2) || (CMD_ARGC % 2)) return ERROR_COMMAND_SYNTAX_ERROR; /* optional "-endstate" "statename" at the end of the arguments, * so that e.g. IRPAUSE can let us load the data register before * entering RUN/IDLE to execute the instruction we load here. */ endstate = TAP_IDLE; if (CMD_ARGC >= 4) { /* have at least one pair of numbers. * is last pair the magic text? */ if (strcmp("-endstate", CMD_ARGV[CMD_ARGC - 2]) == 0) { endstate = tap_state_by_name(CMD_ARGV[CMD_ARGC - 1]); if (endstate == TAP_INVALID) return ERROR_COMMAND_SYNTAX_ERROR; if (!scan_is_safe(endstate)) LOG_WARNING("unstable irscan endstate \"%s\"", CMD_ARGV[CMD_ARGC - 1]); CMD_ARGC -= 2; } } int num_fields = CMD_ARGC / 2; if (num_fields > 1) { /* we really should be looking at plain_ir_scan if we want * anything more fancy. */ LOG_ERROR("Specify a single value for tap"); return ERROR_COMMAND_SYNTAX_ERROR; } size_t fields_len = sizeof(struct scan_field) * num_fields; fields = malloc(fields_len); memset(fields, 0, fields_len); int retval; for (i = 0; i < num_fields; i++) { tap = jtag_tap_by_string(CMD_ARGV[i*2]); if (tap == NULL) { int j; for (j = 0; j < i; j++) free((void *)fields[j].out_value); free(fields); command_print(CMD_CTX, "Tap: %s unknown", CMD_ARGV[i*2]); return ERROR_FAIL; } int field_size = tap->ir_length; fields[i].num_bits = field_size; fields[i].out_value = malloc(DIV_ROUND_UP(field_size, 8)); uint32_t value; retval = parse_u32(CMD_ARGV[i * 2 + 1], &value); if (ERROR_OK != retval) goto error_return; void *v = (void *)fields[i].out_value; buf_set_u32(v, 0, field_size, value); fields[i].in_value = NULL; } /* did we have an endstate? */ jtag_add_ir_scan(tap, fields, endstate); retval = jtag_execute_queue(); error_return: for (i = 0; i < num_fields; i++) { if (NULL != fields[i].out_value) free((void *)fields[i].out_value); } free(fields); return retval; } COMMAND_HANDLER(handle_verify_ircapture_command) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC == 1) { bool enable; COMMAND_PARSE_ENABLE(CMD_ARGV[0], enable); jtag_set_verify_capture_ir(enable); } const char *status = jtag_will_verify_capture_ir() ? "enabled" : "disabled"; command_print(CMD_CTX, "verify Capture-IR is %s", status); return ERROR_OK; } COMMAND_HANDLER(handle_verify_jtag_command) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC == 1) { bool enable; COMMAND_PARSE_ENABLE(CMD_ARGV[0], enable); jtag_set_verify(enable); } const char *status = jtag_will_verify() ? "enabled" : "disabled"; command_print(CMD_CTX, "verify jtag capture is %s", status); return ERROR_OK; } COMMAND_HANDLER(handle_tms_sequence_command) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC == 1) { bool use_new_table; if (strcmp(CMD_ARGV[0], "short") == 0) use_new_table = true; else if (strcmp(CMD_ARGV[0], "long") == 0) use_new_table = false; else return ERROR_COMMAND_SYNTAX_ERROR; tap_use_new_tms_table(use_new_table); } command_print(CMD_CTX, "tms sequence is %s", tap_uses_new_tms_table() ? "short" : "long"); return ERROR_OK; } COMMAND_HANDLER(handle_jtag_flush_queue_sleep) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; int sleep_ms; COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], sleep_ms); jtag_set_flush_queue_sleep(sleep_ms); return ERROR_OK; } COMMAND_HANDLER(handle_wait_srst_deassert) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; int timeout_ms; COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], timeout_ms); if ((timeout_ms <= 0) || (timeout_ms > 100000)) { LOG_ERROR("Timeout must be an integer between 0 and 100000"); return ERROR_FAIL; } LOG_USER("Waiting for srst assert + deassert for at most %dms", timeout_ms); int asserted_yet; long long then = timeval_ms(); while (jtag_srst_asserted(&asserted_yet) == ERROR_OK) { if ((timeval_ms() - then) > timeout_ms) { LOG_ERROR("Timed out"); return ERROR_FAIL; } if (asserted_yet) break; } while (jtag_srst_asserted(&asserted_yet) == ERROR_OK) { if ((timeval_ms() - then) > timeout_ms) { LOG_ERROR("Timed out"); return ERROR_FAIL; } if (!asserted_yet) break; } return ERROR_OK; } static const struct command_registration jtag_command_handlers[] = { { .name = "jtag_flush_queue_sleep", .handler = handle_jtag_flush_queue_sleep, .mode = COMMAND_ANY, .help = "For debug purposes(simulate long delays of interface) " "to test performance or change in behavior. Default 0ms.", .usage = "[sleep in ms]", }, { .name = "jtag_rclk", .handler = handle_jtag_rclk_command, .mode = COMMAND_ANY, .help = "With an argument, change to to use adaptive clocking " "if possible; else to use the fallback speed. " "With or without argument, display current setting.", .usage = "[fallback_speed_khz]", }, { .name = "jtag_ntrst_delay", .handler = handle_jtag_ntrst_delay_command, .mode = COMMAND_ANY, .help = "delay after deasserting trst in ms", .usage = "[milliseconds]", }, { .name = "jtag_ntrst_assert_width", .handler = handle_jtag_ntrst_assert_width_command, .mode = COMMAND_ANY, .help = "delay after asserting trst in ms", .usage = "[milliseconds]", }, { .name = "scan_chain", .handler = handle_scan_chain_command, .mode = COMMAND_ANY, .help = "print current scan chain configuration", .usage = "" }, { .name = "jtag_reset", .handler = handle_jtag_reset_command, .mode = COMMAND_EXEC, .help = "Set reset line values. Value '1' is active, " "value '0' is inactive.", .usage = "trst_active srst_active", }, { .name = "runtest", .handler = handle_runtest_command, .mode = COMMAND_EXEC, .help = "Move to Run-Test/Idle, and issue TCK for num_cycles.", .usage = "num_cycles" }, { .name = "irscan", .handler = handle_irscan_command, .mode = COMMAND_EXEC, .help = "Execute Instruction Register (DR) scan. The " "specified opcodes are put into each TAP's IR, " "and other TAPs are put in BYPASS.", .usage = "[tap_name instruction]* ['-endstate' state_name]", }, { .name = "verify_ircapture", .handler = handle_verify_ircapture_command, .mode = COMMAND_ANY, .help = "Display or assign flag controlling whether to " "verify values captured during Capture-IR.", .usage = "['enable'|'disable']", }, { .name = "verify_jtag", .handler = handle_verify_jtag_command, .mode = COMMAND_ANY, .help = "Display or assign flag controlling whether to " "verify values captured during IR and DR scans.", .usage = "['enable'|'disable']", }, { .name = "tms_sequence", .handler = handle_tms_sequence_command, .mode = COMMAND_ANY, .help = "Display or change what style TMS sequences to use " "for JTAG state transitions: short (default) or " "long. Only for working around JTAG bugs.", /* Specifically for working around DRIVER bugs... */ .usage = "['short'|'long']", }, { .name = "wait_srst_deassert", .handler = handle_wait_srst_deassert, .mode = COMMAND_ANY, .help = "Wait for an SRST deassert. " "Useful for cases where you need something to happen within ms " "of an srst deassert. Timeout in ms ", .usage = "ms", }, { .name = "jtag", .mode = COMMAND_ANY, .help = "perform jtag tap actions", .usage = "", .chain = jtag_subcommand_handlers, }, { .chain = jtag_command_handlers_to_move, }, COMMAND_REGISTRATION_DONE }; int jtag_register_commands(struct command_context *cmd_ctx) { return register_commands(cmd_ctx, NULL, jtag_command_handlers); } openocd-0.7.0/src/jtag/hla/0000755000175000001440000000000012141414412012414 500000000000000openocd-0.7.0/src/jtag/hla/hla_interface.h0000644000175000001440000000453112137151331015277 00000000000000/*************************************************************************** * Copyright (C) 2011 by Mathias Kuester * * Mathias Kuester * * * * Copyright (C) 2012 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef _HL_INTERFACE #define _HL_INTERFACE /** */ struct target; /** */ enum e_hl_transports; /** */ extern const char *hl_transports[]; struct hl_interface_param_s { /** */ char *device_desc; /** */ char *serial; /** */ uint16_t vid; /** */ uint16_t pid; /** */ unsigned api; /** */ enum hl_transports transport; /** */ int max_buffer; /** */ bool connect_under_reset; }; struct hl_interface_s { /** */ struct hl_interface_param_s param; /** */ const struct hl_layout *layout; /** */ void *fd; }; /** */ int hl_interface_open(enum hl_transports tr); /** */ int hl_interface_init_target(struct target *t); int hl_interface_init_reset(void); #endif /* _HL_INTERFACE */ openocd-0.7.0/src/jtag/hla/hla_transport.c0000644000175000001440000001372512134336410015373 00000000000000/*************************************************************************** * Copyright (C) 2011 by Mathias Kuester * * Mathias Kuester * * * * Copyright (C) 2012 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* project specific includes */ #include #include #include #include #include #include #include #include COMMAND_HANDLER(hl_transport_jtag_command) { LOG_DEBUG("hl_transport_jtag_command"); return ERROR_OK; } COMMAND_HANDLER(hl_transport_reset_command) { return hl_interface_init_reset(); } static const struct command_registration hl_transport_stlink_subcommand_handlers[] = { { .name = "newtap", .mode = COMMAND_CONFIG, .jim_handler = jim_hl_newtap, .help = "Create a new TAP instance named basename.tap_type, " "and appends it to the scan chain.", .usage = "basename tap_type '-irlen' count " "['-expected_id' number] ", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration hl_transport_jtag_subcommand_handlers[] = { { .name = "init", .mode = COMMAND_ANY, .handler = hl_transport_jtag_command, .usage = "" }, { .name = "arp_init", .mode = COMMAND_ANY, .handler = hl_transport_jtag_command, .usage = "" }, { .name = "arp_init-reset", .mode = COMMAND_ANY, .handler = hl_transport_reset_command, .usage = "" }, { .name = "tapisenabled", .mode = COMMAND_EXEC, .jim_handler = jim_jtag_tap_enabler, }, { .name = "tapenable", .mode = COMMAND_EXEC, .jim_handler = jim_jtag_tap_enabler, }, { .name = "tapdisable", .mode = COMMAND_EXEC, .handler = hl_transport_jtag_command, .usage = "", }, { .name = "configure", .mode = COMMAND_EXEC, .handler = hl_transport_jtag_command, .usage = "", }, { .name = "cget", .mode = COMMAND_EXEC, .jim_handler = jim_jtag_configure, }, { .name = "names", .mode = COMMAND_ANY, .handler = hl_transport_jtag_command, .usage = "", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration stlink_transport_command_handlers[] = { { .name = "hla", .mode = COMMAND_ANY, .help = "perform hl adapter actions", .usage = "", .chain = hl_transport_stlink_subcommand_handlers, }, { .name = "jtag", .mode = COMMAND_ANY, .usage = "", .chain = hl_transport_jtag_subcommand_handlers, }, COMMAND_REGISTRATION_DONE }; static int hl_transport_register_commands(struct command_context *cmd_ctx) { return register_commands(cmd_ctx, NULL, stlink_transport_command_handlers); } static int hl_transport_init(struct command_context *cmd_ctx) { LOG_DEBUG("hl_transport_init"); struct target *t = get_current_target(cmd_ctx); struct transport *transport; enum hl_transports tr; if (!t) { LOG_ERROR("no current target"); return ERROR_FAIL; } transport = get_current_transport(); if (!transport) { LOG_ERROR("no transport selected"); return ERROR_FAIL; } LOG_DEBUG("current transport %s", transport->name); /* get selected transport as enum */ tr = HL_TRANSPORT_UNKNOWN; if (strcmp(transport->name, "hla_swd") == 0) tr = HL_TRANSPORT_SWD; else if (strcmp(transport->name, "hla_jtag") == 0) tr = HL_TRANSPORT_JTAG; else if (strcmp(transport->name, "stlink_swim") == 0) tr = HL_TRANSPORT_SWIM; int retval = hl_interface_open(tr); if (retval != ERROR_OK) return retval; return hl_interface_init_target(t); } static int hl_transport_select(struct command_context *ctx) { LOG_DEBUG("hl_transport_select"); int retval; /* NOTE: interface init must already have been done. * That works with only C code ... no Tcl glue required. */ retval = hl_transport_register_commands(ctx); if (retval != ERROR_OK) return retval; return ERROR_OK; } static struct transport hl_swd_transport = { .name = "hla_swd", .select = hl_transport_select, .init = hl_transport_init, }; static struct transport hl_jtag_transport = { .name = "hla_jtag", .select = hl_transport_select, .init = hl_transport_init, }; static struct transport stlink_swim_transport = { .name = "stlink_swim", .select = hl_transport_select, .init = hl_transport_init, }; const char *hl_transports[] = { "hla_swd", "hla_jtag", "stlink_swim", NULL }; static void hl_constructor(void) __attribute__ ((constructor)); static void hl_constructor(void) { transport_register(&hl_swd_transport); transport_register(&hl_jtag_transport); transport_register(&stlink_swim_transport); } openocd-0.7.0/src/jtag/hla/hla_layout.h0000644000175000001440000000635412134336410014661 00000000000000/*************************************************************************** * Copyright (C) 2011 by Mathias Kuester * * Mathias Kuester * * * * Copyright (C) 2012 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef _HL_LAYOUT_H #define _HL_LAYOUT_H /** */ struct hl_interface_s; struct hl_interface_param_s; /** */ extern struct hl_layout_api_s stlink_usb_layout_api; extern struct hl_layout_api_s icdi_usb_layout_api; /** */ struct hl_layout_api_s { /** */ int (*open) (struct hl_interface_param_s *param, void **fd); /** */ int (*close) (void *fd); /** */ int (*reset) (void *fd); /** */ int (*assert_srst) (void *fd, int srst); /** */ int (*run) (void *fd); /** */ int (*halt) (void *fd); /** */ int (*step) (void *fd); /** */ int (*read_regs) (void *fd); /** */ int (*read_reg) (void *fd, int num, uint32_t *val); /** */ int (*write_reg) (void *fd, int num, uint32_t val); /** */ int (*read_mem8) (void *handle, uint32_t addr, uint16_t len, uint8_t *buffer); /** */ int (*write_mem8) (void *handle, uint32_t addr, uint16_t len, const uint8_t *buffer); /** */ int (*read_mem32) (void *handle, uint32_t addr, uint16_t len, uint8_t *buffer); /** */ int (*write_mem32) (void *handle, uint32_t addr, uint16_t len, const uint8_t *buffer); /** */ int (*write_debug_reg) (void *handle, uint32_t addr, uint32_t val); /** */ int (*idcode) (void *fd, uint32_t *idcode); /** */ enum target_state (*state) (void *fd); }; /** */ struct hl_layout { /** */ char *name; /** */ int (*open) (struct hl_interface_s *adapter); /** */ int (*close) (struct hl_interface_s *adapter); /** */ struct hl_layout_api_s *api; }; /** */ const struct hl_layout *hl_layout_get_list(void); /** */ int hl_layout_init(struct hl_interface_s *adapter); #endif /* _HL_LAYOUT_H */ openocd-0.7.0/src/jtag/hla/hla_transport.h0000644000175000001440000000352612134336410015376 00000000000000/*************************************************************************** * Copyright (C) 2011 by Mathias Kuester * * Mathias Kuester * * * * Copyright (C) 2012 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef _HL_TRANSPORT #define _HL_TRANSPORT enum hl_transports { HL_TRANSPORT_UNKNOWN = 0, HL_TRANSPORT_SWD, HL_TRANSPORT_JTAG, HL_TRANSPORT_SWIM }; #endif /* _HL_TRANSPORT */ openocd-0.7.0/src/jtag/hla/Makefile.in0000644000175000001440000004224712141414276014422 00000000000000# Makefile.in generated by automake 1.13.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ DIST_COMMON = $(top_srcdir)/common.mk $(srcdir)/Makefile.in \ $(srcdir)/Makefile.am $(top_srcdir)/depcomp $(noinst_HEADERS) @INTERNAL_JIMTCL_TRUE@am__append_1 = -I$(top_srcdir)/jimtcl \ @INTERNAL_JIMTCL_TRUE@ -I$(top_builddir)/jimtcl @HLADAPTER_TRUE@am__append_2 = hla_transport.c hla_tcl.c \ @HLADAPTER_TRUE@ hla_interface.c hla_layout.c subdir = src/jtag/hla ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/config_subdir.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libocdhla_la_LIBADD = am__libocdhla_la_SOURCES_DIST = hla_transport.c hla_tcl.c \ hla_interface.c hla_layout.c @HLADAPTER_TRUE@am__objects_1 = hla_transport.lo hla_tcl.lo \ @HLADAPTER_TRUE@ hla_interface.lo hla_layout.lo am__objects_2 = $(am__objects_1) am_libocdhla_la_OBJECTS = $(am__objects_2) libocdhla_la_OBJECTS = $(am_libocdhla_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libocdhla_la_SOURCES) DIST_SOURCES = $(am__libocdhla_la_SOURCES_DIST) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CC_FOR_BUILD = @CC_FOR_BUILD@ CFLAGS = @CFLAGS@ CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@ FGREP = @FGREP@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ doxygen_as_html = @doxygen_as_html@ doxygen_as_pdf = @doxygen_as_pdf@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ # common flags used in openocd build AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src \ -I$(top_srcdir)/src/helper -DPKGDATADIR=\"$(pkgdatadir)\" \ -DPKGLIBDIR=\"$(pkglibdir)\" $(am__append_1) noinst_LTLIBRARIES = libocdhla.la libocdhla_la_SOURCES = \ $(HLFILES) HLFILES = $(am__append_2) noinst_HEADERS = \ hla_interface.h \ hla_layout.h \ hla_tcl.h \ hla_transport.h MAINTAINERCLEANFILES = $(srcdir)/Makefile.in all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/common.mk $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/jtag/hla/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/jtag/hla/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_srcdir)/common.mk: $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libocdhla.la: $(libocdhla_la_OBJECTS) $(libocdhla_la_DEPENDENCIES) $(EXTRA_libocdhla_la_DEPENDENCIES) $(AM_V_CCLD)$(LINK) $(libocdhla_la_OBJECTS) $(libocdhla_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hla_interface.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hla_layout.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hla_tcl.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hla_transport.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: openocd-0.7.0/src/jtag/hla/hla_layout.c0000644000175000001440000000604212134336410014646 00000000000000/*************************************************************************** * Copyright (C) 2011 by Mathias Kuester * * Mathias Kuester * * * * Copyright (C) 2012 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* project specific includes */ #include #include #include #include #include #include #include static int hl_layout_open(struct hl_interface_s *adapter) { int res; LOG_DEBUG("hl_layout_open"); adapter->fd = NULL; res = adapter->layout->api->open(&adapter->param, &adapter->fd); if (res != ERROR_OK) { LOG_DEBUG("failed"); return res; } /* make sure adapter has set the buffer size */ if (!adapter->param.max_buffer) { LOG_ERROR("buffer size not set"); return ERROR_FAIL; } return ERROR_OK; } static int hl_layout_close(struct hl_interface_s *adapter) { return ERROR_OK; } static const struct hl_layout hl_layouts[] = { { .name = "stlink", .open = hl_layout_open, .close = hl_layout_close, .api = &stlink_usb_layout_api, }, { .name = "ti-icdi", .open = hl_layout_open, .close = hl_layout_close, .api = &icdi_usb_layout_api, }, {.name = NULL, /* END OF TABLE */ }, }; /** */ const struct hl_layout *hl_layout_get_list(void) { return hl_layouts; } int hl_layout_init(struct hl_interface_s *adapter) { LOG_DEBUG("hl_layout_init"); if (adapter->layout == NULL) { LOG_ERROR("no layout specified"); return ERROR_FAIL; } return ERROR_OK; } openocd-0.7.0/src/jtag/hla/hla_tcl.c0000644000175000001440000001053612134336410014116 00000000000000/*************************************************************************** * Copyright (C) 2011 by Mathias Kuester * * Mathias Kuester * * * * Copyright (C) 2012 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* project specific includes */ #include #include #include static int jim_newtap_expected_id(Jim_Nvp *n, Jim_GetOptInfo *goi, struct jtag_tap *pTap) { jim_wide w; int e = Jim_GetOpt_Wide(goi, &w); if (e != JIM_OK) { Jim_SetResultFormatted(goi->interp, "option: %s bad parameter", n->name); return e; } unsigned expected_len = sizeof(uint32_t) * pTap->expected_ids_cnt; uint32_t *new_expected_ids = malloc(expected_len + sizeof(uint32_t)); if (new_expected_ids == NULL) { Jim_SetResultFormatted(goi->interp, "no memory"); return JIM_ERR; } memcpy(new_expected_ids, pTap->expected_ids, expected_len); new_expected_ids[pTap->expected_ids_cnt] = w; free(pTap->expected_ids); pTap->expected_ids = new_expected_ids; pTap->expected_ids_cnt++; return JIM_OK; } #define NTAP_OPT_EXPECTED_ID 0 static int jim_hl_newtap_cmd(Jim_GetOptInfo *goi) { struct jtag_tap *pTap; int x; int e; Jim_Nvp *n; char *cp; const Jim_Nvp opts[] = { {.name = "-expected-id", .value = NTAP_OPT_EXPECTED_ID}, {.name = NULL, .value = -1}, }; pTap = calloc(1, sizeof(struct jtag_tap)); if (!pTap) { Jim_SetResultFormatted(goi->interp, "no memory"); return JIM_ERR; } /* * we expect CHIP + TAP + OPTIONS * */ if (goi->argc < 3) { Jim_SetResultFormatted(goi->interp, "Missing CHIP TAP OPTIONS ...."); free(pTap); return JIM_ERR; } Jim_GetOpt_String(goi, &cp, NULL); pTap->chip = strdup(cp); Jim_GetOpt_String(goi, &cp, NULL); pTap->tapname = strdup(cp); /* name + dot + name + null */ x = strlen(pTap->chip) + 1 + strlen(pTap->tapname) + 1; cp = malloc(x); sprintf(cp, "%s.%s", pTap->chip, pTap->tapname); pTap->dotted_name = cp; LOG_DEBUG("Creating New Tap, Chip: %s, Tap: %s, Dotted: %s, %d params", pTap->chip, pTap->tapname, pTap->dotted_name, goi->argc); while (goi->argc) { e = Jim_GetOpt_Nvp(goi, opts, &n); if (e != JIM_OK) { Jim_GetOpt_NvpUnknown(goi, opts, 0); free((void *)pTap->dotted_name); free(pTap); return e; } LOG_DEBUG("Processing option: %s", n->name); switch (n->value) { case NTAP_OPT_EXPECTED_ID: e = jim_newtap_expected_id(n, goi, pTap); if (JIM_OK != e) { free((void *)pTap->dotted_name); free(pTap); return e; } break; } /* switch (n->value) */ } /* while (goi->argc) */ /* default is enabled-after-reset */ pTap->enabled = !pTap->disabled_after_reset; jtag_tap_init(pTap); return JIM_OK; } int jim_hl_newtap(Jim_Interp *interp, int argc, Jim_Obj * const *argv) { Jim_GetOptInfo goi; Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1); return jim_hl_newtap_cmd(&goi); } openocd-0.7.0/src/jtag/hla/hla_tcl.h0000644000175000001440000000345112134336410014121 00000000000000/*************************************************************************** * Copyright (C) 2011 by Mathias Kuester * * Mathias Kuester * * * * Copyright (C) 2012 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef _HL_TCL_ #define _HL_TCL_ /** */ int jim_hl_newtap(Jim_Interp *interp, int argc, Jim_Obj * const *argv); #endif /* _HL_TCL_ */ openocd-0.7.0/src/jtag/hla/hla_interface.c0000644000175000001440000001634112137151331015274 00000000000000/*************************************************************************** * Copyright (C) 2011 by Mathias Kuester * * Mathias Kuester * * * * Copyright (C) 2012 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* project specific includes */ #include #include #include #include #include #include #include #include static struct hl_interface_s hl_if = { {0, 0, 0, 0, 0, HL_TRANSPORT_UNKNOWN, 0, false}, 0, 0 }; int hl_interface_open(enum hl_transports tr) { LOG_DEBUG("hl_interface_open"); enum reset_types jtag_reset_config = jtag_get_reset_config(); if (jtag_reset_config & RESET_CNCT_UNDER_SRST) { if (jtag_reset_config & RESET_SRST_NO_GATING) hl_if.param.connect_under_reset = true; else LOG_WARNING("\'srst_nogate\' reset_config option is required"); } /* set transport mode */ hl_if.param.transport = tr; int result = hl_if.layout->open(&hl_if); if (result != ERROR_OK) return result; return hl_interface_init_reset(); } int hl_interface_init_target(struct target *t) { int res; LOG_DEBUG("hl_interface_init_target"); /* this is the interface for the current target and we * can setup the private pointer in the tap structure * if the interface match the tap idcode */ res = hl_if.layout->api->idcode(hl_if.fd, &t->tap->idcode); if (res != ERROR_OK) return res; unsigned ii, limit = t->tap->expected_ids_cnt; int found = 0; for (ii = 0; ii < limit; ii++) { uint32_t expected = t->tap->expected_ids[ii]; /* treat "-expected-id 0" as a "don't-warn" wildcard */ if (!expected || (t->tap->idcode == expected)) { found = 1; break; } } if (found == 0) { LOG_ERROR("hl_interface_init_target: target not found: idcode: 0x%08x", t->tap->idcode); return ERROR_FAIL; } t->tap->priv = &hl_if; t->tap->hasidcode = 1; return ERROR_OK; } static int hl_interface_init(void) { LOG_DEBUG("hl_interface_init"); /* here we can initialize the layout */ return hl_layout_init(&hl_if); } static int hl_interface_quit(void) { LOG_DEBUG("hl_interface_quit"); return ERROR_OK; } static int hl_interface_execute_queue(void) { LOG_DEBUG("hl_interface_execute_queue: ignored"); return ERROR_OK; } int hl_interface_init_reset(void) { /* incase the adapter has not already handled asserting srst * we will attempt it again */ if (hl_if.param.connect_under_reset) { jtag_add_reset(0, 1); hl_if.layout->api->assert_srst(hl_if.fd, 0); } return ERROR_OK; } COMMAND_HANDLER(hl_interface_handle_device_desc_command) { LOG_DEBUG("hl_interface_handle_device_desc_command"); if (CMD_ARGC == 1) { hl_if.param.device_desc = strdup(CMD_ARGV[0]); } else { LOG_ERROR("expected exactly one argument to hl_device_desc "); } return ERROR_OK; } COMMAND_HANDLER(hl_interface_handle_serial_command) { LOG_DEBUG("hl_interface_handle_serial_command"); if (CMD_ARGC == 1) { hl_if.param.serial = strdup(CMD_ARGV[0]); } else { LOG_ERROR("expected exactly one argument to hl_serial "); } return ERROR_OK; } COMMAND_HANDLER(hl_interface_handle_layout_command) { LOG_DEBUG("hl_interface_handle_layout_command"); if (CMD_ARGC != 1) { LOG_ERROR("Need exactly one argument to stlink_layout"); return ERROR_COMMAND_SYNTAX_ERROR; } if (hl_if.layout) { LOG_ERROR("already specified hl_layout %s", hl_if.layout->name); return (strcmp(hl_if.layout->name, CMD_ARGV[0]) != 0) ? ERROR_FAIL : ERROR_OK; } for (const struct hl_layout *l = hl_layout_get_list(); l->name; l++) { if (strcmp(l->name, CMD_ARGV[0]) == 0) { hl_if.layout = l; return ERROR_OK; } } LOG_ERROR("No adapter layout '%s' found", CMD_ARGV[0]); return ERROR_FAIL; } COMMAND_HANDLER(hl_interface_handle_vid_pid_command) { LOG_DEBUG("hl_interface_handle_vid_pid_command"); if (CMD_ARGC != 2) { LOG_WARNING("ignoring extra IDs in hl_vid_pid (maximum is 1 pair)"); return ERROR_COMMAND_SYNTAX_ERROR; } COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], hl_if.param.vid); COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], hl_if.param.pid); return ERROR_OK; } COMMAND_HANDLER(stlink_interface_handle_api_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; unsigned new_api; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], new_api); if ((new_api == 0) || (new_api > 2)) return ERROR_COMMAND_SYNTAX_ERROR; hl_if.param.api = new_api; return ERROR_OK; } static const struct command_registration hl_interface_command_handlers[] = { { .name = "hla_device_desc", .handler = &hl_interface_handle_device_desc_command, .mode = COMMAND_CONFIG, .help = "set the a device description of the adapter", .usage = "description_string", }, { .name = "hla_serial", .handler = &hl_interface_handle_serial_command, .mode = COMMAND_CONFIG, .help = "set the serial number of the adapter", .usage = "serial_string", }, { .name = "hla_layout", .handler = &hl_interface_handle_layout_command, .mode = COMMAND_CONFIG, .help = "set the layout of the adapter", .usage = "layout_name", }, { .name = "hla_vid_pid", .handler = &hl_interface_handle_vid_pid_command, .mode = COMMAND_CONFIG, .help = "the vendor and product ID of the adapter", .usage = "(vid pid)* ", }, { .name = "stlink_api", .handler = &stlink_interface_handle_api_command, .mode = COMMAND_CONFIG, .help = "set the desired stlink api level", .usage = "api version 1 or 2", }, COMMAND_REGISTRATION_DONE }; struct jtag_interface hl_interface = { .name = "hla", .supported = 0, .commands = hl_interface_command_handlers, .transports = hl_transports, .init = hl_interface_init, .quit = hl_interface_quit, .execute_queue = hl_interface_execute_queue, }; openocd-0.7.0/src/jtag/hla/Makefile.am0000644000175000001440000000055612134336410014401 00000000000000include $(top_srcdir)/common.mk noinst_LTLIBRARIES = libocdhla.la libocdhla_la_SOURCES = \ $(HLFILES) HLFILES = if HLADAPTER HLFILES += hla_transport.c HLFILES += hla_tcl.c HLFILES += hla_interface.c HLFILES += hla_layout.c endif noinst_HEADERS = \ hla_interface.h \ hla_layout.h \ hla_tcl.h \ hla_transport.h MAINTAINERCLEANFILES = $(srcdir)/Makefile.in openocd-0.7.0/src/jtag/minidriver/0000755000175000001440000000000012141414411014017 500000000000000openocd-0.7.0/src/jtag/minidriver/minidriver_imp.h0000644000175000001440000000412712134336410017135 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Copyright (C) 2007,2008 Øyvind Harboe * * Copyright (C) 2009 Zachary T Welch * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef MINIDRIVER_IMP_H #define MINIDRIVER_IMP_H #include static inline void jtag_add_dr_out(struct jtag_tap *tap, int num_fields, const int *num_bits, const uint32_t *value, tap_state_t end_state) { cmd_queue_cur_state = end_state; interface_jtag_add_dr_out(tap, num_fields, num_bits, value, end_state); } #define jtag_add_callback(callback, in) interface_jtag_add_callback(callback, in) #define jtag_add_callback4(callback, in, data1, data2, data3) \ interface_jtag_add_callback4(callback, in, data1, data2, data3) #endif /* MINIDRIVER_IMP_H */ openocd-0.7.0/src/jtag/interface.c0000644000175000001440000003430512134336410013704 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2009 SoftPLC Corporation * * http://softplc.com * * dick@softplc.com * * * * Copyright (C) 2009 Zachary T Welch * * zw@superlucidity.net * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "jtag.h" #include "interface.h" /** * @see tap_set_state() and tap_get_state() accessors. * Actual name is not important since accessors hide it. */ static tap_state_t state_follower = TAP_RESET; void tap_set_state_impl(tap_state_t new_state) { /* this is the state we think the TAPs are in now, was cur_state */ state_follower = new_state; } tap_state_t tap_get_state() { return state_follower; } /** * @see tap_set_end_state() and tap_get_end_state() accessors. * Actual name is not important because accessors hide it. */ static tap_state_t end_state_follower = TAP_RESET; void tap_set_end_state(tap_state_t new_end_state) { /* this is the state we think the TAPs will be in at completion of the * current TAP operation, was end_state */ end_state_follower = new_end_state; } tap_state_t tap_get_end_state() { return end_state_follower; } int tap_move_ndx(tap_state_t astate) { /* given a stable state, return the index into the tms_seqs[] * array within tap_get_tms_path() */ int ndx; switch (astate) { case TAP_RESET: ndx = 0; break; case TAP_IDLE: ndx = 1; break; case TAP_DRSHIFT: ndx = 2; break; case TAP_DRPAUSE: ndx = 3; break; case TAP_IRSHIFT: ndx = 4; break; case TAP_IRPAUSE: ndx = 5; break; default: LOG_ERROR("FATAL: unstable state \"%s\" in tap_move_ndx()", tap_state_name(astate)); exit(1); } return ndx; } /* tap_move[i][j]: tap movement command to go from state i to state j * encodings of i and j are what tap_move_ndx() reports. * * DRSHIFT->DRSHIFT and IRSHIFT->IRSHIFT have to be caught in interface specific code */ struct tms_sequences { uint8_t bits; uint8_t bit_count; }; /* * These macros allow us to specify TMS state transitions by bits rather than hex bytes. * Read the bits from LSBit first to MSBit last (right-to-left). */ #define HEX__(n) 0x##n##LU #define B8__(x) \ ((((x) & 0x0000000FLU) ? (1 << 0) : 0) \ +(((x) & 0x000000F0LU) ? (1 << 1) : 0) \ +(((x) & 0x00000F00LU) ? (1 << 2) : 0) \ +(((x) & 0x0000F000LU) ? (1 << 3) : 0) \ +(((x) & 0x000F0000LU) ? (1 << 4) : 0) \ +(((x) & 0x00F00000LU) ? (1 << 5) : 0) \ +(((x) & 0x0F000000LU) ? (1 << 6) : 0) \ +(((x) & 0xF0000000LU) ? (1 << 7) : 0)) #define B8(bits, count) {((uint8_t)B8__(HEX__(bits))), (count)} static const struct tms_sequences old_tms_seqs[6][6] = { /* [from_state_ndx][to_state_ndx] */ /* value clocked to TMS to move from one of six stable states to another. * N.B. OOCD clocks TMS from LSB first, so read these right-to-left. * N.B. Reset only needs to be 0b11111, but in JLink an even byte of 1's is more stable. * These extra ones cause no TAP state problem, because we go into reset and stay in reset. */ /* to state: */ /* RESET IDLE DRSHIFT DRPAUSE IRSHIFT IRPAUSE */ /* from state: */ {B8(1111111, 7), B8(0000000, 7), B8(0010111, 7), B8(0001010, 7), B8(0011011, 7), B8(0010110, 7)},/* RESET */ {B8(1111111, 7), B8(0000000, 7), B8(0100101, 7), B8(0000101, 7), B8(0101011, 7), B8(0001011, 7)},/* IDLE */ {B8(1111111, 7), B8(0110001, 7), B8(0000000, 7), B8(0000001, 7), B8(0001111, 7), B8(0101111, 7)},/* DRSHIFT */ {B8(1111111, 7), B8(0110000, 7), B8(0100000, 7), B8(0010111, 7), B8(0011110, 7), B8(0101111, 7)},/* DRPAUSE */ {B8(1111111, 7), B8(0110001, 7), B8(0000111, 7), B8(0010111, 7), B8(0000000, 7), B8(0000001, 7)},/* IRSHIFT */ {B8(1111111, 7), B8(0110000, 7), B8(0011100, 7), B8(0010111, 7), B8(0011110, 7), B8(0101111, 7)},/* IRPAUSE */ }; static const struct tms_sequences short_tms_seqs[6][6] = { /* [from_state_ndx][to_state_ndx] */ /* this is the table submitted by Jeff Williams on 3/30/2009 with this comment: OK, I added Peter's version of the state table, and it works OK for me on MC1322x. I've recreated the jlink portion of patch with this new state table. His changes to my state table are pretty minor in terms of total transitions, but Peter feels that his version fixes some long-standing problems. Jeff I added the bit count into the table, reduced RESET column to 7 bits from 8. Dick state specific comments: ------------------------ *->RESET tried the 5 bit reset and it gave me problems, 7 bits seems to work better on ARM9 with ft2232 driver. (Dick) RESET->DRSHIFT add 1 extra clock cycles in the RESET state before advancing. needed on ARM9 with ft2232 driver. (Dick) (For a total of *THREE* extra clocks in RESET; NOP.) RESET->IRSHIFT add 1 extra clock cycles in the RESET state before advancing. needed on ARM9 with ft2232 driver. (Dick) (For a total of *TWO* extra clocks in RESET; NOP.) RESET->* always adds one or more clocks in the target state, which should be NOPS; except shift states which (as noted above) add those clocks in RESET. The X-to-X transitions always add clocks; from *SHIFT, they go via IDLE and thus *DO HAVE SIDE EFFECTS* (capture and update). */ /* to state: */ /* RESET IDLE DRSHIFT DRPAUSE IRSHIFT IRPAUSE */ /* from state: */ {B8(1111111, 7), B8(0000000, 7), B8(0010111, 7), B8(0001010, 7), B8(0011011, 7), B8(0010110, 7)}, /* RESET */ {B8(1111111, 7), B8(0000000, 7), B8(001, 3), B8(0101, 4), B8(0011, 4), B8(01011, 5)}, /* IDLE */ {B8(1111111, 7), B8(011, 3), B8(00111, 5), B8(01, 2), B8(001111, 6), B8(0101111, 7)}, /* DRSHIFT */ {B8(1111111, 7), B8(011, 3), B8(01, 2), B8(0, 1), B8(001111, 6), B8(0101111, 7)}, /* DRPAUSE */ {B8(1111111, 7), B8(011, 3), B8(00111, 5), B8(010111, 6), B8(001111, 6), B8(01, 2)}, /* IRSHIFT */ {B8(1111111, 7), B8(011, 3), B8(00111, 5), B8(010111, 6), B8(01, 2), B8(0, 1)} /* IRPAUSE */ }; typedef const struct tms_sequences tms_table[6][6]; static tms_table *tms_seqs = &short_tms_seqs; int tap_get_tms_path(tap_state_t from, tap_state_t to) { return (*tms_seqs)[tap_move_ndx(from)][tap_move_ndx(to)].bits; } int tap_get_tms_path_len(tap_state_t from, tap_state_t to) { return (*tms_seqs)[tap_move_ndx(from)][tap_move_ndx(to)].bit_count; } bool tap_is_state_stable(tap_state_t astate) { bool is_stable; /* A switch () is used because it is symbol dependent * (not value dependent like an array), and can also check bounds. */ switch (astate) { case TAP_RESET: case TAP_IDLE: case TAP_DRSHIFT: case TAP_DRPAUSE: case TAP_IRSHIFT: case TAP_IRPAUSE: is_stable = true; break; default: is_stable = false; } return is_stable; } tap_state_t tap_state_transition(tap_state_t cur_state, bool tms) { tap_state_t new_state; /* A switch is used because it is symbol dependent and not value dependent * like an array. Also it can check for out of range conditions. */ if (tms) { switch (cur_state) { case TAP_RESET: new_state = cur_state; break; case TAP_IDLE: case TAP_DRUPDATE: case TAP_IRUPDATE: new_state = TAP_DRSELECT; break; case TAP_DRSELECT: new_state = TAP_IRSELECT; break; case TAP_DRCAPTURE: case TAP_DRSHIFT: new_state = TAP_DREXIT1; break; case TAP_DREXIT1: case TAP_DREXIT2: new_state = TAP_DRUPDATE; break; case TAP_DRPAUSE: new_state = TAP_DREXIT2; break; case TAP_IRSELECT: new_state = TAP_RESET; break; case TAP_IRCAPTURE: case TAP_IRSHIFT: new_state = TAP_IREXIT1; break; case TAP_IREXIT1: case TAP_IREXIT2: new_state = TAP_IRUPDATE; break; case TAP_IRPAUSE: new_state = TAP_IREXIT2; break; default: LOG_ERROR("fatal: invalid argument cur_state=%d", cur_state); exit(1); break; } } else { switch (cur_state) { case TAP_RESET: case TAP_IDLE: case TAP_DRUPDATE: case TAP_IRUPDATE: new_state = TAP_IDLE; break; case TAP_DRSELECT: new_state = TAP_DRCAPTURE; break; case TAP_DRCAPTURE: case TAP_DRSHIFT: case TAP_DREXIT2: new_state = TAP_DRSHIFT; break; case TAP_DREXIT1: case TAP_DRPAUSE: new_state = TAP_DRPAUSE; break; case TAP_IRSELECT: new_state = TAP_IRCAPTURE; break; case TAP_IRCAPTURE: case TAP_IRSHIFT: case TAP_IREXIT2: new_state = TAP_IRSHIFT; break; case TAP_IREXIT1: case TAP_IRPAUSE: new_state = TAP_IRPAUSE; break; default: LOG_ERROR("fatal: invalid argument cur_state=%d", cur_state); exit(1); break; } } return new_state; } /* NOTE: do not change these state names. They're documented, * and we rely on them to match SVF input (except for "RUN/IDLE"). */ static const struct name_mapping { enum tap_state symbol; const char *name; } tap_name_mapping[] = { { TAP_RESET, "RESET", }, { TAP_IDLE, "RUN/IDLE", }, { TAP_DRSELECT, "DRSELECT", }, { TAP_DRCAPTURE, "DRCAPTURE", }, { TAP_DRSHIFT, "DRSHIFT", }, { TAP_DREXIT1, "DREXIT1", }, { TAP_DRPAUSE, "DRPAUSE", }, { TAP_DREXIT2, "DREXIT2", }, { TAP_DRUPDATE, "DRUPDATE", }, { TAP_IRSELECT, "IRSELECT", }, { TAP_IRCAPTURE, "IRCAPTURE", }, { TAP_IRSHIFT, "IRSHIFT", }, { TAP_IREXIT1, "IREXIT1", }, { TAP_IRPAUSE, "IRPAUSE", }, { TAP_IREXIT2, "IREXIT2", }, { TAP_IRUPDATE, "IRUPDATE", }, /* only for input: accept standard SVF name */ { TAP_IDLE, "IDLE", }, }; const char *tap_state_name(tap_state_t state) { unsigned i; for (i = 0; i < ARRAY_SIZE(tap_name_mapping); i++) { if (tap_name_mapping[i].symbol == state) return tap_name_mapping[i].name; } return "???"; } tap_state_t tap_state_by_name(const char *name) { unsigned i; for (i = 0; i < ARRAY_SIZE(tap_name_mapping); i++) { /* be nice to the human */ if (strcasecmp(name, tap_name_mapping[i].name) == 0) return tap_name_mapping[i].symbol; } /* not found */ return TAP_INVALID; } #ifdef _DEBUG_JTAG_IO_ #define JTAG_DEBUG_STATE_APPEND(buf, len, bit) \ do { buf[len] = bit ? '1' : '0'; } while (0) #define JTAG_DEBUG_STATE_PRINT(a, b, astr, bstr) \ DEBUG_JTAG_IO("TAP/SM: %9s -> %5s\tTMS: %s\tTDI: %s", \ tap_state_name(a), tap_state_name(b), astr, bstr) tap_state_t jtag_debug_state_machine(const void *tms_buf, const void *tdi_buf, unsigned tap_bits, tap_state_t next_state) { const uint8_t *tms_buffer; const uint8_t *tdi_buffer; unsigned tap_bytes; unsigned cur_byte; unsigned cur_bit; unsigned tap_out_bits; char tms_str[33]; char tdi_str[33]; tap_state_t last_state; /* set startstate (and possibly last, if tap_bits == 0) */ last_state = next_state; DEBUG_JTAG_IO("TAP/SM: START state: %s", tap_state_name(next_state)); tms_buffer = (const uint8_t *)tms_buf; tdi_buffer = (const uint8_t *)tdi_buf; tap_bytes = DIV_ROUND_UP(tap_bits, 8); DEBUG_JTAG_IO("TAP/SM: TMS bits: %u (bytes: %u)", tap_bits, tap_bytes); tap_out_bits = 0; for (cur_byte = 0; cur_byte < tap_bytes; cur_byte++) { for (cur_bit = 0; cur_bit < 8; cur_bit++) { /* make sure we do not run off the end of the buffers */ unsigned tap_bit = cur_byte * 8 + cur_bit; if (tap_bit == tap_bits) break; /* check and save TMS bit */ tap_bit = !!(tms_buffer[cur_byte] & (1 << cur_bit)); JTAG_DEBUG_STATE_APPEND(tms_str, tap_out_bits, tap_bit); /* use TMS bit to find the next TAP state */ next_state = tap_state_transition(last_state, tap_bit); /* check and store TDI bit */ tap_bit = !!(tdi_buffer[cur_byte] & (1 << cur_bit)); JTAG_DEBUG_STATE_APPEND(tdi_str, tap_out_bits, tap_bit); /* increment TAP bits */ tap_out_bits++; /* Only show TDO bits on state transitions, or */ /* after some number of bits in the same state. */ if ((next_state == last_state) && (tap_out_bits < 32)) continue; /* terminate strings and display state transition */ tms_str[tap_out_bits] = tdi_str[tap_out_bits] = 0; JTAG_DEBUG_STATE_PRINT(last_state, next_state, tms_str, tdi_str); /* reset state */ last_state = next_state; tap_out_bits = 0; } } if (tap_out_bits) { /* terminate strings and display state transition */ tms_str[tap_out_bits] = tdi_str[tap_out_bits] = 0; JTAG_DEBUG_STATE_PRINT(last_state, next_state, tms_str, tdi_str); } DEBUG_JTAG_IO("TAP/SM: FINAL state: %s", tap_state_name(next_state)); return next_state; } #endif /* _DEBUG_JTAG_IO_ */ void tap_use_new_tms_table(bool use_new) { tms_seqs = use_new ? &short_tms_seqs : &old_tms_seqs; } bool tap_uses_new_tms_table(void) { return tms_seqs == &short_tms_seqs; } openocd-0.7.0/src/jtag/driver.h0000644000175000001440000000313112134336410013235 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef JTAG_DRIVER_H #define JTAG_DRIVER_H struct command_context; int interface_register_commands(struct command_context *ctx); #endif /* JTAG_DRIVER_H */ openocd-0.7.0/src/jtag/Makefile.am0000644000175000001440000000250412134336410013630 00000000000000include $(top_srcdir)/common.mk METASOURCES = AUTO noinst_LTLIBRARIES = libjtag.la SUBDIRS = DRIVERFILES = libjtag_la_LIBADD = CLEANFILES = BUILT_SOURCES = BUILT_SOURCES += minidriver_imp.h CLEANFILES += minidriver_imp.h if MINIDRIVER if ZY1000 DRIVERFILES += zy1000/zy1000.c JTAG_MINIDRIVER_DIR = $(srcdir)/zy1000 endif if MINIDRIVER_DUMMY DRIVERFILES += minidummy/minidummy.c commands.c JTAG_MINIDRIVER_DIR = $(srcdir)/minidummy endif MINIDRIVER_IMP_DIR = $(srcdir)/minidriver jtag_minidriver.h: $(JTAG_MINIDRIVER_DIR)/jtag_minidriver.h cp $< $@ BUILT_SOURCES += jtag_minidriver.h CLEANFILES += jtag_minidriver.h else MINIDRIVER_IMP_DIR = $(srcdir)/drivers DRIVERFILES += commands.c if HLADAPTER SUBDIRS += hla libjtag_la_LIBADD += $(top_builddir)/src/jtag/hla/libocdhla.la endif SUBDIRS += drivers libjtag_la_LIBADD += $(top_builddir)/src/jtag/drivers/libocdjtagdrivers.la endif # endif // MINIDRIVER minidriver_imp.h: $(MINIDRIVER_IMP_DIR)/minidriver_imp.h cp $< $@ libjtag_la_SOURCES = \ adapter.c \ core.c \ interface.c \ interfaces.c \ tcl.c \ $(DRIVERFILES) noinst_HEADERS = \ commands.h \ driver.h \ interface.h \ interfaces.h \ minidriver.h \ jtag.h \ minidriver/minidriver_imp.h \ minidummy/jtag_minidriver.h \ swd.h \ tcl.h EXTRA_DIST = startup.tcl MAINTAINERCLEANFILES = $(srcdir)/Makefile.in openocd-0.7.0/src/jtag/interfaces.c0000644000175000001440000001476212134336410014074 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2009 SoftPLC Corporation * * http://softplc.com * * dick@softplc.com * * * * Copyright (C) 2009 Zachary T Welch * * zw@superlucidity.net * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "interfaces.h" /** @file * This file includes declarations for all built-in jtag interfaces, * which are then listed in the jtag_interfaces array. * * Dynamic loading can be implemented be searching for shared libraries * that contain a jtag_interface structure that can added to this list. */ #if BUILD_ZY1000 == 1 extern struct jtag_interface zy1000_interface; #elif defined(BUILD_MINIDRIVER_DUMMY) extern struct jtag_interface minidummy_interface; #else /* standard drivers */ #if BUILD_PARPORT == 1 extern struct jtag_interface parport_interface; #endif #if BUILD_DUMMY == 1 extern struct jtag_interface dummy_interface; #endif #if BUILD_FT2232_FTD2XX == 1 extern struct jtag_interface ft2232_interface; #endif #if BUILD_FT2232_LIBFTDI == 1 extern struct jtag_interface ft2232_interface; #endif #if BUILD_FTDI == 1 extern struct jtag_interface ftdi_interface; #endif #if BUILD_USB_BLASTER_LIBFTDI == 1 || BUILD_USB_BLASTER_FTD2XX == 1 extern struct jtag_interface usb_blaster_interface; #endif #if BUILD_AMTJTAGACCEL == 1 extern struct jtag_interface amt_jtagaccel_interface; #endif #if BUILD_EP93XX == 1 extern struct jtag_interface ep93xx_interface; #endif #if BUILD_AT91RM9200 == 1 extern struct jtag_interface at91rm9200_interface; #endif #if BUILD_GW16012 == 1 extern struct jtag_interface gw16012_interface; #endif #if BUILD_PRESTO_LIBFTDI == 1 || BUILD_PRESTO_FTD2XX == 1 extern struct jtag_interface presto_interface; #endif #if BUILD_USBPROG == 1 extern struct jtag_interface usbprog_interface; #endif #if BUILD_JLINK == 1 extern struct jtag_interface jlink_interface; #endif #if BUILD_VSLLINK == 1 extern struct jtag_interface vsllink_interface; #endif #if BUILD_RLINK == 1 extern struct jtag_interface rlink_interface; #endif #if BUILD_ULINK == 1 extern struct jtag_interface ulink_interface; #endif #if BUILD_ARMJTAGEW == 1 extern struct jtag_interface armjtagew_interface; #endif #if BUILD_BUSPIRATE == 1 extern struct jtag_interface buspirate_interface; #endif #if BUILD_REMOTE_BITBANG == 1 extern struct jtag_interface remote_bitbang_interface; #endif #if BUILD_HLADAPTER == 1 extern struct jtag_interface hl_interface; #endif #if BUILD_OSBDM == 1 extern struct jtag_interface osbdm_interface; #endif #if BUILD_OPENDOUS == 1 extern struct jtag_interface opendous_interface; #endif #if BUILD_SYSFSGPIO == 1 extern struct jtag_interface sysfsgpio_interface; #endif #endif /* standard drivers */ /** * The list of built-in JTAG interfaces, containing entries for those * drivers that were enabled by the @c configure script. * * The list should be defined to contain either one minidriver interface * or some number of standard driver interfaces, never both. */ struct jtag_interface *jtag_interfaces[] = { #if BUILD_ZY1000 == 1 &zy1000_interface, #elif defined(BUILD_MINIDRIVER_DUMMY) &minidummy_interface, #else /* standard drivers */ #if BUILD_PARPORT == 1 &parport_interface, #endif #if BUILD_DUMMY == 1 &dummy_interface, #endif #if BUILD_FT2232_FTD2XX == 1 &ft2232_interface, #endif #if BUILD_FT2232_LIBFTDI == 1 &ft2232_interface, #endif #if BUILD_FTDI == 1 &ftdi_interface, #endif #if BUILD_USB_BLASTER_LIBFTDI == 1 || BUILD_USB_BLASTER_FTD2XX == 1 &usb_blaster_interface, #endif #if BUILD_AMTJTAGACCEL == 1 &amt_jtagaccel_interface, #endif #if BUILD_EP93XX == 1 &ep93xx_interface, #endif #if BUILD_AT91RM9200 == 1 &at91rm9200_interface, #endif #if BUILD_GW16012 == 1 &gw16012_interface, #endif #if BUILD_PRESTO_LIBFTDI == 1 || BUILD_PRESTO_FTD2XX == 1 &presto_interface, #endif #if BUILD_USBPROG == 1 &usbprog_interface, #endif #if BUILD_JLINK == 1 &jlink_interface, #endif #if BUILD_VSLLINK == 1 &vsllink_interface, #endif #if BUILD_RLINK == 1 &rlink_interface, #endif #if BUILD_ULINK == 1 &ulink_interface, #endif #if BUILD_ARMJTAGEW == 1 &armjtagew_interface, #endif #if BUILD_BUSPIRATE == 1 &buspirate_interface, #endif #if BUILD_REMOTE_BITBANG == 1 &remote_bitbang_interface, #endif #if BUILD_HLADAPTER == 1 &hl_interface, #endif #if BUILD_OSBDM == 1 &osbdm_interface, #endif #if BUILD_OPENDOUS == 1 &opendous_interface, #endif #if BUILD_SYSFSGPIO == 1 &sysfsgpio_interface, #endif #endif /* standard drivers */ NULL, }; void jtag_interface_modules_load(const char *path) { /* @todo: implement dynamic module loading for JTAG interface drivers */ } openocd-0.7.0/src/jtag/startup.tcl0000644000175000001440000000723012134336410014003 00000000000000# Defines basic Tcl procs for OpenOCD JTAG module # Executed during "init". Can be overridden # by board/target/... scripts proc jtag_init {} { if {[catch {jtag arp_init} err]!=0} { # try resetting additionally init_reset startup } } # This reset logic may be overridden by board/target/... scripts as needed # to provide a reset that, if possible, is close to a power-up reset. # # Exit requirements include: (a) JTAG must be working, (b) the scan # chain was validated with "jtag arp_init" (or equivalent), (c) nothing # stays in reset. No TAP-specific scans were performed. It's OK if # some targets haven't been reset yet; they may need TAP-specific scans. # # The "mode" values include: halt, init, run (from "reset" command); # startup (at OpenOCD server startup, when JTAG may not yet work); and # potentially more (for reset types like cold, warm, etc) proc init_reset { mode } { jtag arp_init-reset } ######### # TODO: power_restore and power_dropout are currently neither # documented nor supported except on ZY1000. proc power_restore {} { echo "Sensed power restore, running reset init and halting GDB." reset init # Halt GDB so user can deal with a detected power restore. # # After GDB is halted, then output is no longer forwarded # to the GDB console. set targets [target names] foreach t $targets { # New event script. $t invoke-event arp_halt_gdb } } add_help_text power_restore "Overridable procedure run when power restore is detected. Runs 'reset init' by default." proc power_dropout {} { echo "Sensed power dropout." } ######### # TODO: srst_deasserted and srst_asserted are currently neither # documented nor supported except on ZY1000. proc srst_deasserted {} { echo "Sensed nSRST deasserted, running reset init and halting GDB." reset init # Halt GDB so user can deal with a detected reset. # # After GDB is halted, then output is no longer forwarded # to the GDB console. set targets [target names] foreach t $targets { # New event script. $t invoke-event arp_halt_gdb } } add_help_text srst_deasserted "Overridable procedure run when srst deassert is detected. Runs 'reset init' by default." proc srst_asserted {} { echo "Sensed nSRST asserted." } # measure actual JTAG clock proc measure_clk {} { set start_time [ms]; runtest 10000000; echo "Running at more than [expr 10000.0 / ([ms]-$start_time)] kHz"; } add_help_text measure_clk "Runs a test to measure the JTAG clk. Useful with RCLK / RTCK." # BEGIN MIGRATION AIDS ... these adapter operations originally had # JTAG-specific names despite the fact that the operations were not # specific to JTAG, or otherewise had troublesome/misleading names. # # FIXME phase these aids out after about April 2011 # proc jtag_khz args { echo "DEPRECATED! use 'adapter_khz' not 'jtag_khz'" eval adapter_khz $args } proc jtag_nsrst_delay args { echo "DEPRECATED! use 'adapter_nsrst_delay' not 'jtag_nsrst_delay'" eval adapter_nsrst_delay $args } proc jtag_nsrst_assert_width args { echo "DEPRECATED! use 'adapter_nsrst_assert_width' not 'jtag_nsrst_assert_width'" eval adapter_nsrst_assert_width $args } # stlink migration helpers proc stlink_device_desc args { echo "DEPRECATED! use 'hla_device_desc' not 'stlink_device_desc'" eval hla_device_desc $args } proc stlink_serial args { echo "DEPRECATED! use 'hla_serial' not 'stlink_serial'" eval hla_serial $args } proc stlink_layout args { echo "DEPRECATED! use 'hla_layout' not 'stlink_layout'" eval hla_layout $args } proc stlink_vid_pid args { echo "DEPRECATED! use 'hla_vid_pid' not 'stlink_vid_pid'" eval hla_vid_pid $args } proc stlink args { echo "DEPRECATED! use 'hla' not 'stlink'" eval hla $args } # END MIGRATION AIDS openocd-0.7.0/src/helper/0000755000175000001440000000000012141414412012202 500000000000000openocd-0.7.0/src/helper/time_support_common.c0000644000175000001440000000440212134336410016373 00000000000000/*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "time_support.h" /* simple and low overhead fetching of ms counter. Use only * the difference between ms counters returned from this fn. */ int64_t timeval_ms() { struct timeval now; int retval = gettimeofday(&now, NULL); if (retval < 0) return retval; return (int64_t)now.tv_sec * 1000 + now.tv_usec / 1000; } openocd-0.7.0/src/helper/command.c0000644000175000001440000011530312134336410013712 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008, Duane Ellis * * openocd@duaneeellis.com * * * * part of this file is taken from libcli (libcli.sourceforge.net) * * Copyright (C) David Parrish (david@dparrish.com) * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* see Embedded-HOWTO.txt in Jim Tcl project hosted on BerliOS*/ #define JIM_EMBEDDED /* @todo the inclusion of target.h here is a layering violation */ #include #include #include "command.h" #include "configuration.h" #include "log.h" #include "time_support.h" #include "jim-eventloop.h" /* nice short description of source file */ #define __THIS__FILE__ "command.c" static int run_command(struct command_context *context, struct command *c, const char *words[], unsigned num_words); struct log_capture_state { Jim_Interp *interp; Jim_Obj *output; }; static void tcl_output(void *privData, const char *file, unsigned line, const char *function, const char *string) { struct log_capture_state *state = (struct log_capture_state *)privData; Jim_AppendString(state->interp, state->output, string, strlen(string)); } static struct log_capture_state *command_log_capture_start(Jim_Interp *interp) { /* capture log output and return it. A garbage collect can * happen, so we need a reference count to this object */ Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0); if (NULL == tclOutput) return NULL; struct log_capture_state *state = malloc(sizeof(*state)); if (NULL == state) return NULL; state->interp = interp; Jim_IncrRefCount(tclOutput); state->output = tclOutput; log_add_callback(tcl_output, state); return state; } /* Classic openocd commands provide progress output which we * will capture and return as a Tcl return value. * * However, if a non-openocd command has been invoked, then it * makes sense to return the tcl return value from that command. * * The tcl return value is empty for openocd commands that provide * progress output. * * Therefore we set the tcl return value only if we actually * captured output. */ static void command_log_capture_finish(struct log_capture_state *state) { if (NULL == state) return; log_remove_callback(tcl_output, state); int length; Jim_GetString(state->output, &length); if (length > 0) Jim_SetResult(state->interp, state->output); else { /* No output captured, use tcl return value (which could * be empty too). */ } Jim_DecrRefCount(state->interp, state->output); free(state); } static int command_retval_set(Jim_Interp *interp, int retval) { int *return_retval = Jim_GetAssocData(interp, "retval"); if (return_retval != NULL) *return_retval = retval; return (retval == ERROR_OK) ? JIM_OK : JIM_ERR; } extern struct command_context *global_cmd_ctx; /* dump a single line to the log for the command. * Do nothing in case we are not at debug level 3 */ void script_debug(Jim_Interp *interp, const char *name, unsigned argc, Jim_Obj * const *argv) { if (debug_level < LOG_LVL_DEBUG) return; char *dbg = alloc_printf("command - %s", name); for (unsigned i = 0; i < argc; i++) { int len; const char *w = Jim_GetString(argv[i], &len); char *t = alloc_printf("%s %s", dbg, w); free(dbg); dbg = t; } LOG_DEBUG("%s", dbg); free(dbg); } static void script_command_args_free(const char **words, unsigned nwords) { for (unsigned i = 0; i < nwords; i++) free((void *)words[i]); free(words); } static const char **script_command_args_alloc( unsigned argc, Jim_Obj * const *argv, unsigned *nwords) { const char **words = malloc(argc * sizeof(char *)); if (NULL == words) return NULL; unsigned i; for (i = 0; i < argc; i++) { int len; const char *w = Jim_GetString(argv[i], &len); words[i] = strdup(w); if (words[i] == NULL) { script_command_args_free(words, i); return NULL; } } *nwords = i; return words; } struct command_context *current_command_context(Jim_Interp *interp) { /* grab the command context from the associated data */ struct command_context *cmd_ctx = Jim_GetAssocData(interp, "context"); if (NULL == cmd_ctx) { /* Tcl can invoke commands directly instead of via command_run_line(). This would * happen when the Jim Tcl interpreter is provided by eCos or if we are running * commands in a startup script. * * A telnet or gdb server would provide a non-default command context to * handle piping of error output, have a separate current target, etc. */ cmd_ctx = global_cmd_ctx; } return cmd_ctx; } static int script_command_run(Jim_Interp *interp, int argc, Jim_Obj * const *argv, struct command *c, bool capture) { target_call_timer_callbacks_now(); LOG_USER_N("%s", ""); /* Keep GDB connection alive*/ unsigned nwords; const char **words = script_command_args_alloc(argc, argv, &nwords); if (NULL == words) return JIM_ERR; struct log_capture_state *state = NULL; if (capture) state = command_log_capture_start(interp); struct command_context *cmd_ctx = current_command_context(interp); int retval = run_command(cmd_ctx, c, (const char **)words, nwords); command_log_capture_finish(state); script_command_args_free(words, nwords); return command_retval_set(interp, retval); } static int script_command(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { /* the private data is stashed in the interp structure */ struct command *c = interp->cmdPrivData; assert(c); script_debug(interp, c->name, argc, argv); return script_command_run(interp, argc, argv, c, true); } static struct command *command_root(struct command *c) { while (NULL != c->parent) c = c->parent; return c; } /** * Find a command by name from a list of commands. * @returns Returns the named command if it exists in the list. * Returns NULL otherwise. */ static struct command *command_find(struct command *head, const char *name) { for (struct command *cc = head; cc; cc = cc->next) { if (strcmp(cc->name, name) == 0) return cc; } return NULL; } struct command *command_find_in_context(struct command_context *cmd_ctx, const char *name) { return command_find(cmd_ctx->commands, name); } struct command *command_find_in_parent(struct command *parent, const char *name) { return command_find(parent->children, name); } /** * Add the command into the linked list, sorted by name. * @param head Address to head of command list pointer, which may be * updated if @c c gets inserted at the beginning of the list. * @param c The command to add to the list pointed to by @c head. */ static void command_add_child(struct command **head, struct command *c) { assert(head); if (NULL == *head) { *head = c; return; } while ((*head)->next && (strcmp(c->name, (*head)->name) > 0)) head = &(*head)->next; if (strcmp(c->name, (*head)->name) > 0) { c->next = (*head)->next; (*head)->next = c; } else { c->next = *head; *head = c; } } static struct command **command_list_for_parent( struct command_context *cmd_ctx, struct command *parent) { return parent ? &parent->children : &cmd_ctx->commands; } static void command_free(struct command *c) { /** @todo if command has a handler, unregister its jim command! */ while (NULL != c->children) { struct command *tmp = c->children; c->children = tmp->next; command_free(tmp); } if (c->name) free((void *)c->name); if (c->help) free((void *)c->help); if (c->usage) free((void *)c->usage); free(c); } static struct command *command_new(struct command_context *cmd_ctx, struct command *parent, const struct command_registration *cr) { assert(cr->name); /* * If it is a non-jim command with no .usage specified, * log an error. * * strlen(.usage) == 0 means that the command takes no * arguments. */ if ((cr->jim_handler == NULL) && (cr->usage == NULL)) { LOG_DEBUG("BUG: command '%s%s%s' does not have the " "'.usage' field filled out", parent && parent->name ? parent->name : "", parent && parent->name ? " " : "", cr->name); } struct command *c = calloc(1, sizeof(struct command)); if (NULL == c) return NULL; c->name = strdup(cr->name); if (cr->help) c->help = strdup(cr->help); if (cr->usage) c->usage = strdup(cr->usage); if (!c->name || (cr->help && !c->help) || (cr->usage && !c->usage)) goto command_new_error; c->parent = parent; c->handler = cr->handler; c->jim_handler = cr->jim_handler; c->jim_handler_data = cr->jim_handler_data; c->mode = cr->mode; command_add_child(command_list_for_parent(cmd_ctx, parent), c); return c; command_new_error: command_free(c); return NULL; } static int command_unknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv); static int register_command_handler(struct command_context *cmd_ctx, struct command *c) { Jim_Interp *interp = cmd_ctx->interp; const char *ocd_name = alloc_printf("ocd_%s", c->name); if (NULL == ocd_name) return JIM_ERR; LOG_DEBUG("registering '%s'...", ocd_name); Jim_CmdProc func = c->handler ? &script_command : &command_unknown; int retval = Jim_CreateCommand(interp, ocd_name, func, c, NULL); free((void *)ocd_name); if (JIM_OK != retval) return retval; /* we now need to add an overrideable proc */ const char *override_name = alloc_printf( "proc %s {args} {eval ocd_bouncer %s $args}", c->name, c->name); if (NULL == override_name) return JIM_ERR; retval = Jim_Eval_Named(interp, override_name, 0, 0); free((void *)override_name); return retval; } struct command *register_command(struct command_context *context, struct command *parent, const struct command_registration *cr) { if (!context || !cr->name) return NULL; const char *name = cr->name; struct command **head = command_list_for_parent(context, parent); struct command *c = command_find(*head, name); if (NULL != c) { /* TODO: originally we treated attempting to register a cmd twice as an error * Sometimes we need this behaviour, such as with flash banks. * http://www.mail-archive.com/openocd-development@lists.berlios.de/msg11152.html */ LOG_DEBUG("command '%s' is already registered in '%s' context", name, parent ? parent->name : ""); return c; } c = command_new(context, parent, cr); if (NULL == c) return NULL; int retval = ERROR_OK; if (NULL != cr->jim_handler && NULL == parent) { retval = Jim_CreateCommand(context->interp, cr->name, cr->jim_handler, cr->jim_handler_data, NULL); } else if (NULL != cr->handler || NULL != parent) retval = register_command_handler(context, command_root(c)); if (ERROR_OK != retval) { unregister_command(context, parent, name); c = NULL; } return c; } int register_commands(struct command_context *cmd_ctx, struct command *parent, const struct command_registration *cmds) { int retval = ERROR_OK; unsigned i; for (i = 0; cmds[i].name || cmds[i].chain; i++) { const struct command_registration *cr = cmds + i; struct command *c = NULL; if (NULL != cr->name) { c = register_command(cmd_ctx, parent, cr); if (NULL == c) { retval = ERROR_FAIL; break; } } if (NULL != cr->chain) { struct command *p = c ? : parent; retval = register_commands(cmd_ctx, p, cr->chain); if (ERROR_OK != retval) break; } } if (ERROR_OK != retval) { for (unsigned j = 0; j < i; j++) unregister_command(cmd_ctx, parent, cmds[j].name); } return retval; } int unregister_all_commands(struct command_context *context, struct command *parent) { if (context == NULL) return ERROR_OK; struct command **head = command_list_for_parent(context, parent); while (NULL != *head) { struct command *tmp = *head; *head = tmp->next; command_free(tmp); } return ERROR_OK; } int unregister_command(struct command_context *context, struct command *parent, const char *name) { if ((!context) || (!name)) return ERROR_COMMAND_SYNTAX_ERROR; struct command *p = NULL; struct command **head = command_list_for_parent(context, parent); for (struct command *c = *head; NULL != c; p = c, c = c->next) { if (strcmp(name, c->name) != 0) continue; if (p) p->next = c->next; else *head = c->next; command_free(c); return ERROR_OK; } return ERROR_OK; } void command_set_handler_data(struct command *c, void *p) { if (NULL != c->handler || NULL != c->jim_handler) c->jim_handler_data = p; for (struct command *cc = c->children; NULL != cc; cc = cc->next) command_set_handler_data(cc, p); } void command_output_text(struct command_context *context, const char *data) { if (context && context->output_handler && data) context->output_handler(context, data); } void command_print_sameline(struct command_context *context, const char *format, ...) { char *string; va_list ap; va_start(ap, format); string = alloc_vprintf(format, ap); if (string != NULL) { /* we want this collected in the log + we also want to pick it up as a tcl return * value. * * The latter bit isn't precisely neat, but will do for now. */ LOG_USER_N("%s", string); /* We already printed it above * command_output_text(context, string); */ free(string); } va_end(ap); } void command_print(struct command_context *context, const char *format, ...) { char *string; va_list ap; va_start(ap, format); string = alloc_vprintf(format, ap); if (string != NULL) { strcat(string, "\n"); /* alloc_vprintf guaranteed the buffer to be at least one *char longer */ /* we want this collected in the log + we also want to pick it up as a tcl return * value. * * The latter bit isn't precisely neat, but will do for now. */ LOG_USER_N("%s", string); /* We already printed it above * command_output_text(context, string); */ free(string); } va_end(ap); } static char *__command_name(struct command *c, char delim, unsigned extra) { char *name; unsigned len = strlen(c->name); if (NULL == c->parent) { /* allocate enough for the name, child names, and '\0' */ name = malloc(len + extra + 1); strcpy(name, c->name); } else { /* parent's extra must include both the space and name */ name = __command_name(c->parent, delim, 1 + len + extra); char dstr[2] = { delim, 0 }; strcat(name, dstr); strcat(name, c->name); } return name; } char *command_name(struct command *c, char delim) { return __command_name(c, delim, 0); } static bool command_can_run(struct command_context *cmd_ctx, struct command *c) { return c->mode == COMMAND_ANY || c->mode == cmd_ctx->mode; } static int run_command(struct command_context *context, struct command *c, const char *words[], unsigned num_words) { if (!command_can_run(context, c)) { /* Many commands may be run only before/after 'init' */ const char *when; switch (c->mode) { case COMMAND_CONFIG: when = "before"; break; case COMMAND_EXEC: when = "after"; break; /* handle the impossible with humor; it guarantees a bug report! */ default: when = "if Cthulhu is summoned by"; break; } LOG_ERROR("The '%s' command must be used %s 'init'.", c->name, when); return ERROR_FAIL; } struct command_invocation cmd = { .ctx = context, .current = c, .name = c->name, .argc = num_words - 1, .argv = words + 1, }; int retval = c->handler(&cmd); if (retval == ERROR_COMMAND_SYNTAX_ERROR) { /* Print help for command */ char *full_name = command_name(c, ' '); if (NULL != full_name) { command_run_linef(context, "usage %s", full_name); free(full_name); } else retval = -ENOMEM; } else if (retval == ERROR_COMMAND_CLOSE_CONNECTION) { /* just fall through for a shutdown request */ } else if (retval != ERROR_OK) { /* we do not print out an error message because the command *should* * have printed out an error */ LOG_DEBUG("Command failed with error code %d", retval); } return retval; } int command_run_line(struct command_context *context, char *line) { /* all the parent commands have been registered with the interpreter * so, can just evaluate the line as a script and check for * results */ /* run the line thru a script engine */ int retval = ERROR_FAIL; int retcode; /* Beware! This code needs to be reentrant. It is also possible * for OpenOCD commands to be invoked directly from Tcl. This would * happen when the Jim Tcl interpreter is provided by eCos for * instance. */ Jim_Interp *interp = context->interp; Jim_DeleteAssocData(interp, "context"); retcode = Jim_SetAssocData(interp, "context", NULL, context); if (retcode == JIM_OK) { /* associated the return value */ Jim_DeleteAssocData(interp, "retval"); retcode = Jim_SetAssocData(interp, "retval", NULL, &retval); if (retcode == JIM_OK) { retcode = Jim_Eval_Named(interp, line, 0, 0); Jim_DeleteAssocData(interp, "retval"); } Jim_DeleteAssocData(interp, "context"); } if (retcode == JIM_ERR) { if (retval != ERROR_COMMAND_CLOSE_CONNECTION) { /* We do not print the connection closed error message */ Jim_MakeErrorMessage(interp); LOG_USER("%s", Jim_GetString(Jim_GetResult(interp), NULL)); } if (retval == ERROR_OK) { /* It wasn't a low level OpenOCD command that failed */ return ERROR_FAIL; } return retval; } else if (retcode == JIM_EXIT) { /* ignore. * exit(Jim_GetExitCode(interp)); */ } else { const char *result; int reslen; result = Jim_GetString(Jim_GetResult(interp), &reslen); if (reslen > 0) { int i; char buff[256 + 1]; for (i = 0; i < reslen; i += 256) { int chunk; chunk = reslen - i; if (chunk > 256) chunk = 256; strncpy(buff, result + i, chunk); buff[chunk] = 0; LOG_USER_N("%s", buff); } LOG_USER_N("\n"); } retval = ERROR_OK; } return retval; } int command_run_linef(struct command_context *context, const char *format, ...) { int retval = ERROR_FAIL; char *string; va_list ap; va_start(ap, format); string = alloc_vprintf(format, ap); if (string != NULL) { retval = command_run_line(context, string); free(string); } va_end(ap); return retval; } void command_set_output_handler(struct command_context *context, command_output_handler_t output_handler, void *priv) { context->output_handler = output_handler; context->output_handler_priv = priv; } struct command_context *copy_command_context(struct command_context *context) { struct command_context *copy_context = malloc(sizeof(struct command_context)); *copy_context = *context; return copy_context; } void command_done(struct command_context *cmd_ctx) { if (NULL == cmd_ctx) return; free(cmd_ctx); } /* find full path to file */ static int jim_find(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 2) return JIM_ERR; const char *file = Jim_GetString(argv[1], NULL); char *full_path = find_file(file); if (full_path == NULL) return JIM_ERR; Jim_Obj *result = Jim_NewStringObj(interp, full_path, strlen(full_path)); free(full_path); Jim_SetResult(interp, result); return JIM_OK; } COMMAND_HANDLER(jim_echo) { if (CMD_ARGC == 2 && !strcmp(CMD_ARGV[0], "-n")) { LOG_USER_N("%s", CMD_ARGV[1]); return JIM_OK; } if (CMD_ARGC != 1) return JIM_ERR; LOG_USER("%s", CMD_ARGV[0]); return JIM_OK; } /* Capture progress output and return as tcl return value. If the * progress output was empty, return tcl return value. */ static int jim_capture(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 2) return JIM_ERR; struct log_capture_state *state = command_log_capture_start(interp); /* disable polling during capture. This avoids capturing output * from polling. * * This is necessary in order to avoid accidentally getting a non-empty * string for tcl fn's. */ bool save_poll = jtag_poll_get_enabled(); jtag_poll_set_enabled(false); const char *str = Jim_GetString(argv[1], NULL); int retcode = Jim_Eval_Named(interp, str, __THIS__FILE__, __LINE__); jtag_poll_set_enabled(save_poll); command_log_capture_finish(state); return retcode; } static COMMAND_HELPER(command_help_find, struct command *head, struct command **out) { if (0 == CMD_ARGC) return ERROR_COMMAND_SYNTAX_ERROR; *out = command_find(head, CMD_ARGV[0]); if (NULL == *out && strncmp(CMD_ARGV[0], "ocd_", 4) == 0) *out = command_find(head, CMD_ARGV[0] + 4); if (NULL == *out) return ERROR_COMMAND_SYNTAX_ERROR; if (--CMD_ARGC == 0) return ERROR_OK; CMD_ARGV++; return CALL_COMMAND_HANDLER(command_help_find, (*out)->children, out); } static COMMAND_HELPER(command_help_show, struct command *c, unsigned n, bool show_help, const char *match); static COMMAND_HELPER(command_help_show_list, struct command *head, unsigned n, bool show_help, const char *match) { for (struct command *c = head; NULL != c; c = c->next) CALL_COMMAND_HANDLER(command_help_show, c, n, show_help, match); return ERROR_OK; } #define HELP_LINE_WIDTH(_n) (int)(76 - (2 * _n)) static void command_help_show_indent(unsigned n) { for (unsigned i = 0; i < n; i++) LOG_USER_N(" "); } static void command_help_show_wrap(const char *str, unsigned n, unsigned n2) { const char *cp = str, *last = str; while (*cp) { const char *next = last; do { cp = next; do { next++; } while (*next != ' ' && *next != '\t' && *next != '\0'); } while ((next - last < HELP_LINE_WIDTH(n)) && *next != '\0'); if (next - last < HELP_LINE_WIDTH(n)) cp = next; command_help_show_indent(n); LOG_USER("%.*s", (int)(cp - last), last); last = cp + 1; n = n2; } } static COMMAND_HELPER(command_help_show, struct command *c, unsigned n, bool show_help, const char *match) { char *cmd_name = command_name(c, ' '); if (NULL == cmd_name) return -ENOMEM; /* If the match string occurs anywhere, we print out * stuff for this command. */ bool is_match = (strstr(cmd_name, match) != NULL) || ((c->usage != NULL) && (strstr(c->usage, match) != NULL)) || ((c->help != NULL) && (strstr(c->help, match) != NULL)); if (is_match) { command_help_show_indent(n); LOG_USER_N("%s", cmd_name); } free(cmd_name); if (is_match) { if (c->usage) { LOG_USER_N(" "); command_help_show_wrap(c->usage, 0, n + 5); } else LOG_USER_N("\n"); } if (is_match && show_help) { char *msg; /* Normal commands are runtime-only; highlight exceptions */ if (c->mode != COMMAND_EXEC) { const char *stage_msg = ""; switch (c->mode) { case COMMAND_CONFIG: stage_msg = " (configuration command)"; break; case COMMAND_ANY: stage_msg = " (command valid any time)"; break; default: stage_msg = " (?mode error?)"; break; } msg = alloc_printf("%s%s", c->help ? : "", stage_msg); } else msg = alloc_printf("%s", c->help ? : ""); if (NULL != msg) { command_help_show_wrap(msg, n + 3, n + 3); free(msg); } else return -ENOMEM; } if (++n > 5) { LOG_ERROR("command recursion exceeded"); return ERROR_FAIL; } return CALL_COMMAND_HANDLER(command_help_show_list, c->children, n, show_help, match); } COMMAND_HANDLER(handle_help_command) { bool full = strcmp(CMD_NAME, "help") == 0; int retval; struct command *c = CMD_CTX->commands; char *match = NULL; if (CMD_ARGC == 0) match = ""; else if (CMD_ARGC >= 1) { unsigned i; for (i = 0; i < CMD_ARGC; ++i) { if (NULL != match) { char *prev = match; match = alloc_printf("%s %s", match, CMD_ARGV[i]); free(prev); if (NULL == match) { LOG_ERROR("unable to build search string"); return -ENOMEM; } } else { match = alloc_printf("%s", CMD_ARGV[i]); if (NULL == match) { LOG_ERROR("unable to build search string"); return -ENOMEM; } } } } else return ERROR_COMMAND_SYNTAX_ERROR; retval = CALL_COMMAND_HANDLER(command_help_show_list, c, 0, full, match); if (CMD_ARGC >= 1) free(match); return retval; } static int command_unknown_find(unsigned argc, Jim_Obj *const *argv, struct command *head, struct command **out, bool top_level) { if (0 == argc) return argc; const char *cmd_name = Jim_GetString(argv[0], NULL); struct command *c = command_find(head, cmd_name); if (NULL == c && top_level && strncmp(cmd_name, "ocd_", 4) == 0) c = command_find(head, cmd_name + 4); if (NULL == c) return argc; *out = c; return command_unknown_find(--argc, ++argv, (*out)->children, out, false); } static int command_unknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { const char *cmd_name = Jim_GetString(argv[0], NULL); if (strcmp(cmd_name, "unknown") == 0) { if (argc == 1) return JIM_OK; argc--; argv++; } script_debug(interp, cmd_name, argc, argv); struct command_context *cmd_ctx = current_command_context(interp); struct command *c = cmd_ctx->commands; int remaining = command_unknown_find(argc, argv, c, &c, true); /* if nothing could be consumed, then it's really an unknown command */ if (remaining == argc) { const char *cmd = Jim_GetString(argv[0], NULL); LOG_ERROR("Unknown command:\n %s", cmd); return JIM_OK; } bool found = true; Jim_Obj *const *start; unsigned count; if (c->handler || c->jim_handler) { /* include the command name in the list */ count = remaining + 1; start = argv + (argc - remaining - 1); } else { c = command_find(cmd_ctx->commands, "usage"); if (NULL == c) { LOG_ERROR("unknown command, but usage is missing too"); return JIM_ERR; } count = argc - remaining; start = argv; found = false; } /* pass the command through to the intended handler */ if (c->jim_handler) { interp->cmdPrivData = c->jim_handler_data; return (*c->jim_handler)(interp, count, start); } return script_command_run(interp, count, start, c, found); } static int jim_command_mode(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { struct command_context *cmd_ctx = current_command_context(interp); enum command_mode mode; if (argc > 1) { struct command *c = cmd_ctx->commands; int remaining = command_unknown_find(argc - 1, argv + 1, c, &c, true); /* if nothing could be consumed, then it's an unknown command */ if (remaining == argc - 1) { Jim_SetResultString(interp, "unknown", -1); return JIM_OK; } mode = c->mode; } else mode = cmd_ctx->mode; const char *mode_str; switch (mode) { case COMMAND_ANY: mode_str = "any"; break; case COMMAND_CONFIG: mode_str = "config"; break; case COMMAND_EXEC: mode_str = "exec"; break; default: mode_str = "unknown"; break; } Jim_SetResultString(interp, mode_str, -1); return JIM_OK; } static int jim_command_type(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (1 == argc) return JIM_ERR; struct command_context *cmd_ctx = current_command_context(interp); struct command *c = cmd_ctx->commands; int remaining = command_unknown_find(argc - 1, argv + 1, c, &c, true); /* if nothing could be consumed, then it's an unknown command */ if (remaining == argc - 1) { Jim_SetResultString(interp, "unknown", -1); return JIM_OK; } if (c->jim_handler) Jim_SetResultString(interp, "native", -1); else if (c->handler) Jim_SetResultString(interp, "simple", -1); else Jim_SetResultString(interp, "group", -1); return JIM_OK; } int help_add_command(struct command_context *cmd_ctx, struct command *parent, const char *cmd_name, const char *help_text, const char *usage) { struct command **head = command_list_for_parent(cmd_ctx, parent); struct command *nc = command_find(*head, cmd_name); if (NULL == nc) { /* add a new command with help text */ struct command_registration cr = { .name = cmd_name, .mode = COMMAND_ANY, .help = help_text, .usage = usage, }; nc = register_command(cmd_ctx, parent, &cr); if (NULL == nc) { LOG_ERROR("failed to add '%s' help text", cmd_name); return ERROR_FAIL; } LOG_DEBUG("added '%s' help text", cmd_name); return ERROR_OK; } if (help_text) { bool replaced = false; if (nc->help) { free((void *)nc->help); replaced = true; } nc->help = strdup(help_text); if (replaced) LOG_INFO("replaced existing '%s' help", cmd_name); else LOG_DEBUG("added '%s' help text", cmd_name); } if (usage) { bool replaced = false; if (nc->usage) { free((void *)nc->usage); replaced = true; } nc->usage = strdup(usage); if (replaced) LOG_INFO("replaced existing '%s' usage", cmd_name); else LOG_DEBUG("added '%s' usage text", cmd_name); } return ERROR_OK; } COMMAND_HANDLER(handle_help_add_command) { if (CMD_ARGC < 2) { LOG_ERROR("%s: insufficient arguments", CMD_NAME); return ERROR_COMMAND_SYNTAX_ERROR; } /* save help text and remove it from argument list */ const char *str = CMD_ARGV[--CMD_ARGC]; const char *help = !strcmp(CMD_NAME, "add_help_text") ? str : NULL; const char *usage = !strcmp(CMD_NAME, "add_usage_text") ? str : NULL; if (!help && !usage) { LOG_ERROR("command name '%s' is unknown", CMD_NAME); return ERROR_COMMAND_SYNTAX_ERROR; } /* likewise for the leaf command name */ const char *cmd_name = CMD_ARGV[--CMD_ARGC]; struct command *c = NULL; if (CMD_ARGC > 0) { c = CMD_CTX->commands; int retval = CALL_COMMAND_HANDLER(command_help_find, c, &c); if (ERROR_OK != retval) return retval; } return help_add_command(CMD_CTX, c, cmd_name, help, usage); } /* sleep command sleeps for milliseconds * this is useful in target startup scripts */ COMMAND_HANDLER(handle_sleep_command) { bool busy = false; if (CMD_ARGC == 2) { if (strcmp(CMD_ARGV[1], "busy") == 0) busy = true; else return ERROR_COMMAND_SYNTAX_ERROR; } else if (CMD_ARGC < 1 || CMD_ARGC > 2) return ERROR_COMMAND_SYNTAX_ERROR; unsigned long duration = 0; int retval = parse_ulong(CMD_ARGV[0], &duration); if (ERROR_OK != retval) return retval; if (!busy) { long long then = timeval_ms(); while (timeval_ms() - then < (long long)duration) { target_call_timer_callbacks_now(); usleep(1000); } } else busy_sleep(duration); return ERROR_OK; } static const struct command_registration command_subcommand_handlers[] = { { .name = "mode", .mode = COMMAND_ANY, .jim_handler = jim_command_mode, .usage = "[command_name ...]", .help = "Returns the command modes allowed by a command:" "'any', 'config', or 'exec'. If no command is" "specified, returns the current command mode. " "Returns 'unknown' if an unknown command is given. " "Command can be multiple tokens.", }, { .name = "type", .mode = COMMAND_ANY, .jim_handler = jim_command_type, .usage = "command_name [...]", .help = "Returns the type of built-in command:" "'native', 'simple', 'group', or 'unknown'. " "Command can be multiple tokens.", }, COMMAND_REGISTRATION_DONE }; static const struct command_registration command_builtin_handlers[] = { { .name = "echo", .handler = jim_echo, .mode = COMMAND_ANY, .help = "Logs a message at \"user\" priority. " "Output message to stdout. " "Option \"-n\" suppresses trailing newline", .usage = "[-n] string", }, { .name = "add_help_text", .handler = handle_help_add_command, .mode = COMMAND_ANY, .help = "Add new command help text; " "Command can be multiple tokens.", .usage = "command_name helptext_string", }, { .name = "add_usage_text", .handler = handle_help_add_command, .mode = COMMAND_ANY, .help = "Add new command usage text; " "command can be multiple tokens.", .usage = "command_name usage_string", }, { .name = "sleep", .handler = handle_sleep_command, .mode = COMMAND_ANY, .help = "Sleep for specified number of milliseconds. " "\"busy\" will busy wait instead (avoid this).", .usage = "milliseconds ['busy']", }, { .name = "help", .handler = handle_help_command, .mode = COMMAND_ANY, .help = "Show full command help; " "command can be multiple tokens.", .usage = "[command_name]", }, { .name = "usage", .handler = handle_help_command, .mode = COMMAND_ANY, .help = "Show basic command usage; " "command can be multiple tokens.", .usage = "[command_name]", }, { .name = "command", .mode = COMMAND_ANY, .help = "core command group (introspection)", .chain = command_subcommand_handlers, }, COMMAND_REGISTRATION_DONE }; struct command_context *command_init(const char *startup_tcl, Jim_Interp *interp) { struct command_context *context = malloc(sizeof(struct command_context)); const char *HostOs; context->mode = COMMAND_EXEC; context->commands = NULL; context->current_target = 0; context->output_handler = NULL; context->output_handler_priv = NULL; /* Create a jim interpreter if we were not handed one */ if (interp == NULL) { /* Create an interpreter */ interp = Jim_CreateInterp(); /* Add all the Jim core commands */ Jim_RegisterCoreCommands(interp); Jim_InitStaticExtensions(interp); } context->interp = interp; /* Stick to lowercase for HostOS strings. */ #if defined(_MSC_VER) /* WinXX - is generic, the forward * looking problem is this: * * "win32" or "win64" * * "winxx" is generic. */ HostOs = "winxx"; #elif defined(__linux__) HostOs = "linux"; #elif defined(__APPLE__) || defined(__DARWIN__) HostOs = "darwin"; #elif defined(__CYGWIN__) HostOs = "cygwin"; #elif defined(__MINGW32__) HostOs = "mingw32"; #elif defined(__ECOS) HostOs = "ecos"; #elif defined(__FreeBSD__) HostOs = "freebsd"; #elif defined(__NetBSD__) HostOs = "netbsd"; #elif defined(__OpenBSD__) HostOs = "openbsd"; #else #warning "Unrecognized host OS..." HostOs = "other"; #endif Jim_SetGlobalVariableStr(interp, "ocd_HOSTOS", Jim_NewStringObj(interp, HostOs, strlen(HostOs))); Jim_CreateCommand(interp, "ocd_find", jim_find, NULL, NULL); Jim_CreateCommand(interp, "capture", jim_capture, NULL, NULL); register_commands(context, NULL, command_builtin_handlers); Jim_SetAssocData(interp, "context", NULL, context); if (Jim_Eval_Named(interp, startup_tcl, "embedded:startup.tcl", 1) == JIM_ERR) { LOG_ERROR("Failed to run startup.tcl (embedded into OpenOCD)"); Jim_MakeErrorMessage(interp); LOG_USER_N("%s", Jim_GetString(Jim_GetResult(interp), NULL)); exit(-1); } Jim_DeleteAssocData(interp, "context"); return context; } int command_context_mode(struct command_context *cmd_ctx, enum command_mode mode) { if (!cmd_ctx) return ERROR_COMMAND_SYNTAX_ERROR; cmd_ctx->mode = mode; return ERROR_OK; } void process_jim_events(struct command_context *cmd_ctx) { static int recursion; if (recursion) return; recursion++; Jim_ProcessEvents(cmd_ctx->interp, JIM_ALL_EVENTS | JIM_DONT_WAIT); recursion--; } #define DEFINE_PARSE_NUM_TYPE(name, type, func, min, max) \ int parse ## name(const char *str, type * ul) \ { \ if (!*str) { \ LOG_ERROR("Invalid command argument"); \ return ERROR_COMMAND_ARGUMENT_INVALID; \ } \ char *end; \ *ul = func(str, &end, 0); \ if (*end) { \ LOG_ERROR("Invalid command argument"); \ return ERROR_COMMAND_ARGUMENT_INVALID; \ } \ if ((max == *ul) && (ERANGE == errno)) { \ LOG_ERROR("Argument overflow"); \ return ERROR_COMMAND_ARGUMENT_OVERFLOW; \ } \ if (min && (min == *ul) && (ERANGE == errno)) { \ LOG_ERROR("Argument underflow"); \ return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \ } \ return ERROR_OK; \ } DEFINE_PARSE_NUM_TYPE(_ulong, unsigned long, strtoul, 0, ULONG_MAX) DEFINE_PARSE_NUM_TYPE(_ullong, unsigned long long, strtoull, 0, ULLONG_MAX) DEFINE_PARSE_NUM_TYPE(_long, long, strtol, LONG_MIN, LONG_MAX) DEFINE_PARSE_NUM_TYPE(_llong, long long, strtoll, LLONG_MIN, LLONG_MAX) #define DEFINE_PARSE_WRAPPER(name, type, min, max, functype, funcname) \ int parse ## name(const char *str, type * ul) \ { \ functype n; \ int retval = parse ## funcname(str, &n); \ if (ERROR_OK != retval) \ return retval; \ if (n > max) \ return ERROR_COMMAND_ARGUMENT_OVERFLOW; \ if (min) \ return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \ *ul = n; \ return ERROR_OK; \ } #define DEFINE_PARSE_ULONG(name, type, min, max) \ DEFINE_PARSE_WRAPPER(name, type, min, max, unsigned long, _ulong) DEFINE_PARSE_ULONG(_uint, unsigned, 0, UINT_MAX) DEFINE_PARSE_ULONG(_u32, uint32_t, 0, UINT32_MAX) DEFINE_PARSE_ULONG(_u16, uint16_t, 0, UINT16_MAX) DEFINE_PARSE_ULONG(_u8, uint8_t, 0, UINT8_MAX) #define DEFINE_PARSE_LONG(name, type, min, max) \ DEFINE_PARSE_WRAPPER(name, type, min, max, long, _long) DEFINE_PARSE_LONG(_int, int, n < INT_MIN, INT_MAX) DEFINE_PARSE_LONG(_s32, int32_t, n < INT32_MIN, INT32_MAX) DEFINE_PARSE_LONG(_s16, int16_t, n < INT16_MIN, INT16_MAX) DEFINE_PARSE_LONG(_s8, int8_t, n < INT8_MIN, INT8_MAX) static int command_parse_bool(const char *in, bool *out, const char *on, const char *off) { if (strcasecmp(in, on) == 0) *out = true; else if (strcasecmp(in, off) == 0) *out = false; else return ERROR_COMMAND_SYNTAX_ERROR; return ERROR_OK; } int command_parse_bool_arg(const char *in, bool *out) { if (command_parse_bool(in, out, "on", "off") == ERROR_OK) return ERROR_OK; if (command_parse_bool(in, out, "enable", "disable") == ERROR_OK) return ERROR_OK; if (command_parse_bool(in, out, "true", "false") == ERROR_OK) return ERROR_OK; if (command_parse_bool(in, out, "yes", "no") == ERROR_OK) return ERROR_OK; if (command_parse_bool(in, out, "1", "0") == ERROR_OK) return ERROR_OK; return ERROR_COMMAND_SYNTAX_ERROR; } COMMAND_HELPER(handle_command_parse_bool, bool *out, const char *label) { switch (CMD_ARGC) { case 1: { const char *in = CMD_ARGV[0]; if (command_parse_bool_arg(in, out) != ERROR_OK) { LOG_ERROR("%s: argument '%s' is not valid", CMD_NAME, in); return ERROR_COMMAND_SYNTAX_ERROR; } /* fall through */ } case 0: LOG_INFO("%s is %s", label, *out ? "enabled" : "disabled"); break; default: return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; } openocd-0.7.0/src/helper/time_support.h0000644000175000001440000000561112134336410015033 00000000000000/*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef TIME_SUPPORT_H #define TIME_SUPPORT_H #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y); int timeval_add_time(struct timeval *result, long sec, long usec); /** @returns gettimeofday() timeval as 64-bit in ms */ int64_t timeval_ms(void); struct duration { struct timeval start; struct timeval elapsed; }; /** Update the duration->start field to start the @a duration measurement. */ int duration_start(struct duration *duration); /** Update the duration->elapsed field to finish the @a duration measurment. */ int duration_measure(struct duration *duration); /** @returns Elapsed time in seconds. */ float duration_elapsed(struct duration *duration); /** @returns KB/sec for the elapsed @a duration and @a count bytes. */ float duration_kbps(struct duration *duration, size_t count); #endif /* TIME_SUPPORT_H */ openocd-0.7.0/src/helper/configuration.h0000644000175000001440000000433212137151331015147 00000000000000/*************************************************************************** * Copyright (C) 2004, 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef CONFIGURATION_H #define CONFIGURATION_H #include int parse_cmdline_args(struct command_context *cmd_ctx, int argc, char *argv[]); int parse_config_file(struct command_context *cmd_ctx); void add_config_command(const char *cfg); void add_script_search_dir(const char *dir); int configuration_output_handler(struct command_context *cmd_ctx, const char *line); FILE *open_file_from_path(const char *file, const char *mode); char *find_file(const char *name); char *get_home_dir(const char *append_path); #endif /* CONFIGURATION_H */ openocd-0.7.0/src/helper/log.h0000644000175000001440000001262412134336410013064 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef ERROR_H #define ERROR_H #include /* To achieve C99 printf compatibility in MinGW, gnu_printf should be * used for __attribute__((format( ... ))), with GCC v4.4 or later */ #if (defined(IS_MINGW) && (((__GNUC__ << 16) + __GNUC_MINOR__) >= 0x00040004)) #define PRINTF_ATTRIBUTE_FORMAT gnu_printf #else #define PRINTF_ATTRIBUTE_FORMAT printf #endif /* logging priorities * LOG_LVL_SILENT - turn off all output. In lieu of try + catch this can be used as a * feeble ersatz. * LOG_LVL_USER - user messages. Could be anything from information * to progress messags. These messages do not represent * incorrect or unexpected behaviour, just normal execution. * LOG_LVL_ERROR - fatal errors, that are likely to cause program abort * LOG_LVL_WARNING - non-fatal errors, that may be resolved later * LOG_LVL_INFO - state information, etc. * LOG_LVL_DEBUG - debug statements, execution trace */ enum log_levels { LOG_LVL_SILENT = -3, LOG_LVL_OUTPUT = -2, LOG_LVL_USER = -1, LOG_LVL_ERROR = 0, LOG_LVL_WARNING = 1, LOG_LVL_INFO = 2, LOG_LVL_DEBUG = 3 }; void log_printf(enum log_levels level, const char *file, unsigned line, const char *function, const char *format, ...) __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 5, 6))); void log_printf_lf(enum log_levels level, const char *file, unsigned line, const char *function, const char *format, ...) __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 5, 6))); /** * Initialize logging module. Call during program startup. */ void log_init(void); int set_log_output(struct command_context *cmd_ctx, FILE *output); int log_register_commands(struct command_context *cmd_ctx); void keep_alive(void); void kept_alive(void); void alive_sleep(uint64_t ms); void busy_sleep(uint64_t ms); typedef void (*log_callback_fn)(void *priv, const char *file, unsigned line, const char *function, const char *string); struct log_callback { log_callback_fn fn; void *priv; struct log_callback *next; }; int log_add_callback(log_callback_fn fn, void *priv); int log_remove_callback(log_callback_fn fn, void *priv); char *alloc_vprintf(const char *fmt, va_list ap); char *alloc_printf(const char *fmt, ...); extern int debug_level; /* Avoid fn call and building parameter list if we're not outputting the information. * Matters on feeble CPUs for DEBUG/INFO statements that are involved frequently */ #define LOG_LEVEL_IS(FOO) ((debug_level) >= (FOO)) #define LOG_DEBUG(expr ...) \ do { \ if (debug_level >= LOG_LVL_DEBUG) \ log_printf_lf(LOG_LVL_DEBUG, \ __FILE__, __LINE__, __func__, \ expr); \ } while (0) #define LOG_INFO(expr ...) \ log_printf_lf(LOG_LVL_INFO, __FILE__, __LINE__, __func__, expr) #define LOG_WARNING(expr ...) \ log_printf_lf(LOG_LVL_WARNING, __FILE__, __LINE__, __func__, expr) #define LOG_ERROR(expr ...) \ log_printf_lf(LOG_LVL_ERROR, __FILE__, __LINE__, __func__, expr) #define LOG_USER(expr ...) \ log_printf_lf(LOG_LVL_USER, __FILE__, __LINE__, __func__, expr) #define LOG_USER_N(expr ...) \ log_printf(LOG_LVL_USER, __FILE__, __LINE__, __func__, expr) #define LOG_OUTPUT(expr ...) \ log_printf(LOG_LVL_OUTPUT, __FILE__, __LINE__, __func__, expr) /* general failures * error codes < 100 */ #define ERROR_OK (0) #define ERROR_NO_CONFIG_FILE (-2) #define ERROR_BUF_TOO_SMALL (-3) /* see "Error:" log entry for meaningful message to the user. The caller should * make no assumptions about what went wrong and try to handle the problem. */ #define ERROR_FAIL (-4) #endif /* LOG_H */ openocd-0.7.0/src/helper/fileio.c0000644000175000001440000001632112134336410013543 00000000000000/*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "log.h" #include "configuration.h" #include "fileio.h" struct fileio_internal { const char *url; ssize_t size; enum fileio_type type; enum fileio_access access; FILE *file; }; static inline int fileio_close_local(struct fileio_internal *fileio); static inline int fileio_open_local(struct fileio_internal *fileio) { char file_access[4]; switch (fileio->access) { case FILEIO_READ: strcpy(file_access, "r"); break; case FILEIO_WRITE: strcpy(file_access, "w"); break; case FILEIO_READWRITE: strcpy(file_access, "w+"); break; case FILEIO_APPEND: strcpy(file_access, "a"); break; case FILEIO_APPENDREAD: strcpy(file_access, "a+"); break; default: LOG_ERROR("BUG: access neither read, write nor readwrite"); return ERROR_COMMAND_SYNTAX_ERROR; } /* win32 always opens in binary mode */ #ifndef _WIN32 if (fileio->type == FILEIO_BINARY) #endif strcat(file_access, "b"); fileio->file = open_file_from_path(fileio->url, file_access); if (!fileio->file) { LOG_ERROR("couldn't open %s", fileio->url); return ERROR_FILEIO_OPERATION_FAILED; } if ((fileio->access != FILEIO_WRITE) || (fileio->access == FILEIO_READWRITE)) { /* NB! Here we use fseek() instead of stat(), since stat is a * more advanced operation that might not apply to e.g. a disk path * that refers to e.g. a tftp client */ int result, result2; result = fseek(fileio->file, 0, SEEK_END); fileio->size = ftell(fileio->file); result2 = fseek(fileio->file, 0, SEEK_SET); if ((fileio->size < 0) || (result < 0) || (result2 < 0)) { fileio_close_local(fileio); return ERROR_FILEIO_OPERATION_FAILED; } } else fileio->size = 0x0; return ERROR_OK; } int fileio_open(struct fileio *fileio_p, const char *url, enum fileio_access access_type, enum fileio_type type) { int retval = ERROR_OK; struct fileio_internal *fileio = malloc(sizeof(struct fileio_internal)); fileio_p->fp = fileio; fileio->type = type; fileio->access = access_type; fileio->url = strdup(url); retval = fileio_open_local(fileio); return retval; } static inline int fileio_close_local(struct fileio_internal *fileio) { int retval = fclose(fileio->file); if (retval != 0) { if (retval == EBADF) LOG_ERROR("BUG: fileio_local->file not a valid file descriptor"); else LOG_ERROR("couldn't close %s: %s", fileio->url, strerror(errno)); return ERROR_FILEIO_OPERATION_FAILED; } return ERROR_OK; } int fileio_close(struct fileio *fileio_p) { int retval; struct fileio_internal *fileio = fileio_p->fp; retval = fileio_close_local(fileio); free((void *)fileio->url); fileio->url = NULL; free(fileio); fileio_p->fp = NULL; return retval; } int fileio_seek(struct fileio *fileio_p, size_t position) { int retval; struct fileio_internal *fileio = fileio_p->fp; retval = fseek(fileio->file, position, SEEK_SET); if (retval != 0) { LOG_ERROR("couldn't seek file %s: %s", fileio->url, strerror(errno)); return ERROR_FILEIO_OPERATION_FAILED; } return ERROR_OK; } static int fileio_local_read(struct fileio_internal *fileio, size_t size, void *buffer, size_t *size_read) { ssize_t retval = fread(buffer, 1, size, fileio->file); *size_read = (retval >= 0) ? retval : 0; return (retval < 0) ? retval : ERROR_OK; } int fileio_read(struct fileio *fileio_p, size_t size, void *buffer, size_t *size_read) { struct fileio_internal *fileio = fileio_p->fp; return fileio_local_read(fileio, size, buffer, size_read); } int fileio_read_u32(struct fileio *fileio_p, uint32_t *data) { uint8_t buf[4]; size_t size_read; struct fileio_internal *fileio = fileio_p->fp; int retval = fileio_local_read(fileio, sizeof(uint32_t), buf, &size_read); if (ERROR_OK == retval && sizeof(uint32_t) != size_read) retval = -EIO; if (ERROR_OK == retval) *data = be_to_h_u32(buf); return retval; } static int fileio_local_fgets(struct fileio_internal *fileio, size_t size, void *buffer) { if (fgets(buffer, size, fileio->file) == NULL) return ERROR_FILEIO_OPERATION_FAILED; return ERROR_OK; } int fileio_fgets(struct fileio *fileio_p, size_t size, void *buffer) { struct fileio_internal *fileio = fileio_p->fp; return fileio_local_fgets(fileio, size, buffer); } static int fileio_local_write(struct fileio_internal *fileio, size_t size, const void *buffer, size_t *size_written) { ssize_t retval = fwrite(buffer, 1, size, fileio->file); *size_written = (retval >= 0) ? retval : 0; return (retval < 0) ? retval : ERROR_OK; } int fileio_write(struct fileio *fileio_p, size_t size, const void *buffer, size_t *size_written) { struct fileio_internal *fileio = fileio_p->fp; int retval = fileio_local_write(fileio, size, buffer, size_written); if (retval == ERROR_OK) fileio->size += *size_written; return retval; } int fileio_write_u32(struct fileio *fileio_p, uint32_t data) { uint8_t buf[4]; h_u32_to_be(buf, data); size_t size_written; int retval = fileio_write(fileio_p, 4, buf, &size_written); if (ERROR_OK == retval && size_written != sizeof(uint32_t)) retval = -EIO; return retval; } /** * FIX!!!! * * For now this can not fail, but that's because a seek was executed * on startup. * * Avoiding the seek on startup opens up for using streams. * */ int fileio_size(struct fileio *fileio_p, int *size) { struct fileio_internal *fileio = fileio_p->fp; *size = fileio->size; return ERROR_OK; } openocd-0.7.0/src/helper/options.c0000644000175000001440000001510412134336410013765 00000000000000/*************************************************************************** * Copyright (C) 2004, 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "configuration.h" /* @todo the inclusion of server.h here is a layering violation */ #include #include static int help_flag, version_flag; static const struct option long_options[] = { {"help", no_argument, &help_flag, 1}, {"version", no_argument, &version_flag, 1}, {"debug", optional_argument, 0, 'd'}, {"file", required_argument, 0, 'f'}, {"search", required_argument, 0, 's'}, {"log_output", required_argument, 0, 'l'}, {"command", required_argument, 0, 'c'}, {"pipe", no_argument, 0, 'p'}, {0, 0, 0, 0} }; int configuration_output_handler(struct command_context *context, const char *line) { LOG_USER_N("%s", line); return ERROR_OK; } static void add_default_dirs(void) { #ifdef _WIN32 char strExePath[MAX_PATH]; char *path; GetModuleFileName(NULL, strExePath, MAX_PATH); /* Strip executable file name, leaving path */ *strrchr(strExePath, '\\') = '\0'; /* Convert path separators to UNIX style, should work on Windows also. */ for (char *p = strExePath; *p; p++) { if (*p == '\\') *p = '/'; } /* Add the parent of the directory where openocd.exe resides to the * config script search path. * * bin/openocd.exe * interface/dummy.cfg * target/at91eb40a.cfg */ path = alloc_printf("%s%s", strExePath, "/.."); if (path) { add_script_search_dir(path); free(path); } /* Add support for the directory layout resulting from a 'make install'. * * bin/openocd.exe * share/openocd/scripts/interface/dummy.cfg * share/openocd/scripts/target/at91eb40a.cfg */ path = alloc_printf("%s%s", strExePath, "/../share/" PACKAGE "/scripts"); if (path) { add_script_search_dir(path); free(path); } /* Add single "scripts" folder to search path for Windows OpenOCD builds that don't use cygwin * * bin/openocd.exe * scripts/interface/dummy.cfg * scripts/target/at91eb40a.cfg */ path = alloc_printf("%s%s", strExePath, "/../scripts"); if (path) { add_script_search_dir(path); free(path); } #else /* * The directory containing OpenOCD-supplied scripts should be * listed last in the built-in search order, so the user can * override these scripts with site-specific customizations. */ const char *home = getenv("HOME"); if (home) { char *path; path = alloc_printf("%s/.openocd", home); if (path) { add_script_search_dir(path); free(path); } } add_script_search_dir(PKGDATADIR "/site"); add_script_search_dir(PKGDATADIR "/scripts"); #endif } int parse_cmdline_args(struct command_context *cmd_ctx, int argc, char *argv[]) { int c; char command_buffer[128]; while (1) { /* getopt_long stores the option index here. */ int option_index = 0; c = getopt_long(argc, argv, "hvd::l:f:s:c:p", long_options, &option_index); /* Detect the end of the options. */ if (c == -1) break; switch (c) { case 0: break; case 'h': /* --help | -h */ help_flag = 1; break; case 'v': /* --version | -v */ version_flag = 1; break; case 'f': /* --file | -f */ { snprintf(command_buffer, 128, "script {%s}", optarg); add_config_command(command_buffer); break; } case 's': /* --search | -s */ add_script_search_dir(optarg); break; case 'd': /* --debug | -d */ if (optarg) snprintf(command_buffer, 128, "debug_level %s", optarg); else snprintf(command_buffer, 128, "debug_level 3"); command_run_line(cmd_ctx, command_buffer); break; case 'l': /* --log_output | -l */ if (optarg) { snprintf(command_buffer, 128, "log_output %s", optarg); command_run_line(cmd_ctx, command_buffer); } break; case 'c': /* --command | -c */ if (optarg) add_config_command(optarg); break; case 'p': /* to replicate the old syntax this needs to be synchronous * otherwise the gdb stdin will overflow with the warning message */ command_run_line(cmd_ctx, "gdb_port pipe; log_output openocd.log"); LOG_WARNING("deprecated option: -p/--pipe. Use '-c \"gdb_port pipe; " "log_output openocd.log\"' instead."); break; } } if (help_flag) { LOG_OUTPUT("Open On-Chip Debugger\nLicensed under GNU GPL v2\n"); LOG_OUTPUT("--help | -h\tdisplay this help\n"); LOG_OUTPUT("--version | -v\tdisplay OpenOCD version\n"); LOG_OUTPUT("--file | -f\tuse configuration file \n"); LOG_OUTPUT("--search | -s\tdir to search for config files and scripts\n"); LOG_OUTPUT("--debug | -d\tset debug level <0-3>\n"); LOG_OUTPUT("--log_output | -l\tredirect log output to file \n"); LOG_OUTPUT("--command | -c\trun \n"); exit(-1); } if (version_flag) { /* Nothing to do, version gets printed automatically. */ /* It is not an error to request the VERSION number. */ exit(0); } /* paths specified on the command line take precedence over these * built-in paths */ add_default_dirs(); return ERROR_OK; } openocd-0.7.0/src/helper/list.h0000644000175000001440000005254212134336410013261 00000000000000#ifndef _LINUX_LIST_H #define _LINUX_LIST_H /* begin local changes */ #include #define prefetch(x) ((void)x) #define LIST_POISON1 NULL #define LIST_POISON2 NULL struct list_head { struct list_head *next, *prev; }; struct hlist_head { struct hlist_node *first; }; struct hlist_node { struct hlist_node *next, **pprev; }; /* end local changes */ /* * Simple doubly linked list implementation. * * Some of the internal functions ("__xxx") are useful when * manipulating whole lists rather than single entries, as * sometimes we already know the next/prev entries and we can * generate better code by using them directly rather than * using the generic single-entry routines. */ #define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name) static inline void INIT_LIST_HEAD(struct list_head *list) { list->next = list; list->prev = list; } /* * Insert a new entry between two known consecutive entries. * * This is only for internal list manipulation where we know * the prev/next entries already! */ #ifndef CONFIG_DEBUG_LIST static inline void __list_add(struct list_head *new, struct list_head *prev, struct list_head *next) { next->prev = new; new->next = next; new->prev = prev; prev->next = new; } #else extern void __list_add(struct list_head *new, struct list_head *prev, struct list_head *next); #endif /** * list_add - add a new entry * @new: new entry to be added * @head: list head to add it after * * Insert a new entry after the specified head. * This is good for implementing stacks. */ static inline void list_add(struct list_head *new, struct list_head *head) { __list_add(new, head, head->next); } /** * list_add_tail - add a new entry * @new: new entry to be added * @head: list head to add it before * * Insert a new entry before the specified head. * This is useful for implementing queues. */ static inline void list_add_tail(struct list_head *new, struct list_head *head) { __list_add(new, head->prev, head); } /* * Delete a list entry by making the prev/next entries * point to each other. * * This is only for internal list manipulation where we know * the prev/next entries already! */ static inline void __list_del(struct list_head *prev, struct list_head *next) { next->prev = prev; prev->next = next; } /** * list_del - deletes entry from list. * @entry: the element to delete from the list. * Note: list_empty() on entry does not return true after this, the entry is * in an undefined state. */ #ifndef CONFIG_DEBUG_LIST static inline void __list_del_entry(struct list_head *entry) { __list_del(entry->prev, entry->next); } static inline void list_del(struct list_head *entry) { __list_del(entry->prev, entry->next); entry->next = LIST_POISON1; entry->prev = LIST_POISON2; } #else extern void __list_del_entry(struct list_head *entry); extern void list_del(struct list_head *entry); #endif /** * list_replace - replace old entry by new one * @old : the element to be replaced * @new : the new element to insert * * If @old was empty, it will be overwritten. */ static inline void list_replace(struct list_head *old, struct list_head *new) { new->next = old->next; new->next->prev = new; new->prev = old->prev; new->prev->next = new; } static inline void list_replace_init(struct list_head *old, struct list_head *new) { list_replace(old, new); INIT_LIST_HEAD(old); } /** * list_del_init - deletes entry from list and reinitialize it. * @entry: the element to delete from the list. */ static inline void list_del_init(struct list_head *entry) { __list_del_entry(entry); INIT_LIST_HEAD(entry); } /** * list_move - delete from one list and add as another's head * @list: the entry to move * @head: the head that will precede our entry */ static inline void list_move(struct list_head *list, struct list_head *head) { __list_del_entry(list); list_add(list, head); } /** * list_move_tail - delete from one list and add as another's tail * @list: the entry to move * @head: the head that will follow our entry */ static inline void list_move_tail(struct list_head *list, struct list_head *head) { __list_del_entry(list); list_add_tail(list, head); } /** * list_is_last - tests whether @list is the last entry in list @head * @list: the entry to test * @head: the head of the list */ static inline int list_is_last(const struct list_head *list, const struct list_head *head) { return list->next == head; } /** * list_empty - tests whether a list is empty * @head: the list to test. */ static inline int list_empty(const struct list_head *head) { return head->next == head; } /** * list_empty_careful - tests whether a list is empty and not being modified * @head: the list to test * * Description: * tests whether a list is empty _and_ checks that no other CPU might be * in the process of modifying either member (next or prev) * * NOTE: using list_empty_careful() without synchronization * can only be safe if the only activity that can happen * to the list entry is list_del_init(). Eg. it cannot be used * if another CPU could re-list_add() it. */ static inline int list_empty_careful(const struct list_head *head) { struct list_head *next = head->next; return (next == head) && (next == head->prev); } /** * list_rotate_left - rotate the list to the left * @head: the head of the list */ static inline void list_rotate_left(struct list_head *head) { struct list_head *first; if (!list_empty(head)) { first = head->next; list_move_tail(first, head); } } /** * list_is_singular - tests whether a list has just one entry. * @head: the list to test. */ static inline int list_is_singular(const struct list_head *head) { return !list_empty(head) && (head->next == head->prev); } static inline void __list_cut_position(struct list_head *list, struct list_head *head, struct list_head *entry) { struct list_head *new_first = entry->next; list->next = head->next; list->next->prev = list; list->prev = entry; entry->next = list; head->next = new_first; new_first->prev = head; } /** * list_cut_position - cut a list into two * @list: a new list to add all removed entries * @head: a list with entries * @entry: an entry within head, could be the head itself * and if so we won't cut the list * * This helper moves the initial part of @head, up to and * including @entry, from @head to @list. You should * pass on @entry an element you know is on @head. @list * should be an empty list or a list you do not care about * losing its data. * */ static inline void list_cut_position(struct list_head *list, struct list_head *head, struct list_head *entry) { if (list_empty(head)) return; if (list_is_singular(head) && (head->next != entry && head != entry)) return; if (entry == head) INIT_LIST_HEAD(list); else __list_cut_position(list, head, entry); } static inline void __list_splice(const struct list_head *list, struct list_head *prev, struct list_head *next) { struct list_head *first = list->next; struct list_head *last = list->prev; first->prev = prev; prev->next = first; last->next = next; next->prev = last; } /** * list_splice - join two lists, this is designed for stacks * @list: the new list to add. * @head: the place to add it in the first list. */ static inline void list_splice(const struct list_head *list, struct list_head *head) { if (!list_empty(list)) __list_splice(list, head, head->next); } /** * list_splice_tail - join two lists, each list being a queue * @list: the new list to add. * @head: the place to add it in the first list. */ static inline void list_splice_tail(struct list_head *list, struct list_head *head) { if (!list_empty(list)) __list_splice(list, head->prev, head); } /** * list_splice_init - join two lists and reinitialise the emptied list. * @list: the new list to add. * @head: the place to add it in the first list. * * The list at @list is reinitialised */ static inline void list_splice_init(struct list_head *list, struct list_head *head) { if (!list_empty(list)) { __list_splice(list, head, head->next); INIT_LIST_HEAD(list); } } /** * list_splice_tail_init - join two lists and reinitialise the emptied list * @list: the new list to add. * @head: the place to add it in the first list. * * Each of the lists is a queue. * The list at @list is reinitialised */ static inline void list_splice_tail_init(struct list_head *list, struct list_head *head) { if (!list_empty(list)) { __list_splice(list, head->prev, head); INIT_LIST_HEAD(list); } } /** * list_entry - get the struct for this entry * @ptr: the &struct list_head pointer. * @type: the type of the struct this is embedded in. * @member: the name of the list_struct within the struct. */ #define list_entry(ptr, type, member) \ container_of(ptr, type, member) /** * list_first_entry - get the first element from a list * @ptr: the list head to take the element from. * @type: the type of the struct this is embedded in. * @member: the name of the list_struct within the struct. * * Note, that list is expected to be not empty. */ #define list_first_entry(ptr, type, member) \ list_entry((ptr)->next, type, member) /** * list_for_each - iterate over a list * @pos: the &struct list_head to use as a loop cursor. * @head: the head for your list. */ #define list_for_each(pos, head) \ for (pos = (head)->next; prefetch(pos->next), pos != (head); \ pos = pos->next) /** * __list_for_each - iterate over a list * @pos: the &struct list_head to use as a loop cursor. * @head: the head for your list. * * This variant differs from list_for_each() in that it's the * simplest possible list iteration code, no prefetching is done. * Use this for code that knows the list to be very short (empty * or 1 entry) most of the time. */ #define __list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); pos = pos->next) /** * list_for_each_prev - iterate over a list backwards * @pos: the &struct list_head to use as a loop cursor. * @head: the head for your list. */ #define list_for_each_prev(pos, head) \ for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \ pos = pos->prev) /** * list_for_each_safe - iterate over a list safe against removal of list entry * @pos: the &struct list_head to use as a loop cursor. * @n: another &struct list_head to use as temporary storage * @head: the head for your list. */ #define list_for_each_safe(pos, n, head) \ for (pos = (head)->next, n = pos->next; pos != (head); \ pos = n, n = pos->next) /** * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry * @pos: the &struct list_head to use as a loop cursor. * @n: another &struct list_head to use as temporary storage * @head: the head for your list. */ #define list_for_each_prev_safe(pos, n, head) \ for (pos = (head)->prev, n = pos->prev; \ prefetch(pos->prev), pos != (head); \ pos = n, n = pos->prev) /** * list_for_each_entry - iterate over list of given type * @pos: the type * to use as a loop cursor. * @head: the head for your list. * @member: the name of the list_struct within the struct. */ #define list_for_each_entry(pos, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member); \ prefetch(pos->member.next), &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member)) /** * list_for_each_entry_reverse - iterate backwards over list of given type. * @pos: the type * to use as a loop cursor. * @head: the head for your list. * @member: the name of the list_struct within the struct. */ #define list_for_each_entry_reverse(pos, head, member) \ for (pos = list_entry((head)->prev, typeof(*pos), member); \ prefetch(pos->member.prev), &pos->member != (head); \ pos = list_entry(pos->member.prev, typeof(*pos), member)) /** * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() * @pos: the type * to use as a start point * @head: the head of the list * @member: the name of the list_struct within the struct. * * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). */ #define list_prepare_entry(pos, head, member) \ ((pos) ? : list_entry(head, typeof(*pos), member)) /** * list_for_each_entry_continue - continue iteration over list of given type * @pos: the type * to use as a loop cursor. * @head: the head for your list. * @member: the name of the list_struct within the struct. * * Continue to iterate over list of given type, continuing after * the current position. */ #define list_for_each_entry_continue(pos, head, member) \ for (pos = list_entry(pos->member.next, typeof(*pos), member); \ prefetch(pos->member.next), &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member)) /** * list_for_each_entry_continue_reverse - iterate backwards from the given point * @pos: the type * to use as a loop cursor. * @head: the head for your list. * @member: the name of the list_struct within the struct. * * Start to iterate over list of given type backwards, continuing after * the current position. */ #define list_for_each_entry_continue_reverse(pos, head, member) \ for (pos = list_entry(pos->member.prev, typeof(*pos), member); \ prefetch(pos->member.prev), &pos->member != (head); \ pos = list_entry(pos->member.prev, typeof(*pos), member)) /** * list_for_each_entry_from - iterate over list of given type from the current point * @pos: the type * to use as a loop cursor. * @head: the head for your list. * @member: the name of the list_struct within the struct. * * Iterate over list of given type, continuing from current position. */ #define list_for_each_entry_from(pos, head, member) \ for (; prefetch(pos->member.next), &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member)) /** * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry * @pos: the type * to use as a loop cursor. * @n: another type * to use as temporary storage * @head: the head for your list. * @member: the name of the list_struct within the struct. */ #define list_for_each_entry_safe(pos, n, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member), \ n = list_entry(pos->member.next, typeof(*pos), member); \ &pos->member != (head); \ pos = n, n = list_entry(n->member.next, typeof(*n), member)) /** * list_for_each_entry_safe_continue - continue list iteration safe against removal * @pos: the type * to use as a loop cursor. * @n: another type * to use as temporary storage * @head: the head for your list. * @member: the name of the list_struct within the struct. * * Iterate over list of given type, continuing after current point, * safe against removal of list entry. */ #define list_for_each_entry_safe_continue(pos, n, head, member) \ for (pos = list_entry(pos->member.next, typeof(*pos), member), \ n = list_entry(pos->member.next, typeof(*pos), member); \ &pos->member != (head); \ pos = n, n = list_entry(n->member.next, typeof(*n), member)) /** * list_for_each_entry_safe_from - iterate over list from current point safe against removal * @pos: the type * to use as a loop cursor. * @n: another type * to use as temporary storage * @head: the head for your list. * @member: the name of the list_struct within the struct. * * Iterate over list of given type from current point, safe against * removal of list entry. */ #define list_for_each_entry_safe_from(pos, n, head, member) \ for (n = list_entry(pos->member.next, typeof(*pos), member); \ &pos->member != (head); \ pos = n, n = list_entry(n->member.next, typeof(*n), member)) /** * list_for_each_entry_safe_reverse - iterate backwards over list safe against removal * @pos: the type * to use as a loop cursor. * @n: another type * to use as temporary storage * @head: the head for your list. * @member: the name of the list_struct within the struct. * * Iterate backwards over list of given type, safe against removal * of list entry. */ #define list_for_each_entry_safe_reverse(pos, n, head, member) \ for (pos = list_entry((head)->prev, typeof(*pos), member), \ n = list_entry(pos->member.prev, typeof(*pos), member); \ &pos->member != (head); \ pos = n, n = list_entry(n->member.prev, typeof(*n), member)) /** * list_safe_reset_next - reset a stale list_for_each_entry_safe loop * @pos: the loop cursor used in the list_for_each_entry_safe loop * @n: temporary storage used in list_for_each_entry_safe * @member: the name of the list_struct within the struct. * * list_safe_reset_next is not safe to use in general if the list may be * modified concurrently (eg. the lock is dropped in the loop body). An * exception to this is if the cursor element (pos) is pinned in the list, * and list_safe_reset_next is called after re-taking the lock and before * completing the current iteration of the loop body. */ #define list_safe_reset_next(pos, n, member) \ n = list_entry(pos->member.next, typeof(*pos), member) /* * Double linked lists with a single pointer list head. * Mostly useful for hash tables where the two pointer list head is * too wasteful. * You lose the ability to access the tail in O(1). */ #define HLIST_HEAD_INIT { .first = NULL } #define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } #define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) static inline void INIT_HLIST_NODE(struct hlist_node *h) { h->next = NULL; h->pprev = NULL; } static inline int hlist_unhashed(const struct hlist_node *h) { return !h->pprev; } static inline int hlist_empty(const struct hlist_head *h) { return !h->first; } static inline void __hlist_del(struct hlist_node *n) { struct hlist_node *next = n->next; struct hlist_node **pprev = n->pprev; *pprev = next; if (next) next->pprev = pprev; } static inline void hlist_del(struct hlist_node *n) { __hlist_del(n); n->next = LIST_POISON1; n->pprev = LIST_POISON2; } static inline void hlist_del_init(struct hlist_node *n) { if (!hlist_unhashed(n)) { __hlist_del(n); INIT_HLIST_NODE(n); } } static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) { struct hlist_node *first = h->first; n->next = first; if (first) first->pprev = &n->next; h->first = n; n->pprev = &h->first; } /* next must be != NULL */ static inline void hlist_add_before(struct hlist_node *n, struct hlist_node *next) { n->pprev = next->pprev; n->next = next; next->pprev = &n->next; *(n->pprev) = n; } static inline void hlist_add_after(struct hlist_node *n, struct hlist_node *next) { next->next = n->next; n->next = next; next->pprev = &n->next; if (next->next) next->next->pprev = &next->next; } /* after that we'll appear to be on some hlist and hlist_del will work */ static inline void hlist_add_fake(struct hlist_node *n) { n->pprev = &n->next; } /* * Move a list from one list head to another. Fixup the pprev * reference of the first entry if it exists. */ static inline void hlist_move_list(struct hlist_head *old, struct hlist_head *new) { new->first = old->first; if (new->first) new->first->pprev = &new->first; old->first = NULL; } #define hlist_entry(ptr, type, member) container_of(ptr, type, member) #define hlist_for_each(pos, head) \ for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \ pos = pos->next) #define hlist_for_each_safe(pos, n, head) \ for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ pos = n) /** * hlist_for_each_entry - iterate over list of given type * @tpos: the type * to use as a loop cursor. * @pos: the &struct hlist_node to use as a loop cursor. * @head: the head for your list. * @member: the name of the hlist_node within the struct. */ #define hlist_for_each_entry(tpos, pos, head, member) \ for (pos = (head)->first; \ pos && ({ prefetch(pos->next); 1; }) && \ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; }); \ pos = pos->next) /** * hlist_for_each_entry_continue - iterate over a hlist continuing after current point * @tpos: the type * to use as a loop cursor. * @pos: the &struct hlist_node to use as a loop cursor. * @member: the name of the hlist_node within the struct. */ #define hlist_for_each_entry_continue(tpos, pos, member) \ for (pos = (pos)->next; \ pos && ({ prefetch(pos->next); 1; }) && \ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; }); \ pos = pos->next) /** * hlist_for_each_entry_from - iterate over a hlist continuing from current point * @tpos: the type * to use as a loop cursor. * @pos: the &struct hlist_node to use as a loop cursor. * @member: the name of the hlist_node within the struct. */ #define hlist_for_each_entry_from(tpos, pos, member) \ for (; pos && ({ prefetch(pos->next); 1; }) && \ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; }); \ pos = pos->next) /** * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry * @tpos: the type * to use as a loop cursor. * @pos: the &struct hlist_node to use as a loop cursor. * @n: another &struct hlist_node to use as temporary storage * @head: the head for your list. * @member: the name of the hlist_node within the struct. */ #define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ for (pos = (head)->first; \ pos && ({ n = pos->next; 1; }) && \ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; }); \ pos = n) #endif openocd-0.7.0/src/helper/command.h0000644000175000001440000004001112134336410013710 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef COMMAND_H #define COMMAND_H #include /* To achieve C99 printf compatibility in MinGW, gnu_printf should be * used for __attribute__((format( ... ))), with GCC v4.4 or later */ #if (defined(IS_MINGW) && (((__GNUC__ << 16) + __GNUC_MINOR__) >= 0x00040004)) #define PRINTF_ATTRIBUTE_FORMAT gnu_printf #else #define PRINTF_ATTRIBUTE_FORMAT printf #endif enum command_mode { COMMAND_EXEC, COMMAND_CONFIG, COMMAND_ANY, }; struct command_context; /** The type signature for command context's output handler. */ typedef int (*command_output_handler_t)(struct command_context *context, const char *line); struct command_context { Jim_Interp *interp; enum command_mode mode; struct command *commands; int current_target; command_output_handler_t output_handler; void *output_handler_priv; }; struct command; /** * When run_command is called, a new instance will be created on the * stack, filled with the proper values, and passed by reference to the * required COMMAND_HANDLER routine. */ struct command_invocation { struct command_context *ctx; struct command *current; const char *name; unsigned argc; const char **argv; }; /** * Command handlers may be defined with more parameters than the base * set provided by command.c. This macro uses C99 magic to allow * defining all such derivative types using this macro. */ #define __COMMAND_HANDLER(name, extra ...) \ int name(struct command_invocation *cmd, ## extra) /** * Use this to macro to call a command helper (or a nested handler). * It provides command handler authors protection against reordering or * removal of unused parameters. * * @b Note: This macro uses lexical capture to provide some arguments. * As a result, this macro should be used @b only within functions * defined by the COMMAND_HANDLER or COMMAND_HELPER macros. Those * macros provide the expected lexical context captured by this macro. * Furthermore, it should be used only from the top-level of handler or * helper function, or care must be taken to avoid redefining the same * variables in intervening scope(s) by accident. */ #define CALL_COMMAND_HANDLER(name, extra ...) \ name(cmd, ## extra) /** * Always use this macro to define new command handler functions. * It ensures the parameters are ordered, typed, and named properly, so * they be can be used by other macros (e.g. COMMAND_PARSE_NUMBER). * All command handler functions must be defined as static in scope. */ #define COMMAND_HANDLER(name) \ static __COMMAND_HANDLER(name) /** * Similar to COMMAND_HANDLER, except some parameters are expected. * A helper is globally-scoped because it may be shared between several * source files (e.g. the s3c24xx device command helper). */ #define COMMAND_HELPER(name, extra ...) __COMMAND_HANDLER(name, extra) /** * Use this macro to access the context of the command being handled, * rather than accessing the variable directly. It may be moved. */ #define CMD_CTX (cmd->ctx) /** * Use this macro to access the number of arguments for the command being * handled, rather than accessing the variable directly. It may be moved. */ #define CMD_ARGC (cmd->argc) /** * Use this macro to access the arguments for the command being handled, * rather than accessing the variable directly. It may be moved. */ #define CMD_ARGV (cmd->argv) /** * Use this macro to access the name of the command being handled, * rather than accessing the variable directly. It may be moved. */ #define CMD_NAME (cmd->name) /** * Use this macro to access the current command being handled, * rather than accessing the variable directly. It may be moved. */ #define CMD_CURRENT (cmd->current) /** * Use this macro to access the invoked command handler's data pointer, * rather than accessing the variable directly. It may be moved. */ #define CMD_DATA (CMD_CURRENT->jim_handler_data) /** * The type signature for command handling functions. They are * usually registered as part of command_registration, providing * a high-level means for executing a command. * * If the command fails, it *MUST* return a value != ERROR_OK * (many commands break this rule, patches welcome!) * * This is *especially* important for commands such as writing * to flash or verifying memory. The reason is that those commands * can be used by programs to determine if the operation succeded * or not. If the operation failed, then a program can try * an alternative approach. * * Returning ERROR_COMMAND_SYNTAX_ERROR will have the effect of * printing out the syntax of the command. */ typedef __COMMAND_HANDLER((*command_handler_t)); struct command { const char *name; const char *help; const char *usage; struct command *parent; struct command *children; command_handler_t handler; Jim_CmdProc jim_handler; void *jim_handler_data; enum command_mode mode; struct command *next; }; /** * @param c The command to be named. * @param delim The character to place between command names. * @returns A malloc'd string containing the full command name, * which may include one or more ancestor components. Multiple names * are separated by single spaces. The caller must free() the string * when done with it. */ char *command_name(struct command *c, char delim); /* * Commands should be registered by filling in one or more of these * structures and passing them to register_command(). * * A conventioal format should be used for help strings, to provide both * usage and basic information: * @code * "@ ... - some explanation text" * @endcode * * @param name The name of the command to register, which must not have * been registered previously in the intended context. * @param handler The callback function that will be called. If NULL, * then the command serves as a placeholder for its children or a script. * @param mode The command mode(s) in which this command may be run. * @param help The help text that will be displayed to the user. */ struct command_registration { const char *name; command_handler_t handler; Jim_CmdProc jim_handler; void *jim_handler_data; enum command_mode mode; const char *help; /** a string listing the options and arguments, required or optional */ const char *usage; /** * If non-NULL, the commands in @c chain will be registered in * the same context and scope of this registration record. * This allows modules to inherit lists commands from other * modules. */ const struct command_registration *chain; }; /** Use this as the last entry in an array of command_registration records. */ #define COMMAND_REGISTRATION_DONE { .name = NULL, .chain = NULL } /** * Register a command @c handler that can be called from scripts during * the execution @c mode specified. * * If @c parent is non-NULL, the new command will be registered as a * sub-command under it; otherwise, it will be available as a top-level * command. * * @param cmd_ctx The command_context in which to register the command. * @param parent Register this command as a child of this, or NULL to * register a top-level command. * @param rec A command_registration record that contains the desired * command parameters. * @returns The new command, if successful; otherwise, NULL. */ struct command *register_command(struct command_context *cmd_ctx, struct command *parent, const struct command_registration *rec); /** * Register one or more commands in the specified context, as children * of @c parent (or top-level commends, if NULL). In a registration's * record contains a non-NULL @c chain member and name is NULL, the * commands on the chain will be registered in the same context. * Otherwise, the chained commands are added as children of the command. * * @param cmd_ctx The command_context in which to register the command. * @param parent Register this command as a child of this, or NULL to * register a top-level command. * @param cmds Pointer to an array of command_registration records that * contains the desired command parameters. The last record must have * NULL for all fields. * @returns ERROR_OK on success; ERROR_FAIL if any registration fails. */ int register_commands(struct command_context *cmd_ctx, struct command *parent, const struct command_registration *cmds); /** * Unregisters command @c name from the given context, @c cmd_ctx. * @param cmd_ctx The context of the registered command. * @param parent The parent of the given command, or NULL. * @param name The name of the command to unregister. * @returns ERROR_OK on success, or an error code. */ int unregister_command(struct command_context *cmd_ctx, struct command *parent, const char *name); /** * Unregisters all commands from the specfied context. * @param cmd_ctx The context that will be cleared of registered commands. * @param parent If given, only clear commands from under this one command. * @returns ERROR_OK on success, or an error code. */ int unregister_all_commands(struct command_context *cmd_ctx, struct command *parent); struct command *command_find_in_context(struct command_context *cmd_ctx, const char *name); struct command *command_find_in_parent(struct command *parent, const char *name); /** * Update the private command data field for a command and all descendents. * This is used when creating a new heirarchy of commands that depends * on obtaining a dynamically created context. The value will be available * in command handlers by using the CMD_DATA macro. * @param c The command (group) whose data pointer(s) will be updated. * @param p The new data pointer to use for the command or its descendents. */ void command_set_handler_data(struct command *c, void *p); void command_set_output_handler(struct command_context *context, command_output_handler_t output_handler, void *priv); int command_context_mode(struct command_context *context, enum command_mode mode); /* Return the current command context associated with the Jim interpreter or * alternatively the global default command interpreter */ struct command_context *current_command_context(Jim_Interp *interp); /** * Creates a new command context using the startup TCL provided and * the existing Jim interpreter, if any. If interp == NULL, then command_init * creates a command interpreter. */ struct command_context *command_init(const char *startup_tcl, Jim_Interp *interp); /** * Creates a copy of an existing command context. This does not create * a deep copy of the command list, so modifications in one context will * affect all shared contexts. The caller must track reference counting * and ensure the commands are freed before destroying the last instance. * @param cmd_ctx The command_context that will be copied. * @returns A new command_context with the same state as the original. */ struct command_context *copy_command_context(struct command_context *cmd_ctx); /** * Frees the resources associated with a command context. The commands * are not removed, so unregister_all_commands() must be called first. * @param context The command_context that will be destroyed. */ void command_done(struct command_context *context); void command_print(struct command_context *context, const char *format, ...) __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 2, 3))); void command_print_sameline(struct command_context *context, const char *format, ...) __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 2, 3))); int command_run_line(struct command_context *context, char *line); int command_run_linef(struct command_context *context, const char *format, ...) __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 2, 3))); void command_output_text(struct command_context *context, const char *data); void process_jim_events(struct command_context *cmd_ctx); #define ERROR_COMMAND_CLOSE_CONNECTION (-600) #define ERROR_COMMAND_SYNTAX_ERROR (-601) #define ERROR_COMMAND_NOTFOUND (-602) #define ERROR_COMMAND_ARGUMENT_INVALID (-603) #define ERROR_COMMAND_ARGUMENT_OVERFLOW (-604) #define ERROR_COMMAND_ARGUMENT_UNDERFLOW (-605) int parse_ulong(const char *str, unsigned long *ul); int parse_ullong(const char *str, unsigned long long *ul); int parse_long(const char *str, long *ul); int parse_llong(const char *str, long long *ul); #define DECLARE_PARSE_WRAPPER(name, type) \ int parse ## name(const char *str, type * ul) DECLARE_PARSE_WRAPPER(_uint, unsigned); DECLARE_PARSE_WRAPPER(_u32, uint32_t); DECLARE_PARSE_WRAPPER(_u16, uint16_t); DECLARE_PARSE_WRAPPER(_u8, uint8_t); DECLARE_PARSE_WRAPPER(_int, int); DECLARE_PARSE_WRAPPER(_s32, int32_t); DECLARE_PARSE_WRAPPER(_s16, int16_t); DECLARE_PARSE_WRAPPER(_s8, int8_t); /** * @brief parses the string @a in into @a out as a @a type, or prints * a command error and passes the error code to the caller. If an error * does occur, the calling function will return the error code produced * by the parsing function (one of ERROR_COMMAND_ARGUMENT_*). * * This function may cause the calling function to return immediately, * so it should be used carefully to avoid leaking resources. In most * situations, parsing should be completed in full before proceding * to allocate resources, and this strategy will most prevents leaks. */ #define COMMAND_PARSE_NUMBER(type, in, out) \ do { \ int retval_macro_tmp = parse_ ## type(in, &(out)); \ if (ERROR_OK != retval_macro_tmp) { \ command_print(CMD_CTX, stringify(out) \ " option value ('%s') is not valid", in); \ return retval_macro_tmp; \ } \ } while (0) /** * Parse the string @c as a binary parameter, storing the boolean value * in @c out. The strings @c on and @c off are used to match different * strings for true and false options (e.g. "on" and "off" or * "enable" and "disable"). */ #define COMMAND_PARSE_BOOL(in, out, on, off) \ do { \ bool value; \ int retval_macro_tmp = command_parse_bool_arg(in, &value); \ if (ERROR_OK != retval_macro_tmp) { \ command_print(CMD_CTX, stringify(out) \ " option value ('%s') is not valid", in); \ command_print(CMD_CTX, " choices are '%s' or '%s'", \ on, off); \ return retval_macro_tmp; \ } \ out = value; \ } while (0) int command_parse_bool_arg(const char *in, bool *out); COMMAND_HELPER(handle_command_parse_bool, bool *out, const char *label); /** parses an on/off command argument */ #define COMMAND_PARSE_ON_OFF(in, out) \ COMMAND_PARSE_BOOL(in, out, "on", "off") /** parses an enable/disable command argument */ #define COMMAND_PARSE_ENABLE(in, out) \ COMMAND_PARSE_BOOL(in, out, "enable", "disable") void script_debug(Jim_Interp *interp, const char *cmd, unsigned argc, Jim_Obj * const *argv); #endif /* COMMAND_H */ openocd-0.7.0/src/helper/types.h0000644000175000001440000001551412134336410013450 00000000000000/*************************************************************************** * Copyright (C) 2004, 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef TYPES_H #define TYPES_H #include #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_INTTYPES_H #include #endif #ifdef HAVE_STDBOOL_H #include #else /* HAVE_STDBOOL_H */ #define __bool_true_false_are_defined 1 #ifndef HAVE__BOOL #ifndef __cplusplus #define false 0 #define true 1 typedef int _Bool; #else typedef bool _Bool; #endif /* __cplusplus */ #endif /* HAVE__BOOL */ #define bool _Bool #endif /* HAVE_STDBOOL_H */ /// turns a macro argument into a string constant #define stringify(s) __stringify(s) #define __stringify(s) #s /** * Compute the number of elements of a variable length array. * * const char *strs[] = { "a", "b", "c" }; * unsigned num_strs = ARRAY_SIZE(strs); * */ #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) /** * Cast a member of a structure out to the containing structure. * @param ptr The pointer to the member. * @param type The type of the container struct this is embedded in. * @param member The name of the member within the struct. * * This is a mechanism which is used throughout the Linux kernel. */ #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (void *) ( (char *)__mptr - offsetof(type,member) ) );}) /** * Rounds @c m up to the nearest multiple of @c n using division. * @param m The value to round up to @c n. * @param n Round @c m up to a multiple of this number. * @returns The rounded integer value. */ #define DIV_ROUND_UP(m, n) (((m) + (n) - 1) / (n)) /* DANGER!!!! here be dragons! * * Leave these fn's as byte accesses because it is safe * across architectures. Clever usage of 32 bit access * will create problems on some hosts. * * Note that the "buf" pointer in memory is probably unaligned. * * Were these functions to be re-written to take a 32 bit wide or 16 bit wide * memory access shortcut, then on some CPU's, i.e. ARM7, the 2 lsbytes of the address are * ignored for 32 bit access, whereas on other CPU's a 32 bit wide unaligned memory access * will cause an exception, and lastly on x86, an unaligned "greater than bytewide" * memory access works as if aligned. So what follows below will work for all * platforms and gives the compiler leeway to do its own platform specific optimizations. * * Again, note that the "buf" pointer in memory is probably unaligned. */ static inline uint32_t le_to_h_u32(const uint8_t* buf) { return (uint32_t)(buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24); } static inline uint32_t le_to_h_u24(const uint8_t* buf) { return (uint32_t)(buf[0] | buf[1] << 8 | buf[2] << 16); } static inline uint16_t le_to_h_u16(const uint8_t* buf) { return (uint16_t)(buf[0] | buf[1] << 8); } static inline uint32_t be_to_h_u32(const uint8_t* buf) { return (uint32_t)(buf[3] | buf[2] << 8 | buf[1] << 16 | buf[0] << 24); } static inline uint32_t be_to_h_u24(const uint8_t* buf) { return (uint32_t)(buf[2] | buf[1] << 8 | buf[0] << 16); } static inline uint16_t be_to_h_u16(const uint8_t* buf) { return (uint16_t)(buf[1] | buf[0] << 8); } static inline void h_u32_to_le(uint8_t* buf, int val) { buf[3] = (uint8_t) (val >> 24); buf[2] = (uint8_t) (val >> 16); buf[1] = (uint8_t) (val >> 8); buf[0] = (uint8_t) (val >> 0); } static inline void h_u32_to_be(uint8_t* buf, int val) { buf[0] = (uint8_t) (val >> 24); buf[1] = (uint8_t) (val >> 16); buf[2] = (uint8_t) (val >> 8); buf[3] = (uint8_t) (val >> 0); } static inline void h_u24_to_le(uint8_t* buf, int val) { buf[2] = (uint8_t) (val >> 16); buf[1] = (uint8_t) (val >> 8); buf[0] = (uint8_t) (val >> 0); } static inline void h_u24_to_be(uint8_t* buf, int val) { buf[0] = (uint8_t) (val >> 16); buf[1] = (uint8_t) (val >> 8); buf[2] = (uint8_t) (val >> 0); } static inline void h_u16_to_le(uint8_t* buf, int val) { buf[1] = (uint8_t) (val >> 8); buf[0] = (uint8_t) (val >> 0); } static inline void h_u16_to_be(uint8_t* buf, int val) { buf[0] = (uint8_t) (val >> 8); buf[1] = (uint8_t) (val >> 0); } #if defined(__ECOS) /* eCos plain lacks these definition... A series of upstream patches * could probably repair it, but it seems like too much work to be * worth it. */ #if !defined(_STDINT_H) #define PRIx32 "x" #define PRId32 "d" #define SCNx32 "x" #define PRIi32 "i" #define PRIu32 "u" #define PRId8 PRId32 #define SCNx64 "llx" #define PRIx64 "llx" typedef CYG_ADDRWORD intptr_t; typedef int64_t intmax_t; typedef uint64_t uintmax_t; #define INT8_MAX 0x7f #define INT8_MIN (-INT8_MAX - 1) # define UINT8_MAX (255) #define INT16_MAX 0x7fff #define INT16_MIN (-INT16_MAX - 1) # define UINT16_MAX (65535) #define INT32_MAX 0x7fffffffL #define INT32_MIN (-INT32_MAX - 1L) # define UINT32_MAX (4294967295U) #define INT64_MAX 0x7fffffffffffffffLL #define INT64_MIN (-INT64_MAX - 1LL) #define UINT64_MAX (__CONCAT(INT64_MAX, U) * 2ULL + 1ULL) #endif #ifndef LLONG_MAX #define ULLONG_MAX UINT64_C(0xFFFFFFFFFFFFFFFF) #define LLONG_MAX INT64_C(0x7FFFFFFFFFFFFFFF) #define LLONG_MIN ULLONG_MAX #endif #define ULLONG_MAX 18446744073709551615 /* C99, eCos is C90 compliant (with bits of C99) */ #define isblank(c) ((c) == ' ' || (c) == '\t') #endif #endif /* TYPES_H */ openocd-0.7.0/src/helper/binarybuffer.h0000644000175000001440000001413712134336410014762 00000000000000/*************************************************************************** * Copyright (C) 2004, 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef BINARYBUFFER_H #define BINARYBUFFER_H #include "list.h" /** @file * Support functions to access arbitrary bits in a byte array */ /** * Sets @c num bits in @c _buffer, starting at the @c first bit, * using the bits in @c value. This routine fast-paths writes * of little-endian, byte-aligned, 32-bit words. * @param _buffer The buffer whose bits will be set. * @param first The bit offset in @c _buffer to start writing (0-31). * @param num The number of bits from @c value to copy (1-32). * @param value Up to 32 bits that will be copied to _buffer. */ static inline void buf_set_u32(void *_buffer, unsigned first, unsigned num, uint32_t value) { uint8_t *buffer = (uint8_t *)_buffer; if ((num == 32) && (first == 0)) { buffer[3] = (value >> 24) & 0xff; buffer[2] = (value >> 16) & 0xff; buffer[1] = (value >> 8) & 0xff; buffer[0] = (value >> 0) & 0xff; } else { for (unsigned i = first; i < first + num; i++) { if (((value >> (i - first)) & 1) == 1) buffer[i / 8] |= 1 << (i % 8); else buffer[i / 8] &= ~(1 << (i % 8)); } } } /** * Retrieves @c num bits from @c _buffer, starting at the @c first bit, * returning the bits in a 32-bit word. This routine fast-paths reads * of little-endian, byte-aligned, 32-bit words. * @param _buffer The buffer whose bits will be read. * @param first The bit offset in @c _buffer to start reading (0-31). * @param num The number of bits from @c _buffer to read (1-32). * @returns Up to 32-bits that were read from @c _buffer. */ static inline uint32_t buf_get_u32(const void *_buffer, unsigned first, unsigned num) { uint8_t *buffer = (uint8_t *)_buffer; if ((num == 32) && (first == 0)) { return (((uint32_t)buffer[3]) << 24) | (((uint32_t)buffer[2]) << 16) | (((uint32_t)buffer[1]) << 8) | (((uint32_t)buffer[0]) << 0); } else { uint32_t result = 0; for (unsigned i = first; i < first + num; i++) { if (((buffer[i / 8] >> (i % 8)) & 1) == 1) result |= 1 << (i - first); } return result; } } /** * Inverts the ordering of bits inside a 32-bit word (e.g. 31..0 -> 0..31). * This routine can be used to flip smaller data types by using smaller * values for @c width. * @param value The word to flip. * @param width The number of bits in value (2-32). * @returns A 32-bit word with @c value in reversed bit-order. */ uint32_t flip_u32(uint32_t value, unsigned width); bool buf_cmp(const void *buf1, const void *buf2, unsigned size); bool buf_cmp_mask(const void *buf1, const void *buf2, const void *mask, unsigned size); /** * Copies @c size bits out of @c from and into @c to. Any extra * bits in the final byte will be set to zero. * @param from The buffer to copy into @c to. * @param to The buffer that will receive the copy of @c from. * @param size The number of bits to copy. */ void *buf_cpy(const void *from, void *to, unsigned size); /** * Set the contents of @c buf with @c count bits, all set to 1. * @param buf The buffer to fill with ones. * @param size The number of bits. * @returns The original buffer (@c buf). */ void *buf_set_ones(void *buf, unsigned size); void *buf_set_buf(const void *src, unsigned src_start, void *dst, unsigned dst_start, unsigned len); int str_to_buf(const char *str, unsigned len, void *bin_buf, unsigned buf_size, unsigned radix); char *buf_to_str(const void *buf, unsigned size, unsigned radix); /* read a uint32_t from a buffer in target memory endianness */ static inline uint32_t fast_target_buffer_get_u32(const void *p, bool le) { return le ? le_to_h_u32(p) : be_to_h_u32(p); } static inline void bit_copy(uint8_t *dst, unsigned dst_offset, const uint8_t *src, unsigned src_offset, unsigned bit_count) { buf_set_buf(src, src_offset, dst, dst_offset, bit_count); } struct bit_copy_queue { struct list_head list; }; struct bit_copy_queue_entry { uint8_t *dst; unsigned dst_offset; const uint8_t *src; unsigned src_offset; unsigned bit_count; struct list_head list; }; void bit_copy_queue_init(struct bit_copy_queue *q); int bit_copy_queued(struct bit_copy_queue *q, uint8_t *dst, unsigned dst_offset, const uint8_t *src, unsigned src_offset, unsigned bit_count); void bit_copy_execute(struct bit_copy_queue *q); void bit_copy_discard(struct bit_copy_queue *q); /* functions to convert to/from hex encoded buffer * used in ti-icdi driver and gdb server */ int unhexify(char *bin, const char *hex, int count); int hexify(char *hex, const char *bin, int count, int out_maxlen); #endif /* BINARYBUFFER_H */ openocd-0.7.0/src/helper/fileio.h0000644000175000001440000000667312134336410013561 00000000000000/*************************************************************************** * Copyright (C) 2007 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef FILEIO_H #define FILEIO_H #define FILEIO_MAX_ERROR_STRING (128) enum fileio_type { FILEIO_TEXT, FILEIO_BINARY, }; enum fileio_access { FILEIO_NONE, /* open without any access (invalid mode) */ FILEIO_READ, /* open for reading, position at beginning */ FILEIO_WRITE, /* open for writing, position at beginning */ FILEIO_READWRITE, /* open for writing, position at beginning, allow reading */ FILEIO_APPEND, /* open for writing, position at end */ FILEIO_APPENDREAD, /* open for writing, position at end, allow reading */ }; struct fileio { /* The structure is opaque */ struct fileio_internal *fp; }; int fileio_open(struct fileio *fileio, const char *url, enum fileio_access access_type, enum fileio_type type); int fileio_close(struct fileio *fileio); int fileio_seek(struct fileio *fileio, size_t position); int fileio_fgets(struct fileio *fileio, size_t size, void *buffer); int fileio_read(struct fileio *fileio, size_t size, void *buffer, size_t *size_read); int fileio_write(struct fileio *fileio, size_t size, const void *buffer, size_t *size_written); int fileio_read_u32(struct fileio *fileio, uint32_t *data); int fileio_write_u32(struct fileio *fileio, uint32_t data); int fileio_size(struct fileio *fileio, int *size); #define ERROR_FILEIO_LOCATION_UNKNOWN (-1200) #define ERROR_FILEIO_NOT_FOUND (-1201) #define ERROR_FILEIO_OPERATION_FAILED (-1202) #define ERROR_FILEIO_ACCESS_NOT_SUPPORTED (-1203) #define ERROR_FILEIO_RESOURCE_TYPE_UNKNOWN (-1204) #define ERROR_FILEIO_OPERATION_NOT_SUPPORTED (-1205) #endif /* FILEIO_H */ openocd-0.7.0/src/helper/configuration.c0000644000175000001440000001070012137151331015136 00000000000000/*************************************************************************** * Copyright (C) 2004, 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "configuration.h" #include "log.h" static size_t num_config_files; static char **config_file_names; static size_t num_script_dirs; static char **script_search_dirs; void add_script_search_dir(const char *dir) { num_script_dirs++; script_search_dirs = (char **)realloc(script_search_dirs, (num_script_dirs + 1) * sizeof(char *)); script_search_dirs[num_script_dirs-1] = strdup(dir); script_search_dirs[num_script_dirs] = NULL; LOG_DEBUG("adding %s", dir); } void add_config_command(const char *cfg) { num_config_files++; config_file_names = (char **)realloc(config_file_names, (num_config_files + 1) * sizeof(char *)); config_file_names[num_config_files-1] = strdup(cfg); config_file_names[num_config_files] = NULL; } /* return full path or NULL according to search rules */ char *find_file(const char *file) { FILE *fp = NULL; char **search_dirs = script_search_dirs; char *dir; char const *mode = "r"; char *full_path; /* Check absolute and relative to current working dir first. * This keeps full_path reporting belowing working. */ full_path = alloc_printf("%s", file); fp = fopen(full_path, mode); while (!fp) { free(full_path); full_path = NULL; dir = *search_dirs++; if (!dir) break; full_path = alloc_printf("%s/%s", dir, file); fp = fopen(full_path, mode); } if (fp) { fclose(fp); LOG_DEBUG("found %s", full_path); return full_path; } free(full_path); return NULL; } FILE *open_file_from_path(const char *file, const char *mode) { if (mode[0] != 'r') return fopen(file, mode); else { char *full_path = find_file(file); if (full_path == NULL) return NULL; FILE *fp = NULL; fp = fopen(full_path, mode); free(full_path); return fp; } } int parse_config_file(struct command_context *cmd_ctx) { int retval; char **cfg; if (!config_file_names) { command_run_line(cmd_ctx, "script openocd.cfg"); return ERROR_OK; } cfg = config_file_names; while (*cfg) { retval = command_run_line(cmd_ctx, *cfg); if (retval != ERROR_OK) return retval; cfg++; } return ERROR_OK; } #ifndef _WIN32 #include #endif char *get_home_dir(const char *append_path) { char *home = getenv("HOME"); if (home == NULL) { #ifdef _WIN32 home = getenv("USERPROFILE"); if (home == NULL) { char homepath[MAX_PATH]; char *drive = getenv("HOMEDRIVE"); char *path = getenv("HOMEPATH"); if (drive && path) { snprintf(homepath, MAX_PATH, "%s/%s", drive, path); home = homepath; } } #else struct passwd *pwd = getpwuid(getuid()); if (pwd) home = pwd->pw_dir; #endif } if (home == NULL) return home; char *home_path; if (append_path) home_path = alloc_printf("%s/%s", home, append_path); else home_path = alloc_printf("%s", home); return home_path; } openocd-0.7.0/src/helper/ioutil.h0000644000175000001440000000301112134336410013576 00000000000000/*************************************************************************** * Copyright (C) 2009 Zachary T Welch * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef HELPER_IOUTILS_H #define HELPER_IOUTILS_H struct command_context; int ioutil_init(struct command_context *cmd_ctx); #endif /* HELPER_IOUTILS_H */ openocd-0.7.0/src/helper/time_support.c0000644000175000001440000000652012134336410015026 00000000000000/*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "time_support.h" /* calculate difference between two struct timeval values */ int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y) { if (x->tv_usec < y->tv_usec) { int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1; y->tv_usec -= 1000000 * nsec; y->tv_sec += nsec; } if (x->tv_usec - y->tv_usec > 1000000) { int nsec = (x->tv_usec - y->tv_usec) / 1000000; y->tv_usec += 1000000 * nsec; y->tv_sec -= nsec; } result->tv_sec = x->tv_sec - y->tv_sec; result->tv_usec = x->tv_usec - y->tv_usec; /* Return 1 if result is negative. */ return x->tv_sec < y->tv_sec; } int timeval_add_time(struct timeval *result, long sec, long usec) { result->tv_sec += sec; result->tv_usec += usec; while (result->tv_usec > 1000000) { result->tv_usec -= 1000000; result->tv_sec++; } return 0; } int duration_start(struct duration *duration) { return gettimeofday(&duration->start, NULL); } int duration_measure(struct duration *duration) { struct timeval end; int retval = gettimeofday(&end, NULL); if (0 == retval) timeval_subtract(&duration->elapsed, &end, &duration->start); return retval; } float duration_elapsed(struct duration *duration) { float t = duration->elapsed.tv_sec; t += (float)duration->elapsed.tv_usec / 1000000.0; return t; } float duration_kbps(struct duration *duration, size_t count) { return count / (1024.0 * duration_elapsed(duration)); } openocd-0.7.0/src/helper/bin2char.c0000644000175000001440000000436212134336410013766 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #include #include #ifdef _WIN32 #include #endif int main(int argc, char **argv) { int c; unsigned int n; const char *name; if (argc == 1) { fprintf(stderr, "bin2char \n"); fprintf(stderr, "read from standard input and write a char" " array out to standard output\n"); exit(1); } #ifdef _WIN32 /* for win32 set stdin/stdout to binary mode */ _setmode(_fileno(stdin), _O_BINARY); _setmode(_fileno(stdout), _O_BINARY); #endif n = 0; name = argv[1]; fprintf(stdout, "/* autogenerated from %s */\n", argv[0]); fprintf(stdout, "unsigned const char %s[] = {\n", name); while ((c = getc(stdin)) != EOF) { fprintf(stdout, "0x%02x,", c & 0xff); if ((++n % 16) == 0) fprintf(stdout, "\n"); } fprintf(stdout, "0 /* terminate with a null */};\n"); return 0; } openocd-0.7.0/src/helper/Makefile.in0000644000175000001440000010227412141414275014204 00000000000000# Makefile.in generated by automake 1.13.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ DIST_COMMON = $(top_srcdir)/common.mk $(srcdir)/Makefile.in \ $(srcdir)/Makefile.am $(top_srcdir)/depcomp $(noinst_HEADERS) @INTERNAL_JIMTCL_TRUE@am__append_1 = -I$(top_srcdir)/jimtcl \ @INTERNAL_JIMTCL_TRUE@ -I$(top_builddir)/jimtcl @IOUTIL_TRUE@am__append_2 = ioutil.c @IOUTIL_FALSE@am__append_3 = ioutil_stubs.c # FD_* macros are sloppy with their signs on MinGW32 platform @IS_MINGW_TRUE@am__append_4 = -Wno-sign-compare subdir = src/helper ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/config_subdir.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libhelper_la_LIBADD = am__libhelper_la_SOURCES_DIST = binarybuffer.c options.c \ time_support_common.c configuration.c log.c command.c \ time_support.c replacements.c fileio.c util.c jim-nvp.c \ ioutil.c ioutil_stubs.c am__objects_1 = libhelper_la-options.lo \ libhelper_la-time_support_common.lo @IOUTIL_TRUE@am__objects_2 = libhelper_la-ioutil.lo @IOUTIL_FALSE@am__objects_3 = libhelper_la-ioutil_stubs.lo am_libhelper_la_OBJECTS = libhelper_la-binarybuffer.lo \ $(am__objects_1) libhelper_la-configuration.lo \ libhelper_la-log.lo libhelper_la-command.lo \ libhelper_la-time_support.lo libhelper_la-replacements.lo \ libhelper_la-fileio.lo libhelper_la-util.lo \ libhelper_la-jim-nvp.lo $(am__objects_2) $(am__objects_3) libhelper_la_OBJECTS = $(am_libhelper_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libhelper_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libhelper_la_CFLAGS) \ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libhelper_la_SOURCES) DIST_SOURCES = $(am__libhelper_la_SOURCES_DIST) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CC_FOR_BUILD = @CC_FOR_BUILD@ CFLAGS = @CFLAGS@ CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@ FGREP = @FGREP@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ doxygen_as_html = @doxygen_as_html@ doxygen_as_pdf = @doxygen_as_pdf@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ # common flags used in openocd build AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src \ -I$(top_srcdir)/src/helper -DPKGDATADIR=\"$(pkgdatadir)\" \ -DPKGLIBDIR=\"$(pkglibdir)\" $(am__append_1) METASOURCES = AUTO noinst_LTLIBRARIES = libhelper.la CONFIGFILES = options.c time_support_common.c libhelper_la_SOURCES = binarybuffer.c $(CONFIGFILES) configuration.c \ log.c command.c time_support.c replacements.c fileio.c util.c \ jim-nvp.c $(am__append_2) $(am__append_3) libhelper_la_CFLAGS = $(am__append_4) noinst_HEADERS = \ binarybuffer.h \ configuration.h \ ioutil.h \ list.h \ util.h \ types.h \ log.h \ command.h \ time_support.h \ replacements.h \ fileio.h \ system.h \ bin2char.c \ jim-nvp.h EXTRA_DIST = startup.tcl BIN2C = bin2char$(EXEEXT_FOR_BUILD) BUILT_SOURCES = $(BIN2C) CLEANFILES = bin2char$(EXEEXT_FOR_BUILD) MAINTAINERCLEANFILES = $(srcdir)/Makefile.in all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/common.mk $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/helper/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/helper/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_srcdir)/common.mk: $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libhelper.la: $(libhelper_la_OBJECTS) $(libhelper_la_DEPENDENCIES) $(EXTRA_libhelper_la_DEPENDENCIES) $(AM_V_CCLD)$(libhelper_la_LINK) $(libhelper_la_OBJECTS) $(libhelper_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhelper_la-binarybuffer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhelper_la-command.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhelper_la-configuration.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhelper_la-fileio.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhelper_la-ioutil.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhelper_la-ioutil_stubs.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhelper_la-jim-nvp.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhelper_la-log.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhelper_la-options.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhelper_la-replacements.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhelper_la-time_support.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhelper_la-time_support_common.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhelper_la-util.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< libhelper_la-binarybuffer.lo: binarybuffer.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libhelper_la_CFLAGS) $(CFLAGS) -MT libhelper_la-binarybuffer.lo -MD -MP -MF $(DEPDIR)/libhelper_la-binarybuffer.Tpo -c -o libhelper_la-binarybuffer.lo `test -f 'binarybuffer.c' || echo '$(srcdir)/'`binarybuffer.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libhelper_la-binarybuffer.Tpo $(DEPDIR)/libhelper_la-binarybuffer.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='binarybuffer.c' object='libhelper_la-binarybuffer.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libhelper_la_CFLAGS) $(CFLAGS) -c -o libhelper_la-binarybuffer.lo `test -f 'binarybuffer.c' || echo '$(srcdir)/'`binarybuffer.c libhelper_la-options.lo: options.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libhelper_la_CFLAGS) $(CFLAGS) -MT libhelper_la-options.lo -MD -MP -MF $(DEPDIR)/libhelper_la-options.Tpo -c -o libhelper_la-options.lo `test -f 'options.c' || echo '$(srcdir)/'`options.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libhelper_la-options.Tpo $(DEPDIR)/libhelper_la-options.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='options.c' object='libhelper_la-options.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libhelper_la_CFLAGS) $(CFLAGS) -c -o libhelper_la-options.lo `test -f 'options.c' || echo '$(srcdir)/'`options.c libhelper_la-time_support_common.lo: time_support_common.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libhelper_la_CFLAGS) $(CFLAGS) -MT libhelper_la-time_support_common.lo -MD -MP -MF $(DEPDIR)/libhelper_la-time_support_common.Tpo -c -o libhelper_la-time_support_common.lo `test -f 'time_support_common.c' || echo '$(srcdir)/'`time_support_common.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libhelper_la-time_support_common.Tpo $(DEPDIR)/libhelper_la-time_support_common.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='time_support_common.c' object='libhelper_la-time_support_common.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libhelper_la_CFLAGS) $(CFLAGS) -c -o libhelper_la-time_support_common.lo `test -f 'time_support_common.c' || echo '$(srcdir)/'`time_support_common.c libhelper_la-configuration.lo: configuration.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libhelper_la_CFLAGS) $(CFLAGS) -MT libhelper_la-configuration.lo -MD -MP -MF $(DEPDIR)/libhelper_la-configuration.Tpo -c -o libhelper_la-configuration.lo `test -f 'configuration.c' || echo '$(srcdir)/'`configuration.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libhelper_la-configuration.Tpo $(DEPDIR)/libhelper_la-configuration.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='configuration.c' object='libhelper_la-configuration.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libhelper_la_CFLAGS) $(CFLAGS) -c -o libhelper_la-configuration.lo `test -f 'configuration.c' || echo '$(srcdir)/'`configuration.c libhelper_la-log.lo: log.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libhelper_la_CFLAGS) $(CFLAGS) -MT libhelper_la-log.lo -MD -MP -MF $(DEPDIR)/libhelper_la-log.Tpo -c -o libhelper_la-log.lo `test -f 'log.c' || echo '$(srcdir)/'`log.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libhelper_la-log.Tpo $(DEPDIR)/libhelper_la-log.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='log.c' object='libhelper_la-log.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libhelper_la_CFLAGS) $(CFLAGS) -c -o libhelper_la-log.lo `test -f 'log.c' || echo '$(srcdir)/'`log.c libhelper_la-command.lo: command.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libhelper_la_CFLAGS) $(CFLAGS) -MT libhelper_la-command.lo -MD -MP -MF $(DEPDIR)/libhelper_la-command.Tpo -c -o libhelper_la-command.lo `test -f 'command.c' || echo '$(srcdir)/'`command.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libhelper_la-command.Tpo $(DEPDIR)/libhelper_la-command.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='command.c' object='libhelper_la-command.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libhelper_la_CFLAGS) $(CFLAGS) -c -o libhelper_la-command.lo `test -f 'command.c' || echo '$(srcdir)/'`command.c libhelper_la-time_support.lo: time_support.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libhelper_la_CFLAGS) $(CFLAGS) -MT libhelper_la-time_support.lo -MD -MP -MF $(DEPDIR)/libhelper_la-time_support.Tpo -c -o libhelper_la-time_support.lo `test -f 'time_support.c' || echo '$(srcdir)/'`time_support.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libhelper_la-time_support.Tpo $(DEPDIR)/libhelper_la-time_support.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='time_support.c' object='libhelper_la-time_support.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libhelper_la_CFLAGS) $(CFLAGS) -c -o libhelper_la-time_support.lo `test -f 'time_support.c' || echo '$(srcdir)/'`time_support.c libhelper_la-replacements.lo: replacements.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libhelper_la_CFLAGS) $(CFLAGS) -MT libhelper_la-replacements.lo -MD -MP -MF $(DEPDIR)/libhelper_la-replacements.Tpo -c -o libhelper_la-replacements.lo `test -f 'replacements.c' || echo '$(srcdir)/'`replacements.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libhelper_la-replacements.Tpo $(DEPDIR)/libhelper_la-replacements.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='replacements.c' object='libhelper_la-replacements.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libhelper_la_CFLAGS) $(CFLAGS) -c -o libhelper_la-replacements.lo `test -f 'replacements.c' || echo '$(srcdir)/'`replacements.c libhelper_la-fileio.lo: fileio.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libhelper_la_CFLAGS) $(CFLAGS) -MT libhelper_la-fileio.lo -MD -MP -MF $(DEPDIR)/libhelper_la-fileio.Tpo -c -o libhelper_la-fileio.lo `test -f 'fileio.c' || echo '$(srcdir)/'`fileio.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libhelper_la-fileio.Tpo $(DEPDIR)/libhelper_la-fileio.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fileio.c' object='libhelper_la-fileio.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libhelper_la_CFLAGS) $(CFLAGS) -c -o libhelper_la-fileio.lo `test -f 'fileio.c' || echo '$(srcdir)/'`fileio.c libhelper_la-util.lo: util.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libhelper_la_CFLAGS) $(CFLAGS) -MT libhelper_la-util.lo -MD -MP -MF $(DEPDIR)/libhelper_la-util.Tpo -c -o libhelper_la-util.lo `test -f 'util.c' || echo '$(srcdir)/'`util.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libhelper_la-util.Tpo $(DEPDIR)/libhelper_la-util.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='util.c' object='libhelper_la-util.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libhelper_la_CFLAGS) $(CFLAGS) -c -o libhelper_la-util.lo `test -f 'util.c' || echo '$(srcdir)/'`util.c libhelper_la-jim-nvp.lo: jim-nvp.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libhelper_la_CFLAGS) $(CFLAGS) -MT libhelper_la-jim-nvp.lo -MD -MP -MF $(DEPDIR)/libhelper_la-jim-nvp.Tpo -c -o libhelper_la-jim-nvp.lo `test -f 'jim-nvp.c' || echo '$(srcdir)/'`jim-nvp.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libhelper_la-jim-nvp.Tpo $(DEPDIR)/libhelper_la-jim-nvp.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='jim-nvp.c' object='libhelper_la-jim-nvp.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libhelper_la_CFLAGS) $(CFLAGS) -c -o libhelper_la-jim-nvp.lo `test -f 'jim-nvp.c' || echo '$(srcdir)/'`jim-nvp.c libhelper_la-ioutil.lo: ioutil.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libhelper_la_CFLAGS) $(CFLAGS) -MT libhelper_la-ioutil.lo -MD -MP -MF $(DEPDIR)/libhelper_la-ioutil.Tpo -c -o libhelper_la-ioutil.lo `test -f 'ioutil.c' || echo '$(srcdir)/'`ioutil.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libhelper_la-ioutil.Tpo $(DEPDIR)/libhelper_la-ioutil.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ioutil.c' object='libhelper_la-ioutil.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libhelper_la_CFLAGS) $(CFLAGS) -c -o libhelper_la-ioutil.lo `test -f 'ioutil.c' || echo '$(srcdir)/'`ioutil.c libhelper_la-ioutil_stubs.lo: ioutil_stubs.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libhelper_la_CFLAGS) $(CFLAGS) -MT libhelper_la-ioutil_stubs.lo -MD -MP -MF $(DEPDIR)/libhelper_la-ioutil_stubs.Tpo -c -o libhelper_la-ioutil_stubs.lo `test -f 'ioutil_stubs.c' || echo '$(srcdir)/'`ioutil_stubs.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libhelper_la-ioutil_stubs.Tpo $(DEPDIR)/libhelper_la-ioutil_stubs.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ioutil_stubs.c' object='libhelper_la-ioutil_stubs.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libhelper_la_CFLAGS) $(CFLAGS) -c -o libhelper_la-ioutil_stubs.lo `test -f 'ioutil_stubs.c' || echo '$(srcdir)/'`ioutil_stubs.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-am all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: all check install install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am $(BIN2C): bin2char.c ${CC_FOR_BUILD} ${CFLAGS_FOR_BUILD} $(srcdir)/bin2char.c -o $@ # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: openocd-0.7.0/src/helper/system.h0000644000175000001440000000544312134336410013630 00000000000000/*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Copyright (C) 2007-2008 by Øyvind Harboe * * Copyright (C) 2008 by Spencer Oliver * * Copyright (C) 2009 by Zachary T Welch * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef SYSTEM_H #define SYSTEM_H /* standard C library header files */ #include #include #include #include #include #include /* +++ AC_HEADER_TIME +++ */ #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif /* --- AC_HEADER_TIME --- */ /* +++ platform specific headers +++ */ #ifdef _WIN32 #include #include #include #include #endif /* --- platform specific headers --- */ #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_SYS_POLL_H #include #endif #ifdef __ECOS /* missing from eCos */ #ifndef EFAULT #define EFAULT 14 /* Bad address */ #endif #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_SYS_SELECT_H #include /* select, FD_SET and friends (POSIX.1-2001) */ #endif #ifdef HAVE_SYS_PARAM_H #include /* for MIN/MAX macros */ #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_FCNTL_H #include #endif #ifndef true #define true 1 #define false 0 #endif #endif /* SYSTEM_H */ openocd-0.7.0/src/helper/jim-nvp.h0000644000175000001440000002323612134336410013664 00000000000000/* Jim - A small embeddable Tcl interpreter * * Copyright 2005 Salvatore Sanfilippo * Copyright 2005 Clemens Hintze * Copyright 2005 patthoyts - Pat Thoyts * Copyright 2008 oharboe - Øyvind Harboe - oyvind.harboe@zylin.com * Copyright 2008 Andrew Lunn * Copyright 2008 Duane Ellis * Copyright 2008 Uwe Klein * Copyright 2008 Steve Bennett * Copyright 2009 Nico Coesel * Copyright 2009 Zachary T Welch zw@superlucidity.net * Copyright 2009 David Brownell * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation * are those of the authors and should not be interpreted as representing * official policies, either expressed or implied, of the Jim Tcl Project. */ #ifndef JIM_NVP_H #define JIM_NVP_H #include /** Name Value Pairs, aka: NVP * - Given a string - return the associated int. * - Given a number - return the associated string. * . * * Very useful when the number is not a simple index into an array of * known string, or there may be multiple strings (aliases) that mean then same * thing. * * An NVP Table is terminated with ".name = NULL". * * During the 'name2value' operation, if no matching string is found * the pointer to the terminal element (with p->name == NULL) is returned. * * Example: * \code * const Jim_Nvp yn[] = { * { "yes", 1 }, * { "no" , 0 }, * { "yep", 1 }, * { "nope", 0 }, * { NULL, -1 }, * }; * * Jim_Nvp *result * e = Jim_Nvp_name2value(interp, yn, "y", &result); * returns &yn[0]; * e = Jim_Nvp_name2value(interp, yn, "n", &result); * returns &yn[1]; * e = Jim_Nvp_name2value(interp, yn, "Blah", &result); * returns &yn[4]; * \endcode * * During the number2name operation, the first matching value is returned. */ typedef struct { const char *name; int value; } Jim_Nvp; int Jim_GetNvp(Jim_Interp *interp, Jim_Obj *objPtr, const Jim_Nvp *nvp_table, const Jim_Nvp **result); /* Name Value Pairs Operations */ Jim_Nvp *Jim_Nvp_name2value_simple(const Jim_Nvp *nvp_table, const char *name); Jim_Nvp *Jim_Nvp_name2value_nocase_simple(const Jim_Nvp *nvp_table, const char *name); Jim_Nvp *Jim_Nvp_value2name_simple(const Jim_Nvp *nvp_table, int v); int Jim_Nvp_name2value(Jim_Interp *interp, const Jim_Nvp *nvp_table, const char *name, Jim_Nvp **result); int Jim_Nvp_name2value_nocase(Jim_Interp *interp, const Jim_Nvp *nvp_table, const char *name, Jim_Nvp **result); int Jim_Nvp_value2name(Jim_Interp *interp, const Jim_Nvp *nvp_table, int value, Jim_Nvp **result); int Jim_Nvp_name2value_obj(Jim_Interp *interp, const Jim_Nvp *nvp_table, Jim_Obj *name_obj, Jim_Nvp **result); int Jim_Nvp_name2value_obj_nocase(Jim_Interp *interp, const Jim_Nvp *nvp_table, Jim_Obj *name_obj, Jim_Nvp **result); int Jim_Nvp_value2name_obj(Jim_Interp *interp, const Jim_Nvp *nvp_table, Jim_Obj *value_obj, Jim_Nvp **result); /** prints a nice 'unknown' parameter error message to the 'result' */ void Jim_SetResult_NvpUnknown(Jim_Interp *interp, Jim_Obj *param_name, Jim_Obj *param_value, const Jim_Nvp *nvp_table); /** Debug: convert argc/argv into a printable string for printf() debug * * \param interp - the interpeter * \param argc - arg count * \param argv - the objects * * \returns string pointer holding the text. * * Note, next call to this function will free the old (last) string. * * For example might want do this: * \code * fp = fopen("some.file.log", "a"); * fprintf(fp, "PARAMS are: %s\n", Jim_DebugArgvString(interp, argc, argv)); * fclose(fp); * \endcode */ const char *Jim_Debug_ArgvString(Jim_Interp *interp, int argc, Jim_Obj *const *argv); /** A TCL -ish GetOpt like code. * * Some TCL objects have various "configuration" values. * For example - in Tcl/Tk the "buttons" have many options. * * Usefull when dealing with command options. * that may come in any order... * * Does not support "-foo = 123" type options. * Only supports tcl type options, like "-foo 123" */ typedef struct jim_getopt { Jim_Interp *interp; int argc; Jim_Obj *const *argv; int isconfigure; /* non-zero if configure */ } Jim_GetOptInfo; /** GetOpt - how to. * * Example (short and incomplete): * \code * Jim_GetOptInfo goi; * * Jim_GetOpt_Setup(&goi, interp, argc, argv); * * while (goi.argc) { * e = Jim_GetOpt_Nvp(&goi, nvp_options, &n); * if (e != JIM_OK) { * Jim_GetOpt_NvpUnknown(&goi, nvp_options, 0); * return e; * } * * switch (n->value) { * case ALIVE: * printf("Option ALIVE specified\n"); * break; * case FIRST: * if (goi.argc < 1) { * .. not enough args error .. * } * Jim_GetOpt_String(&goi, &cp, NULL); * printf("FIRSTNAME: %s\n", cp); * case AGE: * Jim_GetOpt_Wide(&goi, &w); * printf("AGE: %d\n", (int)(w)); * break; * case POLITICS: * e = Jim_GetOpt_Nvp(&goi, nvp_politics, &n); * if (e != JIM_OK) { * Jim_GetOpt_NvpUnknown(&goi, nvp_politics, 1); * return e; * } * } * } * * \endcode * */ /** Setup GETOPT * * \param goi - get opt info to be initialized * \param interp - jim interp * \param argc - argc count. * \param argv - argv (will be copied) * * \code * Jim_GetOptInfo goi; * * Jim_GetOptSetup(&goi, interp, argc, argv); * \endcode */ int Jim_GetOpt_Setup(Jim_GetOptInfo *goi, Jim_Interp *interp, int argc, Jim_Obj *const *argv); /** Debug - Dump parameters to stderr * \param goi - current parameters */ void Jim_GetOpt_Debug(Jim_GetOptInfo *goi); /** Remove argv[0] from the list. * * \param goi - get opt info * \param puthere - where param is put * */ int Jim_GetOpt_Obj(Jim_GetOptInfo *goi, Jim_Obj **puthere); /** Remove argv[0] as string. * * \param goi - get opt info * \param puthere - where param is put * \param len - return its length */ int Jim_GetOpt_String(Jim_GetOptInfo *goi, char **puthere, int *len); /** Remove argv[0] as double. * * \param goi - get opt info * \param puthere - where param is put. * */ int Jim_GetOpt_Double(Jim_GetOptInfo *goi, double *puthere); /** Remove argv[0] as wide. * * \param goi - get opt info * \param puthere - where param is put. */ int Jim_GetOpt_Wide(Jim_GetOptInfo *goi, jim_wide *puthere); /** Remove argv[0] as NVP. * * \param goi - get opt info * \param lookup - nvp lookup table * \param puthere - where param is put. * */ int Jim_GetOpt_Nvp(Jim_GetOptInfo *goi, const Jim_Nvp *lookup, Jim_Nvp **puthere); /** Create an appropriate error message for an NVP. * * \param goi - options info * \param lookup - the NVP table that was used. * \param hadprefix - 0 or 1 if the option had a prefix. * * This function will set the "interp->result" to a human readable * error message listing the available options. * * This function assumes the previous option argv[-1] is the unknown string. * * If this option had some prefix, then pass "hadprefix = 1" else pass "hadprefix = 0" * * Example: * \code * * while (goi.argc) { * // Get the next option * e = Jim_GetOpt_Nvp(&goi, cmd_options, &n); * if (e != JIM_OK) { * // option was not recognized * // pass 'hadprefix = 0' because there is no prefix * Jim_GetOpt_NvpUnknown(&goi, cmd_options, 0); * return e; * } * * switch (n->value) { * case OPT_SEX: * // handle: --sex male | female | lots | needmore * e = Jim_GetOpt_Nvp(&goi, &nvp_sex, &n); * if (e != JIM_OK) { * Jim_GetOpt_NvpUnknown(&ogi, nvp_sex, 1); * return e; * } * printf("Code: (%d) is %s\n", n->value, n->name); * break; * case ...: * [snip] * } * } * \endcode * */ void Jim_GetOpt_NvpUnknown(Jim_GetOptInfo *goi, const Jim_Nvp *lookup, int hadprefix); /** Remove argv[0] as Enum * * \param goi - get opt info * \param lookup - lookup table. * \param puthere - where param is put. * */ int Jim_GetOpt_Enum(Jim_GetOptInfo *goi, const char *const *lookup, int *puthere); #endif openocd-0.7.0/src/helper/util.h0000644000175000001440000000300212134336410013246 00000000000000/*************************************************************************** * Copyright (C) 2010 by Øyvind Harboe * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef HELPER_UTILS_H #define HELPER_UTILS_H struct command_context; int util_init(struct command_context *cmd_ctx); #endif /* HELPER_UTILS_H */ openocd-0.7.0/src/helper/replacements.h0000644000175000001440000002013512134336410014761 00000000000000/*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef REPLACEMENTS_H #define REPLACEMENTS_H /* MIN,MAX macros */ #ifndef MIN #define MIN(a, b) (((a) < (b)) ? (a) : (b)) #endif #ifndef MAX #define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif /* for systems that do not support ENOTSUP * win32 being one of them */ #ifndef ENOTSUP #define ENOTSUP 134 /* Not supported */ #endif /* for systems that do not support O_BINARY * linux being one of them */ #ifndef O_BINARY #define O_BINARY 0 #endif #ifndef HAVE_SYS_TIME_H #ifndef _TIMEVAL_DEFINED #define _TIMEVAL_DEFINED struct timeval { long tv_sec; long tv_usec; }; #endif /* _TIMEVAL_DEFINED */ #endif /* gettimeofday() */ #ifndef HAVE_GETTIMEOFDAY #ifdef _WIN32 struct timezone { int tz_minuteswest; int tz_dsttime; }; #endif struct timezone; int gettimeofday(struct timeval *tv, struct timezone *tz); #endif #ifndef IN_REPLACEMENTS_C /**** clear_malloc & fill_malloc ****/ void *clear_malloc(size_t size); void *fill_malloc(size_t size); #endif /* * Now you have 3 ways for the malloc function: * * 1. Do not change anything, use the original malloc * * 2. Use the clear_malloc function instead of the original malloc. * In this case you must use the following define: * #define malloc((_a)) clear_malloc((_a)) * * 3. Use the fill_malloc function instead of the original malloc. * In this case you must use the following define: * #define malloc((_a)) fill_malloc((_a)) * * We have figured out that there could exist some malloc problems * where variables are using without to be initialise. To find this * places, use the fill_malloc function. With this function we want * to initialize memory to some known bad state. This is quite easily * spotted in the debugger and will trap to an invalid address. * * clear_malloc can be used if you want to set not initialise * variable to 0. * * If you do not want to change the malloc function, to not use one of * the following macros. Which is the default way. */ /* #define malloc(_a) clear_malloc(_a) * #define malloc(_a) fill_malloc(_a) */ /* GNU extensions to the C library that may be missing on some systems */ #ifndef HAVE_STRNDUP char *strndup(const char *s, size_t n); #endif /* HAVE_STRNDUP */ #ifndef HAVE_STRNLEN size_t strnlen(const char *s, size_t maxlen); #endif /* HAVE_STRNLEN */ #ifndef HAVE_USLEEP #ifdef _WIN32 static inline unsigned usleep(unsigned int usecs) { Sleep((usecs/1000)); return 0; } #else #error no usleep defined for your platform #endif #endif /* HAVE_USLEEP */ /* Windows specific */ #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include #include /* Windows does not declare sockaddr_un */ #define UNIX_PATH_LEN 108 struct sockaddr_un { uint16_t sun_family; char sun_path[UNIX_PATH_LEN]; }; /* win32 systems do not support ETIMEDOUT */ #ifndef ETIMEDOUT #define ETIMEDOUT WSAETIMEDOUT #endif #if IS_MINGW == 1 static inline unsigned char inb(unsigned short int port) { unsigned char _v; __asm__ __volatile__ ("inb %w1,%0" : "=a" (_v) : "Nd" (port)); return _v; } static inline void outb(unsigned char value, unsigned short int port) { __asm__ __volatile__ ("outb %b0,%w1" : : "a" (value), "Nd" (port)); } /* mingw does not have ffs, so use gcc builtin types */ #define ffs __builtin_ffs #endif /* IS_MINGW */ int win_select(int max_fd, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *tv); #endif /* _WIN32 */ /* generic socket functions for Windows and Posix */ static inline int write_socket(int handle, const void *buffer, unsigned int count) { #ifdef _WIN32 return send(handle, buffer, count, 0); #else return write(handle, buffer, count); #endif } static inline int read_socket(int handle, void *buffer, unsigned int count) { #ifdef _WIN32 return recv(handle, buffer, count, 0); #else return read(handle, buffer, count); #endif } static inline int close_socket(int sock) { #ifdef _WIN32 return closesocket(sock); #else return close(sock); #endif } static inline void socket_nonblock(int fd) { #ifdef _WIN32 unsigned long nonblock = 1; ioctlsocket(fd, FIONBIO, &nonblock); #else int oldopts = fcntl(fd, F_GETFL, 0); fcntl(fd, F_SETFL, oldopts | O_NONBLOCK); #endif } static inline int socket_select(int max_fd, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *tv) { #ifdef _WIN32 return win_select(max_fd, rfds, wfds, efds, tv); #else return select(max_fd, rfds, wfds, efds, tv); #endif } #ifndef HAVE_ELF_H typedef uint32_t Elf32_Addr; typedef uint16_t Elf32_Half; typedef uint32_t Elf32_Off; typedef int32_t Elf32_Sword; typedef uint32_t Elf32_Word; typedef uint32_t Elf32_Size; typedef Elf32_Off Elf32_Hashelt; typedef struct { unsigned char e_ident[16]; /* Magic number and other info */ Elf32_Half e_type; /* Object file type */ Elf32_Half e_machine; /* Architecture */ Elf32_Word e_version; /* Object file version */ Elf32_Addr e_entry; /* Entry point virtual address */ Elf32_Off e_phoff; /* Program header table file offset */ Elf32_Off e_shoff; /* Section header table file offset */ Elf32_Word e_flags; /* Processor-specific flags */ Elf32_Half e_ehsize; /* ELF header size in bytes */ Elf32_Half e_phentsize; /* Program header table entry size */ Elf32_Half e_phnum; /* Program header table entry count */ Elf32_Half e_shentsize; /* Section header table entry size */ Elf32_Half e_shnum; /* Section header table entry count */ Elf32_Half e_shstrndx; /* Section header string table index */ } Elf32_Ehdr; #define ELFMAG "\177ELF" #define SELFMAG 4 #define EI_CLASS 4 /* File class byte index */ #define ELFCLASS32 1 /* 32-bit objects */ #define ELFCLASS64 2 /* 64-bit objects */ #define EI_DATA 5 /* Data encoding byte index */ #define ELFDATA2LSB 1 /* 2's complement, little endian */ #define ELFDATA2MSB 2 /* 2's complement, big endian */ typedef struct { Elf32_Word p_type; /* Segment type */ Elf32_Off p_offset; /* Segment file offset */ Elf32_Addr p_vaddr; /* Segment virtual address */ Elf32_Addr p_paddr; /* Segment physical address */ Elf32_Size p_filesz; /* Segment size in file */ Elf32_Size p_memsz; /* Segment size in memory */ Elf32_Word p_flags; /* Segment flags */ Elf32_Size p_align; /* Segment alignment */ } Elf32_Phdr; #define PT_LOAD 1 /* Loadable program segment */ #endif /* HAVE_ELF_H */ #endif /* REPLACEMENTS_H */ openocd-0.7.0/src/helper/binarybuffer.c0000644000175000001440000002566512134336410014765 00000000000000/*************************************************************************** * Copyright (C) 2004, 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "log.h" #include "binarybuffer.h" static const unsigned char bit_reverse_table256[] = { 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA, 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1, 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9, 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD, 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF }; void *buf_cpy(const void *from, void *_to, unsigned size) { if (NULL == from || NULL == _to) return NULL; /* copy entire buffer */ memcpy(_to, from, DIV_ROUND_UP(size, 8)); /* mask out bits that don't belong to the buffer */ unsigned trailing_bits = size % 8; if (trailing_bits) { uint8_t *to = _to; to[size / 8] &= (1 << trailing_bits) - 1; } return _to; } static bool buf_cmp_masked(uint8_t a, uint8_t b, uint8_t m) { return (a & m) != (b & m); } static bool buf_cmp_trailing(uint8_t a, uint8_t b, uint8_t m, unsigned trailing) { uint8_t mask = (1 << trailing) - 1; return buf_cmp_masked(a, b, mask & m); } bool buf_cmp(const void *_buf1, const void *_buf2, unsigned size) { if (!_buf1 || !_buf2) return _buf1 != _buf2; unsigned last = size / 8; if (memcmp(_buf1, _buf2, last) != 0) return false; unsigned trailing = size % 8; if (!trailing) return false; const uint8_t *buf1 = _buf1, *buf2 = _buf2; return buf_cmp_trailing(buf1[last], buf2[last], 0xff, trailing); } bool buf_cmp_mask(const void *_buf1, const void *_buf2, const void *_mask, unsigned size) { if (!_buf1 || !_buf2) return _buf1 != _buf2 || _buf1 != _mask; const uint8_t *buf1 = _buf1, *buf2 = _buf2, *mask = _mask; unsigned last = size / 8; for (unsigned i = 0; i < last; i++) { if (buf_cmp_masked(buf1[i], buf2[i], mask[i])) return true; } unsigned trailing = size % 8; if (!trailing) return false; return buf_cmp_trailing(buf1[last], buf2[last], mask[last], trailing); } void *buf_set_ones(void *_buf, unsigned size) { uint8_t *buf = _buf; if (!buf) return NULL; memset(buf, 0xff, size / 8); unsigned trailing_bits = size % 8; if (trailing_bits) buf[size / 8] = (1 << trailing_bits) - 1; return buf; } void *buf_set_buf(const void *_src, unsigned src_start, void *_dst, unsigned dst_start, unsigned len) { const uint8_t *src = _src; uint8_t *dst = _dst; unsigned i, sb, db, sq, dq, lb, lq; sb = src_start / 8; db = dst_start / 8; sq = src_start % 8; dq = dst_start % 8; lb = len / 8; lq = len % 8; src += sb; dst += db; /* check if both buffers are on byte boundary and * len is a multiple of 8bit so we can simple copy * the buffer */ if ((sq == 0) && (dq == 0) && (lq == 0)) { for (i = 0; i < lb; i++) *dst++ = *src++; return (uint8_t *)_dst; } /* fallback to slow bit copy */ for (i = 0; i < len; i++) { if (((*src >> (sq&7)) & 1) == 1) *dst |= 1 << (dq&7); else *dst &= ~(1 << (dq&7)); if (sq++ == 7) { sq = 0; src++; } if (dq++ == 7) { dq = 0; dst++; } } return (uint8_t *)_dst; } uint32_t flip_u32(uint32_t value, unsigned int num) { uint32_t c = (bit_reverse_table256[value & 0xff] << 24) | (bit_reverse_table256[(value >> 8) & 0xff] << 16) | (bit_reverse_table256[(value >> 16) & 0xff] << 8) | (bit_reverse_table256[(value >> 24) & 0xff]); if (num < 32) c = c >> (32 - num); return c; } static int ceil_f_to_u32(float x) { if (x < 0) /* return zero for negative numbers */ return 0; uint32_t y = x; /* cut off fraction */ if ((x - y) > 0.0) /* if there was a fractional part, increase by one */ y++; return y; } char *buf_to_str(const void *_buf, unsigned buf_len, unsigned radix) { float factor; switch (radix) { case 16: factor = 2.0; /* log(256) / log(16) = 2.0 */ break; case 10: factor = 2.40824; /* log(256) / log(10) = 2.40824 */ break; case 8: factor = 2.66667; /* log(256) / log(8) = 2.66667 */ break; default: return NULL; } unsigned str_len = ceil_f_to_u32(DIV_ROUND_UP(buf_len, 8) * factor); char *str = calloc(str_len + 1, 1); const uint8_t *buf = _buf; int b256_len = DIV_ROUND_UP(buf_len, 8); for (int i = b256_len - 1; i >= 0; i--) { uint32_t tmp = buf[i]; if (((unsigned)i == (buf_len / 8)) && (buf_len % 8)) tmp &= (0xff >> (8 - (buf_len % 8))); /* base-256 digits */ for (unsigned j = str_len; j > 0; j--) { tmp += (uint32_t)str[j-1] * 256; str[j-1] = (uint8_t)(tmp % radix); tmp /= radix; } } const char *DIGITS = "0123456789ABCDEF"; for (unsigned j = 0; j < str_len; j++) str[j] = DIGITS[(int)str[j]]; return str; } /** identify radix, and skip radix-prefix (0, 0x or 0X) */ static void str_radix_guess(const char **_str, unsigned *_str_len, unsigned *_radix) { unsigned radix = *_radix; if (0 != radix) return; const char *str = *_str; unsigned str_len = *_str_len; if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) { radix = 16; str += 2; str_len -= 2; } else if ((str[0] == '0') && (str_len != 1)) { radix = 8; str += 1; str_len -= 1; } else radix = 10; *_str = str; *_str_len = str_len; *_radix = radix; } int str_to_buf(const char *str, unsigned str_len, void *_buf, unsigned buf_len, unsigned radix) { str_radix_guess(&str, &str_len, &radix); float factor; if (radix == 16) factor = 0.5; /* log(16) / log(256) = 0.5 */ else if (radix == 10) factor = 0.41524; /* log(10) / log(256) = 0.41524 */ else if (radix == 8) factor = 0.375; /* log(8) / log(256) = 0.375 */ else return 0; /* copy to zero-terminated buffer */ char *charbuf = strndup(str, str_len); /* number of digits in base-256 notation */ unsigned b256_len = ceil_f_to_u32(str_len * factor); uint8_t *b256_buf = calloc(b256_len, 1); /* go through zero terminated buffer * input digits (ASCII) */ unsigned i; for (i = 0; charbuf[i]; i++) { uint32_t tmp = charbuf[i]; if ((tmp >= '0') && (tmp <= '9')) tmp = (tmp - '0'); else if ((tmp >= 'a') && (tmp <= 'f')) tmp = (tmp - 'a' + 10); else if ((tmp >= 'A') && (tmp <= 'F')) tmp = (tmp - 'A' + 10); else continue; /* skip characters other than [0-9,a-f,A-F] */ if (tmp >= radix) continue; /* skip digits invalid for the current radix */ /* base-256 digits */ for (unsigned j = 0; j < b256_len; j++) { tmp += (uint32_t)b256_buf[j] * radix; b256_buf[j] = (uint8_t)(tmp & 0xFF); tmp >>= 8; } } uint8_t *buf = _buf; for (unsigned j = 0; j < DIV_ROUND_UP(buf_len, 8); j++) { if (j < b256_len) buf[j] = b256_buf[j]; else buf[j] = 0; } /* mask out bits that don't belong to the buffer */ if (buf_len % 8) buf[(buf_len / 8)] &= 0xff >> (8 - (buf_len % 8)); free(b256_buf); free(charbuf); return i; } void bit_copy_queue_init(struct bit_copy_queue *q) { INIT_LIST_HEAD(&q->list); } int bit_copy_queued(struct bit_copy_queue *q, uint8_t *dst, unsigned dst_offset, const uint8_t *src, unsigned src_offset, unsigned bit_count) { struct bit_copy_queue_entry *qe = malloc(sizeof(*qe)); if (!qe) return ERROR_FAIL; qe->dst = dst; qe->dst_offset = dst_offset; qe->src = src; qe->src_offset = src_offset; qe->bit_count = bit_count; list_add_tail(&qe->list, &q->list); return ERROR_OK; } void bit_copy_execute(struct bit_copy_queue *q) { struct bit_copy_queue_entry *qe; struct bit_copy_queue_entry *tmp; list_for_each_entry_safe(qe, tmp, &q->list, list) { bit_copy(qe->dst, qe->dst_offset, qe->src, qe->src_offset, qe->bit_count); list_del(&qe->list); free(qe); } } void bit_copy_discard(struct bit_copy_queue *q) { struct bit_copy_queue_entry *qe; struct bit_copy_queue_entry *tmp; list_for_each_entry_safe(qe, tmp, &q->list, list) { list_del(&qe->list); free(qe); } } int unhexify(char *bin, const char *hex, int count) { int i, tmp; for (i = 0; i < count; i++) { if (sscanf(hex + (2 * i), "%02x", &tmp) != 1) return i; bin[i] = tmp; } return i; } int hexify(char *hex, const char *bin, int count, int out_maxlen) { int i, cmd_len = 0; /* May use a length, or a null-terminated string as input. */ if (count == 0) count = strlen(bin); for (i = 0; i < count; i++) cmd_len += snprintf(hex + cmd_len, out_maxlen - cmd_len, "%02x", bin[i] & 0xff); return cmd_len; } openocd-0.7.0/src/helper/jim-nvp.c0000644000175000001440000001753012134336410013657 00000000000000/* Jim - A small embeddable Tcl interpreter * * Copyright 2005 Salvatore Sanfilippo * Copyright 2005 Clemens Hintze * Copyright 2005 patthoyts - Pat Thoyts * Copyright 2008 oharboe - Øyvind Harboe - oyvind.harboe@zylin.com * Copyright 2008 Andrew Lunn * Copyright 2008 Duane Ellis * Copyright 2008 Uwe Klein * Copyright 2008 Steve Bennett * Copyright 2009 Nico Coesel * Copyright 2009 Zachary T Welch zw@superlucidity.net * Copyright 2009 David Brownell * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation * are those of the authors and should not be interpreted as representing * official policies, either expressed or implied, of the Jim Tcl Project. */ #include #include int Jim_GetNvp(Jim_Interp *interp, Jim_Obj *objPtr, const Jim_Nvp *nvp_table, const Jim_Nvp **result) { Jim_Nvp *n; int e; e = Jim_Nvp_name2value_obj(interp, nvp_table, objPtr, &n); if (e == JIM_ERR) return e; /* Success? found? */ if (n->name) { /* remove const */ *result = (Jim_Nvp *) n; return JIM_OK; } else return JIM_ERR; } Jim_Nvp *Jim_Nvp_name2value_simple(const Jim_Nvp *p, const char *name) { while (p->name) { if (0 == strcmp(name, p->name)) break; p++; } return (Jim_Nvp *) (p); } Jim_Nvp *Jim_Nvp_name2value_nocase_simple(const Jim_Nvp *p, const char *name) { while (p->name) { if (0 == strcasecmp(name, p->name)) break; p++; } return (Jim_Nvp *) (p); } int Jim_Nvp_name2value_obj(Jim_Interp *interp, const Jim_Nvp *p, Jim_Obj *o, Jim_Nvp **result) { return Jim_Nvp_name2value(interp, p, Jim_String(o), result); } int Jim_Nvp_name2value(Jim_Interp *interp, const Jim_Nvp *_p, const char *name, Jim_Nvp **result) { const Jim_Nvp *p; p = Jim_Nvp_name2value_simple(_p, name); /* result */ if (result) *result = (Jim_Nvp *) (p); /* found? */ if (p->name) return JIM_OK; else return JIM_ERR; } int Jim_Nvp_name2value_obj_nocase(Jim_Interp *interp, const Jim_Nvp *p, Jim_Obj *o, Jim_Nvp **puthere) { return Jim_Nvp_name2value_nocase(interp, p, Jim_String(o), puthere); } int Jim_Nvp_name2value_nocase(Jim_Interp *interp, const Jim_Nvp *_p, const char *name, Jim_Nvp **puthere) { const Jim_Nvp *p; p = Jim_Nvp_name2value_nocase_simple(_p, name); if (puthere) *puthere = (Jim_Nvp *) (p); /* found */ if (p->name) return JIM_OK; else return JIM_ERR; } int Jim_Nvp_value2name_obj(Jim_Interp *interp, const Jim_Nvp *p, Jim_Obj *o, Jim_Nvp **result) { int e; jim_wide w; e = Jim_GetWide(interp, o, &w); if (e != JIM_OK) return e; return Jim_Nvp_value2name(interp, p, w, result); } Jim_Nvp *Jim_Nvp_value2name_simple(const Jim_Nvp *p, int value) { while (p->name) { if (value == p->value) break; p++; } return (Jim_Nvp *) (p); } int Jim_Nvp_value2name(Jim_Interp *interp, const Jim_Nvp *_p, int value, Jim_Nvp **result) { const Jim_Nvp *p; p = Jim_Nvp_value2name_simple(_p, value); if (result) *result = (Jim_Nvp *) (p); if (p->name) return JIM_OK; else return JIM_ERR; } int Jim_GetOpt_Setup(Jim_GetOptInfo *p, Jim_Interp *interp, int argc, Jim_Obj *const *argv) { memset(p, 0, sizeof(*p)); p->interp = interp; p->argc = argc; p->argv = argv; return JIM_OK; } void Jim_GetOpt_Debug(Jim_GetOptInfo *p) { int x; fprintf(stderr, "---args---\n"); for (x = 0; x < p->argc; x++) fprintf(stderr, "%2d) %s\n", x, Jim_String(p->argv[x])); fprintf(stderr, "-------\n"); } int Jim_GetOpt_Obj(Jim_GetOptInfo *goi, Jim_Obj **puthere) { Jim_Obj *o; o = NULL; /* failure */ if (goi->argc) { /* success */ o = goi->argv[0]; goi->argc -= 1; goi->argv += 1; } if (puthere) *puthere = o; if (o != NULL) return JIM_OK; else return JIM_ERR; } int Jim_GetOpt_String(Jim_GetOptInfo *goi, char **puthere, int *len) { int r; Jim_Obj *o; const char *cp; r = Jim_GetOpt_Obj(goi, &o); if (r == JIM_OK) { cp = Jim_GetString(o, len); if (puthere) { /* remove const */ *puthere = (char *)(cp); } } return r; } int Jim_GetOpt_Double(Jim_GetOptInfo *goi, double *puthere) { int r; Jim_Obj *o; double _safe; if (puthere == NULL) puthere = &_safe; r = Jim_GetOpt_Obj(goi, &o); if (r == JIM_OK) { r = Jim_GetDouble(goi->interp, o, puthere); if (r != JIM_OK) Jim_SetResultFormatted(goi->interp, "not a number: %#s", o); } return r; } int Jim_GetOpt_Wide(Jim_GetOptInfo *goi, jim_wide *puthere) { int r; Jim_Obj *o; jim_wide _safe; if (puthere == NULL) puthere = &_safe; r = Jim_GetOpt_Obj(goi, &o); if (r == JIM_OK) r = Jim_GetWide(goi->interp, o, puthere); return r; } int Jim_GetOpt_Nvp(Jim_GetOptInfo *goi, const Jim_Nvp *nvp, Jim_Nvp **puthere) { Jim_Nvp *_safe; Jim_Obj *o; int e; if (puthere == NULL) puthere = &_safe; e = Jim_GetOpt_Obj(goi, &o); if (e == JIM_OK) e = Jim_Nvp_name2value_obj(goi->interp, nvp, o, puthere); return e; } void Jim_GetOpt_NvpUnknown(Jim_GetOptInfo *goi, const Jim_Nvp *nvptable, int hadprefix) { if (hadprefix) Jim_SetResult_NvpUnknown(goi->interp, goi->argv[-2], goi->argv[-1], nvptable); else Jim_SetResult_NvpUnknown(goi->interp, NULL, goi->argv[-1], nvptable); } int Jim_GetOpt_Enum(Jim_GetOptInfo *goi, const char *const *lookup, int *puthere) { int _safe; Jim_Obj *o; int e; if (puthere == NULL) puthere = &_safe; e = Jim_GetOpt_Obj(goi, &o); if (e == JIM_OK) e = Jim_GetEnum(goi->interp, o, lookup, puthere, "option", JIM_ERRMSG); return e; } void Jim_SetResult_NvpUnknown(Jim_Interp *interp, Jim_Obj *param_name, Jim_Obj *param_value, const Jim_Nvp *nvp) { if (param_name) Jim_SetResultFormatted(interp, "%#s: Unknown: %#s, try one of: ", param_name, param_value); else Jim_SetResultFormatted(interp, "Unknown param: %#s, try one of: ", param_value); while (nvp->name) { const char *a; const char *b; if ((nvp + 1)->name) { a = nvp->name; b = ", "; } else { a = "or "; b = nvp->name; } Jim_AppendStrings(interp, Jim_GetResult(interp), a, b, NULL); nvp++; } } const char *Jim_Debug_ArgvString(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { static Jim_Obj *debug_string_obj; int x; if (debug_string_obj) Jim_FreeObj(interp, debug_string_obj); debug_string_obj = Jim_NewEmptyStringObj(interp); for (x = 0; x < argc; x++) Jim_AppendStrings(interp, debug_string_obj, Jim_String(argv[x]), " ", NULL); return Jim_String(debug_string_obj); } int Jim_nvpInit(Jim_Interp *interp) { /* This is really a helper library, not an extension, but this is the easy way */ return JIM_OK; } openocd-0.7.0/src/helper/util.c0000644000175000001440000000444612134336410013256 00000000000000/*************************************************************************** * Copyright (C) 2010 by Øyvind Harboe * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /* this file contains various functionality useful to standalone systems */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "log.h" #include "time_support.h" static int util_Jim_Command_ms(Jim_Interp *interp, int argc, Jim_Obj * const *argv) { if (argc != 1) { Jim_WrongNumArgs(interp, 1, argv, "ls ?dir?"); return JIM_ERR; } /* Cast from 64 to 32 bit int works for 2's-compliment * when calculating differences*/ Jim_SetResult(interp, Jim_NewIntObj(interp, (int)timeval_ms())); return JIM_OK; } static const struct command_registration util_command_handlers[] = { /* jim handlers */ { .name = "ms", .mode = COMMAND_ANY, .jim_handler = util_Jim_Command_ms, .help = "Returns ever increasing milliseconds. Used to calculuate differences in time.", .usage = "", }, COMMAND_REGISTRATION_DONE }; int util_init(struct command_context *cmd_ctx) { return register_commands(cmd_ctx, NULL, util_command_handlers); } openocd-0.7.0/src/helper/ioutil_stubs.c0000644000175000001440000000311312134336410015014 00000000000000/*************************************************************************** * Copyright (C) 2009 Zachary T Welch * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include "ioutil.h" #include "log.h" int ioutil_init(struct command_context *cmd_ctx) { LOG_DEBUG("libocdhelper was built without I/O utility support"); return ERROR_OK; } openocd-0.7.0/src/helper/replacements.c0000644000175000001440000001702712134336410014762 00000000000000/*************************************************************************** * Copyright (C) 2006 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /* DANGER!!!! These must be defined *BEFORE* replacements.h and the malloc() macro!!!! */ #include #include /* * clear_malloc * * will alloc memory and clear it */ void *clear_malloc(size_t size) { void *t = malloc(size); if (t != NULL) memset(t, 0x00, size); return t; } void *fill_malloc(size_t size) { void *t = malloc(size); if (t != NULL) { /* We want to initialize memory to some known bad state. * 0 and 0xff yields 0 and -1 as integers, which often * have meaningful values. 0x5555... is not often a valid * integer and is quite easily spotted in the debugger * also it is almost certainly an invalid address */ memset(t, 0x55, size); } return t; } #define IN_REPLACEMENTS_C #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_STRINGS_H #include #endif #ifdef _WIN32 #include #endif /* replacements for gettimeofday */ #ifndef HAVE_GETTIMEOFDAY /* Windows */ #ifdef _WIN32 #ifndef __GNUC__ #define EPOCHFILETIME (116444736000000000i64) #else #define EPOCHFILETIME (116444736000000000LL) #endif int gettimeofday(struct timeval *tv, struct timezone *tz) { FILETIME ft; LARGE_INTEGER li; __int64 t; static int tzflag; if (tv) { GetSystemTimeAsFileTime(&ft); li.LowPart = ft.dwLowDateTime; li.HighPart = ft.dwHighDateTime; t = li.QuadPart; /* In 100-nanosecond intervals */ t -= EPOCHFILETIME; /* Offset to the Epoch time */ t /= 10; /* In microseconds */ tv->tv_sec = (long)(t / 1000000); tv->tv_usec = (long)(t % 1000000); } if (tz) { if (!tzflag) { _tzset(); tzflag++; } tz->tz_minuteswest = _timezone / 60; tz->tz_dsttime = _daylight; } return 0; } #endif /* _WIN32 */ #endif /* HAVE_GETTIMEOFDAY */ #ifndef HAVE_STRNLEN size_t strnlen(const char *s, size_t maxlen) { const char *end = (const char *)memchr(s, '\0', maxlen); return end ? (size_t) (end - s) : maxlen; } #endif #ifndef HAVE_STRNDUP char *strndup(const char *s, size_t n) { size_t len = strnlen(s, n); char *new = (char *) malloc(len + 1); if (new == NULL) return NULL; new[len] = '\0'; return (char *) memcpy(new, s, len); } #endif #ifdef _WIN32 int win_select(int max_fd, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *tv) { DWORD ms_total, limit; HANDLE handles[MAXIMUM_WAIT_OBJECTS]; int handle_slot_to_fd[MAXIMUM_WAIT_OBJECTS]; int n_handles = 0, i; fd_set sock_read, sock_write, sock_except; fd_set aread, awrite, aexcept; int sock_max_fd = -1; struct timeval tvslice; int retcode; #define SAFE_FD_ISSET(fd, set) (set != NULL && FD_ISSET(fd, set)) /* calculate how long we need to wait in milliseconds */ if (tv == NULL) ms_total = INFINITE; else { ms_total = tv->tv_sec * 1000; ms_total += tv->tv_usec / 1000; } FD_ZERO(&sock_read); FD_ZERO(&sock_write); FD_ZERO(&sock_except); /* build an array of handles for non-sockets */ for (i = 0; i < max_fd; i++) { if (SAFE_FD_ISSET(i, rfds) || SAFE_FD_ISSET(i, wfds) || SAFE_FD_ISSET(i, efds)) { intptr_t handle = (intptr_t) _get_osfhandle(i); handles[n_handles] = (HANDLE)handle; if (handles[n_handles] == INVALID_HANDLE_VALUE) { /* socket */ if (SAFE_FD_ISSET(i, rfds)) FD_SET(i, &sock_read); if (SAFE_FD_ISSET(i, wfds)) FD_SET(i, &sock_write); if (SAFE_FD_ISSET(i, efds)) FD_SET(i, &sock_except); if (i > sock_max_fd) sock_max_fd = i; } else { handle_slot_to_fd[n_handles] = i; n_handles++; } } } if (n_handles == 0) { /* plain sockets only - let winsock handle the whole thing */ return select(max_fd, rfds, wfds, efds, tv); } /* mixture of handles and sockets; lets multiplex between * winsock and waiting on the handles */ FD_ZERO(&aread); FD_ZERO(&awrite); FD_ZERO(&aexcept); limit = GetTickCount() + ms_total; do { retcode = 0; if (sock_max_fd >= 0) { /* overwrite the zero'd sets here; the select call * will clear those that are not active */ aread = sock_read; awrite = sock_write; aexcept = sock_except; tvslice.tv_sec = 0; tvslice.tv_usec = 1000; retcode = select(sock_max_fd + 1, &aread, &awrite, &aexcept, &tvslice); } if (n_handles > 0) { /* check handles */ DWORD wret; wret = MsgWaitForMultipleObjects(n_handles, handles, FALSE, retcode > 0 ? 0 : 1, QS_ALLEVENTS); if (wret == WAIT_TIMEOUT) { /* set retcode to 0; this is the default. * select() may have set it to something else, * in which case we leave it alone, so this branch * does nothing */ ; } else if (wret == WAIT_FAILED) { if (retcode == 0) retcode = -1; } else { if (retcode < 0) retcode = 0; for (i = 0; i < n_handles; i++) { if (WAIT_OBJECT_0 == WaitForSingleObject(handles[i], 0)) { if (SAFE_FD_ISSET(handle_slot_to_fd[i], rfds)) { DWORD dwBytes; intptr_t handle = (intptr_t) _get_osfhandle( handle_slot_to_fd[i]); if (PeekNamedPipe((HANDLE)handle, NULL, 0, NULL, &dwBytes, NULL)) { /* check to see if gdb pipe has data available */ if (dwBytes) { FD_SET(handle_slot_to_fd[i], &aread); retcode++; } } else { FD_SET(handle_slot_to_fd[i], &aread); retcode++; } } if (SAFE_FD_ISSET(handle_slot_to_fd[i], wfds)) { FD_SET(handle_slot_to_fd[i], &awrite); retcode++; } if (SAFE_FD_ISSET(handle_slot_to_fd[i], efds)) { FD_SET(handle_slot_to_fd[i], &aexcept); retcode++; } } } } } } while (retcode == 0 && (ms_total == INFINITE || GetTickCount() < limit)); if (rfds) *rfds = aread; if (wfds) *wfds = awrite; if (efds) *efds = aexcept; return retcode; } #endif openocd-0.7.0/src/helper/Makefile.am0000644000175000001440000000176512134336410014172 00000000000000include $(top_srcdir)/common.mk METASOURCES = AUTO noinst_LTLIBRARIES = libhelper.la CONFIGFILES = options.c time_support_common.c libhelper_la_SOURCES = \ binarybuffer.c \ $(CONFIGFILES) \ configuration.c \ log.c \ command.c \ time_support.c \ replacements.c \ fileio.c \ util.c \ jim-nvp.c if IOUTIL libhelper_la_SOURCES += ioutil.c else libhelper_la_SOURCES += ioutil_stubs.c endif libhelper_la_CFLAGS = if IS_MINGW # FD_* macros are sloppy with their signs on MinGW32 platform libhelper_la_CFLAGS += -Wno-sign-compare endif noinst_HEADERS = \ binarybuffer.h \ configuration.h \ ioutil.h \ list.h \ util.h \ types.h \ log.h \ command.h \ time_support.h \ replacements.h \ fileio.h \ system.h \ bin2char.c \ jim-nvp.h EXTRA_DIST = startup.tcl BIN2C = bin2char$(EXEEXT_FOR_BUILD) BUILT_SOURCES = $(BIN2C) $(BIN2C): bin2char.c ${CC_FOR_BUILD} ${CFLAGS_FOR_BUILD} $(srcdir)/bin2char.c -o $@ CLEANFILES = bin2char$(EXEEXT_FOR_BUILD) MAINTAINERCLEANFILES = $(srcdir)/Makefile.in openocd-0.7.0/src/helper/ioutil.c0000644000175000001440000003363212134336410013605 00000000000000/*************************************************************************** * Copyright (C) 2007-2010 by Øyvind Harboe * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /* this file contains various functionality useful to standalone systems */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "log.h" #include "time_support.h" #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_DIRENT_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_NET_IF_H #include #endif #ifdef HAVE_SYS_IOCTL_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif #ifdef HAVE_IFADDRS_H #include #endif #ifdef HAVE_MALLOC_H #include #endif /* loads a file and returns a pointer to it in memory. The file contains * a 0 byte(sentinel) after len bytes - the length of the file. */ int loadFile(const char *fileName, void **data, size_t *len) { /* ensure returned length is always sane */ *len = 0; FILE *pFile; pFile = fopen(fileName, "rb"); if (pFile == NULL) { LOG_ERROR("Can't open %s", fileName); return ERROR_FAIL; } if (fseek(pFile, 0, SEEK_END) != 0) { LOG_ERROR("Can't open %s", fileName); fclose(pFile); return ERROR_FAIL; } long fsize = ftell(pFile); if (fsize == -1) { LOG_ERROR("Can't open %s", fileName); fclose(pFile); return ERROR_FAIL; } *len = fsize; if (fseek(pFile, 0, SEEK_SET) != 0) { LOG_ERROR("Can't open %s", fileName); fclose(pFile); return ERROR_FAIL; } *data = malloc(*len + 1); if (*data == NULL) { LOG_ERROR("Can't open %s", fileName); fclose(pFile); return ERROR_FAIL; } if (fread(*data, 1, *len, pFile) != *len) { fclose(pFile); free(*data); LOG_ERROR("Can't open %s", fileName); return ERROR_FAIL; } fclose(pFile); /* 0-byte after buffer (not included in *len) serves as a sentinel */ char *buf = (char *)*data; buf[*len] = 0; return ERROR_OK; } COMMAND_HANDLER(handle_cat_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; /* NOTE!!! we only have line printing capability so we print the entire file as a single * line. */ void *data; size_t len; int retval = loadFile(CMD_ARGV[0], &data, &len); if (retval == ERROR_OK) { command_print(CMD_CTX, "%s", (char *)data); free(data); } else command_print(CMD_CTX, "%s not found", CMD_ARGV[0]); return ERROR_OK; } COMMAND_HANDLER(handle_trunc_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; FILE *config_file = NULL; config_file = fopen(CMD_ARGV[0], "w"); if (config_file != NULL) fclose(config_file); return ERROR_OK; } #ifdef HAVE_MALLOC_H COMMAND_HANDLER(handle_meminfo_command) { static int prev; struct mallinfo info; if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; info = mallinfo(); if (prev > 0) command_print(CMD_CTX, "Diff: %d", prev - info.fordblks); prev = info.fordblks; command_print(CMD_CTX, "Available ram: %d", info.fordblks); return ERROR_OK; } #endif COMMAND_HANDLER(handle_append_command) { if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; int retval = ERROR_FAIL; FILE *config_file = NULL; config_file = fopen(CMD_ARGV[0], "a"); if (config_file != NULL) { fseek(config_file, 0, SEEK_END); unsigned i; for (i = 1; i < CMD_ARGC; i++) { if (fwrite(CMD_ARGV[i], 1, strlen(CMD_ARGV[i]), config_file) != strlen(CMD_ARGV[i])) break; if (i != CMD_ARGC - 1) { if (fwrite(" ", 1, 1, config_file) != 1) break; } } if ((i == CMD_ARGC) && (fwrite("\n", 1, 1, config_file) == 1)) retval = ERROR_OK; fclose(config_file); } return retval; } COMMAND_HANDLER(handle_cp_command) { if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; /* NOTE!!! we only have line printing capability so we print the entire file as a single * line. */ void *data; size_t len; int retval = loadFile(CMD_ARGV[0], &data, &len); if (retval != ERROR_OK) return retval; FILE *f = fopen(CMD_ARGV[1], "wb"); if (f == NULL) retval = ERROR_COMMAND_SYNTAX_ERROR; size_t pos = 0; for (;; ) { size_t chunk = len - pos; static const size_t maxChunk = 512 * 1024; /* ~1/sec */ if (chunk > maxChunk) chunk = maxChunk; if ((retval == ERROR_OK) && (fwrite(((char *)data) + pos, 1, chunk, f) != chunk)) retval = ERROR_COMMAND_SYNTAX_ERROR; if (retval != ERROR_OK) break; command_print(CMD_CTX, "%zu", len - pos); pos += chunk; if (pos == len) break; } if (retval == ERROR_OK) command_print(CMD_CTX, "Copied %s to %s", CMD_ARGV[0], CMD_ARGV[1]); else command_print(CMD_CTX, "copy failed"); if (data != NULL) free(data); if (f != NULL) fclose(f); if (retval != ERROR_OK) unlink(CMD_ARGV[1]); return retval; } #define SHOW_RESULT(a, b) LOG_ERROR(# a " failed %d\n", (int)b) #define IOSIZE 512 void copyfile(char *name2, char *name1) { int err; char buf[IOSIZE]; int fd1, fd2; ssize_t done, wrote; fd1 = open(name1, O_WRONLY | O_CREAT, 0664); if (fd1 < 0) SHOW_RESULT(open, fd1); fd2 = open(name2, O_RDONLY); if (fd2 < 0) SHOW_RESULT(open, fd2); for (;; ) { done = read(fd2, buf, IOSIZE); if (done < 0) { SHOW_RESULT(read, done); break; } if (done == 0) break; wrote = write(fd1, buf, done); if (wrote != done) SHOW_RESULT(write, wrote); if (wrote != done) break; } err = close(fd1); if (err < 0) SHOW_RESULT(close, err); err = close(fd2); if (err < 0) SHOW_RESULT(close, err); } /* utility fn to copy a directory */ void copydir(char *name, char *destdir) { int err; DIR *dirp; dirp = opendir(destdir); if (dirp == NULL) mkdir(destdir, 0777); else err = closedir(dirp); dirp = opendir(name); if (dirp == NULL) SHOW_RESULT(opendir, -1); for (;; ) { struct dirent *entry = readdir(dirp); if (entry == NULL) break; if (strcmp(entry->d_name, ".") == 0) continue; if (strcmp(entry->d_name, "..") == 0) continue; int isDir = 0; struct stat buf; char fullPath[PATH_MAX]; strncpy(fullPath, name, PATH_MAX); strcat(fullPath, "/"); strncat(fullPath, entry->d_name, PATH_MAX - strlen(fullPath)); if (stat(fullPath, &buf) == -1) { LOG_ERROR("unable to read status from %s", fullPath); break; } isDir = S_ISDIR(buf.st_mode) != 0; if (isDir) continue; /* diag_printf(": entry %14s",entry->d_name); */ char fullname[PATH_MAX]; char fullname2[PATH_MAX]; strcpy(fullname, name); strcat(fullname, "/"); strcat(fullname, entry->d_name); strcpy(fullname2, destdir); strcat(fullname2, "/"); strcat(fullname2, entry->d_name); /* diag_printf("from %s to %s\n", fullname, fullname2); */ copyfile(fullname, fullname2); /* diag_printf("\n"); */ } err = closedir(dirp); if (err < 0) SHOW_RESULT(stat, err); } COMMAND_HANDLER(handle_rm_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; bool del = false; if (rmdir(CMD_ARGV[0]) == 0) del = true; else if (unlink(CMD_ARGV[0]) == 0) del = true; return del ? ERROR_OK : ERROR_FAIL; } static int ioutil_Jim_Command_ls(Jim_Interp *interp, int argc, Jim_Obj * const *argv) { if (argc != 2) { Jim_WrongNumArgs(interp, 1, argv, "ls ?dir?"); return JIM_ERR; } char *name = (char *) Jim_GetString(argv[1], NULL); DIR *dirp = NULL; dirp = opendir(name); if (dirp == NULL) return JIM_ERR; Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0); for (;; ) { struct dirent *entry = NULL; entry = readdir(dirp); if (entry == NULL) break; if ((strcmp(".", entry->d_name) == 0) || (strcmp("..", entry->d_name) == 0)) continue; Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, entry->d_name, strlen(entry->d_name))); } closedir(dirp); Jim_SetResult(interp, objPtr); return JIM_OK; } static int ioutil_Jim_Command_peek(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 2) { Jim_WrongNumArgs(interp, 1, argv, "peek ?address?"); return JIM_ERR; } long address; if (Jim_GetLong(interp, argv[1], &address) != JIM_OK) return JIM_ERR; int value = *((volatile int *) address); Jim_SetResult(interp, Jim_NewIntObj(interp, value)); return JIM_OK; } static int ioutil_Jim_Command_poke(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 3) { Jim_WrongNumArgs(interp, 1, argv, "poke ?address? ?value?"); return JIM_ERR; } long address; if (Jim_GetLong(interp, argv[1], &address) != JIM_OK) return JIM_ERR; long value; if (Jim_GetLong(interp, argv[2], &value) != JIM_OK) return JIM_ERR; *((volatile int *) address) = value; return JIM_OK; } /* not so pretty code to fish out ip number*/ static int ioutil_Jim_Command_ip(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { #if !defined(__CYGWIN__) Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0); struct ifaddrs *ifa = NULL, *ifp = NULL; if (getifaddrs(&ifp) < 0) return JIM_ERR; for (ifa = ifp; ifa; ifa = ifa->ifa_next) { char ip[200]; socklen_t salen; if (ifa->ifa_addr->sa_family == AF_INET) salen = sizeof(struct sockaddr_in); else if (ifa->ifa_addr->sa_family == AF_INET6) salen = sizeof(struct sockaddr_in6); else continue; if (getnameinfo(ifa->ifa_addr, salen, ip, sizeof(ip), NULL, 0, NI_NUMERICHOST) < 0) continue; Jim_AppendString(interp, tclOutput, ip, strlen(ip)); break; } freeifaddrs(ifp); #else Jim_Obj *tclOutput = Jim_NewStringObj(interp, "fixme!!!", 0); LOG_ERROR("NOT IMPLEMENTED!!!"); #endif Jim_SetResult(interp, tclOutput); return JIM_OK; } #ifdef HAVE_SYS_IOCTL_H #ifdef SIOCGIFHWADDR /* not so pretty code to fish out eth0 mac address */ static int ioutil_Jim_Command_mac(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { struct ifreq *ifr, *ifend; struct ifreq ifreq; struct ifconf ifc; struct ifreq ifs[5]; int SockFD; SockFD = socket(AF_INET, SOCK_DGRAM, 0); if (SockFD < 0) return JIM_ERR; ifc.ifc_len = sizeof(ifs); ifc.ifc_req = ifs; if (ioctl(SockFD, SIOCGIFCONF, &ifc) < 0) { close(SockFD); return JIM_ERR; } ifend = ifs + (ifc.ifc_len / sizeof(struct ifreq)); for (ifr = ifc.ifc_req; ifr < ifend; ifr++) { /* if (ifr->ifr_addr.sa_family == AF_INET) */ { if (strcmp("eth0", ifr->ifr_name) != 0) continue; strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name)); if (ioctl(SockFD, SIOCGIFHWADDR, &ifreq) < 0) { close(SockFD); return JIM_ERR; } close(SockFD); Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0); char buffer[256]; sprintf(buffer, "%02x-%02x-%02x-%02x-%02x-%02x", ifreq.ifr_hwaddr.sa_data[0]&0xff, ifreq.ifr_hwaddr.sa_data[1]&0xff, ifreq.ifr_hwaddr.sa_data[2]&0xff, ifreq.ifr_hwaddr.sa_data[3]&0xff, ifreq.ifr_hwaddr.sa_data[4]&0xff, ifreq.ifr_hwaddr.sa_data[5]&0xff); Jim_AppendString(interp, tclOutput, buffer, strlen(buffer)); Jim_SetResult(interp, tclOutput); return JIM_OK; } } close(SockFD); return JIM_ERR; } #endif #endif static const struct command_registration ioutil_command_handlers[] = { { .name = "cat", .handler = handle_cat_command, .mode = COMMAND_ANY, .help = "display text file content", .usage = "file_name", }, { .name = "trunc", .handler = handle_trunc_command, .mode = COMMAND_ANY, .help = "truncate a file to zero length", .usage = "file_name", }, { .name = "cp", .handler = handle_cp_command, .mode = COMMAND_ANY, .help = "copy a file", .usage = "src_file_name dst_file_name", }, { .name = "append_file", .handler = handle_append_command, .mode = COMMAND_ANY, .help = "append a variable number of strings to a file", .usage = "file_name [, [, ...]]", }, #ifdef HAVE_MALLOC_H { .name = "meminfo", .handler = handle_meminfo_command, .mode = COMMAND_ANY, .help = "display free heap space", }, #endif { .name = "rm", .mode = COMMAND_ANY, .handler = handle_rm_command, .help = "remove a directory or file", .usage = "file_name", }, /* * Peek and poke are security holes -- they manipulate * server-internal addresses. */ /* jim handlers */ { .name = "peek", .mode = COMMAND_ANY, .jim_handler = ioutil_Jim_Command_peek, .help = "peek at a memory address", .usage = "address", }, { .name = "poke", .mode = COMMAND_ANY, .jim_handler = ioutil_Jim_Command_poke, .help = "poke at a memory address", .usage = "address value", }, { .name = "ls", .mode = COMMAND_ANY, .jim_handler = ioutil_Jim_Command_ls, .help = "show a listing of files", .usage = "dirname", }, #ifdef HAVE_SYS_IOCTL_H #ifdef SIOCGIFHWADDR { .name = "mac", .mode = COMMAND_ANY, .jim_handler = ioutil_Jim_Command_mac, .help = "show MAC address", }, #endif #endif { .name = "ip", .jim_handler = ioutil_Jim_Command_ip, .mode = COMMAND_ANY, .help = "show IP address", }, COMMAND_REGISTRATION_DONE }; int ioutil_init(struct command_context *cmd_ctx) { return register_commands(cmd_ctx, NULL, ioutil_command_handlers); } openocd-0.7.0/src/helper/log.c0000644000175000001440000003014512134336410013055 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "time_support.h" /* @todo the inclusion of server.h here is a layering violation */ #include #include #ifdef _DEBUG_FREE_SPACE_ #ifdef HAVE_MALLOC_H #include #else #error "malloc.h is required to use --enable-malloc-logging" #endif #endif int debug_level = -1; static FILE *log_output; static struct log_callback *log_callbacks; static long long last_time; static long long current_time; static long long start; static char *log_strings[5] = { "User : ", "Error: ", "Warn : ", /* want a space after each colon, all same width, colons aligned */ "Info : ", "Debug: " }; static int count; static struct store_log_forward *log_head; static int log_forward_count; struct store_log_forward { struct store_log_forward *next; const char *file; int line; const char *function; const char *string; }; /* either forward the log to the listeners or store it for possible forwarding later */ static void log_forward(const char *file, unsigned line, const char *function, const char *string) { if (log_forward_count == 0) { struct log_callback *cb, *next; cb = log_callbacks; /* DANGER!!!! the log callback can remove itself!!!! */ while (cb) { next = cb->next; cb->fn(cb->priv, file, line, function, string); cb = next; } } else { struct store_log_forward *log = malloc(sizeof(struct store_log_forward)); log->file = strdup(file); log->line = line; log->function = strdup(function); log->string = strdup(string); log->next = NULL; if (log_head == NULL) log_head = log; else { /* append to tail */ struct store_log_forward *t; t = log_head; while (t->next != NULL) t = t->next; t->next = log; } } } /* The log_puts() serves to somewhat different goals: * * - logging * - feeding low-level info to the user in GDB or Telnet * * The latter dictates that strings without newline are not logged, lest there * will be *MANY log lines when sending one char at the time(e.g. * target_request.c). * */ static void log_puts(enum log_levels level, const char *file, int line, const char *function, const char *string) { char *f; if (level == LOG_LVL_OUTPUT) { /* do not prepend any headers, just print out what we were given and return */ fputs(string, log_output); fflush(log_output); return; } f = strrchr(file, '/'); if (f != NULL) file = f + 1; if (strlen(string) > 0) { if (debug_level >= LOG_LVL_DEBUG) { /* print with count and time information */ int t = (int)(timeval_ms()-start); #ifdef _DEBUG_FREE_SPACE_ struct mallinfo info; info = mallinfo(); #endif fprintf(log_output, "%s%d %d %s:%d %s()" #ifdef _DEBUG_FREE_SPACE_ " %d" #endif ": %s", log_strings[level + 1], count, t, file, line, function, #ifdef _DEBUG_FREE_SPACE_ info.fordblks, #endif string); } else { /* if we are using gdb through pipes then we do not want any output * to the pipe otherwise we get repeated strings */ fprintf(log_output, "%s%s", (level > LOG_LVL_USER) ? log_strings[level + 1] : "", string); } } else { /* Empty strings are sent to log callbacks to keep e.g. gdbserver alive, here we do *nothing. */ } fflush(log_output); /* Never forward LOG_LVL_DEBUG, too verbose and they can be found in the log if need be */ if (level <= LOG_LVL_INFO) log_forward(file, line, function, string); } void log_printf(enum log_levels level, const char *file, unsigned line, const char *function, const char *format, ...) { char *string; va_list ap; count++; if (level > debug_level) return; va_start(ap, format); string = alloc_vprintf(format, ap); if (string != NULL) { log_puts(level, file, line, function, string); free(string); } va_end(ap); } void log_printf_lf(enum log_levels level, const char *file, unsigned line, const char *function, const char *format, ...) { char *string; va_list ap; count++; if (level > debug_level) return; va_start(ap, format); string = alloc_vprintf(format, ap); if (string != NULL) { strcat(string, "\n"); /* alloc_vprintf guaranteed the buffer to be at least one *char longer */ log_puts(level, file, line, function, string); free(string); } va_end(ap); } COMMAND_HANDLER(handle_debug_level_command) { if (CMD_ARGC == 1) { int new_level; COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], new_level); if ((new_level > LOG_LVL_DEBUG) || (new_level < LOG_LVL_SILENT)) { LOG_ERROR("level must be between %d and %d", LOG_LVL_SILENT, LOG_LVL_DEBUG); return ERROR_COMMAND_SYNTAX_ERROR; } debug_level = new_level; } else if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; command_print(CMD_CTX, "debug_level: %i", debug_level); return ERROR_OK; } COMMAND_HANDLER(handle_log_output_command) { if (CMD_ARGC == 1) { FILE *file = fopen(CMD_ARGV[0], "w"); if (file) log_output = file; } return ERROR_OK; } static struct command_registration log_command_handlers[] = { { .name = "log_output", .handler = handle_log_output_command, .mode = COMMAND_ANY, .help = "redirect logging to a file (default: stderr)", .usage = "file_name", }, { .name = "debug_level", .handler = handle_debug_level_command, .mode = COMMAND_ANY, .help = "Sets the verbosity level of debugging output. " "0 shows errors only; 1 adds warnings; " "2 (default) adds other info; 3 adds debugging.", .usage = "number", }, COMMAND_REGISTRATION_DONE }; int log_register_commands(struct command_context *cmd_ctx) { return register_commands(cmd_ctx, NULL, log_command_handlers); } void log_init(void) { /* set defaults for daemon configuration, * if not set by cmdline or cfgfile */ if (debug_level == -1) debug_level = LOG_LVL_INFO; char *debug_env = getenv("OPENOCD_DEBUG_LEVEL"); if (NULL != debug_env) { int value; int retval = parse_int(debug_env, &value); if (ERROR_OK == retval && debug_level >= LOG_LVL_SILENT && debug_level <= LOG_LVL_DEBUG) debug_level = value; } if (log_output == NULL) log_output = stderr; start = last_time = timeval_ms(); } int set_log_output(struct command_context *cmd_ctx, FILE *output) { log_output = output; return ERROR_OK; } /* add/remove log callback handler */ int log_add_callback(log_callback_fn fn, void *priv) { struct log_callback *cb; /* prevent the same callback to be registered more than once, just for sure */ for (cb = log_callbacks; cb; cb = cb->next) { if (cb->fn == fn && cb->priv == priv) return ERROR_COMMAND_SYNTAX_ERROR; } /* alloc memory, it is safe just to return in case of an error, no need for the caller to *check this */ cb = malloc(sizeof(struct log_callback)); if (cb == NULL) return ERROR_BUF_TOO_SMALL; /* add item to the beginning of the linked list */ cb->fn = fn; cb->priv = priv; cb->next = log_callbacks; log_callbacks = cb; return ERROR_OK; } int log_remove_callback(log_callback_fn fn, void *priv) { struct log_callback *cb, **p; for (p = &log_callbacks; (cb = *p); p = &(*p)->next) { if (cb->fn == fn && cb->priv == priv) { *p = cb->next; free(cb); return ERROR_OK; } } /* no such item */ return ERROR_COMMAND_SYNTAX_ERROR; } /* return allocated string w/printf() result */ char *alloc_vprintf(const char *fmt, va_list ap) { va_list ap_copy; int len; char *string; /* determine the length of the buffer needed */ va_copy(ap_copy, ap); len = vsnprintf(NULL, 0, fmt, ap_copy); va_end(ap_copy); /* allocate and make room for terminating zero. */ /* FIXME: The old version always allocated at least one byte extra and * other code depend on that. They should be probably be fixed, but for * now reserve the extra byte. */ string = malloc(len + 2); if (string == NULL) return NULL; /* do the real work */ vsnprintf(string, len + 1, fmt, ap); return string; } char *alloc_printf(const char *format, ...) { char *string; va_list ap; va_start(ap, format); string = alloc_vprintf(format, ap); va_end(ap); return string; } /* Code must return to the server loop before 1000ms has returned or invoke * this function. * * The GDB connection will time out if it spends >2000ms and you'll get nasty * error messages from GDB: * * Ignoring packet error, continuing... * Reply contains invalid hex digit 116 * * While it is possible use "set remotetimeout" to more than the default 2000ms * in GDB, OpenOCD guarantees that it sends keep-alive packages on the * GDB protocol and it is a bug in OpenOCD not to either return to the server * loop or invoke keep_alive() every 1000ms. * * This function will send a keep alive packet if >500ms has passed since last time * it was invoked. * * Note that this function can be invoked often, so it needs to be relatively * fast when invoked more often than every 500ms. * */ void keep_alive() { current_time = timeval_ms(); if (current_time-last_time > 1000) { extern int gdb_actual_connections; if (gdb_actual_connections) LOG_WARNING("keep_alive() was not invoked in the " "1000ms timelimit. GDB alive packet not " "sent! (%lld). Workaround: increase " "\"set remotetimeout\" in GDB", current_time-last_time); else LOG_DEBUG("keep_alive() was not invoked in the " "1000ms timelimit (%lld). This may cause " "trouble with GDB connections.", current_time-last_time); } if (current_time-last_time > 500) { /* this will keep the GDB connection alive */ LOG_USER_N("%s", ""); /* DANGER!!!! do not add code to invoke e.g. target event processing, * jim timer processing, etc. it can cause infinite recursion + * jim event callbacks need to happen at a well defined time, * not anywhere keep_alive() is invoked. * * These functions should be invoked at a well defined spot in server.c */ last_time = current_time; } } /* reset keep alive timer without sending message */ void kept_alive() { current_time = timeval_ms(); last_time = current_time; } /* if we sleep for extended periods of time, we must invoke keep_alive() intermittantly */ void alive_sleep(uint64_t ms) { uint64_t napTime = 10; for (uint64_t i = 0; i < ms; i += napTime) { uint64_t sleep_a_bit = ms - i; if (sleep_a_bit > napTime) sleep_a_bit = napTime; usleep(sleep_a_bit * 1000); keep_alive(); } } void busy_sleep(uint64_t ms) { uint64_t then = timeval_ms(); while (timeval_ms() - then < ms) { /* * busy wait */ } } openocd-0.7.0/src/helper/startup.tcl0000644000175000001440000000334612134336410014341 00000000000000# Defines basic Tcl procs that must exist for OpenOCD scripts to work. # # Embedded into OpenOCD executable # # We need to explicitly redirect this to the OpenOCD command # as Tcl defines the exit proc proc exit {} { ocd_throw exit } # All commands are registered with an 'ocd_' prefix, while the "real" # command is a wrapper that calls this function. Its primary purpose is # to discard 'handler' command output, proc ocd_bouncer {name args} { set cmd [format "ocd_%s" $name] set type [eval ocd_command type $cmd $args] if {$type == "native"} { return [eval $cmd $args] } else {if {$type == "simple"} { if {[catch {eval $cmd $args}] == 0} { return "" } else { # 'classic' commands output error message as part of progress output set errmsg "" } } else {if {$type == "group"} { catch {eval ocd_usage $name $args} set errmsg [format "%s: command requires more arguments" \ [concat $name " " $args]] } else { set errmsg [format "Unknown command type: %s" $type] }}} return -code error $errmsg } # Try flipping / and \ to find file if the filename does not # match the precise spelling proc find {filename} { if {[catch {ocd_find $filename} t]==0} { return $t } if {[catch {ocd_find [string map {\ /} $filename} t]==0} { return $t } if {[catch {ocd_find [string map {/ \\} $filename} t]==0} { return $t } # make sure error message matches original input string return -code error "Can't find $filename" } add_usage_text find "" add_help_text find "print full path to file according to OpenOCD search rules" # Find and run a script proc script {filename} { uplevel #0 [list source [find $filename]] } add_help_text script "filename of OpenOCD script (tcl) to run" add_usage_text script "" ######### openocd-0.7.0/src/server/0000755000175000001440000000000012141414413012232 500000000000000openocd-0.7.0/src/server/server_stubs.c0000644000175000001440000000302612134336410015047 00000000000000/*************************************************************************** * Copyright (C) 2009 Zachary T Welch * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include "server.h" void openocd_sleep_prelude(void) { /* no-op */ } void openocd_sleep_postlude(void) { /* no-op */ } openocd-0.7.0/src/server/telnet_server.c0000644000175000001440000004721212137151331015207 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "telnet_server.h" #include #include static const char *telnet_port; static char *negotiate = "\xFF\xFB\x03" /* IAC WILL Suppress Go Ahead */ "\xFF\xFB\x01" /* IAC WILL Echo */ "\xFF\xFD\x03" /* IAC DO Suppress Go Ahead */ "\xFF\xFE\x01"; /* IAC DON'T Echo */ #define CTRL(c) (c - '@') #define TELNET_HISTORY ".openocd_history" /* The only way we can detect that the socket is closed is the first time * we write to it, we will fail. Subsequent write operations will * succeed. Shudder! */ static int telnet_write(struct connection *connection, const void *data, int len) { struct telnet_connection *t_con = connection->priv; if (t_con->closed) return ERROR_SERVER_REMOTE_CLOSED; if (connection_write(connection, data, len) == len) return ERROR_OK; t_con->closed = 1; return ERROR_SERVER_REMOTE_CLOSED; } static int telnet_prompt(struct connection *connection) { struct telnet_connection *t_con = connection->priv; return telnet_write(connection, t_con->prompt, strlen(t_con->prompt)); } static int telnet_outputline(struct connection *connection, const char *line) { int len; /* process lines in buffer */ while (*line) { char *line_end = strchr(line, '\n'); if (line_end) len = line_end-line; else len = strlen(line); telnet_write(connection, line, len); if (line_end) { telnet_write(connection, "\r\n", 2); line += len + 1; } else line += len; } return ERROR_OK; } static int telnet_output(struct command_context *cmd_ctx, const char *line) { struct connection *connection = cmd_ctx->output_handler_priv; return telnet_outputline(connection, line); } static void telnet_log_callback(void *priv, const char *file, unsigned line, const char *function, const char *string) { struct connection *connection = priv; struct telnet_connection *t_con = connection->priv; int i; /* if there is no prompt, simply output the message */ if (t_con->line_cursor < 0) { telnet_outputline(connection, string); return; } /* clear the command line */ for (i = strlen(t_con->prompt) + t_con->line_size; i > 0; i -= 16) telnet_write(connection, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", i > 16 ? 16 : i); for (i = strlen(t_con->prompt) + t_con->line_size; i > 0; i -= 16) telnet_write(connection, " ", i > 16 ? 16 : i); for (i = strlen(t_con->prompt) + t_con->line_size; i > 0; i -= 16) telnet_write(connection, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", i > 16 ? 16 : i); /* output the message */ telnet_outputline(connection, string); /* put the command line to its previous state */ telnet_prompt(connection); telnet_write(connection, t_con->line, t_con->line_size); for (i = t_con->line_size; i > t_con->line_cursor; i--) telnet_write(connection, "\b", 1); } static void telnet_load_history(struct telnet_connection *t_con) { FILE *histfp; char buffer[TELNET_BUFFER_SIZE]; int i = 0; char *history = get_home_dir(TELNET_HISTORY); if (history == NULL) { LOG_INFO("unable to get user home directory, telnet history will be disabled"); return; } histfp = fopen(history, "rb"); if (histfp) { while (fgets(buffer, sizeof(buffer), histfp) != NULL) { char *p = strchr(buffer, '\n'); if (p) *p = '\0'; if (buffer[0] && i < TELNET_LINE_HISTORY_SIZE) t_con->history[i++] = strdup(buffer); } t_con->next_history = i; t_con->next_history %= TELNET_LINE_HISTORY_SIZE; /* try to set to last entry - 1, that way we skip over any exit/shutdown cmds */ t_con->current_history = t_con->next_history > 0 ? i - 1 : 0; fclose(histfp); } free(history); } static void telnet_save_history(struct telnet_connection *t_con) { FILE *histfp; int i; int num; char *history = get_home_dir(TELNET_HISTORY); if (history == NULL) { LOG_INFO("unable to get user home directory, telnet history will be disabled"); return; } histfp = fopen(history, "wb"); if (histfp) { num = TELNET_LINE_HISTORY_SIZE; i = t_con->current_history + 1; i %= TELNET_LINE_HISTORY_SIZE; while (t_con->history[i] == NULL && num > 0) { i++; i %= TELNET_LINE_HISTORY_SIZE; num--; } if (num > 0) { for (; num > 0; num--) { fprintf(histfp, "%s\n", t_con->history[i]); i++; i %= TELNET_LINE_HISTORY_SIZE; } } fclose(histfp); } free(history); } static int telnet_new_connection(struct connection *connection) { struct telnet_connection *telnet_connection = malloc(sizeof(struct telnet_connection)); struct telnet_service *telnet_service = connection->service->priv; int i; connection->priv = telnet_connection; /* initialize telnet connection information */ telnet_connection->closed = 0; telnet_connection->line_size = 0; telnet_connection->line_cursor = 0; telnet_connection->option_size = 0; telnet_connection->prompt = strdup("> "); telnet_connection->state = TELNET_STATE_DATA; /* output goes through telnet connection */ command_set_output_handler(connection->cmd_ctx, telnet_output, connection); /* negotiate telnet options */ telnet_write(connection, negotiate, strlen(negotiate)); /* print connection banner */ if (telnet_service->banner) { telnet_write(connection, telnet_service->banner, strlen(telnet_service->banner)); telnet_write(connection, "\r\n", 2); } /* the prompt is always placed at the line beginning */ telnet_write(connection, "\r", 1); telnet_prompt(connection); /* initialize history */ for (i = 0; i < TELNET_LINE_HISTORY_SIZE; i++) telnet_connection->history[i] = NULL; telnet_connection->next_history = 0; telnet_connection->current_history = 0; telnet_load_history(telnet_connection); log_add_callback(telnet_log_callback, connection); return ERROR_OK; } static void telnet_clear_line(struct connection *connection, struct telnet_connection *t_con) { /* move to end of line */ if (t_con->line_cursor < t_con->line_size) telnet_write(connection, t_con->line + t_con->line_cursor, t_con->line_size - t_con->line_cursor); /* backspace, overwrite with space, backspace */ while (t_con->line_size > 0) { telnet_write(connection, "\b \b", 3); t_con->line_size--; } t_con->line_cursor = 0; } static int telnet_input(struct connection *connection) { int bytes_read; unsigned char buffer[TELNET_BUFFER_SIZE]; unsigned char *buf_p; struct telnet_connection *t_con = connection->priv; struct command_context *command_context = connection->cmd_ctx; bytes_read = connection_read(connection, buffer, TELNET_BUFFER_SIZE); if (bytes_read == 0) return ERROR_SERVER_REMOTE_CLOSED; else if (bytes_read == -1) { LOG_ERROR("error during read: %s", strerror(errno)); return ERROR_SERVER_REMOTE_CLOSED; } buf_p = buffer; while (bytes_read) { switch (t_con->state) { case TELNET_STATE_DATA: if (*buf_p == 0xff) t_con->state = TELNET_STATE_IAC; else { if (isprint(*buf_p)) { /* printable character */ /* watch buffer size leaving one spare character for * string null termination */ if (t_con->line_size == TELNET_LINE_MAX_SIZE-1) { /* output audible bell if buffer is full * "\a" does not work, at least on windows */ telnet_write(connection, "\x07", 1); } else if (t_con->line_cursor == t_con->line_size) { telnet_write(connection, buf_p, 1); t_con->line[t_con->line_size++] = *buf_p; t_con->line_cursor++; } else { int i; memmove(t_con->line + t_con->line_cursor + 1, t_con->line + t_con->line_cursor, t_con->line_size - t_con->line_cursor); t_con->line[t_con->line_cursor] = *buf_p; t_con->line_size++; telnet_write(connection, t_con->line + t_con->line_cursor, t_con->line_size - t_con->line_cursor); t_con->line_cursor++; for (i = t_con->line_cursor; i < t_con->line_size; i++) telnet_write(connection, "\b", 1); } } else { /* non-printable */ if (*buf_p == 0x1b) { /* escape */ t_con->state = TELNET_STATE_ESCAPE; t_con->last_escape = '\x00'; } else if ((*buf_p == 0xd) || (*buf_p == 0xa)) { /* CR/LF */ int retval; /* skip over combinations with CR/LF and NUL characters */ if ((bytes_read > 1) && ((*(buf_p + 1) == 0xa) || (*(buf_p + 1) == 0xd))) { buf_p++; bytes_read--; } if ((bytes_read > 1) && (*(buf_p + 1) == 0)) { buf_p++; bytes_read--; } t_con->line[t_con->line_size] = 0; telnet_write(connection, "\r\n\x00", 3); if (strcmp(t_con->line, "history") == 0) { int i; for (i = 1; i < TELNET_LINE_HISTORY_SIZE; i++) { /* the t_con->next_history line contains empty string * (unless NULL), thus it is not printed */ char *history_line = t_con->history[(t_con-> next_history + i) % TELNET_LINE_HISTORY_SIZE]; if (history_line) { telnet_write(connection, history_line, strlen(history_line)); telnet_write(connection, "\r\n\x00", 3); } } t_con->line_size = 0; t_con->line_cursor = 0; continue; } /* save only non-blank not repeating lines in the history */ char *prev_line = t_con->history[(t_con->current_history > 0) ? t_con->current_history - 1 : TELNET_LINE_HISTORY_SIZE-1]; if (*t_con->line && (prev_line == NULL || strcmp(t_con->line, prev_line))) { /* if the history slot is already taken, free it */ if (t_con->history[t_con->next_history]) free(t_con->history[t_con->next_history]); /* add line to history */ t_con->history[t_con->next_history] = strdup(t_con->line); /* wrap history at TELNET_LINE_HISTORY_SIZE */ t_con->next_history = (t_con->next_history + 1) % TELNET_LINE_HISTORY_SIZE; /* current history line starts at the new entry */ t_con->current_history = t_con->next_history; if (t_con->history[t_con->current_history]) free(t_con->history[t_con->current_history]); t_con->history[t_con->current_history] = strdup(""); } t_con->line_size = 0; /* to suppress prompt in log callback during command execution */ t_con->line_cursor = -1; if (strcmp(t_con->line, "shutdown") == 0) telnet_save_history(t_con); retval = command_run_line(command_context, t_con->line); t_con->line_cursor = 0; if (retval == ERROR_COMMAND_CLOSE_CONNECTION) return ERROR_SERVER_REMOTE_CLOSED; /* the prompt is always * placed at the line beginning */ telnet_write(connection, "\r", 1); retval = telnet_prompt(connection); if (retval == ERROR_SERVER_REMOTE_CLOSED) return ERROR_SERVER_REMOTE_CLOSED; } else if ((*buf_p == 0x7f) || (*buf_p == 0x8)) { /* delete character */ if (t_con->line_cursor > 0) { if (t_con->line_cursor != t_con->line_size) { int i; telnet_write(connection, "\b", 1); t_con->line_cursor--; t_con->line_size--; memmove(t_con->line + t_con->line_cursor, t_con->line + t_con->line_cursor + 1, t_con->line_size - t_con->line_cursor); telnet_write(connection, t_con->line + t_con->line_cursor, t_con->line_size - t_con->line_cursor); telnet_write(connection, " \b", 2); for (i = t_con->line_cursor; i < t_con->line_size; i++) telnet_write(connection, "\b", 1); } else { t_con->line_size--; t_con->line_cursor--; /* back space: move the 'printer' head one char * back, overwrite with space, move back again */ telnet_write(connection, "\b \b", 3); } } } else if (*buf_p == 0x15) /* clear line */ telnet_clear_line(connection, t_con); else if (*buf_p == CTRL('B')) { /* cursor left */ if (t_con->line_cursor > 0) { telnet_write(connection, "\b", 1); t_con->line_cursor--; } t_con->state = TELNET_STATE_DATA; } else if (*buf_p == CTRL('F')) { /* cursor right */ if (t_con->line_cursor < t_con->line_size) telnet_write(connection, t_con->line + t_con->line_cursor++, 1); t_con->state = TELNET_STATE_DATA; } else LOG_DEBUG("unhandled nonprintable: %2.2x", *buf_p); } } break; case TELNET_STATE_IAC: switch (*buf_p) { case 0xfe: t_con->state = TELNET_STATE_DONT; break; case 0xfd: t_con->state = TELNET_STATE_DO; break; case 0xfc: t_con->state = TELNET_STATE_WONT; break; case 0xfb: t_con->state = TELNET_STATE_WILL; break; } break; case TELNET_STATE_SB: break; case TELNET_STATE_SE: break; case TELNET_STATE_WILL: case TELNET_STATE_WONT: case TELNET_STATE_DO: case TELNET_STATE_DONT: t_con->state = TELNET_STATE_DATA; break; case TELNET_STATE_ESCAPE: if (t_con->last_escape == '[') { if (*buf_p == 'D') { /* cursor left */ if (t_con->line_cursor > 0) { telnet_write(connection, "\b", 1); t_con->line_cursor--; } t_con->state = TELNET_STATE_DATA; } else if (*buf_p == 'C') { /* cursor right */ if (t_con->line_cursor < t_con->line_size) telnet_write(connection, t_con->line + t_con->line_cursor++, 1); t_con->state = TELNET_STATE_DATA; } else if (*buf_p == 'A') { /* cursor up */ int last_history = (t_con->current_history > 0) ? t_con->current_history - 1 : TELNET_LINE_HISTORY_SIZE-1; if (t_con->history[last_history]) { telnet_clear_line(connection, t_con); t_con->line_size = strlen(t_con->history[last_history]); t_con->line_cursor = t_con->line_size; memcpy(t_con->line, t_con->history[last_history], t_con->line_size); telnet_write(connection, t_con->line, t_con->line_size); t_con->current_history = last_history; } t_con->state = TELNET_STATE_DATA; } else if (*buf_p == 'B') { /* cursor down */ int next_history = (t_con->current_history + 1) % TELNET_LINE_HISTORY_SIZE; if (t_con->history[next_history]) { telnet_clear_line(connection, t_con); t_con->line_size = strlen(t_con->history[next_history]); t_con->line_cursor = t_con->line_size; memcpy(t_con->line, t_con->history[next_history], t_con->line_size); telnet_write(connection, t_con->line, t_con->line_size); t_con->current_history = next_history; } t_con->state = TELNET_STATE_DATA; } else if (*buf_p == '3') t_con->last_escape = *buf_p; else t_con->state = TELNET_STATE_DATA; } else if (t_con->last_escape == '3') { /* Remove character */ if (*buf_p == '~') { if (t_con->line_cursor < t_con->line_size) { int i; t_con->line_size--; /* remove char from line buffer */ memmove(t_con->line + t_con->line_cursor, t_con->line + t_con->line_cursor + 1, t_con->line_size - t_con->line_cursor); /* print remainder of buffer */ telnet_write(connection, t_con->line + t_con->line_cursor, t_con->line_size - t_con->line_cursor); /* overwrite last char with whitespace */ telnet_write(connection, " \b", 2); /* move back to cursor position*/ for (i = t_con->line_cursor; i < t_con->line_size; i++) telnet_write(connection, "\b", 1); } t_con->state = TELNET_STATE_DATA; } else t_con->state = TELNET_STATE_DATA; } else if (t_con->last_escape == '\x00') { if (*buf_p == '[') t_con->last_escape = *buf_p; else t_con->state = TELNET_STATE_DATA; } else { LOG_ERROR("BUG: unexpected value in t_con->last_escape"); t_con->state = TELNET_STATE_DATA; } break; default: LOG_ERROR("unknown telnet state"); exit(-1); } bytes_read--; buf_p++; } return ERROR_OK; } static int telnet_connection_closed(struct connection *connection) { struct telnet_connection *t_con = connection->priv; int i; log_remove_callback(telnet_log_callback, connection); if (t_con->prompt) { free(t_con->prompt); t_con->prompt = NULL; } /* save telnet history */ telnet_save_history(t_con); for (i = 0; i < TELNET_LINE_HISTORY_SIZE; i++) { if (t_con->history[i]) { free(t_con->history[i]); t_con->history[i] = NULL; } } /* if this connection registered a debug-message receiver delete it */ delete_debug_msg_receiver(connection->cmd_ctx, NULL); if (connection->priv) { free(connection->priv); connection->priv = NULL; } else LOG_ERROR("BUG: connection->priv == NULL"); return ERROR_OK; } int telnet_init(char *banner) { if (strcmp(telnet_port, "disabled") == 0) { LOG_INFO("telnet server disabled"); return ERROR_OK; } struct telnet_service *telnet_service = malloc(sizeof(struct telnet_service)); telnet_service->banner = banner; return add_service("telnet", telnet_port, 1, telnet_new_connection, telnet_input, telnet_connection_closed, telnet_service); } /* daemon configuration command telnet_port */ COMMAND_HANDLER(handle_telnet_port_command) { return CALL_COMMAND_HANDLER(server_pipe_command, &telnet_port); } COMMAND_HANDLER(handle_exit_command) { return ERROR_COMMAND_CLOSE_CONNECTION; } static const struct command_registration telnet_command_handlers[] = { { .name = "exit", .handler = handle_exit_command, .mode = COMMAND_EXEC, .usage = "", .help = "exit telnet session", }, { .name = "telnet_port", .handler = handle_telnet_port_command, .mode = COMMAND_ANY, .help = "Specify port on which to listen " "for incoming telnet connections. " "Read help on 'gdb_port'.", .usage = "[port_num]", }, COMMAND_REGISTRATION_DONE }; int telnet_register_commands(struct command_context *cmd_ctx) { telnet_port = strdup("4444"); return register_commands(cmd_ctx, NULL, telnet_command_handlers); } openocd-0.7.0/src/server/server.h0000644000175000001440000001032112134336410013630 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef SERVER_H #define SERVER_H #include #ifdef HAVE_NETINET_IN_H #include #endif enum connection_type { CONNECTION_TCP, CONNECTION_PIPE, CONNECTION_STDINOUT }; struct connection { int fd; int fd_out; /* When using pipes we're writing to a different fd */ struct sockaddr_in sin; struct command_context *cmd_ctx; struct service *service; int input_pending; void *priv; struct connection *next; }; typedef int (*new_connection_handler_t)(struct connection *connection); typedef int (*input_handler_t)(struct connection *connection); typedef int (*connection_closed_handler_t)(struct connection *connection); struct service { const char *name; enum connection_type type; const char *port; unsigned short portnumber; int fd; struct sockaddr_in sin; int max_connections; struct connection *connections; new_connection_handler_t new_connection; input_handler_t input; connection_closed_handler_t connection_closed; void *priv; struct service *next; }; int add_service(char *name, const char *port, int max_connections, new_connection_handler_t new_connection_handler, input_handler_t in_handler, connection_closed_handler_t close_handler, void *priv); int server_preinit(void); int server_init(struct command_context *cmd_ctx); int server_quit(void); int server_loop(struct command_context *command_context); int server_register_commands(struct command_context *context); int connection_write(struct connection *connection, const void *data, int len); int connection_read(struct connection *connection, void *data, int len); /** * Used by server_loop(), defined in server_stubs.c */ void openocd_sleep_prelude(void); /** * Used by server_loop(), defined in server_stubs.c */ void openocd_sleep_postlude(void); /** * Defines an extended command handler function declaration to enable * access to (and manipulation of) the server port number. * Call server_port like a normal COMMAND_HANDLER with an extra @a out parameter * to receive the specified port number. */ #define SERVER_PIPE_COMMAND() \ COMMAND_HELPER(server_pipe_command, const char **out) SERVER_PIPE_COMMAND(); #define SERVER_PORT_COMMAND() \ COMMAND_HELPER(server_port_command, unsigned short *out) SERVER_PORT_COMMAND(); #define ERROR_SERVER_REMOTE_CLOSED (-400) #define ERROR_CONNECTION_REJECTED (-401) #endif /* SERVER_H */ openocd-0.7.0/src/server/gdb_server.h0000644000175000001440000000531312134336410014451 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2009 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef GDB_SERVER_H #define GDB_SERVER_H struct image; struct reg; #include #define GDB_BUFFER_SIZE 16384 int gdb_target_add_all(struct target *target); int gdb_register_commands(struct command_context *command_context); int gdb_put_packet(struct connection *connection, char *buffer, int len); static inline struct target *get_target_from_connection(struct connection *connection) { struct gdb_service *gdb_service = connection->service->priv; return gdb_service->target; } #define ERROR_GDB_BUFFER_TOO_SMALL (-800) #define ERROR_GDB_TIMEOUT (-801) #endif /* GDB_SERVER_H */ openocd-0.7.0/src/server/Makefile.in0000644000175000001440000005552512141414276014242 00000000000000# Makefile.in generated by automake 1.13.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ DIST_COMMON = $(top_srcdir)/common.mk $(srcdir)/Makefile.in \ $(srcdir)/Makefile.am $(top_srcdir)/depcomp $(noinst_HEADERS) @INTERNAL_JIMTCL_TRUE@am__append_1 = -I$(top_srcdir)/jimtcl \ @INTERNAL_JIMTCL_TRUE@ -I$(top_builddir)/jimtcl # FD_* macros are sloppy with their signs on MinGW32 platform @IS_MINGW_TRUE@am__append_2 = -Wno-sign-compare subdir = src/server ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/config_subdir.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libserver_la_LIBADD = am_libserver_la_OBJECTS = libserver_la-server.lo \ libserver_la-telnet_server.lo libserver_la-gdb_server.lo \ libserver_la-server_stubs.lo libserver_la-tcl_server.lo libserver_la_OBJECTS = $(am_libserver_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libserver_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libserver_la_CFLAGS) \ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libserver_la_SOURCES) DIST_SOURCES = $(libserver_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CC_FOR_BUILD = @CC_FOR_BUILD@ CFLAGS = @CFLAGS@ CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@ FGREP = @FGREP@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ doxygen_as_html = @doxygen_as_html@ doxygen_as_pdf = @doxygen_as_pdf@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ # common flags used in openocd build AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src \ -I$(top_srcdir)/src/helper -DPKGDATADIR=\"$(pkgdatadir)\" \ -DPKGLIBDIR=\"$(pkglibdir)\" $(am__append_1) METASOURCES = AUTO noinst_LTLIBRARIES = libserver.la # tcl server addons noinst_HEADERS = server.h telnet_server.h gdb_server.h tcl_server.h libserver_la_SOURCES = server.c telnet_server.c gdb_server.c \ server_stubs.c tcl_server.c libserver_la_CFLAGS = $(am__append_2) EXTRA_DIST = \ startup.tcl MAINTAINERCLEANFILES = $(srcdir)/Makefile.in all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/common.mk $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/server/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/server/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_srcdir)/common.mk: $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libserver.la: $(libserver_la_OBJECTS) $(libserver_la_DEPENDENCIES) $(EXTRA_libserver_la_DEPENDENCIES) $(AM_V_CCLD)$(libserver_la_LINK) $(libserver_la_OBJECTS) $(libserver_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libserver_la-gdb_server.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libserver_la-server.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libserver_la-server_stubs.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libserver_la-tcl_server.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libserver_la-telnet_server.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< libserver_la-server.lo: server.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libserver_la_CFLAGS) $(CFLAGS) -MT libserver_la-server.lo -MD -MP -MF $(DEPDIR)/libserver_la-server.Tpo -c -o libserver_la-server.lo `test -f 'server.c' || echo '$(srcdir)/'`server.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libserver_la-server.Tpo $(DEPDIR)/libserver_la-server.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='server.c' object='libserver_la-server.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libserver_la_CFLAGS) $(CFLAGS) -c -o libserver_la-server.lo `test -f 'server.c' || echo '$(srcdir)/'`server.c libserver_la-telnet_server.lo: telnet_server.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libserver_la_CFLAGS) $(CFLAGS) -MT libserver_la-telnet_server.lo -MD -MP -MF $(DEPDIR)/libserver_la-telnet_server.Tpo -c -o libserver_la-telnet_server.lo `test -f 'telnet_server.c' || echo '$(srcdir)/'`telnet_server.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libserver_la-telnet_server.Tpo $(DEPDIR)/libserver_la-telnet_server.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='telnet_server.c' object='libserver_la-telnet_server.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libserver_la_CFLAGS) $(CFLAGS) -c -o libserver_la-telnet_server.lo `test -f 'telnet_server.c' || echo '$(srcdir)/'`telnet_server.c libserver_la-gdb_server.lo: gdb_server.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libserver_la_CFLAGS) $(CFLAGS) -MT libserver_la-gdb_server.lo -MD -MP -MF $(DEPDIR)/libserver_la-gdb_server.Tpo -c -o libserver_la-gdb_server.lo `test -f 'gdb_server.c' || echo '$(srcdir)/'`gdb_server.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libserver_la-gdb_server.Tpo $(DEPDIR)/libserver_la-gdb_server.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gdb_server.c' object='libserver_la-gdb_server.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libserver_la_CFLAGS) $(CFLAGS) -c -o libserver_la-gdb_server.lo `test -f 'gdb_server.c' || echo '$(srcdir)/'`gdb_server.c libserver_la-server_stubs.lo: server_stubs.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libserver_la_CFLAGS) $(CFLAGS) -MT libserver_la-server_stubs.lo -MD -MP -MF $(DEPDIR)/libserver_la-server_stubs.Tpo -c -o libserver_la-server_stubs.lo `test -f 'server_stubs.c' || echo '$(srcdir)/'`server_stubs.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libserver_la-server_stubs.Tpo $(DEPDIR)/libserver_la-server_stubs.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='server_stubs.c' object='libserver_la-server_stubs.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libserver_la_CFLAGS) $(CFLAGS) -c -o libserver_la-server_stubs.lo `test -f 'server_stubs.c' || echo '$(srcdir)/'`server_stubs.c libserver_la-tcl_server.lo: tcl_server.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libserver_la_CFLAGS) $(CFLAGS) -MT libserver_la-tcl_server.lo -MD -MP -MF $(DEPDIR)/libserver_la-tcl_server.Tpo -c -o libserver_la-tcl_server.lo `test -f 'tcl_server.c' || echo '$(srcdir)/'`tcl_server.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libserver_la-tcl_server.Tpo $(DEPDIR)/libserver_la-tcl_server.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tcl_server.c' object='libserver_la-tcl_server.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libserver_la_CFLAGS) $(CFLAGS) -c -o libserver_la-tcl_server.lo `test -f 'tcl_server.c' || echo '$(srcdir)/'`tcl_server.c mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: openocd-0.7.0/src/server/tcl_server.c0000644000175000001440000001320112134336410014465 00000000000000/*************************************************************************** * Copyright (C) 2010 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "tcl_server.h" #define TCL_SERVER_VERSION "TCL Server 0.1" #define TCL_MAX_LINE (4096) struct tcl_connection { int tc_linedrop; int tc_lineoffset; char tc_line[TCL_MAX_LINE]; int tc_outerror;/* flag an output error */ }; static const char *tcl_port; /* handlers */ static int tcl_new_connection(struct connection *connection); static int tcl_input(struct connection *connection); static int tcl_output(struct connection *connection, const void *buf, ssize_t len); static int tcl_closed(struct connection *connection); /* write data out to a socket. * * this is a blocking write, so the return value must equal the length, if * that is not the case then flag the connection with an output error. */ int tcl_output(struct connection *connection, const void *data, ssize_t len) { ssize_t wlen; struct tcl_connection *tclc; tclc = connection->priv; if (tclc->tc_outerror) return ERROR_SERVER_REMOTE_CLOSED; wlen = connection_write(connection, data, len); if (wlen == len) return ERROR_OK; LOG_ERROR("error during write: %d != %d", (int)wlen, (int)len); tclc->tc_outerror = 1; return ERROR_SERVER_REMOTE_CLOSED; } /* connections */ static int tcl_new_connection(struct connection *connection) { struct tcl_connection *tclc; tclc = malloc(sizeof(struct tcl_connection)); if (tclc == NULL) return ERROR_CONNECTION_REJECTED; memset(tclc, 0, sizeof(struct tcl_connection)); connection->priv = tclc; return ERROR_OK; } static int tcl_input(struct connection *connection) { Jim_Interp *interp = (Jim_Interp *)connection->cmd_ctx->interp; int retval; int i; ssize_t rlen; const char *result; int reslen; struct tcl_connection *tclc; unsigned char in[256]; rlen = connection_read(connection, &in, sizeof(in)); if (rlen <= 0) { if (rlen < 0) LOG_ERROR("error during read: %s", strerror(errno)); return ERROR_SERVER_REMOTE_CLOSED; } tclc = connection->priv; if (tclc == NULL) return ERROR_CONNECTION_REJECTED; /* push as much data into the line as possible */ for (i = 0; i < rlen; i++) { /* buffer the data */ tclc->tc_line[tclc->tc_lineoffset] = in[i]; if (tclc->tc_lineoffset < TCL_MAX_LINE) tclc->tc_lineoffset++; else tclc->tc_linedrop = 1; /* ctrl-z is end of command. When testing from telnet, just * press ctrl-z a couple of times first to put telnet into the * mode where it will send 0x1a in response to pressing ctrl-z */ if (in[i] != '\x1a') continue; /* process the line */ if (tclc->tc_linedrop) { #define ESTR "line too long\n" retval = tcl_output(connection, ESTR, sizeof(ESTR)); if (retval != ERROR_OK) return retval; #undef ESTR } else { tclc->tc_line[tclc->tc_lineoffset-1] = '\0'; LOG_DEBUG("Executing script:\n %s", tclc->tc_line); retval = Jim_Eval_Named(interp, tclc->tc_line, "remote:connection", 1); result = Jim_GetString(Jim_GetResult(interp), &reslen); LOG_DEBUG("Result: %d\n %s", retval, result); retval = tcl_output(connection, result, reslen); if (retval != ERROR_OK) return retval; /* Always output ctrl-d as end of line to allow multiline results */ tcl_output(connection, "\x1a", 1); } tclc->tc_lineoffset = 0; tclc->tc_linedrop = 0; } return ERROR_OK; } static int tcl_closed(struct connection *connection) { /* cleanup connection context */ if (connection->priv) { free(connection->priv); connection->priv = NULL; } return ERROR_OK; } int tcl_init(void) { if (strcmp(tcl_port, "disabled") == 0) { LOG_INFO("tcl server disabled"); return ERROR_OK; } return add_service("tcl", tcl_port, 1, &tcl_new_connection, &tcl_input, &tcl_closed, NULL); } COMMAND_HANDLER(handle_tcl_port_command) { return CALL_COMMAND_HANDLER(server_pipe_command, &tcl_port); } static const struct command_registration tcl_command_handlers[] = { { .name = "tcl_port", .handler = handle_tcl_port_command, .mode = COMMAND_CONFIG, .help = "Specify port on which to listen " "for incoming Tcl syntax. " "Read help on 'gdb_port'.", .usage = "[port_num]", }, COMMAND_REGISTRATION_DONE }; int tcl_register_commands(struct command_context *cmd_ctx) { tcl_port = strdup("6666"); return register_commands(cmd_ctx, NULL, tcl_command_handlers); } openocd-0.7.0/src/server/server.c0000644000175000001440000004014612134336410013633 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "server.h" #include #include #include "openocd.h" #include "tcl_server.h" #include "telnet_server.h" #include #ifndef _WIN32 #include #endif static struct service *services; /* shutdown_openocd == 1: exit the main event loop, and quit the debugger */ static int shutdown_openocd; static int add_connection(struct service *service, struct command_context *cmd_ctx) { socklen_t address_size; struct connection *c, **p; int retval; int flag = 1; c = malloc(sizeof(struct connection)); c->fd = -1; c->fd_out = -1; memset(&c->sin, 0, sizeof(c->sin)); c->cmd_ctx = copy_command_context(cmd_ctx); c->service = service; c->input_pending = 0; c->priv = NULL; c->next = NULL; if (service->type == CONNECTION_TCP) { address_size = sizeof(c->sin); c->fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size); c->fd_out = c->fd; /* This increases performance dramatically for e.g. GDB load which * does not have a sliding window protocol. * * Ignore errors from this fn as it probably just means less performance */ setsockopt(c->fd, /* socket affected */ IPPROTO_TCP, /* set option at TCP level */ TCP_NODELAY, /* name of option */ (char *)&flag, /* the cast is historical cruft */ sizeof(int)); /* length of option value */ LOG_INFO("accepting '%s' connection from %s", service->name, service->port); retval = service->new_connection(c); if (retval != ERROR_OK) { close_socket(c->fd); LOG_ERROR("attempted '%s' connection rejected", service->name); command_done(c->cmd_ctx); free(c); return retval; } } else if (service->type == CONNECTION_STDINOUT) { c->fd = service->fd; c->fd_out = fileno(stdout); #ifdef _WIN32 /* we are using stdin/out so ignore ctrl-c under windoze */ SetConsoleCtrlHandler(NULL, TRUE); #endif /* do not check for new connections again on stdin */ service->fd = -1; LOG_INFO("accepting '%s' connection from pipe", service->name); retval = service->new_connection(c); if (retval != ERROR_OK) { LOG_ERROR("attempted '%s' connection rejected", service->name); command_done(c->cmd_ctx); free(c); return retval; } } else if (service->type == CONNECTION_PIPE) { c->fd = service->fd; /* do not check for new connections again on stdin */ service->fd = -1; char *out_file = alloc_printf("%so", service->port); c->fd_out = open(out_file, O_WRONLY); free(out_file); if (c->fd_out == -1) { LOG_ERROR("could not open %s", service->port); exit(1); } LOG_INFO("accepting '%s' connection from pipe %s", service->name, service->port); retval = service->new_connection(c); if (retval != ERROR_OK) { LOG_ERROR("attempted '%s' connection rejected", service->name); command_done(c->cmd_ctx); free(c); return retval; } } /* add to the end of linked list */ for (p = &service->connections; *p; p = &(*p)->next) ; *p = c; service->max_connections--; return ERROR_OK; } static int remove_connection(struct service *service, struct connection *connection) { struct connection **p = &service->connections; struct connection *c; /* find connection */ while ((c = *p)) { if (c->fd == connection->fd) { service->connection_closed(c); if (service->type == CONNECTION_TCP) close_socket(c->fd); else if (service->type == CONNECTION_PIPE) { /* The service will listen to the pipe again */ c->service->fd = c->fd; } command_done(c->cmd_ctx); /* delete connection */ *p = c->next; free(c); service->max_connections++; break; } /* redirect p to next list pointer */ p = &(*p)->next; } return ERROR_OK; } /* FIX! make service return error instead of invoking exit() */ int add_service(char *name, const char *port, int max_connections, new_connection_handler_t new_connection_handler, input_handler_t input_handler, connection_closed_handler_t connection_closed_handler, void *priv) { struct service *c, **p; int so_reuseaddr_option = 1; c = malloc(sizeof(struct service)); c->name = strdup(name); c->port = strdup(port); c->max_connections = 1; /* Only TCP/IP ports can support more than one connection */ c->fd = -1; c->connections = NULL; c->new_connection = new_connection_handler; c->input = input_handler; c->connection_closed = connection_closed_handler; c->priv = priv; c->next = NULL; long portnumber; if (strcmp(c->port, "pipe") == 0) c->type = CONNECTION_STDINOUT; else { char *end; portnumber = strtol(c->port, &end, 0); if (!*end && (parse_long(c->port, &portnumber) == ERROR_OK)) { c->portnumber = portnumber; c->type = CONNECTION_TCP; } else c->type = CONNECTION_PIPE; } if (c->type == CONNECTION_TCP) { c->max_connections = max_connections; c->fd = socket(AF_INET, SOCK_STREAM, 0); if (c->fd == -1) { LOG_ERROR("error creating socket: %s", strerror(errno)); exit(-1); } setsockopt(c->fd, SOL_SOCKET, SO_REUSEADDR, (void *)&so_reuseaddr_option, sizeof(int)); socket_nonblock(c->fd); memset(&c->sin, 0, sizeof(c->sin)); c->sin.sin_family = AF_INET; c->sin.sin_addr.s_addr = INADDR_ANY; c->sin.sin_port = htons(c->portnumber); if (bind(c->fd, (struct sockaddr *)&c->sin, sizeof(c->sin)) == -1) { LOG_ERROR("couldn't bind to socket: %s", strerror(errno)); exit(-1); } #ifndef _WIN32 int segsize = 65536; setsockopt(c->fd, IPPROTO_TCP, TCP_MAXSEG, &segsize, sizeof(int)); #endif int window_size = 128 * 1024; /* These setsockopt()s must happen before the listen() */ setsockopt(c->fd, SOL_SOCKET, SO_SNDBUF, (char *)&window_size, sizeof(window_size)); setsockopt(c->fd, SOL_SOCKET, SO_RCVBUF, (char *)&window_size, sizeof(window_size)); if (listen(c->fd, 1) == -1) { LOG_ERROR("couldn't listen on socket: %s", strerror(errno)); exit(-1); } } else if (c->type == CONNECTION_STDINOUT) { c->fd = fileno(stdin); #ifdef _WIN32 /* for win32 set stdin/stdout to binary mode */ if (_setmode(_fileno(stdout), _O_BINARY) < 0) LOG_WARNING("cannot change stdout mode to binary"); if (_setmode(_fileno(stdin), _O_BINARY) < 0) LOG_WARNING("cannot change stdin mode to binary"); if (_setmode(_fileno(stderr), _O_BINARY) < 0) LOG_WARNING("cannot change stderr mode to binary"); #else socket_nonblock(c->fd); #endif } else if (c->type == CONNECTION_PIPE) { #ifdef _WIN32 /* we currenty do not support named pipes under win32 * so exit openocd for now */ LOG_ERROR("Named pipes currently not supported under this os"); exit(1); #else /* Pipe we're reading from */ c->fd = open(c->port, O_RDONLY | O_NONBLOCK); if (c->fd == -1) { LOG_ERROR("could not open %s", c->port); exit(1); } #endif } /* add to the end of linked list */ for (p = &services; *p; p = &(*p)->next) ; *p = c; return ERROR_OK; } static int remove_services(void) { struct service *c = services; /* loop service */ while (c) { struct service *next = c->next; if (c->name) free((void *)c->name); if (c->type == CONNECTION_PIPE) { if (c->fd != -1) close(c->fd); } if (c->port) free((void *)c->port); if (c->priv) free(c->priv); /* delete service */ free(c); /* remember the last service for unlinking */ c = next; } services = NULL; return ERROR_OK; } int server_loop(struct command_context *command_context) { struct service *service; bool poll_ok = true; /* used in select() */ fd_set read_fds; int fd_max; /* used in accept() */ int retval; #ifndef _WIN32 if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) LOG_ERROR("couldn't set SIGPIPE to SIG_IGN"); #endif while (!shutdown_openocd) { /* monitor sockets for activity */ fd_max = 0; FD_ZERO(&read_fds); /* add service and connection fds to read_fds */ for (service = services; service; service = service->next) { if (service->fd != -1) { /* listen for new connections */ FD_SET(service->fd, &read_fds); if (service->fd > fd_max) fd_max = service->fd; } if (service->connections) { struct connection *c; for (c = service->connections; c; c = c->next) { /* check for activity on the connection */ FD_SET(c->fd, &read_fds); if (c->fd > fd_max) fd_max = c->fd; } } } struct timeval tv; tv.tv_sec = 0; if (poll_ok) { /* we're just polling this iteration, this is faster on embedded * hosts */ tv.tv_usec = 0; retval = socket_select(fd_max + 1, &read_fds, NULL, NULL, &tv); } else { /* Every 100ms */ tv.tv_usec = 100000; /* Only while we're sleeping we'll let others run */ openocd_sleep_prelude(); kept_alive(); retval = socket_select(fd_max + 1, &read_fds, NULL, NULL, &tv); openocd_sleep_postlude(); } if (retval == -1) { #ifdef _WIN32 errno = WSAGetLastError(); if (errno == WSAEINTR) FD_ZERO(&read_fds); else { LOG_ERROR("error during select: %s", strerror(errno)); exit(-1); } #else if (errno == EINTR) FD_ZERO(&read_fds); else { LOG_ERROR("error during select: %s", strerror(errno)); exit(-1); } #endif } if (retval == 0) { /* We only execute these callbacks when there was nothing to do or we timed *out */ target_call_timer_callbacks(); process_jim_events(command_context); FD_ZERO(&read_fds); /* eCos leaves read_fds unchanged in this case! */ /* We timed out/there was nothing to do, timeout rather than poll next time **/ poll_ok = false; } else { /* There was something to do, next time we'll just poll */ poll_ok = true; } /* This is a simple back-off algorithm where we immediately * re-poll if we did something this time around. * * This greatly improves performance of DCC. */ poll_ok = poll_ok || target_got_message(); for (service = services; service; service = service->next) { /* handle new connections on listeners */ if ((service->fd != -1) && (FD_ISSET(service->fd, &read_fds))) { if (service->max_connections > 0) add_connection(service, command_context); else { if (service->type == CONNECTION_TCP) { struct sockaddr_in sin; socklen_t address_size = sizeof(sin); int tmp_fd; tmp_fd = accept(service->fd, (struct sockaddr *)&service->sin, &address_size); close_socket(tmp_fd); } LOG_INFO( "rejected '%s' connection, no more connections allowed", service->name); } } /* handle activity on connections */ if (service->connections) { struct connection *c; for (c = service->connections; c; ) { if ((FD_ISSET(c->fd, &read_fds)) || c->input_pending) { retval = service->input(c); if (retval != ERROR_OK) { struct connection *next = c->next; if (service->type == CONNECTION_PIPE || service->type == CONNECTION_STDINOUT) { /* if connection uses a pipe then * shutdown openocd on error */ shutdown_openocd = 1; } remove_connection(service, c); LOG_INFO("dropped '%s' connection", service->name); c = next; continue; } } c = c->next; } } } #ifdef _WIN32 MSG msg; while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) shutdown_openocd = 1; } #endif } return ERROR_OK; } #ifdef _WIN32 BOOL WINAPI ControlHandler(DWORD dwCtrlType) { shutdown_openocd = 1; return TRUE; } void sig_handler(int sig) { shutdown_openocd = 1; } #endif int server_preinit(void) { /* this currently only calls WSAStartup on native win32 systems * before any socket operations are performed. * This is an issue if you call init in your config script */ #ifdef _WIN32 WORD wVersionRequested; WSADATA wsaData; wVersionRequested = MAKEWORD(2, 2); if (WSAStartup(wVersionRequested, &wsaData) != 0) { LOG_ERROR("Failed to Open Winsock"); exit(-1); } /* register ctrl-c handler */ SetConsoleCtrlHandler(ControlHandler, TRUE); signal(SIGINT, sig_handler); signal(SIGTERM, sig_handler); signal(SIGBREAK, sig_handler); signal(SIGABRT, sig_handler); #endif return ERROR_OK; } int server_init(struct command_context *cmd_ctx) { int ret = tcl_init(); if (ERROR_OK != ret) return ret; return telnet_init("Open On-Chip Debugger"); } int server_quit(void) { remove_services(); #ifdef _WIN32 WSACleanup(); SetConsoleCtrlHandler(ControlHandler, FALSE); #endif return ERROR_OK; } int connection_write(struct connection *connection, const void *data, int len) { if (len == 0) { /* successful no-op. Sockets and pipes behave differently here... */ return 0; } if (connection->service->type == CONNECTION_TCP) return write_socket(connection->fd_out, data, len); else return write(connection->fd_out, data, len); } int connection_read(struct connection *connection, void *data, int len) { if (connection->service->type == CONNECTION_TCP) return read_socket(connection->fd, data, len); else return read(connection->fd, data, len); } /* tell the server we want to shut down */ COMMAND_HANDLER(handle_shutdown_command) { LOG_USER("shutdown command invoked"); shutdown_openocd = 1; return ERROR_OK; } static const struct command_registration server_command_handlers[] = { { .name = "shutdown", .handler = &handle_shutdown_command, .mode = COMMAND_ANY, .usage = "", .help = "shut the server down", }, COMMAND_REGISTRATION_DONE }; int server_register_commands(struct command_context *cmd_ctx) { int retval = telnet_register_commands(cmd_ctx); if (ERROR_OK != retval) return retval; retval = tcl_register_commands(cmd_ctx); if (ERROR_OK != retval) return retval; return register_commands(cmd_ctx, NULL, server_command_handlers); } SERVER_PORT_COMMAND() { switch (CMD_ARGC) { case 0: command_print(CMD_CTX, "%d", *out); break; case 1: { uint16_t port; COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], port); *out = port; break; } default: return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; } SERVER_PIPE_COMMAND() { switch (CMD_ARGC) { case 0: command_print(CMD_CTX, "%s", *out); break; case 1: { if (CMD_CTX->mode == COMMAND_EXEC) { LOG_WARNING("unable to change server port after init"); return ERROR_COMMAND_ARGUMENT_INVALID; } const char *t = strdup(CMD_ARGV[0]); free((void *)*out); *out = t; break; } default: return ERROR_COMMAND_SYNTAX_ERROR; } return ERROR_OK; } openocd-0.7.0/src/server/gdb_server.c0000644000175000001440000020334312137151331014447 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007-2010 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * Copyright (C) 2011 by Broadcom Corporation * * Evan Hunter - ehunter@broadcom.com * * * * Copyright (C) ST-Ericsson SA 2011 * * michel.jaouen@stericsson.com : smp minimum support * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include "server.h" #include #include "gdb_server.h" #include #include #include "rtos/rtos.h" #include "target/smp.h" /** * @file * GDB server implementation. * * This implements the GDB Remote Serial Protocol, over TCP connections, * giving GDB access to the JTAG or other hardware debugging facilities * found in most modern embedded processors. */ /* private connection data for GDB */ struct gdb_connection { char buffer[GDB_BUFFER_SIZE]; char *buf_p; int buf_cnt; int ctrl_c; enum target_state frontend_state; struct image *vflash_image; int closed; int busy; int noack_mode; /* set flag to true if you want the next stepi to return immediately. * allowing GDB to pick up a fresh set of register values from the target * without modifying the target state. */ bool sync; /* We delay reporting memory write errors until next step/continue or memory * write. This improves performance of gdb load significantly as the GDB packet * can be replied immediately and a new GDB packet will be ready without delay * (ca. 10% or so...). */ bool mem_write_error; /* with extended-remote it seems we need to better emulate attach/detach. * what this means is we reply with a W stop reply after a kill packet, * normally we reply with a S reply via gdb_last_signal_packet. * as a side note this behaviour only effects gdb > 6.8 */ bool attached; }; #if 0 #define _DEBUG_GDB_IO_ #endif static struct gdb_connection *current_gdb_connection; static int gdb_breakpoint_override; static enum breakpoint_type gdb_breakpoint_override_type; static int gdb_error(struct connection *connection, int retval); static const char *gdb_port; static const char *gdb_port_next; static void gdb_log_callback(void *priv, const char *file, unsigned line, const char *function, const char *string); /* number of gdb connections, mainly to suppress gdb related debugging spam * in helper/log.c when no gdb connections are actually active */ int gdb_actual_connections; /* set if we are sending a memory map to gdb * via qXfer:memory-map:read packet */ /* enabled by default*/ static int gdb_use_memory_map = 1; /* enabled by default*/ static int gdb_flash_program = 1; /* if set, data aborts cause an error to be reported in memory read packets * see the code in gdb_read_memory_packet() for further explanations. * Disabled by default. */ static int gdb_report_data_abort; static int gdb_last_signal(struct target *target) { switch (target->debug_reason) { case DBG_REASON_DBGRQ: return 0x2; /* SIGINT */ case DBG_REASON_BREAKPOINT: case DBG_REASON_WATCHPOINT: case DBG_REASON_WPTANDBKPT: return 0x05; /* SIGTRAP */ case DBG_REASON_SINGLESTEP: return 0x05; /* SIGTRAP */ case DBG_REASON_NOTHALTED: return 0x0; /* no signal... shouldn't happen */ default: LOG_USER("undefined debug reason %d - target needs reset", target->debug_reason); return 0x0; } } static int check_pending(struct connection *connection, int timeout_s, int *got_data) { /* a non-blocking socket will block if there is 0 bytes available on the socket, * but return with as many bytes as are available immediately */ struct timeval tv; fd_set read_fds; struct gdb_connection *gdb_con = connection->priv; int t; if (got_data == NULL) got_data = &t; *got_data = 0; if (gdb_con->buf_cnt > 0) { *got_data = 1; return ERROR_OK; } FD_ZERO(&read_fds); FD_SET(connection->fd, &read_fds); tv.tv_sec = timeout_s; tv.tv_usec = 0; if (socket_select(connection->fd + 1, &read_fds, NULL, NULL, &tv) == 0) { /* This can typically be because a "monitor" command took too long * before printing any progress messages */ if (timeout_s > 0) return ERROR_GDB_TIMEOUT; else return ERROR_OK; } *got_data = FD_ISSET(connection->fd, &read_fds) != 0; return ERROR_OK; } static int gdb_get_char_inner(struct connection *connection, int *next_char) { struct gdb_connection *gdb_con = connection->priv; int retval = ERROR_OK; #ifdef _DEBUG_GDB_IO_ char *debug_buffer; #endif for (;; ) { if (connection->service->type != CONNECTION_TCP) gdb_con->buf_cnt = read(connection->fd, gdb_con->buffer, GDB_BUFFER_SIZE); else { retval = check_pending(connection, 1, NULL); if (retval != ERROR_OK) return retval; gdb_con->buf_cnt = read_socket(connection->fd, gdb_con->buffer, GDB_BUFFER_SIZE); } if (gdb_con->buf_cnt > 0) break; if (gdb_con->buf_cnt == 0) { gdb_con->closed = 1; return ERROR_SERVER_REMOTE_CLOSED; } #ifdef _WIN32 errno = WSAGetLastError(); switch (errno) { case WSAEWOULDBLOCK: usleep(1000); break; case WSAECONNABORTED: gdb_con->closed = 1; return ERROR_SERVER_REMOTE_CLOSED; case WSAECONNRESET: gdb_con->closed = 1; return ERROR_SERVER_REMOTE_CLOSED; default: LOG_ERROR("read: %d", errno); exit(-1); } #else switch (errno) { case EAGAIN: usleep(1000); break; case ECONNABORTED: gdb_con->closed = 1; return ERROR_SERVER_REMOTE_CLOSED; case ECONNRESET: gdb_con->closed = 1; return ERROR_SERVER_REMOTE_CLOSED; default: LOG_ERROR("read: %s", strerror(errno)); gdb_con->closed = 1; return ERROR_SERVER_REMOTE_CLOSED; } #endif } #ifdef _DEBUG_GDB_IO_ debug_buffer = strndup(gdb_con->buffer, gdb_con->buf_cnt); LOG_DEBUG("received '%s'", debug_buffer); free(debug_buffer); #endif gdb_con->buf_p = gdb_con->buffer; gdb_con->buf_cnt--; *next_char = *(gdb_con->buf_p++); if (gdb_con->buf_cnt > 0) connection->input_pending = 1; else connection->input_pending = 0; #ifdef _DEBUG_GDB_IO_ LOG_DEBUG("returned char '%c' (0x%2.2x)", *next_char, *next_char); #endif return retval; } /** * The cool thing about this fn is that it allows buf_p and buf_cnt to be * held in registers in the inner loop. * * For small caches and embedded systems this is important! */ static inline int gdb_get_char_fast(struct connection *connection, int *next_char, char **buf_p, int *buf_cnt) { int retval = ERROR_OK; if ((*buf_cnt)-- > 0) { *next_char = **buf_p; (*buf_p)++; if (*buf_cnt > 0) connection->input_pending = 1; else connection->input_pending = 0; #ifdef _DEBUG_GDB_IO_ LOG_DEBUG("returned char '%c' (0x%2.2x)", *next_char, *next_char); #endif return ERROR_OK; } struct gdb_connection *gdb_con = connection->priv; gdb_con->buf_p = *buf_p; gdb_con->buf_cnt = *buf_cnt; retval = gdb_get_char_inner(connection, next_char); *buf_p = gdb_con->buf_p; *buf_cnt = gdb_con->buf_cnt; return retval; } static int gdb_get_char(struct connection *connection, int *next_char) { struct gdb_connection *gdb_con = connection->priv; return gdb_get_char_fast(connection, next_char, &gdb_con->buf_p, &gdb_con->buf_cnt); } static int gdb_putback_char(struct connection *connection, int last_char) { struct gdb_connection *gdb_con = connection->priv; if (gdb_con->buf_p > gdb_con->buffer) { *(--gdb_con->buf_p) = last_char; gdb_con->buf_cnt++; } else LOG_ERROR("BUG: couldn't put character back"); return ERROR_OK; } /* The only way we can detect that the socket is closed is the first time * we write to it, we will fail. Subsequent write operations will * succeed. Shudder! */ static int gdb_write(struct connection *connection, void *data, int len) { struct gdb_connection *gdb_con = connection->priv; if (gdb_con->closed) return ERROR_SERVER_REMOTE_CLOSED; if (connection_write(connection, data, len) == len) return ERROR_OK; gdb_con->closed = 1; return ERROR_SERVER_REMOTE_CLOSED; } static int gdb_put_packet_inner(struct connection *connection, char *buffer, int len) { int i; unsigned char my_checksum = 0; #ifdef _DEBUG_GDB_IO_ char *debug_buffer; #endif int reply; int retval; struct gdb_connection *gdb_con = connection->priv; for (i = 0; i < len; i++) my_checksum += buffer[i]; #ifdef _DEBUG_GDB_IO_ /* * At this point we should have nothing in the input queue from GDB, * however sometimes '-' is sent even though we've already received * an ACK (+) for everything we've sent off. */ int gotdata; for (;; ) { retval = check_pending(connection, 0, &gotdata); if (retval != ERROR_OK) return retval; if (!gotdata) break; retval = gdb_get_char(connection, &reply); if (retval != ERROR_OK) return retval; if (reply == '$') { /* fix a problem with some IAR tools */ gdb_putback_char(connection, reply); LOG_DEBUG("Unexpected start of new packet"); break; } LOG_WARNING("Discard unexpected char %c", reply); } #endif while (1) { #ifdef _DEBUG_GDB_IO_ debug_buffer = strndup(buffer, len); LOG_DEBUG("sending packet '$%s#%2.2x'", debug_buffer, my_checksum); free(debug_buffer); #endif char local_buffer[1024]; local_buffer[0] = '$'; if ((size_t)len + 4 <= sizeof(local_buffer)) { /* performance gain on smaller packets by only a single call to gdb_write() */ memcpy(local_buffer + 1, buffer, len++); len += snprintf(local_buffer + len, sizeof(local_buffer) - len, "#%02x", my_checksum); retval = gdb_write(connection, local_buffer, len); if (retval != ERROR_OK) return retval; } else { /* larger packets are transmitted directly from caller supplied buffer * by several calls to gdb_write() to avoid dynamic allocation */ snprintf(local_buffer + 1, sizeof(local_buffer) - 1, "#%02x", my_checksum); retval = gdb_write(connection, local_buffer, 1); if (retval != ERROR_OK) return retval; retval = gdb_write(connection, buffer, len); if (retval != ERROR_OK) return retval; retval = gdb_write(connection, local_buffer + 1, 3); if (retval != ERROR_OK) return retval; } if (gdb_con->noack_mode) break; retval = gdb_get_char(connection, &reply); if (retval != ERROR_OK) return retval; if (reply == '+') break; else if (reply == '-') { /* Stop sending output packets for now */ log_remove_callback(gdb_log_callback, connection); LOG_WARNING("negative reply, retrying"); } else if (reply == 0x3) { gdb_con->ctrl_c = 1; retval = gdb_get_char(connection, &reply); if (retval != ERROR_OK) return retval; if (reply == '+') break; else if (reply == '-') { /* Stop sending output packets for now */ log_remove_callback(gdb_log_callback, connection); LOG_WARNING("negative reply, retrying"); } else if (reply == '$') { LOG_ERROR("GDB missing ack(1) - assumed good"); gdb_putback_char(connection, reply); return ERROR_OK; } else { LOG_ERROR("unknown character(1) 0x%2.2x in reply, dropping connection", reply); gdb_con->closed = 1; return ERROR_SERVER_REMOTE_CLOSED; } } else if (reply == '$') { LOG_ERROR("GDB missing ack(2) - assumed good"); gdb_putback_char(connection, reply); return ERROR_OK; } else { LOG_ERROR("unknown character(2) 0x%2.2x in reply, dropping connection", reply); gdb_con->closed = 1; return ERROR_SERVER_REMOTE_CLOSED; } } if (gdb_con->closed) return ERROR_SERVER_REMOTE_CLOSED; return ERROR_OK; } int gdb_put_packet(struct connection *connection, char *buffer, int len) { struct gdb_connection *gdb_con = connection->priv; gdb_con->busy = 1; int retval = gdb_put_packet_inner(connection, buffer, len); gdb_con->busy = 0; /* we sent some data, reset timer for keep alive messages */ kept_alive(); return retval; } static inline int fetch_packet(struct connection *connection, int *checksum_ok, int noack, int *len, char *buffer) { unsigned char my_checksum = 0; char checksum[3]; int character; int retval = ERROR_OK; struct gdb_connection *gdb_con = connection->priv; my_checksum = 0; int count = 0; count = 0; /* move this over into local variables to use registers and give the * more freedom to optimize */ char *buf_p = gdb_con->buf_p; int buf_cnt = gdb_con->buf_cnt; for (;; ) { /* The common case is that we have an entire packet with no escape chars. * We need to leave at least 2 bytes in the buffer to have * gdb_get_char() update various bits and bobs correctly. */ if ((buf_cnt > 2) && ((buf_cnt + count) < *len)) { /* The compiler will struggle a bit with constant propagation and * aliasing, so we help it by showing that these values do not * change inside the loop */ int i; char *buf = buf_p; int run = buf_cnt - 2; i = 0; int done = 0; while (i < run) { character = *buf++; i++; if (character == '#') { /* Danger! character can be '#' when esc is * used so we need an explicit boolean for done here. */ done = 1; break; } if (character == '}') { /* data transmitted in binary mode (X packet) * uses 0x7d as escape character */ my_checksum += character & 0xff; character = *buf++; i++; my_checksum += character & 0xff; buffer[count++] = (character ^ 0x20) & 0xff; } else { my_checksum += character & 0xff; buffer[count++] = character & 0xff; } } buf_p += i; buf_cnt -= i; if (done) break; } if (count > *len) { LOG_ERROR("packet buffer too small"); retval = ERROR_GDB_BUFFER_TOO_SMALL; break; } retval = gdb_get_char_fast(connection, &character, &buf_p, &buf_cnt); if (retval != ERROR_OK) break; if (character == '#') break; if (character == '}') { /* data transmitted in binary mode (X packet) * uses 0x7d as escape character */ my_checksum += character & 0xff; retval = gdb_get_char_fast(connection, &character, &buf_p, &buf_cnt); if (retval != ERROR_OK) break; my_checksum += character & 0xff; buffer[count++] = (character ^ 0x20) & 0xff; } else { my_checksum += character & 0xff; buffer[count++] = character & 0xff; } } gdb_con->buf_p = buf_p; gdb_con->buf_cnt = buf_cnt; if (retval != ERROR_OK) return retval; *len = count; retval = gdb_get_char(connection, &character); if (retval != ERROR_OK) return retval; checksum[0] = character; retval = gdb_get_char(connection, &character); if (retval != ERROR_OK) return retval; checksum[1] = character; checksum[2] = 0; if (!noack) *checksum_ok = (my_checksum == strtoul(checksum, NULL, 16)); return ERROR_OK; } static int gdb_get_packet_inner(struct connection *connection, char *buffer, int *len) { int character; int retval; struct gdb_connection *gdb_con = connection->priv; while (1) { do { retval = gdb_get_char(connection, &character); if (retval != ERROR_OK) return retval; #ifdef _DEBUG_GDB_IO_ LOG_DEBUG("character: '%c'", character); #endif switch (character) { case '$': break; case '+': /* gdb sends a dummy ack '+' at every remote connect - see * remote_start_remote (remote.c) * in case anyone tries to debug why they receive this * warning every time */ LOG_WARNING("acknowledgment received, but no packet pending"); break; case '-': LOG_WARNING("negative acknowledgment, but no packet pending"); break; case 0x3: gdb_con->ctrl_c = 1; *len = 0; return ERROR_OK; default: LOG_WARNING("ignoring character 0x%x", character); break; } } while (character != '$'); int checksum_ok = 0; /* explicit code expansion here to get faster inlined code in -O3 by not * calculating checksum */ if (gdb_con->noack_mode) { retval = fetch_packet(connection, &checksum_ok, 1, len, buffer); if (retval != ERROR_OK) return retval; } else { retval = fetch_packet(connection, &checksum_ok, 0, len, buffer); if (retval != ERROR_OK) return retval; } if (gdb_con->noack_mode) { /* checksum is not checked in noack mode */ break; } if (checksum_ok) { retval = gdb_write(connection, "+", 1); if (retval != ERROR_OK) return retval; break; } } if (gdb_con->closed) return ERROR_SERVER_REMOTE_CLOSED; return ERROR_OK; } static int gdb_get_packet(struct connection *connection, char *buffer, int *len) { struct gdb_connection *gdb_con = connection->priv; gdb_con->busy = 1; int retval = gdb_get_packet_inner(connection, buffer, len); gdb_con->busy = 0; return retval; } static int gdb_output_con(struct connection *connection, const char *line) { char *hex_buffer; int bin_size; bin_size = strlen(line); hex_buffer = malloc(bin_size * 2 + 2); if (hex_buffer == NULL) return ERROR_GDB_BUFFER_TOO_SMALL; hex_buffer[0] = 'O'; int pkt_len = hexify(hex_buffer + 1, line, bin_size, bin_size * 2 + 1); int retval = gdb_put_packet(connection, hex_buffer, pkt_len + 1); free(hex_buffer); return retval; } static int gdb_output(struct command_context *context, const char *line) { /* this will be dumped to the log and also sent as an O packet if possible */ LOG_USER_N("%s", line); return ERROR_OK; } static void gdb_frontend_halted(struct target *target, struct connection *connection) { struct gdb_connection *gdb_connection = connection->priv; /* In the GDB protocol when we are stepping or continuing execution, * we have a lingering reply. Upon receiving a halted event * when we have that lingering packet, we reply to the original * step or continue packet. * * Executing monitor commands can bring the target in and * out of the running state so we'll see lots of TARGET_EVENT_XXX * that are to be ignored. */ if (gdb_connection->frontend_state == TARGET_RUNNING) { char sig_reply[4]; int signal_var; /* stop forwarding log packets! */ log_remove_callback(gdb_log_callback, connection); if (gdb_connection->ctrl_c) { signal_var = 0x2; gdb_connection->ctrl_c = 0; } else signal_var = gdb_last_signal(target); snprintf(sig_reply, 4, "T%2.2x", signal_var); gdb_put_packet(connection, sig_reply, 3); gdb_connection->frontend_state = TARGET_HALTED; rtos_update_threads(target); } } static int gdb_target_callback_event_handler(struct target *target, enum target_event event, void *priv) { int retval; struct connection *connection = priv; target_handle_event(target, event); switch (event) { case TARGET_EVENT_GDB_HALT: gdb_frontend_halted(target, connection); break; case TARGET_EVENT_HALTED: target_call_event_callbacks(target, TARGET_EVENT_GDB_END); break; case TARGET_EVENT_GDB_FLASH_ERASE_START: retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; break; default: break; } return ERROR_OK; } static int gdb_new_connection(struct connection *connection) { struct gdb_connection *gdb_connection = malloc(sizeof(struct gdb_connection)); struct gdb_service *gdb_service = connection->service->priv; int retval; int initial_ack; connection->priv = gdb_connection; /* initialize gdb connection information */ gdb_connection->buf_p = gdb_connection->buffer; gdb_connection->buf_cnt = 0; gdb_connection->ctrl_c = 0; gdb_connection->frontend_state = TARGET_HALTED; gdb_connection->vflash_image = NULL; gdb_connection->closed = 0; gdb_connection->busy = 0; gdb_connection->noack_mode = 0; gdb_connection->sync = true; gdb_connection->mem_write_error = false; gdb_connection->attached = true; /* send ACK to GDB for debug request */ gdb_write(connection, "+", 1); /* output goes through gdb connection */ command_set_output_handler(connection->cmd_ctx, gdb_output, connection); /* we must remove all breakpoints registered to the target as a previous * GDB session could leave dangling breakpoints if e.g. communication * timed out. */ breakpoint_clear_target(gdb_service->target); watchpoint_clear_target(gdb_service->target); /* clean previous rtos session if supported*/ if ((gdb_service->target->rtos) && (gdb_service->target->rtos->type->clean)) gdb_service->target->rtos->type->clean(gdb_service->target); /* remove the initial ACK from the incoming buffer */ retval = gdb_get_char(connection, &initial_ack); if (retval != ERROR_OK) return retval; /* FIX!!!??? would we actually ever receive a + here??? * Not observed. */ if (initial_ack != '+') gdb_putback_char(connection, initial_ack); target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_ATTACH); if (gdb_use_memory_map) { /* Connect must fail if the memory map can't be set up correctly. * * This will cause an auto_probe to be invoked, which is either * a no-op or it will fail when the target isn't ready(e.g. not halted). */ int i; for (i = 0; i < flash_get_bank_count(); i++) { struct flash_bank *p; retval = get_flash_bank_by_num(i, &p); if (retval != ERROR_OK) { LOG_ERROR("Connect failed. Consider setting up a gdb-attach event for the target " \ "to prepare target for GDB connect, or use 'gdb_memory_map disable'."); return retval; } } } gdb_actual_connections++; LOG_DEBUG("New GDB Connection: %d, Target %s, state: %s", gdb_actual_connections, target_name(gdb_service->target), target_state_name(gdb_service->target)); /* DANGER! If we fail subsequently, we must remove this handler, * otherwise we occasionally see crashes as the timer can invoke the * callback fn. * * register callback to be informed about target events */ target_register_event_callback(gdb_target_callback_event_handler, connection); return ERROR_OK; } static int gdb_connection_closed(struct connection *connection) { struct gdb_service *gdb_service = connection->service->priv; struct gdb_connection *gdb_connection = connection->priv; /* we're done forwarding messages. Tear down callback before * cleaning up connection. */ log_remove_callback(gdb_log_callback, connection); gdb_actual_connections--; LOG_DEBUG("GDB Close, Target: %s, state: %s, gdb_actual_connections=%d", target_name(gdb_service->target), target_state_name(gdb_service->target), gdb_actual_connections); /* see if an image built with vFlash commands is left */ if (gdb_connection->vflash_image) { image_close(gdb_connection->vflash_image); free(gdb_connection->vflash_image); gdb_connection->vflash_image = NULL; } /* if this connection registered a debug-message receiver delete it */ delete_debug_msg_receiver(connection->cmd_ctx, gdb_service->target); if (connection->priv) { free(connection->priv); connection->priv = NULL; } else LOG_ERROR("BUG: connection->priv == NULL"); target_unregister_event_callback(gdb_target_callback_event_handler, connection); target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_END); target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_DETACH); return ERROR_OK; } static void gdb_send_error(struct connection *connection, uint8_t the_error) { char err[4]; snprintf(err, 4, "E%2.2X", the_error); gdb_put_packet(connection, err, 3); } static int gdb_last_signal_packet(struct connection *connection, char *packet, int packet_size) { struct target *target = get_target_from_connection(connection); struct gdb_connection *gdb_con = connection->priv; char sig_reply[4]; int signal_var; if (!gdb_con->attached) { /* if we are here we have received a kill packet * reply W stop reply otherwise gdb gets very unhappy */ gdb_put_packet(connection, "W00", 3); return ERROR_OK; } signal_var = gdb_last_signal(target); snprintf(sig_reply, 4, "S%2.2x", signal_var); gdb_put_packet(connection, sig_reply, 3); return ERROR_OK; } static inline int gdb_reg_pos(struct target *target, int pos, int len) { if (target->endianness == TARGET_LITTLE_ENDIAN) return pos; else return len - 1 - pos; } /* Convert register to string of bytes. NB! The # of bits in the * register might be non-divisible by 8(a byte), in which * case an entire byte is shown. * * NB! the format on the wire is the target endianness * * The format of reg->value is little endian * */ static void gdb_str_to_target(struct target *target, char *tstr, struct reg *reg) { int i; uint8_t *buf; int buf_len; buf = reg->value; buf_len = DIV_ROUND_UP(reg->size, 8); for (i = 0; i < buf_len; i++) { int j = gdb_reg_pos(target, i, buf_len); tstr += sprintf(tstr, "%02x", buf[j]); } } /* copy over in register buffer */ static void gdb_target_to_reg(struct target *target, char *tstr, int str_len, uint8_t *bin) { if (str_len % 2) { LOG_ERROR("BUG: gdb value with uneven number of characters encountered"); exit(-1); } int i; for (i = 0; i < str_len; i += 2) { unsigned t; if (sscanf(tstr + i, "%02x", &t) != 1) { LOG_ERROR("BUG: unable to convert register value"); exit(-1); } int j = gdb_reg_pos(target, i/2, str_len/2); bin[j] = t; } } static int gdb_get_registers_packet(struct connection *connection, char *packet, int packet_size) { struct target *target = get_target_from_connection(connection); struct reg **reg_list; int reg_list_size; int retval; int reg_packet_size = 0; char *reg_packet; char *reg_packet_p; int i; #ifdef _DEBUG_GDB_IO_ LOG_DEBUG("-"); #endif if ((target->rtos != NULL) && (ERROR_OK == rtos_get_gdb_reg_list(connection))) return ERROR_OK; retval = target_get_gdb_reg_list(target, ®_list, ®_list_size); if (retval != ERROR_OK) return gdb_error(connection, retval); for (i = 0; i < reg_list_size; i++) reg_packet_size += DIV_ROUND_UP(reg_list[i]->size, 8) * 2; assert(reg_packet_size > 0); reg_packet = malloc(reg_packet_size + 1); /* plus one for string termination null */ reg_packet_p = reg_packet; for (i = 0; i < reg_list_size; i++) { if (!reg_list[i]->valid) reg_list[i]->type->get(reg_list[i]); gdb_str_to_target(target, reg_packet_p, reg_list[i]); reg_packet_p += DIV_ROUND_UP(reg_list[i]->size, 8) * 2; } #ifdef _DEBUG_GDB_IO_ { char *reg_packet_p_debug; reg_packet_p_debug = strndup(reg_packet, reg_packet_size); LOG_DEBUG("reg_packet: %s", reg_packet_p_debug); free(reg_packet_p_debug); } #endif gdb_put_packet(connection, reg_packet, reg_packet_size); free(reg_packet); free(reg_list); return ERROR_OK; } static int gdb_set_registers_packet(struct connection *connection, char *packet, int packet_size) { struct target *target = get_target_from_connection(connection); int i; struct reg **reg_list; int reg_list_size; int retval; char *packet_p; #ifdef _DEBUG_GDB_IO_ LOG_DEBUG("-"); #endif /* skip command character */ packet++; packet_size--; if (packet_size % 2) { LOG_WARNING("GDB set_registers packet with uneven characters received, dropping connection"); return ERROR_SERVER_REMOTE_CLOSED; } retval = target_get_gdb_reg_list(target, ®_list, ®_list_size); if (retval != ERROR_OK) return gdb_error(connection, retval); packet_p = packet; for (i = 0; i < reg_list_size; i++) { uint8_t *bin_buf; int chars = (DIV_ROUND_UP(reg_list[i]->size, 8) * 2); if (packet_p + chars > packet + packet_size) LOG_ERROR("BUG: register packet is too small for registers"); bin_buf = malloc(DIV_ROUND_UP(reg_list[i]->size, 8)); gdb_target_to_reg(target, packet_p, chars, bin_buf); reg_list[i]->type->set(reg_list[i], bin_buf); /* advance packet pointer */ packet_p += chars; free(bin_buf); } /* free struct reg *reg_list[] array allocated by get_gdb_reg_list */ free(reg_list); gdb_put_packet(connection, "OK", 2); return ERROR_OK; } static int gdb_get_register_packet(struct connection *connection, char *packet, int packet_size) { struct target *target = get_target_from_connection(connection); char *reg_packet; int reg_num = strtoul(packet + 1, NULL, 16); struct reg **reg_list; int reg_list_size; int retval; #ifdef _DEBUG_GDB_IO_ LOG_DEBUG("-"); #endif retval = target_get_gdb_reg_list(target, ®_list, ®_list_size); if (retval != ERROR_OK) return gdb_error(connection, retval); if (reg_list_size <= reg_num) { LOG_ERROR("gdb requested a non-existing register"); return ERROR_SERVER_REMOTE_CLOSED; } if (!reg_list[reg_num]->valid) reg_list[reg_num]->type->get(reg_list[reg_num]); reg_packet = malloc(DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2 + 1); /* plus one for string termination null */ gdb_str_to_target(target, reg_packet, reg_list[reg_num]); gdb_put_packet(connection, reg_packet, DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2); free(reg_list); free(reg_packet); return ERROR_OK; } static int gdb_set_register_packet(struct connection *connection, char *packet, int packet_size) { struct target *target = get_target_from_connection(connection); char *separator; uint8_t *bin_buf; int reg_num = strtoul(packet + 1, &separator, 16); struct reg **reg_list; int reg_list_size; int retval; LOG_DEBUG("-"); retval = target_get_gdb_reg_list(target, ®_list, ®_list_size); if (retval != ERROR_OK) return gdb_error(connection, retval); if (reg_list_size <= reg_num) { LOG_ERROR("gdb requested a non-existing register"); return ERROR_SERVER_REMOTE_CLOSED; } if (*separator != '=') { LOG_ERROR("GDB 'set register packet', but no '=' following the register number"); return ERROR_SERVER_REMOTE_CLOSED; } /* convert from GDB-string (target-endian) to hex-string (big-endian) */ bin_buf = malloc(DIV_ROUND_UP(reg_list[reg_num]->size, 8)); int chars = (DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2); if ((unsigned int)chars != strlen(separator + 1)) { LOG_ERROR("gdb sent a packet with wrong register size"); free(bin_buf); return ERROR_SERVER_REMOTE_CLOSED; } gdb_target_to_reg(target, separator + 1, chars, bin_buf); reg_list[reg_num]->type->set(reg_list[reg_num], bin_buf); gdb_put_packet(connection, "OK", 2); free(bin_buf); free(reg_list); return ERROR_OK; } /* No attempt is made to translate the "retval" to * GDB speak. This has to be done at the calling * site as no mapping really exists. */ static int gdb_error(struct connection *connection, int retval) { LOG_DEBUG("Reporting %i to GDB as generic error", retval); gdb_send_error(connection, EFAULT); return ERROR_OK; } /* We don't have to worry about the default 2 second timeout for GDB packets, * because GDB breaks up large memory reads into smaller reads. * * 8191 bytes by the looks of it. Why 8191 bytes instead of 8192????? */ static int gdb_read_memory_packet(struct connection *connection, char *packet, int packet_size) { struct target *target = get_target_from_connection(connection); char *separator; uint32_t addr = 0; uint32_t len = 0; uint8_t *buffer; char *hex_buffer; int retval = ERROR_OK; /* skip command character */ packet++; addr = strtoul(packet, &separator, 16); if (*separator != ',') { LOG_ERROR("incomplete read memory packet received, dropping connection"); return ERROR_SERVER_REMOTE_CLOSED; } len = strtoul(separator + 1, NULL, 16); buffer = malloc(len); LOG_DEBUG("addr: 0x%8.8" PRIx32 ", len: 0x%8.8" PRIx32 "", addr, len); retval = target_read_buffer(target, addr, len, buffer); if ((retval != ERROR_OK) && !gdb_report_data_abort) { /* TODO : Here we have to lie and send back all zero's lest stack traces won't work. * At some point this might be fixed in GDB, in which case this code can be removed. * * OpenOCD developers are acutely aware of this problem, but there is nothing * gained by involving the user in this problem that hopefully will get resolved * eventually * * http://sourceware.org/cgi-bin/gnatsweb.pl? \ * cmd = view%20audit-trail&database = gdb&pr = 2395 * * For now, the default is to fix up things to make current GDB versions work. * This can be overwritten using the gdb_report_data_abort <'enable'|'disable'> command. */ memset(buffer, 0, len); retval = ERROR_OK; } if (retval == ERROR_OK) { hex_buffer = malloc(len * 2 + 1); int pkt_len = hexify(hex_buffer, (char *)buffer, len, len * 2 + 1); gdb_put_packet(connection, hex_buffer, pkt_len); free(hex_buffer); } else retval = gdb_error(connection, retval); free(buffer); return retval; } static int gdb_write_memory_packet(struct connection *connection, char *packet, int packet_size) { struct target *target = get_target_from_connection(connection); char *separator; uint32_t addr = 0; uint32_t len = 0; uint8_t *buffer; int retval; /* skip command character */ packet++; addr = strtoul(packet, &separator, 16); if (*separator != ',') { LOG_ERROR("incomplete write memory packet received, dropping connection"); return ERROR_SERVER_REMOTE_CLOSED; } len = strtoul(separator + 1, &separator, 16); if (*(separator++) != ':') { LOG_ERROR("incomplete write memory packet received, dropping connection"); return ERROR_SERVER_REMOTE_CLOSED; } buffer = malloc(len); LOG_DEBUG("addr: 0x%8.8" PRIx32 ", len: 0x%8.8" PRIx32 "", addr, len); if (unhexify((char *)buffer, separator, len) != (int)len) LOG_ERROR("unable to decode memory packet"); retval = target_write_buffer(target, addr, len, buffer); if (retval == ERROR_OK) gdb_put_packet(connection, "OK", 2); else retval = gdb_error(connection, retval); free(buffer); return retval; } static int gdb_write_memory_binary_packet(struct connection *connection, char *packet, int packet_size) { struct target *target = get_target_from_connection(connection); char *separator; uint32_t addr = 0; uint32_t len = 0; int retval = ERROR_OK; /* skip command character */ packet++; addr = strtoul(packet, &separator, 16); if (*separator != ',') { LOG_ERROR("incomplete write memory binary packet received, dropping connection"); return ERROR_SERVER_REMOTE_CLOSED; } len = strtoul(separator + 1, &separator, 16); if (*(separator++) != ':') { LOG_ERROR("incomplete write memory binary packet received, dropping connection"); return ERROR_SERVER_REMOTE_CLOSED; } struct gdb_connection *gdb_connection = connection->priv; if (gdb_connection->mem_write_error) { retval = ERROR_FAIL; /* now that we have reported the memory write error, we can clear the condition */ gdb_connection->mem_write_error = false; } /* By replying the packet *immediately* GDB will send us a new packet * while we write the last one to the target. */ if (retval == ERROR_OK) gdb_put_packet(connection, "OK", 2); else { retval = gdb_error(connection, retval); if (retval != ERROR_OK) return retval; } if (len) { LOG_DEBUG("addr: 0x%8.8" PRIx32 ", len: 0x%8.8" PRIx32 "", addr, len); retval = target_write_buffer(target, addr, len, (uint8_t *)separator); if (retval != ERROR_OK) gdb_connection->mem_write_error = true; } return ERROR_OK; } static int gdb_step_continue_packet(struct connection *connection, char *packet, int packet_size) { struct target *target = get_target_from_connection(connection); int current = 0; uint32_t address = 0x0; int retval = ERROR_OK; LOG_DEBUG("-"); if (packet_size > 1) { packet[packet_size] = 0; address = strtoul(packet + 1, NULL, 16); } else current = 1; if (packet[0] == 'c') { LOG_DEBUG("continue"); /* resume at current address, don't handle breakpoints, not debugging */ retval = target_resume(target, current, address, 0, 0); } else if (packet[0] == 's') { LOG_DEBUG("step"); /* step at current or address, don't handle breakpoints */ retval = target_step(target, current, address, 0); } return retval; } static int gdb_breakpoint_watchpoint_packet(struct connection *connection, char *packet, int packet_size) { struct target *target = get_target_from_connection(connection); int type; enum breakpoint_type bp_type = BKPT_SOFT /* dummy init to avoid warning */; enum watchpoint_rw wp_type = WPT_READ /* dummy init to avoid warning */; uint32_t address; uint32_t size; char *separator; int retval; LOG_DEBUG("-"); type = strtoul(packet + 1, &separator, 16); if (type == 0) /* memory breakpoint */ bp_type = BKPT_SOFT; else if (type == 1) /* hardware breakpoint */ bp_type = BKPT_HARD; else if (type == 2) /* write watchpoint */ wp_type = WPT_WRITE; else if (type == 3) /* read watchpoint */ wp_type = WPT_READ; else if (type == 4) /* access watchpoint */ wp_type = WPT_ACCESS; else { LOG_ERROR("invalid gdb watch/breakpoint type(%d), dropping connection", type); return ERROR_SERVER_REMOTE_CLOSED; } if (gdb_breakpoint_override && ((bp_type == BKPT_SOFT) || (bp_type == BKPT_HARD))) bp_type = gdb_breakpoint_override_type; if (*separator != ',') { LOG_ERROR("incomplete breakpoint/watchpoint packet received, dropping connection"); return ERROR_SERVER_REMOTE_CLOSED; } address = strtoul(separator + 1, &separator, 16); if (*separator != ',') { LOG_ERROR("incomplete breakpoint/watchpoint packet received, dropping connection"); return ERROR_SERVER_REMOTE_CLOSED; } size = strtoul(separator + 1, &separator, 16); switch (type) { case 0: case 1: if (packet[0] == 'Z') { retval = breakpoint_add(target, address, size, bp_type); if (retval != ERROR_OK) { retval = gdb_error(connection, retval); if (retval != ERROR_OK) return retval; } else gdb_put_packet(connection, "OK", 2); } else { breakpoint_remove(target, address); gdb_put_packet(connection, "OK", 2); } break; case 2: case 3: case 4: { if (packet[0] == 'Z') { retval = watchpoint_add(target, address, size, wp_type, 0, 0xffffffffu); if (retval != ERROR_OK) { retval = gdb_error(connection, retval); if (retval != ERROR_OK) return retval; } else gdb_put_packet(connection, "OK", 2); } else { watchpoint_remove(target, address); gdb_put_packet(connection, "OK", 2); } break; } default: break; } return ERROR_OK; } /* print out a string and allocate more space as needed, * mainly used for XML at this point */ static void xml_printf(int *retval, char **xml, int *pos, int *size, const char *fmt, ...) { if (*retval != ERROR_OK) return; int first = 1; for (;; ) { if ((*xml == NULL) || (!first)) { /* start by 0 to exercise all the code paths. * Need minimum 2 bytes to fit 1 char and 0 terminator. */ *size = *size * 2 + 2; char *t = *xml; *xml = realloc(*xml, *size); if (*xml == NULL) { if (t) free(t); *retval = ERROR_SERVER_REMOTE_CLOSED; return; } } va_list ap; int ret; va_start(ap, fmt); ret = vsnprintf(*xml + *pos, *size - *pos, fmt, ap); va_end(ap); if ((ret > 0) && ((ret + 1) < *size - *pos)) { *pos += ret; return; } /* there was just enough or not enough space, allocate more. */ first = 0; } } static int decode_xfer_read(char *buf, char **annex, int *ofs, unsigned int *len) { char *separator; /* Extract and NUL-terminate the annex. */ *annex = buf; while (*buf && *buf != ':') buf++; if (*buf == '\0') return -1; *buf++ = 0; /* After the read marker and annex, qXfer looks like a * traditional 'm' packet. */ *ofs = strtoul(buf, &separator, 16); if (*separator != ',') return -1; *len = strtoul(separator + 1, NULL, 16); return 0; } static int compare_bank(const void *a, const void *b) { struct flash_bank *b1, *b2; b1 = *((struct flash_bank **)a); b2 = *((struct flash_bank **)b); if (b1->base == b2->base) return 0; else if (b1->base > b2->base) return 1; else return -1; } static int gdb_memory_map(struct connection *connection, char *packet, int packet_size) { /* We get away with only specifying flash here. Regions that are not * specified are treated as if we provided no memory map(if not we * could detect the holes and mark them as RAM). * Normally we only execute this code once, but no big deal if we * have to regenerate it a couple of times. */ struct target *target = get_target_from_connection(connection); struct flash_bank *p; char *xml = NULL; int size = 0; int pos = 0; int retval = ERROR_OK; struct flash_bank **banks; int offset; int length; char *separator; uint32_t ram_start = 0; int i; int target_flash_banks = 0; /* skip command character */ packet += 23; offset = strtoul(packet, &separator, 16); length = strtoul(separator + 1, &separator, 16); xml_printf(&retval, &xml, &pos, &size, "\n"); /* Sort banks in ascending order. We need to report non-flash * memory as ram (or rather read/write) by default for GDB, since * it has no concept of non-cacheable read/write memory (i/o etc). * * FIXME Most non-flash addresses are *NOT* RAM! Don't lie. * Current versions of GDB assume unlisted addresses are RAM... */ banks = malloc(sizeof(struct flash_bank *)*flash_get_bank_count()); for (i = 0; i < flash_get_bank_count(); i++) { retval = get_flash_bank_by_num(i, &p); if (retval != ERROR_OK) { free(banks); gdb_error(connection, retval); return retval; } if (p->target == target) banks[target_flash_banks++] = p; } qsort(banks, target_flash_banks, sizeof(struct flash_bank *), compare_bank); for (i = 0; i < target_flash_banks; i++) { int j; unsigned sector_size = 0; uint32_t start; p = banks[i]; start = p->base; if (ram_start < p->base) xml_printf(&retval, &xml, &pos, &size, "\n", ram_start, p->base - ram_start); /* Report adjacent groups of same-size sectors. So for * example top boot CFI flash will list an initial region * with several large sectors (maybe 128KB) and several * smaller ones at the end (maybe 32KB). STR7 will have * regions with 8KB, 32KB, and 64KB sectors; etc. */ for (j = 0; j < p->num_sectors; j++) { unsigned group_len; /* Maybe start a new group of sectors. */ if (sector_size == 0) { start = p->base + p->sectors[j].offset; xml_printf(&retval, &xml, &pos, &size, "sectors[j].size; } /* Does this finish a group of sectors? * If not, continue an already-started group. */ if (j == p->num_sectors - 1) group_len = (p->base + p->size) - start; else if (p->sectors[j + 1].size != sector_size) group_len = p->base + p->sectors[j + 1].offset - start; else continue; xml_printf(&retval, &xml, &pos, &size, "length=\"0x%x\">\n" "" "0x%x\n" "\n", group_len, sector_size); sector_size = 0; } ram_start = p->base + p->size; } if (ram_start != 0) xml_printf(&retval, &xml, &pos, &size, "\n", ram_start, 0-ram_start); /* ELSE a flash chip could be at the very end of the 32 bit address * space, in which case ram_start will be precisely 0 */ free(banks); banks = NULL; xml_printf(&retval, &xml, &pos, &size, "\n"); if (retval != ERROR_OK) { gdb_error(connection, retval); return retval; } if (offset + length > pos) length = pos - offset; char *t = malloc(length + 1); t[0] = 'l'; memcpy(t + 1, xml + offset, length); gdb_put_packet(connection, t, length + 1); free(t); free(xml); return ERROR_OK; } static int gdb_query_packet(struct connection *connection, char *packet, int packet_size) { struct command_context *cmd_ctx = connection->cmd_ctx; struct gdb_connection *gdb_connection = connection->priv; struct target *target = get_target_from_connection(connection); if (strncmp(packet, "qRcmd,", 6) == 0) { if (packet_size > 6) { char *cmd; cmd = malloc((packet_size - 6) / 2 + 1); int len = unhexify(cmd, packet + 6, (packet_size - 6) / 2); cmd[len] = 0; /* We want to print all debug output to GDB connection */ log_add_callback(gdb_log_callback, connection); target_call_timer_callbacks_now(); /* some commands need to know the GDB connection, make note of current * GDB connection. */ current_gdb_connection = gdb_connection; command_run_line(cmd_ctx, cmd); current_gdb_connection = NULL; target_call_timer_callbacks_now(); log_remove_callback(gdb_log_callback, connection); free(cmd); } gdb_put_packet(connection, "OK", 2); return ERROR_OK; } else if (strncmp(packet, "qCRC:", 5) == 0) { if (packet_size > 5) { int retval; char gdb_reply[10]; char *separator; uint32_t checksum; uint32_t addr = 0; uint32_t len = 0; /* skip command character */ packet += 5; addr = strtoul(packet, &separator, 16); if (*separator != ',') { LOG_ERROR("incomplete read memory packet received, dropping connection"); return ERROR_SERVER_REMOTE_CLOSED; } len = strtoul(separator + 1, NULL, 16); retval = target_checksum_memory(target, addr, len, &checksum); if (retval == ERROR_OK) { snprintf(gdb_reply, 10, "C%8.8" PRIx32 "", checksum); gdb_put_packet(connection, gdb_reply, 9); } else { retval = gdb_error(connection, retval); if (retval != ERROR_OK) return retval; } return ERROR_OK; } } else if (strncmp(packet, "qSupported", 10) == 0) { /* we currently support packet size and qXfer:memory-map:read (if enabled) * disable qXfer:features:read for the moment */ int retval = ERROR_OK; char *buffer = NULL; int pos = 0; int size = 0; xml_printf(&retval, &buffer, &pos, &size, "PacketSize=%x;qXfer:memory-map:read%c;qXfer:features:read-;QStartNoAckMode+", (GDB_BUFFER_SIZE - 1), ((gdb_use_memory_map == 1) && (flash_get_bank_count() > 0)) ? '+' : '-'); if (retval != ERROR_OK) { gdb_send_error(connection, 01); return ERROR_OK; } gdb_put_packet(connection, buffer, strlen(buffer)); free(buffer); return ERROR_OK; } else if ((strncmp(packet, "qXfer:memory-map:read::", 23) == 0) && (flash_get_bank_count() > 0)) return gdb_memory_map(connection, packet, packet_size); else if (strncmp(packet, "qXfer:features:read:", 20) == 0) { char *xml = NULL; int size = 0; int pos = 0; int retval = ERROR_OK; int offset; unsigned int length; char *annex; /* skip command character */ packet += 20; if (decode_xfer_read(packet, &annex, &offset, &length) < 0) { gdb_send_error(connection, 01); return ERROR_OK; } if (strcmp(annex, "target.xml") != 0) { gdb_send_error(connection, 01); return ERROR_OK; } xml_printf(&retval, &xml, &pos, &size, \ "l < target version=\"1.0\">\n < architecture > arm\n\n"); if (retval != ERROR_OK) { gdb_error(connection, retval); return retval; } gdb_put_packet(connection, xml, strlen(xml)); free(xml); return ERROR_OK; } else if (strncmp(packet, "QStartNoAckMode", 15) == 0) { gdb_connection->noack_mode = 1; gdb_put_packet(connection, "OK", 2); return ERROR_OK; } gdb_put_packet(connection, "", 0); return ERROR_OK; } static int gdb_v_packet(struct connection *connection, char *packet, int packet_size) { struct gdb_connection *gdb_connection = connection->priv; struct gdb_service *gdb_service = connection->service->priv; int result; /* if flash programming disabled - send a empty reply */ if (gdb_flash_program == 0) { gdb_put_packet(connection, "", 0); return ERROR_OK; } if (strncmp(packet, "vFlashErase:", 12) == 0) { unsigned long addr; unsigned long length; char *parse = packet + 12; if (*parse == '\0') { LOG_ERROR("incomplete vFlashErase packet received, dropping connection"); return ERROR_SERVER_REMOTE_CLOSED; } addr = strtoul(parse, &parse, 16); if (*(parse++) != ',' || *parse == '\0') { LOG_ERROR("incomplete vFlashErase packet received, dropping connection"); return ERROR_SERVER_REMOTE_CLOSED; } length = strtoul(parse, &parse, 16); if (*parse != '\0') { LOG_ERROR("incomplete vFlashErase packet received, dropping connection"); return ERROR_SERVER_REMOTE_CLOSED; } /* assume all sectors need erasing - stops any problems * when flash_write is called multiple times */ flash_set_dirty(); /* perform any target specific operations before the erase */ target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_FLASH_ERASE_START); /* vFlashErase:addr,length messages require region start and * end to be "block" aligned ... if padding is ever needed, * GDB will have become dangerously confused. */ result = flash_erase_address_range(gdb_service->target, false, addr, length); /* perform any target specific operations after the erase */ target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_FLASH_ERASE_END); /* perform erase */ if (result != ERROR_OK) { /* GDB doesn't evaluate the actual error number returned, * treat a failed erase as an I/O error */ gdb_send_error(connection, EIO); LOG_ERROR("flash_erase returned %i", result); } else gdb_put_packet(connection, "OK", 2); return ERROR_OK; } if (strncmp(packet, "vFlashWrite:", 12) == 0) { int retval; unsigned long addr; unsigned long length; char *parse = packet + 12; if (*parse == '\0') { LOG_ERROR("incomplete vFlashErase packet received, dropping connection"); return ERROR_SERVER_REMOTE_CLOSED; } addr = strtoul(parse, &parse, 16); if (*(parse++) != ':') { LOG_ERROR("incomplete vFlashErase packet received, dropping connection"); return ERROR_SERVER_REMOTE_CLOSED; } length = packet_size - (parse - packet); /* create a new image if there isn't already one */ if (gdb_connection->vflash_image == NULL) { gdb_connection->vflash_image = malloc(sizeof(struct image)); image_open(gdb_connection->vflash_image, "", "build"); } /* create new section with content from packet buffer */ retval = image_add_section(gdb_connection->vflash_image, addr, length, 0x0, (uint8_t *)parse); if (retval != ERROR_OK) return retval; gdb_put_packet(connection, "OK", 2); return ERROR_OK; } if (strncmp(packet, "vFlashDone", 10) == 0) { uint32_t written; /* process the flashing buffer. No need to erase as GDB * always issues a vFlashErase first. */ target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_FLASH_WRITE_START); result = flash_write(gdb_service->target, gdb_connection->vflash_image, &written, 0); target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_FLASH_WRITE_END); if (result != ERROR_OK) { if (result == ERROR_FLASH_DST_OUT_OF_BANK) gdb_put_packet(connection, "E.memtype", 9); else gdb_send_error(connection, EIO); } else { LOG_DEBUG("wrote %u bytes from vFlash image to flash", (unsigned)written); gdb_put_packet(connection, "OK", 2); } image_close(gdb_connection->vflash_image); free(gdb_connection->vflash_image); gdb_connection->vflash_image = NULL; return ERROR_OK; } gdb_put_packet(connection, "", 0); return ERROR_OK; } static int gdb_detach(struct connection *connection) { struct gdb_service *gdb_service = connection->service->priv; target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_DETACH); return gdb_put_packet(connection, "OK", 2); } static void gdb_log_callback(void *priv, const char *file, unsigned line, const char *function, const char *string) { struct connection *connection = priv; struct gdb_connection *gdb_con = connection->priv; if (gdb_con->busy) { /* do not reply this using the O packet */ return; } gdb_output_con(connection, string); } static void gdb_sig_halted(struct connection *connection) { char sig_reply[4]; snprintf(sig_reply, 4, "T%2.2x", 2); gdb_put_packet(connection, sig_reply, 3); } static int gdb_input_inner(struct connection *connection) { /* Do not allocate this on the stack */ static char gdb_packet_buffer[GDB_BUFFER_SIZE]; struct gdb_service *gdb_service = connection->service->priv; struct target *target = gdb_service->target; char *packet = gdb_packet_buffer; int packet_size; int retval; struct gdb_connection *gdb_con = connection->priv; static int extended_protocol; /* drain input buffer. If one of the packets fail, then an error * packet is replied, if applicable. * * This loop will terminate and the error code is returned. * * The calling fn will check if this error is something that * can be recovered from, or if the connection must be closed. * * If the error is recoverable, this fn is called again to * drain the rest of the buffer. */ do { packet_size = GDB_BUFFER_SIZE-1; retval = gdb_get_packet(connection, packet, &packet_size); if (retval != ERROR_OK) return retval; /* terminate with zero */ packet[packet_size] = 0; if (LOG_LEVEL_IS(LOG_LVL_DEBUG)) { if (packet[0] == 'X') { /* binary packets spew junk into the debug log stream */ char buf[50]; int x; for (x = 0; (x < 49) && (packet[x] != ':'); x++) buf[x] = packet[x]; buf[x] = 0; LOG_DEBUG("received packet: '%s:'", buf); } else LOG_DEBUG("received packet: '%s'", packet); } if (packet_size > 0) { retval = ERROR_OK; switch (packet[0]) { case 'T': /* Is thread alive? */ gdb_thread_packet(connection, packet, packet_size); break; case 'H': /* Set current thread ( 'c' for step and continue, * 'g' for all other operations ) */ gdb_thread_packet(connection, packet, packet_size); break; case 'q': case 'Q': retval = gdb_thread_packet(connection, packet, packet_size); if (retval == GDB_THREAD_PACKET_NOT_CONSUMED) retval = gdb_query_packet(connection, packet, packet_size); break; case 'g': retval = gdb_get_registers_packet(connection, packet, packet_size); break; case 'G': retval = gdb_set_registers_packet(connection, packet, packet_size); break; case 'p': retval = gdb_get_register_packet(connection, packet, packet_size); break; case 'P': retval = gdb_set_register_packet(connection, packet, packet_size); break; case 'm': retval = gdb_read_memory_packet(connection, packet, packet_size); break; case 'M': retval = gdb_write_memory_packet(connection, packet, packet_size); break; case 'z': case 'Z': retval = gdb_breakpoint_watchpoint_packet(connection, packet, packet_size); break; case '?': gdb_last_signal_packet(connection, packet, packet_size); break; case 'c': case 's': { gdb_thread_packet(connection, packet, packet_size); log_add_callback(gdb_log_callback, connection); if (gdb_con->mem_write_error) { LOG_ERROR("Memory write failure!"); /* now that we have reported the memory write error, * we can clear the condition */ gdb_con->mem_write_error = false; } bool nostep = false; bool already_running = false; if (target->state == TARGET_RUNNING) { LOG_WARNING("WARNING! The target is already running. " "All changes GDB did to registers will be discarded! " "Waiting for target to halt."); already_running = true; } else if (target->state != TARGET_HALTED) { LOG_WARNING("The target is not in the halted nor running stated, " \ "stepi/continue ignored."); nostep = true; } else if ((packet[0] == 's') && gdb_con->sync) { /* Hmm..... when you issue a continue in GDB, then a "stepi" is * sent by GDB first to OpenOCD, thus defeating the check to * make only the single stepping have the sync feature... */ nostep = true; LOG_WARNING("stepi ignored. GDB will now fetch the register state " \ "from the target."); } gdb_con->sync = false; if (!already_running && nostep) { /* Either the target isn't in the halted state, then we can't * step/continue. This might be early setup, etc. * * Or we want to allow GDB to pick up a fresh set of * register values without modifying the target state. * */ gdb_sig_halted(connection); /* stop forwarding log packets! */ log_remove_callback(gdb_log_callback, connection); } else { /* We're running/stepping, in which case we can * forward log output until the target is halted */ gdb_con->frontend_state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_GDB_START); if (!already_running) { /* Here we don't want packet processing to stop even if this fails, * so we use a local variable instead of retval. */ retval = gdb_step_continue_packet(connection, packet, packet_size); if (retval != ERROR_OK) { /* we'll never receive a halted * condition... issue a false one.. */ gdb_frontend_halted(target, connection); } } } } break; case 'v': retval = gdb_v_packet(connection, packet, packet_size); break; case 'D': retval = gdb_detach(connection); extended_protocol = 0; break; case 'X': retval = gdb_write_memory_binary_packet(connection, packet, packet_size); if (retval != ERROR_OK) return retval; break; case 'k': if (extended_protocol != 0) { gdb_con->attached = false; break; } gdb_put_packet(connection, "OK", 2); return ERROR_SERVER_REMOTE_CLOSED; case '!': /* handle extended remote protocol */ extended_protocol = 1; gdb_put_packet(connection, "OK", 2); break; case 'R': /* handle extended restart packet */ breakpoint_clear_target(gdb_service->target); watchpoint_clear_target(gdb_service->target); command_run_linef(connection->cmd_ctx, "ocd_gdb_restart %s", target_name(target)); /* set connection as attached after reset */ gdb_con->attached = true; /* info rtos parts */ gdb_thread_packet(connection, packet, packet_size); break; case 'j': /* packet supported only by smp target i.e cortex_a.c*/ /* handle smp packet replying coreid played to gbd */ gdb_read_smp_packet(connection, packet, packet_size); break; case 'J': /* packet supported only by smp target i.e cortex_a.c */ /* handle smp packet setting coreid to be played at next * resume to gdb */ gdb_write_smp_packet(connection, packet, packet_size); break; default: /* ignore unknown packets */ LOG_DEBUG("ignoring 0x%2.2x packet", packet[0]); gdb_put_packet(connection, NULL, 0); break; } /* if a packet handler returned an error, exit input loop */ if (retval != ERROR_OK) return retval; } if (gdb_con->ctrl_c) { if (target->state == TARGET_RUNNING) { retval = target_halt(target); if (retval != ERROR_OK) target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT); gdb_con->ctrl_c = 0; } else { LOG_INFO("The target is not running when halt was requested, stopping GDB."); target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT); } } } while (gdb_con->buf_cnt > 0); return ERROR_OK; } static int gdb_input(struct connection *connection) { int retval = gdb_input_inner(connection); struct gdb_connection *gdb_con = connection->priv; if (retval == ERROR_SERVER_REMOTE_CLOSED) return retval; /* logging does not propagate the error, yet can set the gdb_con->closed flag */ if (gdb_con->closed) return ERROR_SERVER_REMOTE_CLOSED; /* we'll recover from any other errors(e.g. temporary timeouts, etc.) */ return ERROR_OK; } static int gdb_target_start(struct target *target, const char *port) { struct gdb_service *gdb_service; int ret; gdb_service = malloc(sizeof(struct gdb_service)); if (NULL == gdb_service) return -ENOMEM; gdb_service->target = target; gdb_service->core[0] = -1; gdb_service->core[1] = -1; target->gdb_service = gdb_service; ret = add_service("gdb", port, 1, &gdb_new_connection, &gdb_input, &gdb_connection_closed, gdb_service); /* initialialize all targets gdb service with the same pointer */ { struct target_list *head; struct target *curr; head = target->head; while (head != (struct target_list *)NULL) { curr = head->target; if (curr != target) curr->gdb_service = gdb_service; head = head->next; } } return ret; } static int gdb_target_add_one(struct target *target) { /* one gdb instance per smp list */ if ((target->smp) && (target->gdb_service)) return ERROR_OK; int retval = gdb_target_start(target, gdb_port_next); if (retval == ERROR_OK) { long portnumber; /* If we can parse the port number * then we increment the port number for the next target. */ char *end; portnumber = strtol(gdb_port_next, &end, 0); if (!*end) { if (parse_long(gdb_port_next, &portnumber) == ERROR_OK) { free((void *)gdb_port_next); gdb_port_next = alloc_printf("%d", portnumber+1); } } } return retval; } int gdb_target_add_all(struct target *target) { if (NULL == target) { LOG_WARNING("gdb services need one or more targets defined"); return ERROR_OK; } while (NULL != target) { int retval = gdb_target_add_one(target); if (ERROR_OK != retval) return retval; target = target->next; } return ERROR_OK; } COMMAND_HANDLER(handle_gdb_sync_command) { if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; if (current_gdb_connection == NULL) { command_print(CMD_CTX, "gdb_sync command can only be run from within gdb using \"monitor gdb_sync\""); return ERROR_FAIL; } current_gdb_connection->sync = true; return ERROR_OK; } /* daemon configuration command gdb_port */ COMMAND_HANDLER(handle_gdb_port_command) { int retval = CALL_COMMAND_HANDLER(server_pipe_command, &gdb_port); if (ERROR_OK == retval) { free((void *)gdb_port_next); gdb_port_next = strdup(gdb_port); } return retval; } COMMAND_HANDLER(handle_gdb_memory_map_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_ENABLE(CMD_ARGV[0], gdb_use_memory_map); return ERROR_OK; } COMMAND_HANDLER(handle_gdb_flash_program_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_ENABLE(CMD_ARGV[0], gdb_flash_program); return ERROR_OK; } COMMAND_HANDLER(handle_gdb_report_data_abort_command) { if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; COMMAND_PARSE_ENABLE(CMD_ARGV[0], gdb_report_data_abort); return ERROR_OK; } /* gdb_breakpoint_override */ COMMAND_HANDLER(handle_gdb_breakpoint_override_command) { if (CMD_ARGC == 0) { /* nothing */ } else if (CMD_ARGC == 1) { gdb_breakpoint_override = 1; if (strcmp(CMD_ARGV[0], "hard") == 0) gdb_breakpoint_override_type = BKPT_HARD; else if (strcmp(CMD_ARGV[0], "soft") == 0) gdb_breakpoint_override_type = BKPT_SOFT; else if (strcmp(CMD_ARGV[0], "disable") == 0) gdb_breakpoint_override = 0; } else return ERROR_COMMAND_SYNTAX_ERROR; if (gdb_breakpoint_override) LOG_USER("force %s breakpoints", (gdb_breakpoint_override_type == BKPT_HARD) ? "hard" : "soft"); else LOG_USER("breakpoint type is not overridden"); return ERROR_OK; } static const struct command_registration gdb_command_handlers[] = { { .name = "gdb_sync", .handler = handle_gdb_sync_command, .mode = COMMAND_ANY, .help = "next stepi will return immediately allowing " "GDB to fetch register state without affecting " "target state", .usage = "" }, { .name = "gdb_port", .handler = handle_gdb_port_command, .mode = COMMAND_ANY, .help = "Normally gdb listens to a TCP/IP port. Each subsequent GDB " "server listens for the next port number after the " "base port number specified. " "No arguments reports GDB port. \"pipe\" means listen to stdin " "output to stdout, an integer is base port number, \"disable\" disables " "port. Any other string is are interpreted as named pipe to listen to. " "Output pipe is the same name as input pipe, but with 'o' appended.", .usage = "[port_num]", }, { .name = "gdb_memory_map", .handler = handle_gdb_memory_map_command, .mode = COMMAND_CONFIG, .help = "enable or disable memory map", .usage = "('enable'|'disable')" }, { .name = "gdb_flash_program", .handler = handle_gdb_flash_program_command, .mode = COMMAND_CONFIG, .help = "enable or disable flash program", .usage = "('enable'|'disable')" }, { .name = "gdb_report_data_abort", .handler = handle_gdb_report_data_abort_command, .mode = COMMAND_CONFIG, .help = "enable or disable reporting data aborts", .usage = "('enable'|'disable')" }, { .name = "gdb_breakpoint_override", .handler = handle_gdb_breakpoint_override_command, .mode = COMMAND_ANY, .help = "Display or specify type of breakpoint " "to be used by gdb 'break' commands.", .usage = "('hard'|'soft'|'disable')" }, COMMAND_REGISTRATION_DONE }; int gdb_register_commands(struct command_context *cmd_ctx) { gdb_port = strdup("3333"); gdb_port_next = strdup("3333"); return register_commands(cmd_ctx, NULL, gdb_command_handlers); } openocd-0.7.0/src/server/tcl_server.h0000644000175000001440000000304412134336410014476 00000000000000/*************************************************************************** * Copyright (C) 2008 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef _TCL_SERVER_H_ #define _TCL_SERVER_H_ #include int tcl_init(void); int tcl_register_commands(struct command_context *cmd_ctx); #endif /* _TCL_SERVER_H_ */ openocd-0.7.0/src/server/telnet_server.h0000644000175000001440000000542712134336410015216 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 by Spencer Oliver * * spen@spen-soft.co.uk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef TELNET_SERVER_H #define TELNET_SERVER_H #include #define TELNET_BUFFER_SIZE (1024) #define TELNET_OPTION_MAX_SIZE (128) #define TELNET_LINE_HISTORY_SIZE (128) #define TELNET_LINE_MAX_SIZE (256) enum telnet_states { TELNET_STATE_DATA, TELNET_STATE_IAC, TELNET_STATE_SB, TELNET_STATE_SE, TELNET_STATE_WILL, TELNET_STATE_WONT, TELNET_STATE_DO, TELNET_STATE_DONT, TELNET_STATE_ESCAPE, }; struct telnet_connection { char *prompt; enum telnet_states state; char line[TELNET_LINE_MAX_SIZE]; int line_size; int line_cursor; char option[TELNET_OPTION_MAX_SIZE]; int option_size; char last_escape; char *history[TELNET_LINE_HISTORY_SIZE]; int next_history; int current_history; int closed; }; struct telnet_service { char *banner; }; int telnet_init(char *banner); int telnet_register_commands(struct command_context *command_context); #endif /* TELNET_SERVER_H */ openocd-0.7.0/src/server/Makefile.am0000644000175000001440000000104612134336410014211 00000000000000include $(top_srcdir)/common.mk METASOURCES = AUTO noinst_LTLIBRARIES = libserver.la noinst_HEADERS = server.h telnet_server.h gdb_server.h libserver_la_SOURCES = server.c telnet_server.c gdb_server.c libserver_la_SOURCES += server_stubs.c libserver_la_CFLAGS = if IS_MINGW # FD_* macros are sloppy with their signs on MinGW32 platform libserver_la_CFLAGS += -Wno-sign-compare endif # tcl server addons noinst_HEADERS += tcl_server.h libserver_la_SOURCES += tcl_server.c EXTRA_DIST = \ startup.tcl MAINTAINERCLEANFILES = $(srcdir)/Makefile.in openocd-0.7.0/src/server/startup.tcl0000644000175000001440000000051312134336410014361 00000000000000# Defines basic Tcl procs for OpenOCD server modules # Handle GDB 'R' packet. Can be overridden by configuration script, # but it's not something one would expect target scripts to do # normally proc ocd_gdb_restart {target_id} { # Fix!!! we're resetting all targets here! Really we should reset only # one target reset halt } openocd-0.7.0/src/hello.c0000644000175000001440000000653712134336410012130 00000000000000/*************************************************************************** * Copyright (C) 2009 Zachary T Welch * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include COMMAND_HANDLER(handle_foo_command) { if (CMD_ARGC < 1 || CMD_ARGC > 2) return ERROR_COMMAND_SYNTAX_ERROR; uint32_t address; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); const char *msg = ""; if (CMD_ARGC == 2) { bool enable; COMMAND_PARSE_ENABLE(CMD_ARGV[1], enable); msg = enable ? "enable" : "disable"; } LOG_INFO("%s: address=0x%8.8" PRIx32 " enabled=%s", CMD_NAME, address, msg); return ERROR_OK; } static bool foo_flag; COMMAND_HANDLER(handle_flag_command) { return CALL_COMMAND_HANDLER(handle_command_parse_bool, &foo_flag, "foo flag"); } static const struct command_registration foo_command_handlers[] = { { .name = "bar", .handler = &handle_foo_command, .mode = COMMAND_ANY, .usage = "address ['enable'|'disable']", .help = "an example command", }, { .name = "baz", .handler = &handle_foo_command, .mode = COMMAND_ANY, .usage = "address ['enable'|'disable']", .help = "a sample command", }, { .name = "flag", .handler = &handle_flag_command, .mode = COMMAND_ANY, .usage = "[on|off]", .help = "set a flag", }, COMMAND_REGISTRATION_DONE }; static COMMAND_HELPER(handle_hello_args, const char **sep, const char **name) { if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; if (1 == CMD_ARGC) { *sep = " "; *name = CMD_ARGV[0]; } else *sep = *name = ""; return ERROR_OK; } COMMAND_HANDLER(handle_hello_command) { const char *sep, *name; int retval = CALL_COMMAND_HANDLER(handle_hello_args, &sep, &name); if (ERROR_OK == retval) command_print(CMD_CTX, "Greetings%s%s!", sep, name); return retval; } const struct command_registration hello_command_handlers[] = { { .name = "hello", .handler = handle_hello_command, .mode = COMMAND_ANY, .help = "prints a warm welcome", .usage = "[name]", }, { .name = "foo", .mode = COMMAND_ANY, .help = "example command handler skeleton", .chain = foo_command_handlers, }, COMMAND_REGISTRATION_DONE }; openocd-0.7.0/src/xsvf/0000755000175000001440000000000012141414413011712 500000000000000openocd-0.7.0/src/xsvf/xsvf.h0000644000175000001440000000321612134336410012775 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef XSVF_H #define XSVF_H #include int xsvf_register_commands(struct command_context *cmd_ctx); #define ERROR_XSVF_EOF (-200) #define ERROR_XSVF_FAILED (-201) #endif /* XSVF_H */ openocd-0.7.0/src/xsvf/Makefile.in0000644000175000001440000004074512141414276013720 00000000000000# Makefile.in generated by automake 1.13.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ DIST_COMMON = $(top_srcdir)/common.mk $(srcdir)/Makefile.in \ $(srcdir)/Makefile.am $(top_srcdir)/depcomp $(noinst_HEADERS) @INTERNAL_JIMTCL_TRUE@am__append_1 = -I$(top_srcdir)/jimtcl \ @INTERNAL_JIMTCL_TRUE@ -I$(top_builddir)/jimtcl subdir = src/xsvf ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/config_subdir.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libxsvf_la_LIBADD = am_libxsvf_la_OBJECTS = xsvf.lo libxsvf_la_OBJECTS = $(am_libxsvf_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libxsvf_la_SOURCES) DIST_SOURCES = $(libxsvf_la_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CC_FOR_BUILD = @CC_FOR_BUILD@ CFLAGS = @CFLAGS@ CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@ FGREP = @FGREP@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ doxygen_as_html = @doxygen_as_html@ doxygen_as_pdf = @doxygen_as_pdf@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ # common flags used in openocd build AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src \ -I$(top_srcdir)/src/helper -DPKGDATADIR=\"$(pkgdatadir)\" \ -DPKGLIBDIR=\"$(pkglibdir)\" $(am__append_1) METASOURCES = AUTO noinst_LTLIBRARIES = libxsvf.la noinst_HEADERS = xsvf.h libxsvf_la_SOURCES = xsvf.c MAINTAINERCLEANFILES = $(srcdir)/Makefile.in all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/common.mk $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/xsvf/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/xsvf/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_srcdir)/common.mk: $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libxsvf.la: $(libxsvf_la_OBJECTS) $(libxsvf_la_DEPENDENCIES) $(EXTRA_libxsvf_la_DEPENDENCIES) $(AM_V_CCLD)$(LINK) $(libxsvf_la_OBJECTS) $(libxsvf_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xsvf.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: openocd-0.7.0/src/xsvf/Makefile.am0000644000175000001440000000026612134336410013674 00000000000000include $(top_srcdir)/common.mk METASOURCES = AUTO noinst_LTLIBRARIES = libxsvf.la noinst_HEADERS = xsvf.h libxsvf_la_SOURCES = xsvf.c MAINTAINERCLEANFILES = $(srcdir)/Makefile.in openocd-0.7.0/src/xsvf/xsvf.c0000644000175000001440000006464312134336410013003 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * * Copyright (C) 2008 Peter Hettkamp * * peter.hettkamp@htp-tel.de * * * * Copyright (C) 2009 SoftPLC Corporation. http://softplc.com * * Dick Hollenbeck * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ /* The specification for SVF is available here: * http://www.asset-intertech.com/support/svf.pdf * Below, this document is refered to as the "SVF spec". * * The specification for XSVF is available here: * http://www.xilinx.com/support/documentation/application_notes/xapp503.pdf * Below, this document is refered to as the "XSVF spec". */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "xsvf.h" #include #include /* XSVF commands, from appendix B of xapp503.pdf */ #define XCOMPLETE 0x00 #define XTDOMASK 0x01 #define XSIR 0x02 #define XSDR 0x03 #define XRUNTEST 0x04 #define XREPEAT 0x07 #define XSDRSIZE 0x08 #define XSDRTDO 0x09 #define XSETSDRMASKS 0x0A #define XSDRINC 0x0B #define XSDRB 0x0C #define XSDRC 0x0D #define XSDRE 0x0E #define XSDRTDOB 0x0F #define XSDRTDOC 0x10 #define XSDRTDOE 0x11 #define XSTATE 0x12 #define XENDIR 0x13 #define XENDDR 0x14 #define XSIR2 0x15 #define XCOMMENT 0x16 #define XWAIT 0x17 /* XWAITSTATE is not in the xilinx XSVF spec, but the svf2xsvf.py translator * generates this. Arguably it is needed because the XSVF XRUNTEST command * was ill conceived and does not directly flow out of the SVF RUNTEST command. * This XWAITSTATE does map directly from the SVF RUNTEST command. */ #define XWAITSTATE 0x18 /* Lattice has extended the SVF file format, and Dick Hollenbeck's python based * SVF2XSVF converter supports these 3 additional XSVF opcodes, LCOUNT, LDELAY, LSDR. * Here is an example of usage of the 3 lattice opcode extensions: ! Set the maximum loop count to 25. LCOUNT 25; ! Step to DRPAUSE give 5 clocks and wait for 1.00e + 000 SEC. LDELAY DRPAUSE 5 TCK 1.00E-003 SEC; ! Test for the completed status. Match means pass. ! Loop back to LDELAY line if not match and loop count less than 25. LSDR 1 TDI (0) TDO (1); */ #define LCOUNT 0x19 #define LDELAY 0x1A #define LSDR 0x1B #define XTRST 0x1C /* XSVF valid state values for the XSTATE command, from appendix B of xapp503.pdf */ #define XSV_RESET 0x00 #define XSV_IDLE 0x01 #define XSV_DRSELECT 0x02 #define XSV_DRCAPTURE 0x03 #define XSV_DRSHIFT 0x04 #define XSV_DREXIT1 0x05 #define XSV_DRPAUSE 0x06 #define XSV_DREXIT2 0x07 #define XSV_DRUPDATE 0x08 #define XSV_IRSELECT 0x09 #define XSV_IRCAPTURE 0x0A #define XSV_IRSHIFT 0x0B #define XSV_IREXIT1 0x0C #define XSV_IRPAUSE 0x0D #define XSV_IREXIT2 0x0E #define XSV_IRUPDATE 0x0F /* arguments to XTRST */ #define XTRST_ON 0 #define XTRST_OFF 1 #define XTRST_Z 2 #define XTRST_ABSENT 3 #define XSTATE_MAX_PATH 12 static int xsvf_fd; /* map xsvf tap state to an openocd "tap_state_t" */ static tap_state_t xsvf_to_tap(int xsvf_state) { tap_state_t ret; switch (xsvf_state) { case XSV_RESET: ret = TAP_RESET; break; case XSV_IDLE: ret = TAP_IDLE; break; case XSV_DRSELECT: ret = TAP_DRSELECT; break; case XSV_DRCAPTURE: ret = TAP_DRCAPTURE; break; case XSV_DRSHIFT: ret = TAP_DRSHIFT; break; case XSV_DREXIT1: ret = TAP_DREXIT1; break; case XSV_DRPAUSE: ret = TAP_DRPAUSE; break; case XSV_DREXIT2: ret = TAP_DREXIT2; break; case XSV_DRUPDATE: ret = TAP_DRUPDATE; break; case XSV_IRSELECT: ret = TAP_IRSELECT; break; case XSV_IRCAPTURE: ret = TAP_IRCAPTURE; break; case XSV_IRSHIFT: ret = TAP_IRSHIFT; break; case XSV_IREXIT1: ret = TAP_IREXIT1; break; case XSV_IRPAUSE: ret = TAP_IRPAUSE; break; case XSV_IREXIT2: ret = TAP_IREXIT2; break; case XSV_IRUPDATE: ret = TAP_IRUPDATE; break; default: LOG_ERROR("UNKNOWN XSVF STATE 0x%02X", xsvf_state); exit(1); } return ret; } static int xsvf_read_buffer(int num_bits, int fd, uint8_t *buf) { int num_bytes; for (num_bytes = (num_bits + 7) / 8; num_bytes > 0; num_bytes--) { /* reverse the order of bytes as they are read sequentially from file */ if (read(fd, buf + num_bytes - 1, 1) < 0) return ERROR_XSVF_EOF; } return ERROR_OK; } COMMAND_HANDLER(handle_xsvf_command) { uint8_t *dr_out_buf = NULL; /* from host to device (TDI) */ uint8_t *dr_in_buf = NULL; /* from device to host (TDO) */ uint8_t *dr_in_mask = NULL; int xsdrsize = 0; int xruntest = 0; /* number of TCK cycles OR *microseconds */ int xrepeat = 0; /* number of retries */ tap_state_t xendir = TAP_IDLE; /* see page 8 of the SVF spec, initial *xendir to be TAP_IDLE */ tap_state_t xenddr = TAP_IDLE; uint8_t opcode; uint8_t uc = 0; long file_offset = 0; int loop_count = 0; tap_state_t loop_state = TAP_IDLE; int loop_clocks = 0; int loop_usecs = 0; int do_abort = 0; int unsupported = 0; int tdo_mismatch = 0; int result; int verbose = 1; bool collecting_path = false; tap_state_t path[XSTATE_MAX_PATH]; unsigned pathlen = 0; /* a flag telling whether to clock TCK during waits, * or simply sleep, controled by virt2 */ int runtest_requires_tck = 0; /* use NULL to indicate a "plain" xsvf file which accounts for * additional devices in the scan chain, otherwise the device * that should be affected */ struct jtag_tap *tap = NULL; if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; /* we mess with CMD_ARGV starting point below, snapshot filename here */ const char *filename = CMD_ARGV[1]; if (strcmp(CMD_ARGV[0], "plain") != 0) { tap = jtag_tap_by_string(CMD_ARGV[0]); if (!tap) { command_print(CMD_CTX, "Tap: %s unknown", CMD_ARGV[0]); return ERROR_FAIL; } } xsvf_fd = open(filename, O_RDONLY); if (xsvf_fd < 0) { command_print(CMD_CTX, "file \"%s\" not found", filename); return ERROR_FAIL; } /* if this argument is present, then interpret xruntest counts as TCK cycles rather than as *usecs */ if ((CMD_ARGC > 2) && (strcmp(CMD_ARGV[2], "virt2") == 0)) { runtest_requires_tck = 1; --CMD_ARGC; ++CMD_ARGV; } if ((CMD_ARGC > 2) && (strcmp(CMD_ARGV[2], "quiet") == 0)) verbose = 0; LOG_USER("xsvf processing file: \"%s\"", filename); while (read(xsvf_fd, &opcode, 1) > 0) { /* record the position of this opcode within the file */ file_offset = lseek(xsvf_fd, 0, SEEK_CUR) - 1; /* maybe collect another state for a pathmove(); * or terminate a path. */ if (collecting_path) { tap_state_t mystate; switch (opcode) { case XCOMMENT: /* ignore/show comments between XSTATE ops */ break; case XSTATE: /* try to collect another transition */ if (pathlen == XSTATE_MAX_PATH) { LOG_ERROR("XSVF: path too long"); do_abort = 1; break; } if (read(xsvf_fd, &uc, 1) < 0) { do_abort = 1; break; } mystate = xsvf_to_tap(uc); path[pathlen++] = mystate; LOG_DEBUG("XSTATE 0x%02X %s", uc, tap_state_name(mystate)); /* If path is incomplete, collect more */ if (!svf_tap_state_is_stable(mystate)) continue; /* Else execute the path transitions we've * collected so far. * * NOTE: Punting on the saved path is not * strictly correct, but we must to do this * unless jtag_add_pathmove() stops rejecting * paths containing RESET. This is probably * harmless, since there aren't many options * for going from a stable state to reset; * at the worst, we may issue extra clocks * once we get to RESET. */ if (mystate == TAP_RESET) { LOG_WARNING("XSVF: dodgey RESET"); path[0] = mystate; } /* FALL THROUGH */ default: /* Execute the path we collected * * NOTE: OpenOCD requires something that XSVF * doesn't: the last TAP state in the path * must be stable. In practice, tools that * create XSVF seem to follow that rule too. */ collecting_path = false; if (path[0] == TAP_RESET) jtag_add_tlr(); else jtag_add_pathmove(pathlen, path); result = jtag_execute_queue(); if (result != ERROR_OK) { LOG_ERROR("XSVF: pathmove error %d", result); do_abort = 1; break; } continue; } } switch (opcode) { case XCOMPLETE: LOG_DEBUG("XCOMPLETE"); result = jtag_execute_queue(); if (result != ERROR_OK) { tdo_mismatch = 1; break; } break; case XTDOMASK: LOG_DEBUG("XTDOMASK"); if (dr_in_mask && (xsvf_read_buffer(xsdrsize, xsvf_fd, dr_in_mask) != ERROR_OK)) do_abort = 1; break; case XRUNTEST: { uint8_t xruntest_buf[4]; if (read(xsvf_fd, xruntest_buf, 4) < 0) { do_abort = 1; break; } xruntest = be_to_h_u32(xruntest_buf); LOG_DEBUG("XRUNTEST %d 0x%08X", xruntest, xruntest); } break; case XREPEAT: { uint8_t myrepeat; if (read(xsvf_fd, &myrepeat, 1) < 0) do_abort = 1; else { xrepeat = myrepeat; LOG_DEBUG("XREPEAT %d", xrepeat); } } break; case XSDRSIZE: { uint8_t xsdrsize_buf[4]; if (read(xsvf_fd, xsdrsize_buf, 4) < 0) { do_abort = 1; break; } xsdrsize = be_to_h_u32(xsdrsize_buf); LOG_DEBUG("XSDRSIZE %d", xsdrsize); if (dr_out_buf) free(dr_out_buf); if (dr_in_buf) free(dr_in_buf); if (dr_in_mask) free(dr_in_mask); dr_out_buf = malloc((xsdrsize + 7) / 8); dr_in_buf = malloc((xsdrsize + 7) / 8); dr_in_mask = malloc((xsdrsize + 7) / 8); } break; case XSDR: /* these two are identical except for the dr_in_buf */ case XSDRTDO: { int limit = xrepeat; int matched = 0; int attempt; const char *op_name = (opcode == XSDR ? "XSDR" : "XSDRTDO"); if (xsvf_read_buffer(xsdrsize, xsvf_fd, dr_out_buf) != ERROR_OK) { do_abort = 1; break; } if (opcode == XSDRTDO) { if (xsvf_read_buffer(xsdrsize, xsvf_fd, dr_in_buf) != ERROR_OK) { do_abort = 1; break; } } if (limit < 1) limit = 1; LOG_DEBUG("%s %d", op_name, xsdrsize); for (attempt = 0; attempt < limit; ++attempt) { struct scan_field field; if (attempt > 0) { /* perform the XC9500 exception handling sequence shown in xapp067.pdf and * illustrated in psuedo code at end of this file. We start from state * DRPAUSE: * go to Exit2-DR * go to Shift-DR * go to Exit1-DR * go to Update-DR * go to Run-Test/Idle * * This sequence should be harmless for other devices, and it * will be skipped entirely if xrepeat is set to zero. */ static tap_state_t exception_path[] = { TAP_DREXIT2, TAP_DRSHIFT, TAP_DREXIT1, TAP_DRUPDATE, TAP_IDLE, }; jtag_add_pathmove(ARRAY_SIZE(exception_path), exception_path); if (verbose) LOG_USER("%s mismatch, xsdrsize=%d retry=%d", op_name, xsdrsize, attempt); } field.num_bits = xsdrsize; field.out_value = dr_out_buf; field.in_value = calloc(DIV_ROUND_UP(field.num_bits, 8), 1); if (tap == NULL) jtag_add_plain_dr_scan(field.num_bits, field.out_value, field.in_value, TAP_DRPAUSE); else jtag_add_dr_scan(tap, 1, &field, TAP_DRPAUSE); jtag_check_value_mask(&field, dr_in_buf, dr_in_mask); free(field.in_value); /* LOG_DEBUG("FLUSHING QUEUE"); */ result = jtag_execute_queue(); if (result == ERROR_OK) { matched = 1; break; } } if (!matched) { LOG_USER("%s mismatch", op_name); tdo_mismatch = 1; break; } /* See page 19 of XSVF spec regarding opcode "XSDR" */ if (xruntest) { result = svf_add_statemove(TAP_IDLE); if (result != ERROR_OK) return result; if (runtest_requires_tck) jtag_add_clocks(xruntest); else jtag_add_sleep(xruntest); } else if (xendir != TAP_DRPAUSE) { /* we are already in TAP_DRPAUSE */ result = svf_add_statemove(xenddr); if (result != ERROR_OK) return result; } } break; case XSETSDRMASKS: LOG_ERROR("unsupported XSETSDRMASKS"); unsupported = 1; break; case XSDRINC: LOG_ERROR("unsupported XSDRINC"); unsupported = 1; break; case XSDRB: LOG_ERROR("unsupported XSDRB"); unsupported = 1; break; case XSDRC: LOG_ERROR("unsupported XSDRC"); unsupported = 1; break; case XSDRE: LOG_ERROR("unsupported XSDRE"); unsupported = 1; break; case XSDRTDOB: LOG_ERROR("unsupported XSDRTDOB"); unsupported = 1; break; case XSDRTDOC: LOG_ERROR("unsupported XSDRTDOC"); unsupported = 1; break; case XSDRTDOE: LOG_ERROR("unsupported XSDRTDOE"); unsupported = 1; break; case XSTATE: { tap_state_t mystate; if (read(xsvf_fd, &uc, 1) < 0) { do_abort = 1; break; } mystate = xsvf_to_tap(uc); LOG_DEBUG("XSTATE 0x%02X %s", uc, tap_state_name(mystate)); if (mystate == TAP_INVALID) { LOG_ERROR("XSVF: bad XSTATE %02x", uc); do_abort = 1; break; } /* NOTE: the current state is SVF-stable! */ /* no change == NOP */ if (mystate == cmd_queue_cur_state && mystate != TAP_RESET) break; /* Hand off to SVF? */ if (svf_tap_state_is_stable(mystate)) { result = svf_add_statemove(mystate); if (result != ERROR_OK) unsupported = 1; break; } /* * A sequence of XSTATE transitions, each TAP * state adjacent to the previous one. Start * collecting them. */ collecting_path = true; pathlen = 1; path[0] = mystate; } break; case XENDIR: if (read(xsvf_fd, &uc, 1) < 0) { do_abort = 1; break; } /* see page 22 of XSVF spec */ if (uc == 0) xendir = TAP_IDLE; else if (uc == 1) xendir = TAP_IRPAUSE; else { LOG_ERROR("illegial XENDIR argument: 0x%02X", uc); unsupported = 1; break; } LOG_DEBUG("XENDIR 0x%02X %s", uc, tap_state_name(xendir)); break; case XENDDR: if (read(xsvf_fd, &uc, 1) < 0) { do_abort = 1; break; } /* see page 22 of XSVF spec */ if (uc == 0) xenddr = TAP_IDLE; else if (uc == 1) xenddr = TAP_DRPAUSE; else { LOG_ERROR("illegial XENDDR argument: 0x%02X", uc); unsupported = 1; break; } LOG_DEBUG("XENDDR %02X %s", uc, tap_state_name(xenddr)); break; case XSIR: case XSIR2: { uint8_t short_buf[2]; uint8_t *ir_buf; int bitcount; tap_state_t my_end_state = xruntest ? TAP_IDLE : xendir; if (opcode == XSIR) { /* one byte bitcount */ if (read(xsvf_fd, short_buf, 1) < 0) { do_abort = 1; break; } bitcount = short_buf[0]; LOG_DEBUG("XSIR %d", bitcount); } else { if (read(xsvf_fd, short_buf, 2) < 0) { do_abort = 1; break; } bitcount = be_to_h_u16(short_buf); LOG_DEBUG("XSIR2 %d", bitcount); } ir_buf = malloc((bitcount + 7) / 8); if (xsvf_read_buffer(bitcount, xsvf_fd, ir_buf) != ERROR_OK) do_abort = 1; else { struct scan_field field; field.num_bits = bitcount; field.out_value = ir_buf; field.in_value = NULL; if (tap == NULL) jtag_add_plain_ir_scan(field.num_bits, field.out_value, field.in_value, my_end_state); else jtag_add_ir_scan(tap, &field, my_end_state); if (xruntest) { if (runtest_requires_tck) jtag_add_clocks(xruntest); else jtag_add_sleep(xruntest); } /* Note that an -irmask of non-zero in your config file * can cause this to fail. Setting -irmask to zero cand work * around the problem. */ /* LOG_DEBUG("FLUSHING QUEUE"); */ result = jtag_execute_queue(); if (result != ERROR_OK) tdo_mismatch = 1; } free(ir_buf); } break; case XCOMMENT: { unsigned int ndx = 0; char comment[128]; do { if (read(xsvf_fd, &uc, 1) < 0) { do_abort = 1; break; } if (ndx < sizeof(comment)-1) comment[ndx++] = uc; } while (uc != 0); comment[sizeof(comment)-1] = 0; /* regardless, terminate */ if (verbose) LOG_USER("# %s", comment); } break; case XWAIT: { /* expected in stream: XWAIT */ uint8_t wait_local; uint8_t end; uint8_t delay_buf[4]; tap_state_t wait_state; tap_state_t end_state; int delay; if (read(xsvf_fd, &wait_local, 1) < 0 || read(xsvf_fd, &end, 1) < 0 || read(xsvf_fd, delay_buf, 4) < 0) { do_abort = 1; break; } wait_state = xsvf_to_tap(wait_local); end_state = xsvf_to_tap(end); delay = be_to_h_u32(delay_buf); LOG_DEBUG("XWAIT %s %s usecs:%d", tap_state_name( wait_state), tap_state_name(end_state), delay); if (runtest_requires_tck && wait_state == TAP_IDLE) jtag_add_runtest(delay, end_state); else { /* FIXME handle statemove errors ... */ result = svf_add_statemove(wait_state); if (result != ERROR_OK) return result; jtag_add_sleep(delay); result = svf_add_statemove(end_state); if (result != ERROR_OK) return result; } } break; case XWAITSTATE: { /* expected in stream: * XWAITSTATE * */ uint8_t clock_buf[4]; uint8_t usecs_buf[4]; uint8_t wait_local; uint8_t end; tap_state_t wait_state; tap_state_t end_state; int clock_count; int usecs; if (read(xsvf_fd, &wait_local, 1) < 0 || read(xsvf_fd, &end, 1) < 0 || read(xsvf_fd, clock_buf, 4) < 0 || read(xsvf_fd, usecs_buf, 4) < 0) { do_abort = 1; break; } wait_state = xsvf_to_tap(wait_local); end_state = xsvf_to_tap(end); clock_count = be_to_h_u32(clock_buf); usecs = be_to_h_u32(usecs_buf); LOG_DEBUG("XWAITSTATE %s %s clocks:%i usecs:%i", tap_state_name(wait_state), tap_state_name(end_state), clock_count, usecs); /* the following states are 'stable', meaning that they have a transition * in the state diagram back to themselves. This is necessary because we will * be issuing a number of clocks in this state. This set of allowed states is also * determined by the SVF RUNTEST command's allowed states. */ if (!svf_tap_state_is_stable(wait_state)) { LOG_ERROR("illegal XWAITSTATE wait_state: \"%s\"", tap_state_name(wait_state)); unsupported = 1; /* REVISIT "break" so we won't run? */ } /* FIXME handle statemove errors ... */ result = svf_add_statemove(wait_state); if (result != ERROR_OK) return result; jtag_add_clocks(clock_count); jtag_add_sleep(usecs); result = svf_add_statemove(end_state); if (result != ERROR_OK) return result; } break; case LCOUNT: { /* expected in stream: * LCOUNT */ uint8_t count_buf[4]; if (read(xsvf_fd, count_buf, 4) < 0) { do_abort = 1; break; } loop_count = be_to_h_u32(count_buf); LOG_DEBUG("LCOUNT %d", loop_count); } break; case LDELAY: { /* expected in stream: * LDELAY */ uint8_t state; uint8_t clock_buf[4]; uint8_t usecs_buf[4]; if (read(xsvf_fd, &state, 1) < 0 || read(xsvf_fd, clock_buf, 4) < 0 || read(xsvf_fd, usecs_buf, 4) < 0) { do_abort = 1; break; } /* NOTE: loop_state must be stable! */ loop_state = xsvf_to_tap(state); loop_clocks = be_to_h_u32(clock_buf); loop_usecs = be_to_h_u32(usecs_buf); LOG_DEBUG("LDELAY %s clocks:%d usecs:%d", tap_state_name( loop_state), loop_clocks, loop_usecs); } break; /* LSDR is more like XSDRTDO than it is like XSDR. It uses LDELAY which * comes with clocks !AND! sleep requirements. */ case LSDR: { int limit = loop_count; int matched = 0; int attempt; LOG_DEBUG("LSDR"); if (xsvf_read_buffer(xsdrsize, xsvf_fd, dr_out_buf) != ERROR_OK || xsvf_read_buffer(xsdrsize, xsvf_fd, dr_in_buf) != ERROR_OK) { do_abort = 1; break; } if (limit < 1) limit = 1; for (attempt = 0; attempt < limit; ++attempt) { struct scan_field field; result = svf_add_statemove(loop_state); if (result != ERROR_OK) return result; jtag_add_clocks(loop_clocks); jtag_add_sleep(loop_usecs); field.num_bits = xsdrsize; field.out_value = dr_out_buf; field.in_value = calloc(DIV_ROUND_UP(field.num_bits, 8), 1); if (attempt > 0 && verbose) LOG_USER("LSDR retry %d", attempt); if (tap == NULL) jtag_add_plain_dr_scan(field.num_bits, field.out_value, field.in_value, TAP_DRPAUSE); else jtag_add_dr_scan(tap, 1, &field, TAP_DRPAUSE); jtag_check_value_mask(&field, dr_in_buf, dr_in_mask); free(field.in_value); /* LOG_DEBUG("FLUSHING QUEUE"); */ result = jtag_execute_queue(); if (result == ERROR_OK) { matched = 1; break; } } if (!matched) { LOG_USER("LSDR mismatch"); tdo_mismatch = 1; break; } } break; case XTRST: { uint8_t trst_mode; if (read(xsvf_fd, &trst_mode, 1) < 0) { do_abort = 1; break; } switch (trst_mode) { case XTRST_ON: jtag_add_reset(1, 0); break; case XTRST_OFF: case XTRST_Z: jtag_add_reset(0, 0); break; case XTRST_ABSENT: break; default: LOG_ERROR("XTRST mode argument (0x%02X) out of range", trst_mode); do_abort = 1; } } break; default: LOG_ERROR("unknown xsvf command (0x%02X)", uc); unsupported = 1; } if (do_abort || unsupported || tdo_mismatch) { LOG_DEBUG("xsvf failed, setting taps to reasonable state"); /* upon error, return the TAPs to a reasonable state */ result = svf_add_statemove(TAP_IDLE); if (result != ERROR_OK) return result; result = jtag_execute_queue(); if (result != ERROR_OK) return result; break; } } if (tdo_mismatch) { command_print(CMD_CTX, "TDO mismatch, somewhere near offset %lu in xsvf file, aborting", file_offset); return ERROR_FAIL; } if (unsupported) { off_t offset = lseek(xsvf_fd, 0, SEEK_CUR) - 1; command_print(CMD_CTX, "unsupported xsvf command (0x%02X) at offset %jd, aborting", uc, (intmax_t)offset); return ERROR_FAIL; } if (do_abort) { command_print(CMD_CTX, "premature end of xsvf file detected, aborting"); return ERROR_FAIL; } if (dr_out_buf) free(dr_out_buf); if (dr_in_buf) free(dr_in_buf); if (dr_in_mask) free(dr_in_mask); close(xsvf_fd); command_print(CMD_CTX, "XSVF file programmed successfully"); return ERROR_OK; } static const struct command_registration xsvf_command_handlers[] = { { .name = "xsvf", .handler = handle_xsvf_command, .mode = COMMAND_EXEC, .help = "Runs a XSVF file. If 'virt2' is given, xruntest " "counts are interpreted as TCK cycles rather than " "as microseconds. Without the 'quiet' option, all " "comments, retries, and mismatches will be reported.", .usage = "(tapname|'plain') filename ['virt2'] ['quiet']", }, COMMAND_REGISTRATION_DONE }; int xsvf_register_commands(struct command_context *cmd_ctx) { return register_commands(cmd_ctx, NULL, xsvf_command_handlers); } /* PSUEDO-Code from Xilinx Appnote XAPP067.pdf : the following pseudo code clarifies the intent of the xrepeat support.The flow given is for the entire processing of an SVF file, not an XSVF file. No idea if this is just for the XC9500/XL/XV devices or all Xilinx parts. "Pseudo-Code Algorithm for SVF-Based ISP" 1. Go to Test-Logic-Reset state 2. Go to Run-Test Idle state 3. Read SVF record 4. if SIR record then go to Shift-IR state Scan in 5. else if SDR record then set to 0 store as store as 6. go to Shift-DR state scan in if < current TDO value > is specified then if < current TDO value > does not equal then if < repeat count > > 32 then LOG ERROR go to Run-Test Idle state go to Step 3 end if go to Pause-DR go to Exit2-DR go to Shift-DR go to Exit1-DR go to Update-DR go to Run-Test/Idle increment by 1 pause microseconds go to Step 6) end if else go to Run-Test Idle state go to Step 3 endif else if RUNTEST record then pause tester for < TCK value > microseconds store as end if */ openocd-0.7.0/src/Makefile.am0000644000175000001440000000565612134336410012716 00000000000000include $(top_srcdir)/common.mk SUBDIRS = \ jtag \ helper \ target \ transport \ flash \ svf \ xsvf \ pld \ server \ rtos lib_LTLIBRARIES = libopenocd.la bin_PROGRAMS = openocd MAINFILE = main.c openocd_SOURCES = $(MAINFILE) openocd_LDADD = libopenocd.la if INTERNAL_JIMTCL openocd_LDADD += $(top_builddir)/jimtcl/libjim.a else openocd_LDADD += -ljim endif if ULINK openocd_LDADD += -lm endif libopenocd_la_SOURCES = \ hello.c \ openocd.c \ startup_tcl.c noinst_HEADERS = \ hello.h \ openocd.h libopenocd_la_CPPFLAGS = -DPKGBLDDATE=\"`date +%F-%R`\" # banner output includes RELSTR appended to $VERSION from the configure script # guess-rev.sh returns either a repository version ID or "-snapshot" if RELEASE libopenocd_la_CPPFLAGS += -DRELSTR=\"\" libopenocd_la_CPPFLAGS += -DGITVERSION=\"\" else libopenocd_la_CPPFLAGS += -DRELSTR=\"`$(top_srcdir)/guess-rev.sh $(top_srcdir)`\" libopenocd_la_CPPFLAGS += -DGITVERSION=\"`cd $(top_srcdir) && git describe`\" endif # add default CPPFLAGS libopenocd_la_CPPFLAGS += $(AM_CPPFLAGS) $(CPPFLAGS) # the library search path. libopenocd_la_LDFLAGS = $(all_libraries) if IS_MINGW MINGWLDADD = -lws2_32 else MINGWLDADD = endif if FT2232_LIBFTDI FTDI2232LIB = -lftdi -lusb else if USB_BLASTER_LIBFTDI FTDI2232LIB = -lftdi -lusb else if PRESTO_LIBFTDI FTDI2232LIB = -lftdi -lusb else FTDI2232LIB = endif endif endif LIBUSB = if USE_LIBUSB1 LIBUSB += -lusb-1.0 endif if USE_LIBUSB0 LIBUSB += -lusb endif libopenocd_la_LIBADD = \ $(top_builddir)/src/xsvf/libxsvf.la \ $(top_builddir)/src/svf/libsvf.la \ $(top_builddir)/src/pld/libpld.la \ $(top_builddir)/src/jtag/libjtag.la \ $(top_builddir)/src/transport/libtransport.la \ $(top_builddir)/src/flash/libflash.la \ $(top_builddir)/src/target/libtarget.la \ $(top_builddir)/src/server/libserver.la \ $(top_builddir)/src/rtos/librtos.la \ $(top_builddir)/src/helper/libhelper.la \ $(FTDI2232LIB) $(MINGWLDADD) $(LIBUSB) STARTUP_TCL_SRCS = \ $(srcdir)/helper/startup.tcl \ $(srcdir)/jtag/startup.tcl \ $(srcdir)/target/startup.tcl \ $(srcdir)/flash/startup.tcl \ $(srcdir)/server/startup.tcl EXTRA_DIST = $(STARTUP_TCL_SRCS) BUILT_SOURCES = startup.tcl startup.tcl: $(STARTUP_TCL_SRCS) cat $^ > $@ BIN2C = $(top_builddir)/src/helper/bin2char$(EXEEXT_FOR_BUILD) # Convert .tcl to cfile startup_tcl.c: startup.tcl $(BIN2C) $(BIN2C) openocd_startup_tcl < $< > $@ || rm -f $@ # add startup_tcl.c to make clean list CLEANFILES = startup.tcl startup_tcl.c # we do not want generated file in the dist dist-hook: rm -f $(distdir)/startup_tcl.c MAINTAINERCLEANFILES = $(srcdir)/Makefile.in # The "quick" target builds executables & reinstalls the executables # Primary use: developer types to quicken the edit/compile/debug # cycle. by not requiring a "full build and full install". Note the # assumption is: You are only rebuilding the EXE.... and everything # else is/was previously installed. # # use at your own risk quick: all install-binPROGRAMS openocd-0.7.0/src/openocd.h0000644000175000001440000000362612134336410012455 00000000000000/*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Copyright (C) 2009 by Zachary T Welch * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef OPENOCD_H #define OPENOCD_H /** * Different applications can define this entry point to override * the default openocd main function. On most systems, this will be * defined in src/openocd.c. * @param argc normally passed from main() * @param argv normally passed from main() * @returns return code for main() */ int openocd_main(int argc, char *argv[]); /** provides a hard-coded command environment setup */ extern const char openocd_startup_tcl[]; #endif openocd-0.7.0/src/hello.h0000644000175000001440000000321112134336410012117 00000000000000/*************************************************************************** * Copyright (C) 2009 Zachary T Welch * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 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. * ***************************************************************************/ #ifndef OPENOCD_HELLO_H #define OPENOCD_HELLO_H struct command_registration; /** * Export the registration for the hello command group, so it can be * embedded in example drivers. */ extern const struct command_registration hello_command_handlers[]; #endif /* OPENOCD_HELLO_H */ openocd-0.7.0/configure.ac0000644000175000001440000012322512141407070012351 00000000000000AC_PREREQ(2.60) AC_INIT([openocd], [0.7.0], [OpenOCD Mailing List ]) AC_CONFIG_SRCDIR([src/openocd.c]) m4_include([config_subdir.m4])dnl AM_INIT_AUTOMAKE([-Wall -Wno-portability dist-bzip2 dist-zip]) AM_MAINTAINER_MODE AC_CONFIG_HEADERS([config.h]) AH_BOTTOM([ #include #include #include ]) AC_LANG_C AC_PROG_CC AC_PROG_CC_C99 AM_PROG_CC_C_O AC_PROG_RANLIB dnl disable checks for C++, Fortran and GNU Java Compiler m4_defun([_LT_AC_LANG_CXX_CONFIG], [:]) m4_defun([_LT_AC_LANG_F77_CONFIG], [:]) m4_defun([_LT_AC_LANG_GCJ_CONFIG], [:]) AC_DISABLE_SHARED AC_PROG_LIBTOOL AC_SUBST([LIBTOOL_DEPS]) dnl configure checks required for Jim files (these are obsolete w/ C99) AC_C_CONST AC_TYPE_LONG_LONG_INT AC_SEARCH_LIBS([ioperm], [ioperm]) AC_SEARCH_LIBS([dlopen], [dl]) AC_CHECK_HEADERS([sys/socket.h]) AC_CHECK_HEADERS([arpa/inet.h], [], [], [dnl #include #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_SYS_SOCKET_H # include #endif ]) AC_CHECK_HEADERS([elf.h]) AC_CHECK_HEADERS([dirent.h]) AC_CHECK_HEADERS([fcntl.h]) AC_CHECK_HEADERS([ifaddrs.h], [], [], [dnl #include #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_SYS_SOCKET_H # include #endif ]) AC_CHECK_HEADERS([malloc.h]) AC_CHECK_HEADERS([netdb.h]) AC_CHECK_HEADERS([netinet/in.h], [], [], [dnl #include #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_SYS_SOCKET_H # include #endif ]) AC_CHECK_HEADERS([netinet/tcp.h], [], [], [dnl #include #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_SYS_SOCKET_H # include #endif ]) AC_CHECK_HEADERS([pthread.h]) AC_CHECK_HEADERS([strings.h]) AC_CHECK_HEADERS([sys/ioctl.h]) AC_CHECK_HEADERS([sys/param.h]) AC_CHECK_HEADERS([sys/poll.h]) AC_CHECK_HEADERS([sys/select.h]) AC_CHECK_HEADERS([sys/stat.h]) AC_CHECK_HEADERS([sys/time.h]) AC_CHECK_HEADERS([sys/types.h]) AC_CHECK_HEADERS([unistd.h]) AC_CHECK_HEADERS([net/if.h], [], [], [dnl #include #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_SYS_SOCKET_H # include #endif ]) AC_HEADER_ASSERT AC_HEADER_STDBOOL AC_HEADER_TIME AC_C_BIGENDIAN AC_CHECK_FUNCS([strndup]) AC_CHECK_FUNCS([strnlen]) AC_CHECK_FUNCS([gettimeofday]) AC_CHECK_FUNCS([usleep]) AC_CHECK_FUNCS([vasprintf]) build_bitbang=no build_bitq=no is_cygwin=no is_mingw=no is_win32=no is_darwin=no # guess-rev.sh only exists in the repository, not in the released archives AC_MSG_CHECKING([whether to build a release]) if test -x $srcdir/guess-rev.sh ; then build_release=no else build_release=yes fi AC_MSG_RESULT([$build_release]) # We are not *ALWAYS* being installed in the standard place. # We may be installed in a "tool-build" specific location. # Normally with other packages - as part of a tool distro. # Thus - we should search that 'libdir' also. # # And - if we are being installed there - the odds are # The libraries unique to what we are are there too. # # Expand nd deal with NONE - just like configure will do later OCDprefix=$prefix OCDxprefix=$exec_prefix test x"$OCDprefix" = xNONE && OCDprefix=$ac_default_prefix # Let make expand exec_prefix. test x"$OCDxprefix" = xNONE && OCDxprefix="$OCDprefix" # what matters is the "exec-prefix" if test "$OCDxprefix" != "$ac_default_prefix" then # We are installing in a non-standard place # Nonstandard --prefix and/or --exec-prefix # We have an override of some sort. # use build specific install library dir LDFLAGS="$LDFLAGS -L$OCDxprefix/lib" # RPATH becomes an issue on Linux only if test $host_os = linux-gnu || test $host_os = linux ; then LDFLAGS="$LDFLAGS -Wl,-rpath,$OCDxprefix/lib" fi # The "INCDIR" is also usable CFLAGS="$CFLAGS -I$includedir" fi AC_ARG_WITH(ftd2xx, AS_HELP_STRING([--with-ftd2xx=],[This option has been removed.]), [ # Option Given. cat << __EOF__ The option: --with-ftd2xx= has been removed. On Linux, the new option is: --with-ftd2xx-linux-tardir=/path/to/files Where is the path the the directory where the "tar.gz" file from FTDICHIP.COM was unpacked, for example: --with-ftd2xx-linux-tardir=${HOME}/libftd2xx0.4.16 On Cygwin/MingW32, the new option is: --with-ftd2xx-win32-zipdir=/path/to/files Where is the path to the directory where the "zip" file from FTDICHIP.COM was unpacked, for example: --with-ftd2xx-win32-zipdir=${HOME}/ftd2xx.cdm.files __EOF__ AC_MSG_ERROR([Sorry Cannot continue]) ], [true]) #======================================== # FTD2XXX support comes in 4 forms. # (1) win32 - via a zip file # (2) linux - via a tar file # (3) linux/cygwin/mingw - via libftdi # (4) darwin - installed under /usr/local # # In case (1) and (2) we need to know where the package was unpacked. AC_ARG_WITH(ftd2xx-win32-zipdir, AS_HELP_STRING([--with-ftd2xx-win32-zipdir],[Where (CYGWIN/MINGW) the zip file from ftdichip.com was unpacked (default=search)]), [ # option present if test -d $with_ftd2xx_win32_zipdir then with_ftd2xx_win32_zipdir=`cd $with_ftd2xx_win32_zipdir && pwd` AC_MSG_NOTICE([Using: ftdichip.com library: $with_ftd2xx_win32_zipdir]) else AC_MSG_ERROR([Parameter to --with-ftd2xx-win32-zipdir is not a dir: $with_ftd2xx_win32_zipdir]) fi ], [true]) AC_ARG_WITH(ftd2xx-linux-tardir, AS_HELP_STRING([--with-ftd2xx-linux-tardir], [Where (Linux/Unix) the tar file from ftdichip.com was unpacked (default=search)]), [ # Option present if test $is_win32 = yes ; then AC_MSG_ERROR([The option: --with-ftd2xx-linux-tardir is only usable on linux]) fi if test -d $with_ftd2xx_linux_tardir then with_ftd2xx_linux_tardir=`cd $with_ftd2xx_linux_tardir && pwd` AC_MSG_NOTICE([Using: ftdichip.com library: $with_ftd2xx_linux_tardir]) else AC_MSG_ERROR([Parameter to --with-ftd2xx-linux-tardir is not a dir: $with_ftd2xx_linux_tardir]) fi ], [true]) AC_ARG_WITH(ftd2xx-lib, AS_HELP_STRING([--with-ftd2xx-lib], [Use static or shared ftd2xx libs (default=static)]), [ case "$withval" in static) with_ftd2xx_lib=$withval ;; shared) with_ftd2xx_lib=$withval ;; *) AC_MSG_ERROR([Option: --with-ftd2xx-lib=static or --with-ftd2xx-lib=shared not, $withval]) ;; esac ], [ # Default is static - it is simpler :-( with_ftd2xx_lib=static ]) AC_ARG_ENABLE([doxygen-html], AS_HELP_STRING([--disable-doxygen-html], [Disable building Doxygen manual as HTML.]), [doxygen_as_html=$enableval], [doxygen_as_html=yes]) AC_SUBST([doxygen_as_html]) AC_MSG_CHECKING([whether to build Doxygen as HTML]) AC_MSG_RESULT([$doxygen_as_html]) AC_ARG_ENABLE([doxygen-pdf], AS_HELP_STRING([--enable-doxygen-pdf], [Enable building Doxygen manual as PDF.]), [doxygen_as_pdf=$enableval], [doxygen_as_pdf=no]) AC_SUBST([doxygen_as_pdf]) AC_MSG_CHECKING([whether to build Doxygen as PDF]) AC_MSG_RESULT([$doxygen_as_pdf]) AC_ARG_ENABLE([gccwarnings], AS_HELP_STRING([--disable-gccwarnings], [Disable compiler warnings]), [gcc_warnings=$enableval], [gcc_warnings=yes]) AC_ARG_ENABLE([wextra], AS_HELP_STRING([--disable-wextra], [Disable extra compiler warnings]), [gcc_wextra=$enableval], [gcc_wextra=$gcc_warnings]) AC_ARG_ENABLE([werror], AS_HELP_STRING([--disable-werror], [Do not treat warnings as errors]), [gcc_werror=$enableval], [gcc_werror=$gcc_warnings]) # set default verbose options, overridden by following options debug_jtag_io=no debug_usb_io=no debug_usb_comms=no AC_ARG_ENABLE([verbose], AS_HELP_STRING([--enable-verbose], [Enable verbose JTAG I/O messages (for debugging).]), [ debug_jtag_io=$enableval debug_usb_io=$enableval debug_usb_comms=$enableval ], []) AC_ARG_ENABLE([verbose_jtag_io], AS_HELP_STRING([--enable-verbose-jtag-io], [Enable verbose JTAG I/O messages (for debugging).]), [debug_jtag_io=$enableval], []) AC_ARG_ENABLE([verbose_usb_io], AS_HELP_STRING([--enable-verbose-usb-io], [Enable verbose USB I/O messages (for debugging)]), [debug_usb_io=$enableval], []) AC_ARG_ENABLE([verbose_usb_comms], AS_HELP_STRING([--enable-verbose-usb-comms], [Enable verbose USB communication messages (for debugging)]), [debug_usb_comms=$enableval], []) AC_MSG_CHECKING([whether to enable verbose JTAG I/O messages]); AC_MSG_RESULT([$debug_jtag_io]) if test $debug_jtag_io = yes; then AC_DEFINE([_DEBUG_JTAG_IO_],[1], [Print verbose JTAG I/O messages]) fi AC_MSG_CHECKING([whether to enable verbose USB I/O messages]); AC_MSG_RESULT([$debug_usb_io]) if test $debug_usb_io = yes; then AC_DEFINE([_DEBUG_USB_IO_],[1], [Print verbose USB I/O messages]) fi AC_MSG_CHECKING([whether to enable verbose USB communication messages]); AC_MSG_RESULT([$debug_usb_comms]) if test $debug_usb_comms = yes; then AC_DEFINE([_DEBUG_USB_COMMS_],[1], [Print verbose USB communication messages]) fi debug_malloc=no AC_ARG_ENABLE([malloc_logging], AS_HELP_STRING([--enable-malloc-logging], [Include free space in logging messages (requires malloc.h).]), [debug_malloc=$enableval], []) AC_MSG_CHECKING([whether to enable malloc free space logging]); AC_MSG_RESULT([$debug_malloc]) if test $debug_malloc = yes; then AC_DEFINE([_DEBUG_FREE_SPACE_],[1], [Include malloc free space in logging]) fi AC_ARG_ENABLE([dummy], AS_HELP_STRING([--enable-dummy], [Enable building the dummy port driver]), [build_dummy=$enableval], [build_dummy=no]) AC_ARG_ENABLE([parport], AS_HELP_STRING([--enable-parport], [Enable building the pc parallel port driver]), [build_parport=$enableval], [build_parport=no]) AC_ARG_ENABLE([parport_ppdev], AS_HELP_STRING([--disable-parport-ppdev], [Disable use of ppdev (/dev/parportN) for parport (for x86 only)]), [parport_use_ppdev=$enableval], [parport_use_ppdev=yes]) AC_ARG_ENABLE([parport_giveio], AS_HELP_STRING([--enable-parport-giveio], [Enable use of giveio for parport (for CygWin only)]), [parport_use_giveio=$enableval], [parport_use_giveio=]) AC_ARG_ENABLE([ft2232_libftdi], AS_HELP_STRING([--enable-ft2232_libftdi], [Enable building support for FT2232 based devices using the libftdi driver, opensource alternate of FTD2XX]), [build_ft2232_libftdi=$enableval], [build_ft2232_libftdi=no]) AC_ARG_ENABLE([ft2232_ftd2xx], AS_HELP_STRING([--enable-ft2232_ftd2xx], [Enable building support for FT2232 based devices using the FTD2XX driver from ftdichip.com]), [build_ft2232_ftd2xx=$enableval], [build_ft2232_ftd2xx=no]) AC_ARG_ENABLE([ftdi], AS_HELP_STRING([--enable-ftdi], [Enable building support for the MPSSE mode of FTDI based devices, using libusb-1.0 in asynchronous mode]), [build_ftdi=$enableval], [build_ftdi=no]) AC_ARG_ENABLE([usb_blaster_libftdi], AS_HELP_STRING([--enable-usb_blaster_libftdi], [Enable building support for the Altera USB-Blaster using the libftdi driver, opensource alternate of FTD2XX]), [build_usb_blaster_libftdi=$enableval], [build_usb_blaster_libftdi=no]) AC_ARG_ENABLE([usb_blaster_ftd2xx], AS_HELP_STRING([--enable-usb_blaster_ftd2xx], [Enable building support for the Altera USB-Blaster using the FTD2XX driver from ftdichip.com]), [build_usb_blaster_ftd2xx=$enableval], [build_usb_blaster_ftd2xx=no]) AC_ARG_ENABLE([amtjtagaccel], AS_HELP_STRING([--enable-amtjtagaccel], [Enable building the Amontec JTAG-Accelerator driver]), [build_amtjtagaccel=$enableval], [build_amtjtagaccel=no]) AC_ARG_ENABLE([zy1000_master], AS_HELP_STRING([--enable-zy1000-master], [Use ZY1000 JTAG master registers]), [build_zy1000_master=$enableval], [build_zy1000_master=no]) AC_ARG_ENABLE([zy1000], AS_HELP_STRING([--enable-zy1000], [Enable ZY1000 interface]), [build_zy1000=$enableval], [build_zy1000=no]) AC_ARG_ENABLE([ioutil], AS_HELP_STRING([--enable-ioutil], [Enable ioutil functions - useful for standalone OpenOCD implementations]), [build_ioutil=$enableval], [build_ioutil=no]) case "${host_cpu}" in arm*) AC_ARG_ENABLE([ep93xx], AS_HELP_STRING([--enable-ep93xx], [Enable building support for EP93xx based SBCs]), [build_ep93xx=$enableval], [build_ep93xx=no]) AC_ARG_ENABLE([at91rm9200], AS_HELP_STRING([--enable-at91rm9200], [Enable building support for AT91RM9200 based SBCs]), [build_at91rm9200=$enableval], [build_at91rm9200=no]) ;; *) build_ep93xx=no build_at91rm9200=no ;; esac AC_ARG_ENABLE([gw16012], AS_HELP_STRING([--enable-gw16012], [Enable building support for the Gateworks GW16012 JTAG Programmer]), [build_gw16012=$enableval], [build_gw16012=no]) AC_ARG_ENABLE([presto_libftdi], AS_HELP_STRING([--enable-presto_libftdi], [Enable building support for ASIX Presto Programmer using the libftdi driver]), [build_presto_libftdi=$enableval], [build_presto_libftdi=no]) AC_ARG_ENABLE([presto_ftd2xx], AS_HELP_STRING([--enable-presto_ftd2xx], [Enable building support for ASIX Presto Programmer using the FTD2XX driver]), [build_presto_ftd2xx=$enableval], [build_presto_ftd2xx=no]) AC_ARG_ENABLE([usbprog], AS_HELP_STRING([--enable-usbprog], [Enable building support for the usbprog JTAG Programmer]), [build_usbprog=$enableval], [build_usbprog=no]) AC_ARG_ENABLE([oocd_trace], AS_HELP_STRING([--enable-oocd_trace], [Enable building support for some prototype OpenOCD+trace ETM capture hardware]), [build_oocd_trace=$enableval], [build_oocd_trace=no]) AC_ARG_ENABLE([jlink], AS_HELP_STRING([--enable-jlink], [Enable building support for the Segger J-Link JTAG Programmer]), [build_jlink=$enableval], [build_jlink=no]) AC_ARG_ENABLE([vsllink], AS_HELP_STRING([--enable-vsllink], [Enable building support for the Versaloon-Link JTAG Programmer]), [build_vsllink=$enableval], [build_vsllink=no]) AC_ARG_ENABLE([rlink], AS_HELP_STRING([--enable-rlink], [Enable building support for the Raisonance RLink JTAG Programmer]), [build_rlink=$enableval], [build_rlink=no]) AC_ARG_ENABLE([ulink], AS_HELP_STRING([--enable-ulink], [Enable building support for the Keil ULINK JTAG Programmer]), [build_ulink=$enableval], [build_ulink=no]) AC_ARG_ENABLE([arm-jtag-ew], AS_HELP_STRING([--enable-arm-jtag-ew], [Enable building support for the Olimex ARM-JTAG-EW Programmer]), [build_armjtagew=$enableval], [build_armjtagew=no]) AC_ARG_ENABLE([buspirate], AS_HELP_STRING([--enable-buspirate], [Enable building support for the Buspirate]), [build_buspirate=$enableval], [build_buspirate=no]) AC_ARG_ENABLE([stlink], AS_HELP_STRING([--enable-stlink], [Enable building support for the ST-Link JTAG Programmer]), [build_hladapter_stlink=$enableval], [build_hladapter_stlink=no]) AC_ARG_ENABLE([ti-icdi], AS_HELP_STRING([--enable-ti-icdi], [Enable building support for the TI ICDI JTAG Programmer]), [build_hladapter_icdi=$enableval], [build_hladapter_icdi=no]) AC_ARG_ENABLE([osbdm], AS_HELP_STRING([--enable-osbdm], [Enable building support for the OSBDM (JTAG only) Programmer]), [build_osbdm=$enableval], [build_osbdm=no]) AC_ARG_ENABLE([opendous], AS_HELP_STRING([--enable-opendous], [Enable building support for the estick/opendous JTAG Programmer]), [build_opendous=$enableval], [build_opendous=no]) AC_ARG_ENABLE([sysfsgpio], AS_HELP_STRING([--enable-sysfsgpio], [Enable building support for programming driven via sysfs gpios.]), [build_sysfsgpio=$enableval], [build_sysfsgpio=no]) AC_ARG_ENABLE([minidriver_dummy], AS_HELP_STRING([--enable-minidriver-dummy], [Enable the dummy minidriver.]), [build_minidriver_dummy=$enableval], [build_minidriver_dummy=no]) AC_ARG_ENABLE([internal-jimtcl], AS_HELP_STRING([--disable-internal-jimtcl], [Disable building internal jimtcl]), [use_internal_jimtcl=$enableval], [use_internal_jimtcl=yes]) AC_ARG_ENABLE([libusb0], AS_HELP_STRING([--enable-libusb0], [Use libusb-0.1 library for USB JTAG devices]), [check_libusb0=$enableval], [check_libusb0=no]) build_minidriver=no AC_MSG_CHECKING([whether to enable ZY1000 minidriver]) if test $build_zy1000 = yes; then if test $build_minidriver = yes; then AC_MSG_ERROR([Multiple minidriver options have been enabled.]) fi AC_DEFINE([HAVE_JTAG_MINIDRIVER_H], [1], [Define to 1 if you have the header file.]) build_minidriver=yes fi AC_MSG_RESULT([$build_zy1000]) AC_ARG_ENABLE([remote-bitbang], AS_HELP_STRING([--enable-remote-bitbang], [Enable building support for the Remote Bitbang jtag driver]), [build_remote_bitbang=$enableval], [build_remote_bitbang=no]) AC_MSG_CHECKING([whether to enable dummy minidriver]) if test $build_minidriver_dummy = yes; then if test $build_minidriver = yes; then AC_MSG_ERROR([Multiple minidriver options have been enabled.]) fi build_minidriver=yes AC_DEFINE([BUILD_MINIDRIVER_DUMMY], [1], [Use the dummy minidriver.]) AC_DEFINE([HAVE_JTAG_MINIDRIVER_H], [1], [Define to 1 if you have the header file.]) fi AC_MSG_RESULT([$build_minidriver_dummy]) AC_MSG_CHECKING([whether standard drivers can be built]) if test "$build_minidriver" = yes; then AC_MSG_RESULT([no]) AC_MSG_WARN([Using the minidriver disables all other drivers.]) sleep 2 else AC_MSG_RESULT([yes]) fi case "${host_cpu}" in i?86|x86*) ;; *) if test x$parport_use_ppdev = xno; then AC_MSG_WARN([--disable-parport-ppdev is not supported by the host CPU]) fi parport_use_ppdev=yes ;; esac case $host in *-cygwin*) is_win32=yes parport_use_ppdev=no AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [[return __MINGW32__;]])], [is_mingw=yes],[is_mingw=no]) if test $is_mingw = yes; then AC_DEFINE([IS_MINGW], [1], [1 if building for MinGW.]) if test x$parport_use_giveio = xno; then AC_MSG_WARN([--disable-parport-giveio is not supported by MinGW32 hosts]) fi parport_use_giveio=yes is_cygwin=no else is_cygwin=yes AC_DEFINE([IS_CYGWIN], [1], [1 if building for Cygwin.]) # sys/io.h needed under cygwin for parport access if test $build_parport = yes; then AC_CHECK_HEADERS([sys/io.h],[],AC_MSG_ERROR([Please install the cygwin ioperm package])) fi fi AC_DEFINE([IS_WIN32], [1], [1 if building for Win32.]) AC_DEFINE([IS_DARWIN], [0], [0 if not building for Darwin.]) ;; *-mingw*) is_mingw=yes is_win32=yes parport_use_ppdev=no if test x$parport_use_giveio = xno; then AC_MSG_WARN([--disable-parport-giveio is not supported by MinGW32 hosts]) fi parport_use_giveio=yes if test x$build_buspirate = xyes; then AC_MSG_ERROR([buspirate currently not supported by MinGW32 hosts]) fi CFLAGS="$CFLAGS -D__USE_MINGW_ANSI_STDIO" AC_DEFINE([IS_MINGW], [1], [1 if building for MinGW.]) AC_DEFINE([IS_WIN32], [1], [1 if building for Win32.]) AC_DEFINE([IS_DARWIN], [0], [0 if not building for Darwin.]) ;; *darwin*) is_darwin=yes if test x$parport_use_giveio = xyes; then AC_MSG_WARN([--enable-parport-giveio cannot be used by Darwin hosts]) fi parport_use_giveio=no AC_DEFINE([IS_CYGWIN], [0], [0 if not building for Cygwin.]) AC_DEFINE([IS_WIN32], [0], [0 if not building for Win32.]) AC_DEFINE([IS_DARWIN], [1], [1 if building for Darwin.]) ;; *) if test x$parport_use_giveio = xyes; then AC_MSG_WARN([--enable-parport-giveio cannot be used by ]$host[ hosts]) fi parport_use_giveio=no AC_DEFINE([IS_CYGWIN], [0], [0 if not building for Cygwin.]) AC_DEFINE([IS_WIN32], [0], [0 if not building for Win32.]) AC_DEFINE([IS_DARWIN], [0], [0 if not building for Darwin.]) ;; esac if test $build_parport = yes; then build_bitbang=yes AC_DEFINE([BUILD_PARPORT], [1], [1 if you want parport.]) else AC_DEFINE([BUILD_PARPORT], [0], [0 if you don't want parport.]) fi if test $build_dummy = yes; then build_bitbang=yes AC_DEFINE([BUILD_DUMMY], [1], [1 if you want dummy driver.]) else AC_DEFINE([BUILD_DUMMY], [0], [0 if you don't want dummy driver.]) fi if test $build_ep93xx = yes; then build_bitbang=yes AC_DEFINE([BUILD_EP93XX], [1], [1 if you want ep93xx.]) else AC_DEFINE([BUILD_EP93XX], [0], [0 if you don't want ep93xx.]) fi if test $build_zy1000 = yes; then AC_DEFINE([BUILD_ZY1000], [1], [1 if you want ZY1000.]) else AC_DEFINE([BUILD_ZY1000], [0], [0 if you don't want ZY1000.]) fi if test $build_zy1000_master = yes; then AC_DEFINE([BUILD_ZY1000_MASTER], [1], [1 if you want ZY1000 JTAG master registers.]) else AC_DEFINE([BUILD_ZY1000_MASTER], [0], [0 if you don't want ZY1000 JTAG master registers.]) fi if test $build_at91rm9200 = yes; then build_bitbang=yes AC_DEFINE([BUILD_AT91RM9200], [1], [1 if you want at91rm9200.]) else AC_DEFINE([BUILD_AT91RM9200], [0], [0 if you don't want at91rm9200.]) fi if test x$parport_use_ppdev = xyes; then AC_DEFINE([PARPORT_USE_PPDEV], [1], [1 if you want parport to use ppdev.]) else AC_DEFINE([PARPORT_USE_PPDEV], [0], [0 if you don't want parport to use ppdev.]) fi if test x$parport_use_giveio = xyes; then AC_DEFINE([PARPORT_USE_GIVEIO], [1], [1 if you want parport to use giveio.]) else AC_DEFINE([PARPORT_USE_GIVEIO], [0], [0 if you don't want parport to use giveio.]) fi if test $build_bitbang = yes; then AC_DEFINE([BUILD_BITBANG], [1], [1 if you want a bitbang interface.]) else AC_DEFINE([BUILD_BITBANG], [0], [0 if you don't want a bitbang interface.]) fi if test $build_ft2232_libftdi = yes; then AC_DEFINE([BUILD_FT2232_LIBFTDI], [1], [1 if you want libftdi ft2232.]) else AC_DEFINE([BUILD_FT2232_LIBFTDI], [0], [0 if you don't want libftdi ft2232.]) fi if test $build_ft2232_ftd2xx = yes; then AC_DEFINE([BUILD_FT2232_FTD2XX], [1], [1 if you want ftd2xx ft2232.]) else AC_DEFINE([BUILD_FT2232_FTD2XX], [0], [0 if you don't want ftd2xx ft2232.]) fi if test $build_ftdi = yes; then AC_DEFINE([BUILD_FTDI], [1], [1 if you want ftdi.]) else AC_DEFINE([BUILD_FTDI], [0], [0 if you don't want ftdi.]) fi if test $build_usb_blaster_libftdi = yes; then build_bitbang=yes AC_DEFINE([BUILD_USB_BLASTER_LIBFTDI], [1], [1 if you want libftdi usb_blaster.]) else AC_DEFINE([BUILD_USB_BLASTER_LIBFTDI], [0], [0 if you don't want libftdi usb_blaster.]) fi if test $build_usb_blaster_ftd2xx = yes; then build_bitbang=yes AC_DEFINE([BUILD_USB_BLASTER_FTD2XX], [1], [1 if you want ftd2xx usb_blaster.]) else AC_DEFINE([BUILD_USB_BLASTER_FTD2XX], [0], [0 if you don't want ftd2xx usb_blaster.]) fi if test $build_amtjtagaccel = yes; then AC_DEFINE([BUILD_AMTJTAGACCEL], [1], [1 if you want the Amontec JTAG-Accelerator driver.]) else AC_DEFINE([BUILD_AMTJTAGACCEL], [0], [0 if you don't want the Amontec JTAG-Accelerator driver.]) fi if test $build_gw16012 = yes; then AC_DEFINE([BUILD_GW16012], [1], [1 if you want the Gateworks GW16012 driver.]) else AC_DEFINE([BUILD_GW16012], [0], [0 if you don't want the Gateworks GW16012 driver.]) fi if test $build_presto_libftdi = yes; then build_bitq=yes AC_DEFINE([BUILD_PRESTO_LIBFTDI], [1], [1 if you want the ASIX PRESTO driver using libftdi.]) else AC_DEFINE([BUILD_PRESTO_LIBFTDI], [0], [0 if you don't want the ASIX PRESTO driver using libftdi.]) fi if test $build_presto_ftd2xx = yes; then build_bitq=yes AC_DEFINE([BUILD_PRESTO_FTD2XX], [1], [1 if you want the ASIX PRESTO driver using FTD2XX.]) else AC_DEFINE([BUILD_PRESTO_FTD2XX], [0], [0 if you don't want the ASIX PRESTO driver using FTD2XX.]) fi if test $build_bitq = yes; then AC_DEFINE([BUILD_BITQ], [1], [1 if you want a bitq interface.]) else AC_DEFINE([BUILD_BITQ], [0], [0 if you don't want a bitq interface.]) fi if test $build_usbprog = yes; then AC_DEFINE([BUILD_USBPROG], [1], [1 if you want the usbprog JTAG driver.]) else AC_DEFINE([BUILD_USBPROG], [0], [0 if you don't want the usbprog JTAG driver.]) fi if test $build_oocd_trace = yes; then AC_DEFINE([BUILD_OOCD_TRACE], [1], [1 if you want the OpenOCD+trace ETM capture driver.]) else AC_DEFINE([BUILD_OOCD_TRACE], [0], [0 if you don't want the OpenOCD+trace ETM capture driver.]) fi if test $build_jlink = yes; then AC_DEFINE([BUILD_JLINK], [1], [1 if you want the J-Link JTAG driver.]) else AC_DEFINE([BUILD_JLINK], [0], [0 if you don't want the J-Link JTAG driver.]) fi if test $build_vsllink = yes; then AC_DEFINE([BUILD_VSLLINK], [1], [1 if you want the Versaloon-Link JTAG driver.]) else AC_DEFINE([BUILD_VSLLINK], [0], [0 if you don't want the Versaloon-Link JTAG driver.]) fi if test $build_rlink = yes; then AC_DEFINE([BUILD_RLINK], [1], [1 if you want the RLink JTAG driver.]) else AC_DEFINE([BUILD_RLINK], [0], [0 if you don't want the RLink JTAG driver.]) fi if test $build_ulink = yes; then AC_DEFINE([BUILD_ULINK], [1], [1 if you want the ULINK JTAG driver.]) else AC_DEFINE([BUILD_ULINK], [0], [0 if you don't want the ULINK JTAG driver.]) fi if test $build_armjtagew = yes; then AC_DEFINE([BUILD_ARMJTAGEW], [1], [1 if you want the ARM-JTAG-EW JTAG driver.]) else AC_DEFINE([BUILD_ARMJTAGEW], [0], [0 if you don't want the ARM-JTAG-EW JTAG driver.]) fi if test $build_buspirate = yes; then AC_DEFINE([BUILD_BUSPIRATE], [1], [1 if you want the Buspirate JTAG driver.]) else AC_DEFINE([BUILD_BUSPIRATE], [0], [0 if you don't want the Buspirate JTAG driver.]) fi if test $build_hladapter_stlink = yes -o $build_hladapter_icdi = yes; then AC_DEFINE([BUILD_HLADAPTER], [1], [1 if you want the High Level JTAG driver.]) else AC_DEFINE([BUILD_HLADAPTER], [0], [0 if you don't want the High Level JTAG driver.]) fi if test $build_osbdm = yes; then AC_DEFINE([BUILD_OSBDM], [1], [1 if you want the OSBDM driver.]) else AC_DEFINE([BUILD_OSBDM], [0], [0 if you don't want the OSBDM driver.]) fi if test $build_opendous = yes; then AC_DEFINE([BUILD_OPENDOUS], [1], [1 if you want the estick/opendous JTAG driver.]) else AC_DEFINE([BUILD_OPENDOUS], [0], [0 if you don't want the estick/opendous JTAG driver.]) fi if test "$use_internal_jimtcl" = yes; then if test -f "$srcdir/jimtcl/configure.ac"; then AX_CONFIG_SUBDIR_OPTION([jimtcl], [--disable-install-jim]) else AC_MSG_ERROR([jimtcl not found, run git submodule init and git submodule update.]) fi fi if test $build_remote_bitbang = yes; then build_bitbang=yes AC_DEFINE([BUILD_REMOTE_BITBANG], [1], [1 if you want the Remote Bitbang JTAG driver.]) else AC_DEFINE([BUILD_REMOTE_BITBANG], [0], [0 if you don't want the Remote Bitbang JTAG driver.]) fi if test $build_sysfsgpio = yes; then build_bitbang=yes AC_DEFINE([BUILD_SYSFSGPIO], [1], [1 if you want the SysfsGPIO driver.]) else AC_DEFINE([BUILD_SYSFSGPIO], [0], [0 if you don't want SysfsGPIO driver.]) fi #-- Deal with MingW/Cygwin FTD2XX issues if test $is_win32 = yes; then if test "${with_ftd2xx_linux_tardir+set}" = set then AC_MSG_ERROR([The option: with_ftd2xx_linux_tardir is for LINUX only.]) fi if test $build_ft2232_ftd2xx = yes -o $build_presto_ftd2xx = yes -o $build_usb_blaster_ftd2xx = yes ; then AC_MSG_CHECKING([for ftd2xx.lib exists (win32)]) # if we are given a zipdir... if test "${with_ftd2xx_win32_zipdir+set}" = set then # Set the CFLAGS for "ftd2xx.h" f=$with_ftd2xx_win32_zipdir/ftd2xx.h if test ! -f $f ; then AC_MSG_ERROR([File: $f cannot be found]) fi CFLAGS="$CFLAGS -I$with_ftd2xx_win32_zipdir" # And calculate the LDFLAGS for the machine case "$host_cpu" in i?86|x86_32) LDFLAGS="$LDFLAGS -L$with_ftd2xx_win32_zipdir/i386" LIBS="$LIBS -lftd2xx" f=$with_ftd2xx_win32_zipdir/i386/ftd2xx.lib ;; amd64|x86_64) LDFLAGS="$LDFLAGS -L$with_ftd2xx_win32_zipdir/amd64" LIBS="$LIBS -lftd2xx" f=$with_ftd2xx_win32_zipdir/amd64/ftd2xx.lib ;; *) AC_MSG_ERROR([Unknown Win32 host cpu: $host_cpu]) ;; esac if test ! -f $f ; then AC_MSG_ERROR([Library: $f not found]) fi else LIBS="$LIBS -lftd2xx" AC_MSG_WARN([ASSUMPTION: The (win32) FTDICHIP.COM files: ftd2xx.h and ftd2xx.lib are in a proper place]) fi fi fi # win32 if test $is_darwin = yes ; then if test "${with_ftd2xx_win32_zipdir+set}" = set then AC_MSG_ERROR([The option: --with-ftd2xx-win32-zipdir is for win32 only]) fi if test "${with_ftd2xx_linux_tardir+set}" = set then AC_MSG_ERROR([The option: with_ftd2xx_linux_tardir is for LINUX only.]) fi if test $build_ft2232_ftd2xx = yes -o $build_presto_ftd2xx = yes -o $build_usb_blaster_ftd2xx = yes ; then AC_MSG_CHECKING([for libftd2xx.a (darwin)]) if test ! -f /usr/local/include/ftd2xx.h ; then AC_MSG_ERROR([ftd2xx library from FTDICHIP.com seems to be missing, cannot find: /usr/local/include/ftd2xx.h]) fi CFLAGS="$CFLAGS -I/usr/local/include" LDFLAGS="$LDFLAGS -L/usr/local/lib" LIBS="$LIBS -lftd2xx" AC_MSG_RESULT([-L/usr/local/lib -lftd2xx]) fi fi # darwin if test $is_win32 = no && test $is_darwin = no ; then if test "${with_ftd2xx_win32_zipdir+set}" = set then AC_MSG_ERROR([The option: --with-ftd2xx-win32-zipdir is for win32 only]) fi if test $build_ft2232_ftd2xx = yes -o $build_presto_ftd2xx = yes -o $build_usb_blaster_ftd2xx = yes ; then # Must be linux if test $host_os != linux-gnu && test $host_os != linux ; then AC_MSG_ERROR([The (linux) ftd2xx library from FTDICHIP.com is linux only. Try --enable-ft2232-libftdi instead]) fi # Are we given a TAR directory? if test "${with_ftd2xx_linux_tardir+set}" = set then AC_MSG_CHECKING([uninstalled ftd2xx distribution]) # The .H file is simple.. FTD2XX_H=$with_ftd2xx_linux_tardir/ftd2xx.h if test ! -f "${FTD2XX_H}"; then AC_MSG_ERROR([Option: --with-ftd2xx-linux-tardir appears wrong, cannot find: ${FTD2XX_H}]) fi CFLAGS="$CFLAGS -I$with_ftd2xx_linux_tardir" if test $with_ftd2xx_lib = shared; then FTD2XX_LDFLAGS="-L$with_ftd2xx_linux_tardir" FTD2XX_LIB="-lftd2xx" else # Test #1 - v1.0.x case "$host_cpu" in i?86|x86_32) dir=build/i386;; amd64|x86_64) dir=build/x86_64;; *) dir=none;; esac if test -f "$with_ftd2xx_linux_tardir/$dir/libftd2xx.a"; then FTD2XX_LDFLAGS="-L$with_ftd2xx_linux_tardir/$dir" # Also needs -lrt FTD2XX_LIB="-lftd2xx -lrt" else # Test Number2. # Grr.. perhaps it exists as a version number? FTD2XX_LIB="$with_ftd2xx_linux_tardir/static_lib/libftd2xx.a.*.*.*" count=`ls ${FTD2XX_LIB} | wc -l` if test $count -gt 1 ; then AC_MSG_ERROR([Multiple libftd2xx.a files found in: $with_ftd2xx_linux_tardir/static_lib sorry cannot handle this yet]) fi if test $count -ne 1 ; then AC_MSG_ERROR([Not found: $f, option: --with-ftd2xx-linux-tardir appears to be wrong]) fi # Because the "-l" rules do not understand version numbers... # we will just stuff the absolute path onto the LIBS variable FTD2XX_LIB="`ls ${FTD2XX_LIB}` -lpthread" FTD2XX_LDFLAGS="" fi fi LDFLAGS="${LDFLAGS} ${FTD2XX_LDFLAGS}" LIBS="${FTD2XX_LIB} ${LIBS}" AC_MSG_RESULT([${FTD2XX_LDFLAGS} ${FTD2XX_LIB}]) else AC_CHECK_HEADER([ftd2xx.h],[],[ AC_MSG_ERROR([You seem to be missing the FTD2xx driver header file.]) ]) AC_SEARCH_LIBS([FT_GetLibraryVersion],[ftd2xx],,[ AC_MSG_ERROR([You appear to be missing the FTD2xx driver library.]) ],[]) fi fi fi # linux if test $build_ft2232_ftd2xx = yes -o $build_presto_ftd2xx = yes -o $build_usb_blaster_ftd2xx = yes ; then # Before we go any further - make sure we can *BUILD* and *RUN* # a simple app with the "ftd2xx.lib" file - in what ever form we where given # We should be able to compile, link and run this test program now AC_MSG_CHECKING([whether ftd2xx library works]) # # Save the LDFLAGS for later.. LDFLAGS_SAVE=$LDFLAGS CFLAGS_SAVE=$CFLAGS _LDFLAGS=`eval echo $LDFLAGS` _CFLAGS=`eval echo $CFLAGS` LDFLAGS=$_LDFLAGS CFLAGS=$_CFLAGS AC_RUN_IFELSE([AC_LANG_PROGRAM([[ #include "confdefs.h" #if IS_WIN32 #include "windows.h" #endif #include #include ]], [[ DWORD x; FT_GetLibraryVersion( &x ); ]])], [ AC_MSG_RESULT([Success!]) ], [ AC_MSG_ERROR([Cannot build & run test program using ftd2xx.lib]) ], [ AC_MSG_RESULT([Skipping as we are cross-compiling]) ]) AC_MSG_CHECKING([for ftd2xx highspeed device support]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include "confdefs.h" #if IS_WIN32 #include "windows.h" #endif #include #include DWORD x = FT_DEVICE_4232H; ]], [])], [ AC_DEFINE([BUILD_FT2232_HIGHSPEED], [1], [Support FT2232H/FT4232HS with FTD2XX or libftdi.]) build_ft2232_highspeed=yes ], [ build_ft2232_highspeed=no ]) AC_MSG_RESULT([$build_ft2232_highspeed]) if test $build_ft2232_highspeed = no; then AC_MSG_WARN([You need a newer FTD2XX driver (version 2.04.16 or later).]) fi AC_MSG_CHECKING([for ftd2xx FT232H device support]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include "confdefs.h" #if IS_WIN32 #include "windows.h" #endif #include #include DWORD x = FT_DEVICE_232H; ]], [])], [ AC_DEFINE([HAS_ENUM_FT232H], [1], [Support FT232H with FTD2XX or libftdi.]) has_enum_ft232h=yes ], [ has_enum_ft232h=no ]) AC_MSG_RESULT([$has_enum_ft232h]) if test $has_enum_ft232h = no; then AC_MSG_WARN([You need a newer FTD2XX driver (version 2.08.12 or later).]) fi LDFLAGS=$LDFLAGS_SAVE CFLAGS=$CFLAGS_SAVE fi if test $build_ft2232_libftdi = yes ; then # We assume: the package is preinstalled in the proper place # these present as 2 libraries.. LIBS="$LIBS -lftdi -lusb" # # Try to build a small program. AC_MSG_CHECKING([Build & Link with libftdi...]) LDFLAGS_SAVE=$LDFLAGS CFLAGS_SAVE=$CFLAGS _LDFLAGS=`eval echo $LDFLAGS` _CFLAGS=`eval echo $CFLAGS` LDFLAGS=$_LDFLAGS CFLAGS=$_CFLAGS AC_RUN_IFELSE([AC_LANG_PROGRAM([[ #include #include ]], [[ struct ftdi_context *p; p = ftdi_new(); if( p != NULL ){ return 0; } else { fprintf( stderr, "calling ftdi_new() failed\n"); return 1; } ]])], [ AC_MSG_RESULT([Success]) ], [ AC_MSG_ERROR([Cannot build & run test program using libftdi]) ], [ AC_MSG_RESULT([Skipping as we are cross-compiling]) ]) AC_MSG_CHECKING([for libftdi highspeed device support]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include #include ]], [[ enum ftdi_chip_type x = TYPE_2232H; ]])], [ AC_DEFINE([BUILD_FT2232_HIGHSPEED], [1], [Support FT2232H/FT4232HS with FTD2XX or libftdi.]) build_ft2232_highspeed=yes ], [ build_ft2232_highspeed=no ]) AC_MSG_RESULT([$build_ft2232_highspeed]) if test $build_ft2232_highspeed = no; then AC_MSG_WARN([You need a newer libftdi version (0.16 or later).]) fi AC_MSG_CHECKING([for libftdi FT232H device support]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include #include ]], [[ enum ftdi_chip_type x = TYPE_232H; ]])], [ AC_DEFINE([HAS_ENUM_FT232H], [1], [Support FT232H with FTD2XX or libftdi.]) has_enum_ft232h=yes ], [ has_enum_ft232h=no ]) AC_MSG_RESULT([$has_enum_ft232h]) if test $has_enum_ft232h = no; then AC_MSG_WARN([You need a newer libftdi version (0.20 or later).]) fi # Restore the 'unexpanded ldflags' LDFLAGS=$LDFLAGS_SAVE CFLAGS=$CFLAGS_SAVE fi # check for usb.h when a driver will require it build_usb=no if test $build_vsllink = yes -o $build_usbprog = yes -o \ $build_rlink = yes -o $build_ulink = yes -o $build_armjtagew = yes then build_usb=yes fi # Check for libusb1 ported drivers. build_usb_ng=no if test $build_jlink = yes -o $build_hladapter_stlink = yes -o $build_osbdm = yes -o \ $build_opendous = yes -o $build_ftdi = yes -o $build_hladapter_icdi = yes then build_usb_ng=yes fi # check for libusb library if necessary use_libusb0=no use_libusb1=no if test $build_usb = yes -o $build_usb_ng = yes; then if test $check_libusb0 = no -a $build_usb_ng = yes; then AC_CHECK_HEADER([libusb-1.0/libusb.h], [AC_DEFINE(HAVE_LIBUSB1, 1, [Define if you have libusb-1.0]) check_libusb0=no use_libusb1=yes ], [ check_libusb0=yes use_libusb1=no ]) fi if test $check_libusb0 = yes -o $build_usb = yes; then AC_CHECK_HEADERS([usb.h], [use_libusb0=yes], [AC_MSG_ERROR([libusb or libusb-1.0 are required to build some OpenOCD driver(s)])]) fi fi AM_CONDITIONAL([RELEASE], [test $build_release = yes]) AM_CONDITIONAL([PARPORT], [test $build_parport = yes]) AM_CONDITIONAL([DUMMY], [test $build_dummy = yes]) AM_CONDITIONAL([GIVEIO], [test x$parport_use_giveio = xyes]) AM_CONDITIONAL([EP93XX], [test $build_ep93xx = yes]) AM_CONDITIONAL([ZY1000], [test $build_zy1000 = yes]) AM_CONDITIONAL([ZY1000_MASTER], [test $build_zy1000_master = yes]) AM_CONDITIONAL([IOUTIL], [test $build_ioutil = yes]) AM_CONDITIONAL([AT91RM9200], [test $build_at91rm9200 = yes]) AM_CONDITIONAL([BITBANG], [test $build_bitbang = yes]) AM_CONDITIONAL([FT2232_LIBFTDI], [test $build_ft2232_libftdi = yes]) AM_CONDITIONAL([FT2232_DRIVER], [test $build_ft2232_ftd2xx = yes -o $build_ft2232_libftdi = yes]) AM_CONDITIONAL([FTDI_DRIVER], [test $build_ftdi = yes]) AM_CONDITIONAL([USB_BLASTER_LIBFTDI], [test $build_usb_blaster_libftdi = yes]) AM_CONDITIONAL([USB_BLASTER_DRIVER], [test $build_usb_blaster_ftd2xx = yes -o $build_usb_blaster_libftdi = yes]) AM_CONDITIONAL([AMTJTAGACCEL], [test $build_amtjtagaccel = yes]) AM_CONDITIONAL([GW16012], [test $build_gw16012 = yes]) AM_CONDITIONAL([PRESTO_LIBFTDI], [test $build_presto_libftdi = yes]) AM_CONDITIONAL([PRESTO_DRIVER], [test $build_presto_ftd2xx = yes -o $build_presto_libftdi = yes]) AM_CONDITIONAL([USBPROG], [test $build_usbprog = yes]) AM_CONDITIONAL([OOCD_TRACE], [test $build_oocd_trace = yes]) AM_CONDITIONAL([JLINK], [test $build_jlink = yes]) AM_CONDITIONAL([VSLLINK], [test $build_vsllink = yes]) AM_CONDITIONAL([RLINK], [test $build_rlink = yes]) AM_CONDITIONAL([ULINK], [test $build_ulink = yes]) AM_CONDITIONAL([ARMJTAGEW], [test $build_armjtagew = yes]) AM_CONDITIONAL([REMOTE_BITBANG], [test $build_remote_bitbang = yes]) AM_CONDITIONAL([BUSPIRATE], [test $build_buspirate = yes]) AM_CONDITIONAL([HLADAPTER], [test $build_hladapter_stlink = yes -o $build_hladapter_icdi = yes]) AM_CONDITIONAL([OSBDM], [test $build_osbdm = yes]) AM_CONDITIONAL([OPENDOUS], [test $build_opendous = yes]) AM_CONDITIONAL([SYSFSGPIO], [test $build_sysfsgpio = yes]) AM_CONDITIONAL([USB], [test $build_usb = yes]) AM_CONDITIONAL([USB_NG], [test $build_usb_ng = yes]) AM_CONDITIONAL([USE_LIBUSB0], [test $use_libusb0 = yes]) AM_CONDITIONAL([USE_LIBUSB1], [test $use_libusb1 = yes]) AM_CONDITIONAL([IS_CYGWIN], [test $is_cygwin = yes]) AM_CONDITIONAL([IS_MINGW], [test $is_mingw = ye]s) AM_CONDITIONAL([IS_WIN32], [test $is_win32 = ye]s) AM_CONDITIONAL([IS_DARWIN], [test $is_darwin = ye]s) AM_CONDITIONAL([BITQ], [test $build_bitq = yes]) AM_CONDITIONAL([MINIDRIVER], [test $build_minidriver = ye]s) AM_CONDITIONAL([MINIDRIVER_DUMMY], [test $build_minidriver_dummy = yes]) AM_CONDITIONAL([INTERNAL_JIMTCL], [test $use_internal_jimtcl = yes]) # Look for environ alternatives. Possibility #1: is environ in unistd.h or stdlib.h? AC_MSG_CHECKING([for environ in unistd.h and stdlib.h]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #define _GNU_SOURCE #include #include ]], [[char **ep = environ;]] )], [ AC_MSG_RESULT([yes]) has_environ=yes ], [ AC_MSG_RESULT([no]) # Possibility #2: can environ be found in an available library? AC_MSG_CHECKING([for extern environ]) AC_LINK_IFELSE([AC_LANG_PROGRAM([[ extern char **environ; ]], [[char **ep = environ;]] )], [ AC_DEFINE(NEED_ENVIRON_EXTERN, [1], [Must declare 'environ' to use it.]) has_environ=yes ], [ has_environ=no ]) AC_MSG_RESULT([${has_environ}]) ]) if test "${has_environ}" != "yes" ; then AC_MSG_FAILURE([Could not find 'environ' in unistd.h or available libraries.]) fi AC_DEFINE([_GNU_SOURCE],[1],[Use GNU C library extensions (e.g. stdndup).]) # set default gcc warnings GCC_WARNINGS="-Wall -Wstrict-prototypes -Wformat-security -Wshadow" if test "${gcc_wextra}" = yes; then GCC_WARNINGS="${GCC_WARNINGS} -Wextra -Wno-unused-parameter" GCC_WARNINGS="${GCC_WARNINGS} -Wbad-function-cast" GCC_WARNINGS="${GCC_WARNINGS} -Wcast-align" GCC_WARNINGS="${GCC_WARNINGS} -Wredundant-decls" fi if test "${gcc_werror}" = yes; then GCC_WARNINGS="${GCC_WARNINGS} -Werror" fi # overide default gcc cflags if test $gcc_warnings = yes; then CFLAGS="$CFLAGS $GCC_WARNINGS" fi # Setup for compiling build tools AC_MSG_CHECKING([for a C compiler for build tools]) if test $cross_compiling = yes; then AC_CHECK_PROGS(CC_FOR_BUILD, gcc cc) CFLAGS_FOR_BUILD="-g -O2 $GCC_WARNINGS" else CC_FOR_BUILD=$CC CFLAGS_FOR_BUILD=$CFLAGS fi AC_MSG_RESULT([$CC_FOR_BUILD]) AC_SUBST([CC_FOR_BUILD]) AC_SUBST([CFLAGS_FOR_BUILD]) AC_MSG_CHECKING([for suffix of executable build tools]) if test $cross_compiling = yes; then cat >conftest.c <<\_______EOF int main () { exit (0); } _______EOF for i in .exe ""; do compile="$CC_FOR_BUILD conftest.c -o conftest$i" if AC_TRY_EVAL(compile); then if (./conftest) 2>&AC_FD_CC; then EXEEXT_FOR_BUILD=$i break fi fi done rm -f conftest* if test "${EXEEXT_FOR_BUILD+set}" != set; then AC_MSG_ERROR([Cannot determine suffix of executable build tools]) fi else EXEEXT_FOR_BUILD=$EXEEXT fi AC_MSG_RESULT([$EXEEXT_FOR_BUILD]) AC_SUBST([EXEEXT_FOR_BUILD]) AC_CONFIG_FILES([ Makefile src/Makefile src/helper/Makefile src/jtag/Makefile src/jtag/drivers/Makefile src/jtag/hla/Makefile src/transport/Makefile src/xsvf/Makefile src/svf/Makefile src/target/Makefile src/rtos/Makefile src/server/Makefile src/flash/Makefile src/flash/nor/Makefile src/flash/nand/Makefile src/pld/Makefile doc/Makefile ]) AC_OUTPUT openocd-0.7.0/COPYING0000644000175000001440000004313512134336410011120 00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 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 Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. openocd-0.7.0/ChangeLog0000644000175000001440000344406512141414414011650 000000000000002013-05-05 Freddie Chopin * : The openocd-0.7.0 release. Change-Id: I08157f47ac056e6d2089119dd2d6cbab11b521e8 Signed-off-by: Freddie Chopin 2013-04-28 Freddie Chopin * : doc: Update list of interfaces, targets and boards Change-Id: If9481e061f09a37f9ee3c461a1a0ce4d382a9a0d Signed-off-by: Freddie Chopin Reviewed-on: http://openocd.zylin.com/1366 Tested-by: jenkins Reviewed-by: Spencer Oliver 2013-05-02 Spencer Oliver * : cfg: remove whitespace Change-Id: I20edbb50efc03711195102f4c6dc8bcfaf043d44 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/1374 Tested-by: jenkins Reviewed-by: Peter Stuge 2013-04-28 Freddie Chopin * : Restore -dev suffix Change-Id: I26f49e02d228b59533237607fa8307ecc627409e Signed-off-by: Freddie Chopin 2013-02-01 Spencer Oliver * : target: rename cortex_a8 to cortex_a Rename cortex_a8 target to use a more correct cortex_a name. This also adds a deprecated_name var so that older scripts issue a warning to update the target name. cfg files have also been updated to the new target name. Change-Id: I0eb1429c9281321efeb444b27a662a941a2ab67f Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/1130 Tested-by: jenkins Reviewed-by: Freddie Chopin 2013-04-20 Freddie Chopin * : Mention "lpc4300" (with "lpc1800" alias) flash drivers in manual Change-Id: I0bb28910b2c07b1ca5bd644e0d88b931d585d3e7 Signed-off-by: Freddie Chopin Reviewed-on: http://openocd.zylin.com/1352 Tested-by: jenkins 2013-04-22 Christopher Kilgour * : kinetis: fix "SF1" parts to limit FlexRAM usage Ensure FlexRAM usage is limited to half the FlexRAM size when programming. Assume the FlexNVM sector size is equal to half the FlexRAM. Fix sector erase checking which had an error introduced when the kinetis_ftfx_command( ) signature was changed. Change-Id: I88edd9c7d4a4ba474cad7b00052feaeedfa8ced8 Signed-off-by: Christopher Kilgour Reviewed-on: http://openocd.zylin.com/1358 Tested-by: jenkins Reviewed-by: Freddie Chopin 2013-04-23 Spencer Oliver * : arm: fix arm reg regression Seems commit fc2abe63fd3cea7497da7be2955d333bd3f800b9 caused a regression in that the arm reg cmd no longer worked. The issue was caused because we changed the value of ARM_MODE_THREAD which was being checked in arm_init_arch_info. Change-Id: Id571d4ab336d1b0e2b93363147af245d24b65ca5 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/1362 Tested-by: jenkins Reviewed-by: Luca Bruno Reviewed-by: Freddie Chopin 2013-04-23 Hsiangkai Wang * : gdb server: Fix bug. Parse 'M' packet error. The format of 'M' packet is 'M addr,length:XX...'. The data follows ':' immediately. No need to '+2' to SEPARATOR in unhexify(), because SEPARATOR points to data correctly. Change-Id: I15b5758b540816cc727752e7bf68cd45e623f603 Signed-off-by: Hsiangkai Wang Reviewed-on: http://openocd.zylin.com/1360 Tested-by: jenkins Reviewed-by: Spencer Oliver Reviewed-by: Freddie Chopin 2013-04-21 Freddie Chopin * : Restore -dev suffix Change-Id: I3662c5993766a76d6dd62b919c56cc059c4e50d4 Signed-off-by: Freddie Chopin 2013-04-20 Freddie Chopin * : Add "lpc1800" alias for "lpc4300" flash driver Change-Id: I6d2bb9105cc778bd1d21580022529d684c3b21b0 Signed-off-by: Freddie Chopin Reviewed-on: http://openocd.zylin.com/1351 Tested-by: jenkins 2013-04-20 Freddie Chopin * : Improve HACKING Reword info about creating SSH key - it's not required to add it to Github account. Mention adding created SSH key to Gerrit account - without this step it's not possible to access Gerrit in further steps. Change-Id: Ibd81521fbe47d4b4beae0b77cdc9d939fd3ee20c Signed-off-by: Freddie Chopin Reviewed-on: http://openocd.zylin.com/1350 Tested-by: jenkins Reviewed-by: Paul Fertser 2013-04-19 R. Steve McKown * : Support newer OSBDM firmware OSBDM: add new VID:PID implemented in OSJTAG/OSBDM firmware somewhere between versions 30.13 and 31.21. PFLASH programming works with this patch, tested on a Freescale Kinetis TWR-K20D72M using its onboard OSBDM JTAG adapter. Note: flash program testing required hacking kinetis_write() to force longword programming, as the FTFL program section commands formulated by kinetis_write() currently fail on this board's PK20DX256VLL7 processor. Change-Id: Ib7b92ff2fe9ebf6158fb1489f554a19e96cd9651 Signed-off-by: R. Steve McKown Reviewed-on: http://openocd.zylin.com/1348 Tested-by: jenkins Reviewed-by: Freddie Chopin 2013-04-03 Salvador Arroyo * : mips: m4k alternate pracc code. Patch 4 Now all the functions with only fetch accesses are modified. The same delay between scans has been added to mips32_pracc_fastdata_xfer(), it should work at the same scan rates as the other pracc functions, but it needs higher scan_delays to work. Change-Id: Ifb31d8ea6de9d22674385782913d221a2494dbbf Signed-off-by: Salvador Arroyo Reviewed-on: http://openocd.zylin.com/1196 Tested-by: jenkins Reviewed-by: Freddie Chopin 2013-03-03 Salvador Arroyo * : mips: m4k alternate pracc code. Patch 2 Each pracc function defines a variable ctx of type struct pracc_queue_info. To simplify the code tree auxiliary functions are defined: pracc_queue_init(), pracc_add() and pracc_queue_free(). The second parameter in pracc_add() is the store address if the instruction is a store at dmseg, otherwise it should be 0. The code is executed by mips32_pracc_queue_exec(). If ejtag_info->mode is 0 mips32_pracc_exec() is called and it should work like with current code. To generate the delay between scans the number of clock ticks are calculated with the help of jtag_get_speed_khz(). Due to delays in the execution of each single ftdi instruction the number of ticks are higher as it should be, specially at higher scan rates. mips32_pracc_read_u32() should now work with the new code. Change-Id: I471590a4fc89b56af10bd46c48767b4c64de154f Signed-off-by: Salvador Arroyo Reviewed-on: http://openocd.zylin.com/1194 Tested-by: jenkins Reviewed-by: Freddie Chopin 2013-04-20 Freddie Chopin * : Improve clone command in README Without the explicit dir at the end the repository will be cloned to "code". Change-Id: Icd8b55b4ba74f23b214c3844e2fb785377768119 Signed-off-by: Freddie Chopin Reviewed-on: http://openocd.zylin.com/1349 Reviewed-by: Øyvind Harboe Tested-by: jenkins 2013-04-17 Ben Nahill * : topic: STM32W support added to em357 driver The em357 driver only supported one page configuration (192k in 96 2048k) pages. This is fine for em357 chips since that's the size they have, but ST's STM32W chips (pretty much the same) have different flash configurations available (64, 128, 192, 256k). I can't find anywhere that would indicate the size of the chip anywhere in memory so the selection must be manual, using the 'size' parameter. For backwards compatibility, any size not known to be in use defaults to the 192k configuration. I don't have any em357 devices to test, but I also found that I had to re-assert the FPEC clock enable before performing an erase. This is a single line and shouldn't break any configurations. My testing so far has only been with a 64k device with 8k of RAM. Change-Id: Ic0ac400a9696efaa09d1407dd4a4d456bc2c318b Signed-off-by: Ben Nahill Reviewed-on: http://openocd.zylin.com/1336 Tested-by: jenkins Reviewed-by: Peter Stuge 2013-04-11 Spencer Oliver * : stlink: fix connect under reset issues We need to make sure that srst is asserted before we attempt to switch into jtag or swd mode otherwise we receive a error (-9) - invalid device id. Change-Id: I625166c751cfba8e8a5290f40122bb9afc9dbb39 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/1315 Tested-by: jenkins 2013-03-19 Andreas Fritiofson * : ft2232: remove ft2232_large_scan memory leak This is a very long outstanding issue see: http://lists.berlios.de/pipermail/openocd-development/2011-June/019404.htmlAs this driver is deprecated the fix is added to purely to reduce the warnings reported by clang. Change-Id: I3a16a704e0e8db27efda50fdcfdd35abf5ebed0f Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/1278 Tested-by: jenkins 2013-03-28 Spencer Oliver * : jimtcl: update embedded jimtcl Update to latest jimtcl commit 2c1eba991e21a6f0b531fb0f83e21f9e6ee7c515. This fixes issues when building on certain versions of Mac OSX. Change-Id: I551477752d7913c84e6deb60b889d0c14bd200a0 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/1311 Tested-by: jenkins Reviewed-by: Xiaofan 2013-04-15 Peter Dietzsch * : flash: Added support for at91sam4sd32c Change-Id: I7223980602d7595a3dd7a3ceaac3f58d4f73f88d Signed-off-by: Peter Dietzsch Reviewed-on: http://openocd.zylin.com/1332 Tested-by: jenkins Reviewed-by: Peter Stuge 2013-03-18 Michel JAOUEN * : arm_adi_v5: fix for csw nonsecure access. Add command to fix CSW_SPROT in register AP_CSW. This solves dap apmem access in non secure access. Change-Id: I7cfcb6434d75f5cfd4a2630a059901cdeea010ce Signed-off-by: Michel JAOUEN Reviewed-on: http://openocd.zylin.com/1276 Tested-by: jenkins Reviewed-by: mike brown Reviewed-by: Spencer Oliver 2013-02-24 Salvador Arroyo * : mips: change in restoring debug working register In current devel code there are 3 functions (related to m4k code) that need to restore register 8 from pracc stack: mips32_pracc_read_u32() mips32_cp0_read() mips32_pracc_write_mem_generic() And mips32_pracc_read_mem() needs to restore regs 8 and 9 from pracc stack. Values in this registers should be the same as read by mips32_pracc_read_regs() when entering debug mode and can be modified by mips32_pracc_write_regs() when leaving debug mode. There is no need to read their values from the processor registers every time. The fields reg8 and reg9 are added to struct mips_ejtag to store these register values and the call to mips32_save_context() is shifted in mips_m4k_debug_entry() in order to store them before any other function needs to restore these registers. For the same reason in function mips_m4k_step() the call to mips_m4k_set_breakpoint(), if needed, should be made after calling mips_m4k_debug_entry(). For single word write the number of pracc accesses are now 9 or 8, from 13 or 12 in current code, single word read takes now 10 instead of 12. This patch is really the first in a set of patches for an alternate m4k pracc code much faster that current code. At least for me with pic32mx works fine. Change-Id: Ibd9df5e8b9f78ce05a180949ba6a561c761b61d6 Signed-off-by: Salvador Arroyo Reviewed-on: http://openocd.zylin.com/1146 Tested-by: jenkins Reviewed-by: Spencer Oliver 2013-02-23 Salvador Arroyo * : pic32mx: 0 wait state option By default pic32mx starts after any reset with 1 wait state for RAM access/exec. It can be changed to 0 wait states by clearing the BMXWSDRM bit (bit 6) in BMXCON register. With 0 wait states near doubles the execution speed. CRC check sum can be done much faster increasing verify_image speed. Fast data transfer also works with a bit higher scan rate, up to 1500 Khz. This option can be set at any time with mww 0xbf882004 0x40 or cleared with mww 0xbf882008 0x40. Some numbers for FTDI/HS with current devel code and a elf file: Core clock / wait states verify_image speed ------------------------------------|------------------------------ 4 Mhz / 1 21 KiB/s 4 Mhz / 0 36 KiB/s 8 Mhz / 1 37 KiB/s 8 Mhz / 0 57 KiB/s Change-Id: I4092ad0f3753f72f77108718d0ed3a3ab84e3b23 Signed-off-by: Salvador Arroyo Reviewed-on: http://openocd.zylin.com/1141 Tested-by: jenkins Reviewed-by: Spencer Oliver Reviewed-by: Xiaofan 2013-02-27 Henrik Nilsson * : Added support for ARMv7-M in arm io. Added support for ARMv7-M targets in arm_nandwrite and arm_nandread. Change-Id: Iab1d78d401f735e191c6a8519f3619035a300fae Signed-off-by: Henrik Nilsson Reviewed-on: http://openocd.zylin.com/1188 Tested-by: jenkins Reviewed-by: Freddie Chopin 2013-03-18 mike brown * : arm_adi_v5: fix mem_ap_read_buf_u32() JTAG nastiness.. Moved JTAG code out of transport-neutral file (arm_adi_v5.c) into transport specific file (adi_v5_jtag.c). Added ap_block_read to dap_ops interface (arm_adi_v5.h) to support the move. Change-Id: I796d3984f138aad052b97c77ac9c12ffd1158f74 Signed-off-by: mike brown Reviewed-on: http://openocd.zylin.com/1277 Tested-by: jenkins Reviewed-by: Michel JAOUEN Reviewed-by: Spencer Oliver 2013-03-19 Spencer Oliver * : ti_icdi: add icdi_usb_query result check Change-Id: I0b40586677a77ee6ae46fe120a677616bde22d1e Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/1279 Tested-by: jenkins Reviewed-by: Xiaofan Reviewed-by: Andreas Fritiofson 2013-03-14 Spencer Oliver * : docs: remove unnecessary whitespace Change-Id: I11bad3de145d941b61e9bd4920bc3281ece91ab3 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/1245 Tested-by: jenkins Reviewed-by: Freddie Chopin 2013-03-23 Thomas Schmid * : at91sam3: Wrong PLLA frequency calculations The command 'at91sam3 info' ignores PLLA DIV values >1. This patch fixes it. Tested on a SAM3S4C chip. Change-Id: I051f41bb3dcefe1ac785fbcb48477a807daa16a2 Signed-off-by: Thomas Schmid Reviewed-on: http://openocd.zylin.com/1307 Tested-by: jenkins Reviewed-by: Peter Stuge 2013-03-15 Spencer Oliver * : target: fix broken Cortex-R4 support This regression was caused due to the recent addition of R4 support and the removal of the bulk_write_memory handler. Change-Id: Ide692737f235c0e9906becb6f3502ba52c5907aa Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/1246 Tested-by: jenkins 2013-03-08 Andreas Fritiofson * : target: Add default implementation of bulk_write_memory Remove dummy implementations from all targets except arm7_9 and mips, which are the only ones with real implementations. Replace with a single default implementation simply calling target_write_memory(). Change-Id: I9228104240bc0b50661be20bc7909713ccda2164 Signed-off-by: Andreas Fritiofson Reviewed-on: http://openocd.zylin.com/1213 Tested-by: jenkins Reviewed-by: Øyvind Harboe Reviewed-by: Spencer Oliver 2012-10-12 Evan Hunter * : adi_v5: search for Debug and Memory AP support Adds dap_find_ap() function. Change-Id: I6643025624009b12d4936de67a605da52c07be49 Signed-off-by: Evan Hunter Reviewed-on: http://openocd.zylin.com/909 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-06-05 Stefan Mahr * : jtag: add support for some probes that are mostly compatible with opendous This patch adds support for usbprog-jtag and usbvlab that are mostly compatible to opendous except for IN and OUT endpoints and usb transfer mode. Change-Id: I44557c2449fe7473295038efa6ae4fc8d80ec7bf Signed-off-by: Stefan Mahr Reviewed-on: http://openocd.zylin.com/687 Tested-by: jenkins Reviewed-by: Spencer Oliver 2013-03-12 Stefan Mahr * : jtag: parport: avoid freeing read-only memory section If command parport_cable is not executed, parport_cable points to const char array in read-only memory as default. On exit free() will try to free this read-only memory. This patch uses strdup to allocate memory when defining default setting. Change-Id: I290e707ac6a37e9dc1b45c85ca51d8bd6aac6761 Signed-off-by: Stefan Mahr Reviewed-on: http://openocd.zylin.com/1223 Tested-by: jenkins Reviewed-by: Spencer Oliver 2013-03-10 Andreas Fritiofson * : target: Remove read_memory_imp Change-Id: Idc6ef3b075ccbb5945df8fea746011cb17175d8f Signed-off-by: Andreas Fritiofson Reviewed-on: http://openocd.zylin.com/1219 Tested-by: jenkins Reviewed-by: Spencer Oliver 2013-03-10 Andreas Fritiofson * : target: Remove soft_reset_halt_imp Change-Id: I12c907584ef73de570eba2dcfeb8477cabc6098f Signed-off-by: Andreas Fritiofson Reviewed-on: http://openocd.zylin.com/1217 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-12-27 Rodrigo Melo * : interface: opendous_ftdi config file added This config file add support to the opendous cable based on the chip ft2232H, using the ft2232 interface driver. Change-Id: I8171a0c475af8d61e081844ee86466a392138fb0 Signed-off-by: Rodrigo Melo Reviewed-on: http://openocd.zylin.com/1096 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-10-08 Drasko DRASKOVIC * : doc: Added MIPS target document This document explains MIPS EJTAG operations implementations within OpenOCD. Change-Id: Ieaf01f8bc5a97d7b0f2c847bac5fbb2ccf8ba088 Signed-off-by: Drasko DRASKOVIC Reviewed-on: http://openocd.zylin.com/904 Tested-by: jenkins Reviewed-by: Spencer Oliver 2013-03-02 Alex Austin * : Kinetis: Symbolic names for Addresses and Commands Change-Id: I2165b66c37bd1608139b5dd00f48124161e13ef0 Signed-off-by: Alex Austin Reviewed-on: http://openocd.zylin.com/1191 Tested-by: jenkins Reviewed-by: Christopher Kilgour Reviewed-by: Spencer Oliver 2013-03-06 Spencer Oliver * : tcl: add flash programming helper This adds a program proc that simplifies using OpenOCD as a standalone programmer. Change-Id: I6ece492cd878c170b734e8bb2e09fe8c4557d5a6 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/1199 Tested-by: jenkins Reviewed-by: Jörg Fischer Reviewed-by: Andreas Fritiofson Reviewed-by: Øyvind Harboe 2013-03-07 Spencer Oliver * : gdb: use stdio functions to convert parameters This reduces the number of gdb conversion routines we have to maintain. Change-Id: Ia43d6cac86cbe4f76fe0875b9d9c16ac340296db Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/1128 Tested-by: jenkins Reviewed-by: Andreas Fritiofson Reviewed-by: Freddie Chopin 2013-03-07 Spencer Oliver * : docs: use doxygen keywords for formatting Rather than use bold fonts etc, use the correct keywords so doxygen formats better. Change-Id: Id9d63f0fc3465665376d7a536c4d6da71998f40e Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/1210 Tested-by: jenkins Reviewed-by: Øyvind Harboe 2013-02-27 Spencer Oliver * : flash: fix stm32 failed probe using incorrect flash size This fixes an issue if the device is manually probed after the initial probe fails due to being unable to read flash size register. In this situation the driver assumes the user has overridden the flash size when infact this may not be the case. It also seems on the older stm32f1 devices the flash register is not readable when locked, this does not seem to apply to the newer parts - f0, f3, f4. Change-Id: I125f872fcb2d962ca6705f97b62d957e2b31303b Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/1187 Tested-by: jenkins Reviewed-by: Johan Almquist Reviewed-by: Freddie Chopin 2013-02-25 Spencer Oliver * : ti-icdi: catch failed icdi_send_cmd warnings detected by clang. Change-Id: I1532bcc12a8ab7446646dfb2a7afa8894ff03679 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/1180 Tested-by: jenkins Reviewed-by: Xiaofan Reviewed-by: Freddie Chopin 2013-02-25 Spencer Oliver * : target: use common target_name to access target::cmd_name member Change-Id: I203b89ef25a072c3b00b504483d5f2a83477fad6 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/1182 Tested-by: jenkins Reviewed-by: Mathias Küster Reviewed-by: Andreas Fritiofson 2013-02-27 Mathias K * : Change reset configuration. This patch change the default reset config from SYSRESETREQ to the working VECTRESET. Change-Id: I21a9a74b9c0c68cfa3a6e6dac9b123acc98a93cb Signed-off-by: Mathias K Reviewed-on: http://openocd.zylin.com/1186 Tested-by: jenkins Reviewed-by: Spencer Oliver 2013-02-25 Mathias K * : Add the target name to debug output for better understanding and error identification. Change-Id: I1054debea6cd3a6548aadeae2d84000a0039814e Signed-off-by: Mathias K Reviewed-on: http://openocd.zylin.com/1178 Tested-by: jenkins Reviewed-by: Spencer Oliver 2013-01-31 Spencer Oliver * : gdbserver: use common hexify/unhexify routines Change-Id: I9989b625666e9c60ec9867cf6f4d94f41c998c3f Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/1105 Tested-by: jenkins Reviewed-by: Mathias Küster Reviewed-by: Øyvind Harboe 2013-02-07 Spencer Oliver * : target: hla correctly use target events Because we were always running using target state TARGET_RUNNING target algorithm's were a bit verbose compared to other targets. This brings the hla target inline with the other targets. Change-Id: I3a257fdc878b87660fac8b5eca22b421eee5b349 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/1134 Tested-by: jenkins 2013-02-19 Johan Almquist * : stm32: add support for stm32l1x 256k high density single bank devices Added support for new ST devices in the stm32lx portfolio, with device id 0x427. These have 256k flash, but in a single bank compared to device id 0x436 which is a dual bank flash. Change-Id: Iafdfe990f24bd04b0d6e00385ee70690f3bf8d5f Signed-off-by: Johan Almquist Reviewed-on: http://openocd.zylin.com/1140 Tested-by: jenkins Reviewed-by: Spencer Oliver 2013-02-05 Spencer Oliver * : stm32: enable flash bank size override It has been seen on some stm32 targets that the flash size register that is probed by the driver may contain an invalid size. This change enables the user to override the probed value. Change-Id: I09359e59a96f9133d3d939670957d32a830a944e Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/1132 Tested-by: jenkins Reviewed-by: Johan Almquist 2013-02-01 Spencer Oliver * : armv7m: use ARM_MODE_THREAD core mode for algoorithm's This makes sure we are using privileged mode when executing any loaders. Change-Id: I18bf32ec92e1c76a66ab25e3712652bc3650b332 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/1108 Tested-by: jenkins Reviewed-by: Andreas Fritiofson 2013-01-09 Spencer Oliver * : armv7m: use generic arm read/write_core_reg Change-Id: I0c15acc1278d2972269d294078495e6b069c830b Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/969 Tested-by: jenkins Reviewed-by: Andreas Fritiofson 2012-11-08 Spencer Oliver * : armv7m: remove unused armv7m_regtype This simplifies the armv7m_core_reg structure ready for the move to using the generic struct arm_reg. Change-Id: I8edb9d77cc54965d49cd2e754568ebcea4cf6964 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/967 Tested-by: jenkins Reviewed-by: Andreas Fritiofson 2013-01-28 Spencer Oliver * : helper: hexify correctly handle signed chars The current implementation of hexify was not correctly handling signed chars. This function is currently used by the ti-icdi driver and as such was causing random write issues. As a note perhaps a better long term fix would be to change to using uint8_t buffers rather than char. This will require changes to the ti-icdi driver aswell. Change-Id: I572e69ff2b99227a7d412de056458c0393794b03 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/1124 Tested-by: jenkins Reviewed-by: Øyvind Harboe 2013-01-03 Spencer Oliver * : rtos: do not use LOG_OUTPUT LOG_OUTPUT is not intended for general output so use the correct LOG_* functions instead. Change-Id: I48d0fe765637024dbafc68f2ea08219d3ff42754 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/1104 Tested-by: jenkins Reviewed-by: Freddie Chopin 2013-01-16 Spencer Oliver * : jtag: only change state if necessary All the other drivers will only change the state if required. This brings all the other drivers inline with this behaviour. The original issue relates to problems on xscale commit 7989000e0969c1ccf69acbc3ce649a020bc1ee66 Change-Id: Ifc90ec2eef68a70a14f37c00931a07982bfa200c Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/1114 Tested-by: jenkins Reviewed-by: Freddie Chopin 2013-01-25 Spencer Oliver * : hla: enable DWT component and fix watchpoints The makes sure the DWT component is always enabled so that watchpoints work as expected. This does need merging into the existing cortex_m logic, however at the moment this is non trivial. Change-Id: Ic6cccd1badb51f70a2ca8ea9ab6923788a94c1bf Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/1122 Tested-by: jenkins Reviewed-by: Freddie Chopin 2012-12-07 Spencer Oliver * : flash: reduce stm32lx loader timeout Waiting 20secs is a bit much excessive, we could probably reduce to 5. Change-Id: Iffb97adb99c2541a075fe78dbc88a53ddf340214 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/1009 Tested-by: jenkins 2012-12-30 Spencer Oliver * : docs: update stm32f1x/stm32f2x driver info As we use the two ST flash drivers for multiple stm32 variants update the docs as to which targets use which driver. Change-Id: I84943ff45482a22b3d3dd8491bb4242d79415939 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/990 Tested-by: jenkins Reviewed-by: Andreas Fritiofson 2013-01-04 Spencer Oliver * : flash: add stm32f2x flash lock/unlock cmds Change-Id: I35344cc47fa4f0a49c034455c5abf479faa0344a Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/988 Tested-by: jenkins Reviewed-by: Andreas Fritiofson 2013-01-18 Roman D * : flash: EFM32 GG/LG page size detection fix Fixed flash page size detection according to EFM32 GG/LG errata. MEM_INFO_PAGE_SIZE register containts invalid value in devices with revision number lower than 18 and should not be used. Change-Id: Idb2832246efcbbec2fd98a5c458f72a36df386fb Signed-off-by: Roman D Reviewed-on: http://openocd.zylin.com/1116 Tested-by: jenkins Reviewed-by: Spencer Oliver 2013-01-10 Roman D * : flash: EFM32 flash implementation Limited (no page unprotect, no block writes) implementation of EFM32 flash support. Verified with EFM32 development kit and STLink V2 adapter using SWD. Change-Id: I3db2054d9aa628a1fe4814430425db3c9959c71c Signed-off-by: Roman D Reviewed-on: http://openocd.zylin.com/1106 Tested-by: jenkins Reviewed-by: Spencer Oliver 2013-01-02 Spencer Oliver * : hla: support setting DCB_DEMCR on resume This is only minimal support to enable use to catch a Hard Fault in the stm32l flash bootloader. Change-Id: I21d6a11893e2f1d173ebff1a651d6f52bf6eec32 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/1103 Reviewed-by: Peter Stuge Tested-by: jenkins 2012-11-20 Spencer Oliver * : flash: use correct stm32f1x option read mask Make sure we do not mask out the BFB2 boot bank bit, as this is used on the larger XL devices. Change-Id: Iacfdf874140e409e0c4ca9b9aee8f5c2f90dc9be Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/991 Tested-by: jenkins Reviewed-by: Andreas Fritiofson 2012-11-20 Spencer Oliver * : stm32f1x: preserve user option byte data The user is able to use 2bytes of the options byte data for whatever purpose they wish. Make sure we preserve this during an option erase/write. Change-Id: Ibf951b11c59a148e671b1eb47fdc9b4f49ccae15 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/983 Tested-by: jenkins Reviewed-by: Andreas Fritiofson 2012-12-29 Andreas Fritiofson * : doc: Clarify the topic field in the commit comment template Change-Id: Iea1f3b665b011ca3748800048039d3f6b33d7756 Signed-off-by: Andreas Fritiofson Reviewed-on: http://openocd.zylin.com/1101 Reviewed-by: Øyvind Harboe Reviewed-by: Tomasz CEDRO Reviewed-by: Spencer Oliver Tested-by: Spencer Oliver 2012-12-06 Spencer Oliver * : cfg: increase stm32l-discovery working area This part has 16k ram so make it all available. Change-Id: Ifeb7bc850bfe4f68d0affb8f6a0931b4327e7257 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/1006 Tested-by: jenkins Reviewed-by: Andreas Fritiofson 2012-12-04 Spencer Oliver * : cfg: enable stlink stm32l HSI Switch to using the internal HSI when a reset init is called, this also matches the std stm32l cfg. Read (verify) speed is increased from 17 to 120 KiB/s. Change-Id: Ic94ba85949ffdefa17b7be45eef14e30f941d107 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/1004 Tested-by: jenkins Reviewed-by: Andreas Fritiofson 2012-11-20 Spencer Oliver * : flash: format stm32f2x driver defines Change-Id: Ie903996368a8d4313df87839d5ba3f2a102796a3 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/987 Tested-by: jenkins Reviewed-by: Andreas Fritiofson 2012-11-15 Spencer Oliver * : stlink: add generic open error routine Change-Id: I1cd18896ab2a37255471a2d160befed8dd8fb544 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/979 Tested-by: jenkins 2012-11-22 Spencer Oliver * : gdb: fix correct shutdown when using pipes 50d5441e2a615fb2c44b41a777e4373901f7a2e6 commit added a regression when using pipes with GDB, OpenOCD would appear to hang when exiting GDB. This fixes that behaviour so we shutdown correctly. Change-Id: I9b337c2bdd41b1966de1c7631118257afcbfa6bd Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/993 Tested-by: jenkins 2012-11-08 Spencer Oliver * : doc: replace luminary with TI urls's Change-Id: Ic8a768f5a498e78b96421c6137238593c159fd72 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/970 Tested-by: jenkins 2012-11-12 Spencer Oliver * : icdi: add TI icdi interface This is the new proprietary interface replacing the older FTDI based adapters. It is currently fitted to the ek-lm4f232 and Stellaris LaunchPad. Change-Id: I794ad79e31ff61ec8e9f49530aca9308025c0b60 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/922 Tested-by: jenkins 2012-10-25 Spencer Oliver * : hla: fix watchpoints not being set Watchpoints were not being enabled when the hl adapter target was resumed. This effects both stlink and icdi interfaces. Change-Id: Ia9f8a9415be97a467cd099b63b6bc9f7f37d0c0d Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/931 Tested-by: jenkins 2012-10-24 Spencer Oliver * : stlink: rename stlink cmd names As part of the switch to using the hla for the stlink interface we rename the cmds to a more generic name. Update scripts to match new names. Also add handlers for deprecated names. Change-Id: I6f00743da746e3aa13ce06acfdc93c8049545e07 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/921 Tested-by: jenkins 2012-10-24 Spencer Oliver * : stlink: print version info Print stlink info always rather than just when debug log enabled. Change-Id: I2a29ef046925200e1c94624280c0b252fab5219a Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/925 Tested-by: jenkins 2012-11-15 Muranaka Masaki * : flash: fm3 mb9bfxx7 mb9bfxx8 support Patch submitted by Trac #55 Change-Id: I08b0d79d24fe9108ca0bbfbc9b45c60359b6d180 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/981 Tested-by: jenkins 2012-12-10 Kamal Dasu * : mips_m4k: Fixed mips_m4k_resume code for smp targets Fix for bug introduced in in mips smp support code in the resume logic that is checking for wrong return value. Change-Id: Ice3e0069f936b556fecc338ccc12ddba38deeaf6 Signed-off-by: Kamal Dasu Reviewed-on: http://openocd.zylin.com/1048 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-11-26 Spencer Oliver * : jtag: fix reset_config copy/paste error As the other arg checks do not OR, it is assumed this is a copy/paste error from the original code author. Change-Id: I7dfc7396254a6f558887def951c57dfd4a0e6c2c Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/997 Tested-by: jenkins Reviewed-by: Paul Fertser Reviewed-by: Freddie Chopin 2012-11-13 Spencer Oliver * : jtag: enable connect under reset Currently if the target supports srst_nogate we wait until target assert_reset until we get a chance to assert the srst. However sometimes we will not get this far if the target has already failed the jtag_examine_chain. This has been tested on targets that support this behaviour (STM32 and STR9). Change-Id: Ibcf7584b137b472f31ba6ddd5cd99d848c5508d1 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/971 Tested-by: jenkins Reviewed-by: Paul Fertser Reviewed-by: Freddie Chopin 2012-11-02 Evan Hunter * : cortex_a: Fix target entry state route. If target is disabled at init, then is examined using 'arp_examine', it can get to cortex_a8_poll with the target state being unknown. Change-Id: Ifffb345bf971d275d2eb1912648b29f0a75f6ccc Signed-off-by: Evan Hunter Reviewed-on: http://openocd.zylin.com/954 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-10-17 Kamal Dasu * : mips_ejtag: Adding EJTAG 4.x and 5.x as valid versions This is a minor change to log EJTAG version 4.x and 5.x as valid versions when debug log is enabled. Change-Id: Ie20458d033c6d22842cb4a31b56765d4ba2ff123 Signed-off-by: Kamal Dasu Reviewed-on: http://openocd.zylin.com/936 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-11-30 Aymeric Vincent * : Make NetBSD a recognized system Change-Id: I7fcb540553da7833a8b6a82335a7296539a8f491 Signed-off-by: Aymeric Vincent Reviewed-on: http://openocd.zylin.com/998 Reviewed-by: Peter Stuge Tested-by: jenkins 2012-11-15 Spencer Oliver * : stlink: format src defines Change-Id: I7c3fd6e84681e007f1983ad9b8c85369cf9f3ba1 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/978 Tested-by: jenkins Reviewed-by: Andreas Fritiofson 2012-11-11 Salvador Arroyo * : mips: patch mips32_pracc_exec_write() No function writes to MIPS32_PRACC_PARAM_IN addresses and probably has no much sense. Any attempt to write to those addresses should be an error. Change-Id: Iebea5fa9954e2cd56ad34976dd7d25009c6e6388 Signed-off-by: Salvador Arroyo Reviewed-on: http://openocd.zylin.com/975 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-11-03 Salvador Arroyo * : mips: optimize mips32_pracc_write_regs() code. All the the loads are done with lui and ori instructions, there is no need to save any register, they will be overwritten. Like in the previous patch, for speed optimization in write code, same instructions can be saved if the lower half word or the upper half word is 0. If the lower half word is 0, it can be loaded with only a lui instruction. If the higher half word is 0 it can be done with an ori instruction with register 0. This code saves 10 pracc accesses at a minimum, and 40 at a maximum, obviously if register 2 to 31 are 0 or a half word is 0 Current code needs 91 pracc accesses. Change-Id: I892c5b440191d0c7a474c96845d41c373b7fc637 Signed-off-by: Salvador Arroyo Reviewed-on: http://openocd.zylin.com/957 Reviewed-by: Spencer Oliver Tested-by: jenkins 2012-11-02 Salvador Arroyo * : mips: optimize read code for speed Really nothing new that not explained in previous patches. The code is expanded as needed, there are no loops in pracc code. For the first value pracc accesses are reduced from 39 to 16 and for aditional values from 10 to 3. dump_image should work around 3x faster. Change-Id: I37c9b13395c09eb52a91f10cdb6cbaedef8ab98b Signed-off-by: Salvador Arroyo Reviewed-on: http://openocd.zylin.com/955 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-11-01 Salvador Arroyo * : mips: optimize CP0 read/write code MIPS32_PRACC_BASE_ADDR is defined as 0xFF200000. Now is possible to load the base address with a lui instruction and only one pracc access. Offsets to the pracc code addresses are defined to simplify the code and probably make it a bit more readable or self-explained. Change-Id: I853dd2d7fad52745931cc6e6be68c0ae156d897e Signed-off-by: Salvador Arroyo Reviewed-on: http://openocd.zylin.com/951 Reviewed-by: Spencer Oliver Tested-by: jenkins 2012-10-30 Salvador Arroyo * : mips: optimize mips_ejtag_step_disable() code The code is a bit large compared to mips_ejtag_step_enable(). With the mips32 xori instruction the code can be reused. The number of pracc accesses are reduced from 18 to 7. Change-Id: If3974ebd64da4461c22b089796646990e68e1b72 Signed-off-by: Salvador Arroyo Reviewed-on: http://openocd.zylin.com/944 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-11-15 Spencer Oliver * : doc: update to new sourceforge git url The new sourceforge platform also supports http access, so use that rather then repo.or.cz. Change-Id: Ica89d9475847a2095c179b240053145795549802 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/982 Tested-by: jenkins 2012-11-10 Matthias Blaicher * : rtos: Fix error in reading the current thread in ChibiOS/RT Commit c4ab127b4069e20e introduces a copy&paste error which affects the detection of the current thread. As a result, the stack of the current thread won't be detected correctly in most cases. Change-Id: Ib46b8f64be8053d7e9103f427c66796963214419 Signed-off-by: Matthias Blaicher Reviewed-on: http://openocd.zylin.com/974 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-10-22 Karl Kurbjun * : ARM v4/v5 target files: mrc and mcr help information is incorrect. The order of the mrc/mcr command matches the ARM Architecture Reference Manual. This patch corrects the help information for mrc/mcr. Change-Id: I1f0e6a628a3644124591a6aa291b8a58cfd93b44 Signed-off-by: Karl Kurbjun Reviewed-on: http://openocd.zylin.com/914 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-10-08 Peter Horn * : cortex_m: Fix single stepping will not return to debug mode sometimes This occurs when stepping past a breakpoint on a even address with maskisr option set to auto With -d3 the following log message appears in this case: "Debug : Interrupt handlers didn't complete within time, leaving target running" Cause : Given a breakpoint is set on the lower half word and the PC is on the upper half word. When another breakpoint is now set on the current PC then resuming the core will not result in a break on the newly set breakpoint. This has been observed on a STM32F1x, STM32F2x (CM3) but not on a STM32F0x (CM0). It's not clear if this is a STM32F1/F2 only or a general CM3 problem. Change-Id: I384813f3bfdf935373b5e23cdb2d7f243c70cc00 Signed-off-by: Peter Horn Reviewed-on: http://openocd.zylin.com/864 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-10-25 Gianluca Renzi * : Generic LPC1850 board w/ SPIFI flash. This config file is intended as an example of how to use the lpcspifi flash driver, but it should be functional for most LPC1850 boards utilizing SPIFI flash. Change-Id: I855854282336701fd210134497ce014017f3aaec Signed-off-by: Gianluca Renzi Reviewed-on: http://openocd.zylin.com/929 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-11-05 Spencer Oliver * : cortex_m: fix define formatting Change-Id: Ibdec882b2afc7e16f2361f86715463e030a54964 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/963 Tested-by: jenkins 2012-11-05 Matthias Blaicher * : rtos: Add FPU detection to ChibiOS/RT The stacking of ChibiOS/RT depends on the usage of an FPU. If the FPU is enabled the FPU registers are also saved on context switch. This patch adds automatic detection of FPU for armv7m targets. Note: With this patch, openocd will only output an error message warning that the FPU is enabled. For further FPU support, the correct stacking information also needs to be added. Change-Id: I0984cbd9180f247ba2fa610e74a6413cc54239ea Signed-off-by: Matthias Blaicher Reviewed-on: http://openocd.zylin.com/961 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-09-19 Sergey Borshch * : fix memory leaks if add_connection() fails, memory allocated in copy_command_context() is lost. Signed-off-by: Sergey Borshch Change-Id: I91a2757f29612038031eb8953100faa3b850d3a6 Reviewed-on: http://openocd.zylin.com/836 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-10-28 Peter Stuge * : mpsse: Always perform a general reset of the MPSSE in mpsse_open() Per AN_135 FTDI MPSSE Basics Version 1.1, section 4.2 step 7. http://www.ftdichip.com/Support/Documents/AppNotes/AN_135_MPSSE_Basics.pdfThis allows to stop and restart OpenOCD reliably, without needing to power cycle the interface. Change-Id: Ibeafe5ecfe7b2f6f82712cbc85116904407ddb36 Signed-off-by: Peter Stuge Reviewed-on: http://openocd.zylin.com/939 Tested-by: jenkins 2012-10-28 Peter Stuge * : ftdi/flyswatter2.cfg: Fix the signal layout Change-Id: If6612af25fa3562f49e9c8ccff01b6ef0af5ceb0 Signed-off-by: Peter Stuge Reviewed-on: http://openocd.zylin.com/938 Tested-by: jenkins 2012-10-26 Spencer Oliver * : gdb: fix broken qCRC packet handling The rtos layer was incorrectly handling a qCRC packet as a qC packet. Make sure we check for the qCRC packet and return unhandled so the gdb server gets a chance to handle it. This packet is used in the gdb compare-sections cmd. Change-Id: I21f8e5fa7225fccd13d65cf9e40186895065a7e3 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/933 Tested-by: jenkins Reviewed-by: Matthias Blaicher Reviewed-by: Peter Stuge 2012-10-18 Edgar Grimberg * : ioutil: make the file compile on MacOS The meminfo command cannot exist if the malloc.h header is not present. Cannot get the mac address without sys/ioctl.h and SIOCGIFHWADDR defined Change-Id: Ifc0fb98c3a60c53ad2e19473e08b34c460529d0b Signed-off-by: Edgar Grimberg Reviewed-on: http://openocd.zylin.com/912 Tested-by: jenkins Reviewed-by: Øyvind Harboe Reviewed-by: Peter Stuge 2012-10-23 Matthias Blaicher * : rtos: fix gdb qC command answer rtos->current_thread is of type int64_t. All other commands already respect this. Change-Id: I9951946ff2a09c53cd78c6ab882c80cdd2ab7ac6 Signed-off-by: Matthias Blaicher Reviewed-on: http://openocd.zylin.com/917 Reviewed-by: Spencer Oliver Tested-by: jenkins Reviewed-by: Peter Stuge 2012-10-27 Matthias Blaicher * : rtos: Fix wrong allocation in linux_get_symbol_list_to_lookup linux_get_symbol_list_to_lookup allocates to few memory. On 64 bit systems the error did not show due to char* being twice its size, leaving accidentally enough space. This patch makes linux_get_symbol_list_to_lookup behave identical to all other RTOS. Change-Id: I290ea241fb20b65585c8be14609a92fdbd2a307d Signed-off-by: Matthias Blaicher Reviewed-on: http://openocd.zylin.com/934 Tested-by: jenkins Reviewed-by: Peter Stuge 2012-10-18 Spencer Oliver * : docs: mention extended-remote support Change-Id: Idd7cc0364856082cbbfee5015e49cd7d237d68ef Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/913 Tested-by: jenkins Reviewed-by: Peter Stuge 2012-10-11 Spencer Oliver * : gdb: fix extended-remote restart Seems versions of gdb > 6.8 require an W stop reply after receiving a kill packet. Without this we receive the following error from gdb: gdb/thread.c:72: internal-error: inferior_thread: Assertion `tp' failed. Change-Id: I86765a321f0429c9b517fe13ded0ee2dbd4b2f87 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/911 Tested-by: jenkins Reviewed-by: Joel Bodenmann Reviewed-by: Freddie Chopin 2012-10-06 Freddie Chopin * : Fix serious bug in LPC2xxx/LPC17xx flash algorithm. Flash algorithm for LPC17xx/LPC2xxx was trying to "reuse" previously allocated working area on next flashing which is not possible - working areas are freed automatically on reset. This caused all but first flashing attempts to fail. As there is no point in storing pointer to working area, it was converted to local variable. Change-Id: I939946325ff9eecc4861c0f51ab0f73871a3d7b9 Signed-off-by: Freddie Chopin Reviewed-on: http://openocd.zylin.com/860 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-10-05 Matthias Blaicher * : rtos: Add ChibiOS/RT support This patch adds ChibiOS/RT support. This patch requires at least ChibiOS/RT development version starting from SVN revision 4734. Note, that the Thread structures depend not only on the target but also on the ChibiOS configuration at build time. To correct this ChibiOS includes a new "memory signature" which specifies the offsets. Special thanks go to Peter Stuge and Spencer Oliver for their continous input and feedback to this patch. Change-Id: I842bf7ba6c2309a4efe93d29ea6cd0784a8b22a3 Signed-off-by: Matthias Blaicher Reviewed-on: http://openocd.zylin.com/901 Tested-by: jenkins Reviewed-by: Peter Stuge 2012-09-27 Spencer Oliver * : flash: update stellaris flash data to latest dev package 9453 Change-Id: I16107a093d4ed7342583f5c32ad16aa98f81d122 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/856 Tested-by: jenkins Reviewed-by: Freddie Chopin 2012-05-17 Paul Fertser * : rtos: support FreeRTOS over stlink Since stlink is a special case it presents the same CPU core under a different name, so copy the configuration to account for that. Change-Id: I9febf79b388301bde6211d185b5b8161cdadb9ff Signed-off-by: Paul Fertser Reviewed-on: http://openocd.zylin.com/652 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-09-30 Andreas Fritiofson * : dsp5680xx_flash: Remove unused flash bank structure Change-Id: I947b6730b3741a71303e440daefa4fcf583cb9cf Signed-off-by: Andreas Fritiofson Reviewed-on: http://openocd.zylin.com/867 Reviewed-by: Freddie Chopin Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-09-30 Andreas Fritiofson * : flash/nor/stellaris: Remove unnecessary write_algorithm check The pointer must be non-null here since we returned if allocation failed. Change-Id: I9b75099ed3b3870c815d1df5760ed1f3fe1d20d6 Signed-off-by: Andreas Fritiofson Reviewed-on: http://openocd.zylin.com/866 Reviewed-by: Freddie Chopin Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-10-04 Spencer Oliver * : readme: update missing configure args Change-Id: I495a4557f161290f8f99788de27958f7dc08d6f6 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/900 Tested-by: jenkins Reviewed-by: Freddie Chopin 2012-10-04 Peter Stuge * : rtos: Rewrite rtos_qsymbol() and fix auto-detect false positive Matthias Blaicher submitted a patch at http://openocd.zylin.com/#/c/891/ to fix the false positive; when no RTOS was detected OpenOCD used the last RTOS in the list. While reviewing the code affected by Matthias' patch a rewrite seemed appropriate, to make the code readable. Matthias has abandoned his change and this change also fixes the false positive. Change-Id: Ic3327ccd036da52ba0a7e21ef93018205e74149c Signed-off-by: Peter Stuge Reviewed-on: http://openocd.zylin.com/895 Reviewed-by: Matthias Blaicher Tested-by: jenkins 2012-10-04 Peter Stuge * : rtos: Rewrite rtos_create() for readability The new code is almost functionally equivalent to the old; besides error handling the only difference is that the code is now readable. Many thanks to Matthias Blaicher for pointing out an iteration error in the rtos_try_next() change, which also affected this change. Change-Id: If38b87439e9de2303b220b3a7e3200ceaa8391da Signed-off-by: Peter Stuge Reviewed-on: http://openocd.zylin.com/893 Tested-by: jenkins Reviewed-by: Matthias Blaicher 2012-10-04 Spencer Oliver * : build: fix broken ftd2xx bus blaster If configure is executed without --enable-ft2232_ftd2xx then the bus blaster or presto will fail to build with unresolved external ftd2xx_status_string. Make sure we run the ftd2xx build test if --enable-usb_blaster_ftd2xx is enabled. Change-Id: I09d270d6fcd083d77f6785b8969d9acb3dfef11d Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/892 Tested-by: jenkins Reviewed-by: Peter Stuge 2012-09-26 Spencer Oliver * : cfg: cortino tested and working Change-Id: I13534742c76ebbb05b47bf98768c997068da747a Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/851 Tested-by: jenkins Reviewed-by: Freddie Chopin 2012-09-26 Spencer Oliver * : cfg: ftdi icdi enable srst open drain config Change-Id: I21a115121f167dc88cd9bf2d1ca1ac9f3e1110d7 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/848 Tested-by: jenkins Reviewed-by: Freddie Chopin 2012-09-25 Spencer Oliver * : cfg: lm3s811ek config tested and working Change-Id: I5402b5521d6e1ef0a569f5cad02c003681f5444b Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/847 Tested-by: jenkins Reviewed-by: Freddie Chopin 2012-09-25 Spencer Oliver * : cfg: stm32-performance stick config tested and working Change-Id: I9852d11e369e501af240a2b8e9f74306aee4e4a0 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/845 Tested-by: jenkins Reviewed-by: Freddie Chopin 2012-09-28 Spencer Oliver * : docs: enable local structs in doxygen output Change-Id: I9c811d49690524f1ce5372326de67ec4ac7b09f4 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/858 Tested-by: jenkins Reviewed-by: Freddie Chopin 2012-09-26 Spencer Oliver * : cfg: add ti ek-lm3s9d92 config Change-Id: Ib09ca3e57de363a24d704b184ba8546bad08f56f Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/853 Tested-by: jenkins Reviewed-by: Freddie Chopin 2012-09-27 Spencer Oliver * : sysfsgpio: remove ignoring return value build warning fixes following gcc warning: error: ignoring return value of write, declared with attribute warn_unused_result Change-Id: I96ea6649078449208a77690caea2cb237c388e6e Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/854 Tested-by: jenkins Reviewed-by: Marc Reilly Reviewed-by: Freddie Chopin 2012-09-26 Spencer Oliver * : cfg: add STM32F3-DISCOVERY board support Change-Id: I4a02e0504fc04ffc1238d9bb77ec05c1f781e7e8 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/810 Reviewed-by: Freddie Chopin Tested-by: jenkins 2012-09-26 Spencer Oliver * : cfg: fix incorrect str9-comstick reset config The str9-comstick uses a direct srst connection rather than via any buffer. As a result this fixes issues with the newer ftdi driver. Change-Id: I0968e8459997a6a2b7bf0c46e89662cd57b4f496 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/842 Tested-by: jenkins Reviewed-by: Andreas Fritiofson Reviewed-by: Freddie Chopin 2012-09-24 Spencer Oliver * : ftdi: correct ftdi_initialize error text Change-Id: If230c0b5b3a18fd273106b743404079d0cbc9ddc Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/840 Tested-by: jenkins Reviewed-by: Andreas Fritiofson Reviewed-by: Freddie Chopin 2012-09-27 Spencer Oliver * : cfg: fix incorrect stm32f3 TAPID Change-Id: Id66d4e03a77c47a49086ee753bed01b3944064e1 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/855 Tested-by: jenkins Reviewed-by: Freddie Chopin 2012-08-22 Spencer Oliver * : jtag: remove libftdi enum-compare warning See Trac #52 for details. Change-Id: Idb509ead2b51bfcceeb00d0224a4d1c395b28a04 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/801 Tested-by: jenkins Reviewed-by: Olivier Schonken Reviewed-by: Freddie Chopin 2012-08-16 George Harris * : Added SPIFI flash driver, algorithms, and docs Added a flash driver designed to allow program/erase of memory-mapped SPI flash chips for LPC43xx/LPC18xx family micros. This driver includes three algorithms - erase, write, and SPIFI peripheral initialization (to allow memory-mapped access after a reset). The driver has been added to the flash driver table (drivers.c), and the OpenOCD documentation has been updated to include the flash driver configuration command. Change-Id: I79f4ff8f1f07de4e5f2fe4f8c23aeb903f868514 Signed-off-by: George Harris Reviewed-on: http://openocd.zylin.com/783 Tested-by: jenkins Reviewed-by: Aurelien Jacobs Reviewed-by: Freddie Chopin 2012-08-20 Marc Reilly * : drivers: new jtag bitbang driver using sysfs gpio This driver implements a bitbang jtag interface using gpio lines exported via sysfs. The aim of this driver implementation is to use system GPIOs but to avoid the need for an additional kernel driver. A config suitable for RaspberryPi is included. Change-Id: Ib2acf720247a219768d1cbfeebd88057ed2d7b8b Signed-off-by: Marc Reilly Reviewed-on: http://openocd.zylin.com/762 Reviewed-by: Spencer Oliver Tested-by: jenkins Reviewed-by: Freddie Chopin 2012-09-07 Freddie Chopin * : The openocd-0.6.0 release. Change-Id: I72eeabfc704d2a979ac0b4492771690631d2300f Signed-off-by: Freddie Chopin 2012-09-02 Chuen Chou * : flash: fix sam3 page read/write address computation error In at91sam3.c for Atmel SAM3 flash support, there are arithmetic errors in the functions sam3_page_read() and sam3_page_write(). Address locations are computed incorrectly due to an extra addition operation. This leads to memory locations being skipped during flash writes and reads. Smaller programs are written successfully into flash, with memory gaps, while larger programs of legitimate size fail because the skipped memory is not utilized and therefore unavailable. The changes address this condition, and have been tested with an Atmel SAM3X-EK evaluation board. Change-Id: I9ea3b9ed0130b71cbc32b2294e31a6a2bc71b47a Signed-off-by: Chuen Chou Reviewed-on: http://openocd.zylin.com/806 Tested-by: jenkins Reviewed-by: Freddie Chopin 2012-09-05 Spencer Oliver * : docs: add user mailing list and irc info Change-Id: I7000b5ab2967f8dc4cea8983978fce824ea1f98e Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/807 Tested-by: jenkins Reviewed-by: Freddie Chopin 2012-08-29 Freddie Chopin * : Restore -dev tag. Signed-off-by: Freddie Chopin 2012-08-25 Salvador Arroyo * : Pic32mx: make row programming work with any offset In function pic32mx_write_block() if the parameter offset is not a multiple of row size the row offset (offset % row_size) will be ignored by the flash controller, shifting the code to the beginning of the row. Word programming gets it right. Change-Id: I134913e3d533688f791bbcb0c6e8983524197f3c Signed-off-by: Salvador Arroyo Reviewed-on: http://openocd.zylin.com/796 Tested-by: jenkins Reviewed-by: Spencer Oliver Reviewed-by: Freddie Chopin 2012-08-28 Spencer Oliver * : stlink: fix typo Change-Id: I5fe7b695b00faef966e7621614bbd60b6e694a4f Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/800 Tested-by: jenkins Reviewed-by: Mathias Küster Reviewed-by: Freddie Chopin 2012-08-23 Andreas Fritiofson * : ftdi: fix overflow if last field of a scan is empty The last bit of a scan is clocked during TAP movement so it's necessary for the last field to have at least one bit. Strip trailing empty fields and make sure the TAP is not affected if there's nothing to scan. Clients probably shouldn't add empty fields so add a debug message to be able to track and fix them. Change-Id: I27552568bc11146570b9b99ed8a1ae81b5fb2c50 Signed-off-by: Andreas Fritiofson Reviewed-on: http://openocd.zylin.com/794 Reviewed-by: Spencer Oliver Tested-by: jenkins Reviewed-by: Freddie Chopin 2012-08-28 Spencer Oliver * : adapter: remove superfluous line breaks Change-Id: I8e68b9d6f571ef7715a2f4cad0aa78fe4e3b48e8 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/798 Tested-by: jenkins Reviewed-by: Freddie Chopin 2012-08-17 Freddie Chopin * : Update NEWS Added some missing items to NEWS file prior to final 0.6.0 release. Change-Id: I69255c85fa8f4b6f06eae7c56f78072e3ec2d6f8 Signed-off-by: Freddie Chopin Reviewed-on: http://openocd.zylin.com/784 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-08-17 Freddie Chopin * : Add another scripts search path for Windows builds Add single "scripts" folder to search path for Windows OpenOCD builds that don't use cygwin bin/openocd.exe scripts/interface/dummy.cfg scripts/target/at91eb40a.cfg Do some refactoring of current code (thx to Andreas). Change-Id: Idbb08d1368b06f25da44f4f9ab1511db992b1724 Signed-off-by: Freddie Chopin Signed-off-by: Andreas Fritiofson Reviewed-on: http://openocd.zylin.com/785 Tested-by: jenkins 2012-07-07 Christopher Kilgour * : kinetis: ensure flash writes are not truncated The number if longwords or "sections" (Freescale term) written for a Kinetis flash write (4, 8, or 16 bytes depending on the part density/granularity) are now rounded up to ensure there are no truncations when the desired write is not a multiple of the minimum write size. Change-Id: I8db40a8769d8ac5393a46cbf4e5ff0df82faf916 Signed-off-by: Christopher Kilgour Reviewed-on: http://openocd.zylin.com/738 Tested-by: jenkins Reviewed-by: Freddie Chopin 2012-08-22 Salvador Arroyo * : Patch: Make pic32mx unlock work at higher scan frequencies For example in a pic32mx220, pic32mx unlock don't work if adapter_khz is set to 5000 or more. A short delay after asserting reset fix the problem. Change-Id: I62e493edfcea585c36c8de77a969cebac7227b96 Signed-off-by: Salvador Arroyo Reviewed-on: http://openocd.zylin.com/790 Tested-by: jenkins Reviewed-by: Freddie Chopin 2012-08-23 Spencer Oliver * : stlink: stlink_interface_init_target use hex prefix Change-Id: I782da74687bcf111c1f04c53b2c1120d6a034441 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/791 Tested-by: jenkins Reviewed-by: Freddie Chopin 2012-08-05 Salvador Arroyo * : Severe bug in Pracc code The function wait_for_pracc_rw() fails if Pracc bit is 0. The variable ejtag_ctrl is loaded with the content of the control register in the first scan. In the second scan Pracc bit is scanned out as 0, letting the proccesor go. The result is unpredictable. All the strange data corruption when scanning at certain frequencies, or the strange delays needed when entering or leaving fasdata area are retated to this bug. Now the code works at any scan frequency, tested up to 15000Khz and indepently of processor speed, tested at 31.25Khz and 4/8Mhz. Change-Id: Iedfd81d06d6af4bc738a521f720e42323025b268 Signed-off-by: Salvador Arroyo Reviewed-on: http://openocd.zylin.com/769 Tested-by: jenkins Reviewed-by: Freddie Chopin 2012-08-14 Andreas Fritiofson * : cfi: fix type-punning warnings in cfi_spansion_write_block Retest the condition when needed, instead of abusing the common_magic field as a flag. There are only two options here. Either it's an armv7m or it's another arm. is_arm(...) will return true even for armv7m, so it's imperative to check in the right order. Change-Id: Ic227f19f7babf1b0b0fe075f9a3abc4eabc7d5f1 Signed-off-by: Andreas Fritiofson Reviewed-on: http://openocd.zylin.com/779 Tested-by: jenkins Reviewed-by: Spencer Oliver Reviewed-by: Freddie Chopin 2012-08-13 Spencer Oliver * : target: catch dap_lookup read error Issue found by clang-3.1 Change-Id: I2e922ec83117e75db5bec1e82edaa75a9e6e7464 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/778 Tested-by: jenkins Reviewed-by: Freddie Chopin 2012-08-13 Spencer Oliver * : tcl: fix potential memory leaks Reorder to allocate all memory after COMMAND_PARSE_NUMBER call. This removes a clang warning about un-released memory Change-Id: I8dbeb664a6467077157015bd879bc0aefc5e8614 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/776 Tested-by: jenkins Reviewed-by: Freddie Chopin 2012-08-10 Spencer Oliver * : flash: fix FC_FLEX_RAM class code path If the flash class was defined as FC_FLEX_RAM then this would always drop through to the default handler. This bug was found by clang, so untested. Change-Id: I2d9fe6415dd216728a145519400f7b9ef1bd3c3a Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/773 Tested-by: jenkins Reviewed-by: Freddie Chopin Reviewed-by: Mathias Küster 2012-08-07 Aurelien Jacobs * : ftdi: Olimex ARM-USB-TINY validated Flashing a CFI flash and debugging with gdb work fine. Change-Id: Ib2578ee6f41c1003968198439033d00d805122f7 Signed-off-by: Aurelien Jacobs Reviewed-on: http://openocd.zylin.com/770 Tested-by: jenkins Reviewed-by: Spencer Oliver Reviewed-by: Freddie Chopin 2012-08-14 Spencer Oliver * : cfg: remove duplicate Olimex ARM-USB-OCD config This file is already included as olimex-arm-usb-ocd.cfg. Change-Id: I0e66977c58e74ac93a0dc3a0c88a5e5af4992f8b Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/780 Tested-by: jenkins Reviewed-by: Peter Stuge 2012-08-02 Freddie Chopin * : Restore "-dev" tag. Change-Id: Ibb7669ea73872d75a5c2f32f2264e57b1d0f20c7 Signed-off-by: Freddie Chopin 2012-08-02 Spencer Oliver * : target: add valid smp target check Check that the target is valid before calling any target functions. Change-Id: I538fccc79d5ec89976e14beab02cb20490b299bb Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/766 Tested-by: jenkins Reviewed-by: Freddie Chopin 2012-08-02 Freddie Chopin * : Add missing files (header and .txt) for release. make distcheck is used to make packages with OpenOCD release, this command uses information from Makefile.am files to know which files should be included in the package and which can be left only in repository. This patch makes a few headers from recent JTAG drivers and one txt file with info about target tcl config files included in released packages. Change-Id: I91202290633a30f53624a8c7d9a0ebf72c40772b Signed-off-by: Freddie Chopin Reviewed-on: http://openocd.zylin.com/767 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-06-08 Alexander Osipenko * : arm946e: cp15 command returns value to the script Not just print it. This enables scripts to analyze valuable config options of arm946e-s cores, do internal BIST memory tests and more. Be careful to flush caches before disabling it. Do not forget that BIST test overwrites memory. - cp15 rewritten from COMMAND_HANDLER to jim_handler. Change-Id: I734da0be6db0a3127c2daa94ed75efef94da8ceb Signed-off-by: Alexander Osipenko Reviewed-on: http://openocd.zylin.com/694 Tested-by: jenkins Reviewed-by: Freddie Chopin 2012-07-31 Alexander Osipenko * : arm946e: don't use global variables for context Global variables 'dc' 'ic' had been used in the code to keep target's state of D-cache and I-cache on debug entry. This may lead to incorrect operation in configurations with multiple cores and unequal cache states. Fix: move cache state to the appropriate bits of the 'cp15_control_reg' field (already present but unused). Vaule of cp15 control register stored here on arm946e_post_debug_entry(), and analyzed later in arm946e_write_memory(). Change-Id: I71ef82be00c21d6fffb3726cec4974d1ece70dfe Signed-off-by: Alexander Osipenko Reviewed-on: http://openocd.zylin.com/692 Tested-by: jenkins Reviewed-by: Freddie Chopin 2012-07-25 Joerg Fischer * : cfg: Add Hitex LPC1768-Stick using ftdi driver Add cfg files for Hitex LPC1768 Stick Website: http://www.hitex.com/?id=1602 This board has a FTDI2232D as JTAG interface, using the same layout as the Hitex STM32-PerformanceStick but with different USB PID. Main MCU is a LPC1768 from NXP. The interface config uses the ftdi driver instead of ft2232. The corresponding ft2232 layout would be "stm32stick". Change-Id: I1fd15588c5af35f7d51777d1ad958cc1dc72c6f7 Signed-off-by: Joerg Fischer Reviewed-on: http://openocd.zylin.com/763 Tested-by: jenkins Reviewed-by: Freddie Chopin 2012-07-19 Freddie Chopin * : cfg: Add config file variants using the ftdi driver instead of ft2232 part 4 - files that are currently untested Change-Id: Ic4a08fdefc99e7a9d50885c888c3fca60ffa39bd Signed-off-by: Andreas Fritiofson Signed-off-by: Freddie Chopin Reviewed-on: http://openocd.zylin.com/750 Tested-by: jenkins 2012-07-20 Freddie Chopin * : cfg: Add config file variants using the ftdi driver instead of ft2232 part 2 - files that are currently untested but assumed to work, as other configs using the same layout work fine Change-Id: Ifaa1904227ebdc394362ccaf3ad3c5384a716657 Signed-off-by: Andreas Fritiofson Signed-off-by: Freddie Chopin Reviewed-on: http://openocd.zylin.com/754 Tested-by: jenkins 2012-07-19 Spencer Oliver * : telnet: cleanup comments seems comments were mangled during the last cleanup. Change-Id: If759f62032705c7baffd3973e9717eb7e8a5d17c Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/752 Tested-by: jenkins Reviewed-by: Freddie Chopin 2012-06-07 Salvador Arroyo * : Bugfixes in mips32_pracc.c When testing a pic32mx220f032b with different values for adapter_khz and cpu clocks i was getting a lot of corrupted data from the chip. From time to time openocd fails with segmentation faults or is aborted due to memory corruption. Change-Id: I134743f75c477b3d55dc74ae4474598e153b4a4a Signed-off-by: Salvador Arroyo Reviewed-on: http://openocd.zylin.com/690 Tested-by: jenkins Reviewed-by: Andreas Fritiofson Reviewed-by: Freddie Chopin 2012-07-17 Andreas Fritiofson * : flash: reduce code duplication in stm32 flash probe Remove a lot of the repetitive code in stm32f1x flash probe by converting the large if-selector to a switch, moving the common checks outside it and concentrating the failure handling to a single point. Do the same with stm32f2x and stm32lx for consistency. Change-Id: Ic0ecfb1533c49f5d2108cda5fd20c8372d7c71ef Signed-off-by: Andreas Fritiofson Reviewed-on: http://openocd.zylin.com/746 Tested-by: jenkins Reviewed-by: Spencer Oliver Reviewed-by: Freddie Chopin 2012-07-12 Spencer Oliver * : flash: handle zero when reading stm32 flash size reg Some variants read 0 for the flash size register, rather than failing lets assume we have max flash fitted. Change-Id: Ie1fb4e73606f49268a6fd5921c3aef75bc4790d3 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/744 Tested-by: jenkins Reviewed-by: Andreas Fritiofson Reviewed-by: Freddie Chopin 2012-07-12 Spencer Oliver * : flash: add stm32l Revision X support Revision X is not mentioned in the latest RM0038 rev5, however it has been confirmed correct by ST using ST-LINK Utilty. Change-Id: I65210e512ea25818a1d0d3b223502ebd7535b29d Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/742 Tested-by: jenkins Reviewed-by: Andreas Fritiofson Reviewed-by: Freddie Chopin 2012-07-11 Andreas Fritiofson * : cfg: remove deprecated stm32 target configs These were deprecated in commit 69ac20a. Signed-off-by: Andreas Fritiofson Change-Id: I047872f8cd61b42aaca6588ab75566219e4a3f5d Reviewed-on: http://openocd.zylin.com/741 Tested-by: jenkins Reviewed-by: Freddie Chopin Reviewed-by: Spencer Oliver 2012-07-11 Andreas Fritiofson * : flash: don't write to FLASH_CR in stm32x_write_block It's unnecessary and prevents reusing this function to fix option byte writes. Also try to disable flash writing after an error. Change-Id: Ib5a7b768a1523e6b8da1555126fef4c1e60ab083 Signed-off-by: Szymon Modzelewski Signed-off-by: Andreas Fritiofson Reviewed-on: http://openocd.zylin.com/479 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-07-20 Alex Austin * : Revert "When calling openocd from a shell like this:" This reverts commit e8641695c634109ebf5f1149923971770da1d28a Original premise was wrong. Proper command is "shutdown", not "exit". Change-Id: I07f5fe0dda9c24abe53628da986bfda0e406bb4a Signed-off-by: Alex Austin Reviewed-on: http://openocd.zylin.com/757 Tested-by: jenkins Reviewed-by: Peter Stuge 2012-07-17 Freddie Chopin * : Add config file for Lattice LC4032ZE CPLD (ispMACH 4000ZE family) Change-Id: Iefec12b30ff737317c454b472200fd7e7edde619 Signed-off-by: Freddie Chopin Reviewed-on: http://openocd.zylin.com/748 Tested-by: jenkins Reviewed-by: Peter Stuge 2012-01-30 Andreas Fritiofson * : Add FTDI JTAG driver using MPSSE layer Based on ft2232.c but uses the MPSSE layer for low-level access, greatly simplifying the JTAG logic. Remove all libftdi/FTD2XX code and all layout specific code. Layout specifications are instead handled in Tcl. Use a signal abstraction to enable Tcl configuration files to define outputs for one or several FTDI GPIO. These outputs can then be controlled using the ftdi_set_signal command. Special signal names are reserved for nTRST, nSRST and LED (for blink) so that they, if defined, will be used for their customary purpose. Depending on the type of buffer attached to the FTDI GPIO, the outputs have to be controlled differently. In order to support tristateable signals such as nSRST, both a data GPIO and an output-enable GPIO can be specified for each signal. The following output buffer configurations are supported: * Push-pull with one FTDI output as (non-)inverted data line * Open drain with one FTDI output as (non-)inverted output-enable * Tristate with one FTDI output as (non-)inverted data line and another FTDI output as (non-)inverted output-enable * Unbuffered, using the FTDI GPIO as a tristate output directly by switching data and direction as necessary The data and output-enables are specified as 16-bit bitmasks, corresponding to the concatenation of the high and low FTDI GPIO registers. To specify an unbuffered output, use the same bitmask for both data and output-enable. The adapter configuration file must also specify default values for the FTDI data and direction GPIO registers, and the channel being used (if different from 0). Change-Id: I287a41d4c696cf5fc74eb10d5e63578b0dc7f826 Signed-off-by: Andreas Fritiofson Reviewed-on: http://openocd.zylin.com/452 Tested-by: jenkins Reviewed-by: Peter Stuge 2012-06-27 Spencer Oliver * : target: Cortex-M use consistent arm dap access Purely cosmetic but use the same style as Cortex-A target, this makes searching refs easier. Change-Id: I732ad9701f561e2312c5d191f5aaffd3a2f2393d Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/731 Reviewed-by: Freddie Chopin Tested-by: jenkins Reviewed-by: Andreas Fritiofson 2012-07-04 Spencer Oliver * : flash: add stm32f3x support add support for the new stm32f3x family from stmicro: http://www.st.com/stm32f3 Change-Id: Icd1db95bb2767d9c0ecef24deefa92b4fdaa4f14 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/735 Tested-by: jenkins Reviewed-by: Freddie Chopin Reviewed-by: Andreas Fritiofson 2012-06-27 Spencer Oliver * : target: detect correct Cortex-M tar auto increment size The ADIv5 spec guarentees that tar_autoincr_block will be 10bits. Make this the default for Cortex-M family until we detect a Cortex-M3/M4, we then change autoincrement to 12bits. Change-Id: Ie8c89134aa036879bdd8a3c312cee9715dbc6913 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/730 Tested-by: jenkins Reviewed-by: simon qian Reviewed-by: Freddie Chopin 2012-02-18 Stian Skjelsad * : When calling openocd from a shell like this: openocd -f board/sheevaplug.cfg -c init -c exit the calling shell will believe that openocd exited with an error due to exitval will be non-zero This is not tested against incomming telnet Change-Id: I63d15715a7b46f39a7de261a45039f8c3cad7a98 Signed-off-by: Stian Skjelstad Reviewed-on: http://openocd.zylin.com/470 Tested-by: jenkins Reviewed-by: Spencer Oliver Reviewed-by: Bill Traynor Reviewed-by: Mathias Küster Reviewed-by: Freddie Chopin 2012-05-24 Vandra Akos * : target/target.c, jim_target_md refractored - Added a few lines of comment before the function explaining the usage and the output generated by the command - Added a few lines of comment in the body explaining what is happening to improve code readability - Renamed a few variables to improve readability: * a -> addr * b -> dwidth * c -> count - Added a new variable, named byte to contain the number of bytes to read, instead of overwriting the count parameter, to avoid confusion between the two values. Change-Id: I5828ec0f5aadaa39becec7b84f198756bb2c3d41 Signed-off-by: Vandra Akos Reviewed-on: http://openocd.zylin.com/665 Tested-by: jenkins Reviewed-by: Freddie Chopin 2012-05-29 Mike Crowe * : topic: flash: description/id added for ATSAM3SD8C New flash description for ATSAM3SD8C used on SAM3S-EK2 development boards. Name used is "at91sam3sd8c" and chipid is 0x29ab0a60. Mirrors description of other similar parts. Change-Id: I7fc4b82e7969451645ab067223663f08b76d866b Signed-off-by: Mike Crowe Reviewed-on: http://openocd.zylin.com/684 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-06-04 Olivier Schonken * : Changed SAM4S Erase for effective Sector erase In the previous iteration, the page counter for erases would not be updated with the erase size. This patch keeps the page counter synced with the sector counter. Signed-off-by: Olivier Schonken Change-Id: I95e56a3257b2ad8301c9f28167b842fa6466334f Reviewed-on: http://openocd.zylin.com/686 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-05-23 Christopher Kilgour * : kinetis: update support for all program flash granularities Updates the Kinetis NOR flash support to handle all known block and sector sizes. Previously only 2kiB sectors were hard-coded, now all four known combinations non-volatile sector sizes are supported. The premise of separating Kinetis Program Flash (PFLASH) from FlexNVM is also introduced. This means each "block" of flash (in Freescale terms) is treated as a bank in OpenOCD. Correspondingly, the existing board configuration for the TWR-K60M512 eval system is updated to recognize two banks instead of one. A board config for the TWR-K60F120M is also added. Bank and sector erase and programming has been checked with both of the mentioned eval boards. Change-Id: Iae2d10ebf8f548d0a3698df5430bbbe1ccadc58a Signed-off-by: Christopher Kilgour Reviewed-on: http://openocd.zylin.com/663 Tested-by: jenkins Reviewed-by: Mathias Küster Reviewed-by: Jan Dakinevich Reviewed-by: Spencer Oliver 2012-05-28 Alexander Osipenko * : JLink: added jlink_usb_io() function jlink_usb_io() function added for basic communication, since jlink_usb_message() is more specific to JTAG transactions. To verify the patch issue "jlink config" command. Change-Id: Id7d10bd5e8985d4c77f2e0ca47fb6033db2877bf Signed-off-by: Alexander Osipenko Reviewed-on: http://openocd.zylin.com/679 Tested-by: jenkins Reviewed-by: Xiaofan Reviewed-by: Spencer Oliver 2012-05-29 Liviu Ionescu * : docs: J-Link commands added to the manual The J-Link related commands and configuration commands were added to the "8.2 Interface Drivers" section of the manual. (previously they were enumerated as comments). The 'jlink pid' was marked as Config all other as Command. A draft of a compatibility note was added, but probably a table would be more appropriate. Change-Id: Ifbe230706815196aaad4e3729ed5089d5088b769 Signed-off-by: Liviu Ionescu Reviewed-on: http://openocd.zylin.com/680 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-06-22 Mirela Tauciuc * : AT91SAM7 Flash: fixed redundant assignation warning Change-Id: Iffacdce9ce90c4ea7e0c8647860a0056b952f387 Signed-off-by: Mirela Tauciuc Reviewed-on: http://openocd.zylin.com/691 Tested-by: jenkins Reviewed-by: Øyvind Harboe 2012-05-29 Spencer Oliver * : docs: update interface support in README Change-Id: Id4b982ee426dedc85b643a71c1cdba67d0dd0ffd Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/682 Tested-by: jenkins Reviewed-by: Peter Stuge 2012-05-25 Spencer Oliver * : build: remove src file execute permission Change-Id: I42a250cdfcd03424a63cd1a255f9cf4a3c6e3ccd Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/671 Reviewed-by: Xiaofan 2012-05-23 Spencer Oliver * : target: fix segfault in arm7_9 8/16bit read Seems I5347352e7595686634bd0de13fcf6de6e55027b0 introduced an issue when reading 8/16 bit data - the in buffer was always set to 32bits. Change-Id: Ife2bb6a20fcb3ec0e486655512164f25ae9196b4 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/660 Tested-by: jenkins Reviewed-by: Mathias Küster 2012-05-09 Mathias K * : board: Add Sony Ericsson J100I Phone This patch add the Sony Ericsson J100I Phone to the board configurations. Change-Id: I083ddf067c8ecdfdda0404fe9e9df980dbb86fe8 Signed-off-by: Mathias K Reviewed-on: http://openocd.zylin.com/631 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-05-22 Bill Traynor * : jtag: fix osbdm.c typo Fixing up tiny spelling error of "receive" vs. "recieve". Change-Id: Ib143d7fdb24ac1f2b7bd4ae90cadaf2e12760ff7 Signed-off-by: Bill Traynor Reviewed-on: http://openocd.zylin.com/659 Tested-by: jenkins Reviewed-by: Xiaofan Reviewed-by: Peter Stuge 2012-05-22 Spencer Oliver * : jtag: remove opendous clang warnings Change-Id: I0285c99507931e7d13aad36f4fc559c29a52faca Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/655 Tested-by: jenkins Reviewed-by: Peter Stuge 2012-05-21 Spencer Oliver * : target: target.h typo and comment cleanup Change-Id: Ib751803754672bf556f4f65bd3f5621f6bbb7f0c Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/654 Tested-by: jenkins Reviewed-by: Bill Traynor 2012-05-14 Spencer Oliver * : target: enable TARGET_EVENT_RESUME_* events Change-Id: I7d8378f9f34c6674db8c8b29d1a961389578e921 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/640 Reviewed-by: Freddie Chopin Tested-by: jenkins Reviewed-by: Bill Traynor 2012-05-10 Spencer Oliver * : target: remove duplicate target events Change-Id: Iba9ae441f3e6d48a7dfafe59ed093fef56a34723 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/633 Reviewed-by: Freddie Chopin Tested-by: jenkins Reviewed-by: Bill Traynor 2012-05-15 Bill Traynor * : UserGuide: Updated list of supported interfaces, boards, and targets. User Guide: Chapter 6 'Config File Guidelines'. The directory listings of interfaces, boards, and targets has been brought up to date. Change-Id: I53f218a94cb81c5e90298b367259e833192af5f3 Signed-off-by: Bill Traynor Reviewed-on: http://openocd.zylin.com/646 Tested-by: jenkins Reviewed-by: Xiaofan Reviewed-by: Spencer Oliver 2012-05-14 Spencer Oliver * : NEWS: add headline items Change-Id: Ie78b0a171af76cf647deef501245caf54209d9f8 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/639 Tested-by: jenkins Reviewed-by: Freddie Chopin Reviewed-by: Xiaofan 2012-05-17 Spencer Oliver * : stlink: add myself to copyright header Change-Id: I39e23b38ee630b80bccb5ff6b5819efa0fcb120a Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/651 Tested-by: jenkins Reviewed-by: Xiaofan 2012-05-15 Spencer Oliver * : contrib: enable cortex-m0 and cortex-m4 libdcc support Change-Id: Ib8ff645d1e5b8baca02de8ea95b629d88b203969 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/644 Tested-by: jenkins 2012-05-17 Alexander Osipenko * : remote_bitbang: missed closing brace in macro REMOTE_BITBANG_RAISE_ERROR Change-Id: I591308bd98810ef6361106c207c55b83c3a83890 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/647 Tested-by: jenkins Reviewed-by: Xiaofan 2012-05-14 Spencer Oliver * : docs: add initial target rtos support info Change-Id: Idd39ce17922602aedd4626496ed8f5422bb76e07 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/641 Tested-by: jenkins Reviewed-by: Peter Stuge 2012-05-11 Spencer Oliver * : stlink: add armv7m stlink handling This enables us to better handle some of the low level functions that the stlink does not support. It also enables us to share a few more of the standard cortex_m3 functions if necessary. Change-Id: I7a2c57450122012ec189245d8879d8967913e00e Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/637 Tested-by: jenkins 2012-05-03 Spencer Oliver * : flash: fix protect check for pic32mx1x/2x family Change-Id: Ib2692d8b79e52cd40f429008047494aa7f552984 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/612 Tested-by: jenkins Reviewed-by: Xiaofan 2012-05-08 Spencer Oliver * : stlink: fix stlink api2 single step This makes the newer v2 api behave as per the v1 api, eg. single stepping masks all interrupts. A better long term solution is to use same behaviour as a cortex-m3 target, see CORTEX_M3_ISRMASK_AUTO. Change-Id: Iaf9f9adf225cf274faaac938050bb996582aa98f Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/621 Tested-by: jenkins 2012-05-04 Spencer Oliver * : stlink: stlink/v1 use v2 api if supported The api v2 is supported on the stlink/v1 if it has a least v11 firmware. Change-Id: Idfdb5a7f5a5881326017451ae9b6004eeaa46a96 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/616 Tested-by: jenkins Reviewed-by: Freddie Chopin Reviewed-by: Xiaofan 2012-05-01 Freddie Chopin * : Use hardware reset and connect under reset on boards with ST-LINK/V2, as now it is supported. Change-Id: Id3b2ca9a2270974a5f453323f9057ecece400c94 Signed-off-by: Freddie Chopin Reviewed-on: http://openocd.zylin.com/609 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-05-01 Spencer Oliver * : stlink: support connecting under reset Some targets support connecting while the target's srst is asserted. Tested on stm32 family. Change-Id: I1197dd721a1e1cbf95ee77dfd8e1082b165b22a9 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/607 Tested-by: jenkins 2012-05-08 Aurelien Jacobs * : cfi: fix write_bank segfault with spansion flash on armv7m cfi_spansion_write_block() passes an arm_algorithm struct to target_run_algorithm() which in turn calls armv7m_start_algorithm() which expect an armv7m_algorithm struct. As armv7m_algorithm is bigger than arm_algorithm, when armv7m_start_algorithm() writes in the struct, it overrun the buffer, writting junk on the stack, which latter on generates a segfault. This patch ensure we use a properly sized armv7m_algorithm struct when the target is an armv7m. Change-Id: I4ab67c15ae4bb72454414a81b92a4231dcdb2239 Signed-off-by: Aurelien Jacobs Reviewed-on: http://openocd.zylin.com/623 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-05-03 Spencer Oliver * : cfi: check supported arch check that the cfi driver supports the current target arch. Change-Id: I8a95908684de67bf1657d1956f2573662a641cc1 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/614 Tested-by: jenkins Reviewed-by: Aurelien Jacobs 2012-05-01 Spencer Oliver * : build: add missing erase_check loader src Change-Id: I1534c1ea1606fda9eb6ffa6a11a708f8c8a3d46a Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/605 Tested-by: jenkins Reviewed-by: Freddie Chopin 2012-05-11 Spencer Oliver * : contrib: fix Neo1973 udev permission typo Change-Id: I6d5ad0cc28e0cb52104ead9e974b8b1ed92d9cdc Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/636 Tested-by: jenkins Reviewed-by: Peter Stuge 2012-04-30 Spencer Oliver * : cfg: increase stm32f0discovery board working area Change-Id: Iea166ee27fc60bbfdeb851fdcf71509f3984f72f Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/602 Tested-by: jenkins Reviewed-by: Freddie Chopin 2012-05-08 Bill Traynor * : cfg: Deleted duplicate busblaster.cfg and renamed original. The busblaster.cfg was contributed on April 23, 2012 and is a duplicate of dp_busblaster.cfg that was contributed on Oct. 23, 2011. Therefore, deleting the second version. Also, renaming the original dp_busblaster.cfg to simply busblaster.cfg, as this name is more concise. Change-Id: Iccb1f10f53dbbb248b1ff4c6295eaf67c32247c1 Signed-off-by: Bill Traynor Reviewed-on: http://openocd.zylin.com/622 Tested-by: jenkins Reviewed-by: Peter Stuge 2012-05-07 Bill Traynor * : cfg: add default pid/vid pair to beaglebone board cfg. The newer versions of BeagleBone boards use the default vid/pid pair for FT2232 debugging. Please see the following README: http://beagleboard.org/static/beaglebone/latest/README.htm On revision A3/A4 boards, the VID/PID were chosen to match the TI XDS100v2 (0x0403/0xA6D0). On A5 and newer revisions when we've given the authors of CCS the chance to update their software, the generic FTDI VID/PID (0x0403/0x6010) will be used to simplify installation of drivers for systems already having those drivers. Change-Id: I44228eb2029162f23d084eb05bcfef39e615668d Signed-off-by: Bill Traynor Reviewed-on: http://openocd.zylin.com/619 Tested-by: jenkins Reviewed-by: Peter Stuge 2012-04-27 Spencer Oliver * : build: remove clang unused variable increments warnings Change-Id: Ib755474aa46f7233495fae1947bc27cd0b2d6b4f Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/599 Tested-by: jenkins Reviewed-by: Freddie Chopin 2012-04-27 Spencer Oliver * : cfg: allow stm32discovery parameter override This enable the user or board config to override the parameters passed to stm32_stlink.cfg. Required to fix a incorrect working area bug with the stm32vldiscovery. Change-Id: I40a4f7913ff37d577d44b1f23befccf0317080a1 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/597 Tested-by: jenkins Reviewed-by: Freddie Chopin 2012-04-19 Spencer Oliver * : stlink: support srst reset This adds the ability to support srst reset for the stlink/v2. stlink/v1 will fallback to using SYSRESETREQ which is a full reset - including peripherals. To enable the use of the srst add the following to your cfg: reset_config srst_only Change-Id: I570de607c5f370fd6a4abf47360686c9be07bcdd Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/581 Tested-by: jenkins Reviewed-by: Mathias Küster Reviewed-by: Freddie Chopin 2012-04-19 Spencer Oliver * : stlink: add hardware srst functions to stlink/v2 Change-Id: Ib82b6a1116b9f396f1933cc5526733334254fd62 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/579 Tested-by: jenkins Reviewed-by: Freddie Chopin Reviewed-by: Mathias Küster 2012-04-19 Spencer Oliver * : stlink: default to latest api available Change-Id: Ic04128f4020055587bb87250f41e5c804d9c2b01 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/577 Tested-by: jenkins Reviewed-by: Mathias Küster Reviewed-by: Freddie Chopin 2012-04-05 Spencer Oliver * : stlink: support stlink api result The stlink api does support results for some functions - add support. Change-Id: I39cb495408c46af8bc343b198a1e0bd4c7aee6d8 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/560 Tested-by: jenkins Reviewed-by: Mathias Küster Reviewed-by: Freddie Chopin 2012-03-18 Olivier Schonken * : topic: Added support for the SAM4S variants Atmel introduced 6 new Cortex-M4 processors on 2011-10-26 SAM4S16C - 1024KB flash LQFP100/BGA100 SAM4S16B - 1024KB flash LQFP64/QFN64 SAM4S16A - 1024KB flash LQFP48/QFN48 SAM4S8C - 512KB flash LQFP100/BGA100 SAM4S8B - 512KB flash LQFP64/QFN64 SAM4S8A - 512KB flash LQFP48/QFN48 The SAM4S processors still suffer from the "6 waitstates needed to program device" errata. Other relevant changes are: 1. Address of flash memory starts at 0x400000. 2. EWP (Erase page and write page) only works for the first two 8KB "sectors" 3. Because of the EWP not working for all the sectors, normal page writes have to be used. The default_flash_blank_check is used to check if lockregions should be erased. 4. The EA (Erase All) command takes 7.3s to complete. (Previous timeout was 500 ms) 5. There are 128 lockable regions of 8KB each. Implemented default blank checking, and page erase for load_image scenarios. This is to compensate for the EWP flash commands only working on the first 2 8KB sectors. Change-Id: I7c5a52b177f7849a107611fd0f635fc416cfb724 Signed-off-by: Olivier Schonken Reviewed-on: http://openocd.zylin.com/528 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-04-24 Linus Tolke * : topic: Ignored TAGS files. Allow use of TAGS. Change-Id: I5e71e8986671642b49cc9a62d37cc8c0dfa37181 Signed-off-by: Linus Tolke Reviewed-on: http://openocd.zylin.com/595 Reviewed-by: Peter Stuge Tested-by: jenkins 2012-04-22 Bill Traynor * : UserGuide: Fixing link to USBprog tool. In section '2.8 USB Other' updated the link to the USBprog tool: http://shop.embedded-projects.net/ Change-Id: I7fa453934ac6a7889e01b22b7e0cb07f42ee168d Signed-off-by: Bill Traynor Reviewed-on: http://openocd.zylin.com/591 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-04-22 Bill Traynor * : UserGuide: Fixed link to Wiggler2 project. In section '2.9 IBM PC Parallel Printer Port based' fixed link to the Wiggler2 project and removed the alternate URL text to retain style consistency with the other URLs in the document: http://www.ccac.rwth-aachen.de/~michaels/index.php/hardware/armjtag Change-Id: I879db1c6eaf683ca6475a0f466f987087c9d60d0 Signed-off-by: Bill Traynor Reviewed-on: http://openocd.zylin.com/593 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-04-22 Bill Traynor * : UserGuide: Fixing two typos. In Section 2.7 USB ST-LINK based made these two changes: "they only works with" to "they only work with" "following method's" to "following methods" Change-Id: Idfe6c11c3fa6f2157d01697cd7f480a9d495c8e2 Signed-off-by: Bill Traynor Reviewed-on: http://openocd.zylin.com/590 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-04-15 Uwe Hermann * : Split olimex_stm32_h107.cfg. Use one board file per eval board, so that the filename matches the exact board the user has / wants to use. Merging different boards into one file is confusing. Change-Id: I7c50233924a87a913723d7215c4851039c2971bc Signed-off-by: Uwe Hermann Reviewed-on: http://openocd.zylin.com/566 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-04-19 Bill Traynor * : UserGuide: Update Section 2.3 USB FT2232 Based Updated the link for the usbjtag project to the correct URL: http://elk.informatik.fh-augsburg.de/hhweb/doc/openocd/usbjtag/usbjtag.htmlAdded a NOTE to indicate the axm0432_jtag as no longer being available from the axman.com page. Change-Id: I70727303dad58d9dc0c5f9b7cce219288b762042 Signed-off-by: Bill Traynor Reviewed-on: http://openocd.zylin.com/583 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-04-19 Bill Traynor * : UserGuide: Fixed link to USB-JTAG project. Updated the URL to Kolja Waschk's USB-Blaster compatible adapter: http://ixo-jtag.sourceforge.net/ Change-Id: If9d2875b5ba5d3bfaaf524cd253a5fab53e05371 Signed-off-by: Bill Traynor Reviewed-on: http://openocd.zylin.com/585 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-04-18 Bill Traynor * : HACKING: Fix instruction for git pull --rebase When following the Patch Guidelines step by step, an error occurs at step 6. "git pull --rebase origin/master" results in the error: fatal: 'origin/master' does not appear to be a git repository Removing the / seems to fix this. Change-Id: I4e2fa23c60654abeaebd3b25a8c8375aa07b0abd Signed-off-by: Bill Traynor Signed-off-by: Peter Stuge Reviewed-on: http://openocd.zylin.com/574 Reviewed-by: David Anders Tested-by: jenkins 2012-04-18 David Anders * : pandaboard: add initial TCL support for pandaboard-es add initial TCL support for the pandaboard-es which is based on the omap4460 from Texas Instruments. Change-Id: Ic63588721487feb95e7cb3d41cfaab0d2f181766 Signed-off-by: David Anders Reviewed-on: http://openocd.zylin.com/573 Tested-by: jenkins Reviewed-by: Peter Stuge 2012-04-18 Spencer Oliver * : cfg: add stm32f0discovery board config Change-Id: I4fccdbd4e0a3bc70cd425c910ad1007519098e20 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/570 Reviewed-by: Peter Stuge Tested-by: jenkins 2012-04-05 Spencer Oliver * : stlink: correctly format printed hex addresses Change-Id: I4a139989927249bb5e9dcc4804965c85c37cc09b Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/559 Tested-by: jenkins Reviewed-by: Andreas Fritiofson 2012-04-04 Stephane Bonnet * : ft2232: Support for Digilent HS1 USB adapter * Added support to the FT2232 driver for the FT2232H-based Digilent HS1 adapter. Change-Id: Iab6cc15f299badaf115615b5d4d785ecb2273c27 Signed-off-by: Stephane Bonnet Reviewed-on: http://openocd.zylin.com/558 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-03-27 Wjatscheslaw Stoljarski (Slawa) * : cfg: add imx53loco board config Add board config for iMX53QSB (loco) Change-Id: I8659dcd71a56d5fe855eaf62be0a415198b558c5 Signed-off-by: Wjatscheslaw Stoljarski (Slawa) Reviewed-on: http://openocd.zylin.com/542 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-04-04 Simon Widmer * : Support for KaRo TX25 CPU Module on a StarterkitV base board This patch adds support for the KaRo TX25 module on a StarterkitV base board. For board details, check http://www.karo-electronics.com/tx25.html Change-Id: I2c80c5467bc476955b55196728aa3c37c8185e6c Author: Simon Widmer Signed-off-by: Mark Vels Reviewed-on: http://openocd.zylin.com/557 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-04-04 Spencer Oliver * : doxygen: remove warnings Change-Id: I020845a8df7b67f3b6c1a233b3ee07a5d14fa685 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/556 Tested-by: jenkins 2012-04-02 Salvador * : Minor bug fixes in Mips32 code Now the the "Fast" version for memory blank check in pic32mx.c can be called: default_flash_blank_check() instead of the "fallback" default_flash_mem_blank_check(). The command "verify_image", without working area, now don't show: checksum mismatch - attempting binary compare when there are no real errors in flash. Change-Id: I256e8ae949289634e1de5c1c2861e4c4c4b7fdce Signed-off-by: Salvador Reviewed-on: http://openocd.zylin.com/549 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-03-30 Spencer Oliver * : docs: remove unused primer ref we already have a link to the patch primer in the main index. Change-Id: Ib90ade76a17f5d99da8fe481d8f87c68eca38f1c Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/546 Tested-by: jenkins 2012-04-02 Uwe Hermann * : Initial config for the Voltcraft DSO-3062C. This is a digital oscilloscope which uses a Samsung S3C2440 internally. http://randomprojects.org/wiki/Voltcraft_DSO-3062C Signed-off-by: Uwe Hermann Change-Id: I5e28c3a8f30665a162e34c831294e4e658a16ebb Reviewed-on: http://openocd.zylin.com/548 Tested-by: jenkins Reviewed-by: Peter Stuge 2012-03-20 Spencer Oliver * : jimtcl: update to version 0.73 Change-Id: I9c943abb3ec5148b9cb24d0823f7787066948201 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/536 Tested-by: jenkins Reviewed-by: Øyvind Harboe 2012-03-15 Mathias K * : stm32: Update register read/write to the register definition. This patch fix the register index on read/write register. Change-Id: I7b52a927a48259d6f497ac0f474aff7ff1529e9a Signed-off-by: Mathias K Reviewed-on: http://openocd.zylin.com/525 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-03-30 Spencer Oliver * : build: correctly quote m4 parameters Change-Id: I8fbef892caa78dba5324a8bc28d2a4a4854b1f48 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/544 Tested-by: jenkins 2012-03-26 Spencer Oliver * : cfg: add STM32F4x and STM3241G-EVAL config files This adds support for the STM32F4 target and the STM3241G Eval Board, in both standalone and using the onboard STLINK. Change-Id: I62f8908b5880568b2b36c78a78f94c40861ff335 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/540 Tested-by: jenkins 2012-03-06 Olivier Schonken * : Added tcl config scripts for SAM3A/X targets and devboard The SAM3A/X processors that were released thus far is either a SAM3A/X(4) - 256K, or a SAM3A/X(8) - 512K device. Thus the config files are per variant, and not per device. Signed-off-by: Olivier Schonken Change-Id: I84d26d044e810eb428b1d6287907ea3bf8364c73 Signed-off-by: Olivier Schonken Reviewed-on: http://openocd.zylin.com/522 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-03-20 Spencer Oliver * : tools: update release scripts to use configure.ac we have already updated autoconf to use configure.ac instead of configure.in, so update release.sh to use the new name. Change-Id: I2dc2beaf2f85058c4627183bc093052677ccba1b Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/537 Tested-by: jenkins 2012-03-08 Chris Morgan * : Create a init_board procedure for the ea dev board. Signed-off-by: Chris Morgan Change-Id: I082b0d3092c7f3b2ee6b68af64d48c78b31f1dbf Reviewed-on: http://openocd.zylin.com/510 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-03-17 Salvador * : Bug in src/target/mips32_pracc.c The bug shows up with the command "mdw addres count" and only if count>1024 (count>0x400). The first 1024 values shows as expected, but the rest of the values are wrong. Name of variable bytesread" is changed to "wordsread" to reflect what really does. Change-Id: Iad79393e72da2637551c5ae6e829e3873605c520 Signed-off-by: Salvador Reviewed-on: http://openocd.zylin.com/527 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-03-15 Mathias K * : gdb_server: Simple close the connection and not exit openocd. This patch let openocd running and only close the gdb connection on error. Change-Id: Ifb88e16834b51207cc4c82210eab904ed8d30b71 Signed-off-by: Mathias K Reviewed-on: http://openocd.zylin.com/523 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-03-14 Paul Fertser * : rtos: add sanity checking for FreeRTOS's quantity of priorities On operating systems with opportunistic malloc() (e.g. default setting in GNU/Linux) malloc can sometimes allocate a huge memory region but later the process will get killed on the first attempt to use this memory, so checking for malloc's return value is not enough to prevent a crash. This patch is compile-tested only. Change-Id: I5e21663115c8e9a0ca9f3d71f7ba4bd09e5c3bb1 Signed-off-by: Paul Fertser Reviewed-on: http://openocd.zylin.com/521 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-02-24 Alexandre Pereira da Silva * : stlink: fix alignment build warning The {read,write}_mem32 interface functions was asking a 32 bits buffer but they don't need 32 bits alignment. This will change the interface to a 8 bits buffer to remove the alignment mismatch warning. This was causing build errors on platforms with strict aliasing rules. Change-Id: I338be8df5686f07a64ddb4f17c1bb494af583999 Signed-off-by: Alexandre Pereira da Silva Reviewed-on: http://openocd.zylin.com/483 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-03-13 Mathias K * : armv7m: Add a dummy register at the end of the register list. Signed-off-by: Mathias K Change-Id: I0bfad091bd8adabd949fc0a74ef3a08a514eb307 Reviewed-on: http://openocd.zylin.com/519 Reviewed-by: Peter Stuge Tested-by: jenkins 2012-03-12 Mathias K * : stm32: determine all cpu types and use common examine This patch determine all cpu types and not only the cortex M3 and the stm32 target use the common target examine function from the cortex_m sources. Change-Id: If689dd994b3855284b927fc4b206f420cf32b6c7 Signed-off-by: Mathias K Reviewed-on: http://openocd.zylin.com/511 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-03-08 Mathias K * : Automatically prepend v1 mass storage protocol. This patch prepend the v1 mass storage protocol to the command buffer and simplify the usb read/write handling. Change-Id: I709602600e93cd1eb5848fa9f4d15659ba85eb35 Signed-off-by: Mathias K Reviewed-on: http://openocd.zylin.com/506 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-03-12 Spencer Oliver * : cfg: correct pic32mx config typo's Change-Id: Ibe5b6b0efefc7cfc75d789eb7e9c7ee239526ae2 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/508 Tested-by: jenkins 2012-02-28 Jan Dakinevich * : jtag: basic support for P&E Micro OSBDM (aka OSJTAG) adapter This driver provides support for the P&E Micro OSBDM adapter (sometimes named as OSJTAG), mounted on the Freescale TWRK60N512 bord. Thus, it provides a quick start when working with this board. The driver doesn't use BDM commands, but work with OSBDM adapter using only JTAG commands. Change-Id: Ibc3779538e666e07651d3136431e5d44344f3b07 Signed-off-by: Jan Dakinevich Reviewed-on: http://openocd.zylin.com/492 Tested-by: jenkins Reviewed-by: Tomas Frydrych Reviewed-by: Spencer Oliver 2012-03-08 Spencer Oliver * : docs: add stm32 dual bank example Change-Id: I1dfe134e2c7694fc978d14b4b21bdf9c82ca4b16 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/507 Tested-by: jenkins 2012-03-05 Øyvind Harboe * : flash: retire unused eCos flash driver even the AT91EB40a's flash is covered by CFI and nobody ever submitted any other drivers based on eCos code. It's just possible that this idea was missing documentation and "marketing", but it's in git if somebody wants to resurrect it. Change-Id: I66449aa6e0997301f9d67f28098789bfc891d6e9 Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/502 Tested-by: jenkins Reviewed-by: Øyvind Harboe 2012-02-25 Szymon Modzelewski * : flash: stm32f1x: add a couple missing stm32x_get_flash_reg Change-Id: I163de2c1bd962e7ea9ca6c741c1c62224c210677 Signed-off-by: Szymon Modzelewski Reviewed-on: http://openocd.zylin.com/486 Tested-by: jenkins Reviewed-by: Andreas Fritiofson Reviewed-by: Spencer Oliver 2012-02-29 Spencer Oliver * : stlink: fix incorrect pc console output target_call_event_callbacks needs to be called after debug entry otherwise we will get a console pc mismatch. Change-Id: I278137736d5e85ca9662c306f6ac81336d8eb6cf Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/499 Tested-by: jenkins Reviewed-by: Øyvind Harboe 2012-02-28 Attila Kinali * : SAM3: Remove unused reference to SUPC registers The SUPC (Supply Controller) registers are on different base addresses on different SAM3 chips: SAM3U: 0x400e1210 SAM3N: 0x400e1410 SAM3S: 0x400e1410 This creates a problem with the sam3_reg_list array which is const, but would need to be changed at runtime to account for this variability. As this register is not used anywhere, it's simplest to just remove it. Change-Id: I987eb371648d826aa6d5e9de18d38c7bb66d6fca Signed-off-by: Attila Kinali Reviewed-on: http://openocd.zylin.com/495 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-02-28 Attila Kinali * : SAM3S: correct flash sector sizes. Lock region count and sector sizes did not match datasheet. (see 6500C-ATARM-8FE11 "SAM3S Series Datasheet", Table 7-1) Change-Id: Ic511802f96ed03856467a24a6736349205a0576a Signed-off-by: Attila Kinali Reviewed-on: http://openocd.zylin.com/493 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-02-21 Szymon Modzelewski * : stlink-v1: fix memory writes implement stlink_usb_send and use it to fix stlink_usb_write_mem using two calls to stlink_usb_recv is inappropriate since each call issues a SG command on stlink-v1, resulting in errors Change-Id: I24ef9f2dda284e041dc4a532b59968a77eebe702 Signed-off-by: Szymon Modzelewski Reviewed-on: http://openocd.zylin.com/498 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-02-21 Szymon Modzelewski * : stlink-v1: code cleanup This patch moves the bulk of the stlink read/write code into the stlink_usb_xfer set of functions and implements stlink_usb_recv in terms of the generic stlink_usb_xfer stlink_usb_xfer will be needed to implement stlink_usb_send without code duplication stlink_usb_xfer: -sends the stlink command -performs a read or write (as requested) -checks the status (v1 only) Change-Id: I0137d52620bd4883d46c9977a9e73f67622000a1 Signed-off-by: Szymon Modzelewski Reviewed-on: http://openocd.zylin.com/477 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-02-17 Spencer Oliver * : flash: add stm32lx High Density Devices Change-Id: Ieed9de4b078e1ebf659054a758b4f69acdf5b83e Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/466 Tested-by: jenkins 2012-02-21 Szymon Modzelewski * : stlink-v1: fix memory writes implement stlink_usb_send and use it to fix stlink_usb_write_mem using two calls to stlink_usb_recv is inappropriate since each call issues a SG command on stlink-v1, resulting in errors Change-Id: I52ff9ee8f5d9ae0d47356477468eb98952205c99 Signed-off-by: Szymon Modzelewski Reviewed-on: http://openocd.zylin.com/478 Tested-by: jenkins Reviewed-by: Mathias Küster Reviewed-by: Spencer Oliver 2012-02-24 Neil Jensen * : cfg: Beaglebone/AM335x refactor Split out functions specific to the AM335x SOC into the target directory and simplified the board config file. This should allow one to quickly create new configs for boards based on the TI processor family. Change-Id: I0c3db97950dfa832f1f1918fc10c180f068bba74 Signed-off-by: Neil Jensen Reviewed-on: http://openocd.zylin.com/489 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-02-21 Spencer Oliver * : jtag: use correct tap -ignore-version mask when -ignore-version is used we should mask of the upper 4bits not 8bits. Change-Id: I9ffe24c2aeeb414677357a647609fdf018890194 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/473 Tested-by: jenkins 2012-02-16 Spencer Oliver * : flash: add stm32f2x async flash loader This enable the stm32f2x flash driver to use the asynchronous algorithm support. Speed increase is as follows: before - wrote 1048576 bytes from file stm32f4x.bin in 30.453804s (33.625 KiB/s) after - wrote 1048576 bytes from file stm32f4x.bin in 23.679497s (43.244 KiB/s) This also fixes a bug that was in the old flash loader. The old loader waited while bit16 of the status reg was 0, the new loader waits until this bit is 0 as stated in the flash spec. Bizarrely this bug did not effect programming on any tested parts. Change-Id: I3efc94d42cbe81283673a8f4203700638080af6e Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/460 Tested-by: jenkins 2012-02-10 Spencer Oliver * : target: add target async algorithm support Currently the stm32f1x flash driver uses an asynchronous algorithm as part of the block flash programming. This greatly speeds up flash programming as the target is always running. Moving the async code to the target enable other targets to use this added functionality. Change-Id: I8e53f094c2ef7848a7f86ddb9a35b6edbfc8454a Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/402 Tested-by: jenkins Reviewed-by: Andreas Fritiofson 2012-02-18 Neil Jensen * : cfg: Beaglebone Support Added support for the Beaglebone board based on the am335x processor family. After much trial and error, I was able to configure the Icepick-D and connect to the processor, halt execution, and run a sample program. This is a unified config file (it doesn't use any include statements) and further work needs to be done to split out the icepick-d configuration to be more generic. Change-Id: Ia1b8e9f01f56bd4f8c575ba3d0160c248583a15e Signed-off-by: Neil Jensen Reviewed-on: http://openocd.zylin.com/471 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-02-13 Andreas Fritiofson * : target: rewrite working area allocator The existing allocator couldn't reuse a freed allocation if the sizes didn't match exactly. That led to problems when for example a flash write routine had allocated all of the working area to speed up operation. A subsequent verify pass couldn't allocate space for the checksum algorithm even though all previous allocations had been freed. This allocator is marginally more complex, but solves the above problem by splitting larger free areas to fulfill smaller requests and by merging released areas into adjacent free areas. An initial free area, covering the entire specified address range, is set up on first allocation, and all allocations are split off from (and ultimately merged into) that one. It can also easily be adapted to support several disjoint working areas for the same target, by setting up several initial free areas and slightly modifying the merge code. Change-Id: I6faaf9801312bb19a4fa4474694a0cd1c6e0ab54 Signed-off-by: Andreas Fritiofson Reviewed-on: http://openocd.zylin.com/445 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-02-21 Spencer Oliver * : stlink: support expected-id 0 This brings the stlink driver inline with the rest of OpenOCD. If the user configures the tap as -expected-id 0 then the IDCODE will be treated as a wildcard and ignored. Change-Id: I99160c69b2b40f5b1f608bb59ab6630894502fd8 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/476 Tested-by: jenkins Reviewed-by: Mathias Küster 2012-02-18 Stian Skjelsad * : Sometime in the past, nand_fileio_finish started to return ERROR_OK (with the value of zero) on success. Change-Id: Ifb743c1617e2a6071a87c901fae8165969efcdbf Signed-off-by: Stian Skjelstad Reviewed-on: http://openocd.zylin.com/468 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-02-17 Jonathan Dumaresq * : Fix Typo in cfg file Change-Id: Id91ef70988212185f9ec653cbf5dc4e1defb1b9e Signed-off-by: Jonathan Dumaresq Reviewed-on: http://openocd.zylin.com/464 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-02-14 Spencer Oliver * : stlink: add arm semi-hosting support Change-Id: Ib275d451a9201580f08ced090e50cf45eb3ab3e2 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/459 Tested-by: jenkins 2012-02-14 Spencer Oliver * : docs: fix texinfo warnings A period or comma must follow the closing brace of an @xref. Change-Id: I272f1e7fac8f1fee4844f485b0b8e2e4e9cf352d Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/456 Tested-by: jenkins Reviewed-by: Øyvind Harboe 2012-02-07 Jonathan Dumaresq * : Add stm32f0x target Change-Id: I4abfef4459b7e2780d17bdd7623fd1ef797cc8ea Signed-off-by: Jonathan Dumaresq Reviewed-on: http://openocd.zylin.com/437 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-02-16 Mathias K * : Add bootloader mode. This patch add the bootloader define. Change-Id: I280a8a35c3514910dd381de3ab8ad59c9bd74ca1 Signed-off-by: Mathias K Reviewed-on: http://openocd.zylin.com/455 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-02-13 Spencer Oliver * : docs: correct small typo Change-Id: I5e8bea591274b4032d3e04c4be7e9110138d5bc2 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/447 Tested-by: jenkins Reviewed-by: Peter Stuge 2012-02-04 James Robinson * : topic: Add support for i.MX28EVK Added the file imx28.cfg to the target directory Added the file imx28evk.cfg to the board directory Change-Id: I02a74a03f3773892f830d13660ffdded34f3261d Signed-off-by: James Robinson Reviewed-on: http://openocd.zylin.com/428 Tested-by: jenkins Reviewed-by: Øyvind Harboe Reviewed-by: Spencer Oliver 2012-02-10 Spencer Oliver * : cfg: add revb ek-lm3s811 board config Add board config for older (revb) ek-lm3s811 Change-Id: I75aca1714de3e88b60d00fa0f99f2c4b076b569c Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/444 Tested-by: jenkins Reviewed-by: Peter Stuge 2012-02-10 Spencer Oliver * : cfg: add stm32ldiscovery board config Change-Id: I392fdc4c588783fda1c7d4d6413b86ae9aa3f6b9 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/442 Tested-by: jenkins Reviewed-by: Peter Stuge 2012-02-03 Freddie Chopin * : Add init_board procedure executed after init_targets This adds init_board procedure that behaves exactly the same as init_targets - it can be overriden by "next level" scripts. This procedure is executed after init_targets, allowing common stuff (jtag chain, memory, flash, ...) to be configured in target script (via init_target) and leaving rest (like additional memory, reset configuration, reset-init handlers, ...) to be done in init_board. This makes init_targets scheme more complete and easier to use - current board scripts will not need new init_targets, because everything can be "packed" in init_boards. Moreover it solves the problem of variables being set in init_targets (executed after init), which were not accessible by "linear" scripts (parsed before init). All that has to be done is to enclose all code in board config file in init_board procedure. Change-Id: I0736b1ff9873a687966407d62b58ccf29a8e597b Signed-off-by: Freddie Chopin Reviewed-on: http://openocd.zylin.com/427 Reviewed-by: Chris Morgan Tested-by: jenkins Reviewed-by: Peter Stuge 2012-02-06 Spencer Oliver * : cfg: add stm32vldiscovery board config Change-Id: I6343d1e61153ba71c71f8a473171972abb8e400d Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/432 Tested-by: jenkins Reviewed-by: Mathias Küster Reviewed-by: Andreas Fritiofson 2012-02-01 Freddie Chopin * : Export _TARGETNAME from generic LPC2xxx script Make _TARGETNAME variable global so it could be used by scripts sourcing it. Change-Id: Iaf1c3b53875734658b1b8f136c9bb958988b56bf Signed-off-by: Freddie Chopin Reviewed-on: http://openocd.zylin.com/421 Tested-by: jenkins Reviewed-by: Chris Morgan Reviewed-by: Øyvind Harboe 2012-02-05 Spencer Oliver * : build: cleanup src/target directory Change-Id: Ia055b6d2b5f6449a38afd0539a8c66e7d7e0c059 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/430 Tested-by: jenkins 2012-02-02 Spencer Oliver * : checkpatch: remove __packed and __aligned checks These checks are specific to linux kernel. Change-Id: Ia9b837b5609922a897822f1d55f96f04c0f1f838 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/424 Tested-by: jenkins 2012-02-02 Spencer Oliver * : checkpatch: increase line length to 120 Change-Id: I963385d0a4880f2b1e55208c8dfe65c1870ac6e1 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/422 Tested-by: jenkins 2012-01-31 Spencer Oliver * : build: cleanup src/flash/nand directory Change-Id: I21bb466a35168cf04743f5baafac9fef50d01707 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/419 Tested-by: jenkins 2012-01-30 Spencer Oliver * : build: cleanup src/rtos directory Change-Id: I24bc62d12409dbfc20a0a986acf6b3f2c913e36d Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/416 Tested-by: jenkins 2012-01-30 Spencer Oliver * : checkpatch: remove volatile check We may enable this again - but at the moment is causing extra issues with reformatting the codebase. Change-Id: I5a2aaaa32ad784e011dff3079ff45501452c1819 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/414 2012-01-30 Spencer Oliver * : build: cleanup src/server directory Change-Id: I6410df28c5999f5cbee2d3bcaa02469a29ea4c15 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/412 Tested-by: jenkins 2012-01-27 Spencer Oliver * : build: cleanup src/xsvf directory Change-Id: I5325980b240fba841d8cce81985f4da369ad9052 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/410 Tested-by: jenkins 2012-01-27 Spencer Oliver * : build: cleanup src/pld directory Change-Id: I9edb027c76e5d7fe21d557a11e6a9691fa581e86 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/408 Tested-by: jenkins 2012-02-05 Spencer Oliver * : build: update uncrustify config This config has been updated for 0.59 Change-Id: If0dc87dd5de052c1228743a196a3198dbd4bc279 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/406 Tested-by: jenkins 2012-01-25 Andreas Fritiofson * : stm32f1x: fix bug in flash loader and restrict instruction set to armv6-m Correct the offset to the read pointer when clearing it on error. Also restrict the instruction set to armv6-m so the flash driver can be used on Cortex-M0 parts with the same flash controller. Change-Id: I380f9dabcc41fb6e4d43a7e02f355e2381913f39 Signed-off-by: Andreas Fritiofson Reviewed-on: http://openocd.zylin.com/399 Tested-by: jenkins Reviewed-by: Freddie Chopin Reviewed-by: Jonathan Dumaresq Reviewed-by: Spencer Oliver 2012-01-23 Mathias K * : STLINK: add stlink v1 configuration Change-Id: I6b9de16879ff928d60e3c4a64731449275291cc2 Signed-off-by: Mathias K Reviewed-on: http://openocd.zylin.com/397 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-01-25 Mathias K * : STLINK: swd transport renamed and jtag+swim transport added This patch add jtag support to the stlink driver add two new transport types, JTAG and SWIM. Change-Id: I7089d74250330be5c6a01c24066307641df7d11e Signed-off-by: Mathias K Reviewed-on: http://openocd.zylin.com/393 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-01-25 Spencer Oliver * : flash: fix stellaris class regression for some reason the following commit was incorrect 769064de4bd8fc59804c37a418b83fcdba6fd36f Only the Sandstorm and Fury class should write this register. Change-Id: Ie18f1da6e9b59fb99cca47aa93c7f2fee447ccea Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/400 Tested-by: jenkins 2011-12-02 Fujitsu FM3 Application Team * : flash: cleanup/reformat fm3 flash driver Signed-off-by: Fujitsu FM3 Application Team Change-Id: Iaf0bacfa5438a0213a65a3d60e7d461965a5a1ac Reviewed-on: http://openocd.zylin.com/249 Reviewed-by: Øyvind Harboe Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-01-17 Timo Ketola * : i.MX25: Set OOB size (MXC NFC) SPAS register (OOB size) is left wrong after reset with respect to 2KiB page NAND chip. That will lead to ECC errors after 'reset halt'. Change-Id: If5a4685cb8d6be35879453951611ef1059da219c Signed-off-by: Timo Ketola Reviewed-on: http://openocd.zylin.com/384 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-01-20 Spencer Oliver * : cfg: add missing Stellaris Blizzard info Change-Id: I1d6fb9a2ec8d87267a266f68c01ce032450e45d5 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/392 Tested-by: jenkins 2012-01-17 Spencer Oliver * : flash: cleanup stellaris device class detection read the target class during probe and save for later use. Change-Id: Ib3ad20edc7d206b7f434bdcc6b947e6a5f06dd1f Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/388 Tested-by: jenkins 2012-01-13 Spencer Oliver * : stlink: enable cortex special reg writes Change-Id: I5aa02e8de6dd5ac5a6ca628ba4068decb200c689 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/378 Tested-by: jenkins 2012-01-19 Spencer Oliver * : flash: print bank usage on failure This makes use of the newly introduced usage field in the flash bank structure. Also remove the assertion if usage field is null and lets print a DEBUG_LOG message instead. Change-Id: I384bf0e2c444fcc99deef73aec9ef01149a91c76 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/391 Tested-by: jenkins 2012-01-17 Timo Ketola * : doc: Update patch procedure Change-Id: I3e50357b4ddaf483712bbac68b6427b31529f666 Signed-off-by: Timo Ketola Reviewed-on: http://openocd.zylin.com/387 Tested-by: jenkins Reviewed-by: Øyvind Harboe Reviewed-by: Spencer Oliver 2012-01-16 Spencer Oliver * : cmd: add missing usage vars we should have caught them all - hopefully. Change-Id: I35435317fccaf5ad0216244d69f76db6857bb582 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/381 Tested-by: jenkins Reviewed-by: Øyvind Harboe 2012-01-06 Michel JAOUEN * : u8500: linux rtos config Change-Id: I21a9dcc5fb260095aed2217e467b74ebecb39afb Signed-off-by: Michel JAOUEN Reviewed-on: http://openocd.zylin.com/349 Tested-by: jenkins Reviewed-by: Øyvind Harboe 2012-01-03 Michel JAOUEN * : rtos : create qsymbol interface and add str_to_hex interface Change-Id: I1b26f7efd3ad4a060f772dd12408e77a03d93cea Signed-off-by: Michel JAOUEN Reviewed-on: http://openocd.zylin.com/347 Tested-by: jenkins Reviewed-by: Evan Hunter Reviewed-by: Øyvind Harboe 2012-01-03 Michel JAOUEN * : rtos : ps command Change-Id: I1b00b6d72f425826c33b0df7dd63114ce642ce93 Signed-off-by: Michel JAOUEN Reviewed-on: http://openocd.zylin.com/345 Tested-by: jenkins Reviewed-by: Evan Hunter Reviewed-by: Øyvind Harboe 2012-01-03 Michel JAOUEN * : rtos : current_threadid move to rtos context Change-Id: I49d9d6d64c418be601d8723cb3eea9c3716ecb6b Signed-off-by: Michel JAOUEN Reviewed-on: http://openocd.zylin.com/343 Tested-by: jenkins Reviewed-by: Evan Hunter Reviewed-by: Øyvind Harboe 2012-01-03 Michel JAOUEN * : rtos : remove unused parameter Change-Id: I98c9f28a0085bd4713b694181ab544777091eac6 Signed-off-by: Michel JAOUEN Reviewed-on: http://openocd.zylin.com/341 Tested-by: jenkins Reviewed-by: Øyvind Harboe 2012-01-12 Mathias K * : stlink: handle wrong initialization file if no layout was specified This patch remove the hardcoded default layout and return an error if no layout was specified in the configuration file. Change-Id: I0e7833faa2dc194e727122840bcbdacd321cc4fd Signed-off-by: Mathias K Reviewed-on: http://openocd.zylin.com/369 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-01-12 Mathias K * : stlink: add read/write 8bit memory This patch add layout api funtions and implementation to read/write 8bit memory. Change-Id: I8d145eb07e5afa9ce1830578e57d80a80d21e7dc Signed-off-by: Mathias K Reviewed-on: http://openocd.zylin.com/366 Tested-by: jenkins Reviewed-by: Spencer Oliver 2012-01-12 Spencer Oliver * : stlink: correctly signal stlink_interface_open failure give the user a error msg on open failure. Change-Id: If4a57bac7f3e1746c2a05c7a96747a38da188041 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/368 Tested-by: jenkins Reviewed-by: Mathias Küster 2012-01-09 Spencer Oliver * : flash: detect stm32f4x device id errata This allows us to detect a device arrata where the device id returned is incorrect. This issue only effects stm32f4x Rev A silicon. Change-Id: Ic9f4985f9abf562f97322dcf484199f0a4eb01bb Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/354 Tested-by: jenkins 2012-01-09 Spencer Oliver * : stlink: add dummy speed handlers Change-Id: I0445be7867637728145941b06225dc0acc5380e8 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/355 Tested-by: jenkins 2012-01-10 Mathias K * : optimize: replace while loop by memcpy There is no need to use a while loop here. This patch simple copy the last bytes with the system function. Change-Id: Ibda72dca449746efeba5a1af2e45c5990f9cf347 Signed-off-by: Mathias K Reviewed-on: http://openocd.zylin.com/364 Tested-by: jenkins Reviewed-by: Øyvind Harboe Reviewed-by: Spencer Oliver 2012-01-10 Bruno FLEURETTE * : flash: pre-check flash unlock for stm32f2x add checking of the current flash lock status before performing the unlock sequence (which would fail in an unlocked state) Change-Id: I693294c9cd2f59e69cb5bf3338120052fd680b1e Signed-off-by: Bruno FLEURETTE Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/363 Reviewed-by: Øyvind Harboe Reviewed-by: Spencer Oliver Tested-by: jenkins Reviewed-by: Mathias Küster 2012-01-09 Spencer Oliver * : target: fix missing semihosting return path bug nicely caught by clang. Change-Id: I7abf0fdd76666fb3eb1c83e3edfd01e0da485ffe Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/359 Tested-by: jenkins Reviewed-by: Øyvind Harboe 2012-01-04 Spencer Oliver * : flash: use stm32f2x flash size register Use the flash size register to calculate flash info. Change-Id: Ia230db8a08d440710c030a9e5001f20561c9f420 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/337 Tested-by: jenkins Reviewed-by: Mathias Küster 2012-01-04 Spencer Oliver * : contrib: add stlink udev rules Change-Id: I3f11de8abfaf8821311a7aa0fd237006de3c2792 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/333 Tested-by: jenkins Reviewed-by: Mathias Küster 2012-01-03 Spencer Oliver * : cfg: use consistent chipname Change-Id: I41e0788f830d5ece13e6231a99d5b4013c9c678f Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/331 Tested-by: jenkins Reviewed-by: Mathias Küster Reviewed-by: Freddie Chopin 2012-01-07 Øyvind Harboe * : rtos: fix bug in error handling checking for != ERROR_FAIL is broken. Change-Id: Id7085afac653bb9c38d08928227a9ea402d8e6e9 Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/351 Tested-by: jenkins Reviewed-by: Michel JAOUEN Reviewed-by: Øyvind Harboe 2011-12-16 Mathias K * : Change return value on error. On wrong parameters a error is signalized to the calling function. Change-Id: I484443fdb39938e20382edc9246d5ec546a5c960 Signed-off-by: Mathias K Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/282 Tested-by: jenkins Reviewed-by: Øyvind Harboe 2011-12-28 Øyvind Harboe * : flash: introduce .usage field for nand and nor flash driver structure Change-Id: I47e7ec8fa8c70d2addc3aa52d7c97e9e1e7bb662 Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/301 Tested-by: jenkins Reviewed-by: Øyvind Harboe Reviewed-by: Spencer Oliver 2011-12-24 Mathias K * : command: print BUG warning when usage is missing These error messages will prompt patches to be submitted for missing .usage or empty fields. All of the below must be resolved before next release. The Jim defined commands are excluded from this checklist because the help text can be set later than during command registration. strlen(.usage) == 0 means that the command expects no arguments. Updates to this patch in Gerrit to fix problems below are most welcome. Anyone can push updated versions of a patch to Gerrit. If there are no further updates to this patch within a week, it will be pushed to the master branch to prompt more fixes. These were caught by launching OpenOCD. Error: BUG: command 'command' does not have the '.usage' field filled out Error: BUG: command 'script' does not have the '.usage' field filled out Error: BUG: command 'power_restore' does not have the '.usage' field filled out Error: BUG: command 'srst_deasserted' does not have the '.usage' field filled out Error: BUG: command 'measure_clk' does not have the '.usage' field filled out Error: BUG: command 'exit' does not have the '.usage' field filled out Error: BUG: command 'shutdown' does not have the '.usage' field filled out Error: BUG: command 'gdb_sync' does not have the '.usage' field filled out Error: BUG: command 'interface_list' does not have the '.usage' field filled out Error: BUG: command 'target' does not have the '.usage' field filled out Error: BUG: command 'target init' does not have the '.usage' field filled out Error: BUG: command 'flash' does not have the '.usage' field filled out Error: BUG: command 'flash init' does not have the '.usage' field filled out Error: BUG: command 'flash banks' does not have the '.usage' field filled out Error: BUG: command 'nand' does not have the '.usage' field filled out Error: BUG: command 'nand drivers' does not have the '.usage' field filled out Error: BUG: command 'nand init' does not have the '.usage' field filled out Error: BUG: command 'pld' does not have the '.usage' field filled out Error: BUG: command 'pld init' does not have the '.usage' field filled out Error: BUG: command 'mflash' does not have the '.usage' field filled out Error: BUG: command 'mflash init' does not have the '.usage' field filled out Error: BUG: command 'dummy' does not have the '.usage' field filled out Error: BUG: command 'dummy foo' does not have the '.usage' field filled out Error: BUG: command 'scan_chain' does not have the '.usage' field filled out Error: BUG: command 'jtag' does not have the '.usage' field filled out Error: BUG: command 'jtag init' does not have the '.usage' field filled out Error: BUG: command 'arm' does not have the '.usage' field filled out Error: BUG: command 'arm reg' does not have the '.usage' field filled out Error: BUG: command 'etm' does not have the '.usage' field filled out Error: BUG: command 'arm7_9' does not have the '.usage' field filled out Error: BUG: command 'at91eb40a.cpu' does not have the '.usage' field filled out Error: BUG: command 'at91eb40a.cpu arm' does not have the '.usage' field filled out Error: BUG: command 'arm reg' does not have the '.usage' field filled out Error: BUG: command 'at91eb40a.cpu etm' does not have the '.usage' field filled out Error: BUG: command 'at91eb40a.cpu arm7_9' does not have the '.usage' field filled out Error: BUG: command 'target_request' does not have the '.usage' field filled out ^C oyvind@fierce:~/openocd$ openocd -c "interface dummy" -f board/at91eb40a.cfg 2>&1 | grep -w BUG Error: BUG: command 'command' does not have the '.usage' field filled out Error: BUG: command 'script' does not have the '.usage' field filled out Error: BUG: command 'power_restore' does not have the '.usage' field filled out Error: BUG: command 'srst_deasserted' does not have the '.usage' field filled out Error: BUG: command 'measure_clk' does not have the '.usage' field filled out Error: BUG: command 'exit' does not have the '.usage' field filled out Error: BUG: command 'shutdown' does not have the '.usage' field filled out Error: BUG: command 'gdb_sync' does not have the '.usage' field filled out Error: BUG: command 'interface_list' does not have the '.usage' field filled out Error: BUG: command 'target' does not have the '.usage' field filled out Error: BUG: command 'target init' does not have the '.usage' field filled out Error: BUG: command 'flash' does not have the '.usage' field filled out Error: BUG: command 'flash init' does not have the '.usage' field filled out Error: BUG: command 'flash banks' does not have the '.usage' field filled out Error: BUG: command 'nand' does not have the '.usage' field filled out Error: BUG: command 'nand drivers' does not have the '.usage' field filled out Error: BUG: command 'nand init' does not have the '.usage' field filled out Error: BUG: command 'pld' does not have the '.usage' field filled out Error: BUG: command 'pld init' does not have the '.usage' field filled out Error: BUG: command 'mflash' does not have the '.usage' field filled out Error: BUG: command 'mflash init' does not have the '.usage' field filled out Error: BUG: command 'dummy' does not have the '.usage' field filled out Error: BUG: command 'dummy foo' does not have the '.usage' field filled out Error: BUG: command 'scan_chain' does not have the '.usage' field filled out Error: BUG: command 'jtag' does not have the '.usage' field filled out Error: BUG: command 'jtag init' does not have the '.usage' field filled out Error: BUG: command 'arm' does not have the '.usage' field filled out Error: BUG: command 'arm reg' does not have the '.usage' field filled out Error: BUG: command 'etm' does not have the '.usage' field filled out Error: BUG: command 'arm7_9' does not have the '.usage' field filled out Error: BUG: command 'at91eb40a.cpu' does not have the '.usage' field filled out Error: BUG: command 'at91eb40a.cpu arm' does not have the '.usage' field filled out Error: BUG: command 'arm reg' does not have the '.usage' field filled out Error: BUG: command 'at91eb40a.cpu etm' does not have the '.usage' field filled out Error: BUG: command 'at91eb40a.cpu arm7_9' does not have the '.usage' field filled out Error: BUG: command 'target_request' does not have the '.usage' field filled out Change-Id: I2c3e529530a15d2295a1950ffc59e8f2fc661012 Signed-off-by: Øyvind Harboe Signed-off-by: Mathias K Reviewed-on: http://openocd.zylin.com/299 Tested-by: jenkins Reviewed-by: Øyvind Harboe Reviewed-by: Spencer Oliver 2011-12-17 Mathias K * : Add STM32F2X/STLINK target config file. Change-Id: I02161fa05da993b5b966c31a706667d1bd91935d Signed-off-by: Mathias K Reviewed-on: http://openocd.zylin.com/287 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-12-17 Mathias K * : STM32 ST-LINK target initial release STM32 ST-LINK target added. Change-Id: Ibe2b7a3c0d5a8cf73d8680d6019adbdb62d68fa2 Signed-off-by: Mathias K Reviewed-on: http://openocd.zylin.com/279 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-12-15 Mathias K * : Make jim functions public accessible. Change this 2 functions to make it accessible for other tcl interfaces. Change-Id: Idee07fcc779941b037a05a40c021e3fb0b1a4a7a Signed-off-by: Mathias K Reviewed-on: http://openocd.zylin.com/277 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-12-01 Mathias K * : add private data pointer to the tap interface This will give us the ability to add special data structures and new interfaces without rewriting the complete jtag engine. Change-Id: I21a6e1daa96c5f4d111bbb734c7c1fbc2eaee227 Signed-off-by: Mathias K Reviewed-on: http://openocd.zylin.com/244 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-12-23 Spencer Oliver * : build: fix mingw build issues 8901fca0270fec41b12c30c7dbd806d460548c5b broke the build under mingw, this fixes that. Change-Id: I22b91e220dac3b68cc576b65a9f1b8711e64263a Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/298 Tested-by: jenkins Reviewed-by: Freddie Chopin Reviewed-by: Øyvind Harboe 2011-12-14 Erik Ahlén * : Documentation for mxc NAND flash controller Change-Id: I9e552491e8b4737c01e4f8ae2b9a582b6ff2bc5d Signed-off-by: Erik Ahlén Reviewed-on: http://openocd.zylin.com/273 Tested-by: jenkins Reviewed-by: Mathias Küster Reviewed-by: Spencer Oliver 2011-12-13 Erik Ahlén * : Added command to enable/disable/query BI-swap for MXC NAND Change-Id: Ifa3eb739afe0760a974b57c5a17cc3bf7704ba79 Signed-off-by: Erik Ahlén Reviewed-on: http://openocd.zylin.com/270 Tested-by: jenkins Reviewed-by: Mathias Küster Reviewed-by: Spencer Oliver 2011-12-13 Erik Ahlén * : Added board type as a parameter to mx2 NFC as they have different base addresses. Change-Id: I7bc326e9a8d9f6817f046a7faeebede567c53dd2 Signed-off-by: Erik Ahlén Reviewed-on: http://openocd.zylin.com/268 Tested-by: jenkins Reviewed-by: Mathias Küster Reviewed-by: Spencer Oliver 2011-12-20 Ulf Samuelsson * : Olimex-ARM-USB-OCD-H: Add udev rule Change-Id: Ifc9a1f7fa9445e05560c335b5bba3a33caeccc51 Signed-off-by: Ulf Samuelsson Reviewed-on: http://openocd.zylin.com/288 Tested-by: jenkins Reviewed-by: Mathias Küster Reviewed-by: Spencer Oliver 2011-12-21 Ulf Samuelsson * : git should ignore patches from format-patch Change-Id: Iafce872fa7559180834532ba80941dec3db7d079 Signed-off-by: Ulf Samuelsson Reviewed-on: http://openocd.zylin.com/295 Tested-by: jenkins Reviewed-by: Mathias Küster Reviewed-by: Øyvind Harboe 2011-12-13 Øyvind Harboe * : jtag: make caller always allocate buffer simplifies the API and there is only one remaining user at this point. Is the implementation busted where the check does not actually happen now? Change-Id: I776a43766f5576a08df320f6fe41a2750d101bde Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/264 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-12-13 Øyvind Harboe * : jtag: retire jtag_alloc_in_value32 API not needed, reduce area of interface and sharp edges to API. Change-Id: I5347352e7595686634bd0de13fcf6de6e55027b0 Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/262 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-12-12 Spencer Oliver * : build: libusb use AC_CHECK_HEADER use AC_CHECK_HEADER rather than AC_CHECK_HEADERS so that we do not generate a unrequired HAVE_LIBUSB_1_0_LIBUSB_H define. Change-Id: I23a93d3813716dce797ca1514fdcb84533454c31 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/259 Tested-by: jenkins Reviewed-by: Mathias Küster 2011-12-12 Spencer Oliver * : build: correctly quote m4 parameters Change-Id: If7ccb52c107cb4ad7629ffcf237f9003f60e63d0 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/257 Tested-by: jenkins 2011-12-13 Erik Ahlén * : Indentation and white space fixes. Change-Id: Iffbaefea4f3d5e9b56b3c36496b44969d7c07e82 Signed-off-by: Erik Ahlén Reviewed-on: http://openocd.zylin.com/266 Tested-by: jenkins Reviewed-by: Øyvind Harboe 2011-12-16 Spencer Oliver * : checkpatch: fix false indent trigger we have changed the indent to 4 to match OpenOCD coding style. Change-Id: I4870a3410eb20fc2f6df6a3e5891d4d4e598131a Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/285 Tested-by: jenkins 2011-12-15 Erik Ahlén * : Change checkpatch.pl tab expanding to 4 characters. The C coding style guide says that tab width is 4 characters but checkpatch.pl expands tabs to 8 characters which produces false negatives. Change-Id: Ibdabbb55269b7cf6bcd38042cccb8bd235e42ce2 Signed-off-by: Erik Ahlén Reviewed-on: http://openocd.zylin.com/275 Tested-by: jenkins Reviewed-by: Øyvind Harboe Reviewed-by: Spencer Oliver 2011-12-13 Øyvind Harboe * : zy1000: fix crash in JTAG over TCP/IP disable asynchronous callbacks and reads as minidriver requires reads and callbacks to be synchronous. Could possibly be fixed by some design work. Change-Id: I7ca79a551085b2e8ba6928e1762d1baed6e95d4b Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/260 Tested-by: jenkins Reviewed-by: Øyvind Harboe Tested-by: Øyvind Harboe 2011-12-07 Øyvind Harboe * : HACKING: add explanation why we want cool-off times as long as a week or two Change-Id: I281e9145f43bc7ac173e02c4e209834f0deaae2b Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/254 Tested-by: jenkins Reviewed-by: Spencer Oliver Reviewed-by: Mathias Küster Reviewed-by: Øyvind Harboe 2011-12-02 Antonio Borneo * : TCL/SPEAr: default one DDR chip Handle default case of single DDR chip Propagate global variable for multi DDR chip Change-Id: I315380f91ee7fcc2976437aa5836d88a7964fc9d Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/251 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-12-03 rodrigo_l_rosa * : HACKING - checkpatch before pushing makes life quicker Change-Id: I4c3cde2aae7bdea138413e373ac986be3efd54de Signed-off-by: rodrigo_l_rosa Reviewed-on: http://openocd.zylin.com/252 Tested-by: jenkins Reviewed-by: Øyvind Harboe 2011-12-01 Spencer Oliver * : gdb_server: use strndup to allocate debug messages Lets be consistent and use strndup to allocate the debug buffer. Change-Id: I535ad270ebfeae6e09d28372ab3749c822971223 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/245 Tested-by: jenkins Reviewed-by: Øyvind Harboe Reviewed-by: Andreas Fritiofson 2011-12-02 Peter Stuge * : Fix remaining incorrect reference to target/at91sam3uXX.cfg Commit 1794e5ee5452c83b5bef6d0a5a8a3f23d647e9c6 renamed the file to have all lowercase characters according to most references to the file, but the commit didn't change the existing reference to the old filename. Change-Id: I380e52e947a8091d48cf010e3919bf2caed7fdff Signed-off-by: Peter Stuge Reviewed-on: http://openocd.zylin.com/248 Tested-by: jenkins 2011-12-01 Spencer Oliver * : binarybuffer: use strndup to allocate string Change-Id: I65d8f37b18d5b5a798406b956f50ab7bb550e172 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/246 Tested-by: jenkins Reviewed-by: Andreas Fritiofson 2011-11-29 Mathias K * : target init sanity check Add a test if the pointer to the target_init function in the target struct is set before the function pointer is used. Change-Id: Ie4ea542f64f35efce8c5bce2ced9b881bf283ec1 Signed-off-by: Mathias K Reviewed-on: http://openocd.zylin.com/241 Tested-by: jenkins Reviewed-by: Øyvind Harboe 2011-11-22 Evan Hunter * : Fix unused variables error in amt_jtagaccel Change-Id: Ic64cf4e3b5cf8c1ea75a13577728b0cb0d70068e Signed-off-by: Evan Hunter Reviewed-on: http://openocd.zylin.com/237 Tested-by: jenkins Reviewed-by: Øyvind Harboe 2011-11-19 rodrigo_l_rosa * : dsp5680xx - flash module clk to freescale cfg value the flash module clock was set according to a spreadsheet from freescale, now it's set according to the configuration file used by the Freescale Flash Programmer. both work, but i think it's better to use the one used by a software that's made by Freescale (should be correct...) Change-Id: I382197a3eb43dd47ff4b9b83d5e05008d5613fc6 Signed-off-by: Rodrigo L. Rosa Reviewed-on: http://openocd.zylin.com/223 Tested-by: jenkins Reviewed-by: Øyvind Harboe 2011-10-04 rodrigo_l_rosa * : dsp5680xx - fix jtag debug request failure handling if JTAG debug request fails then halting with a reset should be attempted. the failure was ignored previously. Change-Id: Ibec08e2e97f962d164a110c21aaa80bfc17b7f1a Signed-off-by: Rodrigo L. Rosa Reviewed-on: http://openocd.zylin.com/221 Tested-by: jenkins Reviewed-by: Øyvind Harboe 2011-11-15 rodrigo_l_rosa * : dsp5680xx - fix - flashing algorithm check now the flash algorithm running on the 568013 checks the buffer_empty bit (instead of the command_finished bit) before trying to write a new word to the flash mem. this should speed up the flashing procedure. since it is open loop, this change may reduce the risk of failure. flashing will fail if JTAG speed is such that the flash module cannot keep up. also, the USTAT register is only read once, as suggested in the flow chart provided by freescale (per. ref. manual @ 6-11) the last step of the flow chart, exiting after commands are complete, is not implemented. the algorithm will stay waiting for more data. it is up to the PC side to *not* send more data. Change-Id: I47fe4b50de7da85f80868f5986a89a7e2152616c Signed-off-by: Rodrigo L. Rosa Reviewed-on: http://openocd.zylin.com/219 Tested-by: jenkins Reviewed-by: Øyvind Harboe 2011-09-02 rodrigo_l_rosa * : dsp5680xx - fix jtag status mask Change-Id: I17a0f22cbeb20e4f6ea4065236243f93d826ccf0 Signed-off-by: Rodrigo L. Rosa Reviewed-on: http://openocd.zylin.com/217 Tested-by: jenkins Reviewed-by: Øyvind Harboe 2011-09-02 rodrigo_l_rosa * : dsp5680xx - error codes added logging of target error codes to enable automatic error handling from tcl. the plan is to use a computer to execute a series of tcl commands, the changes allow simple parsing of return messages to detect errors. Change-Id: Ia98d3bd036e1b6065b475ffff6c1d30baeaf7417 Signed-off-by: Rodrigo L. Rosa Reviewed-on: http://openocd.zylin.com/215 Tested-by: jenkins Tested-by: Øyvind Harboe Reviewed-by: Øyvind Harboe 2011-11-23 Antonio Borneo * : TCL/SPEAr: fix name of included file Fix error introduced in recent commit. Correct the name of the board file. Change-Id: I46bca8329812fb24bc4f8d316be9e7cba9b56496 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/234 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-11-18 Antonio Borneo * : TCL: Add board file for EVALSPEAr300 Initial support for SPEAr300 chip and for evaluation board named EVALSPEAr300. Currently supports only those parts in common with SPEAr310. Change-Id: I8075aa721cf3dfaac561ee51e5df4ce9a2992e3e Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/230 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-11-21 Antonio Borneo * : TCL/SPEAr: move DDR activation in common code DDR controller activation should not be in DDR chip specific code, but in generic DDR controller part. Change-Id: If1b178228352b48b0097d7b9b300005fb5bb4fb6 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/228 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-01-21 Antonio Borneo * : TCL/SPEAr: move device generic code The initialization of RAS enable and clock is required by all SPEAr3xx devices Change-Id: Iea4cd0902e4da219475d7f35b4c25fc87ec6b902 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/226 Tested-by: jenkins Reviewed-by: Spencer Oliver 2010-11-27 Antonio Borneo * : TCL/SPEAr: Add reference to ST Application Note ST-AN was mentioned but there was no reference Change-Id: Ie065f8faba94d63cf391a994ec895692d499394e Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/224 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-11-15 Spencer Oliver * : usbprog: fix shadowed declaration warning see Trac #38 Change-Id: If86fda797391f10d745384794b68e60380ef0b21 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/204 Tested-by: jenkins Reviewed-by: Andreas Fritiofson 2011-11-16 Mauro Gamba * : libusb-1.0 support The configuration script check for libusb-1.0 availability first and only if not found check for libusb-0. So if both libraries are installed on the system the build script will use libusb-1.0 It's possible to force compiling with libusb-0 with the --enable-libusb0 switch. If the driver support only libusb0 the script check anly for it. Change-Id: I7eb045d4e2bd553abefad53f3f4023ff46b0f5f6 Signed-off-by: Mauro Gamba Reviewed-on: http://openocd.zylin.com/33 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-11-18 Spencer Oliver * : Revert "build: fix gcc 4.6.2 warnings" This reverts commit 0ef5a90d93c5a026bcf70132e60e957ae339d1e1 Causes older versions of gcc to break - need to look into a better fix. This passed through the jenkins build as we originally did not build this module - we do now. Change-Id: Iafeac8442b2249269ff45a52ccd3e2870920f635 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/214 Tested-by: jenkins 2011-11-14 Robert Pasz * : presto: fix tms_sequence short issue fix issue when using tms_sequence short see Trac #31 Change-Id: I22a9cd2af59eae4d8a276dae60b6a99d05af53bb Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/201 Tested-by: jenkins Reviewed-by: Andreas Fritiofson 2011-11-14 Philip Nye * : gdb: fix multi core gdb issue gdb_memory_map() correctly calculates the target specific number of flash banks, but then uses the total number (all targets) instead of the target specific number to construct its GDB response, causing a crash. Change-Id: I3f8639b3e90303a59753ebe140ce4fff96fd5db0 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/199 Tested-by: jenkins Reviewed-by: Andreas Fritiofson 2011-11-14 Spencer Oliver * : flash: match stm32f2x loader src name Change-Id: I60523f809f2d9ec9c9283e0456746ce9a63576a7 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/196 Tested-by: jenkins Reviewed-by: Andreas Fritiofson 2011-11-17 Felix Ruess * : config: do not use deprecated stm32.cfg Change-Id: Id72d2d7f874043331ecb5586a3797d017606129e Signed-off-by: Spencer Oliver Signed-off-by: Felix Ruess Reviewed-on: http://openocd.zylin.com/212 Tested-by: jenkins 2011-11-16 Andreas Fritiofson * : bitq: make private functions static Change-Id: I3fabbdbda4ba8ba6557d79b97444fe06f1710b58 Signed-off-by: Andreas Fritiofson Reviewed-on: http://openocd.zylin.com/209 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-11-16 Andreas Fritiofson * : bitq: remove the remaining static variables in_mask and in_idx are just another encoding of the same state information that is already kept in bitq_in_state.bit_pos so derive them from that instead of maintaining them separately. Change-Id: I4ac6bbe923698a8c1090a785b8babcbb90f82931 Signed-off-by: Andreas Fritiofson Reviewed-on: http://openocd.zylin.com/207 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-11-15 Andreas Fritiofson * : bitq: remove a static variable in_buff is only ever set to field->in_value and that pointer is still available when the parsing is restarted so it could just as well be used directly, removing the need for the static variable. Change-Id: I3dd7a8315ed5c5bdc3bfb74044f89492bca9816c Signed-off-by: Andreas Fritiofson Reviewed-on: http://openocd.zylin.com/206 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-11-13 Tomas Frydrych * : kinetis flash: use longword write when writing into pflash Check whether the destination is in the program flash or NVM regions, in the former case, use the normal longword mechanism, not the fast NVM write. Change-Id: I7366b7c8919928ee690252df83b99701776aee82 Signed-off-by: Tomas Frydrych Reviewed-on: http://openocd.zylin.com/194 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-10-17 Aurelien Jacobs * : at91sam7: ensure probed flash bank has a name (fix a segfault) Before this commit, openocd used to segfault when probing flash of an at91sam7x512 (which contains 2 banks of flash). This was due to the way it systematically insert a new flash bank without setting its name. Then, when get_flash_bank_by_name_noprobe() is called, it is doing a strcmp() on the non-initialized bank->name. This commit prevents allocation of second probed bank if it is already allocated (for example, if it is set in a target config file). If a new bank really needs to be allocated, it ensures that a default name is set. Change-Id: I38d15bef1fda2ec746efad37171975136cf7b371 Signed-off-by: Aurelien Jacobs Reviewed-on: http://openocd.zylin.com/171 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-11-10 Øyvind Harboe * : image: remove assignments to local variables that is never read Change-Id: I1a5e968f165e060fd4aa7c023ad870a9e21bb5dd Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/191 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-11-07 Øyvind Harboe * : svf: fix warnings Change-Id: Ib7f67612db3a865f9acc5ae349455da7ddcd3348 Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/177 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-11-09 Spencer Oliver * : docs: remove berlios related info Change-Id: I9593eb165fce51411f20fa068e324b3fd882cdb3 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/190 Tested-by: jenkins 2011-10-22 Kyle Manna * : contrib: Add udev rules for TI xds100v2 debugger This corrects permissions on the FTDI chip on the xds100v2 debugger enabling normal users to access it. Change-Id: I0f6618692ebdee6284eee28f9e612e68782c4d78 Signed-off-by: Kyle Manna Reviewed-on: http://openocd.zylin.com/188 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-11-08 Øyvind Harboe * : buspirate: add missing error propagation found by clang. Change-Id: I80ea8e6afc8dcc1aa7edb6f63af0d94f6781b81c Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/182 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-11-08 Øyvind Harboe * : em357: fix warning by removing unused local variables Change-Id: I9def63d36ed4fa8bf9cdeeedc18b1b25d0e487d6 Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/184 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-11-03 Spencer Oliver * : flash: update luminary device table add support for checking target against the device CLASS rather then just the PARTNO. This change also adds the new LM4F family (Blizzard). Change-Id: Ia9d1e33f1f1c2817c0039a2232ecf932fae072f9 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/161 Reviewed-by: Øyvind Harboe 2011-10-17 Aurelien Jacobs * : at91sam7: add a new target config file for at91sam7x512 The main difference with at91sam7x256 is the declaration of the second bank of flash. Change-Id: I87a20dcbb639b797799139ccf46cc73934fa3b9e Signed-off-by: Aurelien Jacobs Reviewed-on: http://openocd.zylin.com/173 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-11-07 Øyvind Harboe * : xsvf: add missing error propagation Change-Id: Ibc70deb980d6d18ceb376b72d9104e6180b16acf Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/176 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-10-31 Øyvind Harboe * : str9x: explain compiler that a local variable will always be initialized Change-Id: I9ddb2793b4cdbf6acea6f69973531491e4ebcc5b Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/145 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-11-07 Øyvind Harboe * : str7x: fix error propagation stick to convention of "retval" being used as error value to be propagated and use "flash_flags" local variable for flash flags read from how. Change-Id: I63f1f2248b4f4538d6cd7634ae277f7c0aadc346 Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/178 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-11-07 Øyvind Harboe * : ecos: add missing error propagation Change-Id: Ib34815c9cf654517f22486a7c8001fdb7471338c Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/174 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-10-31 Øyvind Harboe * : warning fix: add self-consitency check to remove warning verify promise of code that more code can be pasted with an assert at the end condition of the code passage that builds string. Change-Id: I76a4e5f91b9142fff932e1493cb43c29eb6a0f80 Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/143 Tested-by: jenkins Reviewed-by: Øyvind Harboe 2011-11-04 Spencer Oliver * : tools: fix permissions Change-Id: I9419138dd2972304daf215594ca917ac8eb7fcda Signed-off-by: Spencer Oliver 2011-11-03 Øyvind Harboe * : etm: fix warning by removing assignment that is immediately overwritten Change-Id: Ia3a83d3c1fc3a1707d69017fce6cf142a81babc4 Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/165 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-11-01 Øyvind Harboe * : dsp5680xx: add missing and broken error propagation found by clang. Change-Id: Ie7e2ecad71bf0838ece93727e4778ad368b890ef Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/156 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-11-03 Øyvind Harboe * : avr32_regs: add missing error propagation Change-Id: Ie8b141dd534d73eccfc045069d5f628bd1eea88e Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/166 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-11-02 Øyvind Harboe * : HACKING: all you need is http access Change-Id: I191c1da5126c4c9ea1ff8826576b6b24feaf9881 Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/157 Tested-by: jenkins Reviewed-by: Øyvind Harboe Reviewed-by: Spencer Oliver 2011-11-03 Spencer Oliver * : tools: add checkpatch script Change-Id: I3579028fc1c6ee8bea58c82e5f0eecba7794d7cb Signed-off-by: Spencer Oliver 2011-11-01 Spencer Oliver * : cfg: add Stellaris LM4F232 Evaluation Kit config Change-Id: Ica754897bef6573a0738ed1afdfe1dfda07292fd Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/151 Tested-by: jenkins Reviewed-by: Andreas Fritiofson 2011-11-01 Mark Vels * : tx27stk5: add board init support for KaRo TX27 CPU module This patch adds support for a KaRo TX27 CPU module on a StarterkitV base board. The register settings have been extracted from a RedBoot distribution that is distributed along with the hardware by KaRo. This setup has been tested with a JTAGKey. The testing has been focussed on loading a program into memory and start execution. Although the flash seems to be correctly detected, no effort has been put in testing the NAND programming yet. Change-Id: Ib17763f1e3ecacd0eb9b5fdc32f8cba7a5e59be5 Signed-off-by: Mark Vels Reviewed-on: http://openocd.zylin.com/158 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-11-01 Øyvind Harboe * : cortex_a: add missing error propagation found by clang. Change-Id: I50eac219d7540fd48d3285f3f213cb659492d0c0 Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/153 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-11-01 Øyvind Harboe * : arm11: print next address to debug fixes clang warning. Basically the next address pointer is not used for anything in the fn, except to be examined in debug. Change-Id: I253519b8e49e54490bbe7da8ec3d2dd31f49052a Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/155 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-11-01 Øyvind Harboe * : target: fix null pointer exception check if no target is selected and return error. Change-Id: Ie8abb63c708d09572b45e88fc6766af108715077 Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/148 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-10-31 Spencer Oliver * : target: rename cortex_m3.[ch] to cortex_m.[ch] This rename is in preparation for cortex_m4 support. Change-Id: Ic08c298ec6ed2aabc2c39db67191f68b3a51f550 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/147 Tested-by: jenkins Reviewed-by: Øyvind Harboe 2011-10-31 Øyvind Harboe * : warnings: null pointer check fix rewrite broken null pointer check code by reducing scope of variable. Change-Id: I8254f6849b187e5c9cd083053cdc11973c6fe339 Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/142 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-10-27 Øyvind Harboe * : bugfixes: tinker a bit with the targets command return error when target can not be found instead of ERROR_OK, split fn. Change-Id: Iba5232d3862a490d0995c3bfece23685bd6856e3 Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/131 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-10-30 Uwe Hermann * : interface configs: Fix whitespace and other issues. Change-Id: I98825c7fb9bdee75b69b06005ed12a3f64ec4db4 Signed-off-by: Uwe Hermann Reviewed-on: http://openocd.zylin.com/139 Tested-by: jenkins Reviewed-by: Peter Stuge 2011-10-29 Øyvind Harboe * : clang: fix warning by adding assert that shows that a variable is used Change-Id: I26e0ba9f1ae9d43c9a14c42c4225746782dc4d66 Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/134 Tested-by: jenkins Reviewed-by: Øyvind Harboe 2011-10-27 Øyvind Harboe * : bugfixes: numerous bugs in error propagation found by clang Change-Id: I784068325b422d1918e28c08544bc5a1332d712f Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/130 Tested-by: jenkins Reviewed-by: Øyvind Harboe 2011-10-26 Jim Norris * : Remove use of undefined variable. Change-Id: Id8fd345438c360b2a42857525f05360ce2794d21 Signed-off-by: Jim Norris Reviewed-on: http://openocd.zylin.com/127 Reviewed-by: Peter Stuge Tested-by: jenkins 2011-10-25 Jim Norris * : Add configuration for ATMEL SAM3N-EK board. Change-Id: I525f6c346cace4e54f47659c5a7aceb29ee4baf2 Signed-off-by: Jim Norris Reviewed-on: http://openocd.zylin.com/125 Tested-by: jenkins Reviewed-by: Øyvind Harboe 2011-10-25 Marti Bolivar * : stm3220g_eval.cfg: fix CHIPNAME. The STM3220G-EVAL board has an STM32F207IGH6. ("...H6", not "...T6"). Change-Id: Iaf3dae6830c5c0685a1dcd1588d391434bc51be7 Signed-off-by: Marti Bolivar Reviewed-on: http://openocd.zylin.com/120 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-10-25 Andreas Fritiofson * : armv7a: make local functions static Also fix a spelling error and remove the declaration for a non-existent function from the header. Change-Id: I13177e2d81aa167c05c1cc766f06924211e6d735 Signed-off-by: Andreas Fritiofson Reviewed-on: http://openocd.zylin.com/118 Tested-by: jenkins Reviewed-by: Øyvind Harboe 2011-10-22 Freddie Chopin * : Fix "Evaluate 'script' in the global scope" This fixes commit Evaluate 'script' in the global scope. It caused Windows builds behave differently than before because path was evaluated twice and backslashes from Windows' paths got unescaped and effectively wiped out. Configs could only be passed with "-f ../dir/config.cfg" or "-f ..\\dir\\config.cfg" instead of usual "-f dir/config.cfg" (or using backslash) as previously. Change-Id: I13b4abac6dbe6d770cc11a4e61c9421ef340da83 Author: Steve Bennett Signed-off-by: Freddie Chopin Reviewed-on: http://openocd.zylin.com/40 Tested-by: jenkins Reviewed-by: Xiaofan Reviewed-by: Spencer Oliver 2011-10-23 Antonio Borneo * : SERVER: fix clang warning The fix is inline with the Linux coding style that forbids assignment in if condition Change-Id: I0b9d0b419d9c8b7a8c755e048d5faf72d1658ba2 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/87 Tested-by: jenkins Reviewed-by: Øyvind Harboe 2011-10-23 Antonio Borneo * : NOR/CORE: fix clang warning The fix is inline with the Linux coding style that forbids assignment in if condition Change-Id: I10338a249bcfeff87d8596f7e17f209e26b41678 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/86 Tested-by: jenkins Reviewed-by: Øyvind Harboe 2011-10-23 Antonio Borneo * : FLASH/CFI: fix clang warnings Total of 5 warnings: 3x "Dead store": removed dead assignment to variable; 1x "Dereference of null pointer": this is not an error, but a limited visibility of clang, since pointer erase_region_info is initialized inside cfi_fixup_non_cfi(); 1x "Branch condition evaluates to a garbage value": this is a real coding bug that could issue SIGSEGV, since "goto cleanup" can be executed before initialization of "source". Change-Id: Id3c323c82bb15cbd3bb8fc04b23541f11145f109 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/84 Tested-by: jenkins Reviewed-by: Øyvind Harboe 2011-10-22 Øyvind Harboe * : fm3: fix warning for superfluous assignment Change-Id: I4f8e8c2e676a2728ddc6227daf9ca6a7ceb3d505 Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/46 Tested-by: jenkins Reviewed-by: Øyvind Harboe 2011-10-22 Øyvind Harboe * : tms470: remove dead assignment warning Change-Id: I21e7ac47f80d93c9c0d7b169f8848b929c664b20 Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/45 Tested-by: jenkins Reviewed-by: Øyvind Harboe 2011-10-21 Øyvind Harboe * : clang: fix warning w/assert so that clang knows that there will be no division by zero Change-Id: I98ac62a22f21043bb535a667a4f1f1537ccde2a4 Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/42 Tested-by: jenkins Reviewed-by: Øyvind Harboe 2011-10-23 Edgar Grimberg * : tms470: removed unnecessary operations This should silence a warning. Change-Id: Id91a9ebacae836083b1db2654a8e7bf24b2300e9 Signed-off-by: Edgar Grimberg Reviewed-on: http://openocd.zylin.com/52 Tested-by: jenkins Reviewed-by: Øyvind Harboe 2011-10-22 Øyvind Harboe * : buspirate: ignore return value and fix warning Perhaps we could do one better and propagate the error? Change-Id: Idc45f516c26f09de4ee01fe05e8d3475f4b80db3 Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/43 Tested-by: jenkins Reviewed-by: Øyvind Harboe 2011-10-22 Øyvind Harboe * : server: remove warning due to dead assignment Change-Id: Idb08aef0c11b3fae92286e8fcea61ab09ab09e74 Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/44 Reviewed-by: Peter Stuge Tested-by: jenkins 2011-10-20 Andreas Fritiofson * : rtos: remove broken code for handling the deprecated qP packet Change-Id: Icca522c1e2a2877abb20665b171c61079b1d8f48 Signed-off-by: Andreas Fritiofson Reviewed-on: http://openocd.zylin.com/37 Tested-by: jenkins Reviewed-by: Peter Stuge 2011-10-19 Freddie Chopin * : Unused variables Fix a few errors with set and unused variables detected by GCC 4.7.0 Change-Id: I59b748e18e514ee9f0cde7883b4ed5116198bd4a Signed-off-by: Freddie Chopin Reviewed-on: http://openocd.zylin.com/36 Tested-by: jenkins Reviewed-by: Spencer Oliver 2011-10-19 Uwe Hermann * : TMPA900/910 MCUs are always little endian. Signed-off-by: Uwe Hermann Change-Id: I8839f2cf0faf1b5ba9f99901c5ee028b199fabd2 Reviewed-on: http://openocd.zylin.com/35 Tested-by: jenkins Reviewed-by: Peter Stuge 2011-09-19 Matt Reimer * : xscale: fix bug in xscale_receive() The code in xscale_receive() that tries to skip invalid reads (i.e. reads that don't have the DBG_SR[0] 'valid' bit set) seems to be wrong, as it only looks at the first word's valid flag rather than each word's own valid flag. Am I reading the code correctly? If so, the attached patch should fix it. If this looks correct, I'll generate a proper patch and commit message. Matt Change-Id: I74ebe2ad7a36d340a9dd3b8487578b6ea7f3cf1e Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/32 Tested-by: jenkins Reviewed-by: Øyvind Harboe 2011-10-17 Spencer Oliver * : luminary: add peripheral reset script some luminary device classes require a reset script to emulate a hardware reset. Change-Id: Id505c92451244b48b0238c2130aebab2df8d208b Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/30 Reviewed-by: Øyvind Harboe Tested-by: Øyvind Harboe 2011-10-02 Karl Kurbjun * : ICEPick-C: Add support for warm reset through JTAG controller and provide finer detail functions. This sets up simple functions that can later be used to provide additional ICEPick Operations. Change-Id: I313b8679267696fad87d23f3692963e513f2fe21 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/22 Tested-by: Øyvind Harboe Reviewed-by: Øyvind Harboe 2011-10-14 Øyvind Harboe * : target_request: add target_got_message() that can be used to improve DCC performance API change to allow implementing a back-off algorithm for polling hardware. Change-Id: I6cbe8b4534c8dfeb8442305171ea96b5481c1f17 Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/26 Reviewed-by: Øyvind Harboe Tested-by: Øyvind Harboe 2011-10-14 Jim Norris * : Add some more detail for setting up Gerrit account. 1) Add a couple more steps when setting up the Gerrit account. Change-Id: I5d81feac4650d4d28653d14cfc0baf14270424c1 Signed-off-by: Jim Norris Reviewed-on: http://openocd.zylin.com/28 Reviewed-by: Peter Stuge Tested-by: Peter Stuge 2011-10-14 Spencer Oliver * : flash: fix lpc2000 driver typo Change-Id: I3a759ed98a27fd186c12355b846d5e97dba86c5b Signed-off-by: Spencer Oliver 2011-10-14 Uwe Hermann * : Add a board file for the Glyn Tonga2. This is a Toshiba TMPA900CMXBG (ARM9) based SO-DIMM CPU module with 64MB DDR SDRAM, 256MB NAND flash, and on-board Ethernet. The board file provides a tonga2_init function which sets up the PLL/clocks and memory (SDRAM and SRAM), which allows writing a boot-loader into RAM via JTAG. Change-Id: I60522b97997bdf50e1f25aebab910d93a98522fb Signed-off-by: Uwe Hermann Reviewed-on: http://openocd.zylin.com/19 Reviewed-by: Spencer Oliver Tested-by: Spencer Oliver 2011-10-03 Michel Jaouen * : breakpoint : smp software breakpoint issue Change-Id: Iefe78bad71d4fdb38ae412ab8fe2f6282836c22e Signed-off-by: Øyvind Harboe Reviewed-on: http://openocd.zylin.com/14 Tested-by: Spencer Oliver Reviewed-by: Spencer Oliver 2011-10-12 Øyvind Harboe * : docs: update HACKING to point to Gerrit Change-Id: If79e86c731ac06aaefca1aebde40e7cb3de68e4d Signed-off-by: Øyvind Harboe 2011-10-12 Spencer Oliver * : docs: update project url's Change-Id: I54fc3aff722ed25143aad85e58d19b72fcecbba0 Signed-off-by: Spencer Oliver 2011-10-11 Spencer Oliver * : replace berlios url's with sourceforge url's Change-Id: I1c9957bb64df87cee7c5e832f21453eb8934a5fb Signed-off-by: Spencer Oliver 2011-07-31 Andreas Fritiofson * : stm32f1x: use async algorithm in flash programming routine Let the target algorithm be running in the background and buffer data continuously through a FIFO. This reduces or removes the effect of latency because only a very small number of queue executions needs to be done per buffer fill. Previously, the many repeated target state changes, register accesses (really inefficient) and algorithm uploads caused the flash programming to be latency bound in many cases. Now it should scale better with increased throughput. Signed-off-by: Andreas Fritiofson 2011-07-15 Andreas Fritiofson * : cortex_m3: use armv7m's async algorithm implementation Signed-off-by: Andreas Fritiofson 2011-07-15 Andreas Fritiofson * : target: add async algorithm entries to the target type On supported targets, this may be used to start a long running algorithm in the background so the target may be interacted with during execution and later wait for its completion. The most obvious use case is a double buffered flash algorithm that can upload the next block of data while the algorithm is flashing the current. Signed-off-by: Andreas Fritiofson 2011-09-16 Simon Barner * : arm-jtag-ew: Formatting 2011-09-16 Simon Barner * : arm-jtag-ew: Emit a warning if interface firmware version != 1.6 2011-09-16 Simon Barner * : arm-jtag-ew: Provide armjtagew_speed_div() in order to fix interactive use of `adapter_khz' 2011-09-16 Simon Barner * : arm-jtag-ew: Fix setting interface speed (1/2) CMD_SET_TCK_FREQUENCY message length is 5, not 4 - Ticket: #34 2011-09-16 Clément Burin des Roziers * : STM32L: Added flash driver and target Added the flash driver for the STM32L family, which highly differ from the STM32F family. Added the TCL target file for JTAG access. 2011-09-19 Michel Jaouen * : u8500 : config for L2 cache 2011-09-29 Steve Bennett * : jim-nvp is moving from jimtcl to openocd The jim-nvp code is specific to openocd, so it belongs in openocd, not in the core jimtcl. Signed-off-by: Steve Bennett 2011-09-21 Mathias K * : add target events, run algorithm and default r/w buffer api Target events are added to get better gdb support. The run algorithm functionality are implemented to support feature fast flash write functionality. The new r/w buffer api is now used to support the special memory address handling. The output of the md command was fixed. 2011-09-17 Mathias K * : kinetis cpu flash driver Initial release of the freescale kinetis cpu flash driver. 2011-09-12 Mathias K * : kinetis auto mass erase on secured devices This is a proof of concept to get access to the debug port of a secured kinetis cpu. On full flash erase the cpu is automatically secured and the debug port is not accessible. To get this to work the srst line is needed and the necessary configuration should be added to the configuration file. 2011-09-01 Uwe Bonnes * : Add definition for the STEVAL-PCC010 board with the STM32F207 2011-08-31 Martin Schmölzer * : ULINK driver: Remove typedefs in ulink.c Signed-off-by: Martin Schmölzer 2011-08-31 Martin Schmölzer * : ULINK driver: Remove typedefs in OpenULINK firmware USB descriptor structures Signed-off-by: Martin Schmölzer 2011-08-31 Rodrigo L. Rosa * : static for some functions made two functions into static, since they are not required by anything external 2011-08-31 Øyvind Harboe * : commit 353362651fc28c1f1d823659cde36dd31d1aede6 Author: Martin Schmoelzer Date: Tue Aug 23 17:22:53 2011 +0200 2011-08-04 Martin Schmoelzer * : ULINK driver: Add '-lm' linker flag when building this driver (required for correct calculation of JTAG TCK speed setting) Signed-off-by: Martin Schmölzer 2011-07-04 Martin Schmölzer * : ULINK driver: Implement variable TCK frequency in OpenULINK firmware Also, speed up jtag_clock_tck() significantly (150 kHz -> 375 kHz) Signed-off-by: Martin Schmölzer 2011-08-23 Martin Schmoelzer * : ULINK driver: Implement JTAG_PATHMOVE command Signed-off-by: Martin Schmölzer 2011-07-04 Martin Schmölzer * : ULINK driver: Implement command to manually force downloading firmware image from arbitrary location Signed-off-by: Martin Schmölzer 2011-07-04 Martin Schmölzer * : ULINK driver: Properly propagate return values in ulink_execute_queue() Signed-off-by: Martin Schmölzer 2011-08-31 simonqian.openocd * : vsllink driver compile fails with'vsllink_debug_buffer' defined but not used USB communication is handled by code under versaloon directory. So _DEBUG_USB_COMMS_ should not be used in vsllink.c. Attachment is the patch. 2011-08-30 Rodrigo L. Rosa * : fix enter debug mode for locking added an alternative way to enter debug mode, which does not require restarting the chip. this will not always work, but in general it will (failure 0.3%), and failure is not a dramatic issue, simply have to use the full sequence. the user can only access "halt", which uses the full sequence, so the user should not have any problems. restarting the chip requires reconfiguring the flash module. the doc is very poor, so i'd rather have the two methods, and live with the 0.3%. 2011-08-30 Rodrigo L. Rosa * : fix debug mode,lock,unlock got new info regarding setting the chip to debug mode, and locking/unlocking flash memory. the newer implementation is a bit slower, but always works. the previous implementation would randomly (as once every 25k-70k times) get the chip into a state where the freescale tool would be necessary. this is fixed now. added functions to play around with the jtag state machine. they are not the happiest, but are necessary to be able to execute the halting/locking/unlocking sequences. Conflicts: src/target/dsp5680xx.c 2011-08-30 Rodrigo L. Rosa * : optional crc for flash writing crc check was always performed on newly flashed data, now it is optional flash mem can be locked by writing a specific word to a specific address in flash. to verify flash, target must be halted, and this will (when the new halt sequence is implemented) require reseting the chip. if the target is reset after writing the lock words, then it will lock, hence the CRC will fail because it is not possible to read stuff from the target. also added a function that resets the jtag state machine. this is not used yet, but will be soon. it is implemented to allow strict control over JTAG state machine, necessary to implement to halt and unlocking sequences. 2011-08-15 Rodrigo L. Rosa * : dsp568013 disable polling by default 2011-08-26 Evan Hunter * : Fix off by one bug in FreeRTOS 2011-08-24 Jonathan Dumaresq * : This will add the Value Line HD of stm32 devices. This has been tested on STM32F100VE 2011-07-18 Evan * : Add suspended task list to FreeRTOS support 2011-08-22 Jim Paris * : Fix redbee config files Currently the board/redbee-*.cfg files incorrectly include the interface definition. Move the interfaces to interface/, and create a single board/redbee.cfg that is common to both boards. Intended usage is now: openocd -f interface/redbee-econotag.cfg -f board/redbee.cfg 2011-08-20 olivier Schonken * : Fix Sam3u flash bank 1 issue 2011-08-17 Jie Zhang * : remove white space before TAB 2011-07-12 SimonQian * : versaloon driver update Signed-off-by: Spencer Oliver 2011-08-16 Spencer Oliver * : build: rename configure.in to configure.ac configure.ac is the correct name to use with modern autotools. Signed-off-by: Spencer Oliver 2011-08-15 Jie Zhang * : show git commit number even when cross-compiling AC_CHECK_FILE will die when cross-compiling. So don't use it to test the existence of guess-rev.sh. Signed-off-by: Spencer Oliver 2011-08-10 Stefan Mahr * : mips: fix potential alignment error 2011-08-10 Stefan Mahr * : target: add helper functions to get/set u16 or u32 array from/to buffer 2011-08-10 Jie Zhang * : remove useless pxref to SMP subsection 2011-08-11 Steve Bennett * : Evaluate 'script' in the global scope Scripts sourced via 'script' should evaluate in the global scope to make it easy to set and reference global variables. Signed-off-by: Steve Bennett 2011-08-05 Rodrigo L. Rosa * : renamed for clarity i had started my code from dsp5683xx, i renamed a bunch of stuff to names i consider to be better. i believe no one is using this code, so nobody should be affected. (it's not too late to do this change) 2011-07-17 Andreas Fritiofson * : rlink: simplify and optimize queue fill level checks Add a helper function for running the queue if it would overflow otherwise. Use it to simplify the queue fill level checks and optimize in a few cases that would previously run the queue prematurely. Signed-off-by: Andreas Fritiofson 2011-07-16 Andreas Fritiofson * : rlink: remove duplicated code After the reply_index handling is fixed, there's no need to special case the out scan. Signed-off-by: Andreas Fritiofson 2011-07-16 Andreas Fritiofson * : rlink: more indentation fixes Remove unnecessary block scopes to reduce indentation level. Signed-off-by: Andreas Fritiofson 2011-07-25 Drasko DRASKOVIC * : mips32 : Fixed memory byte access Function mips_m4k_write_memory() does endianess byte swap, but this procedure break one byte access (temporary array overwrites content in buffer). As a fix, this endianess swap and buffer affecting is preformed only on hword and word accesses (not on byte access). 2011-07-07 Drasko DRASKOVIC * : mips32: Added CP0 coprocessor R/W routines This patch adds MIPS32 CP0 coprocessor R/W routines, as well as adequate commands to use these routines via telnet interface. Now is becomes possible to affect CP0 internal registers and configure CPU directly from OpenOCD. 2011-07-05 Drasko DRASKOVIC * : mips32: Removed Unnecessary JTAG Queue Flush jtag_execute_queue() is executed as a part of mips_ejtag_drscan_32(). No need for this to be done before - removed for optimisation. 2011-08-09 Rodrigo L. Rosa * : fix return error msj retval was not correctly propagated 2011-08-09 Øyvind Harboe * : Revert "dsp5680xx: disable for now, it generates warnings" This reverts commit d567df02b9f3e7d2e7e78b3c2907ecad9aa4bbd4. 2011-07-19 Rodrigo L. Rosa * : dsp5680xx fix FM clk before doing anything with the flash module (FM) the clock divider must be set. if erase_check was the first thing done with the FM after reset then an error would be generated because the clk divider was not set. now erase_check sets the clk divider. 2011-08-09 Jean-Christophe PLAGNIOL-VILLARD * : Archive and recreate NEWS file. Archive released NEWS file as NEWS-0.5.0. Create new NEWS file from release script template. 2011-08-09 Jean-Christophe PLAGNIOL-VILLARD * : The openocd 0.5.0 release. Remove '-dev' version tag: 0.5.0-dev -> 0.5.0 2011-08-03 Luca Bruno * : Automatically generate ChangeLog from git log for release tarball make dist should use git2cl to generate ChangeLog from git history, populating the placeholder file in released tarball. Signed-off-by: Luca Bruno Signed-off-by: Spencer Oliver 2011-08-01 Jie Zhang * : etb: fix incorrect previous patchset This corrects two issues found with openocd. d7f71e7fe9645fa8c3f88cf6fc9ad438aa6708f3 removed some code that was being used. The above then caused even more code to get removed by commit 1cfb2287a67c1f78b76583b2e5ed83ca3560b0d5. Signed-off-by: Spencer Oliver 2011-07-28 Spencer Oliver * : docs: remove obsolete luminary target info The lm3s variant is not required as this is handled in the target script - see tcl/target/stellaris.cfg. Signed-off-by: Spencer Oliver 2011-07-28 Spencer Oliver * : cfg: update scripts to use new stm32 driver names Signed-off-by: Spencer Oliver 2011-07-28 Spencer Oliver * : flash: update stm32 driver names Use consistent names for the stm32 family flash drivers, eg. stm32x -> stm32f1x stm32f2xxx -> stm32f2x this makes it easier to add support for newer stm32 families. Signed-off-by: Spencer Oliver 2011-07-27 Spencer Oliver * : doc: add Fujitsu FM3 flash driver info Signed-off-by: Spencer Oliver 2011-07-21 Jie Zhang * : Update doc about Jim since it's not a single .C file and a single .H file any more Signed-off-by: Spencer Oliver 2011-07-18 Michael Hunold * : CPU name in TMPA900 config file should obviously be TMPA900 (not TMPA910). Signed-off-by: Spencer Oliver 2011-07-18 Spencer Oliver * : jimtcl: update to support --disable-install-jim Update jimtcl version to commit 6233a6c5d39928f1bfafa8f41cb1ddf0c5a83de0 This enable to to build jimtcl as a submodule but not install it. Signed-off-by: Spencer Oliver 2011-07-09 Luca Bruno * : Do not append git info to version string when building from released tarball When building official releases from tarball, git commit info is not available in the building environment. Thus, automake should not try to append the git commit to the version string. Signed-off-by: Luca Bruno Signed-off-by: Spencer Oliver 2011-07-12 Spencer Oliver * : busblaster: Fix warnings when building against D2XX The default is -Werror, so warnings become errors. Signed-off-by: Spencer Oliver 2011-07-12 Steve Bennett * : ftdi: update for latest libftdi 1.0.4 For libftd2xx1.0.4, which uses a different directory structure than libftd2xx0.4.16 Without this fix the build fails with version 1.0.4 of the driver. Note that this does not fix --with-ftd2xx-lib=shared Signed-off-by: Steve Bennett Signed-off-by: Spencer Oliver 2011-07-04 Drasko DRASKOVIC * : mips_m4k and arm7_9 : Fix soft bkpt endianess for 16-bit instructions The patch fix comparison of target data on the host by using target_buffer_get_u16() to transform current_instr to _host_ endianess before comparison. 2011-07-04 Spencer Oliver * : Revert "cortex_m3: add auto maskisr" This reverts commit ff640f197a9a343b2f3ed10e9174e35282334e8c. Original patch reverted as Author's name was incorrectly set. 2011-06-29 Spencer Oliver * : jimtcl: update to 0.71 based release The actual release is 411e92fea9621630eb350e0c2bb43543e553b84f as we had a few issues relating to its use within openocd. Signed-off-by: Spencer Oliver 2011-06-28 Øyvind Harboe * : mips4k: fix big-endian hosts and host alignment problems the code was making assumptions about the endianness of the host. 2011-06-28 Spencer Oliver * : cortex_m3: add auto maskisr This patch extends the cortex_m3 maskisr command by a new option 'auto'. The 'auto' option handles interrupts during stepping in a way they are processed but don't disturb the program flow during debugging. Before one had to choose to either enable or disable interrupts. The former steps into interrupt handlers when they trigger. This disturbs the flow during debugging, making it hard to follow some piece of code when interrupts occur often. When interrupts are disabled, the flow isn't disturbed but code relying on interrupt handlers to be processed will stop working. For example a delay function counting the number of timer interrupts will never complete, RTOS task switching will not occur and output I/O queues of interrupt driven I/O will stall or overflow. Using the 'maskisr' command also typically requires gdb hooks to be supplied by the user to switch interrupts off during the step and to enable them again afterward. The new 'auto' option of the 'maskisr' command solves the above problems. When set, the step command allows pending interrupt handlers to be executed before the step, then the step is taken with interrupts disabled and finally interrupts are enabled again. This way interrupt processing stays in the background without disturbing the flow of debugging. No gdb hooks are required. The 'auto' option is the default, since it's believed that handling interrupts in this way is suitable for most users. The principle used for interrupt handling could probably be used for other targets too. Signed-off-by: Spencer Oliver 2011-06-27 Spencer Oliver * : build: cleanup jimtcl generated configure.gnu We use configure.gnu to pass options to the jimtcl submodule. Make sure a distclean removes any generated files Signed-off-by: Spencer Oliver 2011-06-20 Martin Schmölzer * : Add OpenULINK driver files generated by SDCC to .gitignore 2011-06-20 Martin Schmölzer * : Include ULINK driver in src/jtag/drivers/Makefile.am A new variable "nobase_dist_pkglib_DATA" is introduced to install the OpenULINK firmware image to $PREFIX/lib/openocd/OpenULINK/ulink_firmware.hex Also, the variable "EXTRA_DIST" is used to include the OpenULINK firmware source in the OpenOCD source distribution. 2011-06-20 Martin Schmölzer * : Include ULINK driver in configure.in 2011-06-20 Martin Schmölzer * : Include ULINK driver in src/jtag/interfaces.c 2011-06-20 Martin Schmölzer * : Add source code for new ULINK driver 2011-06-17 Spencer Oliver * : build: do not included generated files in distribution We have to use this method as automake seems to ignore nodist_ on libs. Signed-off-by: Spencer Oliver 2011-06-17 Spencer Oliver * : build: pass correct flags to jimtcl during make distcheck This is only for the case of a make distcheck. During a normal release build these flags will be created by configure.gnu Signed-off-by: Spencer Oliver 2011-06-16 Tomek CEDRO * : ADAPTER: Fixed transport selection mechanism to support transports other than jtag (if defined). 2011-06-15 Dale Lukas Peterson * : Added Olimex STM32 {H,P}107.cfg board 2011-06-12 Øyvind Harboe * : HACKING: add tip on how to write comments 2011-06-10 Rodrigo L. Rosa * : doxy more 2011-06-10 Rodrigo L. Rosa * : fix protection behavior 2011-06-10 Rodrigo L. Rosa * : flash speed improved 2011-06-10 Rodrigo L. Rosa * : cleanup flash module command 2011-06-10 Rodrigo L. Rosa * : fix read speed improved by queueing commands 2011-06-10 Rodrigo L. Rosa * : Added minimodule (ftdi) interface 2011-06-06 Laurent Charpentier * : Added configuration file for stm32f2xxx. 2011-06-03 Freddie Chopin * : Fix "unused variable" warnings (errors) detected with GCC 4.7.0 - leftover changes 2011-06-02 Rodrigo L. Rosa * : crc check on flashed data 2011-06-03 Freddie Chopin * : Fix "unused variable" warnings (errors) detected with GCC 4.7.0 - dubious fixes 2011-06-02 Bear * : uptech2410 2011-05-31 Stefan Mahr * : mips: fixup fastdata fixup fastdata 2011-05-31 Laurent Charpentier * : bootstrap: fix argument handling - no argument => run submodule init - "nosubmoudle" => do not run submodule - other values => error message 2011-05-29 Stefan Mahr * : mips: fix swapping if running on big endian host 2011-05-28 Damjan Marion * : Fixed values for Samung NAND chips 2011-05-23 Damjan Marion * : Reorganize NAND flash table - added manufacturer field - name moved to the end for better text alignment 2011-05-23 Alan Bowman * : Report actual current thread 2011-05-24 Stefan Mahr * : add support for spansion flash on mindspeed c300 eval board Signed-off-by: Stefan Mahr 2011-05-23 Spencer Oliver * : Fix build issue under cygwin cygwin does not define sleep, so use our internal win32 version. caused by commit 9d4aec6bda90ad39a140747ea270c6a09dd26440 Signed-off-by: Spencer Oliver 2011-05-03 Jie Zhang * : Get register value if it's invalid in cache. 2011-05-17 Rodrigo L. Rosa * : flash support (only full erase/write) for 568013 and 568037 2011-05-11 Alan Bowman * : Correct stacking direction and use of address offset 2011-05-04 Øyvind Harboe * : beagleboard: add support for various icepick versions The beagleboard icepick jtag tap id's vary. 2011-04-27 Alexandre Pereira da Silva * : Add support for the lpc2460 target 2011-05-03 Jie Zhang * : Remove useless MIPS code in avr32_ap7k.c. 2011-04-28 Øyvind Harboe * : ecos: add 64 bit types for sprintf/sscanf 2011-04-19 Michel Jaouen * : gdb_server : 'R' command replied by OK 2011-04-19 Michel Jaouen * : smp : infra for smp minimum support 2011-04-24 SimonQian * : add STM32F2 revY 2011-04-21 Damjan Marion * : buspirate: fix building on some OSes 2011-04-12 Alexandre Pereira da Silva * : Fix non cfi x16 nor flash connected to x8 bus. The ids in the table should be masked before comparison. 2011-04-12 Alexandre Pereira da Silva * : Make the LPC32xx slc nand driver the default 2011-04-14 Broadcom Corporation (Evan Hunter) * : RTOS Thread awareness support wip - works on Cortex-M3 with ThreadX and FreeRTOS Compared to original patch a few nits were fixed: - remove stricmp usage - unsigned compare fix - printf formatting fixes - fixed a bug with overrunning a memory buffer allocated with malloc. 2011-04-13 Luca Ellero * : Replace byte-access to memory with faster word-access Freescale iMX53 doesn't seem to like unaligned accesses to his memory mapped registers. Anyway this patch makes dump_image/load_image 4X faster for every access through APB. Signed-off-by: Luca Ellero 2011-04-13 Luca Ellero * : Add preliminary support for Freescale iMX53 Signed-off-by: Luca Ellero 2011-04-12 Michel JAOUEN * : cortex_a :apb mem read/write working with mmu_on Conflicts: src/target/cortex_a.c 2011-04-12 Michel JAOUEN * : cortex_a : use dap ref from armv4_5common 2011-04-09 Jean-Christophe PLAGNIOL-VILLARD * : at91: add chip register definition and generic init support for - pio - pmc - rstc - wdt - sdramc - smc Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Cc: Nicolas Ferre Cc: Patrice Vilchez 2011-04-09 Jean-Christophe PLAGNIOL-VILLARD * : add at91sam9261-ek support Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Cc: Nicolas Ferre Cc: Patrice Vilchez 2011-04-09 Jean-Christophe PLAGNIOL-VILLARD * : jlink: jlink_debug_buffer use inline function when _DEBUG_USB_COMMS_ not define Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Cc: Nicolas Ferre Cc: Patrice Vilchez 2011-04-03 Ali Lown * : Add support for LED to USB Blaster code. 2011-04-05 Michel JAOUEN * : cortex_a : implement jtag console for cortex_a 2011-04-04 Drasko DRASKOVIC * : Corrected waiting on PrAcc in wait_for_pracc_rw(). Added necessary check that PrAcc is "1" before FASTDATA access. 2011-04-02 Øyvind Harboe * : pandaboard: use new -dbgbase option to workaround broken ROM table Signed-off-by: Øyvind Harboe 2011-04-01 Michel JAOUEN * : cortex_a: fix gaffe in first implementation of -dbgbase 2011-04-01 Øyvind Harboe * : mips: fix gaffe in previous commit accidentally invoked return jtag_execute_queue() in the middle of a fn. Hmm.... I would have expected gcc or at least lint to catch this. Signed-off-by: Øyvind Harboe 2011-03-31 Phil * : Added s19 to (fast_)load_image documentation to match the online help. 2011-03-31 Øyvind Harboe * : types: write memory now uses const Signed-off-by: Øyvind Harboe 2011-03-31 Øyvind Harboe * : startup: fix bugs in cleanup upon errors during startup Importantly adapter cleanup will now happen upon startup failure. Signed-off-by: Øyvind Harboe 2011-03-31 Øyvind Harboe * : mips: mips_ejtag_get_impcode error propagation added Signed-off-by: Øyvind Harboe 2011-03-31 Øyvind Harboe * : mips: fix error handling for jtag_execute_queue() Signed-off-by: Øyvind Harboe 2011-03-30 Øyvind Harboe * : cortex-a: use -dbgbase option Signed-off-by: Øyvind Harboe 2011-03-28 Olivier Schonken * : at91sam3: Modified cidr comparisson to ignore version bits production processor versions increment, thus the version bits should be ignored for future proofing. e.g. Engineering sample version == 0x00, production version 0x01 2011-03-29 Alexandre Pereira da Silva * : Clarify LPC32XX address cycles message Hi, This is a more descriptive message about LPC32XX error, when the nand chip needs 5 address cycles. Thanks. 2011-03-28 Andrew Lyon * : bugfix for step

mips_m4k The patch below fixes step
on mips_m4k. Spencer Oliver : The current code is used on all other arch's - is there a underlying issue with those aswell ? 2011-03-22 Øyvind Harboe * : cortex_a: rename cortex_a8.c/h to cortex_a.c/h Signed-off-by: Øyvind Harboe 2011-03-21 Øyvind Harboe * : cortex a9: merge cortex a9 and a8 code better to keep this in a single file. Signed-off-by: Øyvind Harboe 2011-03-21 Øyvind Harboe * : zy1000: fix bug in ir scan handling set cur_instr to BYPASS as optimisation code will rely on checking the cached value. Signed-off-by: Øyvind Harboe 2011-03-20 Øyvind Harboe * : dsp563xx_once: fix warning and potential bug I don't think dsp563xx_once_read_register() would ever be called with len==0, but it would have been broken in that case. Signed-off-by: Øyvind Harboe 2011-03-03 Mathias K * : target: allow targets to override memory alignment Targets can implement read/write_buffer to handle alignment. 2011-03-17 Uwe Hermann * : Fix a bunch of typos. Fix a bunch of typos. Most are in code comments, so nothing should break. UNKOWN_COMMAND and CMD_UNKOWN are not used elsewhere, so correcting the spelling should also not break anything. 2011-03-15 Øyvind Harboe * : dsp563xx: fix bug in x buffer handling found by inspection. Signed-off-by: Øyvind Harboe 2011-03-03 Øyvind Harboe * : zy1000: fix JTAG over TCP/IP performance problem only flush write queue just before waiting for more data, rather than when fetching more data from the buffer. Signed-off-by: Øyvind Harboe 2011-03-03 Øyvind Harboe * : jtag: clean up jtag_sleep, handle short sleeps correctly via usleep short sleeps are handled via usleep, longer sleeps we round up to nearest ms. There was a bug in jtag_sleep() in that it would round *down* to nearest ms, thus making all <1ms sleeps 0. Found by inspection rather than symptom. Signed-off-by: Øyvind Harboe 2011-03-10 Aaron Carroll * : omap4430: add Blaze config Signed-off-by: Aaron Carroll 2011-03-07 Jean-Christophe PLAGNIOL-VILLARD * : jlink: add Emulator configuration support Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Cc: Nicolas Ferre Cc: Patrice Vilchez 2011-03-07 Jean-Christophe PLAGNIOL-VILLARD * : jlink: use tap buffer as 2k as said in the datasheet Section 3.3.2 Organization of buffers All buffers are big enough to hold 2 KByte of data. this will double the speed of download Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Cc: Nicolas Ferre Cc: Patrice Vilchez 2011-03-03 Mathias K * : ft2232: fix log message and change log output to debug 2011-03-02 Jean-Christophe PLAGNIOL-VILLARD * : at91: add at91sam9g10 support Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Cc: Nicolas Ferre Cc: Patrice Vilchez 2011-03-02 Jean-Christophe PLAGNIOL-VILLARD * : at91: add at91sam9263 support Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Cc: Nicolas Ferre Cc: Patrice Vilchez 2011-03-02 Jean-Christophe PLAGNIOL-VILLARD * : at91sam9: factorise cpu support all at91sam9 are nearly the same except sram and soc name Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Cc: Nicolas Ferre Cc: Patrice Vilchez 2011-02-28 Jean-Christophe PLAGNIOL-VILLARD * : jlink: switch commands to subcommands Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD 2011-02-28 Jean-Christophe PLAGNIOL-VILLARD * : jlink: add new PID and VID The default pid of the segger is 0x0101 But when you change the USB Address it will also pid = ( usb_address > 0x4) ? 0x0101 : (0x101 + usb_address) Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD 2011-02-24 Øyvind Harboe * : log: debug level is between silent and debug output levels It wasn't previously possible to silence the output. Signed-off-by: Øyvind Harboe 2011-02-24 Mathias K * : ft2232: fix possible read buffer overflow This patch fix a possible read buffer overflow in ft2232_execute_queue. Also the correct read queue size for libftdi and libftd2xx was added and and tested. In function ft2232_write a uninitialized value was initialized because we don't know if this value was set in the ftdi api call. 2011-02-21 Jean-Christophe PLAGNIOL-VILLARD * : add at91rm9200-ek board support tested with jlink sam-ice v5 while loading barebox (gdb) load Loading section .text, size 0x2f190 lma 0x21f00000 Loading section .rodata, size 0x931c lma 0x21f2f190 Loading section .data, size 0x29e8 lma 0x21f384ac Loading section .barebox_cmd, size 0x78c lma 0x21f3ae94 Loading section .barebox_initcalls, size 0x80 lma 0x21f3b620 Start address 0x21f00000, load size 243360 Transfer rate: 26 KB/sec, 13520 bytes/write. Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Cc: Nicolas Ferre Cc: Patrice Vilchez 2011-02-20 Mathias K * : dsp563xx: rudimentary gdb support This patch add rudimentary gdb support. The gdb register list order is corrected. All registers are now 32bit width. Events are send to signalize gdb the current target status. Resume and step function was corrected to consider a modified pc register. Read/write memory now support L memory type, this means a memory with alternating y/x memory words. The memspace variable, used by gdb, is now observed before a default memory access is initiated. Dummy functions for breakpoint and watchpoint are added. 2011-02-18 SimonQian * : fix compile error under MinGW 2011-02-14 Luca Ellero * : arm_adi_v5: add/move apsel member in struct adiv5_dap This patch tries to make some order in "apsel" mess. "dap apsel" command was quite useless (and broken) by itself. With this patch we can use it to select between AHB or APB memory access (previous patch 05ab8bdb813acdcd74afa71d6656c2df816cb230 was somehow broken). - moves member apsel (in struct adiv5_dap) to ap_current - adds apsel member this strange choice is made trying to keep coherence in "dap apsel" command and to keep compatibility with other code (for example cortex_a8). Signed-off-by: Luca Ellero 2011-02-17 Mathias K * : dsp563xx_once: Correct wrong return value on jtag communication errors This patch change the return value on a jtag communication error to TARGET_UNKNOWN because this function should return the current target status and not a error code from the underlying api call. Also the validity of the jtag_status is extended to all static bits in this value. 2011-02-15 Bjarne Steinsbo * : lpc32xx: Flash driver Based on the lpc3180 driver, but released as a separate driver for two reasons: 1) I don't have an lpc3180 to test it against, so it might unintentionally break compatibility. 2) It's using a different OOB layout than lpc3180. Rewritten so that it no longer borrows code from the NXP CDL library. Instead borrowing code from the u-boot port to lpc32xx, written by Kevin Wells. Tested on lpc3250 (Hitex LPC3250-Stick). OOB layout is compatible with LPCLinux. 2011-02-15 Mathias K * : - add bulk memory write function - execute jtag queue at the end of the memory transfer 2011-02-13 Mathias K * : ft2232: add functions for ft2232 set data bits high/low byte command reduce duplication. No change in behavior. 2011-02-12 Luca Ellero * : arm_adi_v5: add wrapping transfer functions with selection of ap Signed-off-by: Luca Ellero 2011-02-12 Luca Ellero * : cortex_a9: check if MMU is enabled on APB read/write memory Signed-off-by: Luca Ellero 2011-02-12 Luca Ellero * : cortex_a9: trivial fixes Signed-off-by: Luca Ellero 2011-02-09 Luca Ellero * : cortex_a9: implement read/write memory through APB-AP This patch adds read/write capability to memory addresses not accessible through AHB-AP (for example "boot ROM code"). To select AHB or APB, a "dap apsel" command must be issued: dap apsel 0 -> following memory accesses are through AHB dap apsel 1 -> following memory accesses are through APB NOTE: at the moment APB memory accesses are very slow, compared to AHB accesses. Work has to be done to get it faster (for example LDR/STR instead od LDRB/STRB) Signed-off-by: Luca Ellero 2011-02-08 Michal Demin * : buspirate: Fix command parsing, fix errors to have more sense. Signed-off-by: Michal Demin 2011-02-07 Luca Ellero * : omap4430: Add JRC TAPID for PandaBoard REV EA1 (PEAP platforms) PandaBoard REV EA1 (Panda Early Adopter Program) has a different ID. This patch add alternate REV EA1 TAP id to configuration file Signed-off-by: Luca Ellero 2011-02-08 Luca Ellero * : cortex_a8/a9: fix some comments Signed-off-by: Luca Ellero 2011-01-31 Øyvind Harboe * : stm32x: add support for STM32F20x ready for wider testing and comments on basic erase + programming. Signed-off-by: Øyvind Harboe 2011-02-02 Mathias K * : 24bit buffer support Hello, this patch add 24bit support to the target buffer functions and little/big endian functions. Regards, Mathias 2011-02-02 Aaron Carroll * : cortex_m3: allow scripts to override reset If a handler for the reset-assert event it present, skip the usual reset handling. This is needed, for example, for board-level resets. Signed-off-by: Aaron Carroll 2011-01-31 Øyvind Harboe * : cfi: use ARM32 machine code on all CPUs but Cortex M3 ARM11 broke with aa61a3b3d8b6acad19050987835ec05f3d298bdb as the code only checked for arm 7/9. CFI probably needs work for non-ARM targets but perhaps not adding working area memory to e.g. MIPS will give the default slow CFI support. Signed-off-by: Øyvind Harboe 2011-01-24 Aaron Carroll * : cortex_a9: add source files for Cortex A9 support. add target and build support for A9 Signed-off-by: Aaron Carroll 2011-01-24 Aaron Carroll * : Add '-coreid' target option to support multiple cores per TAP. ARM Cortex-A9 multi-core chips expose a single TAP/DAP which connects to both cores. The '-coreid' option selects which core the target should connect to. Note that at present, OpenOCD can connect to either core, but not both simulatenously, until ADI contexts can be shared. Signed-off-by: Aaron Carroll 2011-01-28 Aaron Carroll * : openocd.texi: minor fixes in Reset Configuration Signed-off-by: Aaron Carroll 2011-01-26 Mathias K * : - add xds100v2 configuaration file Signed-off-by: Spencer Oliver 2011-01-26 Mathias K * : add basic TI xds100v2 support Signed-off-by: Spencer Oliver 2011-01-18 Eric Wetzel * : stellaris: automatically generate and update device IDs Added a Perl script to contrib that uses the header files in StellarisWare complete Firmware Development Package provided by TI/Luminary to generate a new list of device IDs Used Perl script and revision 6734 of TI/Luminary StellarisWare to update device IDs 2011-01-13 Santeri Salko * : str9xpec: Find flash controller from the chain. Find the flash controller by position since it is before the core, not after it. This fixes the problem that str9xpec enable_turbo (or any other str9xpec command) did not work. (See my post in http://forum.sparkfun.com/viewtopic.php?f=18&t=25542) Signed-off-by: Santeri Salko 2011-01-13 simon qian * : transport: fix LOG_DEBUG gaffe LOG_DEBUG() arguments are only evaluated when DEBUG logging is enabled, do not use arguments that have side effects like foo++. Signed-off-by: Øyvind Harboe 2011-01-05 Eric Wetzel * : nit: more LOG_* \n fixes Remove extra \n from LOG_DEBUG, LOG_INFO, and LOG_WARNING messages Remove LOG_INFO_N LOG_INFO_N was only used once and had a \n at the end Change LOG_USER_N calls that end with \n to LOG_USER 2011-01-08 David Brownell * : present CM3 Trace agenda 2011-01-06 Spencer Oliver * : cfi: use safer arch detection Signed-off-by: Spencer Oliver 2011-01-05 Jonathan Dumaresq * : Add the support for the armv7m arch. Signed-off-by: Jonathan Dumaresq 2011-01-05 Eric Wetzel * : nit: do not add \n at end of LOG_ERROR Fixed in many other places, and submitted in response to Øyvind's invitation. 2010-12-24 Spencer Oliver * : target: change working area free data type We only use the struct working_area member 'free' as a true/false type so might as well use a bool data type. Signed-off-by: Spencer Oliver 2011-01-03 Øyvind Harboe * : error handling: the error number is not part of the user interface Do not propagate error number to user. This is for internal programming purposes only. Error messages to the user is reported as text via LOG_ERROR(). Signed-off-by: Øyvind Harboe 2011-01-02 Michael Schwingen * : cfi_protect is not implemented on Spansion flashes (many do not even have protection bits). Demote from error to warning, so that common board code can use "flash write_image erase unlock" regardless of the flash type. Signed-off-by: Michael Schwingen 2011-01-02 Jon Povey * : svf: implement sleep for RUNTEST min_time Signed-off-by: Jon Povey min_time was effectively ignored, I needed it to program a Lattice MachXO which uses a RUNTEST to wait for an erase operation, amongst other things. With this patch pauses happen and I can program the device with an SVF generated in LSC ispVM (with "Rev D Standard" checked to suppress nonstandard LOOP statements) 2010-12-31 Antonio Borneo * : NAND/S3CXXXX: remove private "target" copy Remove "target" form private data, and use common one in struct nand_block. Signed-off-by: Antonio Borneo 2010-12-31 Antonio Borneo * : NAND/NUC910: remove private "target" copy Remove "target" form private data, and use common one in struct nand_block. Signed-off-by: Antonio Borneo 2010-12-31 Antonio Borneo * : NAND/MX2: remove private "target" copy Remove "target" form private data, and use common one in struct nand_block. Signed-off-by: Antonio Borneo 2010-12-31 Antonio Borneo * : NAND/DAVINCI: remove private "target" copy Remove "target" form private data, and use common one in struct nand_block. Signed-off-by: Antonio Borneo 2010-12-31 Antonio Borneo * : NAND/TCL: prepare for common "target" reference Every NAND driver keeps private copy of "target" structure. Prepare infostructure to move private "target" copy in common/shared struct nand_device. Signed-off-by: Antonio Borneo 2010-12-31 Antonio Borneo * : NAND/CORE: Comment use of alive_sleep() Signed-off-by: Antonio Borneo 2010-12-31 Antonio Borneo * : flash/nand: review NAND driver interface From struct nand_flash_controller : - remove unused field register_commands; - remove field controller_ready, exported but never referenced. Remove dead code pointed by controller_ready. Signed-off-by: Antonio Borneo 2010-12-29 Andrew MacIsaac * : Compilation Warnings on OS X 10.5 I received a number of "-Wshadow" related warnings (treated as errors) while trying to build on OS X Leopard. In addition, there were two miscellaneous other warnings in the flash drivers. Attached are two patches which correct these issues and the commit messages to accompany them. My system has the following configuration (taken from uname -a): Darwin 9.8.0 Darwin Kernel Version 9.8.0: Wed Jul 15 16:55:01 PDT 2009; root:xnu-1228.15.4~1/RELEASE_I386 i386 === Werror_patch.txt Commit Message === compilation: fixes for -Wshadow warnings on OS X These changes fix -Wshadow compilation warnings on OS X 10.5.8 Compiled with the following configure command: ../configure --prefix=/usr/local --enable-maintainer-mode --enable-jlink --enable-ft2232_libftdi === flash_patch.txt Commit Message === compilation: fixes for flash driver warnings on OS X These changes fix two compilation warnings on OS X 10.5.8: ../../../../src/flash/nor/at91sam3.c:2767: warning: redundant redeclaration of 'at91sam3_flash' ../../../../src/flash/nor/at91sam3.c:101: warning: previous declaration of 'at91sam3_flash' was here and ../../../../src/flash/nor/stmsmi.c:205: warning: format not a string literal and no format arguments Compiled with the following configure command: ../configure --prefix=/usr/local --enable-maintainer-mode --enable-jlink --enable-ft2232_libftdi === Andrew 2010-12-29 Øyvind Harboe * : warnings: use more 'const' for char * Signed-off-by: Øyvind Harboe 2010-12-24 David Brownell * : initial SWD transport (SWD infrastructure #2) This piggy backs on JTAG so it's not yet pretty, but that seems unavoidable so far given today's OpenOCD internals. SWD init and data transfer are unfinished and untested, but that should cause no regressions, and will be addressed by the time drivers start using this infrastructure. Checking in whould get the code working better sooner, and turn up any structural/architectural issues while they're easier to fix. The debug adapter drivers will provide simple SWD driver structs with methods that kick in as needed (instead of JTAG). So far just one adapter driver has been updated (not yet ready to use or circulate). The biggest issues are probably - fault handling, where the ARM Debug Interface V5 pipelining needs work in both JTAG and SWD modes and - missing rewrite of block I/O code to work on both of our Cortex-ready transports (Current code is hard-wired to JTAG); relates also to the pipelining issue. - omitted support to activate/deactivate SWO/SWV trace (this is technically trivial, but configuring what to trace is NOT. Signed-off-by: David Brownell ---- doc/openocd.texi | 17 ++ src/jtag/core.c | 3 src/jtag/interface.h | 4 src/jtag/jtag.h | 2 src/jtag/swd.h | 114 +++++++++++++++++++ src/jtag/tcl.c | 2 src/target/adi_v5_swd.c | 281 ++++++++++++++++++++++++++++++++++++++++++++++-- src/target/arm_adi_v5.c | 8 + src/target/arm_adi_v5.h | 3 9 files changed, 425 insertions(+), 9 deletions(-) 2010-12-23 Spencer Oliver * : flash: print flash bank name on flash info cmd The flash bank name is a required element in adding flash banks, however other than looking at the config file there is no way of getting the name used in openocd. Signed-off-by: Spencer Oliver 2010-12-23 Spencer Oliver * : stm32: update option bytes for stm32xl family add supoort for xl family boot bank option. The option byte handling will be cleaned up in a later patch. Signed-off-by: Spencer Oliver 2010-12-22 Spencer Oliver * : stm32: add dual flash bank support This patch adds the initial dual flash bank support for devices such as the stm32xl family. Signed-off-by: Spencer Oliver 2010-12-21 Øyvind Harboe * : lpc2148: redo to the new target configuration scheme Define a proc which PCBs can easily override. Also demonstrates how to add multiple TAP exepcted-id's using arguments. Added 0x3f0f0f0f as expected TAP-id. Old LPC2148 silicon I happened to have on my desk? Signed-off-by: Øyvind Harboe 2010-12-22 Øyvind Harboe * : bootstrap: by default the submodules are initialized use "nosubmodule" to skip setting up submodules. Signed-off-by: Øyvind Harboe 2010-12-19 Tormod Volden * : tcl/interface/flashlink.cfg: Fix broken ST URL 2010-12-19 Tormod Volden * : tcl/board: Fix ST URLs in stm32* eval board configuration files ST recently rewamped (screwed up) their web site and broke all links. Also match the chip names with those on the web site product descriptions. 2010-12-16 Michael Trensch * : Add support for Hilscher netX controllers 2010-12-19 Antonio Borneo * : TCL: fix non TCL comments End of line comments fixed with ';' before '#'. Added few additional 'space' to keep indentation in multi-line comments. Signed-off-by: Antonio Borneo 2010-12-14 John Devereux * : Fix for compilation failure amt_jtagaccel.c Hi, I think there are errors in amt_jtagaccel.c I attach a small patch that I needed to make it compile. 2010-12-14 Øyvind Harboe * : stm32: fix unprotect the unprotect fn in stm32 needs to unprotect more sectors than was requested aligned to some boundary. Print warning when this happens. Signed-off-by: Øyvind Harboe 2010-12-10 Spencer Oliver * : contrib: add source to the cfi flash loaders Signed-off-by: Spencer Oliver 2010-12-08 Spencer Oliver * : stm32: add STM32E-EVAL external memory config script Signed-off-by: Spencer Oliver 2010-12-08 Spencer Oliver * : cfi: allow optional buffer write support Some flash's do not support buffer writes, so we now check they are supported before trying to use them. Signed-off-by: Spencer Oliver 2010-12-08 Spencer Oliver * : cfi: prefix string hex output Add hex prefix so we know output is not decimal. Signed-off-by: Spencer Oliver 2010-12-08 Spencer Oliver * : cfi: whitespace and long line cleanup Signed-off-by: Spencer Oliver 2010-12-04 Freddie Chopin * : remove srst_pulls_trst from LPC2xxx target scripts LPC2xxx do not require reset_config srst_pulls_trst. This can cause various "strange" problems when flashing the chip, because "reset halt" actually allows the chip to run for some short period of time and execute some code. Signed-off-by: Freddie Chopin 2010-12-06 Øyvind Harboe * : jtag: getting the JTAG speed can fail If the JTAG speed has not been set, then it has no defined value, add code to propagate the error. No change to actual behavior as no new failure paths have been introduced. This is a no-op patch to make subsequent patches smaller. Signed-off-by: Øyvind Harboe 2010-12-03 Rolf Meeser * : lpc2478 target config: CCLK as (mandatory) parameter 2010-12-03 Rolf Meeser * : Add board config for Embedded Artists LPC2478-32 2010-12-03 Rolf Meeser * : Fix sector layout for 504-KiB LPC2000 devices 2010-12-02 Spencer Oliver * : luminary: remove unused config cmds. Due to commit e40aee2954d2beabe1d8c530d9ff1e564fb01f48 we now honour the targets 'reset_config' setting. Previously we ignored the srst setting for luminary targets. Luminary targets have never supported using srst to reset into debug mode so remove the option from the target configs files. Signed-off-by: Spencer Oliver 2010-12-02 Spencer Oliver * : config: fix luminary jtag config When this config was updated in commit e3773e3e3d1f1ee0dbb0b69e8babe8419784d1c1 the old jtag declaration was not removed. Signed-off-by: Spencer Oliver 2010-12-01 Øyvind Harboe * : profile: use 100Hz as a default sampling frequency it's a lie that is somewhere in the vicinity of the truth. Certainly 64MHz confuses gprof and produces zero output and no error messages. Signed-off-by: Øyvind Harboe 2010-12-01 Rolf Meeser * : lpc2900.c: Add support for new device LPC2926 2010-11-29 Piotr Esden-Tempski * : Some cosmetic fixes to the Lisa/L layout support functions. 2010-11-29 Piotr Esden-Tempski * : Updated Floss-JTAG config file to support v0.3 and newer. Also added noeeprom version of the config file for older versions of Floss-JTAG. 2010-11-26 Spencer Oliver * : build: correct configure help message As we default to building jimtcl the help text should show that. No change in functionality or configure args required. Signed-off-by: Spencer Oliver 2010-11-22 Antonio Borneo * : FLASH/NOR: rename from spearsmi to stmsmi STMicroelectronics controller SMI is not SPEAr specific. Rename it and change name to every symbol in the code. Signed-off-by: Antonio Borneo 2010-11-18 Antonio Borneo * : NOR/SPEARSMI: fix segfault If flash chip is not listed in the table, or if no flash is connected, pointer must be properly initialized. Signed-off-by: Antonio Borneo 2010-11-22 Øyvind Harboe * : flash: iterating over an address range now handles multiple banks e.g. flash erase_address now works across an address range that spans multiple flash chips. Signed-off-by: Øyvind Harboe 2010-11-19 Spencer Oliver * : build: remove AC_CONFIG_AUX_DIR macro This was used during testing and should have been removed. Signed-off-by: Spencer Oliver 2010-11-19 Spencer Oliver * : build: fix subconfigure parameter issue When passing CFLAGS for example through to the jimtcl subconfigure the quotes were not being preserved. Signed-off-by: Spencer Oliver 2010-11-19 Spencer Oliver * : build: prepend --with-jim-ext=nvp to jimtcl configure This allows us to add options to jimtcl configure. The default autoconf AC_CONFIG_SUBDIRS does not currently support this. Signed-off-by: Spencer Oliver 2010-11-12 Spencer Oliver * : build: add common.mk Rather than specifying common makefile variables move them all to a common.mk. Signed-off-by: Spencer Oliver 2010-11-17 Antonio Borneo * : FLASH/NOR: Remove useless file str9xpec.h Signed-off-by: Antonio Borneo 2010-11-17 Antonio Borneo * : FLASH/NOR: Remove useless file str7x.h Signed-off-by: Antonio Borneo 2010-11-17 Antonio Borneo * : FLASH/NOR: Remove useless file stellaris.h Signed-off-by: Antonio Borneo 2010-11-17 Antonio Borneo * : FLASH/NOR: Remove useless file lpc288x.h Signed-off-by: Antonio Borneo 2010-11-17 Antonio Borneo * : FLASH/NOR: Remove useless file avrf.h Signed-off-by: Antonio Borneo 2010-11-17 Antonio Borneo * : FLASH/NOR: Remove useless file at91sam7.h Signed-off-by: Antonio Borneo 2010-11-17 Antonio Borneo * : FLASH/NOR: Remove useless file spearsmi.h Signed-off-by: Antonio Borneo 2010-11-11 Antonio Borneo * : TCL/SPEAr: Added Serial flash in board file Signed-off-by: Antonio Borneo 2010-11-11 Øyvind Harboe * : httpd: retire this server this never panned out and there are enough mistakes in the code that probably nobody used this. Use the tcl server and implement a standalone http app instead works fine. Signed-off-by: Øyvind Harboe 2010-11-13 Øyvind Harboe * : gdb: fix occasional crash when flash probe failed Signed-off-by: Øyvind Harboe 2010-11-09 Øyvind Harboe * : cortex_m3: report detected error condition in poll If the CPU crashed at some point, poll will discover this. Previously the poll fn would clear the error and print a warning, rather than propagating the error. The new behavior is to report the error back up, but still clear the error. Signed-off-by: Øyvind Harboe 2010-11-08 Antonio Borneo * : TCL scripts: replace "puts" with "echo" Signed-off-by: Antonio Borneo 2010-11-08 Antonio Borneo * : JIM: Add "-n" option to "echo" With the new JIMTCL, "puts" only writes to stdout. To write on telnet port too, "echo" must be used. This patch gives to "echo" similar commandline option of "puts". Signed-off-by: Antonio Borneo 2010-11-08 Øyvind Harboe * : stm32: return error when failing to read add missing error handling. Output warning when assuming maximum flash size in the family when failing to read. Signed-off-by: Øyvind Harboe 2010-11-08 Øyvind Harboe * : stm32: sharpen error handling for timeouts delete lots of crud by handling this all in one spot. Signed-off-by: Øyvind Harboe 2010-11-04 Antonio Borneo * : TCL scripts: add support for ST SPEAr310 Initial support for ST SPEAr310 and for the evaluation board EVALSPEAr310 Rev. 2.0. Scripts are split in generic for SPEAr3xx family and specific for SPEAr310. This should easily allow adding new members of the family. Signed-off-by: Antonio Borneo 2010-10-29 Marek Vasut * : CortexA8: Introduce Freescale i.MX51 variant This patch introduces support for Cortex A8 based Freescale i.MX51 CPU. This CPU has the Debug Access Port located at a different address (0x60008000) than TI OMAP3 series of CPUs. i.MX51 configuration file based on OMAP3 configuration file and an email from Alan Carvalho de Assis . Signed-off-by: Marek Vasut 2010-10-31 Marek Vasut * : ADIv5: Implement function to lookup CoreSight component This patch implements "dap_lookup_cs_component()", which allows to lookup CS component by it's identification. Signed-off-by: Marek Vasut 2010-11-04 ddraskovic * : arm964e: Add support for ARM946E target. So far most of the people have been using existing ARM966E in the place of ARM946E, because they have practically the same scan chains. However, ARM946E has caches, which further complicates JATG handling via scan-chain. this was preventing single-stepping for ARM946E when SW breakpoints are used. This patch thus introduces : 1) Correct cache handling on memory write 2) Possibility to flush whole cache and turn it off during debug, or just to flush affected lines (faster and better) 3) Correct SW breakpoint handling and correct single-stepping 4) Corrects the bug on CP15 read and write, so CP15 values are now correctly R/W 2010-10-15 Øyvind Harboe * : jimtcl: 0.63 release as a git module. Signed-off-by: Øyvind Harboe 2010-10-28 Spencer Oliver * : src: add loader src description - add comment where to find the various loaders src files. Signed-off-by: Spencer Oliver 2010-10-28 Øyvind Harboe * : imx31pdk: use rclk w/1MHz fallback measure_clk indicates ca. 3-4MHz, so 1MHz should be safe. Added self_test proc used to test that rclk worked. Signed-off-by: Øyvind Harboe 2010-10-24 Peter Stuge * : Make systesetreq typos read sysresetreq instead Signed-off-by: Peter Stuge 2010-10-22 Michal Demin * : buspirate: change handling of communication speed setting + create serial port open function Signed-off-by: Michal Demin 2010-10-12 Antonio Borneo * : TARGET: review handle_load_image_command() Collect variable definitions. Report syntax error to command dispatcher. Propagate error when unable to open file. Signed-off-by: Antonio Borneo 2010-10-10 David Brownell * : swj-dp.tcl (SWD infrastructure #1) Provide new helper proc that can set up either an SWD or JTAG DAP based on the transport which is in use -- mostly for SWJ-DP. Also update some SWJ-DP based chips/targets to use it. The goal is making SWD-vs-JTAG transparent in most places. SWJ-DP based chips really need this flexible configuration to cope with debug adapters that support different transports, without needing new target configs for each transport or adapter. For JTAG-DP, callers will use "jtag newtap" directly, as today; only one chip-level transport option exists. For SW-DP (e.g. LPC1[13]xx or EFM32, they'll use "swd newdap" directly (part of an upcoming SWD transport patch). Again, only one transport option exists, so hard-wiring is appropriate there. Signed-off-by: David Brownell 2010-10-05 Spencer Oliver * : build: remove warn_unused_result errors Remove any build errors for strtol when building release version of openocd. Signed-off-by: Spencer Oliver 2010-10-04 Spencer Oliver * : gdbserver: fix gdb_port memory leak Signed-off-by: Spencer Oliver 2010-09-05 Øyvind Harboe * : zy1000: add : port number syntax for tftp filing system Allows using non-standard port number. Default to port 69. Signed-off-by: Øyvind Harboe 2010-09-27 Øyvind Harboe * : server: add support for pipes -p/--pipe is now deprecated. Use '-c "gdb_port pipe;log_output openocd.log"' instead. Warning logged. Signed-off-by: Øyvind Harboe 2010-09-27 Øyvind Harboe * : server: read/write now goes through connection fn's depending on whether the connection is over a socket or pipe, the read is done differently. pipes can return -1 when writing 0 bytes, make 0 byte writes a successful no-op. 0 byte writes falls out naturally of tcl server code. Signed-off-by: Øyvind Harboe 2010-09-26 Øyvind Harboe * : server: rely on ctrl-c to stop openocd there was special support to support pressing 'x' to quit openocd. ctrl-c is sufficient. The main server loop is already complicated enough. Signed-off-by: Øyvind Harboe 2010-09-27 Luca Bruno * : Update ep93xx and at91rm9200 drivers ep93xx and at91rm9200 are conditionally built only on arm and were not updated to reflect changes in command registration handler. This patch makes them properly compile again, fixing a build failure experienced on Debian armel. Signed-off-by: Luca Bruno Signed-off-by: Zachary T Welch 2010-09-28 Øyvind Harboe * : fileio: refactor struct fileio to be an opaque structure Signed-off-by: Øyvind Harboe 2010-09-27 Øyvind Harboe * : flash: fix error handling memory leaks and missing check on memory allocation. Signed-off-by: Øyvind Harboe 2010-09-24 Zachary T Welch * : Fix omap3_dbginit to write to physical memory. Setting the OMAP3530 DBGEN bit must be done in physical memory, so update omap3_dbginit callback to use the new 'mww phys' command syntax. 2010-09-26 Øyvind Harboe * : gdb: fix blank line at top snuck in at some point... Signed-off-by: Øyvind Harboe 2010-09-20 Øyvind Harboe * : flash: fix error handling sensible error must be reported at failure site Signed-off-by: Øyvind Harboe 2010-09-21 Antonio Borneo * : TCL scripts: collect duplicated procedures TCL procedures mrw and mmw, originally in DaVinci target code, are duplicated in other TCL scripts. Moved in a common helper file, and added help/usage description. Signed-off-by: Antonio Borneo 2010-09-20 Øyvind Harboe * : helper: fix flaky capture command capture of progress output would get polling results. This will break in the example below where polling output would override the tcl return value. capture {sleep 10000; set abc def} Signed-off-by: Øyvind Harboe 2010-09-18 Øyvind Harboe * : logging: turn of stdout/stderr buffering with this buffering disabled fancier logging scripts will be able to process each line as it is output. Signed-off-by: Øyvind Harboe 2010-09-20 Øyvind Harboe * : jtag: build jtag first because it generates header files Signed-off-by: Øyvind Harboe 2010-09-07 Øyvind Harboe * : zy1000: split out configure option for eCos and JTAG master Signed-off-by: Øyvind Harboe 2010-09-20 Øyvind Harboe * : tcl: remove incomplete unused tcl file Signed-off-by: Øyvind Harboe 2010-09-19 Mike Dunn * : xscale: check that wp length does not exceed address Hi everyone, A while back I sent in a patch that adds support for watchpoint lengths greater than four on xscale. It's been working well, until the other day, when it caused an unexpected debug exception. Looking into this I realized there is a case where it breaks: when the length arg is greater than the base address. This is a consequence of the way the hardware works. Don't see a work-around, so I added code to xscale_add_watchpoint() to check for and disallow this combination. Some more detail... xscale watchpoint hardware does not support a length directly. Instead, a mask value can be specified (not to be confused with the optional mask arg to the wp command, which xscale does not support). Any bits set in the mask are ignored when the watchpoint hardware compares the access address to the watchpoint address. So as long as the length is a power of two, setting the mask to length-1 effectively specifies the length. Or so I thought, until I realized that if the length exceeds the base address, *all* bits of the base address are ignored by the comaparator, and the watchpoint range effectively becomes 0 .. length. Questions, comments, criticisms gratefully received. Thanks, Mike Signed-off-by: Mike Dunn 2010-09-18 Karl Kurbjun * : AM/DM37x: Unify configuration scripts and add support for TI Beagleboard xM. 2010-09-13 Øyvind Harboe * : breakpoints: fix error handling do not try to interpret "retval" into a string, just amend a bit about the context of the already reported error. Signed-off-by: Øyvind Harboe 2010-09-13 Mike Dunn * : xscale: fix sw breakpoints for thumb; set bp immediately Hi everyone, Version 2 of this patch. Code added to breakpoints.c was removed from previous patch, and item 3 added, per discussion with Øyvind regarding error reporting. Item 4 added, which I just noticed. I tried to use a software breakpoint in thumb code on the xscale for the first time recently, and was surprised to find that it didn't work. The result was this patch, which does four things: 1): fix trivial cut-n-paste error that caused thumb breakpoints to not work 2): call xscale_set_breakpoint() from xscale_add_breakpoint() 3): log error on data abort in xscale_write_memory() 4): fixed incorrect error code returned by xscale_set_breakpoint() when no breakpoint register is available; added comment Item 2 not only makes the xscale breakpoint code consistent with other targets, but also alerts the user immediately if an error occurs when writing the breakpoint instruction to target memory (previously, xscale_set_breakpoint() was not called until execution resumed). Also, calling xscale_breakpoint_set() as part of the call chain starting with handle_bp_command() and propagating the return status back up the chain avoids the situation where OpenOCD "thinks" the breakpoint is set when in reality an error ocurred. Item 3 provides a helpful message for a common reason for failure to set sw breakpoint. This was thoroughly tested, mindful of the fact that breakpoint management is somewhat dicey during single-stepping. Comments and criticisms of course gratefully received. Mike Signed-off-by: Mike Dunn Signed-off-by: Øyvind Harboe 2010-09-12 Øyvind Harboe * : helper: add stacktrace command that returns error stacktrace Ability to access the stacktrace from a script is quite handy. Signed-off-by: Øyvind Harboe 2010-09-10 Øyvind Harboe * : version command: make it scriptable you can now set a variable in a script like set version [version]. Also version takes an optional argument "git" to show git version of source. If git is not installed during the build, then this will yield an error that is ignored during the build and "version git" returns an empty string. Signed-off-by: Øyvind Harboe 2010-09-10 Øyvind Harboe * : cfi: random crash in cfi_probe() fixed for non_cfi cfi chips free() was invoked on rodata. The mystery is why this bug has survived for so long. Signed-off-by: Øyvind Harboe 2010-09-08 Mike Dunn * : xscale: mark xscale registers invalid on debug entry Hi everyone, This simple patch fixes a problem I noticed on the xscale where incorrect values are sometimes reported by the reg command. The problem can occur when requesting the value of registers in the xscale-specific register cache. With a couple of exceptions, none of the registers in the xscale register cache are automatically retrieved on debug entry. This is probably fine, as they are unlikely to be needed on a regular basis during a typical debug session, and they can be retrieved when explicitly requested by name using the reg command. The problem is that once this is done, the register remains marked as valid for the remainder of the OpenOCD session, and the reg command will henceforth always report the same value because it is obtained from the cache and is never again retrieved from the debug handler on the target. The fix is to mark all registers in the xscale register cache as invalid on debug entry (before the two exceptions are retrieved), thus forcing retrieval (when requested) from the target across resumptions in execution, and avoiding the reporting of stale values. Small addition change by Øyvind: change 'i' to unsigned to fix compiler warning for xscale_debug_entry() fn. Signed-off-by: Mike Dunn Signed-off-by: Øyvind Harboe 2010-09-07 Øyvind Harboe * : warning: fix silly -O3 warning Some versions of GCC don't pick up that local variables are set in all code paths. Signed-off-by: Øyvind Harboe 2010-08-31 Wookey * : Numonyx M29W160ET patch Someone called David Carne popped up on IRC and offered a fix (as he's not on this list so can;t post here). I am just passing it on. (thanx David) 10:54 < davidc__> Basically; the Numonyx M29W160ET has an incorrect CFI PRI block; it describes the erase blocks backwards 10:54 < davidc__> the linked patch has a fixup for that part [really trivial]: 2010-08-24 Spencer Oliver * : flash: increase stellaris flash loader buffer This speeds up programming for targets with more working area, Signed-off-by: Spencer Oliver 2010-08-27 David Brownell * : bitq: unshadow pause() bitq.c: In function ‘bitq_scan_field’: bitq.c:224: error: declaration of ‘pause’ shadows a global declaration /usr/include/unistd.h:429: error: shadowed declaration is here Signed-off-by: David Brownell 2010-08-17 Øyvind Harboe * : mcb1700: Keil MCB1700 w/1768 config script Ca. 93kBytes/s flashing speed @ 10MHz JTAG clock Signed-off-by: Øyvind Harboe 2010-08-16 David Brownell * : two NEWS updates Mention AVR32 AP7000 support. Clarify ARM semihosting update was for V7M (not ARM9 etc). Signed-off-by: David Brownell 2010-08-15 Oleksandr Tymoshenko * : avr32: basic target script 2010-08-15 Oleksandr Tymoshenko * : avr32: work-in-progress committed so as to ease cooperation and to let it be improved over time. So far it supports: - halt/resume - registers inspection - memory inspection/modification I'm still getting up to speed with OpenOCD internals and AVR32 so code is a little bit messy and I'd appreciate any feedback. 2010-08-13 Catalin Patulea * : Fix typo in documentation of usb_blaster_vid_pid command 2010-08-03 Piotr Esden-Tempski * : Added support for the Lisa/L jtag LEDs. 2010-08-03 Piotr Esden-Tempski * : Added support for Lisa/L builtin JTAG interface. 2010-08-10 Thomas Koeller * : jtag: fix handling of 'tap enable' error if a tap could not be _enabled_, the error message was 'failed to disable tap'. Fixed that. Also, display the failing tap's name. Signed-off-by: Thomas Koeller 2010-08-10 Thomas Koeller * : DM36x: Disable unused SYSCLKs Clear the enable bits for all clocks that are not set explicitly. This is done to increase robustness by removing pre-existing state. Signed-off-by: Thomas Koeller 2010-08-12 Fredrik Hederstierna * : str9x: faster flash erase of entire chip The patch improves flash erase for STR9x in case of a full bank erase. Then the chip erase command is used instead which improves speed significantly. Also I think it might help if e.g. STR912 enters some state where flash banks are locked, and a chip erase command is the key for unlocking the flash. 2010-08-11 Øyvind Harboe * : board: added at91cap7a stk w/sdram config scripts The strange thing here with this board is that 16MHz kinda works, but only 2MHz is really stable. Signed-off-by: Øyvind Harboe 2010-08-11 Øyvind Harboe * : arm: add missing error reporting when an unknown core mode is read from the target, report error. Can be communication failure. Signed-off-by: Øyvind Harboe 2010-08-09 Ben Gardiner * : cfg: add omapl138 support and da850evm preliminary support This patch adds support for the omapl138 target and preliminary support for the da850evm. The target cfg file is based on the icepick routing done by the target/ti_dm6446.cfg file. I have performed limited testing with this setup. I am posting this patch in the interest of sharing cfg files and in the hopes that the experts on this list can correct errors I have made or point out enhancements. The testing I have performed is debugging uboot with gdb where I also use the following local.cfg and gdbinit files. Debugging appears to work in so much as 'ni' works. local.cfg: gdb_memory_map disable gdbinit: target remote localhost:3333 set remote hardware-breakpoint-limit 2 set remote hardware-watchpoint-limit 2 monitor poll on Comments welcome. Best Regards, Ben Gardiner 2010-08-08 Øyvind Harboe * : target: if polling fails, back off back-off algorithm for polling. Double polling interval up to 5000ms when it fails. when polling succeeds, reset backoff. This avoids flooding logs(as much) when working with conditions where the target polling will fail. Signed-off-by: Øyvind Harboe 2010-08-02 Mike Dunn * : xscale documentation: vector table handling Hi everyone. I noticed some incorrect information in the user manual regarding how the vector table is handled on the xscale, so for your consideration, here's a short patch that corrects it, and adds a little more detail I thought might be helpful. The documentation states that OpenOCD does not attempt to synchronize the vector tables in memory with those stored in the "mini instruction cache". In fact, on each resume it does copy from memory to the cache all entries in the high and low tables that were not previously defined using the 'xscale vector_table' command. (In src/target/xscale.c, see xscale_update_vectors(), which is invoked by xscale_resume().) I take advantage of this during Linux boot-up. The extra detail describes in general terms how I do this. Corrections, comments are of course gratefully received. Thanks, Mike Signed-off-by: Mike Dunn 2010-08-02 Øyvind Harboe * : zy1000: use correct base clock when calculating speed divisor revc uses 60MHz and revb 64MHz, use this in calculations. Signed-off-by: Øyvind Harboe 2010-08-02 Øyvind Harboe * : lpc1768: even if rclk "works", it isn't necessarily the correct clk rclk = 4MHz oon lpc1768, the correct JTAG clk is 666MHz(4MHz/6). Signed-off-by: Øyvind Harboe 2010-08-02 Øyvind Harboe * : jtag: measure_clk debug proc It can be useful to get an approximate measurement of rtck frequency for debugging purposes. Signed-off-by: Øyvind Harboe 2010-08-01 Øyvind Harboe * : util: ms command to calculate length of operations This can be used to calculate approximate RTCK frequency for instance. Signed-off-by: Øyvind Harboe 2010-08-01 Peter Stuge * : Remove srst_pulls_trst from LPC2148 target srst_pulls_trst is only true on some (broken) LPC2148 boards, a fact which is already documented in doc/openocd.texi, so it shouldn't be set unconditionally in the target tcl. This patch was needed to reflash when an Abort exception occured very early after reset, before OpenOCD tried to halt the CPU. 2010-07-30 Øyvind Harboe * : lpc7168: make flash available upon reset init set user mode to avoid ROM being mapped at address 0 rather than flash. Signed-off-by: Øyvind Harboe 2010-07-10 Michal Demin * : Buspirate: fix shadow 2010-07-19 Spencer Oliver * : flash: remove algorithm exit_point address for supported targets For the above targets the exit_point is optional when used with run_algorithm, so remove it. This makes updating the algorithm less error prone. Signed-off-by: Spencer Oliver 2010-07-19 Spencer Oliver * : armv7m: exit_point optional for armv7m_run_algorithm As the armv7m uses instruction breakpoints for algorithms we do not really need to check the pc on exit. This now matches the behaviour of the arm4_5 codebase. Signed-off-by: Spencer Oliver 2010-07-20 Øyvind Harboe * : arm11 error propagation fixes Signed-off-by: Øyvind Harboe 2010-07-19 Øyvind Harboe * : arm_dpm: error propagation fixes found by inspection Signed-off-by: Øyvind Harboe 2010-07-19 Øyvind Harboe * : arm: error propagation of arm_jtag_set_instr Signed-off-by: Øyvind Harboe 2010-07-19 Øyvind Harboe * : arm_adi_v5: mem_ap_write error propagation Signed-off-by: Øyvind Harboe 2010-07-19 Øyvind Harboe * : mem_ap_read_u32 error propagation Signed-off-by: Øyvind Harboe 2010-07-19 Øyvind Harboe * : debug: debug entry error propagation Signed-off-by: Øyvind Harboe 2010-07-19 Øyvind Harboe * : arm: add error propagation for enable/disable mmu caches Signed-off-by: Øyvind Harboe 2010-07-19 David Brownell * : more careful luminary init Set up more of the Luminary-specific signals, and stop cloning a few of the JTAG defaults. More comments too. Still leaves the "dap info 0" bugs unresolved (presumably coupled to this particular adapter family) where TPIU, ITM, DWT, and other debug modules wrongly display as extra NVICs. Signed-off-by: David Brownell 2010-07-19 Spencer Oliver * : flash: add nuc910 nand driver This adds a nand driver support for the nuc910 target. Note that ECC is not currently supported by this driver, although it is supported by the peripheral. Signed-off-by: Spencer Oliver 2010-07-16 Spencer Oliver * : cfg: update rsc-w910 script - Only enable the FMI (NAND) and DMA clocks. - Select NAND interface on the MFSEL. Signed-off-by: Spencer Oliver 2010-07-18 Øyvind Harboe * : cortex a8: lots of error propagation fixes found by code inspection Signed-off-by: Øyvind Harboe 2010-07-18 Øyvind Harboe * : cortex a8: add missing error handling for cortex_a8_dap_write/read_coreregister_u32() Signed-off-by: Øyvind Harboe 2010-07-18 Øyvind Harboe * : cortex a8: add missing error handling for mem_ap_atomic_write_u32() Signed-off-by: Øyvind Harboe 2010-07-18 David Brownell * : comments for Luminary ICDI layout Provide $defines for more of the signals involved in the Luminary ICDI hardware, and comment some of what's going on. Signed-off-by: David Brownell 2010-07-17 Øyvind Harboe * : debug-feature: jtagtcpip, improve jtag performance postpone callbacks until jtag execute queue time. Signed-off-by: Øyvind Harboe 2010-07-16 David Brownell * : ARM ADI-V5: cleanup CID/PID addressing Use addition for offsetting, not masking. Shorten some lines. Make "component_start" print-only (unused otherwise; don't save). Still doesn't resolve the issue where multiple components are wrongly displaying as NVICs on some Cortex-M3 parts because many PIDs appear to be zeroes ... maybe adapter related?? Signed-off-by: David Brownell 2010-07-16 Øyvind Harboe * : fix warnings Signed-off-by: Øyvind Harboe 2010-07-16 Øyvind Harboe * : debug feature: jtagtcpip, improve performance waiting for ZY1000 fifo to idle is now queued as an asynchronous command. This radically improves performance when waitIdle() is interspersed with writes as no readback is required over TCP/IP. Signed-off-by: Øyvind Harboe 2010-07-13 David Brownell * : ARM ADI-V5: PIDs and CIDs are 8 bits Mask the upper bits after 32-bit reads. Alsoo revert the ugly changes to use PRIx32; just cast to unsized integers when printing (two chars not eight). Signed-off-by: David Brownell 2010-07-12 Spencer Oliver * : jtag: fix shadow issues in adapter_init Use global jtag_only rather than local static. Signed-off-by: Spencer Oliver 2010-07-12 Spencer Oliver * : docs: fix transport typo Signed-off-by: Spencer Oliver 2010-07-09 David Brownell * : transport selection tweaks * Bugfix and simplify legacy jtag-only defaulting * Make "dummy" declare its jtag-only nature * likewise update ft2232 * warn if selection is _required_ (multi-transport adapters), fixes the "only ft2232 works" bug for at least dummy, with other drivers going the "legacy" path (submit patches). Signed-off-by: David Brownell 2010-07-07 Øyvind Harboe * : transport: fix segfault in transport select String compare against addresses in range 0 or so due to not checking if there was an active session first. Signed-off-by: Øyvind Harboe 2010-07-05 sb-sf * : gdbserver: incorrect memory map for multiple targets (bug #24) The gdb server incorrectly reports the memory map if we have multiple targets with multiple flash banks. Signed-off-by: Spencer Oliver 2010-07-02 David Brownell * : Fix minor openocd.texi bug ::X Signed-off-by: David Brownell 2010-07-02 Spencer Oliver * : ft2232: revert ft2232_read_scan changes Revert change made in commit dd88b461da1cb8642200dd5c96fb1ff384ca9f7b. Caused segfaults when using ftdi driver under win32. Signed-off-by: Spencer Oliver 2010-06-17 Marc Pignat * : ft2232: simplify ft2232_read_scan 2010-06-25 Olaf Lüke * : at91sam3s* support Signed-off-by: Øyvind Harboe 2010-06-23 Øyvind Harboe * : arm11: fix gaffe in no-ack transfers The code did not transfer the last word in no-ack transfers. The strange thing is that this did not lead to any observable errors. This gaffe was introduced in commit 1f5883ea56cb058221f Signed-off-by: Øyvind Harboe 2010-06-22 Øyvind Harboe * : am3517 evm: use physical write to memory while target is running Signed-off-by: Øyvind Harboe 2010-06-22 Øyvind Harboe * : target: $_TARGET mdw now has a phys option just like the mdw command Signed-off-by: Øyvind Harboe 2010-06-21 Edgar Grimberg * : xsvf: Fix shadow issues on Mac wait is declared in /usr/include/sys/wait.h Signed-off-by: Edgar Grimberg 2010-06-21 Edgar Grimberg * : flash: fix shadow issues on Mac Wait is declared in /usr/include/sys/wait.h Signed-off-by: Edgar Grimberg 2010-06-21 Øyvind Harboe * : gitignore: start list of emacs temp files to ignore Signed-off-by: Øyvind Harboe 2010-06-21 Øyvind Harboe * : cortex a8: add error propagation for poll/resume Signed-off-by: Øyvind Harboe 2010-06-21 Øyvind Harboe * : cortex a8: add error propagation for mem_ap_read/write_atomic_u32 Error propagation avoids e.g. infinite loops waiting for target to halt, etc. Signed-off-by: Øyvind Harboe 2010-06-20 Antonio Borneo * : nand/mx2: review scope of symbols Add "static" qualifier to private variable. Signed-off-by: Antonio Borneo 2010-06-20 Antonio Borneo * : openocd.c: review scope of symbols Add "static" qualifier to private data. Signed-off-by: Antonio Borneo 2010-06-20 Antonio Borneo * : target/avrt: review unused symbols Remove unused functions: - mcu_write_dr_u16 - mcu_write_dr_u8 - mcu_write_ir_u16 - mcu_write_ir_u32 Signed-off-by: Antonio Borneo 2010-06-20 Antonio Borneo * : target/feroceon: review scope of symbols Add "static" qualifier to private functions. Signed-off-by: Antonio Borneo 2010-06-19 Antonio Borneo * : helper/jim-eventloop.h: review unused definitions Remove unused typedef and define Signed-off-by: Antonio Borneo 2010-06-19 Antonio Borneo * : helper/jim-eventloop: review scope of symbols Add "static" qualifier to private functions. Remove private prototypes from include file. Remove empty definition of JIM_STATIC. Signed-off-by: Antonio Borneo 2010-06-21 Øyvind Harboe * : jtag: do not use jtag_get_error() normal code should not call jtag_get_error(), but rather check the return code from jtag_execute_queue(). Signed-off-by: Øyvind Harboe 2010-06-21 Øyvind Harboe * : cortex a8: add missing error handling cortex examine was missing error handling. Signed-off-by: Øyvind Harboe 2010-06-18 Øyvind Harboe * : cortex a8: fix segfault for unexamined targets print error message instead of segfaulting for unexamined targets. Signed-off-by: Øyvind Harboe 2010-06-18 Antonio Borneo * : target/dsp563xx: review scope of symbols Add "static" qualifier to private functions. Remove private prototypes from include file. Signed-off-by: Antonio Borneo 2010-06-18 Andreas Fritiofson * : don't add confusing source info to Jim When an interactive command fails, the Jim stack trace prints references to the line in "command.c" where the interpreter was invoked. Since that location has no relation to the actual command that failed, the information serves only to add confusion. By not adding the useless source info to Jim the noise can be reduced, while still printing a useful trace for nested commands. Signed-off-by: Andreas Fritiofson Signed-off-by: Øyvind Harboe 2010-06-18 Antonio Borneo * : helper/jim: review scope of symbols Add "static" qualifier to private functions. Function Jim_InterpolateTokens() is private, but has not been changed to "static". This function is called only once, so compiler inlines it. After inline, there is a warning for variable uninitialized. Signed-off-by: Antonio Borneo Signed-off-by: Øyvind Harboe 2010-06-17 Freddie Chopin * : mingw32: -Wshadow fixes in rlink.c (error: declaration of ‘byte’ shadows a global declaration; /usr/local/lib/gcc/i686-w64-mingw32/4.4.2/../../../../i686-w64-mingw32/include/rpcndr.h:50: error: shadowed declaration is here)Signed-off-by: Freddie Chopin 2010-06-17 Freddie Chopin * : mingw32: -Wshadow fixes in jim.c (error: declaration of ‘boolean’ shadows a global declaration; /usr/local/lib/gcc/i686-w64-mingw32/4.4.2/../../../../i686-w64-mingw32/include/rpcndr.h:52: error: shadowed declaration is here)Signed-off-by: Freddie Chopin 2010-06-17 Antonio Borneo * : vsllink: fix -Wshadow warning Signed-off-by: Antonio Borneo 2010-06-17 Øyvind Harboe * : zy1000: fix arm11 optimisation copy & paste error + added FIFO throttling to work around lockup bug in FPGA. The arm11 optimisation was introduced post v0.4.0, so this is not a regression compared to previous release. Signed-off-by: Øyvind Harboe 2010-06-14 Antonio Borneo * : nor/at91sam3: replace helper membuf Helper ./src/helper/membuf.c is only used in at91sam3.c 1) Replace membuf with LOG_* 2) The original code in sam3_GetDetails() invalidates all the buffered output of sam3_GetInfo(). The new code skips sam3_GetInfo() if its output should not be printed. Signed-off-by: Antonio Borneo 2010-06-16 Øyvind Harboe * : gdb: -Wshadow warning fixes Signed-off-by: Øyvind Harboe 2010-06-16 Øyvind Harboe * : xsvf: -Wshadow warning fixes I think this fixed an error message where the error message would show the *previous* uc code rather than the current unsupported uc code. Signed-off-by: Øyvind Harboe 2010-06-16 Øyvind Harboe * : mflash: -Wshadow warning fix Signed-off-by: Øyvind Harboe 2010-06-16 Øyvind Harboe * : nand: when verify failed, it didn't return an error when the verify failed, it didn't return an error, which breaks e.g. tcl scripts that rely on this for exceptions to work. Found by -Wshadow Signed-off-by: Øyvind Harboe 2010-06-16 Øyvind Harboe * : str9xpec: -Wshadow warning fixes Signed-off-by: Øyvind Harboe 2010-06-16 Øyvind Harboe * : oops... backup file snuck in, remove it. Signed-off-by: Øyvind Harboe 2010-06-16 Øyvind Harboe * : stm32x: -Wshadow warning fixes Signed-off-by: Øyvind Harboe 2010-06-15 Øyvind Harboe * : lpc2900: -Wshadow warning fixes Signed-off-by: Øyvind Harboe 2010-06-15 Øyvind Harboe * : ecos flash: -Wshadow warning fixes Signed-off-by: Øyvind Harboe 2010-06-15 Øyvind Harboe * : flash: -Wshadow warning fix Signed-off-by: Øyvind Harboe 2010-06-15 Øyvind Harboe * : mips32_pracc: -Wshadow warning fixes Signed-off-by: Øyvind Harboe 2010-06-15 Øyvind Harboe * : mips32: -Wshadow warning fixes Signed-off-by: Øyvind Harboe 2010-06-15 Øyvind Harboe * : arm11_dbgtap: -Wshadow warning fixes Signed-off-by: Øyvind Harboe 2010-06-15 Øyvind Harboe * : arm920t: -Wshadow warning fixes Signed-off-by: Øyvind Harboe 2010-06-15 Øyvind Harboe * : adi_v5_jtag: -Wshadow warning fixes Signed-off-by: Øyvind Harboe 2010-06-15 Øyvind Harboe * : arm_simulator: -Wshadow warning fixes Signed-off-by: Øyvind Harboe 2010-06-15 Øyvind Harboe * : target: -Wshdaow warning fix Signed-off-by: Øyvind Harboe 2010-06-15 Øyvind Harboe * : zy1000: -Wshadow warning fix Signed-off-by: Øyvind Harboe 2010-06-15 Øyvind Harboe * : jim: -Wshadow warning fix Signed-off-by: Øyvind Harboe 2010-06-14 Øyvind Harboe * : jim: -Wshadow fixes this batch of fixes should be pretty straightforward rename of 'index' and an 'i' local variable shadowing. 'index' conflicts with a global name. Signed-off-by: Øyvind Harboe 2010-06-14 michal smulski * : arm1136 scripts Here is a patch to fix a startup in C100 (arm1136). Basically make sure that UART is configured before using it. Michal Signed-off-by: Øyvind Harboe 2010-06-14 Øyvind Harboe * : cfi: add LOG_ERROR() in case of unsupported intel erase algorithm found by code inspection. There are many other places in CFI where LOG_ERROR() should be called similarly... Signed-off-by: Øyvind Harboe 2010-06-14 Øyvind Harboe * : helper: fix -Wshadow warning in number parsing use obtuse local variable names in macros to avoid interfering with global name space Signed-off-by: Øyvind Harboe 2010-06-14 Øyvind Harboe * : target: fix retval gaffe in mwX commands failure to write to memory was not propagated. This is an interesting case of broken error handling: with exceptions we wouldn't have had this at all, and I also wonder if there is a GCC option to warn about these kinds of potential bugs. Signed-off-by: Øyvind Harboe 2010-06-12 Antonio Borneo * : TARGET: removed unsed parameter Parameter "type" of function armv4_5_mmu_translate_va() is now not used. Remove the parameter and the "enum" listing its values. Signed-off-by: Antonio Borneo 2010-06-12 Antonio Borneo * : TARGET/ARM920T: fix return value Function arm920t_write_memory() default return value should be ERROR_OK. All cases of local errors are handled immediately and not further propagated. Signed-off-by: Antonio Borneo 2010-06-11 Øyvind Harboe * : flash: add error handling to get_flash_by_addr/name autoprobing can fail and this error has to be reported up the call stack. Signed-off-by: Øyvind Harboe 2010-06-10 Øyvind Harboe * : cfi: fix error propagation any read/write operation to memory can fail. block write algorithm error propagation was broken in that it would continue after an error was reported writing data to ram or the algorithm failing. Signed-off-by: Øyvind Harboe 2010-06-09 Øyvind Harboe * : flash: add error message if image is too big for flash replaced assert() w/error message if the image is too big. Signed-off-by: Øyvind Harboe 2010-06-07 Øyvind Harboe * : zy1000: fix optimisation gaffe DCC optimisation was broken on targets w/multiple TAP's. Signed-off-by: Øyvind Harboe 2010-05-05 Øyvind Harboe * : cfi: fix GDB keep alive bug Long running CFI writes could cause GDB timeout. Signed-off-by: Øyvind Harboe 2010-06-07 Øyvind Harboe * : gdb-server: fix error reporting bugs GDB and OpenOCD has two different error number spaces and no mapping exists between them. If a specific error number is to be reported to GDB then this has to be done at the calling site, rather than as a generic routine that tries to map "retval" to GDB error number speak. Signed-off-by: Øyvind Harboe 2010-06-01 gcembed * : stm32 : change returned value of mass_erase function Hello, "stm32x mass_erase" return ERROR_OK even if something goes wrong. Here is a summary of changes : * in stm32x_mass_erase : return ERROR_FLASH_OPERATION_FAILED when error detected in FLASH_SR register; * in COMMAND_HANDLER(stm32x_handle_mass_erase_command) : return the returned value of stm32x_mass_erase(). I don't know if there is reason to always return ERROR_OK ? Gaëtan 2010-05-31 Jon Povey * : etm: print something when trace buffer empty ETM analyze produced no output when the trace buffer was empty. This patch provides users with a clue. Signed-off-by: Jon Povey Signed-off-by: Øyvind Harboe 2010-05-24 Spencer Oliver * : flash: virtual driver update for get_flash_bank_by_name_noprobe Make sure we do not probe a flash when getting info. Signed-off-by: Spencer Oliver 2010-05-24 Spencer Oliver * : cfg: add pic32 virtual banks make use of the new virtual bank flash driver. Signed-off-by: Spencer Oliver 2010-05-26 Antonio Borneo * : NOR/CFI: fix memory leak; check malloc return value Every time command "flash probe #" is executed, memory structures are re-allocated without preventive free() of former areas, causing memory leak. Also, memory allocation does not check return value, determining segmentation fault in case of out of memory. Signed-off-by: Antonio Borneo Signed-off-by: Spencer Oliver 2010-05-21 Freddie Chopin * : All LPC2xxx chips are little endian and that cannot be changed - update config scripts Signed-off-by: Spencer Oliver 2010-05-21 Freddie Chopin * : Update "flash bank" helper comments for LPC2xxx chips Signed-off-by: Spencer Oliver 2010-05-21 Øyvind Harboe * : at91sam9260: use RCLK It might be possible to get this target going without RCLK, but it would require more careful analysis and usage of the reset events. Enable fast memory accesses. Tested on an at91sam9260 custom board w/external DRAM and flash. Signed-off-by: Øyvind Harboe 2010-05-21 Spencer Oliver * : arm_adi_v5: correct ahbap_debugport_init mem-ap id (bug #23) We request a id register read at the end of ahbap_debugport_init but we never actually run the queue. In some cases this causes a segfault. Signed-off-by: Spencer Oliver 2010-05-20 gcembed * : nand : Add Freescale iMX27 nand flash controller support This patch add support of iMX27 nand flash controller. This is based on driver for imx31 nand flash controller. OOB functionality is not fully working. As in mx31 controller, mx2 NFC has a bug that swap two bytes between SPARE and MAIN buffer. I used this driver for several months and no problems appear. 2010-05-18 Gary Carlson * : target: slow targets could cause GDB to time out This second half of the patch is proposed to clean up some GDB keep alive issues on arm7_9 targets that start up with very slow clocks. If an attempt is made to write to key registers on the processor with a slow jtag speed, GDB timeout warnings appear on the console (at least mine) when "reset halt" or "reset init" commands are issued from the gdb client: *** BEFORE PATCH *** (gdb) monitor reset init fast memory access is disabled 2 kHz keep_alive() was not invoked in the 1000ms timelimit. GDB alive packet not sent! (1026). Workaround: increase "set remotetimeout" in GDB JTAG tap: at91sam9g20.cpu tap/device found: 0x0792603f (mfg: 0x01f, part: 0x7926, ver: 0x0) target state: halted target halted in ARM state due to breakpoint, current mode: Supervisor cpsr: 0x000000d3 pc: 0x00000000 MMU: disabled, D-Cache: disabled, I-Cache: disabled keep_alive() was not invoked in the 1000ms timelimit. GDB alive packet not sent! (1027). Workaround: increase "set remotetimeout" in GDB keep_alive() was not invoked in the 1000ms timelimit. GDB alive packet not sent! (1006). Workaround: increase "set remotetimeout" in GDB keep_alive() was not invoked in the 1000ms timelimit. GDB alive packet not sent! (1006). Workaround: increase "set remotetimeout" in GDB keep_alive() was not invoked in the 1000ms timelimit. GDB alive packet not sent! (1006). Workaround: increase "set remotetimeout" in GDB keep_alive() was not invoked in the 1000ms timelimit. GDB alive packet not sent! (1004). Workaround: increase "set remotetimeout" in GDB RCLK - adaptive dcc downloads are enabled fast memory access is enabled NAND flash device 'NAND 256MiB 3,3V 8-bit' found (gdb) I added additional keep alive steps in areas that troubleshooting revealed were causing problems. I only did this however for non-fast write memory accesses. I don't think most people would be using fast memory accesses to write to memory when the jtag and system clocks are slow anyway. If you disagree with my feeling, think there is a more elegant way to handle the problem, or think the patch will cause other unforeseen problems with other targets, let me know. As you can see below, the patch does eliminate the problem on my development station and I suspect that it will benefit others. *** AFTER PATCH *** (gdb) monitor reset init fast memory access is disabled 2 kHz JTAG tap: at91sam9g20.cpu tap/device found: 0x0792603f (mfg: 0x01f, part: 0x7926, ver: 0x0) target state: halted target halted in ARM state due to breakpoint, current mode: Supervisor cpsr: 0x000000d3 pc: 0x00000000 MMU: disabled, D-Cache: disabled, I-Cache: disabled RCLK - adaptive dcc downloads are enabled fast memory access is enabled NAND flash device 'NAND 256MiB 3,3V 8-bit' found (gdb) Gary Carlson Gary Carlson, MSEE Principal Engineer Carlson-Minot Inc. 2010-05-18 Øyvind Harboe * : zy1000: fix false positive warning about unitialized local variable Signed-off-by: Øyvind Harboe 2010-05-17 Jon Povey * : NAND/davinci: Fix segfault for hwecc4_infix reads Page reads using hwecc4_infix layout segfaulted for check_bad_blocks because the read assumed a valid data buffer, which check_bad_blocks does not use (it only passes a 6 byte buffer for the start of OOB). This version copes with undersized or missing data or oob buffers and uses random read commands within the page to skip unwanted areas of data/OOB for speed. NOTE: Running check_bad_blocks with this layout will be reading infix OOB locations, not manufacturer bad block markers. This means that if you check blocks written in infix layout they will appear good, but manufacturer- marked bad blocks may also appear good. If you want to scan for manufactuer-marked bad blocks, you need to enable raw_access before running check_bad_blocks, or use the non-infix layout. Signed-off-by: Jon Povey CC: David Brownell 2010-05-17 Spencer Oliver * : gdbserver: gdb cmds returning failure on success The gdb_memory_map cmd for example fell through and returned ERROR_COMMAND_SYNTAX_ERROR on success - behaviour is now as expected. Signed-off-by: Spencer Oliver 2010-05-11 Antonio Borneo * : NOR/CFI: minor code cleanup Remove few LOG_DEBUG() messages, together with code and variables required to build such messages. Signed-off-by: Antonio Borneo 2010-05-11 Antonio Borneo * : NOR: add read() callback to struct flash_driver Final target is to force bus_width size during CFI flash read. In this first step I need to replace default flash read with flash specific implementation. This patch introduces: - flash_driver_read() layer; - default_flash_read(), backward compatible; - read() callback in struct flash_driver; - proper initialization in every flash_driver instance. Signed-off-by: Antonio Borneo 2010-05-07 Antonio Borneo * : NOR: fix comment for Doxygen Either bus_width and chip_width are in bytes. Signed-off-by: Antonio Borneo 2010-05-07 Antonio Borneo * : NOR/CFI: use bus_width for memory access in cfi_write() During cfi_write(), head and tail of destination area could be not aligned to bus_width. Since write operation must be at bus_width size, source buffer size is extended and buffer padded with current values read from flash. Force using bus_width to read current value from flash. Do not use cfi_add_byte() anymore, to allow removing this function later on. Signed-off-by: Antonio Borneo 2010-04-20 Antonio Borneo * : NOR/CFI: identify memory accesses not using "bus_width". Since NOR flash devices does not handle "byte enable lanes", each read/write access involves the whole "chip_width". When multiple devices are in parallel, usually all chips are enabled during each access. All such cases are compatible with flash accesses at "bus_width" size. Access at "bus_width" size is mandatory for write access to avoid transferring of garbage values to flash. During read access the flash controller should take care, and discard unneeded bytes. Anyway, it is good practice to use "bus_width" size also for read. Every memory access that does not respect "bus_width" size is marked with a "FIXME" comment. Signed-off-by: Antonio Borneo 2010-04-16 Antonio Borneo * : NOR/CFI: check "flash bank" command arguments Arguments chip_width and bus_width of command "flash bank" are not fully checked. While bus_width is later on redundantly checked in several other parts (e.g. in cfi_command_val()) and generates run-time error, chip_width is never checked, nor related to actual bus_width value. Added check to avoid: - (chip_width == 0), that would mean no memory chip at all, avoiding also division by zero e.g. in cfi_get_u8(); - (bus_width == 0), that would mean no bus at all; - unsupported cases of chip_width or bus_width value not power of 2; - unsupported case of chip width wider than bus. Signed-off-by: Antonio Borneo 2010-05-14 Jun Ma * : missing pointer's declaration when enable macro -D_DEBUG_GDB_IO_. reproducable when "./configure --enable-maintainer-mode CFLAGS=-D_DEBUG_GDB_IO_" Signed-off-by: Jun Ma Signed-off-by: Øyvind Harboe 2010-05-13 Jon Povey * : NAND: fix off-by-one error in erase command argument range The last_block argument to nand_erase() is checked against nand->num_blocks, but the highest valid block number is (total - 1), the test for invalid should be ">=" rather than ">". Signed-off-by: Jon Povey Signed-off-by: Øyvind Harboe 2010-05-12 Spencer Oliver * : flash: require unique flash bank name Make sure the flash bank name is unique Signed-off-by: Spencer Oliver 2010-05-12 Øyvind Harboe * : zy1000.cfg: gdb connect will fail first time without gdb-attach gdb-attach does a reset init to make sure that the CFI probe will succeed upon first gdb connect. Signed-off-by: Øyvind Harboe 2010-05-10 Karl Kurbjun * : Fujitsu MBM29SL800TE flash support Hi, This is my first post to the list. First, I would like to thank everyone for their work on OpenOCD, it is a great tool to work with. I have been using it to debug code on hardware for the Rockbox project (www.rockbox.org). The target that I primarily work with has a Spansion/Fujitsu NOR flash (MBM29SL800TE). I attached a patch that adds support for this flash. I hope it can be included in the main repository. If there is something that needs to be changed with the patch before inclusion please let me know. -Karl Kurbjun 2010-05-11 Marc Pignat * : Documentation : arm920t implements armv4 There is a small typo in the cpu list, arm920t is armv4. 2010-05-10 Spencer Oliver * : armv7m: 20 second timeout/megabyte for CRC check There was a fixed 20 second timeout which is too little for large, slow timeout checks. Signed-off-by: Spencer Oliver 2010-05-07 Spencer Oliver * : cfg: add stm32eval board configs Increase working area for stm3210e_eval.cfg. Add new configs for the following boards: STM321000B-EVAL, STM32100C-EVAL, STM32100B-EVAL Signed-off-by: Spencer Oliver 2010-05-05 Øyvind Harboe * : flash: stop caching protection state There are a million reasons why cached protection state might be stale: power cycling of target, reset, code executing on the target, etc. The "flash protect_check" command is now gone. This is *always* executed when running a "flash info". As a bonus for more a more robust approach, lots of code could be deleted. Signed-off-by: Øyvind Harboe 2010-05-05 Øyvind Harboe * : cfi: fix error handling for protect fn No error was propagated. Signed-off-by: Øyvind Harboe 2010-05-04 Øyvind Harboe * : gdb: connect will now fail if flash autoprobe fails This stops GDB from launching with an empty memory map, making gdb load w/flashing fail for no obvious reason. The error message points in the direction of the gdb-attach event that can be set up to issue a halt or "reset init" which will put GDB in a well defined stated upon attach and thus have a robust flash autoprobe. Signed-off-by: Øyvind Harboe 2010-05-03 Matthias Bode * : Fixed bug in tcl-server No segmentationfault when sending commands to tcl-server. modified: src/server/server.c modified: src/server/tcl_server.c modified: src/server/tcl_server.h 2010-05-04 Øyvind Harboe * : flash: more flash write_image bugfixes Remove/fix lots of bugs in handling of non-contigious sections and out of order sections. Fix a gaffe introduced in previous commit to src/flash/nor/core.c Signed-off-by: Øyvind Harboe 2010-05-05 Marc Pignat * : documentation typo Signed-off-by: Øyvind Harboe 2010-05-04 Spencer Oliver * : str71x: fix previous commit fix build issue with 70226c221f5879bb6126ff3f2ec9ae64c68d80d6 commit Signed-off-by: Spencer Oliver 2010-05-03 Øyvind Harboe * : str7x: fix bogus error messages Remove bogus error messages when trying to allocate a large chunk of target memory and then falling back to a smaller one. Signed-off-by: Øyvind Harboe 2010-05-04 Øyvind Harboe * : zy1000: wait for srst to deassert make wait for srst deassert more long latency friendly (JTAG over TCP/IP), print actual time if it was more than 1ms. Signed-off-by: Øyvind Harboe 2010-04-30 Tobias Ringström * : STM32 flash erase timeout fix The current timeout for STM32 flash block erase and flash mass erase is 10 (ms), which is too tight, and fails around 50% of the time for me. The data sheet for STM32F107VC specifies a maximum erase time of 40 ms (for both operations). I'd also consider it a bug that the code does not detect a timeout, but just assumes that the operation has completed. The attached patch does not address this bug. The attached patch increases the timeouts from 10 to 100 ms. Please apply. /Tobias 2010-04-29 Øyvind Harboe * : flash: write_image would fail for certain images Fix a bug where write_image would fail if the sections in the image were not in ascending order. This has previously been fixed in gdb load. Solved by sorting the image sections before running flash write_image erase unlock foo.elf. Signed-off-by: Øyvind Harboe 2010-04-28 Øyvind Harboe * : nor: remove bogus output about padding sections padding of 0 bytes is actually no padding, do not output warning about padding in that case. Signed-off-by: Øyvind Harboe 2010-04-26 Marek Vasut * : Add VPACLink interface definition This patch adds definition file for the Voipac VPACLink JTAG adaptor. The adaptor is combined JTAG/UART device. Signed-off-by: Marek Vasut 2010-04-24 michal smulski * : telo: update configuration scripts to matched master branch Signed-off-by: Øyvind Harboe 2010-04-20 michal smulski * : docs: improve load_image docs add docs for missing args. Signed-off-by: Øyvind Harboe 2010-04-17 Andreas Fritiofson * : stm32x: allow flash probe on a running target If the flash has not yet been probed and GDB connects while the target is running, the flash probe triggered by GDB's memory map read will fail. In that case the returned memory map will be empty, causing a subsequent load from within GDB to fail. There's not much you can do from GDB to recover, other than a restart; a 'mon reset init' and manual 'mon flash probe' won't help since GDB has already made up its mind about the memory map. It seems there's no reason to require the target to be halted when probing the flash. Remove the check to let a valid memory map be provided to GDB even when connecting to a running target. Signed-off-by: Andreas Fritiofson 2010-04-14 Antonio Borneo * : NOR/CFI: remove redundant code Arguments for "flash bank" command are already parsed and put in "bank" struct. Removed code to parse them again. Signed-off-by: Antonio Borneo 2010-04-13 Mike Dunn * : xscale: fix analyze_trace for trace data collected in wrap mode This patch fixes the xscale_analyze_trace() function. This function was defective for a trace collected in 'fill' mode (hiccups with repeated instructions) and completely broken when buffer overflowed in 'wrap' mode. The reason for the latter case is that the checkpoint registers were interpreted incorrectly when two checkpoints are present in the trace (which will be true in 'wrap' mode once the buffer fills). In this case, checkpoint1 register will contain the older entry, and checkpoint0 the newer. The original code assumed the opposite. I eventually gave up trying to understand all the logic of the function, and rewrote it. I think it's much cleaner and understandable now. I have been using and testing this for a few weeks now. I'm confident it hasn't regressed in any way. Also added capability to handle (as best as possible) the case where an instruction can not be read from the loaded trace image; e.g., partial image. This was a 'TODO' comment in the original xscale_analyze_trace(). Outside of xcsale_analyze_trace(), these (related) changes were made: - Remove pc_ok and current_pc elements from struct xscale_trace. These elements and associated logic are useless clutter because the very first entry placed in the trace buffer is always an indirect jump to the address at which execution resumed. This type of trace entry includes the literal address in the trace buffer, so the initial address of the trace is immediately determined from the trace buffer contents and does not need to be recorded when trace is enabled. - Added num_checkpoints to struct xscale_trace_data, which is necessary in order to correctly interpret the checkpoint register contents. - In xscale_read_trace() - Fix potential array out-of-bounds condition. - Eliminate partial address entries when parsing trace (can occur in wrap mode). - Count and record number of checkpoints in trace. - Added small, inlined utility function xscale_display_instruction() to help make the code more concise and clear. TODO: - Save processor state (arm or thumb) in struct xscale_trace when trace is enabled so that trace can be analyzed correctly (currently assumes arm mode). - Add element to struct xscale_trace that records (when trace is enabled) whether vector table is relocated high (to 0xffff0000) or not, so that a branch to an exception vector is traced correctly (curently assumes vectors at 0x0). 2010-04-14 Anton Fedotov * : cortex-a8: more MMU support + virt2phys() can now convert virtual address to real + read_memory() and write_memory() are renamed to read_phys_memory() and write_phys_memory() + new read_memory() and write_memory() try to resolve real address if mmu is enambled than perform real address reading/writing + if address is bellow 0xc000000 than TTB0 is used for page table dereference, if above - than TTB1. Linux style of user/kernel address separation + if above fails (i.e address is unspecified) than mode is checked whether it is Supervisor (than TTB1) or User (than TTB0) - Software breakpoints doesn't work. You should invoke "gdb_breakpoint_override hard" before you start debugging + cortex_a8_mmu(), cortex_a8_enable_mmu_caches(), cortex_a8_disable_mmu_caches() are implemented Signed-off-by: Øyvind Harboe 2010-04-11 Antonio Borneo * : NOR/TMS470: review scope of symbols Add "static" qualifier to private functions and data. Signed-off-by: Antonio Borneo 2010-04-11 Antonio Borneo * : TARGET/MIPS32_PRACC: review scope of functions Add "static" qualifier to private functions. Signed-off-by: Antonio Borneo 2010-04-10 Antonio Borneo * : HELPER/LOG: review unused symbols Remove unused functions: - log_catch - log_rethrow - log_try Signed-off-by: Antonio Borneo 2010-04-10 Antonio Borneo * : NOR/CFI: review scope of functions Add "static" qualifier to private functions. Signed-off-by: Antonio Borneo 2010-04-10 Antonio Borneo * : OPENOCD: review scope of functions Add "static" qualifier to private functions. Signed-off-by: Antonio Borneo 2010-04-10 Antonio Borneo * : BINARYBUFFER: review scope of data and functions Add "static" qualifier to private data and functions. Signed-off-by: Antonio Borneo 2010-04-10 Antonio Borneo * : NAND/TCL: review scope of functions Add "static" qualifier to private functions. Signed-off-by: Antonio Borneo 2010-04-10 Antonio Borneo * : NAND/ARM_IO: review scope of functions Add "static" qualifier to private functions. Signed-off-by: Antonio Borneo 2010-04-10 Antonio Borneo * : NAND/MX3: review scope of data Add "static" qualifier to private data. Signed-off-by: Antonio Borneo 2010-04-10 Antonio Borneo * : NOR/AVRF: review scope of data Add "static" qualifier to private data. Signed-off-by: Antonio Borneo 2010-04-10 Antonio Borneo * : NOR/DRIVERS: review scope of functions Add "static" qualifier to private functions. Remove unused "extern" in src/ecosboard.c Signed-off-by: Antonio Borneo 2010-04-10 Antonio Borneo * : TCL: review scope of functions Add "static" qualifier to private functions. Signed-off-by: Antonio Borneo 2010-04-10 Antonio Borneo * : HELLO: review unused symbols Remove unused functions: - hello_register_commands Signed-off-by: Antonio Borneo 2010-04-10 Antonio Borneo * : ADI_V5_JTAG: review scope of data Add "static" qualifier to private data. Signed-off-by: Antonio Borneo 2010-04-10 Antonio Borneo * : ARM_JTAG: review scope of functions Add "static" qualifier to private functions. Signed-off-by: Antonio Borneo 2010-04-10 Antonio Borneo * : ARMV4_5_MMU: review unused symbols Remove unused data: - armv4_5_mmu_page_type_names Remove prototype of not existing function: - armv4mmu_translate_va Signed-off-by: Antonio Borneo 2010-04-10 Antonio Borneo * : EMBEDDEDICE: review scope of functions Add "static" qualifier to private functions. Signed-off-by: Antonio Borneo 2010-04-10 Antonio Borneo * : TARGET: review scope of functions Add "static" qualifier to private functions. Remove unused "extern" in src/ecosboard.c Signed-off-by: Antonio Borneo 2010-04-04 David Brownell * : Restore deleted '!' character I'm not sure what caused this significant character to get deleted. it may be related to intermittent Editor or terminal flakes I've been seeing lately (sigh). This fix is trivial. Signed-off-by: David Brownell 2010-04-04 David Brownell * : simplify and unconfuse target_run_algorithm() For some reason there are *two* schemes for interposing logic into the run_algorithm() code path... One is a standard procedural wapper around the target method invocation. the other (superfluous) one hacked the method table by splicing a second procedural wrapper into the method table. Remove it: * Rename its slightly-more-featureful wrapper so it becomes the standard procedural wrapper, leaving its added logic (where it should have been in the first place. Also add a paranoia check, to report targets that don't support algorithms without traversing a NULL pointer, and tweak its code structure a bit so it's easier to modify. * Get rid of the superfluous/conusing method table hacks. This is a net simplification, making it simpler to analyse what's going on, and then interpose logic . ... by ensuring there's only one natural place for it to live. ------------ Signed-off-by: David Brownell 2010-03-28 Mike Dunn * : xscale: fix trace buffer functionality when resuming from a breakpoint Problem: halt at a breakpoint, enable trace buffer ('xscale trace_buffer enable fill'), then resume. Wait for debug exception when trace buffer fills (if not sooner due to another breakpoint, vector catch, etc). Instead, never halts. When halted explicitly from OpenOCD and trace buffer dumped, it contains only one entry; a branch to the address of the original breakpoint. If the above steps are repeated, except that the breakpoint is removed before resuming, the trace buffer fills and the debug exception is generated, as expected. Cause: related to how a breakpoint is stepped over on resume. The breakpoint is temporarily removed, and a hardware breakpoint is set on the next instruction that will execute. xscale_debug_entry() is called when that breakpoint hits. This function checks if the trace buffer is enabled, and if so reads the trace buffer from the target and then disables the trace (unless multiple trace buffers are specified by the user when trace is enabled). Thus you only trace one instruction before it is disabled. Solution: kind of a hack on top of a hack, but it's simple. Anything better would involve some refactoring. This has been tested and trace now works as intended, except that the very first instruction is not part of the trace when resuming from a breakpoint. TODO: still many issues with trace: doesn't work during single-stepping (trace buffer is flushed each step), 'xscale analyze_trace' works only marginally for a trace captured in 'fill' mode, and not at all for a trace captured in 'wrap' mode. Signed-off-by: Øyvind Harboe 2010-03-26 Antonio Borneo * : NOR TCL: fix usage message The command "flash bank" has updated syntax. Add the mandatory parameter to the usage message that prints in case of error. Signed-off-by: Antonio Borneo 2010-03-04 Øyvind Harboe * : zy1000: dev tool first cut peek/poke over tcp/ip, used for debug/research purposes only. Long term JTAG over TCP/IP might be an offshoot. The performance is usable for development/testing purposes. Signed-off-by: Øyvind Harboe 2010-03-25 Daniel Bäder * : change %x and %d to PRIx32 and PRId32 where needed for cygwin 2010-03-24 Antonio Borneo * : telnet_server: review unused symbols Remove unused function Signed-off-by: Antonio Borneo 2010-03-24 David Brownell * : FT2232 Messaaging fix The init cleanup patch overlooked a message which was wrongly specific to the "usbjtag" layout. Fix. Signed-off-by: David Brownell 2010-03-24 Antonio Borneo * : server: review scope of functions and data Add "static" qualifier to private functions and data. Signed-off-by: Antonio Borneo 2010-03-20 Mike Dunn * : fix software breakpoints on xscale This patch fixes xscale software breakpoints by cleaning the dcache and invalidating the icache after the bkpt instruction is inserted or removed. The icache operation is necessary in order to flush the fetch buffers, even if the icache is disabled (see section 4.2.7 of the xscale core developer's manual). The dcache is presumed to be enabled; no harm done if not. The dcache is also invalidated after cleaning in order to safeguard against a future load of invalid data, in the event that cache_clean_address points to memory that is valid and in use. Also corrected a confusing typo I noticed in a comment. TODO (or not TODO...?): the xscale's 2K "mini dcache" is not cleaned. This cache is not used unless the 'X' bit in the page table entry is set. This is a proprietary xscale extension to the ARM architecture. If a target's OS or executive makes use of this for memory regions holding code, the breakpoint problem will persist. Flushing the mini dcache requires that 2K of valid cacheable memory (mapped with 'X' bit set) be designated by the user for this purpose. The debug handler that gets downloaded to the target will also need to be extended. 2010-03-21 David Brownell * : ft2232 init mess cleanup In the ft2232 driver, initialization for many layouts punts to a routine called usbjtag_init(), instead of a routine specific to each layout. That routine is a mess built around a "what type layout am I" core. That's a bad design ... in this case, especially so, since it bypasses the layout-specific dispatch which was just done, and obfuscates the initialization which is at least somewhat generic, instead of being specific to the "usbjtag" layout. Split and document out the generic parts of usbjtag_init(), and make the rest of those layouts have layout-specific init methods. Also, rename usbjtag_reset() ... that also was not specific to the "usbjtag" layout, and thus contributed to the previous code structure confusion. (Eventually, all layout-specific code (and method tables) should probably live in files specific to each layout. These changes will facilitate those and other cleanups to this driver.) Signed-off-by: David Brownell 2010-03-19 Øyvind Harboe * : jtag: make out_value const Tightens up the jtag_add_xxx_scan() API Signed-off-by: Øyvind Harboe 2010-03-19 David Brownell * : FT2232 comment tweaks Note that the FT4232 chips have four channels not two, and Elaborate on uses of the additional channels. Signed-off-by: David Brownell 2010-03-19 Øyvind Harboe * : zy1000: fix bug in end state of DCC writes Introduced in latest commits, found by code inspection & GCC warning. Signed-off-by: Øyvind Harboe 2010-03-18 Øyvind Harboe * : jtag: remove jtag_get_end_state() usage Code inspection indicated what constant end states to use. Signed-off-by: Øyvind Harboe 2010-03-18 Øyvind Harboe * : jtag: remove unecessary usage of jtag_get_end_state(). By code inspection. Signed-off-by: Øyvind Harboe 2010-03-18 Mike Dunn * : Fix underlying problem with xscale icache and dcache commands Fix problem with the xscale icache and dcache commands. Both commands were enabling or disabling the mmu, not the caches I didn't look any further after my earlier patch fixed the trivial problem with command argument parsing. Turns out the underlying code was broken. The resolution is straightforward when you look at the arguments to xscale_enable_mmu_caches() and xscale_disable_mmu_caches(). I finally took a deeper look after dumping the cp15 control register (XSCALE_CTRL) and seeing that the cache bits weren't changing, but the mmu bit was (which caused all manner of grief, as you can imagine). This has been tested and works OK now. src/target/xscale.c | 17 +++++++++++------ 1 files changed, 11 insertions(+), 6 deletions(-) Signed-off-by: David Brownell 2010-03-18 David Brownell * : commit 52a788e008ecf0ca6156f02de08a0f062d49a236 Author: David Brownell Date: Thu Mar 18 11:56:17 2010 -0700 2010-03-18 Øyvind Harboe * : jtag: retire one instance of jtag_get_end_state() usage Less global variables.... Signed-off-by: Øyvind Harboe 2010-03-18 Spencer Oliver * : DOCS: update flash bank examples - include the $_FLASHNAME in all flash bank examples. Signed-off-by: Spencer Oliver 2010-03-17 Spencer Oliver * : MIPS: remove unused arg from mips_ejtag_set_instr This arg was never used and was just taken from the arm jtag code. Signed-off-by: Spencer Oliver 2010-03-17 Øyvind Harboe * : linker error: fix problem with duplicate fn A fn was copied instead of moved to a new file. The linker can discard exact copies of fn's without warning. This is a C++'ism. However on my Ubuntu 9.10 machine, it fails. Signed-off-by: Øyvind Harboe 2010-03-17 Øyvind Harboe * : gdb: long running "monitor mww" now works w/gdb invoke keep_alive() to make sure that the default 2000ms timeout does not trigger. Signed-off-by: Øyvind Harboe 2010-03-17 Øyvind Harboe * : target: mdX/mwX on target were badly broken - incorrect parsing of arguments - mdX didn't display arguments correctly I don't think anyone ever used that code path :-) Did you know that "target mdw" and mdw are very different? for {set i 0} {$i < 256} {set i [expr $i+1]} {mwb [expr 0x2000000+$i] $i} mdw 0x2000000 0x10 0x02000000: 03020100 07060504 0b0a0908 0f0e0d0c 13121110 17161514 1b1a1918 1f1e1d1c 0x02000020: 23222120 27262524 2b2a2928 2f2e2d2c 33323130 37363534 3b3a3938 3f3e3d3c > zy1000.cpu mdb 0x2000000 0x20 0x02000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f ................ 0x02000010 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f ................ > zy1000.cpu mdh 0x2000000 0x20 0x02000000 0100 0302 0504 0706 0908 0b0a 0d0c 0f0e ................ 0x02000010 1110 1312 1514 1716 1918 1b1a 1d1c 1f1e ................ 0x02000020 2120 2322 2524 2726 2928 2b2a 2d2c 2f2e !"#$%&'()*+,-./ 0x02000030 3130 3332 3534 3736 3938 3b3a 3d3c 3f3e 0123456789:;<=>? > zy1000.cpu mdw 0x2000000 0x20 0x02000000 03020100 07060504 0b0a0908 0f0e0d0c ................ 0x02000010 13121110 17161514 1b1a1918 1f1e1d1c ................ 0x02000020 23222120 27262524 2b2a2928 2f2e2d2c !"#$%&'()*+,-./ 0x02000030 33323130 37363534 3b3a3938 3f3e3d3c 0123456789:;<=>? 0x02000040 43424140 47464544 4b4a4948 4f4e4d4c @ABCDEFGHIJKLMNO 0x02000050 53525150 57565554 5b5a5958 5f5e5d5c PQRSTUVWXYZ[\]^_ 0x02000060 63626160 67666564 6b6a6968 6f6e6d6c `abcdefghijklmno 0x02000070 73727170 77767574 7b7a7978 7f7e7d7c pqrstuvwxyz{|}~. Signed-off-by: Øyvind Harboe 2010-03-16 Spencer Oliver * : PIC32: add software reset support The PIC32MX does not support the ejtag software reset - it is optional in the ejtag spec. We perform the equivalent using the microchip specific MTAP cmd's. Signed-off-by: Spencer Oliver 2010-03-16 Øyvind Harboe * : gdb_server: improved gdb load performance by ack'ing memory writes immediately and reporting either at next memory write or stepi/continue time. GDB will then send off a new packet that is ready by the time the previous packet has been written to target memory. On faster adapters this can be as much as 10% improvement. Signed-off-by: Øyvind Harboe 2010-03-16 Øyvind Harboe * : arm7/9: remove unused post_restore_context Unused. If something should happen after context restore, then the calling code can just do it afterwards. Signed-off-by: Øyvind Harboe 2010-03-01 Øyvind Harboe * : bitbang: add jtag_add_tms_seq support Signed-off-by: Øyvind Harboe 2010-03-16 Spencer Oliver * : PIC32: add Microchip Explorer16 cfg - add Microchip Explorer16 cfg using PIC32MX360F512L PIM. - remove reset config from PIC32 target cfg. Signed-off-by: Spencer Oliver 2010-03-15 Bradey Honsinger * : image loading: fix problem with offsets > 0x80000000 Fixes bug that prevented users from specifying a base address of 0x80000000 or higher in image commands (flash write_image, etm image, xscale trace_image). image.base_address is an offset from the start address contained in the image file (if there is one), or from 0 (for binary files). As a signed 32-bit int, it couldn't be greater than 0x7fffffff, which is a problem when trying to write a binary file to flash above that address. Changing it to a 64-bit long long keeps it as a signed offset, but allows it to cover the entire 32-bit address space. Signed-off-by: Øyvind Harboe 2010-03-15 David Brownell * : rename jtag_nsrst_assert_width as adapter_nsrst_assert_width Globally rename "jtag_nsrst_assert_width" as "adapter_nsrst_assert_width", and move it out of the "jtag" command group ... it needs to be used with non-JTAG transports Includes a migration aid (in jtag/startup.tcl) so that old user scripts won't break. That aid should Sunset in about a year. Signed-off-by: David Brownell 2010-03-15 David Brownell * : rename jtag_khz as adapter_khz Globally rename "jtag_khz" as "adapter_khz", and move it out of the "jtag" command group ... it needs to be used with non-JTAG transports Includes a migration aid (in jtag/startup.tcl) so that old user scripts won't break. That aid should Sunset in about a year. (We may want to update it to include a nag message too.) Signed-off-by: David Brownell 2010-03-15 Spencer Oliver * : PIC32MX: update cfg script The default config script will now dynamically setup the BMX registers in the reset init script. This will also work if the user overrides the default working area. Signed-off-by: Spencer Oliver 2010-03-14 David Brownell * : FT2232: lookup and save layout just once Streamline use of the layout: have the "ft2232_layout" command look it up and save the result, instead of having a few different chunks of code looking it up later, and saving just its name (which is already part of the layout). This - is cleaner - reports errors sooner - facilitates earlier adapter-specific setup - removes unused "default to "usbjtag" logic Signed-off-by: David Brownell 2010-03-11 David Brownell * : versaloon cleanup patch Remove undesirable - backslashes at end-of-line; - initializations of BSS data to zero/NULL; - overlong lines (80+ characters) - whitespace issues - brackets around single-line statements And other minor issues reported by the Linux "checkpatch" utility Signed-off-by: David Brownell 2010-03-08 Michal Demin * : Add support for Bus Pirate as a JTAG adapter. This includes a driver and matching config file. This support needs to be enabled through the initial "configure" (use "--enable-buspirate"). Signed-off-by: Michal Demin Signed-off-by: David Brownell 2010-03-10 Spencer Oliver * : MIPS: make fixed code arrays static const Signed-off-by: Spencer Oliver 2010-03-08 Spencer Oliver * : PIC32: add flash algorithm support Add flash algorithm support for the PIC32MX. Still a few things todo but this dramatically decreases the programing time, eg. approx programming for 2.5k test file. - without fastload: 60secs - with fastload: 45secs - with fastload and algorithm: 2secs. Add new devices to supported list. Signed-off-by: Spencer Oliver 2010-03-08 Spencer Oliver * : STR7: flash loader cleanup - make algorithm array static const. - increase algorithm buffer size to 32k. Signed-off-by: Spencer Oliver 2010-03-08 Spencer Oliver * : ADUC702x: flash loader cleanup - make algorithm array static const. Signed-off-by: Spencer Oliver 2010-03-08 David Brownell * : move a constant table to .rodata section The table of command registration functions shouldn't be in writable memory, where stray pointers can clobber it. Also, it shouldn't be initialized at runtime; that just consumes needless code space. Signed-off-by: David Brownell 2010-03-08 Øyvind Harboe * : zy1000: embedded ice dcc tweak How many bits to shift out before/after enabled tap not in bypass is calculated outside the loop. This is more of a demonstration of principle and to clarify code than a performance optimisation as such. Follows up a bit on the simplification work in jtag interface. Signed-off-by: Øyvind Harboe 2010-03-04 Øyvind Harboe * : jtag: jtag_add_ir_scan() now takes a single field In the code a single field was all that was ever used. Makes jtag_add_ir_scan() simpler and leaves more complicated stuff to jtag_add_plain_ir_scan(). Signed-off-by: Øyvind Harboe 2010-03-06 Antonio Borneo * : CFI: review print of Voltage values JEDEC standard reports Vpp integer part encoded as 4 bit HEX value. To print it using decimal digits, %u is required. Other voltage values are coded as BCD, so %x is appropriate. Code already prints one nibble at a time, so no need for field width and precision in format string. Signed-off-by: Antonio Borneo Signed-off-by: Øyvind Harboe 2010-03-05 David Brownell * : README: update libftdi version The FT2232H really wants libftdi 0.17 or newer; some notable bugs got fixed in that version. Signed-off-by: David Brownell 2010-03-04 Øyvind Harboe * : minidriver: fix arm11 compilation problem Signed-off-by: Øyvind Harboe 2010-03-03 David Brownell * : NOR: trim range in flash_driver_protect() When the beginning or end of the specified range of sectors already has the requested protection status, don't ask the flash driver to change those sectors. This will among other things turn command sequences like this into the NOPs one would expect: flash protect_check 0 flash info 0 ... reports everything as unprotected ... flash protect 0 0 1 off That speeds things up (by whatever work was just avoided). Also, with Stellaris (which can't unprotect flash at page level) this can eliminate some undesirable/false error reports. (And finishes fixing a bug currently listed in our bug database...) Signed-off-by: David Brownell 2010-03-03 David Brownell * : NOR: stellaris message tweaks Give a more accurate failure message when trying to unprotect; don't complain about pages being write protected, just say that unprotect is not supported by the hardware ... referencing the new "recover" command, which is the way to achieve that. Likewise, when trying to protect, talk about "pages" (matching hardware doc) not "sectors" (an concept that's alien to these chips). Also make the helptext for the "recover" command mention that it also erases the device. Signed-off-by: David Brownell 2010-03-02 David Brownell * : ADIv5: use new DAP ops for AP read/write Make ADIv5 internals use the two new transport-neutral calls for reading and writing DP registers; and do the same for external callers. Also, bugfix some of their call sites to handle the fault returns, instead of ignoring them. Remove most of the JTAG-specific calls, using their code as the bodies of the JTAG-specific implementation for the new methods. NOTE that there's a remaining issue: mem_ap_read_buf_u32() makes calls which are JTAG-specific. A later patch will need to remove those, so JTAG-specific operations can be removed from this file, and so that SWD support will be able to properly drop in as just a transport layer to the ADIv5 infrastructure. (The way read results are posted may need some more attention in the transport-neutrality interface.) Signed-off-by: David Brownell 2010-03-02 David Brownell * : ADIv5: use new dap_run() operation Make ADIv5 use one of the new transport-neutral interfaces: call dap_run(), not jtagdp_transaction_endcheck(). Also, make that old interface private; and bugfix some of its call sites to handle the fault returns, instead of ignoring them. Signed-off-by: David Brownell 2010-03-02 David Brownell * : target_resume() doxygen Add doxygen for target_resume() ... referencing the still-unresolved confusion about what the "debug_execution" parameter means (not all CPU support code acts the same). The 'handle_breakpoints" param seems to have resolved the main issue with its semantics, but it wasn't part of the function spec before. Signed-off-by: David Brownell 2010-03-02 David Brownell * : ADIv5: use right ID for Cortex-M3 ETM Correct a mistake made copying the ID of the Cortex-M3 ETM module from the TRM, so that "dap info" on a CM3 with an ETM will now correctly describe ROM table entries for such modules. (They are included on LPC17xx and some other cores.) Signed-off-by: David Brownell 2010-03-01 Øyvind Harboe * : zy1000: faster jtag_add_ir_scan() Faster and simpler. Signed-off-by: Øyvind Harboe 2010-03-01 Øyvind Harboe * : zy1000: add jtag_add_tms_seq support Signed-off-by: Øyvind Harboe 2010-02-28 Spencer Oliver * : armv4_5: remove core_type check in mcr/mrc cmd core_type check is not required as the core function will be null for cores that do not support the mcr/mrc functions. Signed-off-by: Spencer Oliver 2010-02-28 Spencer Oliver * : stellaris: recover_command use usleep rather than sleep windows api does not define a posix sleep, use usleep that has an openocd wrapper to the win32 native function. Signed-off-by: Spencer Oliver 2010-02-26 Spencer Oliver * : semihosting: add armv7m semihosting support do_semihosting and arm_semihosting now check the core type and use the generic arm structure. Signed-off-by: Spencer Oliver 2010-02-26 Spencer Oliver * : CortexM3: move disassemble cmd to arm cmd group Rather than using a Cortex disassemble cmd, we now use the arm generic version. Signed-off-by: Spencer Oliver 2010-01-13 Spencer Oliver * : MIPS: add mips algorithm support - add mips support for target algorithms. - added handlers for target_checksum_memory and target_blank_check_memory. - clean up long lines Signed-off-by: Spencer Oliver 2010-02-28 Mariano Alvira * : Add board/redbee-usb.cfg The Redbee USB is a small form-factor usb stick from Redwire, LLC (www.redwirellc.com/store), built around a Freescale MC13224V ARM7TDMI + 802.15.4 radio (plus antenna). It includes an FT2232H for debugging, with Channel B connected to the mc13224v's JTAG interface (unusual) and Channel A connected to UART1. Signed-off-by: David Brownell 2010-02-27 Mariano Alvira * : Add target/mc13224v.cfg The MC13224V is a FreeScale ARM7TDMI based IEEE802.15.4 platform for Zigbee and similar low-power wireless applications. Using PIP (Platform In Package) technology, it integrates: an RF balun and matching network; a buck converter (only an external inductor is necessary); 96KB of SRAM; and 128KB of non-volatile memory. It has an integrated bootloader and can boot from a variety of sources: external SPI or I2C non-volatile memory, an image loaded over UART1, or the internal non-volatile memory. The image loaded from one of these sources is executed directly from SRAM starting at location 0x00400000. Open source development code at http://mc1322x.devl.org Signed-off-by: David Brownell 2010-02-27 David Brownell * : ADIv5 DAP ops switching to JTAG or SWD modes Define two new DAP operations which use the new jtag_add_tms_seq() calls to put the DAP's transport into either SWD or JTAG mode, when the hardware allows. Tested with the Stellaris 'Recovering a "Locked" Device' procedure, which loops five times over both of these. Signed-off-by: David Brownell 2010-02-27 David Brownell * : interface: define TMS sequence command For support of SWD we need to be able to clock out special bit sequences over TMS or SWDIO. Create this as a generic operation, not yet called by anything, which is split as usual into: - upper level abstraction ... here, jtag_add_tms_seq(); - midlayer implementation logic hooking that to the lowlevel code; - lowlevel minidriver operation ... here, interface_add_tms_seq(); - message type for request queue, here JTAG_TMS. This is done slightly differently than other operations: there's a flag saying whether the interface driver supports this request. (In fact a flag *word* so upper layers can learn about other capabilities too ... for example, supporting SWD operations.) That approach (flag) lets this method *eventually* be used to eliminate pathmove() and statemove() support from most adapter drivers, by moving all that logic into the mid-layer and increasing uniformity between the various drivers. (Which will in turn reduce subtle bugginess.) Signed-off-by: David Brownell 2010-02-24 David Brownell * : ARM ADIv5 doxygen and cleanup Add doxygen for mem_ap_read_buf_u{8,16,32}() calls, and shrink a few overlong lines. Signed-off-by: David Brownell 2010-02-23 David Brownell * : ARM ADIv5: rename more JTAG-specific routines Highlight more of the internal JTAG-specific utilities, so it's easier to identify code needing changes to become transport-neutral. Signed-off-by: David Brownell 2010-02-09 Øyvind Harboe * : arm11: allow minidrivers to implement inner loop of memory writes This allows minidrivers to e.g. hardware accelerate memory writes. Same trick as is used for arm7/9 dcc writes. Added error propagation for memory transfer failures in code rearrangement. Also the JTAG end state is not updated until after the memory write run is complete. Signed-off-by: Øyvind Harboe 2010-02-21 David Brownell * : ft2232 table init cleanup Use labeled initializers in the table of layouts instead of positional ones. This ls cleaner and less error prone, plus it simplifies patches which add members to these structure. Signed-off-by: David Brownell 2010-02-21 David Brownell * : ADIv5: relocate memacess_tck cycles When using an AP to access a memory (or a memory-mapped register), some extra TCK (assuming JTAG) cycles should be added to ensure the AP has enugh time to complete that access before trying to collect the response. The previous code was adding these cycles *before* trying to access (read or write) data to that address, not *after*. Fix by putting the delays in the right location. Signed-off-by: David Brownell 2010-02-21 David Brownell * : ARM: ADIv5, deadcode cleanup I have no idea what the scan_inout_check() was *expecting* to achieve by issuing a read of the DP_RDBUFF register. But in any case, that code was clearly never being called ("invalue" always NULL) ... so remove it, and the associated comment. Also rename it as ap_write_check(), facilitating a cleanup of its single call site by removing constant parameters. Signed-off-by: David Brownell 2010-02-21 David Brownell * : ADIv5 clean up AP fault handling Pass up fault codes from various routines, so their callers can clean up after failures, and remove the FIXME comments highlighting those previously goofy code paths. dap_ap_{read,write}_reg_u32() dap_ap_write_reg() mem_ap_{read,write}_u32() mem_ap_{read,write}_atomic_u32() dap_setup_accessport() Make dap_ap_write_reg_u32() just wrap dap_ap_write_reg(), instead of cloning its core code (and broken fault handling). Signed-off-by: David Brownell 2010-02-21 David Brownell * : ARM: keep a handle to the PC Keep a handle to the PC in "struct arm", and use it. This register is used a fair amount, so this is a net minor code shrink (other than some line length fixes), but mostly it's to make things more readable. For XScale, fix a dodgy sequence while stepping. It was initializing a variable to a non-NULL value, then updating it to handle the step-over-active-breakpoint case, and then later testing for non-NULL to see if it should reverse that step-over-active logic. It should have done like ARM7/ARM9 does: init to NULL. Signed-off-by: David Brownell 2010-02-21 David Brownell * : ARM11: per-core options should not be global Address some FIXME comments by getting rid of globals, moving per-core parameters in the existing per-core data structure. This will matter most whenever there are multiple ARM11 cores, e.g. ARM11 MPcore chips, but in general is just cleanup. Signed-off-by: David Brownell 2010-02-21 David Brownell * : Open the merge window for the 0.5.0 release cycle. Signed-off-by: David Brownell 2010-02-21 David Brownell * : User's Guide mentions OS-specific installation Specifically the Linux issue of needing "udev" rules, and MS-Windows needing driver configuration. Also, update the existing udev note to use the correct name of that rules file in the source tree. Signed-off-by: David Brownell 2010-02-20 David Brownell * : CSB337 board cleanup (quasi-regression) Get rid of new nasty warning: NOTE! Severe performance degradation without fast memory access enabled... Signed-off-by: David Brownell 2010-02-16 Marc Pignat * : atm920t : fix breakpoints and data cache handling Breakpoints did not work because the data cache was not flushed properly. As a bonus add capability to write to memory marked as read only by the MMU, which allows software breakpoints in such memory regions. 2010-02-15 Øyvind Harboe * : gpl: fix GPL startup message Signed-off-by: Øyvind Harboe 2010-02-14 Mathias Kuester * : fix crash with DSP563XX When a DSP563xx-aware GDB asks OpenOCD for target registers, the result should be a GDB with register data ... not an OpenOCD crash. (Note that mainline GDB doesn't currently support this core, so for now, this requires a GDB with FreeScale patches.) Signed-off-by: David Brownell 2010-02-13 David Brownell * : Restore "-dev" version suffix (0.4.0-rc2-dev) Signed-off-by: David Brownell 2010-02-11 Spencer Oliver * : STR9xpec: issue warning when unlocking device Issue warning to user when unlocking or writing the option bytes. The new settings will not take effect until a target reset. Signed-off-by: Spencer Oliver 2010-02-12 Øyvind Harboe * : arm720t: virt2phys callback added This is a copy and paste of arm926ejs. Not tested, but ready for testing at least. There is a good chance that it will work if the generic armv4_5 fn's are robust enough... Signed-off-by: Øyvind Harboe 2010-02-11 Viktar Palstsiuk * : target library: configuration files for openocd tested with Atmel SAM-ICE V6 JTAG. Signed-off-by: Øyvind Harboe 2010-02-10 Øyvind Harboe * : arm11: fix another infinite loop bug reset init would get stuck in an infinite loop when e.g. khz was too high. Added timeout. This is a copy of paste of a number of such bugfixes in the arm11 code. Arm11 code reviewed for further such infinite loop bugs and I couldn't find any more. Xing fingers it's the last one... Signed-off-by: Øyvind Harboe 2010-02-09 Øyvind Harboe * : target: add todo in target_write_memory() about alignment target_write_buffer() does not align "buffer" in host memory passed to target_write_memory(). Signed-off-by: Øyvind Harboe 2010-02-06 David Brownell * : Re-title Developer's Guide The Doxygen output was previously titled "OpenOCD Reference Manual", which was quite misleading ... the User's Guide is the reference manual which folk should consult about how to use the software. Just rename it to match how it's been discussed previously, and to bring out its intended audience: developers of this software. As a rule, Doxygen is only for folk who work with the code it documents. Signed-off-by: David Brownell 2010-02-05 Øyvind Harboe * : zy1000: complete zy1000_uart to jim command switch Signed-off-by: Øyvind Harboe 2010-02-04 David Brownell * : Documentation: mention bug database Have the User's Guide and BUG handling notes both reference the fact that we now have a bug database at SourceForge. Signed-off-by: David Brownell 2010-02-04 Spencer Oliver * : CMD: duplicate cmd error msg When registering cmds we report duplicate attempts to register a cmd as a LOG_ERROR. Some situations need this, such as when registering dual flash banks. http://www.mail-archive.com/openocd-development@lists.berlios.de/msg11152.htmlSigned-off-by: Spencer Oliver 2010-02-03 Spencer Oliver * : JTAG: fix bug when no interface connected - fix coredump when OpenOCD is started without a jtag interface connected. Signed-off-by: Spencer Oliver 2010-02-02 David Brownell * : NOR: User's Guide updates Remove long-obsolete text about "erase_check" affecting "flash info" output. Move parts of that text to "protect_check", where it's still relevant; and update the "flash info" description to mention the issue. (This is still awkward. It might be best to make "protect_check" mirror "erase_check" by dumping what it finds, so "flash info" doesn't dump any potentially-stale cache info.) Signed-off-by: David Brownell 2010-02-02 Edgar Grimberg * : flash/str7x: After reset init the flash is unlocked The default state of the STR7 flash after a reset init is unlocked. The information in the flash driver now reflects this. The information about the lock status cannot be read from the flash chip, so the user is informed that flash info might not contain accurate information. [dbrownell@users.sourceforge.net: line length shrinkage] Signed-off-by: Edgar Grimberg Signed-off-by: David Brownell 2010-01-29 Edgar Grimberg * : Test cases ran on v0.4.0-rc1 Test cases ran on v0.4.0-rc1 for a number of targets: AT91FR40162 LPC2148 SAM7 STR710 STR912 The goal of the testing session was to prove basic functionality of OpenOCD for different targets. Signed-off-by: Edgar Grimberg 2010-01-31 David Brownell * : ADIv5: more messaging cleanup, docs When the TAR cache was explicitly invalidated, don't bother printing it; the actual hardware status is more informative. Provide some doxygen for the MEM-AP setup routine. Signed-off-by: David Brownell 2010-01-21 Øyvind Harboe * : telnet: fix strage blank spaces at beginning of telnet lines Sometimes we saw two strange blank spaces at the beginning of the telnet lines. progress ogress > This patch fixes this problem: progress progress > The code changes are *reasonably* clean, but perhaps it could be made a bit more elegant, but I didn't want to change things after I finished diagnosis/testing & submitting the patch. The problem was that logging can send the text and the newline separately in two different requests and the telnet code would incorrectly remove the prompt from the end of a line. Signed-off-by: Øyvind Harboe 2010-01-30 David Brownell * : ADIv5 error checking for Tcl commands Reject invalid AP numbers (256+) as Tcl operation parameters. Shrink one of the overlong lines. Add my copyright to the ADIv5 code (multiple contributions). Signed-off-by: David Brownell 2010-01-29 David Brownell * : ADIv5: cleanup, rename swjdp_transaction_endcheck() Make messages reference "DAP" if they're actually transport-agnostic, or "JTAG-DP" when they're JTAG-specific. Saying SWJ-DP is often wrong (on most Cortex-A8 chips) and is confusing even if correct (since we don't yet support SWD). Rename a JTAG-specific routine to jtagdp_transaction_endcheck() to highlight that it's JTAG-specific, and that identify DAP clients undesirably depending on JTAG. (They will all need to change for SWD support.) Shrink a few overlong lines of code. Copy a comment from code removed in a previous patch (for the ARMv7-M "dap baseaddr" command). Signed-off-by: David Brownell 2010-01-29 David Brownell * : NOR: cleanup driver decls Fix goofy struct indents. Function names *are* their addresses. Signed-off-by: David Brownell 2010-01-28 David Brownell * : doc clarifications for server flags The "-f" is a shortcut for "-c" ... and providing any "-c" options means the "openocd.cfg" file isn't implicitly used. Both the User's Guide and the manual page were weak on these points, which has led to some confusion. Also update the manual page to include highlights of the search path mechanism, including the facts that it exists and that "-s" adds to it. Stop saying only the current directory is involved; the OpenOCD script library is quite significant. (Missing: complete manpage coverage of the search path, including a FILES section listing all components and saying where the script library is found.) Signed-off-by: David Brownell 2010-01-28 Spencer Oliver * : ARM semihosting: win32 and cygwin fixes Cygwin would fail to reopen a previously written file if the mode is not given. Simplified converting the open flags and made sure the win32 O_BINARY bit is set. Added define for systems that do not support O_BINARY. Signed-off-by: Spencer Oliver 2010-01-27 David Brownell * : Cortex-M3: report lockup, and recover ARMv7-M defines a "lockup" state that's entered in certain double fault sequences which can't be recovered from without external help. OpenOCD has previously ignored this. Issue a diagnostic saying the chip has locked up, and force exit from this state by halting the core. It's not clear this is the best way to handle lockup; but there should now be less confusion. Signed-off-by: David Brownell 2010-01-27 David Brownell * : Cortex-A8: debug messaging tweaks Make that "TODO" message say what needs to be done. Say what part of examining failed. Signed-off-by: David Brownell 2010-01-26 David Brownell * : cygwin buildfix isspace() parameter must be an integer, else a 'char' gets used as an array index (sigh). Signed-off-by: David Brownell 2010-01-25 Edgar Grimberg * : core arm11: Silence logs at level 3 if there is no activity If the target and openocd are idling, the log should normally be silent at level 3. (Given no verbose logging options.) Signed-off-by: Edgar Grimberg Signed-off-by: David Brownell 2010-01-22 David Brownell * : EmbeddedICE - fix Feroceon/Dragonite message The breakpoint/watchpoint message was wrong for Feroceon and Dragonite, which have only one working watchpoint unit. Signed-off-by: David Brownell 2010-01-22 David Brownell * : ARM11: fix breakpoints with GDB This fixes a bug whereby GDB's breakpoints weren't activated. The root cause is a confused interface to resume(). Fix by almost ignoring the "handle breakpoints" parameter; it only seems related to the case of skipping breakpoint-at-PC. Update a few coments to clarify what's happening. Signed-off-by: David Brownell 2010-01-21 David Brownell * : User's Guide secton on target hardware setup Highlight the needs to properly jumper development boards; to make the OpenOCD configuration match the jumpering; and to have a usable "reset-init" method when debugging early boot code. Specific mention of the "ATX Mode" that seems useful on many i.MX boards, forcing NAND boot. Signed-off-by: David Brownell 2010-01-21 Øyvind Harboe * : target: print reason why GDB halts If GDB halts unexpectedly, print reason: srst assert or power out detected. If polling fails, then things are a bit trickier. We do not want to spam telnet or the log with polling failed messages. Leave that case be w/a comment in a code for now. Signed-off-by: Øyvind Harboe 2010-01-21 Edgar Grimberg * : target: Fixed format problem for mdh Fixed format problem for mdh. It needs to display 4 chars. Signed-off-by: Edgar Grimberg 2010-01-21 Øyvind Harboe * : ecos: add missing PRId8 definition Signed-off-by: Øyvind Harboe 2010-01-20 David Brownell * : Cortex-M3 vector_catch testing support The "cm3-ftest.cfg" can be used to verify that OpenOCD handles certain faults correctly: - Test #1: it ignores faults that it wasn't told to catch - Test #2: if vector_catch is told to catch, it catches The "fault.c" generates ASM code to trigger faults, while the config script loads and runs pre-compiled code. This covers most, but not all, of the vector_catch options. Signed-off-by: David Brownell 2010-01-20 David Brownell * : gdb_server: correctly report flash sector sizes Report each region of same-size sectors separately, instead of incorrectly reporting that every sector has the same size. This is a longstanding bug on NOR flash chips with non-uniform sector sizes. It was largely hidden by other bugs in flash handling. When some of those were recently fixed, this one was exposed as a regression on str710. [oyvind.harboe@zylin.com: update the loop to behave on str7 ] Signed-off-by: Øyvind Harboe Signed-off-by: David Brownell 2010-01-20 Øyvind Harboe * : testing: fix str710 test case now builds Make the test case easily adjustable in size. str710 has very peculiar flash sector layout, nice for testing, but a larget test_rom.elf is required. Signed-off-by: Øyvind Harboe 2010-01-19 Spencer Oliver * : ARMV7M: handle bkpt instruction on resume/step Skip over a bkpt instruction if found on resume/step. Only software breakpoints known to OpenOCD are currently handled. So this handles the special case of either a user added bkpt or library added, eg. semi-hosting support. Signed-off-by: Spencer Oliver 2010-01-19 David Brownell * : gdb_server -- subroutinize memory map logic Put the memory map logic into its own subroutine. This will make it a bit easier to package bugfixes, and simplifies the query packet handling. Signed-off-by: David Brownell 2009-11-21 Andreas Fritiofson * : update win32 script search path The default script search path on Windows is out of date with the current layout (from installation and documentation), which makes the standard script library not be found after a normal ./configure && make && make install under msys/MinGW. The same should hold true for cygwin native builds (not verified). Update search path to ../share/openocd/scripts not ../lib/openocd, relative to the openocd executable. Signed-off-by: Andreas Fritiofson Signed-off-by: David Brownell 2010-01-18 Øyvind Harboe * : zy1000: flush jtag buffer before changing speed It is conceivable that there could be commands in the queue when a speed change request comes in. Flush the hw queue before changing speed. Not observed, found by inspection. Signed-off-by: Øyvind Harboe 2010-01-19 Øyvind Harboe * : flash: add error messages upon incorrect arguments to flash iteration According to OpenOCD error handling rules the error is logged at where it occurs(same site where an exception would have been thrown). Signed-off-by: Øyvind Harboe 2010-01-18 Øyvind Harboe * : commands: allow scan_chain command to be executed during config Adding taps and then dumping them is quite reasonable thing to do in a config script. Signed-off-by: Øyvind Harboe 2010-01-16 richard vegh * : NAND: lpc3180 crashes on LPC3250 The LPC3180 NAND driver was crashing on some large page chips. Fix: - Crash and related functionality (don't memset too much OOB data) - Some debug messages - Command handling now works [dbrownell@users.sourceforge.net: whitespace/linelength/message cleanup] Signed-off-by: David Brownell 2010-01-15 David Brownell * : ARM DPM: disable some nyet-ready breakpoint code Until we manage breakpoints at runtime (patches not ready for 0.4) the only way this code should touch them is to disable them at server startup (a previous debug session may have left them active). Signed-off-by: David Brownell 2010-01-14 David Brownell * : jtag.h whitespace/comment cleanup Signed-off-by: David Brownell 2010-01-14 David Brownell * : ARM7/ARM9: improved reset support Teach most remaining ARM cores how to use the "reset-assert" event. Same model as elsewhere: iff a handler is provided for that event, use that instead of trying to assert SRST (which may be unavailable, or inappropriate since it resets too much). Else no change. Signed-off-by: David Brownell 2010-01-14 Laurentiu Cocanu * : str9x.c: remove optimization when erasing the whole bank Using the erase bank command will cause a time out error. Replacing this with the erase sector bank will provide a slower but safer and stable method to erase the flash. Signed-off-by: Laurentiu Cocanu Signed-off-by: Øyvind Harboe 2010-01-14 Spencer Oliver * : GDB: change gdb_breakpoint_override to COMMAND_ANY - enable gdb_breakpoint_override to be used within config script. Signed-off-by: Spencer Oliver 2010-01-13 David Brownell * : NOR: add optional "flash erase_address" sector padding Add a NOR flash mechanism where erase_address ranges can be padded out to sector boundaries, triggering a diagnostic: > flash erase_address 0x0001f980 16 address range 0x0001f980 .. 0x0001f98f is not sector-aligned Command handler execution failed in procedure 'flash' called at file "command.c", line 647 called at file "command.c", line 361 > > flash erase_address pad 0x0001f980 16 Adding extra erase range, 0x0001f800 to 0x0001f97f Adding extra erase range, 0x0001f990 to 0x0001fbff erased address 0x0001f980 (length 16) in 0.095975s (0.163 kb/s) > This addresses what would otherwise be something of a functional regression. An earlier version of the interface had a dangerous problem: it would silently erase data outside the range it was told to erase. Fixing that bug turned up some folk who relied on that unsafe behavior. (The classic problem with interface bugs!) Now they can get that behavior again. If they really need it, just specify "pad". Signed-off-by: David Brownell 2010-01-11 Øyvind Harboe * : arm7/9: enable check that DCC downloads have been enabled Signed-off-by: Øyvind Harboe 2010-01-11 Øyvind Harboe * : target: add check_reset hook Allow targets to run checks post reset. Used to check that e.g. DCC downloads have been enabled. Signed-off-by: Øyvind Harboe 2010-01-11 Øyvind Harboe * : debug: make logging of commands terser one line / command instead of one line per argument. Signed-off-by: Øyvind Harboe 2010-01-11 Vladimir Zapolskiy * : Added Openmoko USB JTAG interface config file. Added interface config file for JTAG/RS232 debug board originally integrated to Neo 1973 and Neo FreeRunner phones. Adapter was tested with i.MX31, S3C2410 and AT91SAM9260 processors. Signed-off-by: Vladimir Zapolskiy 2010-01-11 Øyvind Harboe * : reset: better error messages Use correct tcl syntax to throw exception. the syntax is "return -code error" not "return -error" Signed-off-by: Øyvind Harboe 2010-01-11 Øyvind Harboe * : zy1000: reset bugfix flush JTAG FIFO before reset. Fixes RCLK problems observed w/lpc2148, but really fixes a wider range of problems. Signed-off-by: Øyvind Harboe 2010-01-08 Øyvind Harboe * : shutdown: more graceful shutdown Shutdown is not an error condition, do not return error from main. Signed-off-by: Øyvind Harboe 2010-01-10 David Brownell * : FreeBSD build fixes Based on notes from Tomek Cedro and Steve Franks . In the User's Guide, sort the list of operating systems reported through Tcl with $ocd_HOSTOS ... and include FreeBSD. Signed-off-by: David Brownell 2010-01-09 David Brownell * : jtag/tcl help/usage fixups The usual: expand several helptexts to be more correct and to use full sentences; make the usage messages use the same EBNF as the User's Guide; use function names for their addresses. Also add a comment about that odd jtag_command_handlers_to_move[] thing. Signed-off-by: David Brownell 2010-01-09 David Brownell * : jtag: presto, parport help/usage updates Presto: add doxygen file comment. Parport: note a couple gaps in layout config. Both: use the uniform EBNF for usage, bugfix helptexts, use function name as its address not "&name". Signed-off-by: David Brownell 2010-01-09 David Brownell * : parport (mostly) doc fixes The "parport_port" commands generally don't *require* a port_number; they're of the "apply any parameter, then print result" variety. Update the User's Guide accordingly. Some of those commands are intended to be write-once: parport_port, and parport_cable. Say so. Use proper EBNF for the parport_write_on_exit parameter. Parport address 0xc8b8 is evidently mutant. Say so in the "parport.cfg" file, to avoid breaking anyone with that mutant config. But update the User's Guide to include a sane example for the LP2 port. Finally document the "presto_serial" command. Signed-off-by: David Brownell 2010-01-09 David Brownell * : src/flash/nor: usage/help/doc updates Make "usage" messages use the same EBNF as the User's Guide; no angle brackets. Improve and correct various helptexts. Don't use "&function"; a function's name is its address. Remove a couple instances of pointless whitespace; shrink a few overlong lines; fix some bad indents. Add TODO list entry re full support for NAND/NOR bank names. Signed-off-by: David Brownell 2010-01-09 David Brownell * : src/server: usage/help/doc updates Make "usage" messages use the same EBNF as the User's Guide; no angle brackets. Improve and correct various helptexts. Specifically for the port commands, clarify that the number is optional, and omitting it causes the current number to be displayed. Don't use "&function"; a function's name is its address. Remove a couple instances of pointless whitespace; shrink a few overlong lines. Signed-off-by: David Brownell 2010-01-08 David Brownell * : PLD: usage/help updates Make "usage" messages use the same EBNF as the User's Guide; no angle brackets. Improve and correct various helptexts. Don't use "&function"; a function's name is its address. Remove a couple instances of pointless whitespace, shrink a few overlong lines. Signed-off-by: David Brownell 2010-01-08 David Brownell * : Doc/examples: clarify usage messages Update/bugfix the "hello" example; emphasize using EBNF syntax, matching the User's Guide. Correct the Texinfo style guide to say EBNF, not BNF. Signed-off-by: David Brownell 2010-01-08 David Brownell * : MFLASH: help/usage updates Make "usage" messages use the same EBNF as the User's Guide; no angle brackets. Improve and correct various helptexts. Don't use "&function"; a function's name is its address. Remove a couple instances of pointless whitespace. Signed-off-by: David Brownell 2010-01-08 David Brownell * : NOR: add FIXMEs for writing ones It can invalidate ECC codes, and in general is not guaranteed to work. (However on some chips it _appears_ to behave.) Just don't do it; don't write in those cases. Signed-off-by: David Brownell 2010-01-07 David Brownell * : ARM966: help/usage updates Usage syntax messages have the same EBNF as the User's Guide; there should be no angle brackets in either place. Fix the User's Guide to say where the magic CP15 bits are defined; and add comments in case someone provides mcr/mrc methods. Signed-off-by: David Brownell 2010-01-07 David Brownell * : ARM720: help/usage updates Deprecate the "pass an instruction opcode" flavor of cp15 access in favor of the "arm mcr ..." and "arm mrc ..." commands, which offer fewer ways to break things. Use the same EBNF syntax in the code as for the user's guide. Update User's Guide to say where to find those magic values (which table in the ARM920 TRM). Signed-off-by: David Brownell 2010-01-07 David Brownell * : ARM11: help/usage updates Usage syntax messages have the same EBNF as the User's Guide; there should be no angle brackets in either place. Uupdate some helptext to be more accurate. Fix the User's Guide in a few places to be more consistent (mostly to use brackets not parentheses) and to recognize that parameter may be entirely optional (in which case the command just displays output, and changes nothing). Also reference NXP, not Philips, for LPC chips. Don't use "&function"; functions are like arrays, their address is their name. Signed-off-by: David Brownell 2010-01-07 David Brownell * : ARMv7: help/usage updates Provide helptext which was sometimes missing; update some of it to be more accurate. Usage syntax messages have the same EBNF as the User's Guide; there should be no angle brackets in either place. Don't use "&function"; functions are like arrays, their address is their name. Shrink some overlong lines, remove some empties. Add a couple comments about things that should change: those extra TCK cycles for MEM-AP reads are in the wrong place (that might explain some problems we've seen); the DAP command tables should be shared, not copied. Signed-off-by: David Brownell 2010-01-07 David Brownell * : target misc: help/usage updates Provide helptext which was sometimes missing; update some of it to be more accurate. Usage syntax messages have the same EBNF as the User's Guide. Don't use "&function"; functions are like arrays, their address is their name. Shrink some overlong lines; remove some empties. Signed-off-by: David Brownell 2010-01-07 Spencer Oliver * : MIPS: change bulk_write_memory fallback msg to LOG_DEBUG Signed-off-by: Spencer Oliver 2010-01-06 Spencer Oliver * : MIPS: fastdata bulk write fallback If fastdata access fails, then fallback to default mips_m4k_write_memory Remove unnecessary fastdata loader verify check Signed-off-by: Spencer Oliver 2010-01-05 David Brownell * : don't require 'openocd.cfg' to start Starting the daemon with with just a bare "openocd" I saw: Can't find openocd.cfg That's not an error; don't treat it as if it were. There may be an error later -- like, "no interface set up" -- but let messages only report real errors, not fake ones. 2010-01-05 David Brownell * : ARM: add comments re DAP assumptions I think some of these assumptions are not well-founded. Related, that swjdp_transaction_endcheck() is a bit iffy. Signed-off-by: David Brownell 2009-12-21 Spencer Oliver * : PIC32: enable ram execution add reset-init script to allow ram execution from reset, this is required for ejtag fastdata access. Signed-off-by: Spencer Oliver 2009-12-17 Spencer Oliver * : parport: output port as hex rather than dec Signed-off-by: Spencer Oliver 2010-01-05 Øyvind Harboe * : gdb: fix regression in gdb_port command The gdb_port command can be invoked during normal execution to report the port used for gdb, whereas it was listed as CONFIG stage only, which caused an error when excuting it to return the reported error. Also in line with the grander goal of making more commands available during all "modes" (perhaps retiring config mode), there is no particular reason to limit gdb_port to the config stage. Regression was introduced in: b3bf1d12b2fdfba1c1cbee3e1afbfbb27cbd1a26 aka v0.4.0-rc1-32-gb3bf1d1 Signed-off-by: Øyvind Harboe 2010-01-04 David Brownell * : ARMv7-M: use AP_REG_* symbol Signed-off-by: David Brownell 2010-01-03 David Brownell * : JTAG/drivers: ft2232 docs Add doxyegen description for this driver. Correct the helptext (configures *or* displays based on #params), and usage (use the same BNF as the User's Guide). Remove superfluous #include Signed-off-by: David Brownell 2010-01-03 David Brownell * : JTAG: Amontec JTAG accelerater "rtck" is back The command processing conversion a while back lost the "rtck" enable/disable command; restore it. NOTE that having such a command is wrong; there's a standard way to enable adaptive clocking ("speed 0"). Signed-off-by: David Brownell 2010-01-03 David Brownell * : JTAG/drivers: amt_jtagaccel fixes + cleanup Build fixes: it failed abysmally with PPDEV enabled. Swapped a build-time error with a FIXME comment in the affected macros. Cleanup: remove "&" before function pointers, and excess indent, for the interface struct declaration. Signed-off-by: David Brownell 2010-01-02 David Brownell * : ARM: dap info fix + tweaks Fix: don't print the BASE address except if it's a MEM-AP; that's an unlikely error, but there's no point getting it wrong. Tweaks: comments, capitalization. Signed-off-by: David Brownell 2010-01-02 David Brownell * : ARM: ADIv5 symbol and comment cleanup Instead of magic numbers, use their AP_REG_* constants. Rename the ROM address symbol as BASE to match ARM's documentation. Comment various other symbols in the header; add some missing ones. Remove an unused struct. Add some doxygen for stuff including the DAP structure and initialization. Signed-off-by: David Brownell 2010-01-02 David Brownell * : streamline and document helptext mode displays Most commands are usable only at runtime; so don't bother saying that, it's noise. Moreover, tokens like EXEC are cryptic. Be more clear: highlight only the commands which may (also) be used during the config stage, thus matching the docs more closely. There are - Configuration commands (per documentation) - And also some commands that valid at *any* time. Update the docs to note that "help" now shows this mode info. This also highlighted a few mistakes in command configuration, mostly commands listed as "valid at any time" which shouldn't have been. This just fixes ones I noted when sanity testing. Signed-off-by: David Brownell 2010-01-01 Dean Glazeski * : Add the current command to the command information I wanted to make it so I can be ignorant of a commands invocation string, so I tried to use CMD_CURRENT (aka cmd->current) which is supposed to house a pointer to the current command.  It turns out that this wasn't being set. This patch adds the current command structure to the command invocation structure before sending it along to the command handler. Signed-off-by: David Brownell 2009-12-31 David Brownell * : User's Guide: warn about the forum Namely, that developers don't hang out; it's a users-only club. Signed-off-by: David Brownell 2009-12-31 Antonio Borneo * : ARM7_9: Fix segfaults Handlers for commands - arm7_9 semihosting - $_TARGETNAME arp_reset assert 1 didn't check if target has already been examined, and could segfault when using the NULL pointer "arm7_9->eice_cache". Signed-off-by: Antonio Borneo Signed-off-by: David Brownell 2009-12-31 Antonio Borneo * : ARM9TDMI: Fix segfault. The handler for "arm9tdmi vector_catch ..." did not check if target has already been examined. Without this fix it segfaults when using NULL pointer "arm7_9->eice_cache". Signed-off-by: Antonio Borneo Signed-off-by: David Brownell 2009-12-30 Øyvind Harboe * : zy1000: add zy1000_ prefix to uart command less polution of the general namespace(preventive action, no problems reported). Signed-off-by: Øyvind Harboe 2009-12-29 Øyvind Harboe * : zy1000: reconfigure FPGA upon reset instead of just the CPU Signed-off-by: Øyvind Harboe 2009-12-25 Øyvind Harboe * : zy1000: less warnings use inline for static functions in header files to avoid warnings about fn not being used. Signed-off-by: Øyvind Harboe 2009-12-28 Piotr Esden-Tempski * : Added floss-jtag interface config file. 2009-12-28 Freddie Chopin * : stm32x commands get "usage" Add .usage fields to stm32x command_registration, so that "help stm32x" shows required parameters. Signed-off-by: Freddie Chopin Signed-off-by: David Brownell 2009-12-28 Piotr Esden-Tempski * : NOR: last_addr also needs correction when checking alignment Otherwise the new alignment checking algorithm thinks that the address is not aligned, because it is way beyond the last sector. Signed-off-by: David Brownell 2009-12-27 David Brownell * : NOR: make flash_write_unlock() pad to sector end Resolve a regression when using newish automagic "write_image" modes, by always padding to the end of affected sectors. Also document some issues associated with those automagic options, in the User's Guide and also some related code comments. We might need similar padding at the *beginning* of some sectors, but this is a minimalist fix for the problems which have currently been reported (plus doc updates). Signed-off-by: David Brownell 2009-12-09 Dean Glazeski * : Olimex SAM9-L9260 board configuration update. This updates the board configuration for the SAM9-L9260 board with the configuration for the on-board NAND and dataflash. Included are commands for configuring the AT91SAM9 NAND flash driver. Signed-off-by: David Brownell 2009-12-26 David Brownell * : User's Guide: update GDB info Advise leaving background polling enabled; fix broken URL; add simple program startup example. 2009-12-26 David Brownell * : NOR: Allocate the right amount of memory Switch to calloc() to simplify review and initialization. 2009-12-26 Antonio Borneo * : PARPORT code cleanup: Align elements in array. Signed-off-by: Antonio Borneo 2009-12-21 David Brownell * : v0.4.0-rc1 milestone Winter Solstice, 2009. Signed-off-by: David Brownell 2009-12-21 David Brownell * : Packaging fix Don't forget to list target/arm_opcodes.h Signed-off-by: David Brownell 2009-12-20 David Brownell * : Cortex-M3: cleanup Misc: - Introduce some "struct reg" temporaries, for clarity - Shorten lines - Add some missing whitespace - Clean up comments - Add notes about some fault handling issues - Most of these errata workarounds are for *OLD* chip revisions Signed-off-by: David Brownell 2009-12-21 Antonio Borneo * : arm7_9: Support VINITHI signal Command "reset halt" checks if PC properly resets, issueing warning: "PC was not 0. Does this target need srst_pulls_trst?". Checking PC against 0 is not always correct. Removed PC value check, as suggested by Øyvind Harboe. Signed-off-by: Antonio Borneo Signed-off-by: U-PROPRIET-28D9DF\PROPRIETAIRE 2009-12-09 Dean Glazeski * : AT91SAM9 NAND flash driver. This creates the TCL interface for configuring an AT91SAM9 NAND flash controller and implements the necessary functions to correctly work with a NAND flash device connected to the chip. This includes updates to the driver list and the Makefile.am to support building the driver and also houses the documentation update in openocd.texi. Signed-off-by: David Brownell 2009-12-19 David Brownell * : ETM: add "etm trigger_debug" command In conjunction with manual register setup, this lets the ETM trigger cause entry to debug state. It should make it easier to test and bugfix the ETM code, by enabling non-trace usage and isolating bugs specific to thef ETM support. (One current issue being that trace data collection using the ETB doesn't yet behave.) For example, many ARM9 cores with an ETM should be able to implement four more (simple) breakpoints and two more (simple) watchpoints than the EmbeddedICE supports. Or, they should be able to support complex breakpoints, incorporating ETM sequencer, counters, and/or subroutine entry/exit criteria int criteria used to trigger debug entry. Signed-off-by: David Brownell 2009-12-19 David Brownell * : ETM: start cleaning up ETM_CTRL bit handling Provide better comments for the ETM_CTRL bits; use the correct bit for half/full clock mode; and define a few more of the bits available from the earliest ETM versions. The new bit defintions use ETM_CTRL_* names to match their register (instead of ETM_PORT_* or ETMV1_*). For clarity, and better matching to docs, they are defined with bitshifting not pre-computed masks. Stop abusing typdefs for ETM_CTRL values; such values are not limited to the enumerated set of individual bit values. Rename etm->portmode to etm->control ... and start morphing it into a single generic shadow of ETM_CTRL. Eventually etm->tracemode should vanish, so we can just write etm->control to ETM_CTRL. Restore an "if" that somehow got dropped. Signed-off-by: David Brownell 2009-12-19 David Brownell * : NEWS: mention libftdi 0.17 2009-12-18 David Brownell * : Subject: flash fill[bwh] should use bulk i/o It's currently allocating a big buffer but writing it out in units of sizeof(host's pointer) ... sub-optimal. Plus fix a couple minor coding style goofs. Signed-off-by: David Brownell 2009-12-18 David Brownell * : XScale: better {read,write}_phys() We can actually do the right thing if the MMU is off; save the error message for the phys-but-MMU-enabled path, which is what isn't yet supported. Signed-off-by: David Brownell 2009-12-18 David Brownell * : stellaris: update bulk flash writes Try to right-size the SRAM buffers, by not: - using them for very small writes - giving up when a large buffer isn't available - allocating buffers much larger than their data Also don't: - bother loading the code unless we allocate the writebuffer too - be so verbose with messaging: * be more concise * reduce importance (e.g. DEBUG not WARNING) * remove duplication The minimum buffer size is something of a guess. It's eight times smaller than before, almost the same size as the code being downloaded. It probably deserves some tuning. Also, note an erratum affecting flash protection on some chips; and narrow many over-wide lines affected by the above changes. Signed-off-by: David Brownell 2009-12-17 Dean Glazeski * : NAND read data page refactor. Added a new function to encapsulate reading a page of data from a NAND device using either the read_block_data function of a NAND controller or to use direct reading of data from the NAND device. This also adds some performance enhancements and uses the read_data function if the read_block_data function fails safely (because it can't allocate a buffer in the working area). [dbrownell@users.sourceforge.net: fix fault handling, whitespace] Signed-off-by: David Brownell 2009-12-16 David Brownell * : Remove duplicate Olimex-"tiny" interface We already have tcl/interface/olimex-jtag-tiny.cfg and don't need a clone of it. 2009-12-16 David Brownell * : stellaris: comments Someday revisit various issues: Tempest parts support writing more than one word at a time; for some target firmware it might be necessary to save and restore flash IRQ configuration. (The safest policy is likely to always reset after flash updates.) Plus swap some undesirable TAB characters with SPACE. Signed-off-by: David Brownell 2009-12-16 David Brownell * : stellaris: remove needless code No point in reading and discarding a status value when fetching part description data. Or having that needless "#if 0" code. Signed-off-by: David Brownell 2009-12-16 David Brownell * : NOR: bugfix "flash fill[bwh] ..." helptext These commands don't have a "bank" parameter. Signed-off-by: David Brownell 2009-12-15 Øyvind Harboe * : ecos: crisper implementation of timeval_ms() A crisper/faster implementation under eCos that makes profiling a tad easier. Signed-off-by: Øyvind Harboe 2009-12-15 David Brownell * : more tcl/{board,target} cleanup Remove more remnants of the old "jtag_device" syntax. Don't [format "%s.cpu" $_CHIPNAME] ... it's needless complexity. Remove various non-supported "-variant" target options; they're not needed often at all. Flag some of the board files as needing to have and use target files for the TAP and target declarations. Signed-off-by: David Brownell 2009-12-14 David Brownell * : XScale: use all-ones for BYPASS, not five-ones PXA3xx has more than five bits in IR. Signed-off-by: David Brownell 2009-12-15 Øyvind Harboe * : zy1000: keep up with command.h cleanup Signed-off-by: Øyvind Harboe 2009-12-15 Øyvind Harboe * : imx31: move srst delay into config script reset init/run now works again. Signed-off-by: Øyvind Harboe 2009-12-14 David Brownell * : ARM: disassemble STM correctly There is no "STMMIDA" instruction. There is however "STMDAMI". Signed-off-by: David Brownell 2009-12-14 Yegor Yefremov * : Common target file for Stellaris chips Common target.cfg file for LM3S CPU family [dbrownell@users.sourceforge.net: rename, generalize more] Signed-off-by: Yegor Yefremov Signed-off-by: David Brownell 2009-12-14 David Brownell * : jtag: add '-ignore-version' option Add a "-ignore-version" to "jtag newtap" which makes the IDCODE comparison logic optionally ignore version differences. Update the "scan_chain" command to illustrate this by showing the "*" character instead of the (ignored) version nibble. Signed-off-by: David Brownell 2009-12-13 David Brownell * : target: further shrink Jim-awareness Don't include from target.h ... not everything which touches targets needs to be able to talk to Jim. Plus, most files include this header by another path. Also, switch the affected files to use the classic sequence for #included files: all first, then the "local_headers.h". This helps prevent growth of problematic layering, by minimizing entanglement. Signed-off-by: David Brownell 2009-12-11 David Brownell * : ARM11: avoid pointless status returns For some routines that only returned ERROR_OK and where the caller never checked ... don't bother. Remove some noise, and bugfix some comments. Signed-off-by: David Brownell 2009-12-11 Zachary T Welch * : fix 'write_image' usage information The 'flash write_image' command erroneously listed the bank number, when it actually uses target addresses to do that lookup for the user. 2009-12-11 David Brownell * : ARM: disassembly fixes for LDC/STC/MRRC/MCRR Properly detect all of these, including the "2" variants; and bugfix parameter display for LDC and STC. Signed-off-by: David Brownell 2009-12-10 Spencer Oliver * : server: add server_preinit which is called before config file is parsed. This fixes the issue under native win32 of the socket interface not being enabled (via WSAStartup) before init is called from a script. Signed-off-by: Spencer Oliver 2009-12-10 Øyvind Harboe * : gdb_server: use more local variables in inner loop of fetching packetstiny refactoring to allow optimisation of inner loops Some profiling information for arm7 16MHz GDB load operation shows gdb_get_packet_inner() near the very top. Each sample counts as 0.01 seconds. % cumulative self self total time seconds seconds calls Ts/call Ts/call name 52.91 2.27 2.27 embeddedice_write_dcc 11.89 2.78 0.51 gdb_get_packet_inner 8.86 3.16 0.38 memcpy 3.26 3.30 0.14 idle_thread_main(unsigned int) 3.03 3.43 0.13 cyg_in_cksum Signed-off-by: Øyvind Harboe 2009-12-10 Øyvind Harboe * : optimisation: tiny optimisation for embedded ice use two shift operations instead of three to set embedded ice register. Signed-off-by: Øyvind Harboe 2009-12-10 David Brownell * : anotyer cygwin compile fix Signed-off-by: David Brownell 2009-12-09 David Brownell * : ARM: update arm_opcodes.h copyright I neglected to copy Magnus' copyright when I moved several declarations from the ARMv7-M header. Signed-off-by: David Brownell 2009-12-09 David Brownell * : Comment and doxygen fixes Signed-off-by: David Brownell 2009-12-08 Rafael Campos Las Heras * : Fix compilation error with gcc 4.4.1 Signed-off-by: Rafael Campos Las Heras 2009-12-08 David Brownell * : target: remove needless "extern"s Most of these happened to be in the target.h file. Some of those are associated with symbols that could be removed at some point ... e.g. NVP_ASSERT/true and its sibling NVP_DEASSERT/false. Signed-off-by: David Brownell 2009-12-08 David Brownell * : ARM: cygwin complile fixes It's as if despite integers being 32-bits, GCC refuses to convert a "uint32_t" to one of them. Signed-off-by: David Brownell 2009-12-04 Øyvind Harboe * : minidriver: fix inline capability of minidriver Low latency low CPU processing power systems(embedded) will benefit greatly from being able to inline certain jtag_add_xxx() fn's. The trick is that this has to be done in such a way as to allow implementing an OpenOCD API with a shared library(eventually) on a PC hosted OpenOCD. Signed-off-by: Øyvind Harboe 2009-12-05 Øyvind Harboe * : build: add build/src to include path This allows including generated include files. Signed-off-by: Øyvind Harboe 2009-12-07 David Brownell * : ARM: list number of HW breakpoints/watchpoints When starting up, say how many hardware breakpoints and watchpoints are available on various targets. This makes it easier to tell GDB how many of those resources exist. Its remote protocol currently has no way to ask OpenOCD for that information, so it must configured by hand (or not at all). Update the docs to mention this; remove obsolete "don't do this" info. Presentation of GDB setup information is still a mess, but at least it calls out the three components that need setup. Signed-off-by: David Brownell 2009-12-07 David Brownell * : ARM: don't clone arm_arch_state() code Have various ARM cores delegate to arm_arch_state() to display basic information, instead of duplicating that logic. This shrinks the code, makes them all report when semihosting is active, and highlights which data are specific to this core. (Like ARM720 not having separate instruction and data caches.) Signed-off-by: David Brownell 2009-12-07 David Brownell * : ARM: use not armv4_5.h Move most declarations in to and update users. What's left in the older file is stuff that I think should be removed ... the old register cache access stuff, which makes it awkward to support microcontroller profile (Cortex-M) cores. The armv4_5_run_algorithm() declaration was moved too, even though it's not yet as generic as it probably ought to be. Signed-off-by: David Brownell 2009-12-07 David Brownell * : ARM: move opcode macros to Move the ARM opcode macros from , and a few Thumb2 ones from , to more appropriate homes in a new file. Removed duplicate opcodes from that v7m/Thumb2 set. Protected a few macro argument references by adding missing parentheses. Tightening up some of the line lengths turned up a curious artifact: the macros for the Thumb opcodes are all 32 bits wide, not 16 bits. There's currently no explanation for why it's done that way... Signed-off-by: David Brownell 2009-12-07 David Brownell * : ARM: disassemble two more v6+ instructions The SRS and RFE instructions speed exception entry/exit by making it easy to save and restore PC and SPSR. This handles both ARM and Thumb2 encodings. Fix minor PLD goofage; that "should never reach this point" can't happen, so remove it. Signed-off-by: David Brownell 2009-12-07 David Brownell * : OMAP2420: define reset-assert event Behave like OMAP3530: force global software reset. Given the patch to teach ARM11 how to use these events, and use VCR to catch the reset vector, this works better than either the current reset logic or than using SRST. Signed-off-by: David Brownell 2009-12-06 Zachary T Welch * : add 'flash list', rewrite 'flash banks' Rename the existing 'flash banks' implementation as 'flash list', and replace the broken 'flash_banks' TCL wrapper with a new command handler. Adds documentation for the new 'flash list' command in the user guide. 2009-12-06 Zachary T Welch * : fix NOR flash regression When factoring the bank setup command into flash_bank_add(), I forgot to include a call to the new helper. 2009-12-05 Mathias Kuester * : NOR: add 29LV400BC flash device Signed-off-by: David Brownell 2009-12-05 Nicolas Pitre * : ARM semihosting: work with both low and high vectors Signed-off-by: Nicolas Pitre Signed-off-by: David Brownell 2009-12-04 Zachary T Welch * : move remaining nand helper files Move remaining NAND implementation files into src/flash/nand/. 2009-12-04 Zachary T Welch * : split NAND driver handling into nand/driver.[ch] This work parallels the NOR directory, encapsulating the NAND drivers into a separate file. This takes an extra step by encapsulating the type of data structure used to manage the drivers, allowing it to be changed from an array to a dynamic list in the future. 2009-12-04 David Brownell * : ARM: rename armv4_5_build_reg_cache() as arm_*() Signed-off-by: David Brownell 2009-12-04 David Brownell * : ARM: misc generic cleanup Remove an undesirable use of the CPSR symbol ... it needs to vanish. Flag mode-to-number stuff as obsolete; say why ... should also vanish. Get rid of no-longer-used mode and state typedefs. Comment a few of the implicit ties to "classic ARM". Signed-off-by: David Brownell 2009-12-04 David Brownell * : ARM: switch target_to_armv4_5() to target_to_arm() And remove that old symbol. Signed-off-by: David Brownell 2009-12-04 David Brownell * : ARM: rename armv4_5_mode_* AS arm_mode_* Signed-off-by: David Brownell 2009-12-04 David Brownell * : ARM: rename ARMV4_5_STATE_* as ARM_STATE_* Signed-off-by: David Brownell 2009-12-04 David Brownell * : ARM11: basic watchpoint support Use the DPM watchpoint support; remove old incomplete stubs. Signed-off-by: David Brownell 2009-12-04 Zachary T Welch * : reorder build order of src directory Descend into the library modules in order, from bottom-to-top. 2009-12-04 Zachary T Welch * : split flash.h into into flash/nor/*.h Move the bulk of the flash.h file into flash/nor/core.h, leaving an empty husk that will be removed in the next patch. The NOR driver structure is an implementation detail, so move it into its own private header file along with helper declaration for finding them by name. 2009-12-04 Zachary T Welch * : split NOR and NAND flash headers Moves common flash errors to to decouple these two mostly unrelated trees of code. 2009-12-04 Zachary T Welch * : add flash/nor/drivers.c Encapsulates access to the flash_drivers array, providing a base of operations for future dynamic driver module loading features. 2009-12-04 David Brownell * : ARM: semihosting entry cleanup Clean up arm_semihosting() entry a bit, comment some issues and just which SVC opcodes are getting intercepted. Microcontroller profile cores will need a new entry, since they use BKPT instead (and don't have either SVC mode or an SPSR register). Signed-off-by: David Brownell 2009-12-04 David Brownell * : User's Guide: more semihosting info List it in the concept index, in the section about target software changes a project might want to consider, and in the section about debug messaging. Signed-off-by: David Brownell 2009-12-03 Zachary T Welch * : add flash/nor/core.[ch] The newly moved flash TCL routines access the internals of the module too much. Fix the layering issues by adding new core NOR flash APIs: : - flash_driver_find_by_name() - self-descriptive : - flash_bank_add() - encapsulates adding banks to bank list - flash_bank_list() - encapsulates retreiving bank list This allows the externs in flash/nor/imp.h to be removed, and these mechanisms may now be re-used by other flash module code. 2009-12-03 Zachary T Welch * : separate Jim from jtag/core.c After previous efforts, only one Jim routine remained in jtag/core.c, and moving it to jtag/tcl.c painlessly finishes separating these layers. The headers need separating, but the implementation is clean. 2009-12-03 Zachary T Welch * : check top-level command registrations When calling module_register_commands, the return value needs to be checked for failures. Instead of duplicating code, use an array of function pointers to the identical registration functions to iterate over during startup. 2009-12-04 David Brownell * : target: cygwin build fixes Signed-off-by: David Brownell 2009-12-03 Nicolas Pitre * : basic ARM semihosting support Semihosting enables code running on an ARM target to use the I/O facilities on the host computer. The target application must be linked against a library that forwards operation requests by using the SVC instruction that is trapped at the Supervisor Call vector by the debugger. The "hosted" library version provided with CodeSourcery's Sourcery G++ Lite for ARM EABI is one example. This is currently available for ARM9 processors, but any ARM variant should be able to support this with little additional work. Tested using binaries compiled with Sourcery G++ Lite 2009q1-161 and ARM RVCT 3.0. [dbrownell@users.sourceforge.net: doc tweaks, NEWS] Signed-off-by: Nicolas Pitre Signed-off-by: David Brownell 2009-11-16 Dean Glazeski * : Make ARM NAND I/O operations aware of last op Updates the ARM NAND I/O code to look at and update the op field of arm_nand_data to reflect the last operation performed. It uses this field to copy the correct code to the target in the case where the struct is used for reads and writes. Signed-off-by: David Brownell 2009-11-20 Dean Glazeski * : NAND page command refactoring. Created a new function that handles sending a command and the address information for pages to a NAND device. [dbrownell@users.sourceforge.net: tweaked line lengths, name 'oob_only'] Signed-off-by: David Brownell 2009-12-03 David Brownell * : ARM DPM: share debug reason logic No point in both ARM11 and Cortex-A8 having private copies of the logic sorting out e.g. DBG_REASON_WATCHPOINT. Add and use a shared routine for this ... there's actually a bunch more debug entry logic that could be shared, this is just a start on that. Note that this routine fixes a bug observed in the ARM11 code, where some abort mode quirks were displayed as being an unknown debug reason; and also silences needless ARM11 chatter. Likewise with private copies of DSCR ... add one to the DPM struct. Save it as part of setting DBG_REASON_* so later patches can switch over to using that copy. Signed-off-by: David Brownell 2009-12-03 David Brownell * : ARM DPM: make DSCR bit defs sharable Move the symbols for these bits from "armv7a.h" to "arm_dpm.h", where they can be seen and used not just by Cortex-A but also by the ARM11 (armv6) code. Change them from bit numbers to bit masks ... this matches the usage in ARM11 code, and also makes it easier to read. Rename DSCR_EXT_INT_EN as DSCR_ITR_EN to match the docs; it's enabling ITR functionality, not external interrupts, so this changes the name to be less misleading. (There *IS* a bit affecting interrupts, and this isn't it.) Signed-off-by: David Brownell 2009-12-03 Zachary T Welch * : fix double 'init' regression To prevent regression in the behavior of 'init', we allow it to run in any mode. If provided with -c init and with -c noinit, then the second init at startup caused a spurious mode failure. Let 'init' handle it. 2009-12-03 Øyvind Harboe * : zy1000: include files have moved about now compiles again after include files were moved about to reduce -I usage and stop using quotes but rather angle brackets for include files. Signed-off-by: Øyvind Harboe 2009-12-03 Zachary T Welch * : change #include "../hello.h" to "hello.h" Before we can -I the top-level src/ directory alone, references to "hello.h" must be updated. This is an internal header, so it does not need angle brackets. 2009-12-03 Zachary T Welch * : change #include "svf.h" to Changes from the flat namespace to heirarchical one. Instead of writing: #include "svf.h" the following form should be used. #include The exception is from .c files in the same directory. 2009-12-03 Zachary T Welch * : change #include "telnet_server.h" to Changes from the flat namespace to heirarchical one. Instead of writing: #include "telnet_server.h" the following form should be used. #include The exception is from .c files in the same directory. 2009-12-03 Zachary T Welch * : change #include "httpd.h" to Changes from the flat namespace to heirarchical one. Instead of writing: #include "httpd.h" the following form should be used. #include The exception is from .c files in the same directory. 2009-12-03 Zachary T Welch * : change #include "s3c24xx_regs.h" to Changes from the flat namespace to heirarchical one. Instead of writing: #include "s3c24xx_regs.h" the following form should be used. #include The exception is from .c files in the same directory. 2009-12-03 Zachary T Welch * : change #include "nand.h" to Changes from the flat namespace to heirarchical one. Instead of writing: #include "nand.h" the following form should be used. #include The exception is from .c files in the same directory. 2009-12-03 Zachary T Welch * : change #include "flash.h" to Changes from the flat namespace to heirarchical one. Instead of writing: #include "flash.h" the following form should be used. #include The exception is from .c files in the same directory. 2009-12-03 Zachary T Welch * : change #include "trace.h" to Changes from the flat namespace to heirarchical one. Instead of writing: #include "trace.h" the following form should be used. #include The exception is from .c files in the same directory. 2009-12-03 Zachary T Welch * : change #include "target.h" to Changes from the flat namespace to heirarchical one. Instead of writing: #include "target.h" the following form should be used. #include The exception is from .c files in the same directory. 2009-12-03 Zachary T Welch * : change #include "mips_ejtag.h" to Changes from the flat namespace to heirarchical one. Instead of writing: #include "mips_ejtag.h" the following form should be used. #include The exception is from .c files in the same directory. 2009-12-03 Zachary T Welch * : change #include "mips32.h" to Changes from the flat namespace to heirarchical one. Instead of writing: #include "mips32.h" the following form should be used. #include The exception is from .c files in the same directory. 2009-12-03 Zachary T Welch * : change #include "etm.h" to Changes from the flat namespace to heirarchical one. Instead of writing: #include "etm.h" the following form should be used. #include The exception is from .c files in the same directory. 2009-12-03 Zachary T Welch * : change #include "breakpoints.h" to Changes from the flat namespace to heirarchical one. Instead of writing: #include "breakpoints.h" the following form should be used. #include The exception is from .c files in the same directory. 2009-12-03 Zachary T Welch * : change #include "armv7m.h" to Changes from the flat namespace to heirarchical one. Instead of writing: #include "armv7m.h" the following form should be used. #include The exception is from .c files in the same directory. 2009-12-03 Zachary T Welch * : change #include "armv4_5_mmu.h" to Changes from the flat namespace to heirarchical one. Instead of writing: #include "armv4_5_mmu.h" the following form should be used. #include The exception is from .c files in the same directory. 2009-12-03 Zachary T Welch * : change #include "armv4_5.h" to Changes from the flat namespace to heirarchical one. Instead of writing: #include "armv4_5.h" the following form should be used. #include The exception is from .c files in the same directory. 2009-12-03 Zachary T Welch * : change #include "arm_dpm.h" to Changes from the flat namespace to heirarchical one. Instead of writing: #include "arm_dpm.h" the following form should be used. #include The exception is from .c files in the same directory. 2009-12-03 Zachary T Welch * : change #include "arm9tdmi.h" to Changes from the flat namespace to heirarchical one. Instead of writing: #include "arm9tdmi.h" the following form should be used. #include The exception is from .c files in the same directory. 2009-12-03 Zachary T Welch * : change #include "arm7tdmi.h" to Changes from the flat namespace to heirarchical one. Instead of writing: #include "arm7tdmi.h" the following form should be used. #include The exception is from .c files in the same directory. 2009-12-03 Zachary T Welch * : change #include "arm11.h" to Changes from the flat namespace to heirarchical one. Instead of writing: #include "arm11.h" the following form should be used. #include The exception is from .c files in the same directory. 2009-12-03 Zachary T Welch * : change #include "minidriver.h" to Changes from the flat namespace to heirarchical one. Instead of writing: #include "minidriver.h" the following form should be used. #include The exception is from .c files in the same directory. 2009-12-03 Zachary T Welch * : change #include "interface.h" to Changes from the flat namespace to heirarchical one. Instead of writing: #include "interface.h" the following form should be used. #include The exception is from .c files in the same directory. 2009-12-03 Zachary T Welch * : change #include "types.h" to Changes from the flat namespace to heirarchical one. Instead of writing: #include "types.h" the following form should be used. #include The exception is from .c files in the same directory. 2009-12-03 Zachary T Welch * : change #include "replacements.h" to Changes from the flat namespace to heirarchical one. Instead of writing: #include "replacements.h" the following form should be used. #include The exception is from .c files in the same directory. 2009-12-03 Zachary T Welch * : change #include "log.h" to Changes from the flat namespace to heirarchical one. Instead of writing: #include "log.h" the following form should be used. #include The exception is from .c files in the same directory. 2009-12-03 Zachary T Welch * : change #include "ioutil.h" to Changes from the flat namespace to heirarchical one. Instead of writing: #include "ioutil.h" the following form should be used. #include The exception is from .c files in the same directory. 2009-12-03 Zachary T Welch * : change #include "configuration.h" to Changes from the flat namespace to heirarchical one. Instead of writing: #include "configuration.h" the following form should be used. #include The exception is from .c files in the same directory. 2009-12-03 Zachary T Welch * : change #include "binarybuffer.h" to Changes from the flat namespace to heirarchical one. Instead of writing: #include "binarybuffer.h" the following form should be used. #include The exception is from .c files in the same directory. 2009-11-28 Zachary T Welch * : change autoconf #include in configure.in Updates "system.h" and "replacements.h" with and respectively. 2009-12-03 Nicolas Pitre * : feroceon.c should be part of ARM7_9_SRC The Feroceon and Dragonite cores are similar to the ARM926 and ARM966 cores respectively. Signed-off-by: Nicolas Pitre 2009-12-02 Zachary T Welch * : move jtag drivers to src/jtag/drivers Moves JTAG interface drivers to src/jtag/drivers/, Adds src/jtag/drivers/Makefile.am. Builds libocdjtagdrivers.la. Flattens the rlink driver files into the drivers/ directory, adding the 'rlink_' prefix or '.rlink' suffix as appropriate. 2009-12-01 Zachary T Welch * : move nand drivers to src/flash/nand/ Moves NAND drivers to src/flash/nand/. Adds src/flash/nand/Makefile.am. Builds libocdflashnand.la. 2009-12-02 David Brownell * : ARM11: store a clean copy of DSCR Just store a clean copy of DSCR in the per-CPU struct, so we trivially pass a pointer to a recent copy. This replaces the previous "last_dscr" and cleans up most of the related calling conventions ... but it doesn't remove the other DSCR copy. 2009-12-02 David Brownell * : ARM11: don't expose RDTR Don't expose the RDTR register through the register cache any more. If anyone wants Tcl scripts to be able to use DCC based communication with app code in the target, this wouldn't do it. Bugfix: don't trust the Tcl-accessible version of DSCR to flag whether RDTR needs to be restored when resuming. 2009-12-02 David Brownell * : ARM11: remove arm11->target Don't need/want arm11->target; we have arm11->arm.target instead. Also remove some unused watchpoint stuff. 2009-12-02 Zachary T Welch * : fix configure problem when building w/o USB If building OpenOCD without any USB drivers, a warning would appear because $build_usb is never set to a sane default. This fixes it. 2009-12-02 Zachary T Welch * : fix 'target init' command registration The command handler registration was put at the top level, rather than as a subcommand. Move it to where it belongs. 2009-12-01 Zachary T Welch * : remove #if BUILD_HTTPD Add httpd_stubs.c to provide no-op implementations of httpd_start() and httpd_stop(). Allows these routines to be called unconditionally and ensures the libocdserver ABI remains unchanged regardless of whether this feature was built-in or not. Prints a DEBUG message when the stub implementation is included. 2009-12-01 Zachary T Welch * : remove #if logic for openocd_sleep_*lude Adds server_stubs.c to hold these routines, using automake logic to ensure it gets included under the right conditions. 2009-11-30 Zachary T Welch * : target: factor target_init() into pieces Moves body of target initialization loop into a helper function, cleaning up its visual flow in the process. 2009-11-30 Zachary T Welch * : flash: factor init to 'flash init' Split flash initialiation into 'flash init', called from 'init'. 2009-11-30 Zachary T Welch * : nand: factor init to 'nand init' Split NAND initialization into 'nand init', which gets called from the main 'init' command. 2009-12-02 David Brownell * : ARMv7a/Cortex-A8: report watchpoint trigger insn Save and display the address of the instruction which triggered the watchpoint. Because of pipelining, that's well behind the PC value when debug entry completes. (Example in a subroutine that had been returned from...) Remove unused A8 stuff, mostly watchpoint hooks from the header. Signed-off-by: David Brownell 2009-12-02 Øyvind Harboe * : zy1000: keep up with startup refactoring work. keep up with server_init() introduction. Signed-off-by: Øyvind Harboe 2009-12-01 David Brownell * : ARM: core DPM support for watchpoints This is a NOP unless the underlying core exposes two new methods, and neither of the two cores using this (ARM11xx, Cortex-A8) do so yet. This patch only updates those cores so they pass a flag saying whether or not to update breakpoint and watchpoint status before resuming; and removing some now-needless anti-segfault code from ARM11. Cortex-A8 didn't have that code ... yes, it segfaulted when setting watchpoints. NOTE: this uses a slightly different strategy for setting/clearing breakpoints than the ARM7/ARM9/etc code uses. It leaves them alone unless it's *got* to change something, to speed halt/resume cycles (including single stepping). ALSO NOTE: this under-delivers for Cortex-A8, where regions with size up to 2 GBytes can be watched ... it handles watchpoints which ARM11 can also handle (size 1/2/4 bytes). Should get fixed later. Signed-off-by: David Brownell 2009-12-01 David Brownell * : Tcl and doc: update to match new 'arm mcr ...' etc Make them match the C code. Signed-off-by: David Brownell 2009-12-01 Øyvind Harboe * : zy1000: keep up with latest changes to command handling Keep up with Jim Tcl interpreter creation cleanup. Signed-off-by: Øyvind Harboe 2009-12-01 David Brownell * : ARM11: remove previous mcr()/mrc() methods We don't need this code, now that the DPM code handles it. Signed-off-by: David Brownell 2009-12-01 David Brownell * : ARM: implement mrc()/mcr() as DPM ops Instead of having separate ARM11 and Cortex-A8 implementations of this code, have one shared implementation which just builds on the existing "run instruction via R0" support. This enables followup patches to remove that now-unused code from those two drivers. (Patches to move the "mrc" and "mcr" code into "struct arm" are due too ... MIPS and other cores do not support those ARM-specific concepts.) Signed-off-by: David Brownell 2009-12-01 David Brownell * : ARMv7-A: stop using CP15 ops The ARMv7-A code uses read_cp15() to access fault registers. Instead, use DPM operations directly, passing in the relevant MRC instructions. This eliminates per-operation overhead (though it'll be hard to observe, this is uncommon) and helps eliminate read_cp15(). Signed-off-by: David Brownell 2009-11-30 Øyvind Harboe * : main: invoke jtag_interface_quit() explicitly There is no particular reason to invoke jtag_interface_quit() on the atexit() handler, it just makes the code more obtuse and stops other legitimate usage of atexit(). Signed-off-by: Øyvind Harboe 2009-11-30 David Brownell * : XScale: restore_context() cleanup Clean up two aspects to this routine: bad naming, since it doesn't restore the context, just the banked registers; and excess indentation for the bulk of the code. Also make some of its call sites stash the function's return code; someday they should use it for error checking. Signed-off-by: David Brownell 2009-11-29 Zachary T Welch * : remove interp global variable! Finish removing references to the 'interp' global variable from the command module, encapsulating all reference via command_context. Eliminates use of the global entirely, so it can be removed. Hurrah! 2009-11-29 Zachary T Welch * : do not extern 'interp' from command.c Adds 'interp' field to command_context, chasing the few remaining references to the global variable outside of the command module. 2009-11-29 Zachary T Welch * : jtag: avoid using interp global variable Adds 'interp' field to jtag_tap_event_action structure to avoid using the global variable of same name. 2009-11-29 Zachary T Welch * : make syntax errors respond with 'usage' The 'help' text will become more verbose, so its entire text will be far more than desired when you only borked your syntax. The usage still allows the commands to be looked up for more help. 2009-11-29 Zachary T Welch * : improve command_done() API and docs command_done() does not need to return an error, but it needed Doxygen comment. Provide some for copy_command_context as well. Note: this audit revealed some potential bugs with the command context implementation. There was a reason that commands were added at the end of the list. Shallow copying of command_context means that the list is shared between them. And commands added at the top-level before the pre-existing commands will not be available in the shared context as they were before. Yikes! Fortunately, this does not seem to occur in general use, as 'add_help_text' gets registered in startup.tcl and claims the first slot in my own test cases. Thus, it seems that we have been masking the issue for now, but it shows the need for further architectural improvement in the core command module. 2009-11-29 Zachary T Welch * : allow deferal of init Adds 'noinit' command to prevent OpenOCD from running 'init' at the end up startup, allowing it to be given from telnet or TCL. This provides the old behavior by default, and users can add this command to their scripts to get the new behavior. 2009-11-28 Zachary T Welch * : improve gdb_init() sequence Rework gdb_init to create flexible APIs (gdb_target_add_{one,all}) and static helper (gdb_target_start) for starting GDB services. Eliminates duplicated code and provides general mechanisms for adding GDB services. The 'init' command is updated to call the new API, and later patches can decouple its policy of adding all targets therein. Provides the new capability to use both piped and TCP servers when multiple targets are defined. The first target fills the pipe, and others will be started on TCP ports (unless disabled, i.e. gdb_port=0). 2009-11-29 David Brownell * : XScale: clean up full_context() (#2) Streamline the loop by continuing as soon as we know there's no work to be done; this lets us un-indent almost everything. Signed-off-by: David Brownell 2009-11-29 David Brownell * : XScale: debug entry uses new register mapping Use the new mapping interfaces in the debug entry path. SPSR and the banked registers now have smaller and faster accessors ... use them. Signed-off-by: David Brownell 2009-11-29 Marek Vasut * : XScale: initial PXA3xx support [dbrownell@users.sourceforge.net: user's guide; variant param is optional] Signed-off-by: David Brownell 2009-11-28 David Brownell * : bugfix: 'init' changes state, not main() Code other than main() may invoke "init". When it does so, customized handlers may need to run ... so make sure the command context state is updated before they do so. Signed-off-by: David Brownell 2009-11-28 David Brownell * : Cortex-M3: don't chain "struct arm" commands Those commands presume support for the "classic" set of CPU modes (FIQ, supervisor, IRQ, etc) ... which aren't supported by the ARMv7-M or ARMv6-M architectures. They also presume a "struct arm" base type, which this code doesn't use. We haven't cleaned up the register handling enough to be able to share any of those "base" methods. Signed-off-by: David Brownell 2009-11-25 Zachary T Welch * : add more stub handlers to testee target Prevent everything from crashing when exercising various commands. 2009-11-25 Zachary T Welch * : split jim_target into multiple handlers The 'target' command group was implemented using its own command dispatching, which can be eliminated by using the new chained command registration mechanism. This patch splits the jim_target() function into individual handlers, which makes them to be visible to the help and usage commands. These one-trick handlers are much easier to understand. 2009-11-26 Zachary T Welch * : improve jtag_tap_configure Splits bulk of the jtag_tap_configure into jtag_tap_configure_event, removing three or four levels of indentation in the process. The resulting code was stylistically improved in other ways, but it should be functionally identical. 2009-11-26 Zachary T Welch * : begin moving JTAG jim handlers/helpers Moves the tertiary jim handlers and required static helpers to the top of tcl.c, defining them in a new registration array that is chained in both the top-level context and under the jtag command. The top-level commands can be removed at some point in the future to reduce clutter. 2009-11-28 Zachary T Welch * : remove redundant 'rm' command handler Two 'rm' commands were implemented and registered. This removes the version that would have never been called prior to refactoring the command registration. 2009-11-28 Zachary T Welch * : include mode information in help text. Extends the help output to list the valid modes for each commands. Fixes a memory leak of the returned command_name() string. 2009-11-27 Zachary T Welch * : add command private data setter/accessor Presently, commands registration taks a static handler data pointer. This patch adds support for commands that require a dynamic pointer, such as those registered in a dynamic context (e.g. subcommands for a user-created 'foo.cpu' command). The command_set_handler_data will update a command (group) to use a new context pointer, while the CMD_DATA macro allows command handlers to access the value. Jim handlers should find this value in interp->cmdPrivData. 2009-11-27 Zachary T Welch * : remove unknown handler Updates command registration to provide top-level handlers for all commands, rather than falling back onto the 'unknown' command. Instead, that same handler is registered for placeholders, providing the same functionality under the root verb command name instead. This permits users to implement their own 'unknown' function, and it resolves some mind-bending breakage related to function object lookup while recursing. Changes 'ocd_bounce' to call 'ocd_command' and 'ocd_help' from the wrapper directly, rather than bouncing through their wrappers. This prevents endless recursion caused by the above changes, whereby the 'command' wrapper's type check would blow the stack to hell and gone. 2009-11-27 Zachary T Welch * : add 'command type' introspective handler Adds the 'command' group handler, with the 'type' command producing a string that tells whether the given command is 'native' (for Jim-based command handlers), 'simple' (for simple built-in commands), 'group' for command group placeholders, and 'unknown' if not found in the command registration tables (e.g. core built-ins functions). 2009-11-28 David Brownell * : ARM11: fix dbgtap JTAG_DEBUG There is no DEBUG() macro; don't call one! Always at least *parse* debug code, to help prevent such errors. Signed-off-by: David Brownell 2009-11-28 David Brownell * : target: remove unused TARGET_EVENT_OLD_* symbols Just two *_OLD_* symbols left... Signed-off-by: David Brownell 2009-11-27 David Brownell * : omap3530.cfg: use new "reset-assert" event Replaces previous "reset-assert-pre" workaround. Signed-off-by: David Brownell 2009-11-27 David Brownell * : target: groundwork for "reset-assert" event This defines a "reset-assert" event and a supporting utility routine, and documents both how targets should implement it and how config scripts should use it. Core-specific updates are needed to make this work. Signed-off-by: David Brownell 2009-11-27 Zachary T Welch * : fix regression causing duplicated output The command refactoring caused subcommand handlers to produce duplicate output when run. The problem was introduced by failing to ensure all such invocations went through a top-level "catcher" script, prefixing the command name with the 'ocd_' prefix and consuming its results. The fix is to ensure such a top-level "catcher" script gets created for each top-level command, regardless of whether it has a handler. Indeed, this patch removes all command registrations for sub-commands, which would not have worked in the new registration scheme anyway. For now, dispatch of subcommands continues to be handled by the new 'unknown' command handler, which gets fixed here to strip the 'ocd_' prefix if searching for the top-level command name fails initially. Some Jim commands may be registered with this prefix, and that situation seems to require the current fallback approach. Otherwise, that prefix could be stripped unconditionally and the logic made a little simpler. The same problem must be handled by the 'help' command handler too, so its lookup process works as intended. Overall, the command dispatching remains more complicated than desired, but this patch fixes the immediate regressions. 2009-11-27 Zachary T Welch * : update minidummy interface driver command handling Changes the interface definition field reference from register_commands to commands, which allows the module to compile. 2009-11-27 Øyvind Harboe * : zy1000: keep up with changes to log_init() fn's and return value for log_init() changed to void. Signed-off-by: Øyvind Harboe 2009-11-16 Dean Glazeski * : ARM NAND I/O header documentation update. Fixed the header file to properly specify the doxygen documentation for the items defined in it. Signed-off-by: David Brownell 2009-11-16 Dean Glazeski * : ARM NAND I/O refactor code copying. Created a function for copying code to the working area on a target. The NAND write and read functions are updated to include use of this function. Signed-off-by: David Brownell 2009-11-17 Dean Glazeski * : NAND Flash documentation update. Updated doxygen comments for different interface structures for the NAND interface. Signed-off-by: David Brownell 2009-11-24 Uwe Hermann * : update bug reporting information The Berlios bug-tracker is disabled, bug reports go to the list. Signed-off-by: Zachary T Welch 2009-11-24 Uwe Hermann * : fix typos in source files Correct some spelling errors in source comments and printed output. Signed-off-by: Zachary T Welch 2009-11-26 Eric Wetzel * : fix 'flash protect' and 'flash erase_sector' Command upgrading introduced two off-by-one bugs in the flash commands. This patch fixes the 'flash {protect,erase_sector}' commands to check that they have been passed the correct number of arguments. Ammended during commit to fix help text for 'erase_address' too. 2009-11-25 David Brownell * : target: target_get_name() --> target_type_name() There are two names that may matter on a per-target basis. One is a per-instance name (for example, "at91sam7s.cpu"). The other is the name of its type (for example, "arm7tdmi"), which is shared among multiple targets. Currently target_get_name() returns the type name, which is misleading and is rarely appropriate for target diagnostics. Rename that as target_type_name(). Signed-off-by: David Brownell 2009-11-25 David Brownell * : ARM: minor armv4/armv5 cleanup Lines of 300+ characters are still bad; debug tweaks. Signed-off-by: David Brownell 2009-11-25 David Brownell * : ARM7/9: shrink run_algorithm_inner() lines 300+ characters is unreasonable. So is half that. Signed-off-by: David Brownell 2009-11-20 Zachary T Welch * : update NEWS with recent developments Mention changes to flash bank command syntax, 'nand verify' command, command error handling and reporting, and help/usage command upgrades. 2009-11-23 Zachary T Welch * : support OPENOCD_DEBUG_LEVEL environment setting Detect the OPENOCD_DEBUG_LEVEL setting in log_init(), allowing the very early startup phases to be debugged. 2009-11-24 Zachary T Welch * : update command handler documentation Adds sections on command registration and chaining, giving an overview to developers that want to use these features. 2009-11-21 Zachary T Welch * : improve command handling examples Removes hello and foo commands from top-level registration. Instead, the dummy interface driver and faux flash driver have been augmented to register these commands as sub-commands. 2009-11-24 Zachary T Welch * : encapsulate and re-use log capture, retval setup Factors log capture while running script commands, eliminating duplicated code between script_command and jim_capture. Factors setting a command's Jim "retval" into a new helper as well. Using these new helpers in the new unknown command handler's fixes possible regressions caused by these bits being missing. 2009-11-23 Zachary T Welch * : improve usage and help command output Rewrite formatting code in C, removing last remenants of TCL help code. Sinificantly improves the readability by using smarter indent and wrap. 2009-11-24 Zachary T Welch * : httpd: use register_commands() Updates httpd_start() to use register_commands() for 'readform' and 'writeform' commands. Adds server/httpd.h to export the new signatures for this function (and httpd_stop), which allows removing the obsoleted declarations inside openocd.c. 2009-11-23 Zachary T Welch * : refactor command_new to use command_registration Save stack space: use a struct. Makes it easier to add new parameters. 2009-11-23 Zachary T Welch * : remove target_type register_command callback Uses chaining of command_registration structures to eliminate all target_type register_callback routines. Exports the command_handler registration arrays for those target types that are used by others. 2009-11-23 Zachary T Welch * : trace: use register_commands() 2009-11-23 Zachary T Welch * : target: use register_commands() 2009-11-23 Zachary T Welch * : etm_dummy: use register_commands() 2009-11-23 Zachary T Welch * : etb: use register_commands() 2009-11-23 Zachary T Welch * : cortex_a8: use register_commands() 2009-11-23 Zachary T Welch * : armv7a: use register_commands() 2009-11-23 Zachary T Welch * : arm9tdmi: use register_commands() 2009-11-23 Zachary T Welch * : arm926ejs: use register_commands() 2009-11-23 Zachary T Welch * : arm7_9_common: use register_commands() 2009-11-23 Zachary T Welch * : arm11: use register_commands() 2009-11-22 Zachary T Welch * : remove flash_driver->register_callbacks Replace flash_driver callback with pointer to command_registration. Eliminates all related routines and allows drivers to omit commands. 2009-11-22 Zachary T Welch * : str9xpec: use register_commands() 2009-11-22 Zachary T Welch * : str7x: use register_commands() 2009-11-22 Zachary T Welch * : stellaris: use register_commands() 2009-11-22 Zachary T Welch * : nand: use register_commands() Eliminates 'nand_cmd' global variable. 2009-11-22 Zachary T Welch * : lpc3180_nand_controller: use register_commands() 2009-11-22 Zachary T Welch * : lpc2000: use register_commands() 2009-11-22 Zachary T Welch * : ecos: use register_commands() 2009-11-22 Zachary T Welch * : avrf: use register_commands() 2009-11-22 Zachary T Welch * : at91sam3: use register_commands() 2009-11-20 Zachary T Welch * : vsllink: use register_commands() Use register_commands() with command registration array. 2009-11-20 Zachary T Welch * : presto: use register_commands() Use register_commands() with command registration array. 2009-11-20 Zachary T Welch * : jlink: use register_commands() Use register_commands() with command registration array. 2009-11-20 Zachary T Welch * : ft2232: use register_commands() Use register_commands() with a command registration array. 2009-11-20 Zachary T Welch * : arm-jtag-ew: use register_commands() Uses register_commands() with command registration array. 2009-11-23 Zachary T Welch * : pld: use static registration instead of callback Remove register_callbacks from pld_device structure, using an array of command_registration records instead. 2009-11-22 Zachary T Welch * : {,x}svf: use register_commands() Use register_commands() for registering {,x}svf commands. 2009-11-20 Zachary T Welch * : log: use register_commands() Use register_commands() for logging callbacks. Improve help and add proper usage. 2009-11-20 Zachary T Welch * : openocd: use register_commands() Use register_commands() for top-level version and init command. 2009-11-21 Zachary T Welch * : hello: use register_commands() Use new register_commands() with command registration table. 2009-11-22 Zachary T Welch * : add public API for locating commands Allow other modules to find a command, primarily for the purpose of registering and unregistering subcommands. 2009-11-21 Zachary T Welch * : add command registration chaining Adds the ability to chain registration structures. Modules can define a command with the 'chain' and 'num_chain' fields defined in their registration table, and the register_commands() function will initialize these commands. If the registration record creates a new command, then the chained commands are created under it; otherwise, they are created in the same context as the other commands (i.e. the parent argument). 2009-11-20 Zachary T Welch * : command: use register_commands for handlers Use register_commands() to register low-level command handlers, adding a builtin_command_handlers declaration that is easy to understand. Splits help and usage information into their appropriate fields. 2009-11-20 Zachary T Welch * : add register_commands for batch registration The register_commands API takes multiple commands in one call, allowing modules to declare and pass a much simpler (and more explicit) array of command_registration records. 2009-11-20 Zachary T Welch * : use COMMAND_REGISTER macro Replaces direct calls to register_command() with a macro, to allow its parameters to be changed and callers updated in phases. 2009-11-21 Zachary T Welch * : improve startup tcl scripts Fix a couple of layering violations missed in the last round. Add missing comment headers. 2009-11-24 David Brownell * : Cortex-A8: hook up DPM This replaces two versions of register access functions. One was commented out, and seemed to have uncertain intent. The other was fairly new, and helped motivate the DPM framework once I observed that the ARM11 was doing the very same ops. Signed-off-by: David Brownell 2009-11-24 David Brownell * : Cortex-A8: minor cleanup Make various functions static, add some comments, report vector catch as a flavor of DBG_REASON_BREAKPOINT, get rid of needless/undesirable ARMV4_5_CORE_REG_MODE, etc. Signed-off-by: David Brownell 2009-11-24 Zachary T Welch * : fix doxygen build Update build rules to skip the PDF unless the TeX has been created. Also, fixes a warning regarding pattern rules being a GNU make trick. 2009-11-19 Zachary T Welch * : jlink: remove superfluous indentation Rewrite logic to remove indentation in jlink_usb_open, in prep for further surgery. 2009-11-19 Zachary T Welch * : rlink: eliminate spurious indentation Rework rlink_init to use less indentation. Best viewed with diff -w. 2009-11-19 Zachary T Welch * : usbprog: use jtag_usb_open Rewrite usbprob_jtag_open to use jtag_usb_open helper. 2009-11-19 Zachary T Welch * : add jtag/usb_common.[ch] files Begins to consolidate code used by several USB JTAG interfaces. This first patch provides the required build system changes and a common jtag_usb_open routine, which will replace the guts for probing the busses and devices for possible VID/PID matches. The following patches convert each driver to use it. 2009-11-24 David Brownell * : ARM11: use standard run_algorithm() As with single stepping, the previous stuff was needed because the ARM11 code wasn't using the standard ARM base type and register access ... but now those mechanisms work, so we can switch out that special-purpose glue, in favor of the more thoroughly tested/capable "standard" code. Fixes a bug in the resume() implementation: it wasn't handling two of its arguments correctly, preventing the "flash erase_check" algorithm from working. (This code needs a *subsequent* update for correct register handling, though... removing the confusion about which "r2", for example, to use.) This should resolve some "FIXME" comments too, for Thumb and processor mode support. It also gets rid of a nasty exit() call; servers should only have *clean* shutdown paths. Signed-off-by: David Brownell 2009-11-24 David Brownell * : ARM11: partial support for standard ARM register interfaces. This provides "standard" ARM register support -- with twenty or more shadow registers on top of what this code now handles, but properly associated with the various core modes -- parallel to the current register code. That is, the current code is stilil managing the "current" registers; the new code shadows them. You can see all the registers with "arm reg", modify the shadows like "r8_fiq" or "sp_abt" with "reg", and see them get properly written back when you step. (Just don't do that with any of the registers managed by the "old" code ...) It also switches to using more standard code, relying on those standard registers, in two places: (a) the poll status display, which now shows core state (ARM/Thumb/...) and mode (Supervisor, IRQ, etc); and (b) GDB register access. So it's not a full migration, there are warts -- every place that touches the old register cache is a potential bug -- but it's a small more-or-less-comprehensible step that's even somewhat useful. Later patches complete the migration. Signed-off-by: David Brownell 2009-11-24 David Brownell * : ARM11: implement provider for new DPM interface This is a very thin layer over some of the current ARM11 debug TAP utilities. The layer isn't yet hooked up. Signed-off-by: David Brownell 2009-11-24 David Brownell * : target: cope with *any* error setting a breakpoint It's wrong to map unrecognized failure codes to success. Signed-off-by: David Brownell 2009-11-23 Jerry Ling * : mips: fix gaffe when removing dynamic array allocation Classic sizeof() gaffe. Signed-off-by: Øyvind Harboe 2009-10-26 Øyvind Harboe * : arm926ejs: retire cp15 commands, handled by mrc/mcr. Signed-off-by: Øyvind Harboe 2009-11-22 David Brownell * : ARM11: macro cleanup Make this code look more like the rest of the OpenOCD code. - Use calloc() directly, not NEW() ... and fix some potential memory leaks while we're at it. - Remove FNC_INFO ... it's a NOP that just clutters things, and it's trivial for developers to add tracing as needed. - Replace FNC_INFO_NOTIMPLEMENTED with LOG_WARNING calls; ditto. And stop having those call sites wrongly succeed! - Waste less space with the CHECK_RETVAL() macro. Signed-off-by: David Brownell 2009-11-22 Øyvind Harboe * : mips: use const for code sequences This will allow data to be allocated in read only memory instead of on the stack. Speeds things up and reduces stack usage. Signed-off-by: Øyvind Harboe 2009-11-22 Øyvind Harboe * : arm926ejs: fix warnings buf_set_u32() operated on an uninitialized stack variable with non-byte boundaries, which led to warnings about reading uninitialized stack. Signed-off-by: Øyvind Harboe 2009-11-22 David Brownell * : ARM: use arm_reg_current() Start using the arm_reg_current() call. This shrinks and speeds the affected code. It can also prevent some coredumps coming from invalid CPSR values ... the ARMV4_5_CORE_REG_MODE() macro returns bogus registers if e.g. "Secure Monitor" mode isn't supported by the current CPU. Signed-off-by: David Brownell 2009-11-22 David Brownell * : target: make register flags "bool" Mostly for clarity, but it also saves code and data space. Signed-off-by: David Brownell 2009-11-22 Øyvind Harboe * : flash: dynamically allocate working storage Allocate working memory rather than using stack. Signed-off-by: Øyvind Harboe 2009-11-22 Øyvind Harboe * : todo: add tip on how to identify excessive stack usage Use dynamic allocations for working memory rather than stack. Signed-off-by: Øyvind Harboe 2009-11-21 Øyvind Harboe * : embedded: reduce stack usage Allocate working structures on stack to avoid issues with path lengths + reduce stack usage. Signed-off-by: Øyvind Harboe 2009-11-21 Øyvind Harboe * : embedded: save stack and also do not recaluate the crc32_table upon every invocation. Signed-off-by: Øyvind Harboe 2009-11-22 Øyvind Harboe * : build: fix breakage in building bin2char bin2char build relied on $(builddir) which is not defined for arm-elf X builds at least. Signed-off-by: Øyvind Harboe 2009-11-22 David Brownell * : ARM: define two register utilities Define arm_reg_current() ... returning handle to a given register, and encapsulating the current mode's register shadowing. It's got one current use, for reporting the current register set to GDB. This will let later patches clean up much ARMV4_5_CORE_REG_MODE() nastiness, saving a bit of code. Define and use arm_set_cpsr() ... initially it updates the cached CPSR and sets up state used by arm_reg_current(), plus any SPSR handle. (Later: can also set up for T and J bits.) Signed-off-by: David Brownell 2009-11-22 David Brownell * : ARM11: remove disabled register hooks Minor cleanup of ARM11 register handling: remove disabled register hooks. This should all be handled by shared code, and this stuff is just clutter. Signed-off-by: David Brownell 2009-11-21 Zachary T Welch * : allow jtag interfaces to lack commands Allow JTAG interface drivers to skip registering an register_commands callback when it will just be empty. 2009-11-20 David Brownell * : ARM: pass 'struct reg *' to register r/w routines Implementations need to access the register struct they modify; make it easier and less error-prone to identify the instance. (This removes over 10% of the ARMV4_5_CORE_REG_MODE nastiness...) Plus some minor fixes noted when making these updates: ARM7/ARM9 accessor methods should be static; don't leave CPSR wrongly marked "dirty"; note significant XScale omissions in register handling; and have armv4_5_build_reg_cache() record its result. Rename "struct armv4_5_core_reg" as "struct arm_reg"; it's used for more than those older architecture generations. Signed-off-by: David Brownell 2009-11-20 Zachary T Welch * : maintain command lists in sorted order Use insertion sort to the command link lists. The only practical effect of this is to order the output of the new 'help' command. 2009-11-20 Zachary T Welch * : provide command context during cmd_init For the startup.tcl code to use built-in commands, the context must be associated with the interpreter temporarily. This will be required to add help text. 2009-11-19 Zachary T Welch * : factor help script command into parts Creates a helper function, cmd_help, which displays the help string for a single command. Presently, it is called from the loop in help. The routine has been extended to allow indentation of command groups, so an improved help command can improve the display of information. 2009-11-19 Zachary T Welch * : change command_find helper interface Avoid requiring double pointers where a single would suffice. 2009-11-20 David Brownell * : target.cfg: TAP id for Hilscher netX 500 Based on email from "Martin Kaul ". Signed-off-by: David Brownell 2009-11-19 David Brownell * : Cortex-A8: better context restore The previous version never wrote dirty registers for non-current CPU modes ... fix that. Signed-off-by: David Brownell 2009-11-19 David Brownell * : target: create/use register_cache_invalidate() Create a generic register_cache_invalidate(), and use it to replace three all-but-identical core-specific routines: - armv4_5_invalidate_core_regs() - armv7m_invalidate_core_regs - mips32_invalidate_core_regs() too. Make cache->num_regs be unsigned, avoiding various errors. Net code shrink and simplification. Signed-off-by: David Brownell 2009-11-18 Zachary T Welch * : document new flash syntax Updates the user documentation with the new syntax for defining flash and nand banks. 2009-11-17 Zachary T Welch * : add support for naming NAND banks Requires users to name their nand banks, allowing them to be used instead of bank numbers in script commands. 2009-11-18 Zachary T Welch * : update 'flash bank' usage in scripts Sets $_FLASHNAME to "$_CHIPNAME.flash" and passes it as the first argument to 'flash bank'. 2009-11-17 Zachary T Welch * : refactor handle_flash_bank_command Move variables to point of first use, reducing their scope. Add driver_name temporary to help arguments be changed later. Eliminates the useless 'found' variable, changing the code to terminate the loop immediate and return its success. 2009-11-17 Zachary T Welch * : allow flash/nand banks commands to accept names Add get_flash_bank_by_name (and get_nand_device_by_name) helpers to retrieves struct flash_bank * (struct nand_device *) given a driver name and an (optional) driver-specific bank index. These are used to extend flash_command_get_bank_by_num (and nand_command_get_device_by_num) to allow all flash (nand) commands to reference defined banks by name, not just by number. To avoid some code duplication, add the flash/common.[ch] files to hold functionality common to both types driver. The first two methods are helpers for the above routines to find a bank specified by a "name" or "name.index" string. get_flash_name_index() finds the '.index' portion, while flash_driver_name_matches() performs the string portion matching. 2009-11-19 David Brownell * : ARM: streamline register init Combine register names with other per-register data into a single template structure. This saves space, and makes it easier to change how registers get handled (by shrinking the number of places that care about cache indices). Signed-off-by: David Brownell 2009-11-18 Dean Glazeski * : nand_fileio_parse_args parses wrong param for size This changes the size parameter from argv[2] to argv[3], which is what it's supposed to be. Signed-off-by: Zachary T Welch 2009-11-19 David Brownell * : ARMv7-A: use standard ARM core_mode symbols The only way ARMv7-A modes differ from ARMv4/ARMv5 flavors is that v7-A is allowed to include "Secure monitor" support. That's now handled by our standard top-level ARM code ... so phase out the stuff that's specific to ARMv7-A. Signed-off-by: David Brownell 2009-11-18 Zachary T Welch * : remove fast command and jim_global_long Removing the fast command eliminates the fast_and_dangerous global, which was used only by arm7_9_common as an initializer. The command is not called in the tree; instead, more explicit commands are used. The jim_global_long function was not used anywhere in the tree. 2009-11-18 Zachary T Welch * : change all bool parsers to accept any value This patch changes the behavior of all boolean parsing callers to accept any one of "true/enable/on/yes/1" or "false/disable/off/no/0". Since one particular pair will be most appropriate in any given situation, the specific macros should continue to be used in order to display the most informative error messages possible. 2009-11-18 Zachary T Welch * : use COMMAND_PARSE_ENABLE macro where appropriate Updates all command parsing of simple "enable" and "disable" arguments. A few case in the tree use a tri-state or extended arguments, which cannot use this simple macro. Simlifies the xscale icache/dcache command handler logic. 2009-11-18 Zachary T Welch * : add COMMAND_PARSE_BOOL macro and friends Adds several macros similar to COMMAND_PARSE_NUMBER, but for parsing boolean command arguments. Two flavors are provided to provide drop-in compatibility with existing code, allow for the elimination of a lot of code bloat while improving the error checking and reporting. COMMAND_PARSE_ON_OFF parses "on"/"off" command parameters. COMMAND_PARSE_ENABLE parses "enable"/"disable" command parameters. Both print the error and return an error out of the calling function. 2009-11-18 David Brownell * : Cortex-A8: xPSR handling updates When we read the CPSR on debug entry, update the CPSR cache in all cases, not just when the current processor state is User or System. Plus minor cleanup of how the (too-many) other registers' cache entries get updated. Signed-off-by: David Brownell 2009-11-18 David Brownell * : ARM: simplify ARMv7-A register handling ARMv7-A doesn't need to duplicate all the standard ARM code for register handling. - Switch Cortex-A8 to use the standard register code - Remove duplicated infrastructure from ARMv7-A - Have ARMv7-A arch_state() show CPSR, like other ARMs Add comments to show where the Cortex-A8 isn't actually doing the right thing for register reads/writes, unless core happens to be in the right mode to start with. (Looks like maybe there may be generic confusion between saved/current PSR values in all the ARM code ...) Make related ARMv7-A and Cortex-A8 symbols properly static. Signed-off-by: David Brownell 2009-11-18 David Brownell * : ARM: add "core_type" field to "struct arm" It's used to flag cores with the "TrustZone" extension, and is used in subsequent patches to set up support for the registers shadowed by its new secure monitor mode. The ARM1176 and Cortex-A8 both support this new mode. Signed-off-by: David Brownell 2009-11-17 Zachary T Welch * : pass startup_tcl to command_init Removes external linkage from helper module, making the startup code a parameter to a new command context's initialization routine. 2009-11-17 Zachary T Welch * : move startup.c to libopenocd Moves the creation of startup_tcl.c from src/helper/ to src/. Prepares to split the startup.tcl file into its per-module parts. 2009-11-17 Øyvind Harboe * : jtag-api: get rid of unecessary buf_set_u23() that make code obtuse. Also, this is on the path to increasing the word size for bit vectors from 8 to something wider(32? natural host machine width?) Signed-off-by: Øyvind Harboe 2009-11-17 David Brownell * : ARM: add arm_mode_name() Add and use arm_mode_name() to map from PSR bits to user meaningful names. It uses a new table which, later, can be used to hold other mode-coupled data. Add definitions for the "Secure Monitor" mode, as seen on some ARM11 cores (like ARM1176) and on Cortex-A8. The previous mode name scheme didn't understand that mode. Remove the old mechanism ... there were two copies, caused by Cortex-A8 needing to add "Secure Monitor" mode support. Signed-off-by: David Brownell 2009-11-17 Zachary T Welch * : allow documentation to be configured Add --disable-doxygen-html and --enable-doxygen-pdf options to the configure script, allowing user to change the defaults. These update the proess of munging the Doxygen configuration file to use the settings thusly provided. Add options in README. 2009-11-17 Zachary T Welch * : update command_handler documentation Improve the developer manual and primer sections which talk about writing command handlers. Notably, it documents the new CMD_* macros. 2009-11-16 Zachary T Welch * : add CMD_NAME variable in command_invocation Update CMD_NAME from its migratory home in CMD_ARGV[-1] to cmd->name. Allows CMD_ARGV++ idiom to be used safely in command handlers. 2009-11-15 Zachary T Welch * : command_handler: change 'cmd_ctx' to CMD_CTX Convert all command handler 'cmd_ctx' parameter usage with CMD_CTX. 2009-11-15 Zachary T Welch * : command_handler: change to 'argc' to CMD_ARGC This patch converts all instances of 'argc' in COMMAND_HANDLER routines to use CMD_ARGC. 2009-11-17 David Brownell * : target: simplify register get/set ops No need to indirect from registered integers to pointers. Just stash the pointers directly in the register struct, and don't even bother registering. This is a small code shrink, speeds register access just a smidgeon, and gets rid of another rude exit() path. Signed-off-by: David Brownell 2009-11-17 Øyvind Harboe * : zy1000: revC UART forwarding Name of serial device differs between revB/C. Signed-off-by: Øyvind Harboe 2009-11-12 Øyvind Harboe * : zy1000: fix bug when running on non-arm CPU Shifting by more than 32 is undefined for 32 bit integers according to the C standard. Robust solution is conditional code. Signed-off-by: Øyvind Harboe 2009-11-17 David Brownell * : ARM9TDMI: remove now-needless "struct arm9tdmi" And move the rest of the vector_catch stuff into the C file; it's not part of the module interface. Signed-off-by: David Brownell 2009-11-17 David Brownell * : target: remove some more duplicate includes Signed-off-by: David Brownell 2009-11-16 David Brownell * : Cortex-A8: no exit() calls, add missing v7-A init Eventually there should be a v7a init routine, but for now all that is inlined here. Signed-off-by: David Brownell 2009-11-16 David Brownell * : MIPS: no exit() calls Signed-off-by: David Brownell 2009-11-16 David Brownell * : ARMv4/ARMv5: no exit() calls Signed-off-by: David Brownell 2009-11-16 David Brownell * : Cortex-M3: don't exit() Get rid of undesirable and needless exit() calls from the Cortex-M3 support. Signed-off-by: David Brownell 2009-11-16 David Brownell * : ARM11: register (most) standard ARM commands Have ARM11 register the "standard" ARM commands. For now, only disassembly really works. Signed-off-by: David Brownell 2009-11-16 David Brownell * : JTAG: fix autoprobe failure. Fix bug noted by Øyvind: terminate the IR length autoscan when the IR is too long, or otherwise broken. Signed-off-by: David Brownell 2009-11-13 Zachary T Welch * : struct fileio: improve member types Add const keyword to file url and cast to free(). Make size an ssize_t and chase all format strings that use it. 2009-11-15 Zachary T Welch * : use Jim_CmdProc in jim_register The jim_register command just needed to use the type defined by jim.h. 2009-11-15 Zachary T Welch * : make command line options const The getopt_long call allows a const struct option, so mark ours const too. 2009-11-16 David Brownell * : target: don't include "log.h" from "armv4_5.h" No point in multiple includes, and that file doesn't use its functions any more. Signed-off-by: David Brownell 2009-11-16 David Brownell * : JTAG: no LOG_WARNING() for taps without IDCODE Signed-off-by: David Brownell 2009-11-16 David Brownell * : "types.h" doxygen fix Signed-off-by: David Brownell 2009-11-16 Zachary T Welch * : move ARRAY_SIZE macro to types.h The ARRAY_SIZE macro was defined in several target files, so move it to types.h. This patch also removes two other identical macros: DIM (from jtag.h) and asizeof (from arm11.h). 2009-11-16 Zachary T Welch * : remove TAP_SCAN_BYTES macro Use DIV_ROUND_UP(n, 8) instead of TAP_SCAN_BYTES macro. 2009-11-16 Zachary T Welch * : move container_of to types.h The container_of macro is useful as a general solution. It belongs in types.h, rather than target.h where it was introduced. Requires the offsetof macro, which comes from (moved as well). 2009-11-15 Zachary T Welch * : flash_command_get_bank_by_num: make COMMAND_HELPER Use COMMAND_HELPER macro to declare flash_command_get_bank_by_num. This is required for COMMAND_PARSE_NUMBER macro. 2009-11-07 Zachary T Welch * : Add 'nand verify' command Add the 'nand verify' command to perform a dump and fake-write simultaneously, checking the read bits against those generated by the write process. Appropriate user documentation for this command has been added to the user guide as well. The algorithm presently makes a relatively naive comparison. Some chips that use ECC may not verify correctly using this implementation, but the new documentation provides details about this limitation. 2009-11-05 Zachary T Welch * : Use nand_fileio_* in write/dump commands. This patch eliminates duplicated code in the the NAND 'dump' and 'write' by using the new static helper functions. These changes also fix a possible memory leak in nand dump command, in the case that the dump file failed to open. Overall, the changes should be functionally equivalent, but the resulting code will be easier to improve and extend further. 2009-11-16 Zachary T Welch * : binarybuffer: add API documentation Adds Doxygen documentation for a number of the binarybuffer APIs, including "unexpected" behavior exposed during review on the list. 2009-11-14 Zachary T Welch * : improve buf_set_buf helper Use void * and unsigned types for buffer and their sizes. Allows it to be used with more than uint8_t * without casts. 2009-11-14 Zachary T Welch * : improve buf_cpy helper Use memcpy for bulk of copy, improve final byte handling. Improve types by using void * for buffers and unsigned for size. 2009-11-14 Zachary T Welch * : improve str_to_buf and buf_to_str helpers Improve types: use void * and unsigned. Move all variables to point of first use. Move radix guessing logic to new str_radix_guess helper. 2009-11-14 Zachary T Welch * : binarybuffer: fix whitespace related issues Add inter-operator whitespace. Improve existing documentation. 2009-11-16 David Brownell * : target: no implicit #includes of "register.h" Same deal: "register.h" got needlessly included all over the place because of being in a few widely included headers. So take it out of the header files which included it, and put it in files which use it ... reduce needless interdependencies. Also, don't need that extra "types.h" inclusion. Signed-off-by: David Brownell 2009-11-16 David Brownell * : target: don't implicitly include "algorithm.h" Most files in the tree seem to have ended up including this, and *quite* needlessly ... only code implementing or using downloadable algorithms actually needs these declarations. So take it out of the header files which included it, and put it in files which use it ... reduce needless interdependencies. Also: "algorithm.h" doesn't need to include "types.h" again; it already comes from a different header. Signed-off-by: David Brownell 2009-11-15 David Brownell * : ARM11: use now-generic memory utils Now the ARM11 cores can use the renamed arm_checksum_memory() and arm_blank_check_memory() routines ... do so. Sanity checked with "flash erase_check" of both NOR banks on an OMAP2420 ... the algorithm code dumped four lines of of "poll" status after each of almost 520 blocks (yes, *very* annoying) but gave plausible results after producing that spam. Signed-off-by: David Brownell 2009-11-15 David Brownell * : ARM: memory utils aren't ARM7/ARM9 dependent The arm7_9_checksum_memory() and arm7_9_blank_check_memory() routines are not actually specific to the ARM7 and ARM9 core generations ... they can work for any core which can run algorithms using basic ARM (not Thumb) instructions. Rename them; move the declarations to a more generic site; likewise move the code (and tidy it a bit in the process). NOTE: the blank_check() method falsely returned a success status (0) on one error path, when the algorithm failed. Fixed this bug. Signed-off-by: David Brownell 2009-11-15 Zachary T Welch * : arm-jtag-ew,jlink: switch to COMMAND_HANDLER These drivers were overlooked during the recent upgrade. Convert them, moving their registration routines to eliminate their declarations. 2009-11-14 Zachary T Welch * : remove unused arm_jtag_buf_to_* helpers Removes unused arm_jtag_buf_* helpers from arm_jtag.[ch]. These could reappear if patches are provided to conver the tree to use them, but this code should not be in the master tree until that series is ready. 2009-11-14 Zachary T Welch * : struct scan_field_s -> struct scan_field Remove obsolete suffix from struct scan_field. Somehow, these definitions did not get updated but did not cause any errors. 2009-11-14 David Brownell * : lpc2900.h -- remove from Makefile.am too Signed-off-by: David Brownell 2009-11-14 David Brownell * : remove annoying $URL$ startup message It's completely unused; the obnoxious "DANGER!!!" comments don't even explain what it was doing (shorthand SVN magic). Signed-off-by: David Brownell 2009-11-14 Zachary T Welch * : add openocd.h for top-level declarations Create src/openocd.h to hold declarations previously made internally by src/main.c and src/server/server.c. This ensures all functions are verified to be in-sync at compile time (rather than at link), making it easier to track down bugs. 2009-11-13 David Brownell * : ARM11: ETM + ETB support Kick in ETM (and ETB) support for ARM11. Tested on OMAP 2420, so update that configuration. (That's an ARM1136ejs, ETB, OpenGL ES1.1, C55x DSP, etc.) Also update the other ARM11 ETM + ETB targets in the tree to set up these modules. (Not tested.) Signed-off-by: David Brownell 2009-11-13 David Brownell * : iMX2* + ETB targets: hook up ETM and ETB ARM9 cores with an ETB will have a matching ETM. Hook them both up by default. Signed-off-by: David Brownell 2009-11-13 David Brownell * : ETM: simplify ETM initialization code paths Return NULL from etm_build_reg_cache() not ERROR_OK; and share code on that fault path. Let ETM code handle any tracking of its cache -- not callers. Signed-off-by: David Brownell 2009-11-13 David Brownell * : target: remove unused "bitfield" infrastructure We have too many different registers, and too many version and context dependent interpretations, for this type of bitfield management to be scalable. (Anyone who really wants bitfield interpretation *can* do that in Tcl code...) There are ... quite a few copies of the same ARM dummy registers. There should eventually be one copy; this many is craziness. Signed-off-by: David Brownell 2009-11-13 David Brownell * : ARM7/9: rm arm7_9_get_arch_pointers() Remove the last external user of arm7_9_get_arch_pointers(), and that annoying downcast utility. Add an is_arm7_9() predicate. Stop returning specious success codes on various failure paths in the ARM7/ARM9 commands which used that downcast utility. Signed-off-by: David Brownell 2009-11-13 Zachary T Welch * : command_t -> struct command Remove misleading typedef and redundant suffix from struct command. 2009-11-13 Zachary T Welch * : remove rlink structure typedefs Remove useless typedefs from the rlink driver. Improve whitespace. 2009-11-13 Zachary T Welch * : nand_device_t -> struct nand_device Remove misleading typedef and redundant suffix from struct nand_device. 2009-11-13 Zachary T Welch * : reg_t -> struct reg Remove misleading typedef and redundant suffix from struct reg. 2009-11-13 Zachary T Welch * : improve mips32_pracc_context Use struct mips32_pracc_context instead of a typedef. 2009-11-13 Zachary T Welch * : armv4_5_common_t -> struct arm Remove misleading typedef and just use struct arm. 2009-11-13 Zachary T Welch * : etb_t -> struct etb Remove misleading typedef and redundant suffix from struct etb. 2009-11-13 Zachary T Welch * : image_elf_t -> struct image_elf Remove misleading typedef and redundant suffix from struct image_elf. 2009-11-13 Zachary T Welch * : cortex_m3_fp_comparator_t -> struct cortex_m3_fp_comparator Remove misleading typedef and redundant suffix from struct cortex_m3_fp_comparator. 2009-11-13 Zachary T Welch * : cortex_a8_brp_t -> struct cortex_a8_brp Remove misleading typedef and redundant suffix from struct cortex_a8_brp. 2009-11-13 Zachary T Welch * : xscale_trace_t -> struct xscale_trace Remove misleading typedef and redundant suffix from struct xscale_trace. 2009-11-13 Zachary T Welch * : target_event_action_t -> struct target_event_action Remove misleading typedef and redundant suffix from struct target_event_action. 2009-11-13 Zachary T Welch * : arm9tdmi_vector_t -> struct arm9tdmi_vector Remove misleading typedef and redundant suffix from struct arm9tdmi_vector. Renames enum arm9tdmi_vector as enum arm9tdmi_vector_bit. 2009-11-13 Zachary T Welch * : xscale_common_t -> struct xscale_common Remove misleading typedef and redundant suffix from struct xscale_common. 2009-11-13 Zachary T Welch * : trace_point_t -> struct trace_point Remove misleading typedef and redundant suffix from struct trace_point. 2009-11-13 Zachary T Welch * : target_timer_callback_t -> struct target_timer_callback Remove misleading typedef and redundant suffix from struct target_timer_callback. 2009-11-13 Zachary T Welch * : working_area_t -> struct working_area Remove misleading typedef and redundant suffix from struct working_area. 2009-11-13 Zachary T Welch * : reg_cache_t -> struct reg_cache Remove misleading typedef and redundant suffix from struct reg_cache. 2009-11-13 Zachary T Welch * : oocd_trace_t -> struct oocd_trace Remove misleading typedef and redundant suffix from struct oocd_trace. 2009-11-13 Zachary T Welch * : mips_ejtag_t -> struct mips_ejtag Remove misleading typedef and redundant suffix from struct mips_ejtag. 2009-11-13 Zachary T Welch * : mips32_common_t -> struct mips32_common Remove misleading typedef and redundant suffix from struct mips32_common. 2009-11-13 Zachary T Welch * : image_mot_t -> struct image_mot Remove misleading typedef and redundant suffix from struct image_mot. 2009-11-13 Zachary T Welch * : image_ihex_t -> struct image_ihex Remove misleading typedef and redundant suffix from struct image_ihex. 2009-11-13 Zachary T Welch * : image_section_t -> struct image_section Remove misleading typedef and redundant suffix from struct image_section. 2009-11-13 Zachary T Welch * : etm_capture_driver_t -> struct etm_capture_driver Remove misleading typedef and redundant suffix from struct etm_capture_driver. 2009-11-13 Zachary T Welch * : etb_reg_t -> struct etb_reg Remove misleading typedef and redundant suffix from struct etb_reg. 2009-11-13 Zachary T Welch * : cortex_m3_common_t -> struct cortex_m3_common Remove misleading typedef and redundant suffix from struct cortex_m3_common. 2009-11-13 Zachary T Welch * : watchpoint_t -> struct watchpoint Remove misleading typedef and redundant suffix from struct watchpoint. 2009-11-13 Zachary T Welch * : mcu_jtag_t -> struct mcu_jtag Remove misleading typedef and redundant suffix from struct mcu_jtag. 2009-11-13 Zachary T Welch * : armv7m_algorithm_t -> struct armv7m_algorithm Remove misleading typedef and redundant suffix from struct armv7m_algorithm. 2009-11-13 Zachary T Welch * : armv7a_core_reg_t -> struct armv7a_core_reg Remove misleading typedef and redundant suffix from struct armv7a_core_reg. 2009-11-13 Zachary T Welch * : armv7a_common_t -> struct armv7a_common Remove misleading typedef and redundant suffix from struct armv7a_common. 2009-11-13 Zachary T Welch * : armv4_5_cache_common_t -> struct armv4_5_cache_common Remove misleading typedef and redundant suffix from struct armv4_5_cache_common. 2009-11-13 Zachary T Welch * : armv4_5_core_reg_t -> struct armv4_5_core_reg Remove misleading typedef and redundant suffix from struct armv4_5_core_reg. 2009-11-13 Zachary T Welch * : arm_jtag_t -> struct arm_jtag Remove misleading typedef and redundant suffix from struct arm_jtag. 2009-11-13 Zachary T Welch * : arm_load_store_instr_t -> struct arm_load_store_instr Remove misleading typedef and redundant suffix from struct arm_load_store_instr. 2009-11-13 Zachary T Welch * : arm_b_bl_bx_blx_instr_t -> struct arm_b_bl_bx_blx_instr Remove misleading typedef and redundant suffix from struct arm_b_bl_bx_blx_instr. 2009-11-13 Zachary T Welch * : swjdp_reg_t -> struct swjdp_reg Remove misleading typedef and redundant suffix from struct swjdp_reg. 2009-11-13 Zachary T Welch * : arm966e_common_t -> struct arm966e_common Remove misleading typedef and redundant suffix from struct arm966e_common. 2009-11-13 Zachary T Welch * : arm920t_tlb_entry_t -> struct arm920t_tlb_entry Remove misleading typedef and redundant suffix from struct arm920t_tlb_entry. 2009-11-13 Zachary T Welch * : arm7tdmi_common_t -> struct arm7tdmi_common Remove misleading typedef and redundant suffix from struct arm7tdmi_common. 2009-11-13 Zachary T Welch * : arm720t_common_t -> struct arm720t_common Remove misleading typedef and redundant suffix from struct arm720t_common. 2009-11-13 Zachary T Welch * : arm11_reg_state_t -> struct arm11_reg_state Remove misleading typedef and redundant suffix from struct arm11_reg_state. 2009-11-13 Zachary T Welch * : arm11_reg_defs_t -> struct arm11_reg_defs Remove misleading typedef and redundant suffix from struct arm11_reg_defs. 2009-11-13 Zachary T Welch * : mem_param_t -> struct mem_param Remove misleading typedef and redundant suffix from struct mem_param. 2009-11-13 Zachary T Welch * : arm11_register_history_t -> struct arm11_register_history Remove misleading typedef and redundant suffix from struct arm11_register_history. 2009-11-13 Zachary T Welch * : pld_device_t -> struct pld_device Remove misleading typedef and redundant suffix from struct pld_device. 2009-11-13 Zachary T Welch * : xilinx_bit_file_t -> struct xilinx_bit_file Remove misleading typedef and redundant suffix from struct xilinx_bit_file. 2009-11-13 Zachary T Welch * : connection_t -> struct connection Remove misleading typedef and redundant suffix from struct connection. 2009-11-13 Zachary T Welch * : tcl_connection_t -> struct tcl_connection Remove misleading typedef and redundant suffix from struct tcl_connection. 2009-11-13 Zachary T Welch * : telnet_service_t -> struct telnet_service Remove misleading typedef and redundant suffix from struct telnet_service. 2009-11-13 Zachary T Welch * : gdb_connection_t -> struct gdb_connection Remove misleading typedef and redundant suffix from struct gdb_connection. 2009-11-13 Zachary T Welch * : aduc702x_flash_bank_t -> struct aduc702x_flash_bank Remove misleading typedef and redundant suffix from struct aduc702x_flash_bank. 2009-11-13 Zachary T Welch * : pic32mx_mem_layout_t -> struct pic32mx_mem_layout Remove misleading typedef and redundant suffix from struct pic32mx_mem_layout. 2009-11-13 Zachary T Welch * : nand_block_t -> struct nand_block Remove misleading typedef and redundant suffix from struct nand_block. 2009-11-13 Zachary T Welch * : str9x_flash_bank_t -> struct str9x_flash_bank Remove misleading typedef and redundant suffix from struct str9x_flash_bank. 2009-11-13 Zachary T Welch * : str7x_flash_bank_t -> struct str7x_flash_bank Remove misleading typedef and redundant suffix from struct str7x_flash_bank. 2009-11-13 Zachary T Welch * : stm32x_flash_bank_t -> struct stm32x_flash_bank Remove misleading typedef and redundant suffix from struct stm32x_flash_bank. 2009-11-13 Zachary T Welch * : stellaris_flash_bank_t -> struct stellaris_flash_bank Remove misleading typedef and redundant suffix from struct stellaris_flash_bank. 2009-11-13 Zachary T Welch * : pic32mx_flash_bank_t -> struct pic32mx_flash_bank Remove misleading typedef and redundant suffix from struct pic32mx_flash_bank. 2009-11-13 Zachary T Welch * : ocl_priv_t -> struct ocl_priv Remove misleading typedef and redundant suffix from struct ocl_priv. 2009-11-13 Zachary T Welch * : nand_manufacturer_t -> struct nand_manufacturer Remove misleading typedef and redundant suffix from struct nand_manufacturer. 2009-11-13 Zachary T Welch * : nand_flash_controller_t -> struct nand_flash_controller Remove misleading typedef and redundant suffix from struct nand_flash_controller. 2009-11-13 Zachary T Welch * : mflash_bank_t -> struct mflash_bank Remove misleading typedef and redundant suffix from struct mflash_bank. 2009-11-13 Zachary T Welch * : mflash_gpio_drv_t -> struct mflash_gpio_drv Remove misleading typedef and redundant suffix from struct mflash_gpio_drv. 2009-11-13 Zachary T Welch * : lpc3180_nand_controller_t -> struct lpc3180_nand_controller Remove misleading typedef and redundant suffix from struct lpc3180_nand_controller. 2009-11-13 Zachary T Welch * : lpc288x_flash_bank_t -> struct lpc288x_flash_bank Remove misleading typedef and redundant suffix from struct lpc288x_flash_bank. 2009-11-13 Zachary T Welch * : flash_driver_t -> struct flash_driver Remove misleading typedef and redundant suffix from struct flash_driver. 2009-11-13 Zachary T Welch * : faux_flash_bank_t -> struct faux_flash_bank Remove misleading typedef and redundant suffix from struct faux_flash_bank. 2009-11-13 Zachary T Welch * : cfi_fixup_t -> struct cfi_fixup Remove misleading typedef and redundant suffix from struct cfi_fixup. 2009-11-13 Zachary T Welch * : cfi_spansion_pri_ext_t -> struct cfi_spansion_pri_ext Remove misleading typedef and redundant suffix from struct cfi_spansion_pri_ext. 2009-11-13 Zachary T Welch * : cfi_intel_pri_ext_t -> struct cfi_intel_pri_ext Remove misleading typedef and redundant suffix from struct cfi_intel_pri_ext. 2009-11-13 Zachary T Welch * : avrf_flash_bank_t -> struct avrf_flash_bank Remove misleading typedef and redundant suffix from struct avrf_flash_bank. 2009-11-13 Zachary T Welch * : at91sam7_flash_bank_t -> struct at91sam7_flash_bank Remove misleading typedef and redundant suffix from struct at91sam7_flash_bank. 2009-11-13 Zachary T Welch * : jtag_command_container_t -> union jtag_command_container Remove misleading typedef from union jtag_container. 2009-11-13 Zachary T Welch * : end_state_command_t -> struct end_state_command Remove misleading typedef from struct end_state_command. 2009-11-13 Zachary T Welch * : stableclocks_command_t -> struct stableclocks_command Remove misleading typedef from struct stableclocks_command. 2009-11-13 Zachary T Welch * : pathmove_command_t -> struct pathmove_command Remove misleading typedef from struct pathmove_command. 2009-11-13 Zachary T Welch * : cmd_queue_page_t -> struct cmd_queue_page Remove misleading typedef from struct cmd_queue_page. 2009-11-13 Zachary T Welch * : more vsllink typedef cleanup Remove useless typedef for struct insert_insignification_operation. 2009-11-13 Zachary T Welch * : presto_t -> struct presto Remove useless typedef. 2009-11-13 Zachary T Welch * : jlink_jtag_t -> struct jlink Remove misleading typedef and redundant suffix. 2009-11-13 Zachary T Welch * : pending_scan_result_t -> struct pending_scan_result Remove misleading typedef from struct struct pending_scan_result. Future patches need to remove these duplicated types and code. 2009-11-13 Zachary T Welch * : use struct jtag_tap_event_action Remove useless typedef and redundant suffix from jtag_tap_event_action. 2009-11-13 Zachary T Welch * : jtag_interface_t -> struct jtag_interface Remove useless typedef and redundant suffix from struct jtag_interface. 2009-11-13 Zachary T Welch * : bitq_interface_t -> struct biq_interface Remove useless typedef and redundant suffix. 2009-11-13 Zachary T Welch * : scan_field_t -> struct scan_field Remove useless structure typedef. 2009-11-13 Zachary T Welch * : fileio_t -> struct fileio Remove useless structure typedef. 2009-11-13 Zachary T Welch * : remove accidental artifact Somehow I managed to slip a temporary build file into the tree. Remove it and update the .gitignore file so it doesn't happen again. 2009-11-11 Zachary T Welch * : add src/hello.c to augment new command tutorial The hello module provides the 'hello' command, printing a greetings to the command console. It can grow to serve as pedagogical example of services that OpenOCD developers should use: a runnable style guide. 2009-11-10 Zachary T Welch * : command_handler_t: make args parameter const This patch prevents command handlers from modifying the strings passed in the 'args' array. 2009-11-10 Zachary T Welch * : command_handler_t: make argc unsigned The number of command arguments will always be 0 or more, so use the right type in handlers. This has a cascading effect up through the layers, but the new COMMAND_HANDLER macros prevented total chaos. 2009-11-10 Zachary T Welch * : use CALL_COMMAND_HANDLER instead of direct calls By using CALL_COMMAND_HANDLER, parameters can be reordered, added, or even removed in inherited signatures, without requiring revisiting all of the various call sites. 2009-11-10 Zachary T Welch * : nand: add NAND_DEVICE_COMMAND_HANDLER macro Abstracts the extended NAND command handling to allow the function signature to be controlled by __COMMAND_HANDLER. 2009-11-10 Zachary T Welch * : add FLASH_BANK_COMMAND_HANDLER macro The FLASH_BANK_COMMAND_HANDLER provides an extended command handler using the __COMMAND_HANDLER macro, whereby changing that macro is sufficient to update flash handlers with the new signature. It also enforces uniform style and scope when implementing this handler. 2009-11-10 Zachary T Welch * : arm_adi,armv7[am]: use COMMAND_HELPER for helpers Rewrites the dap_* command helpers to use the COMMAND_HELPER paradigm. Uses CALL_COMMAND_HELPER to hide inherited calling conventions. 2009-11-09 Zachary T Welch * : use COMMAND_HANDLER macro to define all commands 2009-11-10 Zachary T Welch * : add COMMAND_HANDLER and COMMAND_HELPER macros The COMMAND_HANDLER and COMMAND_HELPER macros allow commands to be defined in a manner that decouples them from the exact order and type of their parameters. Once converted, incremental changes to the command handler type can be addressed in incremental patches that do not need to touch the entire tree. These macros' implementation, __COMMAND_HANDLER, is used to define the new command_handler_t type, and additional patches will use it to derive new macros to define extended command types (e.g. flash, nand, pld). The CALL_COMMAND_HANDLER provides a means of calling helpers or nested handlers from withing a command handler. This patch uses C99 varadic macro expansion. Please report compilers that cannot handle this code. 2009-11-13 David Brownell * : Cortex-A8: fix indent The "remove (forward) declarations" patch goofed indentation on the "cortexa8_target" struct; fix. Signed-off-by: David Brownell 2009-11-12 David Brownell * : ETM: start support for ETMv2+ ARM11 and newer cores include updated ETM modules. Recognize their version codes and some key config differences. Sanity checked on an OMAP2, with an ETM11RV r0p1 (ETMv3.1). This still handles only scan chain 6, with at most 128 registers. Newer cores (mostly, Cortex) will need to use the DAP instead. Note that the newer ETM modules don't quite fit the quirky config model of the older ones ... having more port widths is easy, but the modes aren't the same. That still needs to change. Fix a curious bug ... how did the register cache NOT get saved?? Signed-off-by: David Brownell 2009-11-12 Jonas Horberg * : parport: add support for the jtag_khz command. Add the khz and speed_div functions to the parport interface driver. Add the parport_toggling_time function that tells the parport driver how long (in nanoseconds) it takes for the hardware to toggle TCK. [dbrownell@users.sourceforge.net: tweak doc for clarity, mention multimeter, and whitespace fixes] Signed-off-by: David Brownell 2009-11-11 David Brownell * : ETM: use new toplevel ETM handle Make ETM itself use the new toplevel ETM handle, instead of the to-be-removed lower level one. As of this patch, nothing should be using the old ARM7/ARM9-specific handle. Signed-off-by: David Brownell 2009-11-11 David Brownell * : ETM: update arm[79]tdmi_examine() Make ARM7 and ARM9 cores use the new toplevel ETM handle to trigger ETM setup, not the to-be-removed lower level one. Signed-off-by: David Brownell 2009-11-10 Zachary T Welch * : fix 'jtag interface' behavior Without this patch, running "openocd -c 'jtag interface'" segfaults. Now, it returns the string "undefined" when the interface is unset. 2009-11-11 Zachary T Welch * : add help regardless of callback Add help for commands regardless of whether a handler is involved. With this, all sorts of new commands can be found in 'help' text. Hopefully, all of them have been documented.... Sadly, the lsort function appears to handle nested lists poorly, such that sub-commands do not group with their parents. 2009-11-11 Zachary T Welch * : add command_name helper The command_name function returns a malloced string for a given command and its parents. This can be used to display a message to the user, but it is used internally to handle registration and syntax errors. This helps permit arbitrary command nesting. 2009-11-11 Zachary T Welch * : remove obsolete doxygen comments Documenting command handler parameters is redundant and pointless. 2009-11-10 Zachary T Welch * : cortex_a8: remove declarations, use static keyword 2009-11-10 Zachary T Welch * : change argv to args in command handlers Subsequent patches expect all command handlers to use a uniform parameter naming scheme. In the entire tree, these two files used standard 'argv' instead of our non-standard 'args'. This patch opts to reduces the noise required to unify the command handlers, using dominant 'args' form. A future patch may be used to convert us back to the standard argv, but that requires coordination with all developers to minimize disruptions. 2009-11-09 Zachary T Welch * : command.c: make private routines static This patch also improves the signature of run_command function. 2009-11-09 Zachary T Welch * : time_support: improve use of types Update timeval_add_time to use long int; implement timeval_add with it. Update timeval_ms to check gettimeofday return value, return int64_t. 2009-11-11 David Brownell * : ETM cleanup Various cleanups of ETM related code. - Saner error return paths - Simplify arm7_9 init ... no need for extra zeroing! - Shrink some lines - Tweak some diagnostics - Use shorter name for ETM struct type. - Don't exit() and similar. The diagnostics look forward to having this ETM code work with more than just ARM7/ARM9. Signed-off-by: David Brownell 2009-11-10 David Brownell * : ARM720: bugfix The "ARM720 uses the new inheritance/nesting scheme" patch wrongly scrubbed a calloc() from arm720t_target_create(). Signed-off-by: David Brownell 2009-11-10 David Brownell * : target.cfg: (re)move some bogus reset_config lines General rule, this is all board-specific and doesn't belong in target config files. Some of these were just cosmetic. Signed-off-by: David Brownell 2009-10-27 Michael Bruck * : arm11: add etmr/etmw registers to access ETM via DBGTAP scan chain First cut of these commands. Øyvind tinkered a bit with the number parsing to bring it up to speed + rebased it. Ready for testing. Signed-off-by: Øyvind Harboe 2009-11-10 Øyvind Harboe * : telo.cfg: fix search paths Add the missing "target/" prefix for scripts in the target folder. Signed-off-by: Øyvind Harboe 2009-11-10 David Brownell * : ARM920: implement basic MMU ops mmu() works; virt2phys() fails and logs an error. Signed-off-by: David Brownell 2009-11-10 David Brownell * : Target: fix bad error messages And shrink a few too-long lines. Signed-off-by: David Brownell 2009-11-10 Øyvind Harboe * : tcl: HostOs now picks up eCos as well during compile time Signed-off-by: Øyvind Harboe 2009-11-09 Zachary T Welch * : command.c: make commands static Removes useless declarations, moving the handler functions to appear before their use in the (much bigger) command registriation function. 2009-11-09 Zachary T Welch * : jtag: remove useless declarations Contrary to my previous assessment, some opportunities to remove forward declarations were overlooked. Remove them by moving the definitions of the command registration and interface structure to the end of files. 2009-11-09 Zachary T Welch * : {pic32m,stm32}x.c: remove useless declarations Remove useless forward declarations. Moves command registrations to end of files. Moves flash structure definitions to end of files. Signed-off-by: Zachary T Welch 2009-11-09 Zachary T Welch * : flash/.c: remove useless declarations Remove useless forward declarations. Moves flash structure definitions to end of files. Signed-off-by: Zachary T Welch 2009-11-09 Zachary T Welch * : flash/at91sam[37].c: remove useless declarations Remove useless forward declarations. Moves command registration to end of file. Moves flash structure definitions to end of files. Changes a few references to global flash structure to local refs. Signed-off-by: Zachary T Welch 2009-11-09 Zachary T Welch * : flash/*nand*.c: remove useless declarations Remove useless forward declarations. Moves command registration to end of files. Moves flash structure definition to end of files. Signed-off-by: Zachary T Welch 2009-11-09 David Brownell * : Revert "target: add target->type->has_mmu fn" This patch introduced a bug preventing flash writes from working on Cortex-M3 targets like the STM32. Moreover, it's the wrong approach for handling no-MMU targets. The right way to handle no-MMU targets is to provide accessors for physical addresses, and use them everywhere; and any code which tries to work with virtual-to-physical mappings should use a identity mapping (which can be defaulted). And ... we can tell if a target has an MMU by seeing if it's got an mmu() method. No such methood means no MMU. Signed-off-by: David Brownell 2009-11-09 David Brownell * : User's Guide: Flash/NAND doc tweaks Rename the "Drivers, Options, and Commands" sections to be just "Driver List" matching the earlier reference. Add an example of parallel CFI flash. Signed-off-by: David Brownell 2009-11-09 Zachary T Welch * : target.h: remove extern keyword and wrap Removes 'extern' keyword from function prototypes and wraps long lines. 2009-11-09 Zachary T Welch * : src/flash: remove 'extern' and wrap headers Removes 'extern' keywords from function prototypes in the flash headers. Wraps long lines to fit into 80 columns. Adds multiple inclusion protection for s3c2xx_nand.h. 2009-11-09 Zachary T Welch * : src/helper: wrap and clean headers. Remove all useless 'extern' keywords from function prototypes. Wraps long lines for readability. 2009-11-09 David Brownell * : EmbeddedICE: minor cleanups Add comments (Doxygen and normal), remove unused code, shrink some overlong lines. Get rid of a forward decl. Signed-off-by: David Brownell 2009-11-06 Zachary T Welch * : Add private header for ARM11 internals. Reduces confusion about location of associated routines and reduces clutter in the arm11 header. Removes extra whitespace around the lines touched by these changes. 2009-11-08 David Brownell * : ARM: minor simulator cleanup Make several functions be static. Shrink some of the overlong lines. Use pure tab indents in some places that mixed in spaces. This gives a minor object code shrink (about 2% on amd64). Signed-off-by: David Brownell 2009-11-08 David Brownell * : target.cfg: remove "-work-area-virt 0" The semantics of "-work-area-virt 0" (or phys) changed with the patch to require specifying physical or virtrual work area addresses. Specifying zero was previously a NOP. Now it means that address zero is valid. This patch addresses three related issues: - MMU-less processors should never specify work-area-virt; remove those specifications. Such processors include ARM7TDMI, Cortex-M3, and ARM966. - MMU-equipped processors *can* specify work-area-virt... but zero won't be appropriate, except in mischievous contexts (which hide null pointer exceptions). Remove those specs from those processors too. If any of those mappings is valid, someone will need to submit a patch adding it ... along with a comment saying what OS provides the mapping, and in which context. Example, say "works with Linux 2.6.30+, in kernel mode". (Note that ARM Linux doesn't map kernel memory to zero ...) - Clarify docs on that "-virt" and other work area stuff. Seems to me work-area-virt is quite problematic; not every operating system provides such static mappings; if they do, they're not in every MMU context... Signed-off-by: David Brownell 2009-11-06 David Brownell * : commit a9abfa7d06dbcfded97b7fb41f50d3581c24fbae Author: David Brownell Date: Fri Nov 6 14:57:21 2009 -0800 2009-11-05 Zachary T Welch * : Simplify nand indentation. Removes check covered by new nand_command_get_device_by_num helper. Reverses logic of probe check to further reduce indentation. 2009-11-06 Zachary T Welch * : Fix arm11 vcr command parsing. 2009-11-05 David Brownell * : ARM: other code uses the new inheritance/nesting scheme Remove most remaining uses of target->arch_info from ARM infrastructure, where it hasn't already been updated. Signed-off-by: David Brownell 2009-11-05 David Brownell * : ARM7TDMI uses the new inheritance/nesting scheme Use target_to_arm7_9(), replacing needless pointer traversals. Also: remove now-useless contents of arm7tdmi struct; it's almost ready to be removed. Signed-off-by: David Brownell 2009-11-05 David Brownell * : XScale uses the new inheritance/nesting scheme Use target_to_xscale(), replacing needless pointer traversals and simplifying a bunch of code. Signed-off-by: David Brownell 2009-11-05 David Brownell * : ARM966 uses the new inheritance/nesting scheme Use target_to_arm966(), replacing needless pointer traversals. Signed-off-by: David Brownell 2009-11-05 David Brownell * : FA526 uses the new inheritance/nesting scheme Replace needless pointer traversals, simplify. Signed-off-by: David Brownell 2009-11-05 David Brownell * : Cortex-M3: use the new inheritance/nesting scheme Use new target_to_cm3() and target_to_armv7m() inlines, instead of a series of x->arch_info conversions. Remove arch_info, since nothing uses it. Also fix an omission: the Cortex-M3 commands didn't verify that they were operating on that kind of target. Add comment about the ARMv7M version of that omission. Signed-off-by: David Brownell 2009-11-05 David Brownell * : ARM7TDMI: remove forward decls The forward decls are just code clutter; remove them, by moving their references after definitions. This is another file which never needed even one internal forward declaration. Also shrink a few overly-long lines with function declarations or definitions; get rid of arm7tdmi_register_commands(), it's not needed (just delegated); minor whitespace declutter. Signed-off-by: David Brownell 2009-11-05 David Brownell * : FA526: remove exports and forward decls Unneeded exports cause confusion about the module interfaces. Make most functions static. The forward decls are just code clutter; remove them, by moving their references after definitions. This is another file which never needed even one internal forward declaration. Signed-off-by: David Brownell 2009-11-05 David Brownell * : ARM966: remove exports and forward decls Unneeded exports cause confusion about the module interfaces. Make most functions static. The forward decls are just code clutter; remove them, by moving their references after definitions. This is another file which never needed even one internal forward declaration. Also remove needless arm966e_init_target(), in favor of the arm9tdmi routine to which it delegates its work. This saved over 100 bytes of code on x86_32. Signed-off-by: David Brownell 2009-11-05 David Brownell * : ARM920: remove exports and forward decls Unneeded exports cause confusion about the module interfaces. Make most functions static. Add a short header comment. The forward decls are just code clutter; remove them, by moving their references after definitions. This is another file which never needed even one internal forward declaration. This saved almost 900 bytes of code on x86_32; it seems the compiler can leverage its knowledge that these functions are not called from the outside world... Signed-off-by: David Brownell 2009-10-23 Zachary T Welch * : Improve str9x config command argument parsing. 2009-10-22 Zachary T Welch * : Improve stm32x.c command argument parsing. 2009-10-22 Zachary T Welch * : Improve pic32mx.c command argument parsing. 2009-10-23 Zachary T Welch * : Improve lpc3180_nand_controller.c parsing. This fixes a memory leak in lpc3180_nand_device_command by reordering the malloc to occur after all parsing has completed. 2009-10-23 Zachary T Welch * : Improve lpc288x.c command argument parsing. 2009-10-23 Zachary T Welch * : Improve cfi.c command argument parsing. 2009-10-22 Zachary T Welch * : Improve orion_nand.c command argument parsing. 2009-10-22 Zachary T Welch * : Improve at91sam7.c command argument parsing. 2009-10-22 Zachary T Welch * : Improve nand.c command argument parsing. 2009-10-23 Zachary T Welch * : Add Flash/NAND bank command argument helpers. This eliminates redundant code for parsing and retreiving the bank specified from a script command argument. This patch was written to replace existing functionality; however, the parsing logic can be updated later to allow flash commands to accept bank names as well as their numbers. 2009-10-22 Zachary T Welch * : Improve etm command argument parsing. 2009-10-24 Zachary T Welch * : Improve arm_adi_v5 command argument parsing. 2009-10-24 Zachary T Welch * : Improve xscale command argument parsing. 2009-10-24 Zachary T Welch * : Improve arm966e command argument parsing. 2009-10-24 Zachary T Welch * : Improve arm920t command argument parsing. 2009-10-22 Zachary T Welch * : Improve arm7_9_common command argument parsing. 2009-10-24 Zachary T Welch * : Improve armv7a command argument parsing. 2009-10-24 Zachary T Welch * : Improve xscale command argument parsing. 2009-10-24 Zachary T Welch * : Update all server port command to use new helper. 2009-10-22 Zachary T Welch * : Improve target.c command argument parsing. Passes cmd_ctx into parse_load_image_command_args for reporting the parsing errors therein. 2009-10-22 Zachary T Welch * : Improve debug_level command argument parsing. 2009-10-22 Zachary T Welch * : Add stringify macros in src/helper/types.h. 2009-10-27 Øyvind Harboe * : arm11: check if target is halted before executing mrc/mcr commands. Signed-off-by: Øyvind Harboe 2009-10-26 Øyvind Harboe * : target: check args to mrc/mcr. Signed-off-by: Øyvind Harboe 2009-10-24 Øyvind Harboe * : TODO: Wrote up list of remaining tasks for target->type->mrc/mcr Signed-off-by: Øyvind Harboe 2009-10-24 Øyvind Harboe * : cortex_a8: add mrc mcr interface. Signed-off-by: Øyvind Harboe 2009-11-05 David Brownell * : watchpoint_add() cleanup Fail watchpoint_add() if it's the same address but the parameters are different ... don't just assume having the same address means the same watchpoint! (Note that overlapping watchpoints aren't detected...) Handle unrecognized return codes more sanely; don't exit()! And describe command params right. Signed-off-by: David Brownell 2009-11-05 David Brownell * : Cortex-M3: minor cleanup There's no reason to read which interrupts are enabled from the NVIC; that state isn't used. Plus, it's highly dynamic since firmware can change it at any time; remove the support for those state records. Remove duplicate definition of DWT_CTRL address; shrink a line. Signed-off-by: David Brownell 2009-11-05 David Brownell * : ARMv7M: add docs, remove exports Add Doxygen for the exported ARMv7-M interfaces. Make the non-exported stuff static. Remove functions and data which are now observably unused. Add comment about a small speedup that the run_algorithm() logic could use. Shrink a few too-long lines. Signed-off-by: David Brownell 2009-10-26 Øyvind Harboe * : Make default implementation of mdw/mmw phys return error 'not implemented' 2009-10-30 Øyvind Harboe * : debug interface: get rid of unused pre_debug fn Removing unused code makes it much less mysterius. Signed-off-by: Øyvind Harboe 2009-11-04 David Brownell * : ft2232: cleanup Previous patch somehow made GCC lose some of its cookies; work around, zero-init that struct. Clean up code from the previous patch. Signed-off-by: David Brownell 2009-11-04 David Brownell * : PXA255: support Intel "Lubbock" platform Config for Intel's "Lubbock" PXA255 development board. Even more so than the PXA255 itself, this is obsolete. AFAIK this was the first generally available development platform for PXA255. Intel stopped providing these after other devel boards became available. One interesting thing about this board from the OpenOCD perspective is probably its flash configuration. Each bank is 32 bits wide, built from two 16-bit StrataFlash chips wired in parallel. This doubles throughput ... it reads/writes 32 bits in the time a single chip takes to write just 16 bits. This conf mostly works, given XScale bugfixes, but has some issues (notably: no access to the on-board SDRAM) flagged by FIXMEs. Signed-off-by: David Brownell 2009-11-04 David Brownell * : Version 0.3.0 Remove -dev tag, remove -rc tag. Signed-off-by: David Brownell 2009-11-04 David Brownell * : Doc: fix broken link Signed-off-by: David Brownell 2009-11-04 David Brownell * : Other files: stop referring to ChangeLog too The ChangeLog idiom is redundant given any decent SCM. Time to phase it out here. Signed-off-by: David Brownell 2009-11-04 David Brownell * : Tweak release docs Contrast releases to git snapshot tarballs. Mention that releases have some quality-improvement focus, with special non-"dev" version IDs. Explain more about version IDs, using "openocd -v" to see them, etc; Make release milestone info be less specific about timing, and presume we have both a merge window and an RC stage. Rework the release process information to match reality a bit more closely. Reference the version.sh script (in one place the wrong script was referenced). Bugfix branches get special treatment, while non-bugfix releases are more or less what *defines* being the mainline branch. Signed-off-by: David Brownell 2009-11-04 Øyvind Harboe * : configure: fix build problems with eCos Various include files require some other include files to be included first. Copied solution from net/if.h. Signed-off-by: Øyvind Harboe 2009-11-03 Øyvind Harboe * : target: 20 second timeout/megabyte for CRC check There was a fixed 20 second timeout which is too little for large, slow timeout checks. Signed-off-by: Øyvind Harboe 2009-11-02 Øyvind Harboe * : target: require working area for physical/virtual addresses to be specified Fixed bug: if virtual address for working memory was not specified and MMU was enabled, then address 0 would be used. Require working address to be specified for both MMU enabled and disabled case. For some completely inexplicable reason this fixes the regression in svn 2646 for flash write in arm926ejs target. The logs showed that MMU was disabled in the case below: https://lists.berlios.de/pipermail/openocd-development/2009-November/011882.htmlSigned-off-by: Øyvind Harboe 2009-11-01 David Brownell * : User's Guide: more init info, autoprobing, etc Mention the autoprobing as a tool that may be useful when figuring out how to set up; and add a section showing how to use that mechanism (with an example). Strengthen the differences between config and run stage descriptions; add a section for the latter. Mention Dragonite. Signed-off-by: David Brownell 2009-11-01 Freddie Chopin * : remove "-ircapture 0x1 -irmask 0x1" from stm32.cfg Gets rid of the runtime warning "stm32.bs: nonstandard IR mask" [dbrownell@users.sourceforge.net: line lengths, note issue, section ref] Signed-off-by: David Brownell 2009-10-29 Freddie Chopin * : target.cfg: use $_TARGETNAME for flash This gets rid of runtime warnings from the use of numbers. STM32 and LPC2103 were tested. Other LPC updates are the same, and so are safe. The CFI updates match other tested changes now in the tree. Signed-off-by: David Brownell 2009-10-30 David Brownell * : ARM926: fix arm926ejs_mmu() reading from bad pointer I'm suspecting this code can never have worked, since the original commit (svn #335) in early 2008. Fix is just copy/paste from another (working) function. Signed-off-by: David Brownell 2009-10-29 Michael Roth * : SVF: fix checking bit pattern against length The code works like follow (N = bit_len): N -1 %4 2<< -1 ~ (binary) -------------------------------------------------- 1 0 0 2 1 1111 1110 2 1 1 4 3 1111 1100 3 2 2 8 7 1111 1000 4 3 3 16 15 1111 0000 5 4 0 2 1 1111 1110 6 5 1 4 3 1111 1100 7 6 2 8 7 1111 1000 8 7 3 16 15 1111 0000 ... ... ... ... ... ... Addresses a bug reported by FangfangLi . [dbrownell@users.sourceforge.net: fix spelling bug too] Signed-off-by: Michael Roth Cc: FangfangLi Signed-off-by: David Brownell 2009-10-29 David Brownell * : XSVF: bugfix handling state paths Implement XSVF support for detailed state path transitions, by collecting sequences of XSTATE transitions into paths and then calling pathmove(). It seems that the Xilinx tools want to force state-by-state transitions instead of relying on the standardized SVF paths. Like maybe there are XSVF tools not implementing SVF paths, which are all that we support using svf_statemove(). So from IRPAUSE, instead of just issuing "XSTATE DRPAUSE" they will issue XSTATES for each intermediate state: first IREXIT2, then IRUPDATE, DRSELECT, DRCAPTURE, DREXIT1, and finally DRPAUSE. This works now. Handling of paths that go *through* reset is a trifle dodgey, but it should be safe. Tested-by: Wookey Signed-off-by: David Brownell 2009-10-28 Zachary T Welch * : The openocd 0.3.0-rc0 release. Remove '-dev' version tag: 0.3.0-rc0-dev -> 0.3.0-rc0 2009-10-28 David Brownell * : ARM926: remove exports and forward decls Unneeded exports cause confusion about the module interfaces. Only the Feroceon code builds on this, so only routines it reuses should be public.. Make most remaining functions static, and fix some of the line-too-long issues. The forward decls are just code clutter; move their references later, after the normal declarations. Turns out we don't need even one forward declaration in this file. Signed-off-by: David Brownell 2009-10-22 Zachary T Welch * : Add script to test the release process. Runs the release.sh script in a freshly cloned repository, charting one hypothetical future of OpenOCD's lineage. 2009-10-20 Zachary T Welch * : Factor version munging capabilities out of release.sh. 2009-10-24 Zachary T Welch * : Add git2cl from repo.or.cz as a submodule in tools/git2cl. 2009-10-27 Nicolas Pitre * : ARM: fix single-step of Thumb unconditional branch Only type 1 branch instruction has a condition code, not type 2. Currently they're both tagged with ARM_B which doesn't allow for the distinction. Signed-off-by: Nicolas Pitre Signed-off-by: David Brownell 2009-10-27 Oleg Seiljus * : Signalyzer: H2 and H4 support This patch includes partial support for these new JTAG adapters. More complete support will require updates to the libftdi code, for EEPROM access. [dbrownell@users.sourceforge.net: fix whitespace, linelen, etc ] Signed-off-by: David Brownell 2009-10-27 Nicolas Pitre * : ARM: fix Thumb mode handling when single-stepping register based branch insns Currently, OpenOCD is always caching the PC value without the T bit. This means that assignment to the PC register must clear that bit and set the processor state to Thumb when it is set. And when the PC register value is transferred to another register or stored into memory then the T bit must be restored. Discussion: It is arguable if OpenOCd should have preserved the original PC value which would have greatly simplified this code. The processor state could then be obtained simply by getting at bit 0 of the PC. This however would require special handling elsewhere instead since the T bit is not always relevant (like when PC is used with ALU insns or as an index with some addressing modes). It is unclear which way would be simpler in the end. Signed-off-by: Nicolas Pitre Signed-off-by: David Brownell 2009-10-27 Nicolas Pitre * : ARM: call thumb_pass_branch_condition() only for actual branch opcodes Calling it first with every opcodes and then testing if the opcode was indeed a branch instruction is wasteful and rather strange. If ever thumb_pass_branch_condition() has side effects (say, like printing a debugging traces) then the result would be garbage for most Thumb instructions which have no condition code. While at it, let's make the nearby code more readable by reducing some of the redundant brace noise and reworking the error handling construct. Signed-off-by: Nicolas Pitre Signed-off-by: David Brownell 2009-10-26 David Brownell * : JTAG: "jtag newtap ..." cleanup Get rid of needless variable, improve and shrink diagnostic. Signed-off-by: David Brownell 2009-10-26 David Brownell * : omap3530: target reset/init improvements Now I can issue "reset halt" and have everything act smoothly; the vector_catch hardware is obviously not kicking in, but the rest of the reset sequence acts sanely. - TAP "setup" event enables the DAP, not omap3_dbginit (resolving a chicken/egg bug I noted a while back) - Remove stuff from omap3_dbginit which should never be used in event handlers - Cope better with slow clocking during reset Also, stop hard-wiring the target name: use the input params in the standard way, and set up $_TARGETNAME as an output param. Signed-off-by: David Brownell 2009-10-26 Spencer Oliver * : Fix incorrect line endings Signed-off-by: Spencer Oliver 2009-10-26 Wookey * : balloon3 board base config This is the very basic board config for the balloon3 board cpu JTAG channel. The rest of the config comprises another 14 .cfg files which I suspect openocd doesn't really want all of. I'm still not sure how to deal with this. I'll post another mail/patch to discuss. Signed-off-by: David Brownell 2009-10-23 Øyvind Harboe * : Idea for adding watchpoint masks. 2009-10-25 David Brownell * : minor fixes to TODO list 2009-10-25 Øyvind Harboe * : check if mmu is enabled before using mmu code path 2009-10-25 David Brownell * : JTAG: jtag_tap_init() bugfixes Stop allocating three bytes per IR bit, and cope somewhat better with IR lengths over 32 bits. Signed-off-by: David Brownell 2009-10-24 Øyvind Harboe * : vector_catch and watchpoint TODO items. 2009-10-23 Øyvind Harboe * : Improve help for arm9 vector_catch. 2009-10-23 Øyvind Harboe * : mcr/mrc interface work. Implemented for arm926ejs and arm720t. mcr/mrc commands added. 2009-10-23 David Brownell * : jtag: clean up TAP state name handling Some cosmetic cleanup, and switch to a single table mapping between state names and symbols (vs two routines which only share that state with difficulty). Get rid of TAP_NUM_STATES, and some related knowledge about how TAP numbers are assigned. Later on, this will help us get rid of more such hardwired knowlege. Signed-off-by: David Brownell 2009-10-22 Nicolas Pitre * : Ferocion: fix corruption of r0 when resuming Thumb mode The wrong variable (pc instead of r0) was used. Furthermore, someone did cover this error by stupidly silencing the compiler warning that occurred before a dummy void reference to r0 was added to the code. Signed-off-by: David Brownell 2009-10-22 David Brownell * : ETM: rename registers, doc tweaks The register names are perversely not documented as zero-indexed, so rename them to match that convention. Also switch to lowercase suffixes and infix numbering, matching ETB and EmbeddedICE usage. Update docs to be a bit more accurate, especially regarding what the "trigger" event can cause; and to split the issues into a few more paragraphs, for clarity. Make "configure" helptext point out that "oocd_trace" is prototype hardware, not anything "real". Signed-off-by: David Brownell 2009-10-21 Øyvind Harboe * : mww_phys retired. Replaced by generic mww phys in target.c 2009-10-21 Øyvind Harboe * : retire obsolete mXY_phys commands. Handled by generic memory read/modify commands and target read/write physical memory callbacks. 2009-10-21 Øyvind Harboe * : add support for target_read/write_phys_memory callbacks. 2009-10-21 Øyvind Harboe * : commit 69a6037ce6e76dca4117689208358231dffa0929 Author: Øyvind Harboe Date: Wed Oct 21 13:10:32 2009 +0200 2009-10-21 Øyvind Harboe * : Retire obsolete and superfluous implementations of virt2phys in each target. This is done in a polymorphic implementation in target.c 2009-10-21 Øyvind Harboe * : Defined target_write_memory() to be able to handle implementing breakpoints for read only ram(e.g. MMU write protected. 2009-10-20 David Brownell * : XSVF: use svf_add_statemove() XSVF improvements: - Layer parts of XSVF directly over SVF, calling svf_add_statemove() instead of expecting jtag_add_statemove() to conform to the SVF/XSVF requirements (which it doesn't). This should improve XSTATE handling a lot; it removes most users of jtag_add_statemove(), and the comments about how it should really do what svf_add_statemove() does. - Update XSTATE logic to be a closer match to the XSVF spec. The main open issue here is (still) that this implementation doesn't know how to build and submit paths from single-state transitions ... but now it will report that error case. - Update the User's Guide to mention the two utility scripts for working with XSVF, and to mention the five extension opcodes. Handling of state transition paths is, overall, still a mess. I think they should all be specified as paths not unlike SVF uses, and compiled to the bitstrings later ... so that we can actually make sense of the paths. (And see the extra clocks, detours through RUN, etc.) Signed-off-by: David Brownell 2009-10-20 Øyvind Harboe * : Added the faux flash driver and target. Used for testing. 2009-10-20 Øyvind Harboe * : More svn to git version string fixes. 2009-10-19 David Brownell * : davinci: add watchdog reset method Lightly tested on dm365. Signed-off-by: David Brownell 2009-10-19 David Brownell * : SVF/XSVF: comment and whitespace fixes SVF: comment the predefined/default paths; make them static const SVF, XSVF: whitespace fixes, mostly so copyrights display sanely Signed-off-by: David Brownell 2009-10-19 Redirect 'Slash' NIL * : MinGW: always use "-D__USE_MINGW_ANSI_STDIO" This is unfortunately needed to make stdio work like OpenOCD expects -- matching the ANSI-C standard, instead of MS-Windows. I tested it in both MinGW-W64 on Vista 64 and MinGW-W32 on XP, and I don't see any adverse effects to enabling it for all MinGW versions. 2009-10-19 David Brownell * : Doc: jtag_init must validate scan chain too Same requirement as like init_reset, and for the same reason: we need to start with a known and working state. 2009-10-19 David Brownell * : Ignore openocd.exe for "git status" 2009-10-19 oyvind * : Sync with official Jim Tcl repository. 2009-10-18 Dean Glazeski * : SDRAM and clock configuration for the SAM9-L9260 board from Olimex 2009-10-17 David Brownell * : Ignore two more generated files On Windows the name is "bin2char.exe". All operating systems now have "xscale_handler.h". 2009-10-17 Redirect \"Slash\" NIL * : jim-eventloop for MinGW-w64 Use JIM_WIDE_MODIFIER for the sscanf format, and apply it for MINGW32 as well as other Windows environments. (Microsoft doesn't conform to the C99 standard, and uses "%I64d" not "%lld" for "long long".) NB: __MINGW32__ should work on both w32 and w64,. 2009-10-16 David Brownell * : xscale: better fix for debug_handler.bin Generate a C struct with the data, and use that, instead of an assembly language file. The assembly language causes issues on Darwin and MS-Windows, which don't necessarily use GNU AS; or if they do, don't necessarily use its ELF syntax. It's also better in two other ways: fewer global symbols; and the init-time size check gets optimized away at compile time. (Unless it fails, in which case bigger chunks of the file vanish.) Signed-off-by: David Brownell 2009-10-14 David Brownell * : portability updates Based on some patches from for preliminary Win64 compilation. More such updates are needed, but they need work. Compile tested on 64 and 32 bit Linuxes, and Cygwin. Signed-off-by: David Brownell 2009-10-14 Wookey * : Fw: [PATCH] OpenRD board configuration Ofrwarded from Ron, who's not subscribed. ----- Forwarded message from Ron ----- From: Ron Date: Wed, 14 Oct 2009 04:50:17 +1030 To: wookey@debian.org Subject: [PATCH] OpenRD board configuration X-Spam-Status: No, score=-3.6 required=4.5 tests=BAYES_00,RCVD_IN_DNSWL_LOW autolearn=ham version=3.2.5 This piggybacks on the 'sheevaplug' layout which uses the same Kirkwood SoC. Signed-off-by: Ron Lee 2009-10-14 Øyvind Harboe * : Work in progress on arm11 reset. Assert srst. 2009-10-14 David Brownell * : Fix problems building xscale_debug.S 2009-10-13 Lennert Buytenhek * : fix detection of PLD instructions Signed-off-by: Lennert Buytenhek Signed-off-by: David Brownell 2009-10-13 David Brownell * : cosmetic cleanup in TMS tables Cleanup comments and layout/whitespace in the TMS tables. Table contents stayed the same (ignoring whitespace). Signed-off-by: David Brownell 2009-10-11 Yauheni Kaliuta * : Do not replace virt2phys with the default one if it was assigned Signed-off-by: Yauheni Kaliuta 2009-10-13 Øyvind Harboe * : Missing type for eCos. 2009-10-13 Øyvind Harboe * : Delete commented out code. Add a bit of error checking. 2009-10-13 Øyvind Harboe * : Propagate error from assert, deassert and halt on tcl target object. 2009-10-12 Øyvind Harboe * : More error propagation fixes. 2009-10-12 Wookey * : Xilinx xcr3256.cfg basic config script 2009-10-12 Øyvind Harboe * : Propagate wDTR/rDTR failure immediately, otherwise it's followed up by timeout errors. 2009-10-12 Øyvind Harboe * : burst writes work fine. clean up junk. 2009-10-12 David Brownell * : simplify XScale debug handler installation Load the XScale debug handler from the read-only data section instead of from a separate file that can get lost or garbaged. This eliminates installation and versioning issues, and also speeds up reset handling a bit. Plus some minor bits of cleanup related to loading that handler: comments about just what this handler does, and check fault codes while writing it into the mini-icache. The only behavioral changes should be cleaner failure modes after errors during handler loading, and being a bit faster. NOTE: presumes GNU assembly syntax, with ".incbin"; and ELF, because of the syntax of the ".size" directive. Signed-off-by: David Brownell 2009-10-12 Øyvind Harboe * : Merge commit 'origin/master' 2009-10-12 Øyvind Harboe * : Supply default reset_config statement to make target scripts useful standalone and provide sensible default 2009-10-11 David Brownell * : xscale.c cleanup Declare almost everything as static. Move stuff to remove most forward references. Remove most forward declarations. Warn if the unimplemented register functions get called. Signed-off-by: David Brownell 2009-10-11 David Brownell * : xscale minor cleanup Add a header comment referencing useful XScale specs. Make most data static, and the tables readonly. Scrub extra blank lines. Return fault codes from one routine. Remove a needless NOP methood. (BUGFIX) When we update R0, mark R0 as dirty/valid ... not R15/PC! Signed-off-by: David Brownell 2009-10-10 Wookey * : Fix reset delays and tinker with ID's 2009-10-09 David Brownell * : add documentation about reset customization We added two overridable procedures; document them, and the two jtag arp_* operations they necessarily expose. Update the comment about the jtag_init_reset() routine; it's been obsolete for as long as it's had SRST support. Signed-off-by: David Brownell 2009-10-09 Øyvind Harboe * : ARM11 error checking 2009-10-09 Øyvind Harboe * : Added tip in documentation on how to translate quirky syntax 2009-10-08 David Brownell * : add overridable Tcl "init_reset" This abstracts the "jtag arp_init-reset" call into a method called from OpenOCD startup and reset processing. Platforms which have different requirements for how such hard resets must be performed can now override "init_reset" instead of needing to rebuild custom hacked versions of the server. Signed-off-by: David Brownell 2009-10-08 Rabeeh Khoury * : Function to flash SheevaPlug u-boot sectors This function is used by the SheevaPlug installer to flash the erase and re-flash the U-Boot environment in the NAND Flash. 2009-10-08 David Brownell * : prevent abort via polling during jtag_reset Observed: openocd: core.c:318: jtag_checks: Assertion `jtag_trst == 0' failed. The issue was that nothing disabled background polling during calls from the TCL shell to "jtag_reset 1 1". Fix by moving the existing poll-disable mechanism to the JTAG layer where it belongs, and then augmenting it to always pay attention to TRST and SRST. Signed-off-by: David Brownell 2009-10-08 David Brownell * : commit 4aacf01e194d09fb55dc759fc42ac42c8432c015 Author: Øyvind Harboe Date: Thu Oct 8 15:43:51 2009 +0200 2009-10-08 Øyvind Harboe * : Add .project to .gitignore 2009-10-08 Øyvind Harboe * : Update copyright statements. Make it easier to sync with Jim Tcl 2009-10-07 John Rigby * : iMX25 target support Signed-off-by: David Brownell 2009-10-07 David Brownell * : commit 03c9e48f88fa8b681b77c6c35d6da0a0e838a7e8 Author: dbrownell Date: Thu Oct 8 00:13:50 2009 +0000 2009-10-07 dbrownell * : Force sane SRST and TRST initialization At least some FT2232 based adapters don't necessarily come up in the expected state, with SRST and TRST disabled. Since other adapters could suffer the same problem, let's avoid needing to patch every driver and just force *all* adapters to initialize those values properly at server startup. git-svn-id: svn://svn.berlios.de/openocd/trunk@2824 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-10-07 dbrownell * : Remove much #ifdeffery around _DEBUG_JTAG_IO_ usage. Have DEBUG_JTAG_IO() always trigger necessary warnings. git-svn-id: svn://svn.berlios.de/openocd/trunk@2822 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-10-07 David Brownell * : commit f8c8d8bc72b2a87d2b2e3d583a052d8f0e5d22ea Author: dbrownell Date: Wed Oct 7 16:15:21 2009 +0000 2009-10-07 dbrownell * : Note bug in handling of variables through command line parameters. git-svn-id: svn://svn.berlios.de/openocd/trunk@2819 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-10-07 oharboe * : first stab at imx35 reset init script git-svn-id: svn://svn.berlios.de/openocd/trunk@2817 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-10-07 oharboe * : add timeouts and fix syntax error handling of mrc/mcr commands. git-svn-id: svn://svn.berlios.de/openocd/trunk@2815 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-10-07 oharboe * : increase pause before reboot so web interface remains responsive when issuing a reboot of zy1000 git-svn-id: svn://svn.berlios.de/openocd/trunk@2813 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-10-07 oharboe * : 1.55 snapshot git-svn-id: svn://svn.berlios.de/openocd/trunk@2810 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-10-06 David Brownell * : commit 0da2f750a1d437b50b21ac7ee766188a47b37fad Author: dbrownell Date: Tue Oct 6 22:56:52 2009 +0000 2009-10-06 dbrownell * : Dragonite has the same EICE affliction as feroceon. From: Nicolas Pitre git-svn-id: svn://svn.berlios.de/openocd/trunk@2807 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-10-06 David Brownell * : commit 39b57471bfd92ef0d9a3aceb69f40c1335f5b62f Author: oharboe Date: Tue Oct 6 08:10:57 2009 +0000 2009-10-06 oharboe * : stop using targetnum git-svn-id: svn://svn.berlios.de/openocd/trunk@2804 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-10-05 David Brownell * : commit 64ec7f66a896fc4de6b472cffb6ef5740a76f61d Author: dbrownell Date: Mon Oct 5 23:45:14 2009 +0000 2009-10-05 David Brownell * : commit 7a57c316196f93c7e31b7d00eb9b52177ae874c6 Author: dbrownell Date: Mon Oct 5 08:23:33 2009 +0000 2009-10-05 dbrownell * : Add a new JTAG "setup" event; use for better DaVinci ICEpick support. The model is that this fires after scanchain verification, when it's safe to call "jtag tapenable $TAPNAME". So it will fire as part of non-error paths of "init" and "reset" command processing. However it will *NOT* trigger during "jtag_reset" processing, which skips all scan chain verification, or after verification errors. ALSO: - switch DaVinci chips to use this new mechanism - log TAP activation/deactivation, since their IDCODEs aren't verified - unify "enum jtag_event" scripted event notifications - remove duplicative JTAG_TAP_EVENT_POST_RESET git-svn-id: svn://svn.berlios.de/openocd/trunk@2800 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-10-05 dbrownell * : Update the NEWS file to cover more of the user-visible changes. git-svn-id: svn://svn.berlios.de/openocd/trunk@2798 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-10-02 mlu * : Updated reset event handling in omap3530 cfg git-svn-id: svn://svn.berlios.de/openocd/trunk@2796 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-10-02 mlu * : Make sure that DSCR_DTR_RX is not full before writing git-svn-id: svn://svn.berlios.de/openocd/trunk@2794 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-10-02 mlu * : Added asser_reset and deassert_reset for cortex_a8 git-svn-id: svn://svn.berlios.de/openocd/trunk@2792 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-10-02 dbrownell * : Minor ETB and ETM bugfixes and doc updates - ETB * report _actual_ hardware status, not just expected status * add a missing diagnostic on a potential ETB setup error * prefix any diagnostics with "ETB" - ETM * make "etm status" show ETM hardware status too, instead of just traceport status (which previously was fake, sigh) - Docs * flesh out "etm tracemode" docs a bit * clarify "etm status" ... previously it was traceport status * explain "etm trigger_percent" as a *traceport* option ETM+ETB tracing still isn't behaving, but now I can see that part of the reason is that the ETB turns itself off almost immediately after being enabled, and before collecting any data. git-svn-id: svn://svn.berlios.de/openocd/trunk@2790 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-30 zwelch * : Update release process documentation. - Improve and clarify the wording of the introduction. - Add section on version taggging. - Some other minor corrections. git-svn-id: svn://svn.berlios.de/openocd/trunk@2788 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-30 zwelch * : Add numeric version tag support to release script. The release process itself does not use this support yet, but it allows packagers to automate the process of managing their own tags, if they patch the source code before releasing binaries. The release processes should be revised to incorporate this feature to support -rc packages. git-svn-id: svn://svn.berlios.de/openocd/trunk@2786 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-30 zwelch * : Add workaround to release script to update source code URL keyword. git-svn-id: svn://svn.berlios.de/openocd/trunk@2784 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-30 zwelch * : Fix release script bugs after experience from 0.2.0: - The NEWS step failed due to an empty commit comment. - The final release step would have failed, because the steps to switch from the secure to insecure repository (and back again) require both switch and a URL relocation steps git-svn-id: svn://svn.berlios.de/openocd/trunk@2782 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-30 mlu * : Add DSCR_DTR_RX_FULL bit define git-svn-id: svn://svn.berlios.de/openocd/trunk@2780 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-30 oharboe * : michal smulski reset now works git-svn-id: svn://svn.berlios.de/openocd/trunk@2778 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-29 dbrownell * : ARM11 command handling fixes - Commands were supposed to have been "arm11 memwrite ..." not "memwrite ..." - Get rid of obfuscatory macros - Re-alphabetize - Add docs for "arm11 vcr" git-svn-id: svn://svn.berlios.de/openocd/trunk@2776 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-29 dbrownell * : Doc updates: add section on target software changes, minor fixes git-svn-id: svn://svn.berlios.de/openocd/trunk@2774 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-29 dbrownell * : ETB: cleanup needless symbol exports and forward decls. git-svn-id: svn://svn.berlios.de/openocd/trunk@2772 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-29 oharboe * : reentry assert git-svn-id: svn://svn.berlios.de/openocd/trunk@2770 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-29 oharboe * : added t/nsrst_assert_width commands git-svn-id: svn://svn.berlios.de/openocd/trunk@2768 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-28 oharboe * : spelling fix git-svn-id: svn://svn.berlios.de/openocd/trunk@2766 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-27 dbrownell * : Add list of JTAG adapter drivers with TAP_RESET statemove bug. git-svn-id: svn://svn.berlios.de/openocd/trunk@2764 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-27 dbrownell * : Don't provide invalid OMAP5912 IR capture value/mask attributes git-svn-id: svn://svn.berlios.de/openocd/trunk@2762 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-26 dbrownell * : Diagnostics tweaks for jtag_examine_chain() failure paths. git-svn-id: svn://svn.berlios.de/openocd/trunk@2760 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-26 dbrownell * : Streamline Capture-IR handling and integrity test. Change the handling of the "-ircapture" and "-irmask" parameters to be slightly more sensible, given that the JTAG spec describes what is required, and that we already require that conformance in one place. IR scan returns some bitstring with LSBs "01". - First, provide and use default values that satisfy the IEEE spec. Existing TAP configs will override the defaults, but those parms are no longer required. - Second, warn if any TAP gets set up to violate the JTAG spec. It's likely a bug, but maybe not; else this should be an error. Improve the related diagnostics to say which TAP is affected. And associated minor fixes/cleanups to comments and diagnostics. git-svn-id: svn://svn.berlios.de/openocd/trunk@2758 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-25 oharboe * : Michael Hasselberg target configuration files for Toshiba TX09 familiy git-svn-id: svn://svn.berlios.de/openocd/trunk@2756 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-24 oharboe * : When attaching GDB to OpenOCD, the target state is no longer affected. Added gdb_sync feature that allows GDB to sync up to target state. Issue "monitor gdb_sync" and the next stepi, will return immediately with updated register values to GDB. git-svn-id: svn://svn.berlios.de/openocd/trunk@2754 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-23 dbrownell * : When setting up an ETM, cache its ETM_CONFIG register. Then only expose the registers which are actually present. They could be missing for two basic reasons: - This version might not support them at all; e.g. ETMv1.1 doesn't have some control/status registers. (My sample of ARM9 boards shows all with ETMv1.3 support, FWIW.) - The configuration on this chip may not populate as many registers as possible; e.g. only two data value comparators instead of eight. Includes a bugfix in the "etm info" command: only one of the two registers is missing on older silicon, so show the first one before bailing. Update ETM usage docs to explain that those registers need to be written to configure what is traced, and that some ETM configs are not yet handled. Also, give some examples of the kinds of constrained trace which could be arranged. git-svn-id: svn://svn.berlios.de/openocd/trunk@2752 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-23 dbrownell * : Initial ETM cleanups. Most of these are cosmetic: - Add a header comment - Line up the ETM context struct, pack it a bit - Remove unused context_id (this doesn't support ETMv2 yet) - Make most functions static - Remove unused string table and other needless lines of code - Correct "tracemode" helptext Also provide and use an etm_reg_lookup() to find entries in the ETM register cache. This will help cope with corrected contents of that cache, which doesn't include entires for non-existent registers. git-svn-id: svn://svn.berlios.de/openocd/trunk@2750 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-22 ntfreak * : - fix build issue under win32 (cygwin/msys) from svn r2746 git-svn-id: svn://svn.berlios.de/openocd/trunk@2748 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-22 dbrownell * : Make it easier to erase or protect through to the end of a (NOR) flash chip: allow passing "last" as an alias for the number of the last sector. Improve several aspects of error checking while we're at it. From: Johnny Halfmoon git-svn-id: svn://svn.berlios.de/openocd/trunk@2746 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-21 dbrownell * : Remove annoying end-of-line whitespace from doc/* files. git-svn-id: svn://svn.berlios.de/openocd/trunk@2744 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-21 dbrownell * : Remove annoying end-of-line whitespace from most src/* files; omitted src/httpd git-svn-id: svn://svn.berlios.de/openocd/trunk@2742 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-21 dbrownell * : Ensure that DaVinci chips can't start with a too-fast JTAG clock. It can be sped up later, once it's known the PLLs are active. Note that modern tools from TI all use adaptive clocking; and that if that's done with OpenOCD, "too fast" is also a non-issue. git-svn-id: svn://svn.berlios.de/openocd/trunk@2740 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-20 dbrownell * : Enhancement: stm32 flash protection error message This patch modifies an error message which, in its original state, I find somewhat unhelpful. So a small hint was added. Signed-off-by: Johnny Halfmoon git-svn-id: svn://svn.berlios.de/openocd/trunk@2738 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-20 dbrownell * : Debug message updates: - Shrink messaging during resets, primarily by getting rid of "nothing happened" noise that hides *useful* information. - Improve: the "no IDCODE" message by identifying which tap only supports BYPASS; and the TAP event strings. Related minor code updates: - Remove two needless tests when examining the chain: we know we have a TAP, and that all TAPs have names. - Clean up two loops, turning "while"s into "for"s which better show what's actually being done. git-svn-id: svn://svn.berlios.de/openocd/trunk@2736 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-19 mlu * : Added CPUDBG_WCR_BASE define git-svn-id: svn://svn.berlios.de/openocd/trunk@2734 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-19 mlu * : Reduced sleep time after reset git-svn-id: svn://svn.berlios.de/openocd/trunk@2732 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-19 dbrownell * : Minor behavior fixes for the two JTAG reset events (C/internal, and Tcl/external): - Reorder so *both* paths (TCK/TMS or TRST) can enable TAPs with ICEpick ... first C code flags TAPs that got disabled, then call any Tcl code that might want to re-enable them. - Always call the C/internal handlers when JTAG operations can be issued; previously that wasn't done when TRST was used. Plus some small cleanups (whitespace, strings, better messaging during debug and on some errors) to reset-related code. git-svn-id: svn://svn.berlios.de/openocd/trunk@2730 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-18 mlu * : Move Cortex A8 debug access initialisation from omap3530.cfg to cortex_a8.c git-svn-id: svn://svn.berlios.de/openocd/trunk@2728 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-18 dbrownell * : Tweak TCL reset script ... mostly improving descriptions of the various steps, but also calling [target names] only once. git-svn-id: svn://svn.berlios.de/openocd/trunk@2726 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-17 dbrownell * : Minor fixes to NAND code and docs Erase logic: - command invocation + treat "nand erase N" (no offset/length) as "erase whole chip N" + catch a few more bogus parameter cases, like length == 0 (sigh) - nand_erase() should be static - on error + say which block failed, and if it was a bad block + don't give up after the first error; try to erase the rest - on success, say which nand device was erased (name isn't unique) Device list ("nand list"): - say how many blocks there are - split summary into two lines - give example in the docs Doc tweaks: - Use @option{...} for DaVinci's supported hardware ECC options For the record, I've observed that _sometimes_ erasing bad blocks causes failure reports, and that manufacturer bad block markers aren't always erasable (even when erasing their blocks doesn't trigger an error report). git-svn-id: svn://svn.berlios.de/openocd/trunk@2724 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-17 oharboe * : michal smulski fix regression in jtag_add_pathmove() which broke arm11 in r1825. Other uses of jtag_add_pathmove are svn + xsvf + xscale... git-svn-id: svn://svn.berlios.de/openocd/trunk@2722 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-17 oharboe * : srst_gates_jtag option. at91sam9260 needs retesting, and possibly srst_gates_jtag added to reset_config. Could i.MX27 be a case where srst does not pull trst, but really srst gates jtag clock? git-svn-id: svn://svn.berlios.de/openocd/trunk@2720 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-17 dbrownell * : Doc update: mention how ARM's WFI instruction affects JTAG clocking by gating the core clock, and workarounds. Most details are with the "halt" command, which is one of the first places this issue will be noticed. git-svn-id: svn://svn.berlios.de/openocd/trunk@2718 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-16 mlu * : Use a variable armv7a->debug_base instead of hardedcoded OMAP3530_DEBUG_BASE git-svn-id: svn://svn.berlios.de/openocd/trunk@2716 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-15 mlu * : Define debug_base, debug_ap, memory_ap in armv7a_common_t git-svn-id: svn://svn.berlios.de/openocd/trunk@2714 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-15 mlu * : Definy symbolic values for VA to PA address translation operations git-svn-id: svn://svn.berlios.de/openocd/trunk@2712 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-15 oharboe * : added embedded ice programming while srst is asserted todo item git-svn-id: svn://svn.berlios.de/openocd/trunk@2710 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-14 mlu * : Cache invalidation when writing to memory git-svn-id: svn://svn.berlios.de/openocd/trunk@2708 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-14 oharboe * : fix email address git-svn-id: svn://svn.berlios.de/openocd/trunk@2706 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-14 oharboe * : fix warning git-svn-id: svn://svn.berlios.de/openocd/trunk@2704 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-13 mlu * : More CortexA8 debug register definitions. git-svn-id: svn://svn.berlios.de/openocd/trunk@2702 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-12 oharboe * : Dirk Behme document post TAP reset event git-svn-id: svn://svn.berlios.de/openocd/trunk@2700 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-12 oharboe * : David Brownell Cleanup some the downloaded ARM target algorithm code: - Provide more complete disassembly of the DCC bulk write code - Make code blocks "static const", in case GCC doesn't - Fix some tabbing/layout issues - Make some arm7_9_common.h flags be "bool" not "int"; and compact the layout a bit (group most bools together) git-svn-id: svn://svn.berlios.de/openocd/trunk@2698 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-11 oharboe * : tap post reset event added. Allows omap3530 to send 100 runtest idle tickle's after a TAP_RESET. git-svn-id: svn://svn.berlios.de/openocd/trunk@2696 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-11 oharboe * : Nicolas Pitre put feroceon target definition at the end so to avoid a bunch of useless forward declarations. git-svn-id: svn://svn.berlios.de/openocd/trunk@2694 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-11 oharboe * : spelling mistake git-svn-id: svn://svn.berlios.de/openocd/trunk@2692 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-11 oharboe * : registering a target event twice caused infinite loop. Same bug as in jtag/core.c copy & pasted. git-svn-id: svn://svn.berlios.de/openocd/trunk@2690 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-11 oharboe * : Alexei Babich cleanup git-svn-id: svn://svn.berlios.de/openocd/trunk@2688 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-10 oharboe * : eol-style:native git-svn-id: svn://svn.berlios.de/openocd/trunk@2686 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-10 oharboe * : Alexei Babich fix problems with unecessary tailend byte accesses. Use 16 bit access on tailend of a memory read if possible. git-svn-id: svn://svn.berlios.de/openocd/trunk@2684 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-09 oharboe * : Rolf Meeser This patch adds target algorithm support for those flash devices that do not support DQ5 polling. So far they could only be programmed with host algorithm, but this was way too slow. git-svn-id: svn://svn.berlios.de/openocd/trunk@2682 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-09 oharboe * : David Brownell Optionally shave time off the armv4_5 run_algorithm() code: let them terminate using software breakpoints, avoiding roundtrips to manage hardware ones. Enable this by using BKPT to terminate execution instead of "branch to here" loops. Then pass zero as the exit address, except when running on an ARMv4 core. ARM7TDMI, ARM9TDMI, and derived cores now set a flag saying they're ARMv4. Use that mechanism in arm_nandwrite(), for about 3% speedup on a DaVinci ARM926 core; not huge, but it helps. Some other algorithms could use this too (mostly flavors of flash operation). git-svn-id: svn://svn.berlios.de/openocd/trunk@2680 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-08 mlu * : Report correct core instruction state for ARMv/A targets git-svn-id: svn://svn.berlios.de/openocd/trunk@2678 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-08 oharboe * : David Brownell Provide an "armv7a disassemble" command. Current omissions include VFP (except as coprocessor instructions), Neon, and various Thumb2 opcodes that are not available in ARMv7-M processors. git-svn-id: svn://svn.berlios.de/openocd/trunk@2676 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-07 mlu * : Improved handling of instruction set state, helps for debugging Thumb state. git-svn-id: svn://svn.berlios.de/openocd/trunk@2674 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-04 oharboe * : use "armv4_5 core_state arm" instead of soft_reset_halt, fewer side effects git-svn-id: svn://svn.berlios.de/openocd/trunk@2672 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-04 oharboe * : Dirk Behme Add default fall back freqency. git-svn-id: svn://svn.berlios.de/openocd/trunk@2670 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-04 oharboe * : Matt Hsu This patch simply enables the halting debug mode. By enabling this bit, the processor halts when a debug event such as breakpoint occurs. git-svn-id: svn://svn.berlios.de/openocd/trunk@2668 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-04 oharboe * : Matt Hsu Tidy up the bit-offset operation for DSCR register git-svn-id: svn://svn.berlios.de/openocd/trunk@2666 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-04 oharboe * : David Claffey get rid of reset recursion git-svn-id: svn://svn.berlios.de/openocd/trunk@2664 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-02 oharboe * : David Claffey tested with the Atheros reference design "PB44" git-svn-id: svn://svn.berlios.de/openocd/trunk@2662 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-09-01 ntfreak * : - fixes the incorrect info msg displayed during stellaris flash programming. git-svn-id: svn://svn.berlios.de/openocd/trunk@2660 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-31 duane * : Warning fix git-svn-id: svn://svn.berlios.de/openocd/trunk@2658 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-31 oharboe * : Ferdinand Postema config script for the MMnet1001 module from Propox. git-svn-id: svn://svn.berlios.de/openocd/trunk@2656 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-30 oharboe * : Dirk Behme Fix typo in help text. It has to be 'production_test' instead of 'production' here. git-svn-id: svn://svn.berlios.de/openocd/trunk@2654 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-30 oharboe * : David Brownell Remove duplicate check for flash write status. Via code review by Steve Grubb   Also minor fixes for the message from "fill": the byte count is unsigned, not signed; and more importantly, print the real number of bytes written git-svn-id: svn://svn.berlios.de/openocd/trunk@2652 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-30 oharboe * : David Brownell start phasing out integers as target IDs git-svn-id: svn://svn.berlios.de/openocd/trunk@2650 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-28 oharboe * : David Brownell fix warnings git-svn-id: svn://svn.berlios.de/openocd/trunk@2648 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-28 oharboe * : restore ICE watchpoint registers when the *last* software breakpoint is removed git-svn-id: svn://svn.berlios.de/openocd/trunk@2646 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-28 oharboe * : David Brownell ARM disassembly support for about five dozen non-Thumb instructions that were added after ARMv5TE was defined: - ARMv5J "BXJ" (for Java/Jazelle) - ARMv6 "media" instructions (for OMAP2420, i.MX31, etc) Compile-tested. This might not set up the simulator right for the ARMv6 single step support; only BXJ branches though, and docs to support Jazelle branching are non-public (still, sigh). ARMv6 instructions known to be mis-handled by this disassembler include: UMAAL, LDREX, STREX, CPS, SETEND, RFE, SRS, MCRR2, MRRC2 git-svn-id: svn://svn.berlios.de/openocd/trunk@2644 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-27 oharboe * : arm11 single stepping wip - at least we know the next PC now git-svn-id: svn://svn.berlios.de/openocd/trunk@2642 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-27 oharboe * : refactor arm simulator to allow arm11 code to use it as well - no observable changes otherwise. git-svn-id: svn://svn.berlios.de/openocd/trunk@2640 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-26 oharboe * : Matt Hsu and Holger Hans Peter Freyther cortex-a8: Wait for the CPU to be halted/started With DCCR we are asking the CPU to halt, we should wait until the CPU has halted before proceeding with the operation. git-svn-id: svn://svn.berlios.de/openocd/trunk@2638 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-26 oharboe * : Matt Hsu and Holger Hans Peter Freyther Only dap_ap_select when we are going to do a memory access in the fast reg case. git-svn-id: svn://svn.berlios.de/openocd/trunk@2636 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-26 oharboe * : Matt Hsu cortex_a8_exec_opcode is writing the ARM instruction into the ITR register but it will only be executed when the DSCR[13] bit is set. The documentation is a bit weird as it classifies the DSCR as read-only but the pseudo code is writing to it as well. This is working on a beagleboard. git-svn-id: svn://svn.berlios.de/openocd/trunk@2634 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-26 oharboe * : Matt Hsu and Holger Hans Peter Freyther Before executing a new instruction wait for the previous instruction to be finished. This comes from the pseudo code of the cortex a8 trm. git-svn-id: svn://svn.berlios.de/openocd/trunk@2632 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-26 oharboe * : added missing check on jtag_execute git-svn-id: svn://svn.berlios.de/openocd/trunk@2630 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-26 oharboe * : reduce arm11 output noise git-svn-id: svn://svn.berlios.de/openocd/trunk@2628 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-26 oharboe * : David Brownell Clock updates/fixes for the Stellaris flash driver: - Bugfixes: * internal osc: it's *12* MHz (not 15 MHz) on _current_ chips + except new Tempest parts where it's 16 MHz (and calibrated!) + or some old Sandstorm ones, where 15 MHz was valid * crystal config: + read and use the crystal config, don't assume 6 MHz + know when that field is 4 bits vs 5 * an RCC2 register may be overriding the original RCC + more clock source options + bigger dividers + fractional dividers on Tempest (NYET handled) * there's a 30 KHz osc on newer chips (for deep sleep) * there's a 32768 Hz osc on newer chips (for hibernation) - Cosmetic * say "rev A0" not "vA.0", to match vendor docs * don't always report master clock as an "estimate": + give the error bound if it's approximate, like "±30%" + else don't say anything * fix whitespace and caps in some messages * these are not AT91SAM chips!! Those clock issues might explain problems sometimes reported when writing to Stellaris flash banks; they affect write timings. That 12-vs-15 MHz issue is problematic; there's no consolidated doc showing which chips (and revs!) have which internal oscillator speed. It's clear that only older silicon had the faster-and-less-accurate flavor. What's less clear is which chips are "old" like that. Lightly tested, on a DustDevil part. git-svn-id: svn://svn.berlios.de/openocd/trunk@2626 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-25 oharboe * : David Brownell Tweak disassembly commands: For ARMv4/ARMv5: - better command parameter error checking - don't require an instruction count; default to one - recognize thumb function addresses - make function static - shorten some too-long lines For Cortex-M3: - don't require an instruction count; default to one With the relevant doc updates. --- Nyet done: invoke the thumb2 disassembler on v4/v5, to better handle branch instructions. git-svn-id: svn://svn.berlios.de/openocd/trunk@2624 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-25 oharboe * : David Brownell More jtag_add_reset() cleanup: Unify the handling of the req_tlr_or_trst parameter. Basically, JTAG TMS+TCK ops ("TLR") is always used ... unless TRST is a safe option in this system configuration. git-svn-id: svn://svn.berlios.de/openocd/trunk@2622 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-25 oharboe * : David Brownell Accomodate targets which don't support various target-specific reset operations. Maybe they can't; or it's a "not yet" thing. Note that the assert/deassert operations can't yet trigger for OMAP3 because resets currently include JTAG reset in all cases, resetting the ICEpick and thus disabling the TAP for Cortex-A8. git-svn-id: svn://svn.berlios.de/openocd/trunk@2620 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-25 ntfreak * : - fix build warnings - add svn props to recently added files armv7a.[ch] git-svn-id: svn://svn.berlios.de/openocd/trunk@2618 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-25 oharboe * : strange.... the code build and links w/Linux GCC target but fails w/arm-elf. The code was clearly broken as it was missing two extern's in the .h file... git-svn-id: svn://svn.berlios.de/openocd/trunk@2616 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-25 oharboe * : Ferdinand Postema increase reset delay to fix regression from 2600 to 2604 git-svn-id: svn://svn.berlios.de/openocd/trunk@2614 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-25 oharboe * : Audrius UrmanaviÄius Latest source (R2606) does not compile under Windows+Cygwin - fails with error about possibly uninitialized use of variable 'ch'. git-svn-id: svn://svn.berlios.de/openocd/trunk@2612 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-25 oharboe * : use cortex_a8 instead of cortex_m3 git-svn-id: svn://svn.berlios.de/openocd/trunk@2610 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-25 oharboe * : David Brownell Subset of Cortex-A8 support from Magnus: create an armv7a file and seed it with DAP access support using the current ADIv5 code. (With tweaks and cleanup from Øyvind and Dave.) The ARMv7-AR architecture manual is not publicly available (even in subset form like the ARMv7-M spec), so it's hard to distinguish between the Cortex-A8 implementation and the ARMv7-A architecture. The register set presumably is architectural, and so it's stored here; it's like earlier ARMs, with small additions. Ditto the instruction set, though Thumb2 support is used (extending Thumb support from ARMv6 with more 32-bit instructions) and there's this ThumbEE thing too. There is a new "debug monitor" mode, not yet fully addressed here, to support debugging in environments (like motor control) where halting debug mode is inadvisable. git-svn-id: svn://svn.berlios.de/openocd/trunk@2608 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-24 oharboe * : Steve Grubb fix various and sundry leaks git-svn-id: svn://svn.berlios.de/openocd/trunk@2606 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-21 oharboe * : Pieter Conradie shuffle things around to the right spots. Should have been done in previous commit. git-svn-id: svn://svn.berlios.de/openocd/trunk@2604 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-21 oharboe * : Pieter Conradie Scripts for Atmel AT91SAM7S256 and AT91SAM9260 git-svn-id: svn://svn.berlios.de/openocd/trunk@2602 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-20 oharboe * : Piotr Ziecik This patch adds handling blank characters between hex digits in SVF file, making OpenOCD compatible with files generated by Altera Quatrus II 9.0. git-svn-id: svn://svn.berlios.de/openocd/trunk@2600 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-20 oharboe * : David Brownell More Thumb2 disassembly: ARMv7-M: A5.3.6 Load/store dual or exclusive, table branch GCC will generate the table branch instructions, usually with inlined tables that will confuse this disassembler. LDREX and STREX are not issued by GCC without inline assembly. This means all Thumb2 instructions implemented by Cortex-M3 can now be disassembled. Cortex-A8 cores support more Thumb2 instructions, but most of those aren't yet publicly documented. git-svn-id: svn://svn.berlios.de/openocd/trunk@2598 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-19 oharboe * : David Brownell Fix some command helptext: - spell "address" right - list bp/wp params as optional And make those source lines wrap at sane margins. git-svn-id: svn://svn.berlios.de/openocd/trunk@2596 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-18 ntfreak * : David Brownell [david-b@pacbell.net]: Simplify dumping of register lists by only printing cached values if they are marked as valid. Most of the time, they are invalid; so printing *any* value is just misleading. Note that for ARM7 and ARM9 most EmbeddedICE registers (except for debug status) could be cached most of the time; and their register cache isn't maintained properly (many accesses seem to bypass that cache code). git-svn-id: svn://svn.berlios.de/openocd/trunk@2594 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-18 ntfreak * : - add cfg file for Amontec JTAGKey2 jtag interface git-svn-id: svn://svn.berlios.de/openocd/trunk@2592 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-18 ntfreak * : Jonas Horberg [jhorberg@sauer-danfoss.com] Change jtag_rclk behaviour so it can be called before the interface init function git-svn-id: svn://svn.berlios.de/openocd/trunk@2590 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-18 oharboe * : David Brownell Add "cortex_m3 vector_catch" command and docs. One minor issue with this is that the core debug support uses this mechanism, then trashes its state over reset. Users can Work around that (for now) by re-assigning the desired config after reset. Also fixes "target halted due to target-not-halted" goof. When we can't describe the reason using OpenOCD's limited vocabulary, say "reason undefined" instead of saying it's not halted. git-svn-id: svn://svn.berlios.de/openocd/trunk@2588 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-18 oharboe * : David Brownell Several of the ARMv7M registers are 8 bits or less; don't display them as 32 bits unless that's their true size. (Removes some confusion. git-svn-id: svn://svn.berlios.de/openocd/trunk@2586 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-16 oharboe * : Xiaofan Chen Split LM3S811 config file into target file and board file git-svn-id: svn://svn.berlios.de/openocd/trunk@2584 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-16 oharboe * : Xiaofan Chen Add config file for TI-Luminary LM3S1968 chip and EK-LM3S1968 board git-svn-id: svn://svn.berlios.de/openocd/trunk@2582 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-16 oharboe * : added note w/reference to discussion on whether or not arm11 code is broken or not. git-svn-id: svn://svn.berlios.de/openocd/trunk@2580 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-07 ntfreak * : David Brownell : Warn about anyone using "jtag_speed" commands; that command is obsolete, and will someday be removed. git-svn-id: svn://svn.berlios.de/openocd/trunk@2578 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-07 ntfreak * : Ferdinand Postema [ferdinand@postema.eu] - fix vector catch issues with certain ARM9 cores - AT91SAM9260 and STR9 git-svn-id: svn://svn.berlios.de/openocd/trunk@2576 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-06 ntfreak * : Gary Carlson [gcarlson@carlson-minot.com]: - revert patch from rev1507 as it was causing reset issues with arm9 cores git-svn-id: svn://svn.berlios.de/openocd/trunk@2574 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-08-06 zwelch * : michal smulski : Fix ARM11 half-word bulk memory read and write. git-svn-id: svn://svn.berlios.de/openocd/trunk@2572 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-27 oharboe * : Fix NPE in GDB_EVENT_END as logforwarding was not disabled early enough git-svn-id: svn://svn.berlios.de/openocd/trunk@2570 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-26 oharboe * : David Brownell More testcase work: A5.3.11 Data processing (shifted register) The usual kinds of problems; the most noteworthy were that the "S"et flags bit was mis-handled in these instructions. --- This is the last patch from a quickie set of tests covering all encodings of the instructions with 32-bit opcodes. There may be some corner cases left, plus the instructions that aren't yet handled, but the Thumb2 disassembler is no longer just "lightly" tested with GCC output ... the new code paths have mostly been verified. git-svn-id: svn://svn.berlios.de/openocd/trunk@2568 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-26 oharboe * : David Brownell More fixes from test cases: A5.3.8 Load halfword, unallocated memory hints It's mostly the usual sort of bitmasking goofage and getting the width specs right. In one case an older x86 GCC generated bad code unless I structred a conditional differently (sigh). git-svn-id: svn://svn.berlios.de/openocd/trunk@2566 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-24 oharboe * : David Brownell More instruction decoding fixes based on test cases, covering ARMv7-M arch manual: A5.3.1 Data processing (modified immediate) A5.3.3 Data processing (plain binary immediate) A5.3.4 Branches and miscellaneous control and other (immediate) encodings referenced there. Several of these just tweak the new syntax ("Unified" ARM/Thumb: UAL) but there were a few bugs too. git-svn-id: svn://svn.berlios.de/openocd/trunk@2564 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-24 oharboe * : Andreas Fritiofson I noticed there are a few checks for (rt == 0xf) even though that case is handled with an early return at the top of the function. git-svn-id: svn://svn.berlios.de/openocd/trunk@2562 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-23 oharboe * : David Brownell thumb2 disassembly for Load byte, memory hints git-svn-id: svn://svn.berlios.de/openocd/trunk@2560 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-23 oharboe * : David Brownell fix warnings git-svn-id: svn://svn.berlios.de/openocd/trunk@2558 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-22 oharboe * : Stefano Voulaz first cut samsung_s3c2450 git-svn-id: svn://svn.berlios.de/openocd/trunk@2556 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-21 ntfreak * : David Brownell : Clean up treatment of registers in ARMv7-M and Cortex-M3. - At the arch level: * Just list registers and names; don't impose core-specific policy about how they are accessed. * Each register has a symbol. * Remove the register mode field (irrelevant to debugger) - At the core/implementation level: * Just map the registers to their relevant access methods; don't require the arch level to say how that should work (cores other than Cortex-M3 could do it differently). * Don't use undefined bits from register 20. * Use register IDs that are part of the ARMv7-M interface. In short, there's now a real distinction between the arch and core layers. git-svn-id: svn://svn.berlios.de/openocd/trunk@2554 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-21 ntfreak * : David Brownell : Revert parts of the previous ARMv7-M register patch. It turns out that part of the issue is a documentation problem for the Cortex-M3 r1 parts. So for the rest, simpler fixes are possible (in followup patch). git-svn-id: svn://svn.berlios.de/openocd/trunk@2552 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-19 oharboe * : aduc flash problems have been resolved git-svn-id: svn://svn.berlios.de/openocd/trunk@2550 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-16 oharboe * : added item to come up with slick new 32 bit jtag_add_xxx() API git-svn-id: svn://svn.berlios.de/openocd/trunk@2548 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-16 oharboe * : microscopic white space fixes git-svn-id: svn://svn.berlios.de/openocd/trunk@2546 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-16 zwelch * : Magnus Lundin , Oyvind Harboe , David Brownell : Move the dap command handler implementations to arm_adi_v5.c, leaving just thin wrappers in armv7m.c. There should be no change in functionality here. (From Magnus.) Minor style cleanup: whitespace, line length, etc. Update spec references to use docs which are currently available. (From Dave.) git-svn-id: svn://svn.berlios.de/openocd/trunk@2544 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-15 zwelch * : David Brownell : More 32-bit Thumb2 instruction decoding: A5.3.7 Load word git-svn-id: svn://svn.berlios.de/openocd/trunk@2542 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-15 zwelch * : David Brownell : More 32-bit instruction decoding: A5.3.11 Data processing (shifted register) git-svn-id: svn://svn.berlios.de/openocd/trunk@2540 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-15 zwelch * : David Brownell : More instructions decoded: A5.3.14 Multiply, and multiply accumulate A5.3.15 Long multiply, long multiply accumulate, divide The EABI requires *adjacent* register pairs, but the long multiply ops can use any pair of registers; interesting. git-svn-id: svn://svn.berlios.de/openocd/trunk@2538 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-15 zwelch * : David Brownell : Print old-style Thumb NOP instructions as such. (GCC uses "mov r8, r8" instead of the architected NOP which is new in Thumb2.) git-svn-id: svn://svn.berlios.de/openocd/trunk@2536 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-15 zwelch * : David Brownell : Make the Thumb2 disassembler handle more 32-bit instructions: A5.3.3 Data processing (plain binary immediate) These use mostly twelve bit literals, but there are also bitfield and saturated add primitives. git-svn-id: svn://svn.berlios.de/openocd/trunk@2534 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-15 zwelch * : David Brownell : Make the Thumb2 disassembler handle a bunch of 32-bit instructions: A5.3.4 Branches and miscellaneous control Note that this shifts some responsabililty out of helper functions, making the code and layout simpler for 32-bit decoders: they only need to know how to format the instruction and its parameters. Also, technical note: with this patch, Thumb1 decoders could now call the Thumb2 decoder if they wanted to get nicer treatment of the exiting 32-bit B/BLX instructions. git-svn-id: svn://svn.berlios.de/openocd/trunk@2532 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-15 zwelch * : David Brownell : Initial support for disassembling Thumb2 code. This works only for Cortex-M3 cores so far. Eventually other cores will also need Thumb2 support ... but they don't yet support any kind of disassembly. - Update the 16-bit Thumb decoder: * Understand CPS, REV*, SETEND, {U,S}XT{B,H} opcodes added by ARMv6. (It already seems to treat CPY as MOV.) * Understand CB, CBNZ, WFI, IT, and other opcodes added by in Thumb2. - A new Thumb2 instruction decode routine is provided. * This has a different signature: pass the target, not the instruction, so it can fetch a second halfword when needed. The instruction size is likewise returned to the caller. * 32-bit instructions are recognized but not yet decoded. - Start using the current "UAL" syntax in some cases. "SWI" is renamed as "SVC"; "LDMIA" as "LDM"; "STMIA" as "STM". - Define a new "cortex_m3 disassemble addr count" command to give access to this disassembly. Sanity checked against "objdump -d" output; a bunch of the new instructions checked out fine. git-svn-id: svn://svn.berlios.de/openocd/trunk@2530 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-15 oharboe * : retire Eclipse settings, charset will be set elsewhere. git-svn-id: svn://svn.berlios.de/openocd/trunk@2528 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-14 oharboe * : David Brownell mention udev, and correct D2XX speed mentions git-svn-id: svn://svn.berlios.de/openocd/trunk@2526 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-14 oharboe * : 1.54 snapshot git-svn-id: svn://svn.berlios.de/openocd/trunk@2523 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-14 zwelch * : Bump minor version and add tag: Bump minor package version number: 0.2.0 -> 0.3.0 Add '-in-development' version tag: 0.3.0 -> 0.3.0-in-development git-svn-id: svn://svn.berlios.de/openocd/trunk@2521 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-14 zwelch * : Improve the release script before 0.2.0: 1) Only archive NEWS file on major and minor relesae, not bug-fixes. 2) Switch back to correct development branch during final release step. 3) Add do_svn_switch helper to ensure package variables are reloaded. git-svn-id: svn://svn.berlios.de/openocd/trunk@2516 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-14 zwelch * : Make the parport-ppdev option enabled by default. This may require giving --disable-parport-ppdev to configure on some platform(s). git-svn-id: svn://svn.berlios.de/openocd/trunk@2514 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-12 oharboe * : Xiaofan Chen document my experiment with MinGW cross build. git-svn-id: svn://svn.berlios.de/openocd/trunk@2512 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-12 oharboe * : Magnus Lundin Thc cortex_m3_poll function does not identify that a target is running unless we transition from RESET. This patch correctly identifies a running target. Patch made a tad more palatable by David Brownell git-svn-id: svn://svn.berlios.de/openocd/trunk@2510 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-12 oharboe * : David Brownell Mention how parallel clock voting implementations of RTCK work, and reference TI's free VHDL code. git-svn-id: svn://svn.berlios.de/openocd/trunk@2508 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-10 oharboe * : wrote up workaround for xscale/debug_handler.bin bug git-svn-id: svn://svn.berlios.de/openocd/trunk@2506 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-10 oharboe * : David Brownell split EK board support out from the target CPU support . git-svn-id: svn://svn.berlios.de/openocd/trunk@2504 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-08 zwelch * : Add section to provide some documentation for cross-compiling. git-svn-id: svn://svn.berlios.de/openocd/trunk@2502 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-08 zwelch * : Add comments to top-level files to "excuse" their Doxygen markup. git-svn-id: svn://svn.berlios.de/openocd/trunk@2500 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-08 oharboe * : fix formatting of xscale bug entry(learning every day) git-svn-id: svn://svn.berlios.de/openocd/trunk@2498 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-08 oharboe * : typo in comment git-svn-id: svn://svn.berlios.de/openocd/trunk@2496 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-08 oharboe * : i.MX27 reset problems fixed & update remaining reset problems notes git-svn-id: svn://svn.berlios.de/openocd/trunk@2494 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-07 oharboe * : srst pulls trst according to Freescale docs for i.mx27 git-svn-id: svn://svn.berlios.de/openocd/trunk@2492 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-07 oharboe * : Use reference to mailing list for known arm926ejs bugs rather fill The List with lots of details git-svn-id: svn://svn.berlios.de/openocd/trunk@2490 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-07 oharboe * : fix return value for "reset" and "runtest" command. Found by code inspection. git-svn-id: svn://svn.berlios.de/openocd/trunk@2488 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-07 oharboe * : more arm926ejs bugs git-svn-id: svn://svn.berlios.de/openocd/trunk@2486 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-06 oharboe * : David Brownell Update docs to say that "arm7_9 dbgrq enable" is the default on ARM9 cores, and update the DaVinci config files so they no longer explicitly specify it. git-svn-id: svn://svn.berlios.de/openocd/trunk@2484 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-06 ntfreak * : - fix build when using a cross compiler - do not try and run any host tools - add missing types.h when platform does not contain elf.h git-svn-id: svn://svn.berlios.de/openocd/trunk@2482 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-06 oharboe * : a bit more debug output for translation of invalid mode numbers git-svn-id: svn://svn.berlios.de/openocd/trunk@2480 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-06 oharboe * : Fix regression in "step" command introduced in 2190 git-svn-id: svn://svn.berlios.de/openocd/trunk@2478 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-06 zwelch * : Update Release Script documentation to reflect current implementation. git-svn-id: svn://svn.berlios.de/openocd/trunk@2476 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-06 zwelch * : Add NEWS file for the 0.2.0 release. git-svn-id: svn://svn.berlios.de/openocd/trunk@2474 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-06 zwelch * : Ferdinand Postema : Updates to private TAP state tables in amtjtagaccel interface driver. The first change is the neccesary one to correct a long-standing bug that caused the IDCODE to be shifted by one bit too many. This was caused by an incorrect path from state RESET to state DRSHIFT. The value of those 2 bytes were 0x8a and 0x04. This means that the bitstream to do this transition is 0b 00100 01010 (send LSB first). This will bring you from the reset state to the shift state; however, you enter the shift-state twice, which explains why the ID-CODE that will be read next will be shifted 1 bit. The fix changes these to 0x05 and 0x00. This will send the bitstream 0b 00101 (send LSB first). This will bring the TAP controller from the RESET state to the DRSHIFT state directly, without entering the DRSHIFT state twice. After checking the whole table, two other transitions were found that could be optimized (5 bits in stead of 10 bits). Summary off all changes: From To Old values Old Bitstream New values New Bitstream Remarks ---- ------- ---------- ------------- ---------- ------------- ------- RESET DRSHIFT 0x8a 0x04 0b00100 01010 0x05 0x00 0b00101 1,2 IDLE DRSHIFT 0x85 0x08 0b01000 00101 0x04 0x00 0b00100 2 IDLE IRSHIFT 0x8b 0x08 0b01000 01011 0x06 0x00 0b00110 2 [1] Fixes the IDCODE bug [2] Optimization git-svn-id: svn://svn.berlios.de/openocd/trunk@2472 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-06 oharboe * : 10ms timeout check on cp15 read/write git-svn-id: svn://svn.berlios.de/openocd/trunk@2470 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-06 zwelch * : Fix maintainer-clean target in doc directory. git-svn-id: svn://svn.berlios.de/openocd/trunk@2468 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-06 oharboe * : added known problem w/line number's being off in syntax errors for target reset events git-svn-id: svn://svn.berlios.de/openocd/trunk@2466 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-06 oharboe * : human readable error message upon invalid arguments git-svn-id: svn://svn.berlios.de/openocd/trunk@2464 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-04 zwelch * : Major update to release process documentation: - Provide overview of OpenOCD versioning schema. - Outline responsibilities and authority of the release manager. - Explain the need for flexibility in the release schedule. - Add and refine the release process steps. - Include tutorials for using new release script. - Many more improvements, too numerous to list. git-svn-id: svn://svn.berlios.de/openocd/trunk@2462 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-02 oharboe * : Xiaofan Chen With this patch, OpenOCD can talk to my Analog Device Eval-ADuC7060 eval board. git-svn-id: svn://svn.berlios.de/openocd/trunk@2459 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-02 zwelch * : Add AUTHORS for 0.2.0 release. git-svn-id: svn://svn.berlios.de/openocd/trunk@2457 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-02 zwelch * : Remove vim editor commands from TCL files. git-svn-id: svn://svn.berlios.de/openocd/trunk@2455 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-02 zwelch * : Commit first draft of release process documentation. git-svn-id: svn://svn.berlios.de/openocd/trunk@2453 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-02 oharboe * : zy1000 1.53 snapshot git-svn-id: svn://svn.berlios.de/openocd/trunk@2451 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-02 zwelch * : David Brownell : More minor improvements to README to help polish the 0.2.0 release: - Add note about Ubuntu 8.04 (in lieu of starting a README.Linux file). - Fix introductory paragraph to Bulding OpenOCD - Remove some vestigial texinfo markup. git-svn-id: svn://svn.berlios.de/openocd/trunk@2448 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-02 zwelch * : David Brownell : Restore some whitespace that got clobbered by over-aggressive whitepace eradication patches a while back. git-svn-id: svn://svn.berlios.de/openocd/trunk@2446 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-01 zwelch * : Add missing copyright header to target_type.h. git-svn-id: svn://svn.berlios.de/openocd/trunk@2444 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-01 zwelch * : Update TODO list to relect 0.2.0 release. git-svn-id: svn://svn.berlios.de/openocd/trunk@2442 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-07-01 ntfreak * : - add stm32 connectivity line tapid to stm32.cfg git-svn-id: svn://svn.berlios.de/openocd/trunk@2440 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-30 zwelch * : Remove at91sam3.h from flash.c; use extern like other drivers. git-svn-id: svn://svn.berlios.de/openocd/trunk@2438 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-30 zwelch * : Provide some useful information in README file, rather than punting. Add some text to introduce the project to new users. Move packaging, configuration, and compilation of OpenOCD out of the User's Guide and into README, where it can be used by users before configuring and compiling the documentation. Improve notes about required Subversion repository build steps. Add reference to the standard GNU INSTALL file. git-svn-id: svn://svn.berlios.de/openocd/trunk@2436 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-30 ntfreak * : - remove cygwin build warnings in at91sam3.c git-svn-id: svn://svn.berlios.de/openocd/trunk@2434 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-30 zwelch * : Remove executable bits from at91sam3 configuration files. git-svn-id: svn://svn.berlios.de/openocd/trunk@2432 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-30 zwelch * : Add svn:eol-style properties missed in last commit. git-svn-id: svn://svn.berlios.de/openocd/trunk@2430 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-30 zwelch * : David Brownell : Add "jtag names" command, mirroring "target names" but returning TAP names instead of target names. This starts letting TAPs be manipulated in scripts ... much like what works now for targets. It's a bit limited just yet, since "jtag cget $TAPNAME" doesn't expose all TAP attributes. "$TARGETNAME cget" is more functional. git-svn-id: svn://svn.berlios.de/openocd/trunk@2428 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-30 zwelch * : Fix doxygen 'undocumented parameter' warnings in membuf.h. git-svn-id: svn://svn.berlios.de/openocd/trunk@2426 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-30 zwelch * : Fix doxygen warning in jtag.h caused by a changed parameter name. git-svn-id: svn://svn.berlios.de/openocd/trunk@2424 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-30 zwelch * : Fix @file documentation blocks in new interfaces source files. git-svn-id: svn://svn.berlios.de/openocd/trunk@2422 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-30 zwelch * : Fix logger.pl script to avoid spurious empty line in some cases. git-svn-id: svn://svn.berlios.de/openocd/trunk@2420 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-29 zwelch * : David Brownell : Minor bugfix ... previous version was tested *with* ICEpick active. The "-disable" can swap with "-enable"; but not with an empty string. git-svn-id: svn://svn.berlios.de/openocd/trunk@2418 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-29 zwelch * : David Brownell : Improve the PXA255 target config: move all that board-specific setup to the pxa255_sst board.cfg, to which it evidently belongs (it's the only PXA255 board now included). Provide the PXA255 JTAG id from Intel docs, and add a comment about how this chip is now EOL'd (last orders taken). Note that I still can't get my old PXA255 board to work. There's something broken in the reset sequence, which is preventing the TAP from coming up at all. Old mailing list posts suggest this is a longstanding bug... git-svn-id: svn://svn.berlios.de/openocd/trunk@2416 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-29 zwelch * : David Brownell : Minor fixup to the User's Guide, primarily related to the handful of commands defined in "startup.tcl"; "help" was not previously documented. Also, be more consistent about "Config Command" definitions (and to be explicit about that doc convention). git-svn-id: svn://svn.berlios.de/openocd/trunk@2414 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-28 oharboe * : David Brownell various missing commands git-svn-id: svn://svn.berlios.de/openocd/trunk@2412 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-28 duane * : A bit more log detail about connections comming and going git-svn-id: svn://svn.berlios.de/openocd/trunk@2410 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-27 duane * : Add Breakpoint/Watchpoint unique ID to help debug hardware debug register leakage git-svn-id: svn://svn.berlios.de/openocd/trunk@2408 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-27 duane * : Switch to strotk() grr.... git-svn-id: svn://svn.berlios.de/openocd/trunk@2406 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-26 oharboe * : David Brownell Add a short chapter on boundary scan support, which currently just documents the SVF and XSVF commands. git-svn-id: svn://svn.berlios.de/openocd/trunk@2404 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-25 oharboe * : Oleksandr Tymoshenko simple watchpoint support for MIPS32/EJTAG (no value comparation yet). git-svn-id: svn://svn.berlios.de/openocd/trunk@2402 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-24 oharboe * : David Brownell Fix formatting bug in at91sam7 doc added with the at91sam3 support; and some formatting issues with sam7 and stm32 keyword params. Tweak at91sam3 docs. Remove ninth nibble from flash bank addresses, clarify "at91sam3 show" variants and that the flash bank layout is not needed as a parameter (unlike with sam7); formatting fixes. git-svn-id: svn://svn.berlios.de/openocd/trunk@2400 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-24 zwelch * : Remove whitespace at end of lines, step 2. - Replace '\s*$' with ''. git-svn-id: svn://svn.berlios.de/openocd/trunk@2398 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-24 zwelch * : Remove whitespace that occurs before ')'. - Replace '[ \t]*[)]' with ')'. git-svn-id: svn://svn.berlios.de/openocd/trunk@2396 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-24 zwelch * : - Fixes '[<>]' whitespace - Replace '\(\w\)\([<>]\)\(\w\)' with '\1 \2 \3'. git-svn-id: svn://svn.berlios.de/openocd/trunk@2394 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-24 zwelch * : - Fixes '+' whitespace - Replace '\(\w\)\(+\)\(\w\)' with '\1 \2 \3'. git-svn-id: svn://svn.berlios.de/openocd/trunk@2392 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-24 zwelch * : - Fixes '==' whitespace - Replace '\(\w\)\(==\)\(\w\)' with '\1 \2 \3'. git-svn-id: svn://svn.berlios.de/openocd/trunk@2390 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-24 zwelch * : - Replace 'switch(' with 'switch ('. git-svn-id: svn://svn.berlios.de/openocd/trunk@2388 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-24 zwelch * : - Replace 'if(' with 'if ('. git-svn-id: svn://svn.berlios.de/openocd/trunk@2386 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-24 zwelch * : Fix end-of-line style properties on newly added files. git-svn-id: svn://svn.berlios.de/openocd/trunk@2384 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-24 duane * : Add quick target - full cygwin builds take a long long long time, this shortens the edit/build/debug cycle git-svn-id: svn://svn.berlios.de/openocd/trunk@2382 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-23 zwelch * : Remove whitespace at end of lines, step 2. - Replace '\s*$' with ''. git-svn-id: svn://svn.berlios.de/openocd/trunk@2380 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-23 zwelch * : - Replace '){' with ') {'. git-svn-id: svn://svn.berlios.de/openocd/trunk@2378 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-23 zwelch * : Remove whitespace that occurs after '('. - Replace '([ \t]*' with '('. git-svn-id: svn://svn.berlios.de/openocd/trunk@2376 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-23 zwelch * : - Fixes '[|]' whitespace - Replace ')\([|]\)(' with ') \1 ('. - Replace ')\([|]\)\(\w\)' with ') \1 \2'. - Replace '\(\w\)\([|]\)(' with '\1 \2 ('. - Replace '\(\w\)\([|]\)\(\w\)' with '\1 \2 \3'. git-svn-id: svn://svn.berlios.de/openocd/trunk@2374 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-23 zwelch * : - Fixes '=' whitespace - Replace ')\(=\)\(\w\)' with ') \1 \2'. - Replace '\(\w\)\(=\)(' with '\1 \2 ('. - Replace '\(\w\)\(=\)\(\w\)' with '\1 \2 \3'. git-svn-id: svn://svn.berlios.de/openocd/trunk@2372 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-23 zwelch * : - Fixes '<<' whitespace - Replace ')\(<<\)\(\w\)' with ') \1 \2'. - Replace '\(\w\)\(<<\)(' with '\1 \2 ('. - Replace '\(\w\)\(<<\)\(\w\)' with '\1 \2 \3'. git-svn-id: svn://svn.berlios.de/openocd/trunk@2370 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-23 zwelch * : - Fixes '<=' whitespace - Replace '\(\w\)\(<=\)\(\w\)' with '\1 \2 \3'. git-svn-id: svn://svn.berlios.de/openocd/trunk@2368 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-23 zwelch * : - Fixes '&&' whitespace - Replace ')\(&&\)(' with ') \1 ('. - Replace '\(\w\)\(&&\)(' with '\1 \2 ('. - Replace '\(\w\)\(&&\)\(\w\)' with '\1 \2 \3'. git-svn-id: svn://svn.berlios.de/openocd/trunk@2366 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-23 zwelch * : - Fixes '[+]=' whitespace - Replace '\(\w\)\([+]=\)(' with '\1 \2 ('. - Replace '\(\w\)\([+]=\)\(\w\)' with '\1 \2 \3'. git-svn-id: svn://svn.berlios.de/openocd/trunk@2364 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-23 zwelch * : - Fixes '-=' whitespace - Replace '\(\w\)\(-=\)(' with '\1 \2 ('. - Replace '\(\w\)\(-=\)\(\w\)' with '\1 \2 \3'. git-svn-id: svn://svn.berlios.de/openocd/trunk@2362 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-23 zwelch * : - Replace 'for(' with 'for ('. git-svn-id: svn://svn.berlios.de/openocd/trunk@2360 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-23 zwelch * : - Replace 'while(' with 'while ('. git-svn-id: svn://svn.berlios.de/openocd/trunk@2358 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-23 oharboe * : update w/missing eCos definitions after latest round of compiler formatting warnings fixes git-svn-id: svn://svn.berlios.de/openocd/trunk@2356 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-22 zwelch * : David Brownell : This should be my last significant update of the User's Guide for this release. Mostly it's a rework of the config file chapter's presentation of board and target config files. - Give the new path for scripts! - Move board-config material out of the target-config section - Add more board-config info, notably for reset-init events - Link out of the board-config section to NAND, NOR, and Reset chapters - Emphasize target input vs. output naming conventions - Other textual improvements Plus some other updates, like adding my copyright (now that I've basically rewritten much of this). git-svn-id: svn://svn.berlios.de/openocd/trunk@2354 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-22 oharboe * : David Brownell Make the Hitex STM32-PerformanceStick board config behave better: source the STM32 target config instead of using a private clone git-svn-id: svn://svn.berlios.de/openocd/trunk@2352 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-21 ntfreak * : - fix break caused by r2208 when using --pipe option - issue is gdb stdin buffer gets full before we redirect openocd output git-svn-id: svn://svn.berlios.de/openocd/trunk@2350 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-21 zwelch * : Oleksandr Tymoshenko : Resume command works only if resume address is provided. git-svn-id: svn://svn.berlios.de/openocd/trunk@2348 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-21 duane * : C99 printf() -Werror fixes git-svn-id: svn://svn.berlios.de/openocd/trunk@2346 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-21 duane * : C99 printf() -Werror fixes git-svn-id: svn://svn.berlios.de/openocd/trunk@2344 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-21 duane * : C99 printf() -Werror fixes git-svn-id: svn://svn.berlios.de/openocd/trunk@2342 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-21 duane * : C99 printf() -Werror fixes git-svn-id: svn://svn.berlios.de/openocd/trunk@2340 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-21 duane * : C99 printf() -Werror fixes git-svn-id: svn://svn.berlios.de/openocd/trunk@2338 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-21 duane * : C99 printf() -Werror fixes git-svn-id: svn://svn.berlios.de/openocd/trunk@2336 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-21 duane * : C99 printf() -Werror fixes git-svn-id: svn://svn.berlios.de/openocd/trunk@2334 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-21 duane * : C99 printf() -Werror fixes git-svn-id: svn://svn.berlios.de/openocd/trunk@2332 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-21 duane * : C99 printf() -Werror fixes git-svn-id: svn://svn.berlios.de/openocd/trunk@2330 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-21 duane * : C99 printf() -Werror fixes git-svn-id: svn://svn.berlios.de/openocd/trunk@2328 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-21 duane * : C99 printf() -Werror fixes git-svn-id: svn://svn.berlios.de/openocd/trunk@2326 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-21 duane * : C99 printf() -Werror fixes git-svn-id: svn://svn.berlios.de/openocd/trunk@2324 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-21 duane * : C99 printf() -Werror fixes git-svn-id: svn://svn.berlios.de/openocd/trunk@2322 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-21 duane * : C99 printf() -Werror fixes git-svn-id: svn://svn.berlios.de/openocd/trunk@2320 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-21 duane * : C99 printf() -Werror fixes git-svn-id: svn://svn.berlios.de/openocd/trunk@2318 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-21 duane * : C99 printf() -Werror fixes git-svn-id: svn://svn.berlios.de/openocd/trunk@2316 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-21 duane * : C99 printf() -Werror fixes git-svn-id: svn://svn.berlios.de/openocd/trunk@2314 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-21 duane * : C99 printf() -Werror fixes git-svn-id: svn://svn.berlios.de/openocd/trunk@2312 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-21 duane * : C99 printf() -Werror fixes git-svn-id: svn://svn.berlios.de/openocd/trunk@2310 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-21 duane * : C99 printf() -Werror fixes git-svn-id: svn://svn.berlios.de/openocd/trunk@2308 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-21 duane * : C99 printf() -Werror fixes git-svn-id: svn://svn.berlios.de/openocd/trunk@2306 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-21 duane * : C99 printf() -Werror fixes git-svn-id: svn://svn.berlios.de/openocd/trunk@2304 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-21 duane * : C99 printf() -Werror fixes git-svn-id: svn://svn.berlios.de/openocd/trunk@2302 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-21 duane * : C99 printf() -Werror fixes git-svn-id: svn://svn.berlios.de/openocd/trunk@2300 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-21 duane * : C99 printf() -Werror fixes git-svn-id: svn://svn.berlios.de/openocd/trunk@2298 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-21 duane * : C99 Type updates, include inttypes.h - it is catagorically required git-svn-id: svn://svn.berlios.de/openocd/trunk@2296 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-19 zwelch * : Remove editor preferences from source files. git-svn-id: svn://svn.berlios.de/openocd/trunk@2294 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-19 zwelch * : Paulius Zaleckas : This is minimal patch to support FA526 ARMv4 compatible core. Since it is very similar to ARM920T I tried to reuse as much code as possible. CPU and board configs will follow soon. git-svn-id: svn://svn.berlios.de/openocd/trunk@2292 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-19 oharboe * : fix jtag_add_callback() args. The first argument is nothing special, it's just another generic argument. git-svn-id: svn://svn.berlios.de/openocd/trunk@2290 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-18 oharboe * : less warnings git-svn-id: svn://svn.berlios.de/openocd/trunk@2288 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-18 zwelch * : Oyvind Harboe : Ecos uses sys/types.h not stdint.h. git-svn-id: svn://svn.berlios.de/openocd/trunk@2286 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-18 zwelch * : Update Style Guide documentation to explain basic type rules. git-svn-id: svn://svn.berlios.de/openocd/trunk@2284 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-18 zwelch * : Transform 'u64' to 'uint64_t' - Replace '\([^_]\)u64' with '\1uint64_t'. git-svn-id: svn://svn.berlios.de/openocd/trunk@2282 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-18 zwelch * : Transform 'u32' to 'uint32_t' in src/flash. - Replace '\([^_]\)u32' with '\1uint32_t'. git-svn-id: svn://svn.berlios.de/openocd/trunk@2280 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-18 zwelch * : Transform 'u32' to 'uint32_t' in src/target/arm* - Replace '\([^_]\)u32' with '\1uint32_t'. - Replace '^u32' with 'uint32_t'. git-svn-id: svn://svn.berlios.de/openocd/trunk@2278 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-18 zwelch * : Transform 'u8' to 'uint8_t' - Replace '\([^_]\)u8' with '\1uint8_t'. - Replace '^u8' with 'uint8_t'. git-svn-id: svn://svn.berlios.de/openocd/trunk@2276 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-18 zwelch * : Transform 'u8' to 'uint8_t' in src/target - Replace '\([^_]\)u8' with '\1uint8_t'. - Replace '^u8' with 'uint8_t'. git-svn-id: svn://svn.berlios.de/openocd/trunk@2274 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-18 zwelch * : David Brownell : Clean up the PLD files: - Get rid of some extraneous whitespace - Make various functions static - Wrap overlong lines git-svn-id: svn://svn.berlios.de/openocd/trunk@2272 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-18 zwelch * : David Brownell : Take a whack at providing some texinfo style docs. Mostly it's just basic "how 2 write sane dox" stuff. git-svn-id: svn://svn.berlios.de/openocd/trunk@2270 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-17 oharboe * : dummy driver now works under eCos git-svn-id: svn://svn.berlios.de/openocd/trunk@2268 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-17 zwelch * : David Brownell : Fix for a goofy "board" config ... reuse target/pxa270.cfg instead of using a private copy. git-svn-id: svn://svn.berlios.de/openocd/trunk@2266 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-17 zwelch * : David Brownell : Let jtag_call_event_callbacks() behave when the callback removes itself. Oddly, this crashed on x86_32 but not x86_64. git-svn-id: svn://svn.berlios.de/openocd/trunk@2264 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-17 zwelch * : Fix compilation for Ubuntu 9.04 on x86-64 when using --enable-httpd. git-svn-id: svn://svn.berlios.de/openocd/trunk@2262 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-17 zwelch * : Ensure range errors are reported only when errno indicates one occurred. git-svn-id: svn://svn.berlios.de/openocd/trunk@2260 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-17 zwelch * : Add argument parsing errors in command.h, use in parse_type routines. git-svn-id: svn://svn.berlios.de/openocd/trunk@2258 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-17 zwelch * : Convert core parse_type implementations to check for underflow errors. git-svn-id: svn://svn.berlios.de/openocd/trunk@2256 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-17 zwelch * : Update parse_type macro definitions to allow re-use with signed types. git-svn-id: svn://svn.berlios.de/openocd/trunk@2254 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-16 zwelch * : David Brownell : Fix a bug preventing ICEpick "enable that TAP" code from working: the "runtest" command wrongly finished with a JTAG reset, discarding the work the TAP enable handler just finished! Instead, JTAG should stay in RUN/IDLE state. git-svn-id: svn://svn.berlios.de/openocd/trunk@2252 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-16 zwelch * : David Brownell : Tighten error handling on TAP enable/disable paths a bit: - Don't enable/disable unless it's necessary. Those event handlers could have nasty side effects... - Don't *succeed* enables/disables if there was no code which could have implemented that action. This prevents bugs like wrongly acting as if the scan chain changed. - Minor whitespace cleanup in enable/disable command code. The big problem is still the lack of code to verify scan chains were actually updated as requested; this adds a comment on that. I suspect the best we can do near term will be to verify IDCODE. git-svn-id: svn://svn.berlios.de/openocd/trunk@2250 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-16 zwelch * : David Brownell : Distributing FTDI's "ftd2xx" library with OpenOCD violates the OpenOCD license (GNU GPLv2 with no exceptions). Make that clear where that build option is presented, and don't describe the FTDI libraries as an option for any packager. (It's fine for personal use, of course.) Plus some related clarifications: libftdi version 0.16 for the new FT2232H chips (for RTCK and high speed USB); the Amontec drivers are just ftd2xx variants. git-svn-id: svn://svn.berlios.de/openocd/trunk@2248 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-16 zwelch * : David Brownell : Doc update: say "jtag newtap ... -disable" records the state after exiting the RESET state, matching the only implementation we're working with so far (TI ICEpick-C). Matching code updates. Now we can be sure that the "enabled" flag value is correct after JTAG resets. git-svn-id: svn://svn.berlios.de/openocd/trunk@2246 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-16 zwelch * : David Brownell : Minor jtag cleanup: - remove hidden assumption about JTAG event numbering - move function declarations to a header - some end'o'line whitespace - use "calloc" not "malloc + memset" git-svn-id: svn://svn.berlios.de/openocd/trunk@2244 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-15 zwelch * : David Brownell : Add another board ... OMAP2420 "H4" board. This won't be very widely used with OpenOCD, but with mainline support in both U-Boot and Linux it at least makes for a more complete set (and another testcase). This is incomplete support in several respects. The ARM11 support is not very deep yet; most registers aren't available, and the ETM can't be hooked up. Plus, there's no script for OMAP-specific stuff like setting up the SDRAM controller. Eventually the same NAND controller driver should work with OMAP2 and OMAP3. git-svn-id: svn://svn.berlios.de/openocd/trunk@2242 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-13 zwelch * : David Brownell : OpenOCD doesn't actually *need* to be keeping all TCP ports active ... creating security issues in some network configs. Instead, let config file specify e.g. "tcl_port 0" (or gdb_port, telnet_port) to disable that particular remote access method. git-svn-id: svn://svn.berlios.de/openocd/trunk@2240 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-13 zwelch * : Improve handle_profile_command argument parsing: - Use parse_uint to ensure timeout value parses properly. git-svn-id: svn://svn.berlios.de/openocd/trunk@2238 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-13 zwelch * : Cleanup and improve handle_wp_command and handle_rwp_command: - Simplify argument parsing logic using switch statement. - Use parse_u32 to ensure all values parse properly. - Return syntax error when mode argument fails to parse. git-svn-id: svn://svn.berlios.de/openocd/trunk@2236 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-13 zwelch * : Improve handle_verify_image_command_internal command argument handling: - Use parse_u32 to ensure address parses properly. git-svn-id: svn://svn.berlios.de/openocd/trunk@2234 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-13 zwelch * : Improve handle_load_image_command argument parsing: - Use parse_u32 to ensure base/min/max addresses parse properly. git-svn-id: svn://svn.berlios.de/openocd/trunk@2232 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-13 zwelch * : Improve handle_md_command argument handling: - Use parse_u32 and parse_uint for address and count, respectively. git-svn-id: svn://svn.berlios.de/openocd/trunk@2230 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-13 zwelch * : Cleanup and improve handle_halt_command: - Make argument check use parse_uint to ensure value parses properly. - Move variable declarations to location of first use. git-svn-id: svn://svn.berlios.de/openocd/trunk@2228 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-13 zwelch * : Use parse_uint in handle_reg_command to ensure reg number parses properly. git-svn-id: svn://svn.berlios.de/openocd/trunk@2226 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-12 zwelch * : David Brownell : Currently the "debug_level 3" command tracing ignores commands that could return values to TCL scripts (by plugging in to a slightly lower level of the interpreter stack). Fix that by abstracting the tracing command and starting to make some of those previously-untraced commands use this new mechanism. git-svn-id: svn://svn.berlios.de/openocd/trunk@2224 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-12 zwelch * : David Brownell : Partial fix to the "long IR length" problems. - Current code could handle up to 32 bit IR lengths with full functionality, if it didn't just reject may of them out of hand. So only reject clear errors, where the IR mask (or capture instruction) needs more than IrLen bits. - Longer IR lengths can only be handled in BYPASS mode for now. Example: TI's DSPs use 38-bit IR lengths. So we can't issue their IDCODE instructions... A more complete fix would be able to issue longer instructions; or minimally, would fail cleanly for the non-BYPASS case. Note that this *could* make some currently broken scripts fail, since the previous code accepted garbage values so long as they didn't use more than 16 bits. git-svn-id: svn://svn.berlios.de/openocd/trunk@2222 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-12 zwelch * : Further cleanup to MIPS target read/write memory function: - Move the mips32_..._read_mem calls to top-level of read_mem function. - Change: Only perform mips_m4k_read_mem conversion when retval == ERROR_OK. - Prevents pointless conversions of bogus read values after failures. - Eliminate retval variable from mips_m4k_write_mem; return directly. - Move declaration of retval variable to point of first use. - Remove the now redundant switch statements testing size: - argument sanitizing already covers these cases. git-svn-id: svn://svn.berlios.de/openocd/trunk@2220 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-12 zwelch * : Fix unitialized use of cur_speed in handle_jtag_khz_command: - Use the default KHz speed setting, in case interface is not initialized. git-svn-id: svn://svn.berlios.de/openocd/trunk@2218 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-12 zwelch * : Improve handle_runtest_command: - Use parse_uint helper to ensure argument is parsed properly. git-svn-id: svn://svn.berlios.de/openocd/trunk@2216 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-12 zwelch * : Improve handle_irscan_command: - Use parse_u32 helper to ensure scan values are parsed properly. - Clear the fields buffer to ensure partial cleanup occur correctly. git-svn-id: svn://svn.berlios.de/openocd/trunk@2214 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-12 zwelch * : Use parse_uint helper to replace strtoul call in jtag_tap_by_string. git-svn-id: svn://svn.berlios.de/openocd/trunk@2212 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-12 zwelch * : Simplify and improve amt_jtagaccel_handle_parport_port_command: - Show the port number to the user when asking for it or setting it. - Print an error if the amt_jtagaccel_port has already been set. - Use parse_u16 helper to ensure amt_jtagaccel_port string parses correctly. git-svn-id: svn://svn.berlios.de/openocd/trunk@2210 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-12 zwelch * : Simplify and improve handle_debug_level_comamnd: - Bug fix: Return a syntax error if more than one argument is given. - Bug fix: Use new parse_uint helper ensure debug_level parses correctly. - Change: Display the debug_level after it has been set. - Simplify bounds checking of debug_level. git-svn-id: svn://svn.berlios.de/openocd/trunk@2208 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-12 zwelch * : Add new parse_uinttype wrappers for strtoul in src/helper/command.[ch]. - Used to improve command argument parsing of unsigned integers values. git-svn-id: svn://svn.berlios.de/openocd/trunk@2206 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-11 zwelch * : David Brownell : Rework the "Simple Configuration Files" chapter so it's more of a quick-start "how to set up your project" tutorial: - Say how to hook up the JTAG adapter. This will help new users, and in any case is worth spelling out somewhere. - Streamline the previous rather haphazard presentation, filling in some missing holes along the way: * Suggest "project directory" structure * Introduce new term, "user config" file (openocd.cfg) * Talk about more options for openocd.cfg contents * ... and about creating new config files * Add new topic, project-specific utilities (+examples) - Remove too-short, yet duplicative, chapter 19 Nudge packagers a bit more strongly to send patches (including config files) upstream. git-svn-id: svn://svn.berlios.de/openocd/trunk@2204 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-11 ntfreak * : - fix bug introduced during r1962 - Original patch submitted by David Claffey [dnclaffey@gmail.com]. git-svn-id: svn://svn.berlios.de/openocd/trunk@2202 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-11 oharboe * : fix ordering of arguments to fwrite() git-svn-id: svn://svn.berlios.de/openocd/trunk@2197 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-11 zwelch * : Factor target_timer_callbacks_check_time into pieces: - Add target_timer_callback_periodic_restart and target_call_timer_callback. - Clean up and simplify logic that determines whether to call each callback. - Move variable declarations to location of first use. git-svn-id: svn://svn.berlios.de/openocd/trunk@2195 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-11 zwelch * : Simplify and fix target handle_rwp_command routine: - Return syntax error unless exactly one argument is passed. - Move variable declaration to point of first use. git-svn-id: svn://svn.berlios.de/openocd/trunk@2193 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-11 zwelch * : Simplify handle_resume_command: - Eliminate redundant calls to target_resume with addr temp variable. - Place variables at location of first use. - Fix minor whitespace issues. git-svn-id: svn://svn.berlios.de/openocd/trunk@2191 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-11 zwelch * : Move jtag_get_flush_queue_count near jtag_execute_queue (fix its docs). git-svn-id: svn://svn.berlios.de/openocd/trunk@2189 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-11 zwelch * : Group JTAG reset configuration and accessor APIs together in header file. Remove unused reset_line_mode enumerated type. git-svn-id: svn://svn.berlios.de/openocd/trunk@2187 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-11 zwelch * : Out-of-line jtag_tap_next_enabled and simplify its logic. git-svn-id: svn://svn.berlios.de/openocd/trunk@2185 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-11 oharboe * : disable polling continuous polling during reset git-svn-id: svn://svn.berlios.de/openocd/trunk@2183 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-10 ntfreak * : - fix texi/pdf issue created in svn r2039 git-svn-id: svn://svn.berlios.de/openocd/trunk@2181 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-10 zwelch * : David Brownell : Tweak the csb337 code so that it doesn't enable alignment traps when it completes the "reset init" sequence. It turns out that the current CFI code reliably triggers such traps. git-svn-id: svn://svn.berlios.de/openocd/trunk@2179 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-09 zwelch * : Improve use of automake conditionals for FTDI-based JTAG drivers: - Remove once-used XXX_FTD2XX symbols; replace with XXX_DRIVER symbols. - Enabled when either libftdi or FTD2xx driver should be built. - Eliminates redundant DRIVERSFILE assignment in JTAG automake input. git-svn-id: svn://svn.berlios.de/openocd/trunk@2177 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-09 zwelch * : Rename jtag_driver.c as driver.c to remove duplicate name component. git-svn-id: svn://svn.berlios.de/openocd/trunk@2175 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-09 oharboe * : reset to eol native for now. guess-rev.sh was broken by eol native, but it was a red herring that these two files were affected. git-svn-id: svn://svn.berlios.de/openocd/trunk@2173 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-09 zwelch * : Encapsulate the core jtag interface pointer: - Add new jtag_config_khz to increase encapsulation of jtag->khz call. - Add new jtag_get_speed_readable to encapsulate of jtag->speed_div call. - Make definition of jtag static in core.c, remove extern from tcl.c. git-svn-id: svn://svn.berlios.de/openocd/trunk@2171 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-09 zwelch * : Continue encapsulation of JTAG event callback sub-API: - Move jtag_event_callbacks struct to core.c; it's an implementation detail. - Move jtag_*_event_callbacks next to the definition of the new function type. git-svn-id: svn://svn.berlios.de/openocd/trunk@2169 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-09 zwelch * : Expose jtag_unregister_event_callback with related API declarations. git-svn-id: svn://svn.berlios.de/openocd/trunk@2167 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-09 zwelch * : Properly encapsulate core hasKHZ variable. git-svn-id: svn://svn.berlios.de/openocd/trunk@2165 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-09 zwelch * : Add missing static keywords to a few variables in JTAG core module. git-svn-id: svn://svn.berlios.de/openocd/trunk@2163 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-09 zwelch * : Encapsulate jtag_reset_config using accessors: - Update handle_reset_config_command in tcl.c to use new helpers. - Replace direct accesses in JTAG interface and target drivers. git-svn-id: svn://svn.berlios.de/openocd/trunk@2161 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-09 zwelch * : Add get and set accessors for jtag_speed: - Setter calls the interface driver callback to improve core encapsulation. - Use getter in standard JTAG interface drivers and ZY1000 minidriver. git-svn-id: svn://svn.berlios.de/openocd/trunk@2159 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-09 zwelch * : Encapsulate the jtag_trst and jtag_srst variables: - Add accessor functions to return their value. - Use new SRST accessor in cortex_m3.c and mips_m4k.c git-svn-id: svn://svn.berlios.de/openocd/trunk@2157 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-09 zwelch * : Remove superfluous extern of jtag_event_strings from jtag.h. git-svn-id: svn://svn.berlios.de/openocd/trunk@2155 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-09 oharboe * : removed native line end style - breaks cygwin git-svn-id: svn://svn.berlios.de/openocd/trunk@2153 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-09 zwelch * : Remove accidental duplicate of hasKHz; fixes pre-init speed setup. git-svn-id: svn://svn.berlios.de/openocd/trunk@2151 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-09 zwelch * : Split main jtag.c file into two layers: - src/jtag/core.c: contains the low-level JTAG TAP and scanning routines. - src/jtag/tcl.c: contains high-level JTAG TCL commands that use the core. - Remove static keywords from routines in core.c, extern from tcl.c: - jtag, jtag_interface global variables - jtag_{examine,validate}_chain and jtag_tap_{init,free} functions - Added myself to the copyright header in both of these files. - Used 'svn cp' to add files, so versioning was preserved for both. git-svn-id: svn://svn.berlios.de/openocd/trunk@2149 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-09 zwelch * : Move Doxygen documentation for IR/DR scan routines to header file. - Move plain IR scan declaration closer to the other IR scan declarations. git-svn-id: svn://svn.berlios.de/openocd/trunk@2147 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-09 zwelch * : Remove non-existant jtag_tap_by_position API declaration. git-svn-id: svn://svn.berlios.de/openocd/trunk@2145 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-09 zwelch * : Cleanup jtag_tap_by_abs_position: - Remove unused orig_n local variable. - Merge variable declaration with first use. - Update code to use current style guidelines. git-svn-id: svn://svn.berlios.de/openocd/trunk@2143 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-09 zwelch * : Simplify and fix bug in jtag_tap_by_string: - Bug fix: Use unsigned type and strtoul when parsing for position number. - Simplify logic by returning directly when a tap is found by name. - Reduce scope: declare temporary variables with first use. - Bring code up to current style guidelines. git-svn-id: svn://svn.berlios.de/openocd/trunk@2141 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-09 zwelch * : Cleanup jtag_tap_count_enabled. git-svn-id: svn://svn.berlios.de/openocd/trunk@2139 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-09 zwelch * : Reduce scope or eliminate temporary variables in jtag_add_statemove: - Change types of tms_bits and tms_count to unsigned, eliminates a cast. - Use moves[] only if needed; a single move can use goal_state directly. - Declare loop induction variable inside its control statement. - Remove retval in favor of direct returns. git-svn-id: svn://svn.berlios.de/openocd/trunk@2137 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-09 zwelch * : Revert changes from r2134 that snuck into the commit. Mea culpa. git-svn-id: svn://svn.berlios.de/openocd/trunk@2135 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-08 kc8apf * : Fix eol-style on guess-rev.sh git-svn-id: svn://svn.berlios.de/openocd/trunk@2133 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-08 oharboe * : Zach Welch wrote a fix for configure problems under Cygwin. ltmain.sh is added to svn ignore git-svn-id: svn://svn.berlios.de/openocd/trunk@2131 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-08 zwelch * : Factor interface list to its own command: - Add handle_interface_list_command, used by handle_interface_command. - Display output of new list to command console. - Change first index of displayed drivers to 1; it's only cosmetic. git-svn-id: svn://svn.berlios.de/openocd/trunk@2129 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-08 zwelch * : Simplify jtag_add_sleep: - Add todo for removing keep_alive: is this a layering violation? - Use jtag_set_error instead of accessing jtag_error directly. - Remove superfluous retval temporary variable and empty return. git-svn-id: svn://svn.berlios.de/openocd/trunk@2127 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-08 zwelch * : Simplify jtag_add_clocks: - Use jtag_set_error instead of accessing jtag_error directly. - Improve error language and whitespace. git-svn-id: svn://svn.berlios.de/openocd/trunk@2125 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-08 zwelch * : Simplify jtag_add_pathmove: - Use jtag_set_error instead of accessing jtag_error directly. - Eliminate superfluous retval temporary variable. - Reduce scope of loop induction variable. - Wrap to fit within 80 columns. git-svn-id: svn://svn.berlios.de/openocd/trunk@2123 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-08 zwelch * : Simplify jtag_add_plain_dr_scan: - Use jtag_set_error instead of accessing jtag_error directly. - Wrap function arguments to fit everything in 80 columns. - Move retval variable to location of first use. git-svn-id: svn://svn.berlios.de/openocd/trunk@2121 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-08 zwelch * : Simplify jtag_add_plain_ir_scan: - Use jtag_set_error instead of accessing jtag_error directly. - Wrap function arguments to fit everything in 80 columns. git-svn-id: svn://svn.berlios.de/openocd/trunk@2119 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-08 zwelch * : Simplify jtag_execute_queue: - Add static inline jtag_error_clear helper to return and clear jtag_error. - Use new helper to shrink body of function to two lines. git-svn-id: svn://svn.berlios.de/openocd/trunk@2117 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-08 zwelch * : Cleanup handle_runtest_command: - Make command argument require exactly one argument; do not allow extras. - Remove superfluous whitespace at end of function. - Wrap function arguments to fit in 80 columns. git-svn-id: svn://svn.berlios.de/openocd/trunk@2115 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-08 zwelch * : Extend handle_jtag_n{s,t}rst_delay_command routines: - Add support to display the reset delays too, like the other commands. - Always show the values, so users can see if they are being redundant. git-svn-id: svn://svn.berlios.de/openocd/trunk@2113 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-08 zwelch * : Update JTAG reset delay command handlers: - Fixes for error handling: - Return a syntax error instead of calling exit(-1). - Return error when more than one argument is provided too. - Remove useless braces and indent after the if/return statements. - Wrap function arguments to fit in 80 columns. git-svn-id: svn://svn.berlios.de/openocd/trunk@2111 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-08 zwelch * : Simplify logic in handle_jtag_speed_command. git-svn-id: svn://svn.berlios.de/openocd/trunk@2109 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-08 oharboe * : David Brownell - Don't let disabled TAPs be set as the current target - Improve "targets" output: * Remove undesirable "chain position" number; we discourage using them * TAP and Target column updates: + make them long enough for current usage + improve labels, removing guesswork + "TapName" label patches scan_chain output * Highlight the "current" target * Display "tap disabled" as a new pseudo-state * Update docs accordingly git-svn-id: svn://svn.berlios.de/openocd/trunk@2107 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-08 zwelch * : Reorder configure script macros: - Check for a compiler before looking for libraries or header files. - Initialize automake before calling other AM_ macros. - Disable libtool shared libraries by default. - Remove checks for unused C++, Fortran, and Java compilers. - Remove redundant AC_CANONICAL_HOST; called by AC_PROG_LIBTOOL. git-svn-id: svn://svn.berlios.de/openocd/trunk@2105 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-08 zwelch * : Move minidummy source file, as was supposed to happen in last commit. git-svn-id: svn://svn.berlios.de/openocd/trunk@2103 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-07 zwelch * : Fix reference warning in JTAG primer, add another external reference. git-svn-id: svn://svn.berlios.de/openocd/trunk@2101 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-07 zwelch * : David Brownell : Clarify docs for the evb_lm3s811 layout: works in two modes, not just one. git-svn-id: svn://svn.berlios.de/openocd/trunk@2099 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-07 zwelch * : David Brownell : Rework chapter 12 (CPU configuration) to use @deffn, match the code more closely, and present things more clearly. Includes the *current* list of targets. git-svn-id: svn://svn.berlios.de/openocd/trunk@2097 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-07 oharboe * : retire endstate command git-svn-id: svn://svn.berlios.de/openocd/trunk@2095 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-07 zwelch * : Fix regressions in previous series of cleanp, caused by r2092. git-svn-id: svn://svn.berlios.de/openocd/trunk@2093 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-07 zwelch * : Factoring of jtag_examine_chain for maintainability: - Improve variable type: change device_count to unsigned. - Improves jtag_tap_count_enabled() API too (now returns unsigned). git-svn-id: svn://svn.berlios.de/openocd/trunk@2091 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-07 zwelch * : Factoring of jtag_examine_chain for maintainability: - Factor TAP ID matching into new helper function. - Simplifies the main jtag_examine_chain loop logic considerably. git-svn-id: svn://svn.berlios.de/openocd/trunk@2089 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-07 zwelch * : Factoring of jtag_examine_chain for maintainability: - Add helper to check for the terminating ID during jtag_examine_chain. git-svn-id: svn://svn.berlios.de/openocd/trunk@2087 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-07 zwelch * : Factoring of jtag_examine_chain for maintainability: - Factor output of accepted/incorrect/expected TAP IDs into static helper. git-svn-id: svn://svn.berlios.de/openocd/trunk@2085 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-07 zwelch * : Factoring of jtag_examine_chain for maintainability: - Factor JTAG chain examination into static helper function. git-svn-id: svn://svn.berlios.de/openocd/trunk@2083 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-07 zwelch * : Factoring of jtag_examine_chain for maintainability: - Reduce indent: invert logic test for unexpected TAP (no IDs). git-svn-id: svn://svn.berlios.de/openocd/trunk@2081 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-07 zwelch * : Factoring of jtag_examine_chain for maintainability: - Move definition of maximum JTAG chain size closer to its only uses. git-svn-id: svn://svn.berlios.de/openocd/trunk@2079 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-07 zwelch * : Clean up handle_endstate_command(): - Merge declaration of state with first use. - Unindent and remove unnecessary 'else' block. git-svn-id: svn://svn.berlios.de/openocd/trunk@2077 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-05 oharboe * : remove hacks no longer required to build OpenOCD w/eCos git-svn-id: svn://svn.berlios.de/openocd/trunk@2074 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-05 oharboe * : remove unused include file: inttypes.h git-svn-id: svn://svn.berlios.de/openocd/trunk@2072 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-05 zwelch * : Eliminate MixedCaps symbol from public JTAG TAP API: - Purely mechanical transformations to the source files. - Rename 'jtag_NextEnabledTap' as 'jtag_tap_next_enabled.' git-svn-id: svn://svn.berlios.de/openocd/trunk@2069 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-05 zwelch * : Eliminate MixedCaps symbol from public JTAG TAP API: - Purely mechanical transformations to the source files. - Rename 'jtag_NumTotalTaps' as 'jtag_tap_count.' git-svn-id: svn://svn.berlios.de/openocd/trunk@2067 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-05 zwelch * : Eliminate MixedCaps symbol from public JTAG TAP API: - Purely mechanical transformations to the source files. - Rename 'jtag_TapByString' as 'jtag_tap_by_string.' git-svn-id: svn://svn.berlios.de/openocd/trunk@2065 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-05 zwelch * : Eliminate MixedCaps symbol from public JTAG TAP API: - Purely mechanical transformations to the source files. - Rename 'jtag_TapByPosition' as 'jtag_tap_by_position.' git-svn-id: svn://svn.berlios.de/openocd/trunk@2063 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-05 zwelch * : Eliminate MixedCaps symbol from public JTAG TAP API: - Purely mechanical transformations to the source files. - Rename 'jtag_all_taps' as '__jtag_all_taps.' - Frees original symbol name to rename the accessor function. git-svn-id: svn://svn.berlios.de/openocd/trunk@2061 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-05 zwelch * : Add accessors for reset delays; use them in jim command handlers. git-svn-id: svn://svn.berlios.de/openocd/trunk@2059 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-04 zwelch * : Add jtag_get_flush_queue_count accessor to help future factoring. git-svn-id: svn://svn.berlios.de/openocd/trunk@2057 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-04 zwelch * : Clean up the core JTAG TAP APIs: - Move jtag_tap_name to same location as other TAP functions; export it. - Factor new jtag_tap_add() from jim_newtap_cmd(); appends TAP to global list. - Move static chain position counter to global; use in jtag_NumTotalTaps(). - Use jtag_AllTaps for reading tap list, instead of accessing global directly. git-svn-id: svn://svn.berlios.de/openocd/trunk@2055 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-04 zwelch * : Add missing static keywords in JTAG source file. git-svn-id: svn://svn.berlios.de/openocd/trunk@2053 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-04 ntfreak * : - add support for different TAR autotincrement sizes as per ARM ADI spec. - set TAR size to 12 bits for Cortex-M3. - Original patch submitted by Magnus Lundin [lundin@mlu.mine.nu]. git-svn-id: svn://svn.berlios.de/openocd/trunk@2051 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-04 oharboe * : Introduce jtag_get_end_state() fn to clarify code a bit. git-svn-id: svn://svn.berlios.de/openocd/trunk@2049 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-04 oharboe * : do not modify global end state from jtag_add_xxx() git-svn-id: svn://svn.berlios.de/openocd/trunk@2047 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-04 oharboe * : no longer use jtag_add_xxx() to set end state to TAP_DRPAUSE git-svn-id: svn://svn.berlios.de/openocd/trunk@2045 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-04 oharboe * : use assert() to catch TAP_INVALID passed to jtag_add_xxx() fn's. git-svn-id: svn://svn.berlios.de/openocd/trunk@2043 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-04 oharboe * : jtag_add_end_state() now returns the value of the global variable and does not modify the global variable if passed TAP_INVALID. This patch has no effect on the current code and is just to prepare upcoming patches. git-svn-id: svn://svn.berlios.de/openocd/trunk@2041 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-04 zwelch * : David Brownell : Update the "General Commands" (a.k.a. "random stuff") chapter, and associated chunks of other text: - Switch to @deffn and review everything that's documented - Improve descriptions of reset events, with reference to the setup.tcl code which issues them. - Move one zy1000-specific command to that driver's doc. - There is no "script" command; remove its doc. NOTE: Some things missing from this bit of work are: 1- Reviewing the code to catch various *missing* functions, mostly from "target.c" 2- Alphabetizing and organizing. This chapter is a real grab-bag with no evident focus or structural principle. 3- Hole-filling and bugfixing with respect to messaging/logging. Example, what principle could possibly justify the tcl command output going into the server output/log instead of just the telnet session? 4- Not just for this chapter ... but there should be a section with descriptions of all the supported image file formats, so every image command can just reference that section. git-svn-id: svn://svn.berlios.de/openocd/trunk@2039 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-04 zwelch * : David Brownell : Minor cleanup of FT2232: - make Olimex glue warn about Olimex issues instead of JTAGkey issues; - make some data static+const; - don't export some internal symbols. git-svn-id: svn://svn.berlios.de/openocd/trunk@2037 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-04 zwelch * : David Brownell : Convert the Interface/Dongle Config chapter's section on drivers to use the @deffn syntax, and integrate the presentation of the driver-specific commands with the relevant driver. Alphabetize. Cross-checked against the code ... several adapters were not listed, and a few commands weren't. (Maintainers for the versaloon and zy1000 drivers would be good candidates to add the commands missing from those sections...) git-svn-id: svn://svn.berlios.de/openocd/trunk@2035 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-03 oharboe * : use assert() for obscure check on illegal arguments upon trst being asserted while commands are queued git-svn-id: svn://svn.berlios.de/openocd/trunk@2033 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-03 oharboe * : catchup with jtag refactoring. git-svn-id: svn://svn.berlios.de/openocd/trunk@2031 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-03 zwelch * : Finish JTAG header file modularization; command factoring follows. git-svn-id: svn://svn.berlios.de/openocd/trunk@2029 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-03 zwelch * : Move JTAG command APIs into new jtag/commands.h header file. git-svn-id: svn://svn.berlios.de/openocd/trunk@2027 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-03 zwelch * : Improve in-source documentation that was causing Doxygen warnings. git-svn-id: svn://svn.berlios.de/openocd/trunk@2025 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-03 zwelch * : Improve logger script to expose warnings and errors in the output. git-svn-id: svn://svn.berlios.de/openocd/trunk@2023 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-03 zwelch * : Add draft of Patching Primer in The Manual; update primer page. git-svn-id: svn://svn.berlios.de/openocd/trunk@2021 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-03 zwelch * : Enable or add doxygen comments to the public JTAG API. git-svn-id: svn://svn.berlios.de/openocd/trunk@2019 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-03 zwelch * : Remove vestigal tap_transition type from public jtag API. git-svn-id: svn://svn.berlios.de/openocd/trunk@2017 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-03 zwelch * : Expose tap_state_by_name TAP helper available in public API. git-svn-id: svn://svn.berlios.de/openocd/trunk@2015 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-03 zwelch * : David Brownell : Rework the TAP creation documentation. - Try to use "TAP" not "tap" everywhere; it's an acronym. - Update the associated "target config files" section: * reference the "TAP Creation" chapter for details * simplify: reference interesting multi-tap config files * let's not forget CPU configuration (*before* workspace setup) * streamline it a bit * move that workspace-vs-mmu issue to a better location - Clean up TAP creation doc mess * switch to @deffn * (re)organize the remaining stuff * reference the "Config File Guidelines" chapter - Tweak the "Target Configuration" chapter * rename as "CPU configuration"; unconfuse vs. target/*.cfg * bring out that it's not just there for GDB * move TAP events to the TAP chapter, where they belong (bugfix) git-svn-id: svn://svn.berlios.de/openocd/trunk@2013 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-03 zwelch * : Add missed accessor for checking the current TMS table. git-svn-id: svn://svn.berlios.de/openocd/trunk@2011 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-03 zwelch * : Make tap_state_by_name available in new JTAG interface API header. git-svn-id: svn://svn.berlios.de/openocd/trunk@2009 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-02 zwelch * : Finish removing '#ifdef HAVE_JTAG_MINIDRIVER_H' from jtag.h: - Wraps JTAG callback API functions: - Outlines jtag_add_callback() and jtag_add_callback4(). - Adds interface_ prefix to existing in-tree driver implementation. - Declare the driver interfaces routines in miniheader.h file. This patch requires renaming the equivalent macros in out-of-tree jtag_minidriver.h implementations. git-svn-id: svn://svn.berlios.de/openocd/trunk@2007 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-02 ntfreak * : - change signature for adi_jtag_dp_scan and adi_jtag_dp_scan_u32 to use swjdp_common_t *swjdp instead of arm_jtag_t *jtag_info - change SWJDP_IR/DR_APACC to DAP_IR/DR_APACC to conform with ARM_ADI docs. - add swjdp->memaccess_tck field and code for extra tck clocks before accessing memory bus - Set default memaccess value to 8 for Cortex-M3. - Add dap memaccess command. - document all armv7 dap cmds. - Original patch submitted by Magnus Lundin [lundin@mlu.mine.nu]. git-svn-id: svn://svn.berlios.de/openocd/trunk@2005 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-02 oharboe * : remove unecessary #ifdef as file is only built when minidriver is enabled. git-svn-id: svn://svn.berlios.de/openocd/trunk@2003 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-02 oharboe * : more missing eCos types git-svn-id: svn://svn.berlios.de/openocd/trunk@2001 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-02 zwelch * : Move interface_jtag_add_scan_check_alloc implementations to their respective implementation files. git-svn-id: svn://svn.berlios.de/openocd/trunk@1999 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-02 oharboe * : Remove unused code, TAP_INVALID is never passed to drivers. git-svn-id: svn://svn.berlios.de/openocd/trunk@1997 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-02 zwelch * : More JTAG interface driver cleanup: - Moves references to global jtag interface to default core implementation. - Missed this reference in the earlier "pointless" patch. Mea culpa. Important: this has a side-effect. Previously, the error return inside the interface routine short-circuited the remainder of that function when 'init' has not been called. With this patch, the command queue will be cleared in the case that 'init' has been called. Since that case indicates a buggy script, this does not seem to be a problem. git-svn-id: svn://svn.berlios.de/openocd/trunk@1995 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-02 zwelch * : More JTAG interface driver cleanup: - Make interface_jtag_execute_queue call new helper function. - Add default_interface_jtag_execute_queue to wrap jtag interface access. This patch may look useless on its own, but it helps to isolate the core JTAG variables from the interface_jtag_* routines, so the later can be moved into jtag_driver.c in a pending patch. git-svn-id: svn://svn.berlios.de/openocd/trunk@1993 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-02 zwelch * : Encapsulate JTAG command interfaces for moving to jtag_interface.h. git-svn-id: svn://svn.berlios.de/openocd/trunk@1991 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-02 zwelch * : Start clean-up of JTAG driver interface: - Factor jtag_add_scan_check to call new jtag_add_scan_check_alloc helper. - Use conditional logic to define two versions of the helper. - These helpers will be moved to other files in future patches. git-svn-id: svn://svn.berlios.de/openocd/trunk@1989 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-01 zwelch * : David Brownell : Whitespace fixes in jtag.c ... mostly end-of-line crap. Flag "jtag_device" command as obsolete in its helptext. git-svn-id: svn://svn.berlios.de/openocd/trunk@1987 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-01 zwelch * : David Brownell : This is the missing half of the r1974 patch: OSK5912 board support, which was split out from the omap5912 target config. git-svn-id: svn://svn.berlios.de/openocd/trunk@1985 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-01 zwelch * : Encapsulate JTAG minidriver functions, plan for new header file. git-svn-id: svn://svn.berlios.de/openocd/trunk@1983 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-01 zwelch * : Scrub final vestiges of in_handler from mips target APIs. git-svn-id: svn://svn.berlios.de/openocd/trunk@1981 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-01 oharboe * : fix warning for a variable that GCC thought might be uninitialized(which it can't be). git-svn-id: svn://svn.berlios.de/openocd/trunk@1979 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-01 zwelch * : David Brownell : Uplevel the arch commands to be a chapter; they really don't fit in the "general commands" category. git-svn-id: svn://svn.berlios.de/openocd/trunk@1977 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-01 zwelch * : David Brownell : Various updates, mostly small/formatting changes: * Small content tweaks: - Re-title: "OpenOCD User's Guide". - For users, URLS for latest doc and SparkFun forum - Mention GIT-SVN * Fix some front-matter goofage, matching texinfo docs: - "paragraphintent" location matters - put release version/date description with the copyright * Fix some other stuff matching texinfo docs: - no tabs - tweak some refs and anchors * whitespace-at-end-o-line fixes git-svn-id: svn://svn.berlios.de/openocd/trunk@1975 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-06-01 zwelch * : David Brownell : Whitespace fixes. git-svn-id: svn://svn.berlios.de/openocd/trunk@1973 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-31 zwelch * : Final step in isolating target_type_s structure: - Move definition of 'struct target_type_s' into new 'target_type.h' file. - Forward delclaration remains in target.h, with comment pointing to new file. - Replaces #define with #include in source files. git-svn-id: svn://svn.berlios.de/openocd/trunk@1971 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-31 zwelch * : First step in hiding target_type_s from public interface: - Add DEFINE_TARGET_TYPE_S symbol in files that need it defined. - Forward declare 'struct target_type_s' only, unless that symbol is defined. git-svn-id: svn://svn.berlios.de/openocd/trunk@1969 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-31 zwelch * : Add target breakpoint and watchpoint wrapper: - replaces all calls to target->type->{add,remove}_{break,watch}point. git-svn-id: svn://svn.berlios.de/openocd/trunk@1967 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-31 zwelch * : Add target_step wrapper: - replaces all calls to target->type->step. git-svn-id: svn://svn.berlios.de/openocd/trunk@1965 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-31 zwelch * : Add target_bulk_write_memory wrapper: - replaces all calls to target->type->bulk_write_memory. - add documentation in target_s to warn not to invoke callback directly. git-svn-id: svn://svn.berlios.de/openocd/trunk@1963 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-31 zwelch * : Add target_run_algorithm wrapper: - replaces all calls to target->type->run_algorithm. - add documentation in target_s to warn not to invoke callback directly. git-svn-id: svn://svn.berlios.de/openocd/trunk@1961 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-31 zwelch * : Add target_read_memory wrapper: - replaces all calls to target->type->read_memory. - add documentation in target_s to warn not to invoke callback directly. git-svn-id: svn://svn.berlios.de/openocd/trunk@1959 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-31 zwelch * : Make nvp_target_event static; remove its external declaration. git-svn-id: svn://svn.berlios.de/openocd/trunk@1957 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-31 zwelch * : Peter Denison : The debugging code in jlink_tap_execute() called when _DEBUG_USB_COMMS_ is defined was using the entire cached scan length to print the results buffers, and not the correct length of each individual buffer. git-svn-id: svn://svn.berlios.de/openocd/trunk@1955 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-30 zwelch * : Eliminate duplicated code in the handle_mw_command memory write loop. - wordsize will always be 1, 2, or 4 due to preceeding switch statement. - move call to keep_alive after successful writes, not upon failures git-svn-id: svn://svn.berlios.de/openocd/trunk@1953 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-30 zwelch * : Remove unused jlink_execute_end_state (unreferenced after r1949). git-svn-id: svn://svn.berlios.de/openocd/trunk@1951 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-30 oharboe * : remove unused JTAG_END_STATE git-svn-id: svn://svn.berlios.de/openocd/trunk@1949 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-30 oharboe * : more reset_config texts git-svn-id: svn://svn.berlios.de/openocd/trunk@1947 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-30 zwelch * : David Brownell : Provide basic documentation on the ARM ETM and ETB trace commands. Fix minor goofs in registration of the ETM commands; and whitespace issues in the proof-of-concept oocd_trace code. (Plus include a ref to Dominic's email saying that it's just proof-of-concept code.) Note that I'm still not sure whether the ETM support works. But documenting how it's expected to work should help sort out which behaviors are bugs, which will help get bugs patched. ZW: whitespace changes were split out of this patch but will follow. git-svn-id: svn://svn.berlios.de/openocd/trunk@1945 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-29 zwelch * : Remove error_handler_t type definition; it was unused in the tree. git-svn-id: svn://svn.berlios.de/openocd/trunk@1943 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-29 zwelch * : David Brownell : Provide basic documentation for some of the other flash drivers. avr ... looks incomplete, may work with one AVR8 microcontroller ecosflash ... can't find docs lpc288x ... an NXP part, driver seems lpc2888-specific ocl ... some arm7/arm9 thing, can't find docs pic32mx ... looks incomplete, for PIC32MX (MIPS 4K) devices tms470 ... for TI TMS470 parts Still seems to be mostly arm7tdmi... several of these have no users in the current tree. git-svn-id: svn://svn.berlios.de/openocd/trunk@1941 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-28 zwelch * : David Brownell : Start converting the architecture-specific commands to @deffn format, reviewing against the code. * armv4_5 disassemble ... now documented; although Jazelle code is not handled * It's "armv4_5 core_state" not "core_mode"; although Jazelle state is not handled * arm7/9 "debug" commands ... now with other arm7_9 commands, no longer in a separate section * arm926ejs cp15 ... previous description was broken, it matched the code for arm920t instead * Have separate subsections for ARMv4/ARMv5, ARMv6, and ARMv7; the latter are new * Move core-specific descriptions into sub-subsections under those architectures; XScale and ARM11 descriptions are new The new XScale and ARM11 command descriptions surely need elaboration and review. ARM CP15 operation descriptions in general seem to be confused and incomplete. git-svn-id: svn://svn.berlios.de/openocd/trunk@1939 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-28 zwelch * : David Brownell : Start updating the NOR flash coverage to use @deffn syntax, so the commands have more consistent presentation and formatting. This reorganizes information and updates its presentation, except where the information didn't really match the code. This patch updates most of the driver specific support, creating one new (and alphabetized!) section just for driver-specific data, where previously that data was split over up to three sections. Of note: - The at91sam7 docs were a bit out of date with respect to the code. - The "str9xpec" stuff still deserves some work. For now, it sits in its own subsection; pretty messy. - Likewise the "mflash" stuff. That's a parallel infrastructure, and is now in a section of its own. - The "mass_erase" commands for the Cortex M3 chips got turned into footnotes. IMO, they should vanish sometime; they're superfluous. - There are still a bunch of undocumented NOR drivers. Examples: avr(8), tms470, pic32mx, more. Plus there are a handful of minor tweaks to the NAND docs (to help make the NOR and NAND presentations be parallel); the "Command Index" has been renamed as the "Command and Driver Index"; reference TI instead of Luminary Micro in several places. git-svn-id: svn://svn.berlios.de/openocd/trunk@1937 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-27 zwelch * : Fix potentialyl unaligned memory accesses in mflash driver. git-svn-id: svn://svn.berlios.de/openocd/trunk@1935 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-27 kc8apf * : Author: Nicolas Pitre - Silence errors about keep_alive() not being called frequently enough unless a gdb session is active or debugging is enabled git-svn-id: svn://svn.berlios.de/openocd/trunk@1933 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-27 zwelch * : unsik Kim : Add large bank write/dump support in mflash driver. git-svn-id: svn://svn.berlios.de/openocd/trunk@1931 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-27 zwelch * : unsik Kim : Remove unused mflash driver 'prove' field. git-svn-id: svn://svn.berlios.de/openocd/trunk@1929 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-27 zwelch * : unsik Kim : Change prefix of mflash driver routines to mg_. git-svn-id: svn://svn.berlios.de/openocd/trunk@1927 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-27 ntfreak * : - add support for cortino jtag interface git-svn-id: svn://svn.berlios.de/openocd/trunk@1925 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-27 zwelch * : Link new Primer pages into the main list of Primers. git-svn-id: svn://svn.berlios.de/openocd/trunk@1923 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-27 zwelch * : Add draft of Autotools Primer to The Manual. git-svn-id: svn://svn.berlios.de/openocd/trunk@1921 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-27 zwelch * : Move TCL script files -- Step 2 of 2: - Move src/tcl to tcl/. - Update top Makefile.am to use new path name. git-svn-id: svn://svn.berlios.de/openocd/trunk@1919 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-27 zwelch * : Add warning to generated Doxyfile to edit Doxyfile.in. git-svn-id: svn://svn.berlios.de/openocd/trunk@1917 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-26 zwelch * : SimonQian , reported by R.Doss: This patch fixes a segfault when TDO was not received in XXR command: - allocate space for the value and mask anyway - clear the mask to zero to effectively skip the output comparison step git-svn-id: svn://svn.berlios.de/openocd/trunk@1915 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-26 zwelch * : David Brownell : Update the "Reset Configuration" information in the User's guide: - Convert to @deffn syntax - Move tutorial text from command descriptions into new sections - Describe several different types of JTAG-visible reset - Expand descriptions of configuration tweaks for SRST and TRST - Link to the "reset" command, and vice versa - Bugfix the "reset_config" description (it didn't match the code) Plus, be more proscriptive: do it in board config files, except for the oddball cases where that won't work. (Current target.cfg files seem to have much goofage there; several seem board-specific.) git-svn-id: svn://svn.berlios.de/openocd/trunk@1913 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-25 kc8apf * : Author: Raúl Sánchez Siles - cfi flash_address coding style fix git-svn-id: svn://svn.berlios.de/openocd/trunk@1911 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-24 zwelch * : David Brownell : Make startup for the various server ports be quiet, unless debugging is active: don't emit needless scarey messages. Update the relevant documentation and its references: - For these port commands ... cover the default values; convert to @deffn syntax; include their use outside of the configuration stage; and alphabetize. Similar updates to the rest of that small chapter: - Highlight that there even *IS* a configuration stage, after which some command functionality is no longer available. - For GDB commands ... convert to @deffn syntax; alphabetize; include a missing command (!); add missing helptext (!) for one non-missing command; update relevant cross-references and index entries. git-svn-id: svn://svn.berlios.de/openocd/trunk@1909 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-24 zwelch * : David Brownell : minor davinci_nand bugfix Fix a bug that joined us at the last minute, when an efficient alloca() call got swapped out for a more portable malloc(). Also log one error, to give a clue in case it appears "in the wild". git-svn-id: svn://svn.berlios.de/openocd/trunk@1907 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-24 zwelch * : Nicolas Pitre : Update sheevaplug interface script: When the CPU is in the WFI state, the JTAG interface simply doesn't respond at all and initial tap examination simply fails. Let's simply do it again when we come around to assert nSRST. git-svn-id: svn://svn.berlios.de/openocd/trunk@1905 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-24 zwelch * : David Brownell : NAND support for DaVinci-family drivers, with HW ECC support. Declare the NAND chip on the DM355 EVM board. Currently tested on DM355 for Linux interop using the standard large page (2KB) chip in the EVM socket; "hwecc1" and "hwecc4" work fine. (Using hwecc4 relies on patches that haven't quite made it through the Linux-MTD bottlenecks yet.) Not yet tested: 1-bit on small-page (although it's hard to see how that could fail); 4-bit on small page (picky layout issues); the "hwecc_infix" mode (primarily for older boot ROMs; testing there is blocked on having new bootloader code). git-svn-id: svn://svn.berlios.de/openocd/trunk@1903 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-24 zwelch * : Properly fix doxygen out-of-tree build process: - move Doxyfile to Doxyfile.in: type 'make Doxyfile' to recreate it - create Doxyfile from Doxyfile.in with make rule: - use sed substitution of $(srcdir) to location directories - delete all doxygen created files with 'make distclean' - include all required files (including logger.pl) in distribution git-svn-id: svn://svn.berlios.de/openocd/trunk@1901 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-24 zwelch * : Freddie Chopin : - add reset delay settings for LPC2103, LPC2124, and LPC2129. git-svn-id: svn://svn.berlios.de/openocd/trunk@1899 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-23 zwelch * : Update main page of doxygen developer documentation: - Rewrite copy to give a better introduction and overview. - Add subpages: The List, Style Guide, Patch Policies, and Bug Reporting. git-svn-id: svn://svn.berlios.de/openocd/trunk@1897 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-23 zwelch * : Update user guide documentation: - Remove style guide from user guide; moved to doxygen manual. - Replace with improved introduction for developers and packagers. - Move introductory paragraph about the project under the About page. git-svn-id: svn://svn.berlios.de/openocd/trunk@1895 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-23 zwelch * : Submitted by Magnus Lundin : - Remove FTDI driver tap_set_state call; performed by jtag_add_reset. git-svn-id: svn://svn.berlios.de/openocd/trunk@1893 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-23 zwelch * : Fix make docs rule to work with out-of-tree builds. git-svn-id: svn://svn.berlios.de/openocd/trunk@1891 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-23 zwelch * : Submitted by Magnus Lundin : Updates to the J-Link interface driver to support more device versions: - Add capability detection: - if capable, detect protocol version; otherwise, assume v2 protocol. - if capable, detect buffer size; otherwise, assume minimal. - Disable command result queries for devices using v2 protocol. - Defined and use JTAG2 command with v2 protocol; JTAG3 is v3 protocol. - Add TCL command to allow explicit setting of J-Link protocol version. With approval, I revised the patch to make the following changes: - add static keywords to new jlink-specific variables - factor calculation of major_version to be more readable - remove braces around simple one-line statements in if/else clauses - remove (rather than #if 0) duplicate reset code; it is in SVN - use &function to be clearer when passing function pointers - add symbols for EMU_CMD_GET_CAPS bits; do not hard-code constants! - almost renamed jlink_handle_jlink_hw_jtag_command (seriously?!?!) - rewrote that function using a switch statement. - made version request processing easier to understand and modify - improve alternate endpoint detection: - make code easier to read by using temporary variables - eliminate extra level of indentation and redundant logging - use ternary conditional to select JTAG2 or JTAG3 command - reverse version test in jlink_usb_message to reduce indentation - this had the biggest effect in cleaning up this patch - use C99's ability to declare new/changed variables with less scope - add spaces around binary operators in new/changed code - revert other superfluous whitespace/comment style changes git-svn-id: svn://svn.berlios.de/openocd/trunk@1889 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-23 zwelch * : Change doxygen configuration to show code comments in documentation. git-svn-id: svn://svn.berlios.de/openocd/trunk@1887 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-22 kc8apf * : Author: Raúl Sánchez Siles - Fix calculation of flash_address for x16 devices used as x8 git-svn-id: svn://svn.berlios.de/openocd/trunk@1885 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-22 kc8apf * : Author: David Brownell Remove un-implemented and dubious "nand copy" command. Doing this efficiently would mean doing the copying on the target CPU, instead of back and forth through JTAG. If anyone ever needs this functionality, that's what they should implement. Also, update on-line "help" for "nand dump" to display its two optional flags; and for "nand write" to display a recently added flag. git-svn-id: svn://svn.berlios.de/openocd/trunk@1883 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-22 zwelch * : Submitted by David Brownell : Improve support for the DM355 EVM board, and eventually other boards based on DaVinci chips: - Provide generic "davinci.cfg" to hold utilities that can be reused by different chips in this family. Start with PINMUX, PSC, and PLL setup. - DM355 chip support updates: provide a dictionary with chip-specific symbols, load those utilities. - Create a new dm355evm board file, with a reset-init event handler which uses those utilities to set up PLLs and clocks, configure the pins, and improve the JTAG speed limit. Also a minor tweak: provide a virtual address for the work area, matching what the very latest kernels do. It's probably unwise to use OpenOCD while the MMU is active though. The DRAM isn't yet accessible, but NAND access is mostly ready. git-svn-id: svn://svn.berlios.de/openocd/trunk@1881 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-22 zwelch * : Submitted by David Brownell : Add a "NAND Commands" section to to the TEXI docs, covering the basic commands except for those previously discussed as being due for removal ("nand copy") or switching to use byte offsets not block numbers. This uses the "@deffn..." syntax for defining commands, as somewhat suggested by the TEXI documentation, and adds a new "Command Index". We might prefer to merge those indexes for the near term, but I think the "@deffn" approch is probably worth switching to. Updates a few other bits to clarify that "flash" doesn't just mean NOR. And to fix one niggling falsity: the "reset-init" event *is* used, and in fact it's quite important. git-svn-id: svn://svn.berlios.de/openocd/trunk@1879 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-21 oharboe * : fix warning. Use %p for pointers git-svn-id: svn://svn.berlios.de/openocd/trunk@1877 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-21 oharboe * : Dirk Behme Minor updates for OMAP3 scripts git-svn-id: svn://svn.berlios.de/openocd/trunk@1875 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-21 zwelch * : David Brownell : This patch adds annotations to the key command_*() helper functions, fixng the bugs that turned up. Several of these bugs were from misuse of PRIi64; that's for 64-bit integers, NOT for "long long" or "u64" (which work best with %lld). git-svn-id: svn://svn.berlios.de/openocd/trunk@1873 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-21 kc8apf * : Author: Thomas Kindler - Increase DTC status retry count to avoid problems with STM Primer git-svn-id: svn://svn.berlios.de/openocd/trunk@1871 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-21 kc8apf * : Author: Holger Schurig -Prevent freezing of target when doing a 'shutdown'. git-svn-id: svn://svn.berlios.de/openocd/trunk@1869 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-21 kc8apf * : Author: Michael Bruck -jtag.c, interface_jtag_add_dr_out(): - use pointer 'field' instead of scan->fields[field_count] - restructure the main loop to clearly separate the two cases: TAP is not bypassed / TAP is bypassed (this is to keep the function similar to interface_jtag_add_dr_scan()) - fix bug where only the first output field has its tap field set - add asserts to verify that target_tap points to the one not bypassed TAP git-svn-id: svn://svn.berlios.de/openocd/trunk@1867 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-21 kc8apf * : Author: Michael Bruck -jtag.c, interface_jtag_add_ir_scan(): - use pointer 'field' instead of scan->fields[nth_tap] - add assertion to ensure that input data has correct size for TAP's IR git-svn-id: svn://svn.berlios.de/openocd/trunk@1865 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-21 kc8apf * : Author: Michael Bruck - jtag.c: remove unused variable 'nth_tap' from DR scan functions git-svn-id: svn://svn.berlios.de/openocd/trunk@1863 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-21 kc8apf * : Author: Michael Bruck - jtag.c: consolidate all memory allocations in scan functions in one block, add out_fields pointer to set stage for further changes git-svn-id: svn://svn.berlios.de/openocd/trunk@1861 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-21 kc8apf * : Author: Michael Bruck - add doxygen comments to scan commands in jtag.c - move jtag_add_dr_scan next to interface_jtag_add_dr_scan to keep these function pairs together git-svn-id: svn://svn.berlios.de/openocd/trunk@1859 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-20 zwelch * : Add initial OpenOCD server documentation (Duane Ellis and myself). git-svn-id: svn://svn.berlios.de/openocd/trunk@1857 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-20 zwelch * : Move TCL overview from source tree to doxygen manual. git-svn-id: svn://svn.berlios.de/openocd/trunk@1855 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-20 zwelch * : Move non-arm target overview from source tree to doxygen manual. git-svn-id: svn://svn.berlios.de/openocd/trunk@1853 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-20 oharboe * : Spencer Oliver use 7 tms out of reset git-svn-id: svn://svn.berlios.de/openocd/trunk@1851 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-20 kc8apf * : Author: Michael Bruck - simplify code in interface_jtag_add_plain_dr_scan() by adding a local variable 'scan' to hold the scan_command_t git-svn-id: svn://svn.berlios.de/openocd/trunk@1849 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-20 kc8apf * : Author: Michael Bruck - simplify code in interface_jtag_add_dr_out() by adding a local variable 'scan' to hold the scan_command_t git-svn-id: svn://svn.berlios.de/openocd/trunk@1847 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-20 kc8apf * : Author: Michael Bruck - simplify code in interface_jtag_add_dr_scan() by adding a local variable 'scan' to hold the scan_command_t git-svn-id: svn://svn.berlios.de/openocd/trunk@1845 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-20 kc8apf * : Author: Michael Bruck - move scan_size in interface_jtag_add_ir_scan() into the scope of the inner loop and change it to unsigned git-svn-id: svn://svn.berlios.de/openocd/trunk@1843 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-20 kc8apf * : Author: Michael Bruck - rename local variable x to num_taps in interface_jtag_add_ir_scan git-svn-id: svn://svn.berlios.de/openocd/trunk@1841 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-19 zwelch * : Wookey : add user documentation for echo command. git-svn-id: svn://svn.berlios.de/openocd/trunk@1839 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-19 oharboe * : fix warnings git-svn-id: svn://svn.berlios.de/openocd/trunk@1837 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-19 oharboe * : David Brownell NAND: update ids, "nand list" bugfix git-svn-id: svn://svn.berlios.de/openocd/trunk@1835 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-18 oharboe * : use tap_get_tms_path_len() instead of fix # of 7. Not tested if this builds, but at least we're looking at a build error instead of a runtime error. git-svn-id: svn://svn.berlios.de/openocd/trunk@1833 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-18 oharboe * : use tap_get_tms_path_len() instead of fix # of 7. git-svn-id: svn://svn.berlios.de/openocd/trunk@1831 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-18 oharboe * : updated w/jtag_add_end_state() note. git-svn-id: svn://svn.berlios.de/openocd/trunk@1829 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-18 kc8apf * : Enable non-7-cycle state table for FT2232 and JLink git-svn-id: svn://svn.berlios.de/openocd/trunk@1827 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-18 kc8apf * : FT2232 support for non-7-cycle state moves by Dick Hollenbeck git-svn-id: svn://svn.berlios.de/openocd/trunk@1825 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-18 kc8apf * : Change last_comand_pointer to last_command_pointer by Michael Bruck git-svn-id: svn://svn.berlios.de/openocd/trunk@1823 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-18 kc8apf * : Add jtag_queue_command() by Michael Bruck [7/8] git-svn-id: svn://svn.berlios.de/openocd/trunk@1821 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-18 kc8apf * : Add jtag_queue_command() by Michael Bruck [5/8] git-svn-id: svn://svn.berlios.de/openocd/trunk@1819 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-18 kc8apf * : Add jtag_queue_command() by Michael Bruck [3/8] git-svn-id: svn://svn.berlios.de/openocd/trunk@1817 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-18 kc8apf * : Add jtag_queue_command() by Michael Bruck git-svn-id: svn://svn.berlios.de/openocd/trunk@1815 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-18 kc8apf * : PATCHES updates from David Brownell git-svn-id: svn://svn.berlios.de/openocd/trunk@1813 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-18 oharboe * : Remove unecessary(and poptentially harmful?) "" around arguments passed in to "eval" in command.c git-svn-id: svn://svn.berlios.de/openocd/trunk@1811 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-18 oharboe * : Dean Glazeski fixed bug in checking of clocked back data in arm7_9_execute_fast_sys_speed. Not reported. There is a chance that this bug hid a deeper problem since it only partially disabled the check(mask & value were equal). git-svn-id: svn://svn.berlios.de/openocd/trunk@1809 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-18 oharboe * : Michael Bruck ARM11 cleanup stale dependencies with generic arm code; added comments and whitespace fixes git-svn-id: svn://svn.berlios.de/openocd/trunk@1807 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-18 kc8apf * : Fix logically inverted comment git-svn-id: svn://svn.berlios.de/openocd/trunk@1805 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-18 kc8apf * : ETM/ETB documentation from David Brownell git-svn-id: svn://svn.berlios.de/openocd/trunk@1803 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-17 oharboe * : fix array2mem/mem2array when used as a "method" on a target. git-svn-id: svn://svn.berlios.de/openocd/trunk@1801 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-16 oharboe * : fix naming of at91sam7 driver git-svn-id: svn://svn.berlios.de/openocd/trunk@1799 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-15 zwelch * : Initialize a more variables in jim.c to allow gcc-4.4 to build. Fix provided by Benjamin Schmidt . git-svn-id: svn://svn.berlios.de/openocd/trunk@1797 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-15 oharboe * : fix -fno-common/Mac build problems. git-svn-id: svn://svn.berlios.de/openocd/trunk@1795 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-15 oharboe * : revert to 1775. 1790 causes SEGFAULT w/Cygwin. git-svn-id: svn://svn.berlios.de/openocd/trunk@1793 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-15 zwelch * : Add current draft of The List of Pending and Open Tasks. git-svn-id: svn://svn.berlios.de/openocd/trunk@1791 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-14 zwelch * : Several minor fixes for the new doxygen manual. git-svn-id: svn://svn.berlios.de/openocd/trunk@1789 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-14 oharboe * : use TAP_INVALID enum instead of -1 git-svn-id: svn://svn.berlios.de/openocd/trunk@1787 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-14 oharboe * : dump_image now works for addresses not divisible by 4 git-svn-id: svn://svn.berlios.de/openocd/trunk@1785 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-14 oharboe * : selftest wip git-svn-id: svn://svn.berlios.de/openocd/trunk@1783 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-13 zwelch * : Update configure script test for net/if.h to work on MacOS. git-svn-id: svn://svn.berlios.de/openocd/trunk@1781 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-13 zwelch * : Fix bootstrap script to support MacOS glibtoolize oddity. git-svn-id: svn://svn.berlios.de/openocd/trunk@1779 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-13 zwelch * : Add JTAG Primer to doxygen manual, contributed by Strontium. git-svn-id: svn://svn.berlios.de/openocd/trunk@1776 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-13 oharboe * : added verify_jtag command git-svn-id: svn://svn.berlios.de/openocd/trunk@1774 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-13 oharboe * : shuffled comments about for jtag_add_dr_out() fn. git-svn-id: svn://svn.berlios.de/openocd/trunk@1772 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-12 oharboe * : irscan now also works correctly in addition to not crashing :-) git-svn-id: svn://svn.berlios.de/openocd/trunk@1770 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-12 oharboe * : 4-bit ECC support for Marvell Kirkwood SOC git-svn-id: svn://svn.berlios.de/openocd/trunk@1768 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-12 oharboe * : move eCos type definition to types.h where it belongs. git-svn-id: svn://svn.berlios.de/openocd/trunk@1766 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-12 ntfreak * : - fix build issue when HAVE_ELF_H is not defined git-svn-id: svn://svn.berlios.de/openocd/trunk@1764 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-12 zwelch * : Include project doxygen configuration with distribution tarballs. git-svn-id: svn://svn.berlios.de/openocd/trunk@1762 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-12 zwelch * : Make replacements.h private by including it from config.h autoheader. git-svn-id: svn://svn.berlios.de/openocd/trunk@1760 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-12 zwelch * : Audit and reduce #include directives in jim source files. git-svn-id: svn://svn.berlios.de/openocd/trunk@1758 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-12 zwelch * : Remove config.h from types.h; all .c files are required to include it. git-svn-id: svn://svn.berlios.de/openocd/trunk@1756 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-12 zwelch * : Update rlink_make_speed_table.pl script to add config.h to its output. git-svn-id: svn://svn.berlios.de/openocd/trunk@1754 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-12 oharboe * : added jtag_alloc_in_value32 - not used in this commit. git-svn-id: svn://svn.berlios.de/openocd/trunk@1752 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-12 zwelch * : Include assert.h in system.h to promote tree-wide use of assertions. git-svn-id: svn://svn.berlios.de/openocd/trunk@1750 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-11 oharboe * : now builds on 64 and 32 bit systems git-svn-id: svn://svn.berlios.de/openocd/trunk@1748 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-11 zwelch * : Update jim helper files to use proper configure script support: - configure.in: Add AC_TYPE_LONG_LONG_INT to detect 'long long int' support. - configure.in: Add AC_C_CONST to provide equivalent support as jim.h. - jim*.c: include config.h when HAVE_CONFIG_H is defined. - jim*.{h,c}: use HAVE_LONG_LONG_INT definition from config.h. - jim.h: Remove hard-coded const and HAVE_LONG_LONG definitions. - jim.h: -DJIM_NO_CONST has been obsoleted; -Dconst is equivalent. git-svn-id: svn://svn.berlios.de/openocd/trunk@1744 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-11 oharboe * : USB performance regression fix git-svn-id: svn://svn.berlios.de/openocd/trunk@1742 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-11 oharboe * : switch to jtag_add_dr_scan() from the synchronous version - USB performance fix git-svn-id: svn://svn.berlios.de/openocd/trunk@1740 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-11 oharboe * : switch to jtag_add_dr_scan_check() - USB performance fix git-svn-id: svn://svn.berlios.de/openocd/trunk@1738 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-11 oharboe * : change jtag_add_callback API to be able to support check_value/mask git-svn-id: svn://svn.berlios.de/openocd/trunk@1735 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-11 oharboe * : switch to jtag_add_callback() - USB performance fix git-svn-id: svn://svn.berlios.de/openocd/trunk@1733 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-11 oharboe * : switch to jtag_add_callback() - USB performance fix git-svn-id: svn://svn.berlios.de/openocd/trunk@1731 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-11 oharboe * : switch to jtag_add_callback() - USB performance fix git-svn-id: svn://svn.berlios.de/openocd/trunk@1729 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-11 oharboe * : switch to jtag_add_callback() - USB performance fix git-svn-id: svn://svn.berlios.de/openocd/trunk@1727 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-11 oharboe * : switch to jtag_add_callback() - USB performance fix git-svn-id: svn://svn.berlios.de/openocd/trunk@1725 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-11 oharboe * : leave eCos include file issues alone for now. git-svn-id: svn://svn.berlios.de/openocd/trunk@1723 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-11 oharboe * : used by upcoming commits git-svn-id: svn://svn.berlios.de/openocd/trunk@1721 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-11 zwelch * : Update Doxyfile configuration for doxygen 1.5.8: - Enable doxygen's C language optimizations. - Use dot command (from graphviz package) to generate visual graphs. git-svn-id: svn://svn.berlios.de/openocd/trunk@1719 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-11 zwelch * : Remove redundant config.h from replacements.h, obtained from types.h. git-svn-id: svn://svn.berlios.de/openocd/trunk@1717 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-11 zwelch * : Audit and eliminate redundant #include directives in other target files. git-svn-id: svn://svn.berlios.de/openocd/trunk@1715 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-11 zwelch * : Audit and eliminate redundant #include directives in core target files. git-svn-id: svn://svn.berlios.de/openocd/trunk@1713 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-11 zwelch * : Audit and eliminate redundant #include directives in src/flash headers. git-svn-id: svn://svn.berlios.de/openocd/trunk@1711 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-11 zwelch * : Audit and eliminate redundant #include directives from src/server. git-svn-id: svn://svn.berlios.de/openocd/trunk@1709 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-11 zwelch * : Audit and eliminate redundant #include directives from src/jtag. git-svn-id: svn://svn.berlios.de/openocd/trunk@1707 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-11 zwelch * : Simplify #include directives in ioutil.c, use new header checks. git-svn-id: svn://svn.berlios.de/openocd/trunk@1705 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-11 zwelch * : Add --enable-malloc-logging configure option and update log.c to match. git-svn-id: svn://svn.berlios.de/openocd/trunk@1703 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-11 zwelch * : Finish portability support for AC_HEADER_STDBOOL configure macro. git-svn-id: svn://svn.berlios.de/openocd/trunk@1701 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-11 zwelch * : Add configure check for sys/types.h; include in our types.h. git-svn-id: svn://svn.berlios.de/openocd/trunk@1699 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-11 zwelch * : Use AC_HEADER_STDBOOL macro instead of AC_CHEACK_HEADERS(stdbool.h). git-svn-id: svn://svn.berlios.de/openocd/trunk@1697 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-10 zwelch * : Extend autotools build to create shared library libopenocd with libtool: - Add libtoolize step too bootstrap script; creates ltmain.sh script. - Add AC_PROG_LIBTOOL to configure.in to add libtool support to build. - Change Makefile.am library rules from static (_a) to libtool (_la). - Install libopenocd.{la,so,a} in $(libdir); update openocd link rules. - Extend MAINTAINERCLEANFILES in top-level Makefile.am to remove ltmain.sh. git-svn-id: svn://svn.berlios.de/openocd/trunk@1695 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-10 zwelch * : Extend configure script to check for environ declaration in stdlib.h. Patch contributed by Martin Thomas . git-svn-id: svn://svn.berlios.de/openocd/trunk@1693 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-10 zwelch * : Revive tclapi.c from r1650: * Remove superfluous #include directives. * Fix warnings and API usage to cure its bit rot. * Build into libhelper library (for now). Add tclapi.h to export tclapi_register_commands(). Register tclapi commands in openocd.c:setup_command_handler(). git-svn-id: svn://svn.berlios.de/openocd/trunk@1691 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-10 oharboe * : David Brownell whitespace fixes. Testing out on one file first... git-svn-id: svn://svn.berlios.de/openocd/trunk@1689 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-10 oharboe * : Michael Bruck use more const git-svn-id: svn://svn.berlios.de/openocd/trunk@1687 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-09 oharboe * : Michael Bruck ARM11 C99 updates git-svn-id: svn://svn.berlios.de/openocd/trunk@1685 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-08 oharboe * : plugged bug w/irlen > 32 introduce in 1672 git-svn-id: svn://svn.berlios.de/openocd/trunk@1683 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-08 oharboe * : David Brownell DaVinci dm6446 git-svn-id: svn://svn.berlios.de/openocd/trunk@1680 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-08 oharboe * : Michael Fischer fix compile problems on Mac git-svn-id: svn://svn.berlios.de/openocd/trunk@1678 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-08 oharboe * : stm32 profiling wip git-svn-id: svn://svn.berlios.de/openocd/trunk@1676 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-08 oharboe * : add flush_count jtag queue profiling feature git-svn-id: svn://svn.berlios.de/openocd/trunk@1674 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-08 oharboe * : in_handler in_check_mask and in_check_value now removed from field. Last big patch in the series of JTAG API cleanup. git-svn-id: svn://svn.berlios.de/openocd/trunk@1672 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-08 oharboe * : use assert instead of adding code that always runs git-svn-id: svn://svn.berlios.de/openocd/trunk@1670 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-08 oharboe * : retire jtag_set_check_value git-svn-id: svn://svn.berlios.de/openocd/trunk@1668 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-08 oharboe * : retire jtag_set_check_value git-svn-id: svn://svn.berlios.de/openocd/trunk@1666 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-08 oharboe * : first jtag_check_value_mask usage. tested by using "arm7_9 fast_memory_access enable" & "mdw 0 0x10" git-svn-id: svn://svn.berlios.de/openocd/trunk@1664 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-08 zwelch * : Fix typo from hurrying the last commit. Nothing to see here. git-svn-id: svn://svn.berlios.de/openocd/trunk@1662 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-08 zwelch * : Re-order and extend header file tests in configure script. git-svn-id: svn://svn.berlios.de/openocd/trunk@1660 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-08 zwelch * : Fix warnings in ioutil.c; improves loadFile inteface. git-svn-id: svn://svn.berlios.de/openocd/trunk@1658 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-07 oharboe * : ouch - typo in last commit git-svn-id: svn://svn.berlios.de/openocd/trunk@1656 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-07 oharboe * : in_handler removal typo fixed git-svn-id: svn://svn.berlios.de/openocd/trunk@1654 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-07 oharboe * : refactor to be able to remove more in_handler stuff git-svn-id: svn://svn.berlios.de/openocd/trunk@1652 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-07 oharboe * : fix c99 compile errors git-svn-id: svn://svn.berlios.de/openocd/trunk@1650 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-07 oharboe * : remove usage of in_handler git-svn-id: svn://svn.berlios.de/openocd/trunk@1648 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-07 oharboe * : remove in_handler usage git-svn-id: svn://svn.berlios.de/openocd/trunk@1646 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-07 oharboe * : remove in_handler usage git-svn-id: svn://svn.berlios.de/openocd/trunk@1644 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-07 oharboe * : remove in_handler usage git-svn-id: svn://svn.berlios.de/openocd/trunk@1642 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-07 oharboe * : remove in_handler usage git-svn-id: svn://svn.berlios.de/openocd/trunk@1640 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-07 oharboe * : jtag API error handling refactoring. git-svn-id: svn://svn.berlios.de/openocd/trunk@1638 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-07 oharboe * : remove in_handler usage git-svn-id: svn://svn.berlios.de/openocd/trunk@1636 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-07 oharboe * : fix line endings git-svn-id: svn://svn.berlios.de/openocd/trunk@1634 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-07 oharboe * : Deleted at9sam7_old driver. Nobody has complained about the new one yet. git-svn-id: svn://svn.berlios.de/openocd/trunk@1632 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-07 oharboe * : another example of removing in_handler usage git-svn-id: svn://svn.berlios.de/openocd/trunk@1630 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-07 zwelch * : Fix most pointer cast alignment warnings in arm11.c; fix u16 memory reads.. git-svn-id: svn://svn.berlios.de/openocd/trunk@1628 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-07 zwelch * : Fix stm32x and pic32mx flash pointer cast alignment warnings, simplify their last word handling. git-svn-id: svn://svn.berlios.de/openocd/trunk@1626 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-06 zwelch * : Fix pointer cast alignment warnings in target/image.c. git-svn-id: svn://svn.berlios.de/openocd/trunk@1624 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-06 zwelch * : Fix pointer cast alignment issues in svf.c git-svn-id: svn://svn.berlios.de/openocd/trunk@1622 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-06 zwelch * : Fix pointer cast alignment warnings in jim.c. git-svn-id: svn://svn.berlios.de/openocd/trunk@1620 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-06 oharboe * : Dick Hollenbeck comments & 7 clock TMS reset for good measure git-svn-id: svn://svn.berlios.de/openocd/trunk@1618 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-06 mlu * : Small changes that might improve stability. Implemented new jtag sequences tap_get_tms_path and tap_get_tms_path_len git-svn-id: svn://svn.berlios.de/openocd/trunk@1616 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-06 oharboe * : Dick Hollenbeck simplifies XSTATE handling, and protects against illegal state transitions that might be in an SVF file. git-svn-id: svn://svn.berlios.de/openocd/trunk@1614 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-06 zwelch * : Fix enviorn configure test failure message (thanks to Anders Montonen). git-svn-id: svn://svn.berlios.de/openocd/trunk@1612 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-06 zwelch * : Add autoconf check to determine where environ should be declared. git-svn-id: svn://svn.berlios.de/openocd/trunk@1610 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-06 oharboe * : retire out_mask - not used anywhere git-svn-id: svn://svn.berlios.de/openocd/trunk@1608 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-05 oharboe * : made warning about keep_alive() not being invoked more helpful git-svn-id: svn://svn.berlios.de/openocd/trunk@1606 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-05 oharboe * : Gabor Juhos juhosg at openwrt.org MIPS: fix a shift value in the MIPS32_R_INST macro git-svn-id: svn://svn.berlios.de/openocd/trunk@1604 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-04 oharboe * : Dirk Behme Add minimalist Cortex A8 file git-svn-id: svn://svn.berlios.de/openocd/trunk@1602 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-04 oharboe * : Mariano Alvira fixes warning as error about a signed vs. unsigned comparison by casting the local unsigned variable as (long long). git-svn-id: svn://svn.berlios.de/openocd/trunk@1600 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-03 oharboe * : fix embedded builds git-svn-id: svn://svn.berlios.de/openocd/trunk@1598 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-03 zwelch * : Fix compilation when HAVE_UNISTD_H is not defined. git-svn-id: svn://svn.berlios.de/openocd/trunk@1596 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-03 oharboe * : Piotr Esden-Tempski Mac OS X compile fixes git-svn-id: svn://svn.berlios.de/openocd/trunk@1594 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-02 zwelch * : Add configure check for usb.h; required by a USB drivers. git-svn-id: svn://svn.berlios.de/openocd/trunk@1592 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-02 oharboe * : Dick Hollenbeck moved stuff into openocd.c - should never have been in main.c in the first place. DLL will now build. git-svn-id: svn://svn.berlios.de/openocd/trunk@1590 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-01 zwelch * : Remove superflous spaces from new JTAG table to fix formatting. git-svn-id: svn://svn.berlios.de/openocd/trunk@1588 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-05-01 zwelch * : Dick Hollenbeck : move OPENOCD_VERSION to use config.h git-svn-id: svn://svn.berlios.de/openocd/trunk@1586 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-30 zwelch * : Uwe Hermann : Make ICEbear look like other targets git-svn-id: svn://svn.berlios.de/openocd/trunk@1584 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-30 oharboe * : list board's as well as target config files. git-svn-id: svn://svn.berlios.de/openocd/trunk@1581 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-30 zwelch * : Add static keywords to core target source file data and functions. git-svn-id: svn://svn.berlios.de/openocd/trunk@1579 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-30 zwelch * : Fix signed/unsigned comparison. git-svn-id: svn://svn.berlios.de/openocd/trunk@1577 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-30 oharboe * : flash fillX now has a verify stage git-svn-id: svn://svn.berlios.de/openocd/trunk@1575 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-30 zwelch * : Michael Bruck : sys/select.h must preceed windows.h. git-svn-id: svn://svn.berlios.de/openocd/trunk@1573 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-29 mlu * : Clear FLASH_SR error flags after flash errors to avoid reset befor further flash operations. git-svn-id: svn://svn.berlios.de/openocd/trunk@1571 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-29 mlu * : More error logging for DAP errors git-svn-id: svn://svn.berlios.de/openocd/trunk@1569 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-29 oharboe * : comments and debug code git-svn-id: svn://svn.berlios.de/openocd/trunk@1567 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-29 zwelch * : Sten : add support for ICEbear FDTI-based interface. git-svn-id: svn://svn.berlios.de/openocd/trunk@1565 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-29 zwelch * : Remove vestigial last_tms variable from jlink driver. git-svn-id: svn://svn.berlios.de/openocd/trunk@1563 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-29 zwelch * : Fix jlink for Debian/Ubuntu (by Ben Dooks ). git-svn-id: svn://svn.berlios.de/openocd/trunk@1561 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-29 zwelch * : Add missing header files to fix C99 compatibility. git-svn-id: svn://svn.berlios.de/openocd/trunk@1559 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-28 oharboe * : Dick Hollenbeck and Jeff Williams tap_get_tms_path_len() git-svn-id: svn://svn.berlios.de/openocd/trunk@1557 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-28 ntfreak * : - fix win32 build git-svn-id: svn://svn.berlios.de/openocd/trunk@1555 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-28 oharboe * : Zach Welch fix gw16012 with --enable-parport_ppdev git-svn-id: svn://svn.berlios.de/openocd/trunk@1553 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-28 oharboe * : Michael Bruck macros for error handling git-svn-id: svn://svn.berlios.de/openocd/trunk@1551 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-28 oharboe * : eol-style native git-svn-id: svn://svn.berlios.de/openocd/trunk@1549 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-27 mlu * : Added dap baseaddr and dap apid commands git-svn-id: svn://svn.berlios.de/openocd/trunk@1547 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-27 oharboe * : SimonQian patch for error compiling vsllink if --enable-verbose-jtag-io is set git-svn-id: svn://svn.berlios.de/openocd/trunk@1545 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-27 oharboe * : more error handling git-svn-id: svn://svn.berlios.de/openocd/trunk@1543 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-27 oharboe * : SimonQian AVR wip git-svn-id: svn://svn.berlios.de/openocd/trunk@1540 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-27 mlu * : Deleted depreciated files ( new versions are arm_adi_v5.c/h ) git-svn-id: svn://svn.berlios.de/openocd/trunk@1538 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-27 mlu * : Changed armv7m and cortexm3 to use nev arm_adi_v5 instead of cortex_swjdp. Added support for accessport ROM table identification, dap command. git-svn-id: svn://svn.berlios.de/openocd/trunk@1536 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-27 oharboe * : Philippe Vachon 64 bit host fixes git-svn-id: svn://svn.berlios.de/openocd/trunk@1534 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-27 oharboe * : Zach Welch wrap _GNU_SOURCE defines git-svn-id: svn://svn.berlios.de/openocd/trunk@1532 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-26 oharboe * : R.Doss AT91SAM9260 git-svn-id: svn://svn.berlios.de/openocd/trunk@1530 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-25 mlu * : Corrected statement order git-svn-id: svn://svn.berlios.de/openocd/trunk@1528 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-25 mlu * : Break ft2232_execute_quie into smaller functions, follows restructure of jlink.c git-svn-id: svn://svn.berlios.de/openocd/trunk@1526 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-24 oharboe * : Zach Welch add TAP_SCAN_BYTES macro (1 of 2) git-svn-id: svn://svn.berlios.de/openocd/trunk@1524 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-24 oharboe * : Uwe Hermann Update udev file git-svn-id: svn://svn.berlios.de/openocd/trunk@1522 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-24 oharboe * : Nicolas Pitre update SheevaPlug interface cfg file git-svn-id: svn://svn.berlios.de/openocd/trunk@1520 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-24 duane * : Remove warning git-svn-id: svn://svn.berlios.de/openocd/trunk@1518 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-23 oharboe * : stm32.cfg can expect one of 4 id's. git-svn-id: svn://svn.berlios.de/openocd/trunk@1516 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-23 oharboe * : Laurentiu Cocanu - fix typo git-svn-id: svn://svn.berlios.de/openocd/trunk@1514 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-22 oharboe * : Michael Bruck ARM11 various updates + fix formatting. git-svn-id: svn://svn.berlios.de/openocd/trunk@1512 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-22 oharboe * : Michael Bruck spotted a typo in help messages git-svn-id: svn://svn.berlios.de/openocd/trunk@1510 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-22 oharboe * : Zach Welch set speed in init git-svn-id: svn://svn.berlios.de/openocd/trunk@1508 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-22 oharboe * : Zach Welch reorder enum tap_state git-svn-id: svn://svn.berlios.de/openocd/trunk@1506 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-22 kc8apf * : Shrink JLink buffer sizes to specified 2KB courtesy of Jeff Williams and Zach Welch git-svn-id: svn://svn.berlios.de/openocd/trunk@1504 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-22 kc8apf * : Fix use of wrong format conversion for size_t (%zu instead of %u) git-svn-id: svn://svn.berlios.de/openocd/trunk@1502 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-22 kc8apf * : refactor jlink_execute_queue courtesy of Zach Welch git-svn-id: svn://svn.berlios.de/openocd/trunk@1500 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-21 oharboe * : Zach Welch refactor git-svn-id: svn://svn.berlios.de/openocd/trunk@1498 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-21 oharboe * : Zach Welch add --enable-verbose* options git-svn-id: svn://svn.berlios.de/openocd/trunk@1496 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-21 oharboe * : Nico Coesel MIPS32 speedup patches git-svn-id: svn://svn.berlios.de/openocd/trunk@1494 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-21 oharboe * : Zach Welch factor jlink usb_bulk_*_ex functions git-svn-id: svn://svn.berlios.de/openocd/trunk@1492 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-21 oharboe * : Zach Welch improve Linux ftd2xx configure-time support git-svn-id: svn://svn.berlios.de/openocd/trunk@1490 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-21 ntfreak * : - remove environ warning under win32 build git-svn-id: svn://svn.berlios.de/openocd/trunk@1488 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-21 oharboe * : Zach Welch fix unused return value warnings (2 of 4) git-svn-id: svn://svn.berlios.de/openocd/trunk@1486 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-21 oharboe * : Zach Welch fix str9x type-punned pointer git-svn-id: svn://svn.berlios.de/openocd/trunk@1484 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-21 oharboe * : Zach Welch fix unused return value warnings (3 of 4) git-svn-id: svn://svn.berlios.de/openocd/trunk@1482 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-21 oharboe * : Michael Schwingen add non-CFI SST flashs git-svn-id: svn://svn.berlios.de/openocd/trunk@1480 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-20 ntfreak * : - fix at91rm9200 warning. Thanks Zach Welch - add missing svn props from previous commit git-svn-id: svn://svn.berlios.de/openocd/trunk@1478 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-20 oharboe * : Zach Welch fix ft2232/presto warnings git-svn-id: svn://svn.berlios.de/openocd/trunk@1476 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-19 oharboe * : Zach Welch use ARM4_5_MODE_ANY instead of -1 git-svn-id: svn://svn.berlios.de/openocd/trunk@1474 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-19 oharboe * : Zach Welch fix -Werror warnings git-svn-id: svn://svn.berlios.de/openocd/trunk@1472 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-19 mifi * : Added functionality to support jtag_khz for the jlink. git-svn-id: svn://svn.berlios.de/openocd/trunk@1470 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-19 oharboe * : Zach Welch add missing initializers in nand.c git-svn-id: svn://svn.berlios.de/openocd/trunk@1468 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-19 oharboe * : Zach Welch fix signed/unsigned comparisons git-svn-id: svn://svn.berlios.de/openocd/trunk@1466 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-19 oharboe * : Zach Welch use tap_state_t git-svn-id: svn://svn.berlios.de/openocd/trunk@1464 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-18 mifi * : The following patches was applied: - openocd-flash-static-keyword-v3.patch - openocd-lpc2000-fix-erase-obo.patch - openocd-jlink-fix-sign-ptr-warn.patch - openocd-wextra-etm.patch - openocd-wextra-jtag.patch - openocd-add-new-tap-symbols-v6.patch Many thanks to Zach Welch git-svn-id: svn://svn.berlios.de/openocd/trunk@1462 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-15 oharboe * : Piotr Esden-Tempski Corrected olimex_stm32_h103 board config git-svn-id: svn://svn.berlios.de/openocd/trunk@1460 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-15 oharboe * : Freddie Chopin LPC2378 config file git-svn-id: svn://svn.berlios.de/openocd/trunk@1458 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-14 mlu * : Improved (for humans) error reporting for flash programming errors. git-svn-id: svn://svn.berlios.de/openocd/trunk@1456 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-03 ntfreak * : - add openocd coding style to texi git-svn-id: svn://svn.berlios.de/openocd/trunk@1454 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-03 ntfreak * : - add svn props from previous commit git-svn-id: svn://svn.berlios.de/openocd/trunk@1452 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-03 oharboe * : Piotr Esden-Tempski added a board file for the Olimex STM32-H103 eval board. git-svn-id: svn://svn.berlios.de/openocd/trunk@1450 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-03 oharboe * : Nicolas Pitre nico at cam.org list the new flag in the "nand write" help line. git-svn-id: svn://svn.berlios.de/openocd/trunk@1448 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-02 oharboe * : Nicolas Pitre nico at cam.org The ECC data is automatically computed and written to the OOB area when the oob_softecc option is passed to the "nand write" command. git-svn-id: svn://svn.berlios.de/openocd/trunk@1446 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-02 oharboe * : Nicolas Pitre nico at cam.org software ECC computation for NAND flash git-svn-id: svn://svn.berlios.de/openocd/trunk@1444 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-02 oharboe * : Nicolas Pitre nico at cam.org Allocating a 6-byte memory location with malloc() is rather silly when this can be allocated on the stack. git-svn-id: svn://svn.berlios.de/openocd/trunk@1442 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-02 oharboe * : Uwe Hermann URL references git-svn-id: svn://svn.berlios.de/openocd/trunk@1439 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-04-02 oharboe * : fix keyword expansion git-svn-id: svn://svn.berlios.de/openocd/trunk@1437 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-03-30 ntfreak * : - add missing usbprog config. patch from Uwe Hermann https://lists.berlios.de/pipermail/openocd-development/2009-March/005145.htmlgit-svn-id: svn://svn.berlios.de/openocd/trunk@1435 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-03-24 ntfreak * : - fix typo's in last commit git-svn-id: svn://svn.berlios.de/openocd/trunk@1433 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-03-24 ntfreak * : - update str9 and stm32 comstick configs - add missing svn props git-svn-id: svn://svn.berlios.de/openocd/trunk@1431 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-03-24 oharboe * : Uwe Hermann Add new board configs: Olimex LPC-H2148, Keil MCB2140. Both boards use an LPC2148, no external flash or RAM. git-svn-id: svn://svn.berlios.de/openocd/trunk@1429 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-03-23 oharboe * : Uwe Hermann eal _CPUTAPID entry for the LPC2148. I don't know if they're the same for all LPC214x, this number is from an Olimex LPC-H2148. The chip on that board is LPC2148FBD64. Also fix a few cosmetic issues and comments in the file and add more docs and pointers to the datasheet. git-svn-id: svn://svn.berlios.de/openocd/trunk@1427 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-03-23 oharboe * : Uwe Hermann typo git-svn-id: svn://svn.berlios.de/openocd/trunk@1425 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-03-20 ntfreak * : - add missing svn props from previous commit git-svn-id: svn://svn.berlios.de/openocd/trunk@1423 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-03-20 oharboe * : Alan Carvalho de Assis adds support to i.MX35 processor. git-svn-id: svn://svn.berlios.de/openocd/trunk@1421 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-03-19 ntfreak * : - fix incorrect str9comstick cfg git-svn-id: svn://svn.berlios.de/openocd/trunk@1419 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-03-18 oharboe * : Hiroshi Ito typos git-svn-id: svn://svn.berlios.de/openocd/trunk@1417 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-03-17 ntfreak * : - remove build warnings git-svn-id: svn://svn.berlios.de/openocd/trunk@1415 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-03-16 ntfreak * : - fix issue with cortex_m3 reset run. Thanks Perry Hung - https://lists.berlios.de/pipermail/openocd-development/2009-March/005028.htmlgit-svn-id: svn://svn.berlios.de/openocd/trunk@1413 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-03-12 oharboe * : Uwe Hermann typos git-svn-id: svn://svn.berlios.de/openocd/trunk@1411 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-03-11 duane * : Added eol-style props git-svn-id: svn://svn.berlios.de/openocd/trunk@1409 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-03-11 duane * : Added -endstate to irscan and drscan to support beagleboard (omap3530) git-svn-id: svn://svn.berlios.de/openocd/trunk@1407 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-03-08 ntfreak * : - add svn props from previous commit git-svn-id: svn://svn.berlios.de/openocd/trunk@1405 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-03-08 duane * : Added VID/PID pair to olimex-jtag-tiny-a the non-a version already has the vid pid git-svn-id: svn://svn.berlios.de/openocd/trunk@1403 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-03-07 duane * : Accept/create both A and Non-A ft2232 based descriptions git-svn-id: svn://svn.berlios.de/openocd/trunk@1401 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-03-05 oharboe * : Audrius UrmanaviÄius cleanup flash fill git-svn-id: svn://svn.berlios.de/openocd/trunk@1399 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-03-04 oharboe * : Nicolas Pitre making reset+halt on the SheevaPlug 100% reliable (needs patch in target.c to fix "halt 0"). git-svn-id: svn://svn.berlios.de/openocd/trunk@1397 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-03-02 ntfreak * : - add missing svn props from previous commit git-svn-id: svn://svn.berlios.de/openocd/trunk@1395 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-03-01 oharboe * : Kees Jongenburger rename description field of the jtag-tiny.cfg git-svn-id: svn://svn.berlios.de/openocd/trunk@1393 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-03-01 oharboe * : Nicolas Pitre nico at cam.org SheevaPlug board configuration git-svn-id: svn://svn.berlios.de/openocd/trunk@1391 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-03-01 oharboe * : Nicolas Pitre nico at cam.org add Feroceon target config file git-svn-id: svn://svn.berlios.de/openocd/trunk@1389 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-03-01 oharboe * : Nicolas Pitre nico at cam.org support for NAND controllers without explicit busy signal git-svn-id: svn://svn.berlios.de/openocd/trunk@1387 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-03-01 oharboe * : Nicolas Pitre nico at cam.org The code unconditionally writes into the oob area all the time. git-svn-id: svn://svn.berlios.de/openocd/trunk@1385 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-02-26 ntfreak * : - stm32x flash driver - add support for stm32105/107 (connectivity line) git-svn-id: svn://svn.berlios.de/openocd/trunk@1383 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-02-23 oharboe * : tinkered a bit with performance for Cortex flash programming. Mainly make it easier to profile as a start. git-svn-id: svn://svn.berlios.de/openocd/trunk@1380 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-02-22 oharboe * : John Woods fix newtap gaffe + rename git-svn-id: svn://svn.berlios.de/openocd/trunk@1378 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-02-18 oharboe * : Holger Schurig incorporate some comments from Rick git-svn-id: svn://svn.berlios.de/openocd/trunk@1376 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-02-17 oharboe * : zy1000 1.49 snapshot git-svn-id: svn://svn.berlios.de/openocd/trunk@1374 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-02-13 ntfreak * : - guess-rev.sh now works as expected when build_dir is not the same as src_dir git-svn-id: svn://svn.berlios.de/openocd/trunk@1372 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-02-10 kc8apf * : Use C89/C99/C++ compliant boolean types git-svn-id: svn://svn.berlios.de/openocd/trunk@1370 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-02-09 ntfreak * : - fix native win32 build issues git-svn-id: svn://svn.berlios.de/openocd/trunk@1368 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-02-03 kc8apf * : - Cable driver helper API courtesy of Dick Hollenbeck - Formatting changes from uncrustify git-svn-id: svn://svn.berlios.de/openocd/trunk@1366 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-02-03 kc8apf * : Add uncrustify config file and helper script git-svn-id: svn://svn.berlios.de/openocd/trunk@1364 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-01-26 oharboe * : update symbols to match source file git-svn-id: svn://svn.berlios.de/openocd/trunk@1362 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-01-23 kc8apf * : xvsf player fixes by Dick Hollenbeck git-svn-id: svn://svn.berlios.de/openocd/trunk@1360 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-01-23 kc8apf * : Search path fixes for MinGW builds. Courtesy of Dimitar Dimitrov git-svn-id: svn://svn.berlios.de/openocd/trunk@1358 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-01-23 kc8apf * : vsllink support for stable clocks by Simon Qian git-svn-id: svn://svn.berlios.de/openocd/trunk@1356 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-01-20 kc8apf * : Fix for incorrect filename in include for at91sam9260 in unknown-board-atmel-at91sam9260.cfg git-svn-id: svn://svn.berlios.de/openocd/trunk@1353 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-01-20 ntfreak * : - add --enable-release to docs git-svn-id: svn://svn.berlios.de/openocd/trunk@1351 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-01-20 kc8apf * : Add axm0432 interface config courtesy of Alan Carvalho de Assis git-svn-id: svn://svn.berlios.de/openocd/trunk@1349 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-01-20 kc8apf * : Fix 'make maintainer-clean' courtesy of Zach Welch git-svn-id: svn://svn.berlios.de/openocd/trunk@1345 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-01-20 kc8apf * : Fix support for ADuC702x flash. Courtesy of Michael Ashton git-svn-id: svn://svn.berlios.de/openocd/trunk@1343 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-01-19 ntfreak * : - remove unused includes, fixes build issues under FreeBSD git-svn-id: svn://svn.berlios.de/openocd/trunk@1341 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-01-19 kc8apf * : SVF player courtesy of Simon Qian git-svn-id: svn://svn.berlios.de/openocd/trunk@1339 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-01-17 kc8apf * : Fix guess-rev.sh where the builtin echo doesn't support -n git-svn-id: svn://svn.berlios.de/openocd/trunk@1337 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-01-16 ntfreak * : - make guess-rev.sh work with msys git-svn-id: svn://svn.berlios.de/openocd/trunk@1333 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-01-16 ntfreak * : - add missing bitq and rlink files to distribution git-svn-id: svn://svn.berlios.de/openocd/trunk@1331 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-01-15 ntfreak * : - add missing svn props from 1323 commit git-svn-id: svn://svn.berlios.de/openocd/trunk@1324 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-01-15 oharboe * : Alan Carvalho de Assis imx31pdk.cfg reset init event git-svn-id: svn://svn.berlios.de/openocd/trunk@1322 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-01-14 oharboe * : wip git-svn-id: svn://svn.berlios.de/openocd/trunk@1320 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-01-14 oharboe * : Alan Carvalho de Assis cfg file to initialize the iMX27ADS board. git-svn-id: svn://svn.berlios.de/openocd/trunk@1318 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-01-14 oharboe * : Alan Carvalho de Assis small fix to move us in the right direction. git-svn-id: svn://svn.berlios.de/openocd/trunk@1316 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-01-13 ntfreak * : - fix mips issues with newer versions of gdb - we simply add more dummy registers git-svn-id: svn://svn.berlios.de/openocd/trunk@1314 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-01-09 oharboe * : wip git-svn-id: svn://svn.berlios.de/openocd/trunk@1312 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-01-09 oharboe * : allow issuing reset_config on the fly. Faster turnaround times in testing. git-svn-id: svn://svn.berlios.de/openocd/trunk@1310 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-01-09 oharboe * : Dick Hollenbeck adds jtag_add_clocks() and implements those in the bitbang and ft2232.c. nearly a full rewrite of the xsvf.c. improved some messaging only affected by _DEBUG_JTAG_IO_ git-svn-id: svn://svn.berlios.de/openocd/trunk@1308 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-01-08 ntfreak * : - a few more docs tweaks git-svn-id: svn://svn.berlios.de/openocd/trunk@1306 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-01-07 oharboe * : Dick Hollenbeck SVF to XSVF converter and the XSVF dumper take #2 git-svn-id: svn://svn.berlios.de/openocd/trunk@1304 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-01-05 ntfreak * : - add missing svn props from r1299 commit git-svn-id: svn://svn.berlios.de/openocd/trunk@1302 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-01-05 oharboe * : John McCarthy formatting fix of debug output git-svn-id: svn://svn.berlios.de/openocd/trunk@1300 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-01-04 oharboe * : eol-style native git-svn-id: svn://svn.berlios.de/openocd/trunk@1298 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-01-02 oharboe * : John McCarthy pic32mx flash wip git-svn-id: svn://svn.berlios.de/openocd/trunk@1296 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2009-01-01 ntfreak * : - add gdb pipe support to native win32 (--pipe option) git-svn-id: svn://svn.berlios.de/openocd/trunk@1294 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-28 ntfreak * : - fix missing/incorrect svn file props git-svn-id: svn://svn.berlios.de/openocd/trunk@1292 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-27 duane * : Added another test build configuration git-svn-id: svn://svn.berlios.de/openocd/trunk@1290 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-27 duane * : Missed the svn add on earlier commit, duh git-svn-id: svn://svn.berlios.de/openocd/trunk@1288 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-27 duane * : Added note to user manual for packagers of OpenOCD git-svn-id: svn://svn.berlios.de/openocd/trunk@1286 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-27 duane * : Some systems report linux as host, others linux-gnu... grrr git-svn-id: svn://svn.berlios.de/openocd/trunk@1284 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-27 duane * : From Lou.openocd012@fixit.nospammail.net git-svn-id: svn://svn.berlios.de/openocd/trunk@1282 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-27 duane * : Added dongle VSLLINK - from Simon Qian git-svn-id: svn://svn.berlios.de/openocd/trunk@1280 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-27 duane * : From Dirk Behme - Further docu fixes git-svn-id: svn://svn.berlios.de/openocd/trunk@1278 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-27 duane * : Renamed build.tests to build.test1 git-svn-id: svn://svn.berlios.de/openocd/trunk@1276 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-24 duane * : Typos found by miceal catudal git-svn-id: svn://svn.berlios.de/openocd/trunk@1274 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-23 oharboe * : httpd wip git-svn-id: svn://svn.berlios.de/openocd/trunk@1272 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-22 oharboe * : httpd wip git-svn-id: svn://svn.berlios.de/openocd/trunk@1269 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-22 oharboe * : Dirk Behme Add missing tap-enable and tap-disable events to documentation. git-svn-id: svn://svn.berlios.de/openocd/trunk@1267 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-22 oharboe * : bumped a LOG_INFO to LOG_DEBUG level to reduce excessive output for normal execution git-svn-id: svn://svn.berlios.de/openocd/trunk@1265 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-19 oharboe * : Dick Hollenbeck - This patch adds JTAG state tracking to dummy.c git-svn-id: svn://svn.berlios.de/openocd/trunk@1263 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-19 oharboe * : Dick Hollenbeck better comments git-svn-id: svn://svn.berlios.de/openocd/trunk@1261 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-19 oharboe * : Dick Hollenbeck convert macros to inline fn's. git-svn-id: svn://svn.berlios.de/openocd/trunk@1259 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-17 oharboe * : check syntax for init/version git-svn-id: svn://svn.berlios.de/openocd/trunk@1257 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-17 oharboe * : houskeeping git-svn-id: svn://svn.berlios.de/openocd/trunk@1255 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-16 oharboe * : work in progress to hook up libmicrohttpd + tcl integration git-svn-id: svn://svn.berlios.de/openocd/trunk@1251 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-16 oharboe * : Dirk Behme Fix some typos in documentation git-svn-id: svn://svn.berlios.de/openocd/trunk@1249 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-16 oharboe * : allow setting/reading gdb_port at any time git-svn-id: svn://svn.berlios.de/openocd/trunk@1247 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-15 ntfreak * : - add missing svn props from r1243 commit git-svn-id: svn://svn.berlios.de/openocd/trunk@1245 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-15 oharboe * : sync up to tap_xxx rename + add with-ioutil for standalone openocd implemetnations git-svn-id: svn://svn.berlios.de/openocd/trunk@1243 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-15 oharboe * : fast_load profiling tool moved to target.c git-svn-id: svn://svn.berlios.de/openocd/trunk@1241 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-13 duane * : Updates and fixes from Kees Jongenburger git-svn-id: svn://svn.berlios.de/openocd/trunk@1239 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-13 kc8apf * : Add JTAG tap events for enable/disable git-svn-id: svn://svn.berlios.de/openocd/trunk@1237 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-13 kc8apf * : Change tap_state naming to be consistent with SVF documentation. Courtesy of Dick Hollenbeck git-svn-id: svn://svn.berlios.de/openocd/trunk@1232 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-12 kc8apf * : Allow -expected-id to be specified multiple times when creating a jtag tap git-svn-id: svn://svn.berlios.de/openocd/trunk@1229 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-11 ntfreak * : - added Axiom AXM-0432 to texi - updated missing jtag dongle url's in texi - reformat and remove whitespace from last commit git-svn-id: svn://svn.berlios.de/openocd/trunk@1227 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-11 ntfreak * : - typo with flash bank help command - typo with flash erase_sector in texi git-svn-id: svn://svn.berlios.de/openocd/trunk@1225 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-10 duane * : More fixes thanks to Kees Jongenburger git-svn-id: svn://svn.berlios.de/openocd/trunk@1223 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-10 duane * : Fix from Kees Jongenburger git-svn-id: svn://svn.berlios.de/openocd/trunk@1221 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-06 duane * : Test of commit email from duane git-svn-id: svn://svn.berlios.de/openocd/trunk@1219 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-05 oharboe * : Karl Beldan - The ibcr count for hw instruction breakpoint registers was decremented with soft breakpoints and breakpoint length error. git-svn-id: svn://svn.berlios.de/openocd/trunk@1215 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-04 oharboe * : zy1000 1.48 snapshot git-svn-id: svn://svn.berlios.de/openocd/trunk@1213 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-04 oharboe * : delete obsolete code git-svn-id: svn://svn.berlios.de/openocd/trunk@1211 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-04 duane * : Fix for Hiroshi Ito discovery of mis-aligned memory allocation git-svn-id: svn://svn.berlios.de/openocd/trunk@1205 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-03 ntfreak * : - incorrect str9 irmask used in config files git-svn-id: svn://svn.berlios.de/openocd/trunk@1203 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-02 oharboe * : Kees Jongenburger - now compiles git-svn-id: svn://svn.berlios.de/openocd/trunk@1201 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-01 oharboe * : "Theodore A. Roth" fixes to distcheck git-svn-id: svn://svn.berlios.de/openocd/trunk@1199 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-01 oharboe * : update zy1000 to svn head jtag api git-svn-id: svn://svn.berlios.de/openocd/trunk@1197 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-12-01 oharboe * : wip git-svn-id: svn://svn.berlios.de/openocd/trunk@1195 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-11-30 duane * : Test checkin from commandline git-svn-id: svn://svn.berlios.de/openocd/trunk@1193 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-11-27 ntfreak * : - fix issue with luminary flash driver and tail bytes git-svn-id: svn://svn.berlios.de/openocd/trunk@1191 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-11-27 ntfreak * : - stm32x flash driver: add support for low density devices git-svn-id: svn://svn.berlios.de/openocd/trunk@1189 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-11-26 ntfreak * : - fixes segfault using the targets cmd if multiple targets defined git-svn-id: svn://svn.berlios.de/openocd/trunk@1187 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-11-26 oharboe * : friendlier error messages git-svn-id: svn://svn.berlios.de/openocd/trunk@1185 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-11-21 ntfreak * : - add new cortex_m3 maskisr cmd git-svn-id: svn://svn.berlios.de/openocd/trunk@1181 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-11-20 ntfreak * : - preserve cortex_m3 C_MASKINTS during resume/step git-svn-id: svn://svn.berlios.de/openocd/trunk@1179 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-11-19 oharboe * : jtag_get_device() now returns NULL and reports error instead of invoking exit() git-svn-id: svn://svn.berlios.de/openocd/trunk@1176 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-11-18 oharboe * : big endian fix for GDB. Probably fixes a memory corruption(not reported) as well. git-svn-id: svn://svn.berlios.de/openocd/trunk@1174 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-11-14 ntfreak * : - stops multiple calls to examine from allocating the breakpoint arrays git-svn-id: svn://svn.berlios.de/openocd/trunk@1171 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-11-13 oharboe * : big endian software breakpoint bogus error messages fixed git-svn-id: svn://svn.berlios.de/openocd/trunk@1167 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-11-13 oharboe * : nios wip git-svn-id: svn://svn.berlios.de/openocd/trunk@1165 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-11-12 ntfreak * : - slight mips32 cleanup/reformat - add missing svn props git-svn-id: svn://svn.berlios.de/openocd/trunk@1159 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-11-11 oharboe * : Fixes (more or less) random SEGFAULT upon invoking script_command(). git-svn-id: svn://svn.berlios.de/openocd/trunk@1156 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-11-10 oharboe * : broadcast mac address in UDP hello message git-svn-id: svn://svn.berlios.de/openocd/trunk@1152 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-11-10 oharboe * : minor cleanup git-svn-id: svn://svn.berlios.de/openocd/trunk@1149 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-11-07 oharboe * : ocd_flash_banks now returns empty list when no flash banks are configured instead of failing. Allows more orthogonal implementations of tcl code. git-svn-id: svn://svn.berlios.de/openocd/trunk@1147 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-11-07 oharboe * : ocd_flash_banks now returns empty list when no flash banks are configured instead of failing. Allows more orthogonal implementations of tcl code. git-svn-id: svn://svn.berlios.de/openocd/trunk@1144 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-11-06 ntfreak * : - remove build warnings - added svn props for newly added files git-svn-id: svn://svn.berlios.de/openocd/trunk@1142 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-11-06 oharboe * : s3c6410 chip git-svn-id: svn://svn.berlios.de/openocd/trunk@1140 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-11-05 oharboe * : 926ejs target uses rclk. Cleaned up jtag_khz output a bit. git-svn-id: svn://svn.berlios.de/openocd/trunk@1138 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-11-05 oharboe * : wip git-svn-id: svn://svn.berlios.de/openocd/trunk@1136 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-11-05 oharboe * : disable continous polling while srst is asserted and power dropout is detected git-svn-id: svn://svn.berlios.de/openocd/trunk@1134 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-11-04 oharboe * : arm7_9_execute_sys_speed error propagation. Found by code inspection, no observed problems as such. git-svn-id: svn://svn.berlios.de/openocd/trunk@1132 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-11-04 oharboe * : Added Tcl escaping to FAQ git-svn-id: svn://svn.berlios.de/openocd/trunk@1130 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-11-03 ntfreak * : - fix issue with jlink/libusb timeout under linux - add missing svn props git-svn-id: svn://svn.berlios.de/openocd/trunk@1128 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-11-03 oharboe * : Rick Altherr - fix warnings git-svn-id: svn://svn.berlios.de/openocd/trunk@1126 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-11-02 oharboe * : invoke target_create() once git-svn-id: svn://svn.berlios.de/openocd/trunk@1124 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-11-02 oharboe * : Alan Carvalho de Assis imx27 config file git-svn-id: svn://svn.berlios.de/openocd/trunk@1122 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-11-02 oharboe * : Rick Altherr - fix flash write_bank output. git-svn-id: svn://svn.berlios.de/openocd/trunk@1120 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-11-02 oharboe * : no longer used git-svn-id: svn://svn.berlios.de/openocd/trunk@1118 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-31 oharboe * : Rick Altherr switch to new syntax for target events git-svn-id: svn://svn.berlios.de/openocd/trunk@1116 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-30 oharboe * : Hongtao Zheng single step fixes git-svn-id: svn://svn.berlios.de/openocd/trunk@1113 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-28 oharboe * : Kees Jongenburger update syntax git-svn-id: svn://svn.berlios.de/openocd/trunk@1111 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-28 oharboe * : Hongtao Zheng - fix a simulation error for "BX PC" git-svn-id: svn://svn.berlios.de/openocd/trunk@1109 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-27 oharboe * : Kees Jongenburger old" syntax target command appears to be broken this patch addresses this issue git-svn-id: svn://svn.berlios.de/openocd/trunk@1107 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-27 oharboe * : Hongtao Zheng - add simulation because previous functions could not halt for instructions that next pc equal to the current pc. git-svn-id: svn://svn.berlios.de/openocd/trunk@1105 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-27 oharboe * : added option to use ramdisk instead of flash jffs2 git-svn-id: svn://svn.berlios.de/openocd/trunk@1103 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-24 ntfreak * : - fix native mingw build if gettimeofday not defined. - reformat whitespace in startup.tcl git-svn-id: svn://svn.berlios.de/openocd/trunk@1101 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-23 oharboe * : fix working memory location git-svn-id: svn://svn.berlios.de/openocd/trunk@1098 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-23 oharboe * : only log BUG: (do not return error) in the case of unknown debug reason(0xc) git-svn-id: svn://svn.berlios.de/openocd/trunk@1096 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-22 oharboe * : load and verify are now synonymous to load/verify_image git-svn-id: svn://svn.berlios.de/openocd/trunk@1092 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-22 oharboe * : produce syntax error git-svn-id: svn://svn.berlios.de/openocd/trunk@1090 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-22 oharboe * : Laurentiu Cocanu - more help text git-svn-id: svn://svn.berlios.de/openocd/trunk@1088 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-22 oharboe * : version number keyword expansion handling git-svn-id: svn://svn.berlios.de/openocd/trunk@1086 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-21 oharboe * : remove duplicate target git-svn-id: svn://svn.berlios.de/openocd/trunk@1084 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-17 ntfreak * : - add link in texi docs git-svn-id: svn://svn.berlios.de/openocd/trunk@1081 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-17 ntfreak * : - remove texi warnings git-svn-id: svn://svn.berlios.de/openocd/trunk@1079 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-16 oharboe * : sleep command now prints out target debugmsgs w/anything like usable performance git-svn-id: svn://svn.berlios.de/openocd/trunk@1076 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-16 oharboe * : Laurentiu Cocanu - integrated new tcl target command docs git-svn-id: svn://svn.berlios.de/openocd/trunk@1073 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-16 oharboe * : adding concept of production script git-svn-id: svn://svn.berlios.de/openocd/trunk@1071 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-16 oharboe * : added capture command to capture log output. Useful when wanting to capture log output from tcl procedures that invoke openocd commands git-svn-id: svn://svn.berlios.de/openocd/trunk@1069 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-16 oharboe * : unsik Kim - mflash support git-svn-id: svn://svn.berlios.de/openocd/trunk@1067 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-15 ntfreak * : - fix tcl_port typo in docs - remove build warning from openocd.c - add missing svn props git-svn-id: svn://svn.berlios.de/openocd/trunk@1065 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-15 oharboe * : ê¹€ìš´ì‹ spotted a bug in target_write_u8 git-svn-id: svn://svn.berlios.de/openocd/trunk@1063 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-14 oharboe * : Laurentiu Cocanu - fix error handling git-svn-id: svn://svn.berlios.de/openocd/trunk@1061 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-14 oharboe * : Laurentiu Cocanu - more error handling fixes git-svn-id: svn://svn.berlios.de/openocd/trunk@1059 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-14 oharboe * : clarified jtag_ntrst_delay option git-svn-id: svn://svn.berlios.de/openocd/trunk@1056 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-14 oharboe * : testing of syntax error in reset and at startup git-svn-id: svn://svn.berlios.de/openocd/trunk@1054 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-14 oharboe * : added warning to use GDB 6.7 or newer git-svn-id: svn://svn.berlios.de/openocd/trunk@1052 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-14 oharboe * : John McCarthy two patches add a mips_m4k target option (ejtag_reset) to cause a reset command to use the EJTAG Peripheral and System Reset in addition to srst. This is for targets like the wrt54gl which do not connect the srst to a system reset (I believe it just goes to a GPIO). git-svn-id: svn://svn.berlios.de/openocd/trunk@1050 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-14 oharboe * : reset cleanup git-svn-id: svn://svn.berlios.de/openocd/trunk@1048 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-13 oharboe * : SEGFAULT gaffe in dummy register handling git-svn-id: svn://svn.berlios.de/openocd/trunk@1046 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-13 oharboe * : fix crash when connecting GDB to powered down target git-svn-id: svn://svn.berlios.de/openocd/trunk@1044 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-13 oharboe * : Fixed gaffes in reset script handling + improved error messages a bit. The file and line # of the syntax error in a reset script is now printed. git-svn-id: svn://svn.berlios.de/openocd/trunk@1042 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-12 oharboe * : Fix problems with DCC downloads routine crashing silently. git-svn-id: svn://svn.berlios.de/openocd/trunk@1040 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-10 oharboe * : John McCarthy openocd-usb.cfg added git-svn-id: svn://svn.berlios.de/openocd/trunk@1038 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-09 oharboe * : enumeration of threads for testing purposes. git-svn-id: svn://svn.berlios.de/openocd/trunk@1035 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-09 oharboe * : added busy sleep (for testing purposes) git-svn-id: svn://svn.berlios.de/openocd/trunk@1033 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-08 oharboe * : Richard Missenden exit now works during startup script git-svn-id: svn://svn.berlios.de/openocd/trunk@1031 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-08 oharboe * : John McCarthy adds support for DMA mode access as supported by EJTAG 1.0/2.0 processors git-svn-id: svn://svn.berlios.de/openocd/trunk@1029 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-07 oharboe * : reduce patch problems by moving $xxx expansion into seperate fn git-svn-id: svn://svn.berlios.de/openocd/trunk@1027 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-07 oharboe * : Frederik Kriewitz Segmentation fault fix. git-svn-id: svn://svn.berlios.de/openocd/trunk@1025 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-07 oharboe * : Georg Acher - arm11 wip. run algorithm + small init bugfix. git-svn-id: svn://svn.berlios.de/openocd/trunk@1023 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-06 oharboe * : basic smoketest on lm3s3748.elf git-svn-id: svn://svn.berlios.de/openocd/trunk@1020 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-06 oharboe * : better keep_alive() handling git-svn-id: svn://svn.berlios.de/openocd/trunk@1018 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-05 oharboe * : Georg Acher corrected TDO sampling git-svn-id: svn://svn.berlios.de/openocd/trunk@1016 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-03 oharboe * : GDB alive fixes for verify_image git-svn-id: svn://svn.berlios.de/openocd/trunk@1014 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-10-01 oharboe * : fixed gaffe: disable interrupts reset init script git-svn-id: svn://svn.berlios.de/openocd/trunk@1012 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-09-29 ntfreak * : - at91sam7.c remove build warnings git-svn-id: svn://svn.berlios.de/openocd/trunk@1010 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-09-26 oharboe * : I do not know why this is necessary, but it fixes strange effects (step/resume cause a NMI after reset) on LM3S6918 -- Michael Schwingen git-svn-id: svn://svn.berlios.de/openocd/trunk@1008 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-09-26 oharboe * : wip git-svn-id: svn://svn.berlios.de/openocd/trunk@1006 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-09-25 ntfreak * : - update docs for aduc702x flash driver git-svn-id: svn://svn.berlios.de/openocd/trunk@996 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-09-24 oharboe * : fix noise in gdb console when single stepping. Remove printing of log before processing halted event. git-svn-id: svn://svn.berlios.de/openocd/trunk@994 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-09-24 oharboe * : "marcel" , I have the ADuC702x flashdriver working again (see attachment). It adds the option to erase and write the ADuC702x flash git-svn-id: svn://svn.berlios.de/openocd/trunk@992 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-09-21 oharboe * : Removed some obsolete stuff + Pushing things in the direction of openocd.texi git-svn-id: svn://svn.berlios.de/openocd/trunk@990 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-09-21 oharboe * : put instructions on how to report bugs onto the users radar git-svn-id: svn://svn.berlios.de/openocd/trunk@988 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-09-12 oharboe * : follow up to keep_alive() fix. process target events before returning from reset procedure. git-svn-id: svn://svn.berlios.de/openocd/trunk@986 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-09-12 oharboe * : Duane Ellis: target_process_reset is now implemented in tcl. This allows better control from target configuration scripts. git-svn-id: svn://svn.berlios.de/openocd/trunk@984 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-09-08 oharboe * : typo fixed. git-svn-id: svn://svn.berlios.de/openocd/trunk@982 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-09-08 oharboe * : Duane Ellis, added clock command. git-svn-id: svn://svn.berlios.de/openocd/trunk@980 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-09-04 oharboe * : s3c2440 OpenMoko target script git-svn-id: svn://svn.berlios.de/openocd/trunk@978 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-09-01 oharboe * : Removed target->reset_mode, no longer used git-svn-id: svn://svn.berlios.de/openocd/trunk@976 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-09-01 oharboe * : retired, nothing came of it. git-svn-id: svn://svn.berlios.de/openocd/trunk@974 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-27 oharboe * : comment about slow RTCK git-svn-id: svn://svn.berlios.de/openocd/trunk@972 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-26 oharboe * : added 1000ms timeout git-svn-id: svn://svn.berlios.de/openocd/trunk@970 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-25 oharboe * : RCLK is not supported, return error instead of crashing. git-svn-id: svn://svn.berlios.de/openocd/trunk@968 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-25 oharboe * : fixed bug in arm11 examine code. git-svn-id: svn://svn.berlios.de/openocd/trunk@966 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-25 oharboe * : sync with Jim Tcl repository. git-svn-id: svn://svn.berlios.de/openocd/trunk@964 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-24 oharboe * : duan ellis target tcl work in progress converts a number of 'simple string lookup tables' into NVP tables. These NVP tables will be used by various commands coming in the next patch. git-svn-id: svn://svn.berlios.de/openocd/trunk@962 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-23 ntfreak * : - clear any existing breakpoints/watchpoints when restarting in gdb extended remote mode git-svn-id: svn://svn.berlios.de/openocd/trunk@960 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-22 ntfreak * : - fix win32 build issues from previous jim patch git-svn-id: svn://svn.berlios.de/openocd/trunk@958 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-20 oharboe * : added gdb timeout handling + error propagation git-svn-id: svn://svn.berlios.de/openocd/trunk@956 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-20 oharboe * : lm3s3748 config file git-svn-id: svn://svn.berlios.de/openocd/trunk@954 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-20 oharboe * : sharpen error propagation a wee bit. git-svn-id: svn://svn.berlios.de/openocd/trunk@952 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-20 oharboe * : Daniel Gimpelevich fix reset halt on feroceon git-svn-id: svn://svn.berlios.de/openocd/trunk@950 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-20 oharboe * : duane ellis: fix warning git-svn-id: svn://svn.berlios.de/openocd/trunk@948 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-19 oharboe * : fixed warning git-svn-id: svn://svn.berlios.de/openocd/trunk@946 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-19 oharboe * : make target_wait_state() usable from other places, made LOG_USER() output LOG_DEBUG() output. Avoids flooding logs in certain cases and OpenOCD will output error message if the halt fails. git-svn-id: svn://svn.berlios.de/openocd/trunk@944 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-19 oharboe * : search and replace usleep(1000) with alive_sleep(1) to avoid GDB timeouts. git-svn-id: svn://svn.berlios.de/openocd/trunk@942 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-19 oharboe * : added some alive_sleep()'s git-svn-id: svn://svn.berlios.de/openocd/trunk@940 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-19 oharboe * : added alive_sleep() function to let GDB alive packets be sent git-svn-id: svn://svn.berlios.de/openocd/trunk@938 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-19 oharboe * : duane ellis: (A) a new concept called "Name Value Pair" or NVP, in simple terms: Think: "String" and "Value". There can be many strings - all related to a single value, for examle: "T", "t", "y", "1", "yes", all can represent "truth", the reverse mapping is more simplistic - the first matching number wins. (B) a new "getopt" like feature for Jim - that simplifies argument parsing in complex functions, normally this would be used in conjunction with either an NVP table of options, or a more simpler Enumeration table. In contrast to the GNU "getopt" package, this is more of a "object model or code oriented" solution then a pure data structure used by GNU getopt, or the main stream Tcl/Tk option processing. git-svn-id: svn://svn.berlios.de/openocd/trunk@936 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-19 oharboe * : fix comment w.r.t. start address for RAM git-svn-id: svn://svn.berlios.de/openocd/trunk@934 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-19 oharboe * : removed a couple of exit()'s from error handling. git-svn-id: svn://svn.berlios.de/openocd/trunk@932 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-19 oharboe * : Daniel Gimpelevich one more parport device git-svn-id: svn://svn.berlios.de/openocd/trunk@930 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-18 oharboe * : more error propagation git-svn-id: svn://svn.berlios.de/openocd/trunk@928 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-18 oharboe * : openocd.texi is the authoratitive source for documentation. Wiki is dead. git-svn-id: svn://svn.berlios.de/openocd/trunk@926 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-17 oharboe * : deleted superfluous sam7s256 which was identical to sam7x256 git-svn-id: svn://svn.berlios.de/openocd/trunk@924 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-15 oharboe * : removed obsolete command. git-svn-id: svn://svn.berlios.de/openocd/trunk@922 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-14 oharboe * : arm7/9 breakpoint cleanup. arm7_9 sw/hw commands retired. openocd.texi is alerady updated. git-svn-id: svn://svn.berlios.de/openocd/trunk@920 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-14 oharboe * : documentation wip for upcoming patch. git-svn-id: svn://svn.berlios.de/openocd/trunk@918 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-13 oharboe * : force lpc2148 target into ARM state. git-svn-id: svn://svn.berlios.de/openocd/trunk@916 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-13 oharboe * : added global gdb breakpoint override configuration command git-svn-id: svn://svn.berlios.de/openocd/trunk@914 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-13 oharboe * : Clear all dangling breakpoints upon GDB connection. git-svn-id: svn://svn.berlios.de/openocd/trunk@912 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-13 oharboe * : return halted signal if step/continue fails git-svn-id: svn://svn.berlios.de/openocd/trunk@910 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-11 oharboe * : fix output from jtag_khz when only jtag_speed has been invoked git-svn-id: svn://svn.berlios.de/openocd/trunk@908 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-11 oharboe * : propagate error code in case of "reset" failing. git-svn-id: svn://svn.berlios.de/openocd/trunk@906 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-11 oharboe * : fix error message git-svn-id: svn://svn.berlios.de/openocd/trunk@904 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-08 ntfreak * : - fix build issues under win32 (mingw) git-svn-id: svn://svn.berlios.de/openocd/trunk@902 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-08 oharboe * : default reset in help text - run git-svn-id: svn://svn.berlios.de/openocd/trunk@900 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-07 oharboe * : David Kuehling - added jim-eventloop.c git-svn-id: svn://svn.berlios.de/openocd/trunk@898 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-07 ntfreak * : - correct BUILD_ECOSBOARD definition is server.c git-svn-id: svn://svn.berlios.de/openocd/trunk@896 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-06 ntfreak * : - added svn props for previously added file git-svn-id: svn://svn.berlios.de/openocd/trunk@894 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-05 oharboe * : GDB monitor commands now also get halted state upon e.g. "reset halt". git-svn-id: svn://svn.berlios.de/openocd/trunk@892 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-05 oharboe * : Duane Ellis: fix warnings git-svn-id: svn://svn.berlios.de/openocd/trunk@890 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-05 oharboe * : define resetting the target into the halted or running state as an atomic operation. git-svn-id: svn://svn.berlios.de/openocd/trunk@888 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-08-04 oharboe * : TAP_TLR won't work in a pathmove sequence. OpenOCD shouldn't and doesn't need to support this. git-svn-id: svn://svn.berlios.de/openocd/trunk@886 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-31 oharboe * : wait up to 1 second for halted state upon reset init/halt. git-svn-id: svn://svn.berlios.de/openocd/trunk@884 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-30 oharboe * : warning output upon connection problems. git-svn-id: svn://svn.berlios.de/openocd/trunk@882 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-28 ntfreak * : - added run_and_halt_time to deprecated/removed functions section git-svn-id: svn://svn.berlios.de/openocd/trunk@880 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-28 oharboe * : fixed gaffe mea culpa git-svn-id: svn://svn.berlios.de/openocd/trunk@878 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-27 oharboe * : working notes. git-svn-id: svn://svn.berlios.de/openocd/trunk@876 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-26 ntfreak * : - merged mips target into svn trunk git-svn-id: svn://svn.berlios.de/openocd/trunk@874 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-25 oharboe * : added yours sincerely for files where I feel that I've made non-trivial contributions. git-svn-id: svn://svn.berlios.de/openocd/trunk@872 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-24 oharboe * : more error message cleanup. invalid args & syntax errors both now print arguments of command. git-svn-id: svn://svn.berlios.de/openocd/trunk@870 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-24 oharboe * : retire daemon_startup git-svn-id: svn://svn.berlios.de/openocd/trunk@868 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-24 oharboe * : Better handling of OpenOCD command invocation result/context. git-svn-id: svn://svn.berlios.de/openocd/trunk@866 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-23 ntfreak * : - comment about dummy ack '+' char from gdb git-svn-id: svn://svn.berlios.de/openocd/trunk@864 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-23 ntfreak * : - fix typo git-svn-id: svn://svn.berlios.de/openocd/trunk@862 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-23 oharboe * : handle end of line comments to improve compatibility with event scripts git-svn-id: svn://svn.berlios.de/openocd/trunk@860 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-22 ntfreak * : - fix bug with stm32 high density write protection git-svn-id: svn://svn.berlios.de/openocd/trunk@858 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-22 oharboe * : Spen: startup.tcl cross compile support git-svn-id: svn://svn.berlios.de/openocd/trunk@856 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-22 oharboe * : very slightly improved error message for not being able to find scripts git-svn-id: svn://svn.berlios.de/openocd/trunk@854 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-21 oharboe * : Allows config scripts to override handling of 'R'(restart) GDB packet. git-svn-id: svn://svn.berlios.de/openocd/trunk@852 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-21 oharboe * : update jtag_speed/khz docs a bit. git-svn-id: svn://svn.berlios.de/openocd/trunk@850 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-21 oharboe * : cross compile fix git-svn-id: svn://svn.berlios.de/openocd/trunk@848 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-21 oharboe * : Duane Ellis stm32 peripherals scripts git-svn-id: svn://svn.berlios.de/openocd/trunk@846 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-20 oharboe * : BUG: prefix to timeout for gdb keep alive packets. git-svn-id: svn://svn.berlios.de/openocd/trunk@844 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-20 oharboe * : Duane Ellis - script commands for stm32 git-svn-id: svn://svn.berlios.de/openocd/trunk@842 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-20 oharboe * : Duane Ellis improve error message in Jim when sourcing a file fails. Previously it did not tell you the CWD Jim was using as its reference point. (Helpful when script filenames are a relative path) git-svn-id: svn://svn.berlios.de/openocd/trunk@840 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-19 oharboe * : throw exception upon syntax error. git-svn-id: svn://svn.berlios.de/openocd/trunk@838 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-19 oharboe * : clarify error message w.r.t. not being able to set breakpoint git-svn-id: svn://svn.berlios.de/openocd/trunk@836 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-18 oharboe * : This allows overriding builtin openocd commands. git-svn-id: svn://svn.berlios.de/openocd/trunk@834 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-18 oharboe * : "reset" without arguments now execute a "reset run". the reset mode argument to the target command is deprecated(ignored w/error message). git-svn-id: svn://svn.berlios.de/openocd/trunk@832 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-18 ntfreak * : - fix incorrectly registered function openocd_array2mem - removed unused variables - reformatted lpc288x.[ch] - fixed helper/Makefile.am dependencies - add correct svn props to added files git-svn-id: svn://svn.berlios.de/openocd/trunk@829 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-18 oharboe * : keep_alive() fix for reset warnings. git-svn-id: svn://svn.berlios.de/openocd/trunk@827 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-18 oharboe * : Duane Ellis more interface files. git-svn-id: svn://svn.berlios.de/openocd/trunk@825 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-18 oharboe * : added missing "reset+load" sequence. git-svn-id: svn://svn.berlios.de/openocd/trunk@823 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-17 oharboe * : Charles Hardin ckhardin at gmail.com Instead of stashing the context in a global variable, just use the "context" associated with the interp structure being passed around And fixed the message referring to mem2array in the array2mem function git-svn-id: svn://svn.berlios.de/openocd/trunk@821 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-17 oharboe * : Charles Hardin ckhardin at gmail.com There isn't a real value to the cfg_cmd_ctx since everything should be run thru the initial context created at start. git-svn-id: svn://svn.berlios.de/openocd/trunk@819 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-17 ntfreak * : - reverted resume_target to old behaviour git-svn-id: svn://svn.berlios.de/openocd/trunk@817 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-16 oharboe * : Fixes to \ and / handling for OpenOCD git-svn-id: svn://svn.berlios.de/openocd/trunk@815 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-16 oharboe * : print out jim error message stack trace in expected order(look at any C++ or Java debugger for instance). git-svn-id: svn://svn.berlios.de/openocd/trunk@813 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-16 oharboe * : print syntax for command upon syntax error. git-svn-id: svn://svn.berlios.de/openocd/trunk@811 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-15 oharboe * : feeble beginnings for tcl api rules. git-svn-id: svn://svn.berlios.de/openocd/trunk@809 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-14 oharboe * : Charles Hardin This evaluates the file at the correct level for the interpreter and the sets and all the globals are then done as expected. added a const to find_file function to avoid typecasting git-svn-id: svn://svn.berlios.de/openocd/trunk@806 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-13 ntfreak * : - added svn props for newly added files git-svn-id: svn://svn.berlios.de/openocd/trunk@804 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-13 oharboe * : Duane Ellis fix to tcl puts git-svn-id: svn://svn.berlios.de/openocd/trunk@802 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-12 ntfreak * : - remove requirement for file2c.tcl git-svn-id: svn://svn.berlios.de/openocd/trunk@800 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-12 oharboe * : testing/*.tcl sample & test code git-svn-id: svn://svn.berlios.de/openocd/trunk@798 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-11 ntfreak * : - configure check added for tclsh - startup.c manually added to clean deps git-svn-id: svn://svn.berlios.de/openocd/trunk@796 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-11 oharboe * : Charles Hardin ckhardin at gmail.com This address the >32 bit problem with drscan also added a check for bypass in the execute since this will manifest itself as a memory corruption when this check helps to debug the problem alot easier git-svn-id: svn://svn.berlios.de/openocd/trunk@794 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-11 oharboe * : work in progress to improve help git-svn-id: svn://svn.berlios.de/openocd/trunk@792 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-11 oharboe * : .cfg files are now executed as Jim Tcl. Commands that terminate script w/error message. git-svn-id: svn://svn.berlios.de/openocd/trunk@790 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-11 oharboe * : working notes. git-svn-id: svn://svn.berlios.de/openocd/trunk@788 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-10 oharboe * : Charles Hardin Add semantics to support memwrite(32,16,8) with an array2mem command Move the global up in bits2bytes.tcl so the set puts the value in the global context. Add memwrite procs to memory.tcl git-svn-id: svn://svn.berlios.de/openocd/trunk@786 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-10 oharboe * : fix quoting problem when handling OpenOCD commands. git-svn-id: svn://svn.berlios.de/openocd/trunk@784 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-10 oharboe * : very slight cleanup of flash banks handling. git-svn-id: svn://svn.berlios.de/openocd/trunk@782 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-09 ntfreak * : - adding missing install entry for luminary-libftdi.cfg git-svn-id: svn://svn.berlios.de/openocd/trunk@780 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-09 ntfreak * : - added luminary libftdi interface config git-svn-id: svn://svn.berlios.de/openocd/trunk@778 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-09 oharboe * : added flash_banks low level command. git-svn-id: svn://svn.berlios.de/openocd/trunk@776 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-08 oharboe * : tcl regression fixes. git-svn-id: svn://svn.berlios.de/openocd/trunk@774 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-08 ntfreak * : - removed target_process_events as only used in handle_resume_command and events will be called anyway by poll git-svn-id: svn://svn.berlios.de/openocd/trunk@772 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-08 ntfreak * : - apply correct formatting to openocd.c - Thanks Charles Hardin git-svn-id: svn://svn.berlios.de/openocd/trunk@770 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-07 oharboe * : more tcl cleanup. git-svn-id: svn://svn.berlios.de/openocd/trunk@768 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-07 ntfreak * : - command_run_line will only search once for the command, and execute if found git-svn-id: svn://svn.berlios.de/openocd/trunk@766 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-07 oharboe * : fix syntax error. git-svn-id: svn://svn.berlios.de/openocd/trunk@764 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-06 ntfreak * : - fix duplicate log entry git-svn-id: svn://svn.berlios.de/openocd/trunk@762 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-06 ntfreak * : - fixed build issues with win32 - fixed build warnings for last commit - set svn props for last commit git-svn-id: svn://svn.berlios.de/openocd/trunk@760 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-06 oharboe * : fix a few compilation problems. git-svn-id: svn://svn.berlios.de/openocd/trunk@758 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-06 oharboe * : Oopss. Forgot to list Duane Ellis as the author of changes in 755. git-svn-id: svn://svn.berlios.de/openocd/trunk@756 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-05 ntfreak * : - added search for libdl - Thanks Charles Hardin git-svn-id: svn://svn.berlios.de/openocd/trunk@754 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-04 ntfreak * : - added event scripts for str73x and str75x targets git-svn-id: svn://svn.berlios.de/openocd/trunk@751 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-04 ntfreak * : - fixed line endings with commands.tcl - added svn props for newly added files git-svn-id: svn://svn.berlios.de/openocd/trunk@749 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-04 oharboe * : fix to peek command. git-svn-id: svn://svn.berlios.de/openocd/trunk@747 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-04 oharboe * : typo git-svn-id: svn://svn.berlios.de/openocd/trunk@745 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-04 oharboe * : added support for Tcl config scripts on the command line(use .tcl extension). git-svn-id: svn://svn.berlios.de/openocd/trunk@743 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-04 oharboe * : ARM11 update. OpenOCD supports starting without being able to talk to the hardware. git-svn-id: svn://svn.berlios.de/openocd/trunk@741 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-07-04 oharboe * : Jim Tcl support added git-svn-id: svn://svn.berlios.de/openocd/trunk@739 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-06-28 oharboe * : wip. git-svn-id: svn://svn.berlios.de/openocd/trunk@737 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-06-27 ntfreak * : - update docs for new target_script events git-svn-id: svn://svn.berlios.de/openocd/trunk@735 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-06-27 oharboe * : hooks to enable experimentation with scripting language support. Reduces patch size, but has no effect on OpenOCD otherwise. git-svn-id: svn://svn.berlios.de/openocd/trunk@733 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-06-27 oharboe * : David Anders more target lib scripts contributed by git-svn-id: svn://svn.berlios.de/openocd/trunk@731 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-06-27 oharboe * : David Anders: fixes an issue with large block nand flash address where the beginning of the OOB area is always selected instead of the beginning of a page when needed git-svn-id: svn://svn.berlios.de/openocd/trunk@729 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-06-25 ntfreak * : - fix reset_halt issue with certain arm cores - address not set in embedded ice reg - Thanks Jonas Hörberg git-svn-id: svn://svn.berlios.de/openocd/trunk@727 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-06-24 ntfreak * : - fix compile errors when _DEBUG_INSTRUCTION_EXECUTION_ is defined - Thanks Simon Qian git-svn-id: svn://svn.berlios.de/openocd/trunk@725 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-06-18 oharboe * : Pavel Chromy: - lower jtag speeds (higher divisor) was used, TDI was not changed on falling TCK edge as it should - reset signal was release upon any TMS transition, making it impossible to use reset halt - added khz() and speed_div() functions git-svn-id: svn://svn.berlios.de/openocd/trunk@716 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-06-18 oharboe * : Spen spotted a bug in warning for missing srst_pulls_trst git-svn-id: svn://svn.berlios.de/openocd/trunk@714 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-06-16 mifi * : - added target and event script for the eir-sam7se512 target git-svn-id: svn://svn.berlios.de/openocd/trunk@712 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-06-16 oharboe * : GDB timeout fix. If a script takes a long time and does not produce any output, ping between every command. git-svn-id: svn://svn.berlios.de/openocd/trunk@710 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-06-11 ntfreak * : - probe incorrect for high density stm32 flash git-svn-id: svn://svn.berlios.de/openocd/trunk@708 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-06-06 ntfreak * : - stm32 erase will use mass_erase if all banks selected git-svn-id: svn://svn.berlios.de/openocd/trunk@706 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-06-05 ntfreak * : - erase bank using bank erase rather than each sector - Thanks Fredrik Hederstierna git-svn-id: svn://svn.berlios.de/openocd/trunk@704 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-06-04 oharboe * : Pavel Chromy: fix logging syntax error + formatting & removing obsolete comments. git-svn-id: svn://svn.berlios.de/openocd/trunk@702 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-06-04 ntfreak * : - luminary, stm32 and str7 flash driver error cleanup git-svn-id: svn://svn.berlios.de/openocd/trunk@700 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-06-03 oharboe * : Fredrik Hederstierna: fix leak + clean up return codes git-svn-id: svn://svn.berlios.de/openocd/trunk@698 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-05-29 ntfreak * : - added checksum_memory and blank_check_memory for xscale git-svn-id: svn://svn.berlios.de/openocd/trunk@696 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-05-27 ntfreak * : - moved flash erase_check target code to target.c git-svn-id: svn://svn.berlios.de/openocd/trunk@694 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-05-27 ntfreak * : - fixed typo in wp command git-svn-id: svn://svn.berlios.de/openocd/trunk@692 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-05-26 mifi * : - added check for max. value of jtag_speed in ft2232_khz. git-svn-id: svn://svn.berlios.de/openocd/trunk@690 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-05-26 oharboe * : found out why str912 reset halt failed. git-svn-id: svn://svn.berlios.de/openocd/trunk@688 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-05-26 ntfreak * : - corrected error with stm32 page calculation git-svn-id: svn://svn.berlios.de/openocd/trunk@686 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-05-24 mifi * : - comment out usb_set_altinterface, because it is not working under Mac OS X. And not needed for Windows. Hopefully it will not break a Linux build. git-svn-id: svn://svn.berlios.de/openocd/trunk@684 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-05-24 ntfreak * : - added stellaris flash mass_erase command git-svn-id: svn://svn.berlios.de/openocd/trunk@682 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-05-24 mifi * : - swap processing of reset handling. First srst and than trst. git-svn-id: svn://svn.berlios.de/openocd/trunk@680 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-05-24 mifi * : - corrected copy/paste type and renamed jlink_usb_read_result to jlink_usb_read_emu_result git-svn-id: svn://svn.berlios.de/openocd/trunk@678 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-05-24 ntfreak * : - jlink jlink_execute_queue returns result - added jlink_get_version_info function - reformatted spaces to tabs git-svn-id: svn://svn.berlios.de/openocd/trunk@676 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-05-23 ntfreak * : - add support for newer high density stm32 parts git-svn-id: svn://svn.berlios.de/openocd/trunk@674 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-05-21 ntfreak * : - remove error message on shutdown git-svn-id: svn://svn.berlios.de/openocd/trunk@672 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-05-21 oharboe * : moved srst_pulls_trst check into arm7_9_common.c. Not tested yet, if it is broken it should "only" print bogus warnings or not print a warning when it should have. git-svn-id: svn://svn.berlios.de/openocd/trunk@670 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-05-19 oharboe * : reverted change in 658 and simply removed the busted warning for now. git-svn-id: svn://svn.berlios.de/openocd/trunk@668 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-05-19 oharboe * : print out an error if srst_pulls_trst is not specified for e.g. at91fr40008. Could possibly show bogus false positives in log without any other side effects. git-svn-id: svn://svn.berlios.de/openocd/trunk@666 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-05-19 oharboe * : fix mode output when illegal arm mode is detected. Now prints illegal mode for index -1. git-svn-id: svn://svn.berlios.de/openocd/trunk@664 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-05-19 oharboe * : updated guidelines. git-svn-id: svn://svn.berlios.de/openocd/trunk@662 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-05-16 mifi * : - added smoketest result for r657 - some corrections for the reset config of at91r40008 git-svn-id: svn://svn.berlios.de/openocd/trunk@660 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-05-14 ntfreak * : - added jlink support, based on Jürgen Stuber patch git-svn-id: svn://svn.berlios.de/openocd/trunk@658 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-05-11 mifi * : - added patch from uwe hermann, thanks for the hint. git-svn-id: svn://svn.berlios.de/openocd/trunk@656 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-05-10 mifi * : - corrected rounding in ft2232_khz git-svn-id: svn://svn.berlios.de/openocd/trunk@654 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-05-10 mifi * : - smoketest for r651 git-svn-id: svn://svn.berlios.de/openocd/trunk@652 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-05-09 oharboe * : Michael Fischer spotted a problem in the reset routines for srst_pulls_trst. It is a bit of a mystery why this was only visible w/LPC2148. Embedded ICE registers are now set up after SRST pulls TRST. git-svn-id: svn://svn.berlios.de/openocd/trunk@650 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-05-07 oharboe * : print available memory in log_level 3 git-svn-id: svn://svn.berlios.de/openocd/trunk@648 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-05-07 oharboe * : Edgar Grimberg plugged a leak found w/Valgrind. git-svn-id: svn://svn.berlios.de/openocd/trunk@646 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-05-06 oharboe * : Edgar Grimberg found tiny memory leak git-svn-id: svn://svn.berlios.de/openocd/trunk@644 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-05-06 oharboe * : The target library is now the authorotative source of config examples git-svn-id: svn://svn.berlios.de/openocd/trunk@642 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-05-03 drath * : - fixed xsvf_add_statemove() git-svn-id: svn://svn.berlios.de/openocd/trunk@640 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-05-02 ntfreak * : - added info about libftdi support under win32 git-svn-id: svn://svn.berlios.de/openocd/trunk@638 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-05-01 oharboe * : Tim Hudson worked on English language. git-svn-id: svn://svn.berlios.de/openocd/trunk@636 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-05-01 ntfreak * : - add missing svn props git-svn-id: svn://svn.berlios.de/openocd/trunk@634 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-30 oharboe * : now compiles again. git-svn-id: svn://svn.berlios.de/openocd/trunk@632 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-30 ntfreak * : - added new device to luminary flash driver - only use SYSRESETREQ on affected luminary parts git-svn-id: svn://svn.berlios.de/openocd/trunk@630 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-30 oharboe * : Edgar's added support for printing jtag_khz git-svn-id: svn://svn.berlios.de/openocd/trunk@628 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-29 oharboe * : Edgar Grimberg added a new rule for target scripts. Flash + verify must succeed. git-svn-id: svn://svn.berlios.de/openocd/trunk@626 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-28 ntfreak * : - add cortex_m3 variant luminary to fix reset issue with asserting SRST - https://lists.berlios.de/pipermail/openocd-development/2008-April/002022.html for detailsgit-svn-id: svn://svn.berlios.de/openocd/trunk@624 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-26 ntfreak * : - luminary flash now loader polls when finished git-svn-id: svn://svn.berlios.de/openocd/trunk@622 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-26 ntfreak * : - incorrect ram size for lm3s811 target script git-svn-id: svn://svn.berlios.de/openocd/trunk@620 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-26 oharboe * : wip instructions for building Cortex toolchain git-svn-id: svn://svn.berlios.de/openocd/trunk@618 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-24 oharboe * : Close dangling file handle git-svn-id: svn://svn.berlios.de/openocd/trunk@616 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-24 oharboe * : Edgar's new test cases. git-svn-id: svn://svn.berlios.de/openocd/trunk@614 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-23 oharboe * : Pavel Chromy's on chip flash loader git-svn-id: svn://svn.berlios.de/openocd/trunk@612 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-23 ntfreak * : - added svn props for newly added files git-svn-id: svn://svn.berlios.de/openocd/trunk@610 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-23 ntfreak * : - fix typo in openocd.texi git-svn-id: svn://svn.berlios.de/openocd/trunk@608 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-23 oharboe * : Tim Hudson: removed setting jtag_speed directly (which should not be done). git-svn-id: svn://svn.berlios.de/openocd/trunk@606 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-23 oharboe * : added fast option. git-svn-id: svn://svn.berlios.de/openocd/trunk@604 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-22 oharboe * : wip on reporting bugs. git-svn-id: svn://svn.berlios.de/openocd/trunk@602 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-21 ntfreak * : - added stm32 stick and luminary eval boards interface configs - corrected target lm3s6965.cfg git-svn-id: svn://svn.berlios.de/openocd/trunk@600 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-20 ntfreak * : - set erase flag on sector git-svn-id: svn://svn.berlios.de/openocd/trunk@598 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-20 ntfreak * : - update docs for flash write_image command - remove info on flash auto_erase, added to removed commands section git-svn-id: svn://svn.berlios.de/openocd/trunk@596 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-19 mifi * : - added test results for r592 git-svn-id: svn://svn.berlios.de/openocd/trunk@594 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-18 drath * : - Flash auto-erase is disabled by default git-svn-id: svn://svn.berlios.de/openocd/trunk@592 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-18 oharboe * : Nicolas Pitre fixed regression. git-svn-id: svn://svn.berlios.de/openocd/trunk@590 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-16 oharboe * : fix for gaffe in 555 that stopped JTAG chain examine + validate from running. git-svn-id: svn://svn.berlios.de/openocd/trunk@588 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-16 ntfreak * : - correct stm32stick config script git-svn-id: svn://svn.berlios.de/openocd/trunk@586 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-16 oharboe * : Edgar Grimberg added some missing scripts from the install git-svn-id: svn://svn.berlios.de/openocd/trunk@584 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-15 oharboe * : - sw_bkpts fails if the target is not halted. The side effect is that sw_bkpts also fails if the target is an unknown state(i.e. not examined yet). - feroceon embedded ICE registers are now set up after TRST has been deasserted(not tested, but it was broken as is anyway). git-svn-id: svn://svn.berlios.de/openocd/trunk@582 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-15 oharboe * : target read/write is no longer attempted for target_xxx() functions when the target has not been examined(fails w/error). git-svn-id: svn://svn.berlios.de/openocd/trunk@580 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-14 oharboe * : retired fast_memory_access. It's always fast now. git-svn-id: svn://svn.berlios.de/openocd/trunk@578 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-14 oharboe * : moved out stuff that wasn't already moved from openocd.pdf to the target library. git-svn-id: svn://svn.berlios.de/openocd/trunk@576 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-14 oharboe * : TRST is asserted *before* target->type->assert_reset() is invoked. Removed old code. git-svn-id: svn://svn.berlios.de/openocd/trunk@574 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-13 oharboe * : A dummy driver to test codepath w/no contact w/target. git-svn-id: svn://svn.berlios.de/openocd/trunk@572 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-13 oharboe * : allows launching OpenOCD w/telnet+gdb server w/the target powered down. git-svn-id: svn://svn.berlios.de/openocd/trunk@570 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-11 oharboe * : found two more gaffes for reset wip git-svn-id: svn://svn.berlios.de/openocd/trunk@568 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-11 oharboe * : Reset wip. Just adding hooks. This is just to reduce the size of the actual change, no change in behaviour. git-svn-id: svn://svn.berlios.de/openocd/trunk@566 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-11 oharboe * : Wip - split target setup and target examination git-svn-id: svn://svn.berlios.de/openocd/trunk@564 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-11 oharboe * : Improved XScale performance for embedded hosted OpenOCD git-svn-id: svn://svn.berlios.de/openocd/trunk@562 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-10 oharboe * : stop using variable sized arrays. That's something that belongs to C++ and not C. git-svn-id: svn://svn.berlios.de/openocd/trunk@560 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-10 ntfreak * : - single core context used, removed debug context as thought unnecessary. - DCRDR now used to access special core registers - info is currently omitted from the cortex_m3 TRM ARM have told me this is the preferred access method and the docs will be updated soon. - now checks for User Thread Mode and Thread mode when halted. - removed repeated function declarations from command.c - cortex_m3_prepare_reset_halt removed, updated cortex_m3_assert_reset to suit git-svn-id: svn://svn.berlios.de/openocd/trunk@558 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-09 oharboe * : target lib wip git-svn-id: svn://svn.berlios.de/openocd/trunk@556 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-09 ntfreak * : - add missing svn props git-svn-id: svn://svn.berlios.de/openocd/trunk@554 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-09 oharboe * : - added "init" command. "init" and "reset" at end of startup script is equivalent to daemon_startup(still supported). - print warning if srst and trst change state at the same time when srst_and_trst is seperate - reset now performs a trst, examines and validates the jtag chain before targets assert reset - if startup fails to examine and validate the jtag chain, try a reset before trying again git-svn-id: svn://svn.berlios.de/openocd/trunk@552 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-08 oharboe * : Edwin Olson found bug & tested fix for flash write_image for stellaris. git-svn-id: svn://svn.berlios.de/openocd/trunk@550 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-08 oharboe * : added a couple of LOG_ERROR() messages to improve logfile. git-svn-id: svn://svn.berlios.de/openocd/trunk@548 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-08 oharboe * : The endstate now reports the endstate of the queue instead of reading endstate variable internal to the driver. git-svn-id: svn://svn.berlios.de/openocd/trunk@546 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-07 oharboe * : - only if "reset halt" or "reset init" are issued will the reset vector be set up - If communication fails during assert between assert/deassert and during assert, warnings are printed. The warning suggests using srst_only if the clock locks up as that would allow the reset vector to be set up before asserting reset. git-svn-id: svn://svn.berlios.de/openocd/trunk@544 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-06 oharboe * : avoid patch trouble by isolating troublesome line... git-svn-id: svn://svn.berlios.de/openocd/trunk@542 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-04 oharboe * : - the reset mode parameter is now DEPRECATED. It is implemented as an optional parameter with default reset_init. This is to streamline things w.r.t. the target library. git-svn-id: svn://svn.berlios.de/openocd/trunk@540 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-04 oharboe * : added query of reset speed git-svn-id: svn://svn.berlios.de/openocd/trunk@538 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-03 oharboe * : - Work on fixing erase check. Many implementations are plain broken. Wrote a default flash erase check fn which uses CFI's target algorithm w/fallback to memory reads. - "flash info" no longer prints erase status as it is stale. - "flash erase_check" now prints erase status. erase check can take a *long* time. Work in progress - arm7/9 with seperate srst & trst now supports reset init/halt after a power outage. arm7/9 no longer makes any assumptions about state of target when reset is asserted. - fixes for srst & trst capable arm7/9 with reset init/halt - prepare_reset_halt retired. This code needs to be inside assert_reset anyway - haven't been able to get stm32 write algorithm to work. Fallback flash write does work. Haven't found a version of openocd trunk where this works. - added target_free_all_working_areas_restore() which can let be of restoring backups. This is needed when asserting reset as the target must be assumed to be an unknown state. Added some comments to working areas API - str9 reset script fixes - some guidelines - fixed dangling callbacks upon reset timeout git-svn-id: svn://svn.berlios.de/openocd/trunk@536 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-02 oharboe * : fix flash info - now reports erased state properly git-svn-id: svn://svn.berlios.de/openocd/trunk@534 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-04-02 oharboe * : optional count argument to mwX git-svn-id: svn://svn.berlios.de/openocd/trunk@532 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-31 oharboe * : Do not assert trst in srst_only case even if srst_pulls_trst. git-svn-id: svn://svn.berlios.de/openocd/trunk@530 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-31 oharboe * : Removed exit()'s. A reset is usually enough to work around these, reducing cycle times to get config scripts right. git-svn-id: svn://svn.berlios.de/openocd/trunk@528 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-28 oharboe * : Edgar Grimberg: added needed delays git-svn-id: svn://svn.berlios.de/openocd/trunk@526 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-26 oharboe * : hooks for multithreading. Disable nagle git-svn-id: svn://svn.berlios.de/openocd/trunk@524 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-22 ntfreak * : - gdb server was incorrectly sending null terminator on qXfer:features:read: packet - armv7m now sends correct gdb register packet git-svn-id: svn://svn.berlios.de/openocd/trunk@522 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-22 ntfreak * : - changed jtag_add_reset errors to warnings - removed extra jtag reset warnings from arm7_9 and cortex_m3 git-svn-id: svn://svn.berlios.de/openocd/trunk@520 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-21 mifi * : - added new test results git-svn-id: svn://svn.berlios.de/openocd/trunk@518 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-14 oharboe * : added profile command. It was added to simplify evaluation by testers. git-svn-id: svn://svn.berlios.de/openocd/trunk@516 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-13 oharboe * : Michael Bruck: fixed warnings git-svn-id: svn://svn.berlios.de/openocd/trunk@514 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-13 oharboe * : added jtag_khz for use with target library git-svn-id: svn://svn.berlios.de/openocd/trunk@512 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-13 oharboe * : print ms in debug_level 3 logs. Seconds is not enough. git-svn-id: svn://svn.berlios.de/openocd/trunk@510 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-13 oharboe * : marked infinite loop in code w/TODO and fixed warning. git-svn-id: svn://svn.berlios.de/openocd/trunk@508 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-12 oharboe * : xscale now passes w/bitbang in 505 git-svn-id: svn://svn.berlios.de/openocd/trunk@506 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-12 oharboe * : This moves common code into functions so as to make it clear that all the jtag_add_xxx() are indeed intended to do the same thing. git-svn-id: svn://svn.berlios.de/openocd/trunk@504 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-12 oharboe * : more info about latest working version git-svn-id: svn://svn.berlios.de/openocd/trunk@502 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-12 oharboe * : tinkered a bit with testing matrix. git-svn-id: svn://svn.berlios.de/openocd/trunk@500 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-11 oharboe * : With the recent changes the TRST needs to happen for every reset. git-svn-id: svn://svn.berlios.de/openocd/trunk@498 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-11 oharboe * : - retired unused jtag events. The code was incorrect - hopefully clarified the difference between TRST and TMS reset. - added DEBUG() statements w.r.t. state changes - TRST released and moving out of TAP_TLR are completely different events. Only TRST released has a DEBUG() statement git-svn-id: svn://svn.berlios.de/openocd/trunk@496 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-11 oharboe * : retire unused code. git-svn-id: svn://svn.berlios.de/openocd/trunk@494 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-11 oharboe * : - fixed jtag_add_reset(). It no longer causes jtag_execute_queue() to fail for two of it's return codes. A little bit weird, but compatible with existing codebase. - tightend up error handling. Since the jtag_xxx() is a queue that is either executed as things are added(hw queue) or a software queue, then errors can only be caught during jtag_execute_queue(). No error code is therefore returned from the queuing fn's. git-svn-id: svn://svn.berlios.de/openocd/trunk@492 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-10 oharboe * : backed out changes from 483. git-svn-id: svn://svn.berlios.de/openocd/trunk@490 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-10 oharboe * : more target scripts wip. git-svn-id: svn://svn.berlios.de/openocd/trunk@488 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-10 oharboe * : Pavel Chromy: the attached patch refines PRESTO support and makes it work with libftdi. git-svn-id: svn://svn.berlios.de/openocd/trunk@486 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-10 oharboe * : - fixed a problem with big endian XScale and GDB register packets. - hmm..... did I screw up? Was XScale and not gdb_server busted here? My thinking was that OpenOCD has a canonical internal representation of registers that match GDB's expectations git-svn-id: svn://svn.berlios.de/openocd/trunk@484 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-10 oharboe * : - Fixed various error handling when looking for memory leaks - Fixed memory leak in gdb_server.c - pushed "Error:" statements up into fn's that know something about what went wrong - load_image now fails if target_write_memory() fails - only issue an asynchronous halt() upon connect of GDB. Synchronous halt/reset doesn't really work as what's required to initialize the target might involve a special monitor sequence for the target in question - syntax error handling improved(fewer exit()'s) git-svn-id: svn://svn.berlios.de/openocd/trunk@482 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-10 oharboe * : added stm32.cfg to install list git-svn-id: svn://svn.berlios.de/openocd/trunk@480 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-09 ntfreak * : - add stm32 target script git-svn-id: svn://svn.berlios.de/openocd/trunk@478 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-08 oharboe * : typo. git-svn-id: svn://svn.berlios.de/openocd/trunk@476 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-07 oharboe * : Asynchronous output information from e.g. a halt is now displayed again. git-svn-id: svn://svn.berlios.de/openocd/trunk@474 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-07 ntfreak * : - The elf loader incorrectly assumed that the program header always follows the ELF header. (Thanks Michael Bruck) git-svn-id: svn://svn.berlios.de/openocd/trunk@472 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-07 oharboe * : Edgar Grimberg, fix arm926ejs_examine_debug_reason return value. git-svn-id: svn://svn.berlios.de/openocd/trunk@470 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-07 oharboe * : minor corrections for target scripts. git-svn-id: svn://svn.berlios.de/openocd/trunk@468 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-07 oharboe * : Pavel Chromy, the patch fixes an issue with PRESTO & FTD2XX under Linux. git-svn-id: svn://svn.berlios.de/openocd/trunk@466 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-07 oharboe * : wi-9c target scripts git-svn-id: svn://svn.berlios.de/openocd/trunk@464 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-07 mifi * : - added str912/str710_program.script - added test infos from r459 git-svn-id: svn://svn.berlios.de/openocd/trunk@462 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-07 oharboe * : Cosmetic fixes from Uwe Hermann git-svn-id: svn://svn.berlios.de/openocd/trunk@460 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-06 oharboe * : retired git-svn-id: svn://svn.berlios.de/openocd/trunk@458 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-06 oharboe * : tms is never referenced, confusing old code left behind probably. git-svn-id: svn://svn.berlios.de/openocd/trunk@456 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-06 oharboe * : Pavel Chromy: faster alloc_printf() git-svn-id: svn://svn.berlios.de/openocd/trunk@454 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-06 oharboe * : Michael Bruck: - force simulate_reset_on_next_halt when target state is initially detected - print out method of debug entry - fix VCR activation (didn't work before) git-svn-id: svn://svn.berlios.de/openocd/trunk@452 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-06 oharboe * : make debug code w.r.t. incorrect args for bypass stricter. git-svn-id: svn://svn.berlios.de/openocd/trunk@450 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-05 oharboe * : - This speeds up dcc arm7_9 bulk write a little bit and exercises the jtag_add_dr_out() codepath - added a check to jtag_add_pathmove() for legal path transitions - tweaked jtag.h docs a little bit - made some jtag bypass tests _DEBUG_JTAG_IO_ git-svn-id: svn://svn.berlios.de/openocd/trunk@448 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-05 oharboe * : Pavel Chromy: memory leak in at91sam7 flash driver, possible incorrect pointer conversion in gpnvm command handling, uninitialized buffer issue in handle_flash_info_command in flash.c, some formatting. git-svn-id: svn://svn.berlios.de/openocd/trunk@446 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-05 oharboe * : telnet_port can now be invoked multiple times git-svn-id: svn://svn.berlios.de/openocd/trunk@444 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-04 oharboe * : Fixed GDB timeout crash - regression introduced back when log_add/remove_callback was added. git-svn-id: svn://svn.berlios.de/openocd/trunk@442 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-04 oharboe * : Michael Bruck: fix warnings. git-svn-id: svn://svn.berlios.de/openocd/trunk@440 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-03 ntfreak * : - added svn prop svn:eol-style native git-svn-id: svn://svn.berlios.de/openocd/trunk@438 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-03 oharboe * : added fill_malloc test. Not quite sure what to do here yet, but it would be good to have something... git-svn-id: svn://svn.berlios.de/openocd/trunk@436 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-03 oharboe * : some comments from Dominic git-svn-id: svn://svn.berlios.de/openocd/trunk@434 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-02 ntfreak * : - added svn prop svn:eol-style native git-svn-id: svn://svn.berlios.de/openocd/trunk@432 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-02 oharboe * : fixed FSF address. Uwe Hermann. git-svn-id: svn://svn.berlios.de/openocd/trunk@430 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-01 oharboe * : wrote up explaining why tests are done on committed code. git-svn-id: svn://svn.berlios.de/openocd/trunk@428 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-01 ntfreak * : - contrib directory added - libdcc added as example for dcc comms with openocd target_request debugmsgs git-svn-id: svn://svn.berlios.de/openocd/trunk@426 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-01 oharboe * : fix memory corruption regression introduced in 335 git-svn-id: svn://svn.berlios.de/openocd/trunk@424 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-01 mifi * : - added example for testing the JTAG speed with a FT2232 device git-svn-id: svn://svn.berlios.de/openocd/trunk@422 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-01 mifi * : - updated svn:eol-style prop to native for AT91R40008 (Thanks to Spen for the hint) git-svn-id: svn://svn.berlios.de/openocd/trunk@420 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-01 ntfreak * : - updated svn:eol-style prop to native git-svn-id: svn://svn.berlios.de/openocd/trunk@418 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-01 oharboe * : improve DCC bulk write performance by using jtag_add_shift() + tweaked embedded ICE communication. git-svn-id: svn://svn.berlios.de/openocd/trunk@416 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-01 oharboe * : Now uses jtag_add_shift() via embeddedice_write_reg_inner(). git-svn-id: svn://svn.berlios.de/openocd/trunk@414 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-01 oharboe * : log_remove_callback git-svn-id: svn://svn.berlios.de/openocd/trunk@412 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-01 mifi * : - added str912 test example, and test result git-svn-id: svn://svn.berlios.de/openocd/trunk@410 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-01 mifi * : - added test result for str710, and test description git-svn-id: svn://svn.berlios.de/openocd/trunk@408 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-03-01 mifi * : - added STR710 example which I used for Eclipse debug testing git-svn-id: svn://svn.berlios.de/openocd/trunk@406 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-29 oharboe * : added an #error in case anybody tries to compile that broken code. git-svn-id: svn://svn.berlios.de/openocd/trunk@404 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-29 ntfreak * : - fix bug with emulated cortex_m3 dcc channel git-svn-id: svn://svn.berlios.de/openocd/trunk@402 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-29 oharboe * : Tweaked logging output. TODO is retired(hopelessly out of date). git-svn-id: svn://svn.berlios.de/openocd/trunk@400 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-29 oharboe * : Pavel Chromy fix: the guess-rev.sh scripts to retrieve SVN revision returns the result including new line causing PKGBLDREV macro to not work git-svn-id: svn://svn.berlios.de/openocd/trunk@398 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-29 oharboe * : Uwe Hermann: Small cosmetic fixes in the license header to make them all look the same, fix some typos, update README. git-svn-id: svn://svn.berlios.de/openocd/trunk@396 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-29 oharboe * : Uwe Hermann: mproves the manpage text a bit and adds the missing -s and -c options. git-svn-id: svn://svn.berlios.de/openocd/trunk@394 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-29 oharboe * : formatting fixes from Pavel Chromy git-svn-id: svn://svn.berlios.de/openocd/trunk@392 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-29 oharboe * : - image.c and fileio.c now uses logging to propagate error strings. More precise, less code. - removed unused code in fileio.c - Windows should now find debug_handler.bin git-svn-id: svn://svn.berlios.de/openocd/trunk@390 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-29 oharboe * : do not write single chars to log file. git-svn-id: svn://svn.berlios.de/openocd/trunk@388 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-29 oharboe * : Summary: passing of variable argument list reduced, strings sent to logging are now formatted just once - more efficient. As a result, ugly string malloc+strcpy are not needed anymore. git-svn-id: svn://svn.berlios.de/openocd/trunk@386 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-29 oharboe * : Michael Bruck: - fix indentation of multi-level commands - make help command work with multi-level commands git-svn-id: svn://svn.berlios.de/openocd/trunk@384 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-28 oharboe * : fixed newline gaffe in OUTPUT() git-svn-id: svn://svn.berlios.de/openocd/trunk@382 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-28 oharboe * : Pavel Chromy spotted a leak git-svn-id: svn://svn.berlios.de/openocd/trunk@380 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-28 oharboe * : numerous fixes from Uwe Hermann git-svn-id: svn://svn.berlios.de/openocd/trunk@378 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-28 oharboe * : Pavel Chromy - cleanup error messages git-svn-id: svn://svn.berlios.de/openocd/trunk@376 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-28 oharboe * : Pavel Chromy cleaned up checks for halted, error messages, etc. git-svn-id: svn://svn.berlios.de/openocd/trunk@374 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-28 oharboe * : fix from Pavel Chromy this patch fixes an issue in jtag_init - shall not reset jtag to NULL. This causes jtag interface (USB device) not to be closed properly if jtag chain validation fails. Once the underlaying jtag interface is initialized, jtag pointer shall be left untouched, even in case of an error, so that proper cleanup can be done, see exit_handler in openocd.c git-svn-id: svn://svn.berlios.de/openocd/trunk@372 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-28 oharboe * : code to be used in upcoming minidriver work. git-svn-id: svn://svn.berlios.de/openocd/trunk@370 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-28 oharboe * : fix copyright. git-svn-id: svn://svn.berlios.de/openocd/trunk@368 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-28 oharboe * : lingering change for eCos flash driver git-svn-id: svn://svn.berlios.de/openocd/trunk@366 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-28 oharboe * : - Added TARGET_REQ_DEBUGCHAR target_request debugmsg. This provides a better impeadance match for debug output char fn's, e.g. eCos. - Line endings are now added at the caller site of command_print*(). command_print() still adds a line ending - echo of commands in scripts are now available via debug_level instead of forced echo - Added a USER_SAMELINE() for printing without a lineend. git-svn-id: svn://svn.berlios.de/openocd/trunk@364 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-28 drath * : - fix line-endings git-svn-id: svn://svn.berlios.de/openocd/trunk@362 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-28 oharboe * : Uwe Hermann fixed some warnings. git-svn-id: svn://svn.berlios.de/openocd/trunk@360 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-27 drath * : - fix typo in ep93xx jtag driver to allow OpenOCD compilation on ARM (thanks to Uwe Hermann for the patch) git-svn-id: svn://svn.berlios.de/openocd/trunk@358 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-27 oharboe * : Nicolas Pitre listed some more devices. git-svn-id: svn://svn.berlios.de/openocd/trunk@356 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-26 ntfreak * : - code reformat (Thanks Pavel Chromy) git-svn-id: svn://svn.berlios.de/openocd/trunk@354 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-26 oharboe * : oopss.. another jtag minidriver reset gaffe. git-svn-id: svn://svn.berlios.de/openocd/trunk@352 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-26 oharboe * : Next step in the JTAG minidriver. This should be fairly close to the final thing, but I'm not calling it "done" quite yet. git-svn-id: svn://svn.berlios.de/openocd/trunk@350 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-25 ntfreak * : - remove build warnings git-svn-id: svn://svn.berlios.de/openocd/trunk@348 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-25 oharboe * : Pavel Chromy - multiple log listeners - added OUTPUT() to replace printf - fix formatting git-svn-id: svn://svn.berlios.de/openocd/trunk@346 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-25 oharboe * : Pavel Chromy style fixes. git-svn-id: svn://svn.berlios.de/openocd/trunk@344 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-25 oharboe * : - Fix target library path problem w/Windows git-svn-id: svn://svn.berlios.de/openocd/trunk@342 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-25 oharboe * : committed bugfix from Michael Bruck git-svn-id: svn://svn.berlios.de/openocd/trunk@340 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-25 oharboe * : - using ERROR_COMMAND_SYNTAX_ERROR to print syntax in a couple of places - some more flash cleanup of checking halted state - moved output handler into options.c - very slightly tweaked server.c to make it a bit more compatible with eCos - retired arch_state. Not quite sure how I managed to leave that out last time. git-svn-id: svn://svn.berlios.de/openocd/trunk@338 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-25 oharboe * : Michael Bruck spotted an omission in svn 322 git-svn-id: svn://svn.berlios.de/openocd/trunk@336 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-24 oharboe * : move options handling to separate file to better support embedded implementations of OpenOCD git-svn-id: svn://svn.berlios.de/openocd/trunk@334 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-24 oharboe * : - fixed target->type->poll() return value - added arch_state to show status of currently selected target - simplified target->type->arch_state() api. - clean up telnet output a bit - fixed GDB output for arch_state - removed a couple of unecessary exit()'s - cleaned up error propagation a bit in a few places git-svn-id: svn://svn.berlios.de/openocd/trunk@332 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-24 oharboe * : debug_level 3 now prints seconds since start of openocd git-svn-id: svn://svn.berlios.de/openocd/trunk@330 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-24 oharboe * : sharpend JTAG docs w.r.t. hw fifo implementations and retired jtag_cancel_queue() which is inheritely incompatible with a hw fifo concept. git-svn-id: svn://svn.berlios.de/openocd/trunk@328 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-24 oharboe * : cosmetic fixes to debug output + phasing out printf() in favour of logging system. From Pavel Chromy git-svn-id: svn://svn.berlios.de/openocd/trunk@326 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-23 drath * : - fix for feroceon CP15 register access (thanks to Niolas Pitre for this patch) git-svn-id: svn://svn.berlios.de/openocd/trunk@324 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-23 mifi * : - added a test document as a starting point - corrected URL information for the repro git-svn-id: svn://svn.berlios.de/openocd/trunk@322 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-22 mifi * : - added patch to remove count and time information from log_printf in case of debug_level is not set to LOG_DEBUG git-svn-id: svn://svn.berlios.de/openocd/trunk@320 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-22 vpalatin * : - fix read/write size for small unaligned accesses (thanks Michael Bruck) git-svn-id: svn://svn.berlios.de/openocd/trunk@318 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-22 mifi * : - added patch to make single-stepping more resilient (thanks to Nicolas Pitre for the patch) git-svn-id: svn://svn.berlios.de/openocd/trunk@316 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-20 ntfreak * : - fix bug when using full paths to config files. Thanks Ted Roth git-svn-id: svn://svn.berlios.de/openocd/trunk@314 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-19 ntfreak * : - add search paths via new arg -s (-search). Thanks Ted Roth - updated docs for new command git-svn-id: svn://svn.berlios.de/openocd/trunk@312 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-19 ntfreak * : - Fixed bug in pathmove for XScale - added virtual address to working_area. - Improved error messages in a number of places - Added ERROR_COMMAND_SYNTAX_ERROR that commands can return to have syntax printed - Added help for some config commands - Added verification of sw breakpoints with ERROR() message - Removed a couple of exit()'s and replaced with error message - cosmetic fix to armv4_5.c, easier to read - added polymorphic(with default) virt2phys and mmu enable query function to target.h - added virt2phys command that uses target->type->virt2phys() fn Thanks to Øyvind Harboe git-svn-id: svn://svn.berlios.de/openocd/trunk@310 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-18 drath * : - Fix problems with stuck telnet sessions. Thanks to Øyvind Harboe for this patch. git-svn-id: svn://svn.berlios.de/openocd/trunk@308 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-18 ntfreak * : - arg list now correctly released on error. Thanks Øyvind Harboe git-svn-id: svn://svn.berlios.de/openocd/trunk@306 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-18 ntfreak * : - removed a raft of unecessary exit() calls. Issuing a reset will solve these ails. - now uses jtag_state_pathmove() instead of making assumptions about implementation of jtag_statemove(). - fixed a couple of bugs in timeout handling - removed megabytes of log output when communication is failing. - sleep is now 300ms as documented instead of 3000ms - fixed error path of bulk write - debug_handler can now be issued during normal operation + has help text. Thanks Øyvind Harboe git-svn-id: svn://svn.berlios.de/openocd/trunk@304 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-18 ntfreak * : - Added a "User:" debug level. These are messages that are intended for the user and are part of normal operation. - Faster DEBUG/INFO() when they are disabled - target_read/write_buffer() now uses 16 and 32 bit access for single word aligned requests. Other requests are serviced as quickly as possible. - *much* faster read/write GDB packets, removing timeout problems. - GDB read/write packets w/single word aligned 32/16 bit access now use 32/16 bit word access. - working area can now be changed on the fly. Provides a way to move working area about as MMU is enabled/disabled. - cleaned up error messages for verify_image. Thanks Øyvind Harboe git-svn-id: svn://svn.berlios.de/openocd/trunk@302 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-16 ntfreak * : - solve lots of problems with stuck GDB connections, making it impossible to connect to GDB, handle timeout of acknowledgement, etc. - "monitor halt/resume" now works correctly - "monitor sleep 10000" no longer makes the GDB protocol lock up. There is an error message and the protocol recovers nicely afterwards. - it's now possible to connect to a target which needs a reset before halt works. - handle failed memory access more gracefully. Connection is now closed instead of OpenOCD quitting. - *much* improved handling of 2 second timeout on memory read packets. Especially important w/mouseover evaluation of variables in Eclipse. - fixed memory leak upon failed memory packet reply. - 'O' packets w/progress info is no longer sent out randomly. - faster packet reply code. - Thanks to Øyvind Harboe for this patch git-svn-id: svn://svn.berlios.de/openocd/trunk@300 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-16 ntfreak * : - fix issue with telnet prompt while gdb running git-svn-id: svn://svn.berlios.de/openocd/trunk@298 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-14 ntfreak * : - fix programming issue with lpc2101/2 git-svn-id: svn://svn.berlios.de/openocd/trunk@296 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-14 ntfreak * : - added check for revA silicon in stm32 flash driver git-svn-id: svn://svn.berlios.de/openocd/trunk@294 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-12 ntfreak * : - add autoprobe support to flash info command - auto_erase can now be called from script/config file git-svn-id: svn://svn.berlios.de/openocd/trunk@292 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-11 ntfreak * : - telnet prompt behaves correctly for new synchronous halt/resume/reset commands - removed unused variables in tms470.c git-svn-id: svn://svn.berlios.de/openocd/trunk@290 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-10 ntfreak * : - stm32 flash driver now checks for correct target git-svn-id: svn://svn.berlios.de/openocd/trunk@288 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-10 mifi * : - added patch to change pathmove handling https://lists.berlios.de/pipermail/openocd-development/2008-January/000678.html(thanks to Øyvind for the patch) git-svn-id: svn://svn.berlios.de/openocd/trunk@286 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-07 ntfreak * : - added synchronous reset patch, Thanks Øyvind Harboe - added target_init_reset which calls target_process_reset after all drivers have been initialised git-svn-id: svn://svn.berlios.de/openocd/trunk@284 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-06 mifi * : - added patch to solve problem with AT91SAM9260 (dirty register) (thanks to Øyvind Harboe for the patch) git-svn-id: svn://svn.berlios.de/openocd/trunk@282 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-02-04 ntfreak * : Added patch to stop SEGFAULT with missing jtag config lines. Thanks Øyvind Harboe https://lists.berlios.de/pipermail/openocd-development/2008-January/000731.htmlgit-svn-id: svn://svn.berlios.de/openocd/trunk@280 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-01-27 mifi * : - added autoprobe functionality - corrected blocksize handling from GDB "info mem" command (thanks to Øyvind and Spen for these patches) git-svn-id: svn://svn.berlios.de/openocd/trunk@278 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-01-24 mifi * : - added patch to check some malloc problems. (thanks to Øyvind Harboe for the patch) git-svn-id: svn://svn.berlios.de/openocd/trunk@276 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-01-23 mifi * : - added patch to fix crash in load_image on corrupt elf file or out of memory. (thanks to Øyvind Harboe for the patch) git-svn-id: svn://svn.berlios.de/openocd/trunk@274 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-01-21 bodylove * : - Added example config and startup-script for a XScale IXP42x system git-svn-id: svn://svn.berlios.de/openocd/trunk@272 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-01-21 bodylove * : - Synced code with branch git-svn-id: svn://svn.berlios.de/openocd/trunk@270 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-01-21 bodylove * : - Eleminated leading tabs/white space git-svn-id: svn://svn.berlios.de/openocd/trunk@267 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-01-21 ntfreak * : - updated docs for cfi command, added missing ft2232_layout names git-svn-id: svn://svn.berlios.de/openocd/trunk@261 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-01-17 ntfreak * : - add support for cortex_m3 target_request debugmsgs - target request handler disabled by default until a target has been registered git-svn-id: svn://svn.berlios.de/openocd/trunk@259 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-01-17 drath * : - fixed 'make distcheck' (thanks to Theodore A. Roth for this patch git-svn-id: svn://svn.berlios.de/openocd/trunk@257 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-01-14 drath * : - use correct SCAN_N check value (disabled by default) - add Øyvind Harboe to list of AUTHORS (thanks a lot to Øyvind for his hard work) git-svn-id: svn://svn.berlios.de/openocd/trunk@255 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-01-10 ntfreak * : - fix gdb packet retransmission omission git-svn-id: svn://svn.berlios.de/openocd/trunk@253 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-01-10 ntfreak * : - added faster gdb packet handling (thanks to oyvind harboe for the patch) - code reformat git-svn-id: svn://svn.berlios.de/openocd/trunk@251 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2008-01-09 ntfreak * : - rename flash_init and flash_erase to flash_init_drivers and flash_erase_address_range - stops conflicts with redboot. Thanks Øyvind Harboe - gdb connection not dropped if we fail to allocate memory in query packets git-svn-id: svn://svn.berlios.de/openocd/trunk@249 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-12-29 ntfreak * : - add support for extended gdb packet R (restart), requires gdb to be started with target extended-remote git-svn-id: svn://svn.berlios.de/openocd/trunk@247 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-12-21 mifi * : - corrected working_area of LPC2129 script - added LPC2148 script - corrected size of the working_area of the LPC2294 script git-svn-id: svn://svn.berlios.de/openocd/trunk@245 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-12-20 ntfreak * : - removed flash write_image - binary compare function has been moved to verify_image command - minor code reformat and cleanup - updated docs to include new commands git-svn-id: svn://svn.berlios.de/openocd/trunk@243 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-12-18 ntfreak * : - added patch by Øyvind Harboe to Intel Hex Start Segment Address Record (Type 3) - added support to parse Motorola Record Count (S5) git-svn-id: svn://svn.berlios.de/openocd/trunk@241 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-12-17 mifi * : - only some cosmetic changes, convert \r\n to unix git-svn-id: svn://svn.berlios.de/openocd/trunk@239 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-12-17 mifi * : - added patch to corrected argument of image_open in handle_flash_write_image_command (thanks to oyvind Harboe for the patch) git-svn-id: svn://svn.berlios.de/openocd/trunk@237 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-12-16 mifi * : - removed some compiler warnings - added patch to fix problem in cfi_intel_write_block. In case of cfi_info->write_algorithm is not NULL, target_code_size was not set. (thanks to oyvind Harboe for the patch) git-svn-id: svn://svn.berlios.de/openocd/trunk@235 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-12-16 mifi * : - initialize num_sectors and sectors in handle_flash_bank_command. (thanks to oyvind Harboe for this hint) git-svn-id: svn://svn.berlios.de/openocd/trunk@233 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-12-14 mifi * : - added the patch CFI-BE-Fixes-Blockwrite-Support.diff (thanks to Carsten Schlote for the patch) git-svn-id: svn://svn.berlios.de/openocd/trunk@231 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-12-14 mifi * : Sorry, I have forgotten to add a description for the last version, where I have added the clear_malloc and fill_malloc functionality. But the default is the original malloc. git-svn-id: svn://svn.berlios.de/openocd/trunk@229 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-12-14 mifi * : - added patch from Dominic to unlock the ATMEL flash in cfi_read_atmel_pri_ext - set cfi_info->write_algorithm and cfi_info->erase_check_algorithm to NULL to get "flash erase_check" command working git-svn-id: svn://svn.berlios.de/openocd/trunk@227 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-12-10 bodylove * : - Stripped trailing spaces (patch preparation) git-svn-id: svn://svn.berlios.de/openocd/trunk@225 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-12-10 bodylove * : - Added PKGLIBDIR define to C options. Allows to store native code fragments at a central place git-svn-id: svn://svn.berlios.de/openocd/trunk@223 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-12-10 bodylove * : Changed openocd version info creation to be more useful. - Now displays subversion revision and svn URL git-svn-id: svn://svn.berlios.de/openocd/trunk@220 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-12-05 bodylove * : Merged rev 215 changes from /branches/xscale-ixp-be into trunk: - Obvious fixes to big endian type conversion macros - Fixed obvious typos for byte masks git-svn-id: svn://svn.berlios.de/openocd/trunk@217 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-11-23 ntfreak * : - added support for Hitex STM32 Performance Stick - added str9 and stm32 scripts to docs git-svn-id: svn://svn.berlios.de/openocd/trunk@213 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-10-26 ntfreak * : - corrected str91x bank1 programming issues - str91x protect_check fixed - bank number now correctly given to str91x flash_config command git-svn-id: svn://svn.berlios.de/openocd/trunk@211 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-10-08 ntfreak * : - cleaned up str7, str9 and stm32 flash drivers - str7 flash driver now checks correct busy bits depending on device - str9 flash driver now disables ITCM order as per st programming manual - added str7 disable_jtag command - added gdb_detach command - updated arm966e cp15 support - fix crash on mingw build when enabling target_request debugmsgs git-svn-id: svn://svn.berlios.de/openocd/trunk@209 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-09-10 mlu * : - Fixed display of sector sizes in flash.c - Clean up, remove unused variables and code in armv7, cortex_m3 and stellaris code - Move restore_context from cortex_m3 to armv7m - Updated halt handling for cortex_m3 git-svn-id: svn://svn.berlios.de/openocd/trunk@206 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-09-05 drath * : Patch by Michael Schwingen that - adds support for the Altium universal JTAG cable - adds support for "wiggler2" cable (basically a wiggler with added LED, documentation coming soon) - adds LED support. The LED is turned on during data transfer - works fine on Altium and wiggler2. - adds PORT_EXIT pattern that is written to port when exiting, in order to turn off power on cables that get their power from parallel port data lines - move port writes (with the system-specific ifdefs) to one central function - increased image cache size to 2KB (might require more adaptive cache handling, e.g. LRU) git-svn-id: svn://svn.berlios.de/openocd/trunk@204 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-08-21 drath * : - correctly initialize start address for XScale trace buffer decodes in fill-once mode git-svn-id: svn://svn.berlios.de/openocd/trunk@202 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-08-20 mlu * : - Support for AT91SAM7xx512 chips git-svn-id: svn://svn.berlios.de/openocd/trunk@200 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-08-17 drath * : - renamed "xscale dump_trace_buffer" to "xscale dump_trace" and added code for it git-svn-id: svn://svn.berlios.de/openocd/trunk@198 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-08-16 drath * : - fixed several bugs in flash writing code (thanks to Pavel Chromy) git-svn-id: svn://svn.berlios.de/openocd/trunk@196 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-08-14 drath * : - reworked presto.c to allow use of either FTD2XX or libftdi (libftdi not functional yet). Configure option changed from --enable-presto to --enable-presto_ftd2xx and --enable-presto_libftdi - completed trace point support for use with ARM7/9 DCC - completed debug message output with support for HEX dumps (1, 2 or 4 byte quantities) - fixed bug in delete_debug_msg_receiver (thanks to Pavel Chromy) - fixed bug in image_add_section (thanks to Pavel Chromy) - at91sam7 sector erase reworked (thanks to Pavel Chromy) - merge consecutive sections during flash image write to work around possible section alignment issues with LPC2000 targets git-svn-id: svn://svn.berlios.de/openocd/trunk@194 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-08-10 drath * : - bumped version information git-svn-id: svn://svn.berlios.de/openocd/trunk@192 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-08-10 drath * : - renamed M5960 USB JTAG to "flyswatter" - make ep93xx and at91rm9200 bitbang JTAG interfaces dependant on ARM host (thanks to Vincent Palatin) - various whitespace fixes - removed various warnings - add support for Debian GNU/kFreeBSD (thanks to Uwe Hermann) - fix OpenOCD compilation for various platforms (thanks to Uwe Hermann and Vincent Palatin) - switched order of JTAG chain examination and validation (examine first, then multiple validation tries even if examination failed) - added target_request subsystem to handle requests from the target (debug messages and tracepoints implemented, future enhancements might include semihosting, all ARM7/9 only for now) - added support for GDB vFlashXXX packets (thanks to Pavel Chromy) - added support for receiving data via ARM7/9 DCC - reworked flash writing. the 'flash write' command is now deprecated and replaced by 'flash write_binary' (old syntax and behaviour) and 'flash write_image' (write image files (bin, hex, elf, s19) to a target). - added support for AMD/ST/SST 29F400B non-cfi flashes git-svn-id: svn://svn.berlios.de/openocd/trunk@190 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-07-31 drath * : - cleaned up cycle counting in ETM analysis - fixed broken OpenOCD version string git-svn-id: svn://svn.berlios.de/openocd/trunk@188 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-07-31 drath * : - calculate cycles since last executed instruction when cycle-accurate tracing is enabled - increase memory pseudo-image cache size to 1024 byte for improved trace analysis performance - added OpenOCD+trace as an ETM capture driver example implementation - new usbprog driver (thanks to Benedikt Sauter) git-svn-id: svn://svn.berlios.de/openocd/trunk@186 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-07-26 ntfreak * : - corrected stm32x_handle_options_write_command, incorrect options printed - added prepare_reset_halt handler for cortex_m3 git-svn-id: svn://svn.berlios.de/openocd/trunk@184 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-07-26 drath * : - documentation fixes (thanks to Uwe Hermann) - bootstrapping changes to accomodate packaging (thanks to Uwe Hermann) git-svn-id: svn://svn.berlios.de/openocd/trunk@182 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-07-15 drath * : - added support for Asix Presto JTAG interface (thanks to Pavel Chromy and Asix for making this addition possible) - added support for usbprog (thanks to Benedikt Sauter) - make OpenOCD listen for WM_QUIT messages on windows (thanks to Pavel Chromy) - register at_exit handler to do necessary unregistering (thanks to Pavel Chromy) - added dummy ETM capture driver to allow ETM to be registered without a capture driver git-svn-id: svn://svn.berlios.de/openocd/trunk@180 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-06-24 ntfreak * : - ST STM32x cortex support added - ST STM32x flash support added - cleaned up armv7m and cortex-m3 support, removed luminary specific code - cortex-m3 16bit read/write added (required for STM32x flash programming) git-svn-id: svn://svn.berlios.de/openocd/trunk@177 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-06-16 ntfreak * : - str9xpec driver was using stricmp, changed to strcmp for posix compatibility git-svn-id: svn://svn.berlios.de/openocd/trunk@175 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-06-15 drath * : - added support for pseudo image type "mem", currently only used for etm analysis: "etm image mem" git-svn-id: svn://svn.berlios.de/openocd/trunk@173 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-06-14 drath * : - added stellaris.[ch] missing from Cortex-M3 merge git-svn-id: svn://svn.berlios.de/openocd/trunk@171 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-06-14 drath * : - added manpage for OpenOCD (thanks to Uwe Hermann) - fixed bug in ARM926EJ-S cache handling that caused cache linefills to be disabled after first debug entry - added support for auto image type detection (thanks to Vincent Palatin) - further work on ETM trace decoding (tested with a ETB interface using an ETM in normal 16-bit port mode, still experimental) git-svn-id: svn://svn.berlios.de/openocd/trunk@169 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-05-30 drath * : - reworked image handling to support multiple sections (tested with ihex file containing gaps) This checkin is still experimental, not recommended for general use git-svn-id: svn://svn.berlios.de/openocd/trunk@159 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-05-29 drath * : - add missing image handling files git-svn-id: svn://svn.berlios.de/openocd/trunk@156 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-05-10 ntfreak * : -- corrected embedded ice definitions -- changed arm966e to use standard arm9_7 reset handling git-svn-id: svn://svn.berlios.de/openocd/trunk@146 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-04-28 ntfreak * : - added support for Hitex comstick. git-svn-id: svn://svn.berlios.de/openocd/trunk@144 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-04-25 drath * : - added support for error handlers to JTAG scan commands (jtag_[plain_][ir|dr]_scan) - catch apparently broken JTAG IR scan after ARM926EJ-S CP15 operations - added "arm7_9 dump_etb" command git-svn-id: svn://svn.berlios.de/openocd/trunk@142 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-04-16 drath * : - allow multiple USB vendor and product ids when searching for connected FT2232 based JTAG interfaces (thanks to Werner Almesberger for this patch) git-svn-id: svn://svn.berlios.de/openocd/trunk@140 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-04-11 drath * : - disabled excessive debug output in jtag.h - output all of EmbeddedICE version register in error message - update OpenOCD's idea of the current core mode, and immediately change core mode, on CPSR changes - added support for CFI cmdset 0002 (patch by Andrew Dyer, thanks a lot) - enhanced CFI cmdset 0002 support to Atmel AT49 flashes (thanks to Joerg Krein for providing test hardware) git-svn-id: svn://svn.berlios.de/openocd/trunk@138 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-03-29 drath * : - added "arm9tdmi vector_catch ['all'|'none'|'vec1 [vec2 [...]]']" command - added missing arm926ej-s cp15 patch (thanks Vincent Palatin) git-svn-id: svn://svn.berlios.de/openocd/trunk@136 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-03-26 drath * : - fixed arm926 cp15 command bug (thanks to Vincent Palatin for this patch) - fixed compiler warnings throughout the code (thanks to Vincent Palatin for this patch) - added support for accessing ETB (embedded trace buffer) registers git-svn-id: svn://svn.berlios.de/openocd/trunk@134 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-03-15 drath * : - reworked file i/o. every fileaccess (target, flash, nand, in future configuration, too) should now go through the fileio subsystem - added support for reading IHEX files (through fileio) - load/dump_binary renamed to the more generic load/dump_image
['bin'|'ihex'] - added NAND framework (preliminary) - added support for the LPC3180 SLC and MLC NAND controllers (preliminary) - fix initialization for parport - gw16012 fixes/cleanups - added EmbeddedICE version 7 (preliminary, reported on two LPC23xx devices so far) - added 'arm7_9 etm ' configuration command to enable access to the ETM registers git-svn-id: svn://svn.berlios.de/openocd/trunk@132 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-02-03 drath * : - add missing parentheses around macro parameters (thanks to Matthias Bauch for noticing this bug and providing a fix) git-svn-id: svn://svn.berlios.de/openocd/trunk@130 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-01-26 drath * : - disabled use of single-step bit for EmbeddedICE version 6 cores git-svn-id: svn://svn.berlios.de/openocd/trunk@128 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-01-25 drath * : - Added support for ARM926EJ-S based cores - Added contributors to AUTHORS file - Added link to Joern Kaipf's OOCD-Link git-svn-id: svn://svn.berlios.de/openocd/trunk@126 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2007-01-18 ntfreak * : - added support for ST flashlink cable git-svn-id: svn://svn.berlios.de/openocd/trunk@123 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2006-11-22 drath * : - checked in missing configure.in changes for GW16012 support git-svn-id: svn://svn.berlios.de/openocd/trunk@117 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2006-11-07 drath * : - added support for the oocd-link (http://www.joernonline.de/dw/doku.php?id=en:projects:oocdlink) - fixed breakpoint handling (this changes the target_t interface) git-svn-id: svn://svn.berlios.de/openocd/trunk@113 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2006-10-23 drath * : - several small fixes (thanks to Magnus Lundin and Spencer Oliver) - added support for using Luminary Micro development board 'evb_lm3s811' as a JTAG interface (thanks to Magnus Lundin) git-svn-id: svn://svn.berlios.de/openocd/trunk@106 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2006-10-12 drath * : - allow FT2232 devices to be opened by serial number instead of device description ('ft2232_serial ' command) - redirect output from target event scripts (currently only reset) to the daemon output (INFO:) - some minor fixes and enhancements git-svn-id: svn://svn.berlios.de/openocd/trunk@103 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2006-10-03 drath * : - fixed regression in gdb_server.c (Thanks to Michael Fischer for finding these bugs) git-svn-id: svn://svn.berlios.de/openocd/trunk@101 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2006-09-12 drath * : - allow writes to second flash bank on STR71x devices (cleaned up sector list building) - cleaned up str7x flash erase and protect code (use two accesses to erase sectors in both banks) git-svn-id: svn://svn.berlios.de/openocd/trunk@98 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2006-09-07 drath * : - free working area used to store flash write buffer git-svn-id: svn://svn.berlios.de/openocd/trunk@96 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2006-09-04 drath * : - added debug output for D/I FSR and FAR (arm920t) - fixed bug that caused CPSR to be corrupted in Thumb mode git-svn-id: svn://svn.berlios.de/openocd/trunk@93 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2006-08-31 drath * : - added missing AT91RM9200 files - bumped OpenOCD version date git-svn-id: svn://svn.berlios.de/openocd/trunk@91 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2006-08-20 drath * : - made bp command more verbose - fixed bug that could result in register corruption on arm920t targets git-svn-id: svn://svn.berlios.de/openocd/trunk@89 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2006-08-17 drath * : - renamed jtag_interface_t.support_statemove to jtag_interface_t.support_pathmove (it is used to indicate jtag_add_pathmove support) - fixed small bug in str7x.c that printed an address instead of the target number in an error message - added support for Olimex ARM-USB-OCD. The new ft2232 layout is called "olimex-jtag" git-svn-id: svn://svn.berlios.de/openocd/trunk@87 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2006-08-14 drath * : - updated configuration examples, installation instructions and README (including list of supported JTAG interfaces) git-svn-id: svn://svn.berlios.de/openocd/trunk@85 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2006-08-11 drath * : - added support for FreeBSD ppi (parallel port access similar to /dev/parport on linux) (thanks to Darius for this patch) - unified 'ftd2xx' and 'ftdi2232' into a single interface 'ft2232'. The library used to access the hardware is choosen during configure with --enable-ft2232_ftd2xx or --enable-ft2232-libftdi. git-svn-id: svn://svn.berlios.de/openocd/trunk@83 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2006-08-06 drath * : - fixed a minor problem with the GDB server that could drop the first packet (non-fatal) - fixed some small memory leaks (thanks to Spencer Oliver) - verify chip- and buswidth of cfi flash configurations - added support for ARM966E based systems (tested only with ST micro STR9, thanks to Spencer Oliver) git-svn-id: svn://svn.berlios.de/openocd/trunk@81 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2006-07-30 drath * : - added configurable delays after reset lines get deasserted. useful if reset circuitry keeps lines asserted for too long. - additional debug output when opening the parallel port - fixed counting of available arm7/9 watchpoint units - 'flash write' now displays elapsed time git-svn-id: svn://svn.berlios.de/openocd/trunk@79 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2006-06-25 drath * : - fixed bug in Thumb sw breakpoint handling (thanks to Spen for this patch) - fixed handling of services linked list (thanks to Spen for this patch) git-svn-id: svn://svn.berlios.de/openocd/trunk@76 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2006-06-25 drath * : - added "version" command (patch from John Hartman, thanks) - fixed bug in telnet history handling (patch from John Hartman, thanks) - OpenOCD version has been changed from SVN revision number to date/time git-svn-id: svn://svn.berlios.de/openocd/trunk@74 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2006-06-16 drath * : - keep additional information for decoded instructions git-svn-id: svn://svn.berlios.de/openocd/trunk@69 b42882b7-edfa-0310-969c-e2dbd0fdcd60 2006-06-05 drath * : - fixed some spelling errors (thanks to Andrew Dyer) git-svn-id: svn://svn.berlios.de/openocd/trunk@67 b42882b7-edfa-0310-969c-e2dbd0fdcd60 openocd-0.7.0/ltmain.sh0000644000175000001440000105152212141414272011706 00000000000000 # libtool (GNU libtool) 2.4.2 # Written by Gordon Matzigkeit , 1996 # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, # 2007, 2008, 2009, 2010, 2011 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. # GNU Libtool 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. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool 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 GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, # or obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Usage: $progname [OPTION]... [MODE-ARG]... # # Provide generalized library-building support services. # # --config show all configuration variables # --debug enable verbose shell tracing # -n, --dry-run display commands without modifying any files # --features display basic configuration information and exit # --mode=MODE use operation mode MODE # --preserve-dup-deps don't remove duplicate dependency libraries # --quiet, --silent don't print informational messages # --no-quiet, --no-silent # print informational messages (default) # --no-warn don't display warning messages # --tag=TAG use configuration variables from tag TAG # -v, --verbose print more informational messages than default # --no-verbose don't print the extra informational messages # --version print version information # -h, --help, --help-all print short, long, or detailed help message # # MODE must be one of the following: # # clean remove files from the build directory # compile compile a source file into a libtool object # execute automatically set library path, then run a program # finish complete the installation of libtool libraries # install install libraries or executables # link create a library or an executable # uninstall remove libraries from an installed directory # # MODE-ARGS vary depending on the MODE. When passed as first option, # `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that. # Try `$progname --help --mode=MODE' for a more detailed description of MODE. # # When reporting a bug, please describe a test case to reproduce it and # include the following information: # # host-triplet: $host # shell: $SHELL # compiler: $LTCC # compiler flags: $LTCFLAGS # linker: $LD (gnu? $with_gnu_ld) # $progname: (GNU libtool) 2.4.2 # automake: $automake_version # autoconf: $autoconf_version # # Report bugs to . # GNU libtool home page: . # General help using GNU software: . PROGRAM=libtool PACKAGE=libtool VERSION=2.4.2 TIMESTAMP="" package_revision=1.3337 # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } # NLS nuisances: We save the old values to restore during execute mode. lt_user_locale= lt_safe_locale= for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${$lt_var+set}\" = set; then save_$lt_var=\$$lt_var $lt_var=C export $lt_var lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\" lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" fi" done LC_ALL=C LANGUAGE=C export LANGUAGE LC_ALL $lt_unset CDPATH # Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh # is ksh but when the shell is invoked as "sh" and the current value of # the _XPG environment variable is not equal to 1 (one), the special # positional parameter $0, within a function call, is the name of the # function. progpath="$0" : ${CP="cp -f"} test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'} : ${MAKE="make"} : ${MKDIR="mkdir"} : ${MV="mv -f"} : ${RM="rm -f"} : ${SHELL="${CONFIG_SHELL-/bin/sh}"} : ${Xsed="$SED -e 1s/^X//"} # Global variables: EXIT_SUCCESS=0 EXIT_FAILURE=1 EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. exit_status=$EXIT_SUCCESS # Make sure IFS has a sensible default lt_nl=' ' IFS=" $lt_nl" dirname="s,/[^/]*$,," basename="s,^.*/,," # func_dirname file append nondir_replacement # Compute the dirname of FILE. If nonempty, add APPEND to the result, # otherwise set result to NONDIR_REPLACEMENT. func_dirname () { func_dirname_result=`$ECHO "${1}" | $SED "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" else func_dirname_result="$func_dirname_result${2}" fi } # func_dirname may be replaced by extended shell implementation # func_basename file func_basename () { func_basename_result=`$ECHO "${1}" | $SED "$basename"` } # func_basename may be replaced by extended shell implementation # func_dirname_and_basename file append nondir_replacement # perform func_basename and func_dirname in a single function # call: # dirname: Compute the dirname of FILE. If nonempty, # add APPEND to the result, otherwise set result # to NONDIR_REPLACEMENT. # value returned in "$func_dirname_result" # basename: Compute filename of FILE. # value retuned in "$func_basename_result" # Implementation must be kept synchronized with func_dirname # and func_basename. For efficiency, we do not delegate to # those functions but instead duplicate the functionality here. func_dirname_and_basename () { # Extract subdirectory from the argument. func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" else func_dirname_result="$func_dirname_result${2}" fi func_basename_result=`$ECHO "${1}" | $SED -e "$basename"` } # func_dirname_and_basename may be replaced by extended shell implementation # func_stripname prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # func_strip_suffix prefix name func_stripname () { case ${2} in .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; esac } # func_stripname may be replaced by extended shell implementation # These SED scripts presuppose an absolute path with a trailing slash. pathcar='s,^/\([^/]*\).*$,\1,' pathcdr='s,^/[^/]*,,' removedotparts=':dotsl s@/\./@/@g t dotsl s,/\.$,/,' collapseslashes='s@/\{1,\}@/@g' finalslash='s,/*$,/,' # func_normal_abspath PATH # Remove doubled-up and trailing slashes, "." path components, # and cancel out any ".." path components in PATH after making # it an absolute path. # value returned in "$func_normal_abspath_result" func_normal_abspath () { # Start from root dir and reassemble the path. func_normal_abspath_result= func_normal_abspath_tpath=$1 func_normal_abspath_altnamespace= case $func_normal_abspath_tpath in "") # Empty path, that just means $cwd. func_stripname '' '/' "`pwd`" func_normal_abspath_result=$func_stripname_result return ;; # The next three entries are used to spot a run of precisely # two leading slashes without using negated character classes; # we take advantage of case's first-match behaviour. ///*) # Unusual form of absolute path, do nothing. ;; //*) # Not necessarily an ordinary path; POSIX reserves leading '//' # and for example Cygwin uses it to access remote file shares # over CIFS/SMB, so we conserve a leading double slash if found. func_normal_abspath_altnamespace=/ ;; /*) # Absolute path, do nothing. ;; *) # Relative path, prepend $cwd. func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath ;; esac # Cancel out all the simple stuff to save iterations. We also want # the path to end with a slash for ease of parsing, so make sure # there is one (and only one) here. func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"` while :; do # Processed it all yet? if test "$func_normal_abspath_tpath" = / ; then # If we ascended to the root using ".." the result may be empty now. if test -z "$func_normal_abspath_result" ; then func_normal_abspath_result=/ fi break fi func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$pathcar"` func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$pathcdr"` # Figure out what to do with it case $func_normal_abspath_tcomponent in "") # Trailing empty path component, ignore it. ;; ..) # Parent dir; strip last assembled component from result. func_dirname "$func_normal_abspath_result" func_normal_abspath_result=$func_dirname_result ;; *) # Actual path component, append it. func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent ;; esac done # Restore leading double-slash if one was found on entry. func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result } # func_relative_path SRCDIR DSTDIR # generates a relative path from SRCDIR to DSTDIR, with a trailing # slash if non-empty, suitable for immediately appending a filename # without needing to append a separator. # value returned in "$func_relative_path_result" func_relative_path () { func_relative_path_result= func_normal_abspath "$1" func_relative_path_tlibdir=$func_normal_abspath_result func_normal_abspath "$2" func_relative_path_tbindir=$func_normal_abspath_result # Ascend the tree starting from libdir while :; do # check if we have found a prefix of bindir case $func_relative_path_tbindir in $func_relative_path_tlibdir) # found an exact match func_relative_path_tcancelled= break ;; $func_relative_path_tlibdir*) # found a matching prefix func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" func_relative_path_tcancelled=$func_stripname_result if test -z "$func_relative_path_result"; then func_relative_path_result=. fi break ;; *) func_dirname $func_relative_path_tlibdir func_relative_path_tlibdir=${func_dirname_result} if test "x$func_relative_path_tlibdir" = x ; then # Have to descend all the way to the root! func_relative_path_result=../$func_relative_path_result func_relative_path_tcancelled=$func_relative_path_tbindir break fi func_relative_path_result=../$func_relative_path_result ;; esac done # Now calculate path; take care to avoid doubling-up slashes. func_stripname '' '/' "$func_relative_path_result" func_relative_path_result=$func_stripname_result func_stripname '/' '/' "$func_relative_path_tcancelled" if test "x$func_stripname_result" != x ; then func_relative_path_result=${func_relative_path_result}/${func_stripname_result} fi # Normalisation. If bindir is libdir, return empty string, # else relative path ending with a slash; either way, target # file name can be directly appended. if test ! -z "$func_relative_path_result"; then func_stripname './' '' "$func_relative_path_result/" func_relative_path_result=$func_stripname_result fi } # The name of this program: func_dirname_and_basename "$progpath" progname=$func_basename_result # Make sure we have an absolute path for reexecution: case $progpath in [\\/]*|[A-Za-z]:\\*) ;; *[\\/]*) progdir=$func_dirname_result progdir=`cd "$progdir" && pwd` progpath="$progdir/$progname" ;; *) save_IFS="$IFS" IFS=${PATH_SEPARATOR-:} for progdir in $PATH; do IFS="$save_IFS" test -x "$progdir/$progname" && break done IFS="$save_IFS" test -n "$progdir" || progdir=`pwd` progpath="$progdir/$progname" ;; esac # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed="${SED}"' -e 1s/^X//' sed_quote_subst='s/\([`"$\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\(["`\\]\)/\\\1/g' # Sed substitution that turns a string into a regex matching for the # string literally. sed_make_literal_regex='s,[].[^$\\*\/],\\&,g' # Sed substitution that converts a w32 file name or path # which contains forward slashes, into one that contains # (escaped) backslashes. A very naive implementation. lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' # Re-`\' parameter expansions in output of double_quote_subst that were # `\'-ed in input to the same. If an odd number of `\' preceded a '$' # in input to double_quote_subst, that '$' was protected from expansion. # Since each input `\' is now two `\'s, look for any number of runs of # four `\'s followed by two `\'s and then a '$'. `\' that '$'. bs='\\' bs2='\\\\' bs4='\\\\\\\\' dollar='\$' sed_double_backslash="\ s/$bs4/&\\ /g s/^$bs2$dollar/$bs&/ s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g s/\n//g" # Standard options: opt_dry_run=false opt_help=false opt_quiet=false opt_verbose=false opt_warning=: # func_echo arg... # Echo program name prefixed message, along with the current mode # name if it has been set yet. func_echo () { $ECHO "$progname: ${opt_mode+$opt_mode: }$*" } # func_verbose arg... # Echo program name prefixed message in verbose mode only. func_verbose () { $opt_verbose && func_echo ${1+"$@"} # A bug in bash halts the script if the last line of a function # fails when set -e is in force, so we need another command to # work around that: : } # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } # func_error arg... # Echo program name prefixed message to standard error. func_error () { $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2 } # func_warning arg... # Echo program name prefixed warning message to standard error. func_warning () { $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2 # bash bug again: : } # func_fatal_error arg... # Echo program name prefixed message to standard error, and exit. func_fatal_error () { func_error ${1+"$@"} exit $EXIT_FAILURE } # func_fatal_help arg... # Echo program name prefixed message to standard error, followed by # a help hint, and exit. func_fatal_help () { func_error ${1+"$@"} func_fatal_error "$help" } help="Try \`$progname --help' for more information." ## default # func_grep expression filename # Check whether EXPRESSION matches any line of FILENAME, without output. func_grep () { $GREP "$1" "$2" >/dev/null 2>&1 } # func_mkdir_p directory-path # Make sure the entire path to DIRECTORY-PATH is available. func_mkdir_p () { my_directory_path="$1" my_dir_list= if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then # Protect directory names starting with `-' case $my_directory_path in -*) my_directory_path="./$my_directory_path" ;; esac # While some portion of DIR does not yet exist... while test ! -d "$my_directory_path"; do # ...make a list in topmost first order. Use a colon delimited # list incase some portion of path contains whitespace. my_dir_list="$my_directory_path:$my_dir_list" # If the last portion added has no slash in it, the list is done case $my_directory_path in */*) ;; *) break ;; esac # ...otherwise throw away the child directory and loop my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"` done my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'` save_mkdir_p_IFS="$IFS"; IFS=':' for my_dir in $my_dir_list; do IFS="$save_mkdir_p_IFS" # mkdir can fail with a `File exist' error if two processes # try to create one of the directories concurrently. Don't # stop in that case! $MKDIR "$my_dir" 2>/dev/null || : done IFS="$save_mkdir_p_IFS" # Bail out if we (or some other process) failed to create a directory. test -d "$my_directory_path" || \ func_fatal_error "Failed to create \`$1'" fi } # func_mktempdir [string] # Make a temporary directory that won't clash with other running # libtool processes, and avoids race conditions if possible. If # given, STRING is the basename for that directory. func_mktempdir () { my_template="${TMPDIR-/tmp}/${1-$progname}" if test "$opt_dry_run" = ":"; then # Return a directory name, but don't create it in dry-run mode my_tmpdir="${my_template}-$$" else # If mktemp works, use that first and foremost my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` if test ! -d "$my_tmpdir"; then # Failing that, at least try and use $RANDOM to avoid a race my_tmpdir="${my_template}-${RANDOM-0}$$" save_mktempdir_umask=`umask` umask 0077 $MKDIR "$my_tmpdir" umask $save_mktempdir_umask fi # If we're not in dry-run mode, bomb out on failure test -d "$my_tmpdir" || \ func_fatal_error "cannot create temporary directory \`$my_tmpdir'" fi $ECHO "$my_tmpdir" } # func_quote_for_eval arg # Aesthetically quote ARG to be evaled later. # This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT # is double-quoted, suitable for a subsequent eval, whereas # FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters # which are still active within double quotes backslashified. func_quote_for_eval () { case $1 in *[\\\`\"\$]*) func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;; *) func_quote_for_eval_unquoted_result="$1" ;; esac case $func_quote_for_eval_unquoted_result in # Double-quote args containing shell metacharacters to delay # word splitting, command substitution and and variable # expansion for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" ;; *) func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" esac } # func_quote_for_expand arg # Aesthetically quote ARG to be evaled later; same as above, # but do not quote variable references. func_quote_for_expand () { case $1 in *[\\\`\"]*) my_arg=`$ECHO "$1" | $SED \ -e "$double_quote_subst" -e "$sed_double_backslash"` ;; *) my_arg="$1" ;; esac case $my_arg in # Double-quote args containing shell metacharacters to delay # word splitting and command substitution for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") my_arg="\"$my_arg\"" ;; esac func_quote_for_expand_result="$my_arg" } # func_show_eval cmd [fail_exp] # Unless opt_silent is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. func_show_eval () { my_cmd="$1" my_fail_exp="${2-:}" ${opt_silent-false} || { func_quote_for_expand "$my_cmd" eval "func_echo $func_quote_for_expand_result" } if ${opt_dry_run-false}; then :; else eval "$my_cmd" my_status=$? if test "$my_status" -eq 0; then :; else eval "(exit $my_status); $my_fail_exp" fi fi } # func_show_eval_locale cmd [fail_exp] # Unless opt_silent is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. Use the saved locale for evaluation. func_show_eval_locale () { my_cmd="$1" my_fail_exp="${2-:}" ${opt_silent-false} || { func_quote_for_expand "$my_cmd" eval "func_echo $func_quote_for_expand_result" } if ${opt_dry_run-false}; then :; else eval "$lt_user_locale $my_cmd" my_status=$? eval "$lt_safe_locale" if test "$my_status" -eq 0; then :; else eval "(exit $my_status); $my_fail_exp" fi fi } # func_tr_sh # Turn $1 into a string suitable for a shell variable name. # Result is stored in $func_tr_sh_result. All characters # not in the set a-zA-Z0-9_ are replaced with '_'. Further, # if $1 begins with a digit, a '_' is prepended as well. func_tr_sh () { case $1 in [0-9]* | *[!a-zA-Z0-9_]*) func_tr_sh_result=`$ECHO "$1" | $SED 's/^\([0-9]\)/_\1/; s/[^a-zA-Z0-9_]/_/g'` ;; * ) func_tr_sh_result=$1 ;; esac } # func_version # Echo version message to standard output and exit. func_version () { $opt_debug $SED -n '/(C)/!b go :more /\./!{ N s/\n# / / b more } :go /^# '$PROGRAM' (GNU /,/# warranty; / { s/^# // s/^# *$// s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ p }' < "$progpath" exit $? } # func_usage # Echo short help message to standard output and exit. func_usage () { $opt_debug $SED -n '/^# Usage:/,/^# *.*--help/ { s/^# // s/^# *$// s/\$progname/'$progname'/ p }' < "$progpath" echo $ECHO "run \`$progname --help | more' for full usage" exit $? } # func_help [NOEXIT] # Echo long help message to standard output and exit, # unless 'noexit' is passed as argument. func_help () { $opt_debug $SED -n '/^# Usage:/,/# Report bugs to/ { :print s/^# // s/^# *$// s*\$progname*'$progname'* s*\$host*'"$host"'* s*\$SHELL*'"$SHELL"'* s*\$LTCC*'"$LTCC"'* s*\$LTCFLAGS*'"$LTCFLAGS"'* s*\$LD*'"$LD"'* s/\$with_gnu_ld/'"$with_gnu_ld"'/ s/\$automake_version/'"`(${AUTOMAKE-automake} --version) 2>/dev/null |$SED 1q`"'/ s/\$autoconf_version/'"`(${AUTOCONF-autoconf} --version) 2>/dev/null |$SED 1q`"'/ p d } /^# .* home page:/b print /^# General help using/b print ' < "$progpath" ret=$? if test -z "$1"; then exit $ret fi } # func_missing_arg argname # Echo program name prefixed message to standard error and set global # exit_cmd. func_missing_arg () { $opt_debug func_error "missing argument for $1." exit_cmd=exit } # func_split_short_opt shortopt # Set func_split_short_opt_name and func_split_short_opt_arg shell # variables after splitting SHORTOPT after the 2nd character. func_split_short_opt () { my_sed_short_opt='1s/^\(..\).*$/\1/;q' my_sed_short_rest='1s/^..\(.*\)$/\1/;q' func_split_short_opt_name=`$ECHO "$1" | $SED "$my_sed_short_opt"` func_split_short_opt_arg=`$ECHO "$1" | $SED "$my_sed_short_rest"` } # func_split_short_opt may be replaced by extended shell implementation # func_split_long_opt longopt # Set func_split_long_opt_name and func_split_long_opt_arg shell # variables after splitting LONGOPT at the `=' sign. func_split_long_opt () { my_sed_long_opt='1s/^\(--[^=]*\)=.*/\1/;q' my_sed_long_arg='1s/^--[^=]*=//' func_split_long_opt_name=`$ECHO "$1" | $SED "$my_sed_long_opt"` func_split_long_opt_arg=`$ECHO "$1" | $SED "$my_sed_long_arg"` } # func_split_long_opt may be replaced by extended shell implementation exit_cmd=: magic="%%%MAGIC variable%%%" magic_exe="%%%MAGIC EXE variable%%%" # Global variables. nonopt= preserve_args= lo2o="s/\\.lo\$/.${objext}/" o2lo="s/\\.${objext}\$/.lo/" extracted_archives= extracted_serial=0 # If this variable is set in any of the actions, the command in it # will be execed at the end. This prevents here-documents from being # left over by shells. exec_cmd= # func_append var value # Append VALUE to the end of shell variable VAR. func_append () { eval "${1}=\$${1}\${2}" } # func_append may be replaced by extended shell implementation # func_append_quoted var value # Quote VALUE and append to the end of shell variable VAR, separated # by a space. func_append_quoted () { func_quote_for_eval "${2}" eval "${1}=\$${1}\\ \$func_quote_for_eval_result" } # func_append_quoted may be replaced by extended shell implementation # func_arith arithmetic-term... func_arith () { func_arith_result=`expr "${@}"` } # func_arith may be replaced by extended shell implementation # func_len string # STRING may not start with a hyphen. func_len () { func_len_result=`expr "${1}" : ".*" 2>/dev/null || echo $max_cmd_len` } # func_len may be replaced by extended shell implementation # func_lo2o object func_lo2o () { func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"` } # func_lo2o may be replaced by extended shell implementation # func_xform libobj-or-source func_xform () { func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'` } # func_xform may be replaced by extended shell implementation # func_fatal_configuration arg... # Echo program name prefixed message to standard error, followed by # a configuration failure hint, and exit. func_fatal_configuration () { func_error ${1+"$@"} func_error "See the $PACKAGE documentation for more information." func_fatal_error "Fatal configuration error." } # func_config # Display the configuration for all the tags in this script. func_config () { re_begincf='^# ### BEGIN LIBTOOL' re_endcf='^# ### END LIBTOOL' # Default configuration. $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" # Now print the configurations for the tags. for tagname in $taglist; do $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" done exit $? } # func_features # Display the features supported by this script. func_features () { echo "host: $host" if test "$build_libtool_libs" = yes; then echo "enable shared libraries" else echo "disable shared libraries" fi if test "$build_old_libs" = yes; then echo "enable static libraries" else echo "disable static libraries" fi exit $? } # func_enable_tag tagname # Verify that TAGNAME is valid, and either flag an error and exit, or # enable the TAGNAME tag. We also add TAGNAME to the global $taglist # variable here. func_enable_tag () { # Global variable: tagname="$1" re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" sed_extractcf="/$re_begincf/,/$re_endcf/p" # Validate tagname. case $tagname in *[!-_A-Za-z0-9,/]*) func_fatal_error "invalid tag name: $tagname" ;; esac # Don't test for the "default" C tag, as we know it's # there but not specially marked. case $tagname in CC) ;; *) if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then taglist="$taglist $tagname" # Evaluate the configuration. Be careful to quote the path # and the sed script, to avoid splitting on whitespace, but # also don't use non-portable quotes within backquotes within # quotes we have to do it in 2 steps: extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` eval "$extractedcf" else func_error "ignoring unknown tag $tagname" fi ;; esac } # func_check_version_match # Ensure that we are using m4 macros, and libtool script from the same # release of libtool. func_check_version_match () { if test "$package_revision" != "$macro_revision"; then if test "$VERSION" != "$macro_version"; then if test -z "$macro_version"; then cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from an older release. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from $PACKAGE $macro_version. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF fi else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, $progname: but the definition of this LT_INIT comes from revision $macro_revision. $progname: You should recreate aclocal.m4 with macros from revision $package_revision $progname: of $PACKAGE $VERSION and run autoconf again. _LT_EOF fi exit $EXIT_MISMATCH fi } # Shorthand for --mode=foo, only valid as the first argument case $1 in clean|clea|cle|cl) shift; set dummy --mode clean ${1+"$@"}; shift ;; compile|compil|compi|comp|com|co|c) shift; set dummy --mode compile ${1+"$@"}; shift ;; execute|execut|execu|exec|exe|ex|e) shift; set dummy --mode execute ${1+"$@"}; shift ;; finish|finis|fini|fin|fi|f) shift; set dummy --mode finish ${1+"$@"}; shift ;; install|instal|insta|inst|ins|in|i) shift; set dummy --mode install ${1+"$@"}; shift ;; link|lin|li|l) shift; set dummy --mode link ${1+"$@"}; shift ;; uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) shift; set dummy --mode uninstall ${1+"$@"}; shift ;; esac # Option defaults: opt_debug=: opt_dry_run=false opt_config=false opt_preserve_dup_deps=false opt_features=false opt_finish=false opt_help=false opt_help_all=false opt_silent=: opt_warning=: opt_verbose=: opt_silent=false opt_verbose=false # Parse options once, thoroughly. This comes as soon as possible in the # script to make things like `--version' happen as quickly as we can. { # this just eases exit handling while test $# -gt 0; do opt="$1" shift case $opt in --debug|-x) opt_debug='set -x' func_echo "enabling shell trace mode" $opt_debug ;; --dry-run|--dryrun|-n) opt_dry_run=: ;; --config) opt_config=: func_config ;; --dlopen|-dlopen) optarg="$1" opt_dlopen="${opt_dlopen+$opt_dlopen }$optarg" shift ;; --preserve-dup-deps) opt_preserve_dup_deps=: ;; --features) opt_features=: func_features ;; --finish) opt_finish=: set dummy --mode finish ${1+"$@"}; shift ;; --help) opt_help=: ;; --help-all) opt_help_all=: opt_help=': help-all' ;; --mode) test $# = 0 && func_missing_arg $opt && break optarg="$1" opt_mode="$optarg" case $optarg in # Valid mode arguments: clean|compile|execute|finish|install|link|relink|uninstall) ;; # Catch anything else as an error *) func_error "invalid argument for $opt" exit_cmd=exit break ;; esac shift ;; --no-silent|--no-quiet) opt_silent=false func_append preserve_args " $opt" ;; --no-warning|--no-warn) opt_warning=false func_append preserve_args " $opt" ;; --no-verbose) opt_verbose=false func_append preserve_args " $opt" ;; --silent|--quiet) opt_silent=: func_append preserve_args " $opt" opt_verbose=false ;; --verbose|-v) opt_verbose=: func_append preserve_args " $opt" opt_silent=false ;; --tag) test $# = 0 && func_missing_arg $opt && break optarg="$1" opt_tag="$optarg" func_append preserve_args " $opt $optarg" func_enable_tag "$optarg" shift ;; -\?|-h) func_usage ;; --help) func_help ;; --version) func_version ;; # Separate optargs to long options: --*=*) func_split_long_opt "$opt" set dummy "$func_split_long_opt_name" "$func_split_long_opt_arg" ${1+"$@"} shift ;; # Separate non-argument short options: -\?*|-h*|-n*|-v*) func_split_short_opt "$opt" set dummy "$func_split_short_opt_name" "-$func_split_short_opt_arg" ${1+"$@"} shift ;; --) break ;; -*) func_fatal_help "unrecognized option \`$opt'" ;; *) set dummy "$opt" ${1+"$@"}; shift; break ;; esac done # Validate options: # save first non-option argument if test "$#" -gt 0; then nonopt="$opt" shift fi # preserve --debug test "$opt_debug" = : || func_append preserve_args " --debug" case $host in *cygwin* | *mingw* | *pw32* | *cegcc*) # don't eliminate duplications in $postdeps and $predeps opt_duplicate_compiler_generated_deps=: ;; *) opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps ;; esac $opt_help || { # Sanity checks first: func_check_version_match if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then func_fatal_configuration "not configured to build any kind of library" fi # Darwin sucks eval std_shrext=\"$shrext_cmds\" # Only execute mode is allowed to have -dlopen flags. if test -n "$opt_dlopen" && test "$opt_mode" != execute; then func_error "unrecognized option \`-dlopen'" $ECHO "$help" 1>&2 exit $EXIT_FAILURE fi # Change the help message to a mode-specific one. generic_help="$help" help="Try \`$progname --help --mode=$opt_mode' for more information." } # Bail if the options were screwed $exit_cmd $EXIT_FAILURE } ## ----------- ## ## Main. ## ## ----------- ## # func_lalib_p file # True iff FILE is a libtool `.la' library or `.lo' object file. # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_lalib_p () { test -f "$1" && $SED -e 4q "$1" 2>/dev/null \ | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 } # func_lalib_unsafe_p file # True iff FILE is a libtool `.la' library or `.lo' object file. # This function implements the same check as func_lalib_p without # resorting to external programs. To this end, it redirects stdin and # closes it afterwards, without saving the original file descriptor. # As a safety measure, use it only where a negative result would be # fatal anyway. Works if `file' does not exist. func_lalib_unsafe_p () { lalib_p=no if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then for lalib_p_l in 1 2 3 4 do read lalib_p_line case "$lalib_p_line" in \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; esac done exec 0<&5 5<&- fi test "$lalib_p" = yes } # func_ltwrapper_script_p file # True iff FILE is a libtool wrapper script # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_script_p () { func_lalib_p "$1" } # func_ltwrapper_executable_p file # True iff FILE is a libtool wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_executable_p () { func_ltwrapper_exec_suffix= case $1 in *.exe) ;; *) func_ltwrapper_exec_suffix=.exe ;; esac $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 } # func_ltwrapper_scriptname file # Assumes file is an ltwrapper_executable # uses $file to determine the appropriate filename for a # temporary ltwrapper_script. func_ltwrapper_scriptname () { func_dirname_and_basename "$1" "" "." func_stripname '' '.exe' "$func_basename_result" func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" } # func_ltwrapper_p file # True iff FILE is a libtool wrapper script or wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_p () { func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" } # func_execute_cmds commands fail_cmd # Execute tilde-delimited COMMANDS. # If FAIL_CMD is given, eval that upon failure. # FAIL_CMD may read-access the current command in variable CMD! func_execute_cmds () { $opt_debug save_ifs=$IFS; IFS='~' for cmd in $1; do IFS=$save_ifs eval cmd=\"$cmd\" func_show_eval "$cmd" "${2-:}" done IFS=$save_ifs } # func_source file # Source FILE, adding directory component if necessary. # Note that it is not necessary on cygwin/mingw to append a dot to # FILE even if both FILE and FILE.exe exist: automatic-append-.exe # behavior happens only for exec(3), not for open(2)! Also, sourcing # `FILE.' does not work on cygwin managed mounts. func_source () { $opt_debug case $1 in */* | *\\*) . "$1" ;; *) . "./$1" ;; esac } # func_resolve_sysroot PATH # Replace a leading = in PATH with a sysroot. Store the result into # func_resolve_sysroot_result func_resolve_sysroot () { func_resolve_sysroot_result=$1 case $func_resolve_sysroot_result in =*) func_stripname '=' '' "$func_resolve_sysroot_result" func_resolve_sysroot_result=$lt_sysroot$func_stripname_result ;; esac } # func_replace_sysroot PATH # If PATH begins with the sysroot, replace it with = and # store the result into func_replace_sysroot_result. func_replace_sysroot () { case "$lt_sysroot:$1" in ?*:"$lt_sysroot"*) func_stripname "$lt_sysroot" '' "$1" func_replace_sysroot_result="=$func_stripname_result" ;; *) # Including no sysroot. func_replace_sysroot_result=$1 ;; esac } # func_infer_tag arg # Infer tagged configuration to use if any are available and # if one wasn't chosen via the "--tag" command line option. # Only attempt this if the compiler in the base compile # command doesn't match the default compiler. # arg is usually of the form 'gcc ...' func_infer_tag () { $opt_debug if test -n "$available_tags" && test -z "$tagname"; then CC_quoted= for arg in $CC; do func_append_quoted CC_quoted "$arg" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case $@ in # Blanks in the command may have been stripped by the calling shell, # but not from the CC environment variable when configure was run. " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; # Blanks at the start of $base_compile will cause this to fail # if we don't check for them as well. *) for z in $available_tags; do if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then # Evaluate the configuration. eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" CC_quoted= for arg in $CC; do # Double-quote args containing other shell metacharacters. func_append_quoted CC_quoted "$arg" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case "$@ " in " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) # The compiler in the base compile command matches # the one in the tagged configuration. # Assume this is the tagged configuration we want. tagname=$z break ;; esac fi done # If $tagname still isn't set, then no tagged configuration # was found and let the user know that the "--tag" command # line option must be used. if test -z "$tagname"; then func_echo "unable to infer tagged configuration" func_fatal_error "specify a tag with \`--tag'" # else # func_verbose "using $tagname tagged configuration" fi ;; esac fi } # func_write_libtool_object output_name pic_name nonpic_name # Create a libtool object file (analogous to a ".la" file), # but don't create it if we're doing a dry run. func_write_libtool_object () { write_libobj=${1} if test "$build_libtool_libs" = yes; then write_lobj=\'${2}\' else write_lobj=none fi if test "$build_old_libs" = yes; then write_oldobj=\'${3}\' else write_oldobj=none fi $opt_dry_run || { cat >${write_libobj}T </dev/null` if test "$?" -eq 0 && test -n "${func_convert_core_file_wine_to_w32_tmp}"; then func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | $SED -e "$lt_sed_naive_backslashify"` else func_convert_core_file_wine_to_w32_result= fi fi } # end: func_convert_core_file_wine_to_w32 # func_convert_core_path_wine_to_w32 ARG # Helper function used by path conversion functions when $build is *nix, and # $host is mingw, cygwin, or some other w32 environment. Relies on a correctly # configured wine environment available, with the winepath program in $build's # $PATH. Assumes ARG has no leading or trailing path separator characters. # # ARG is path to be converted from $build format to win32. # Result is available in $func_convert_core_path_wine_to_w32_result. # Unconvertible file (directory) names in ARG are skipped; if no directory names # are convertible, then the result may be empty. func_convert_core_path_wine_to_w32 () { $opt_debug # unfortunately, winepath doesn't convert paths, only file names func_convert_core_path_wine_to_w32_result="" if test -n "$1"; then oldIFS=$IFS IFS=: for func_convert_core_path_wine_to_w32_f in $1; do IFS=$oldIFS func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" if test -n "$func_convert_core_file_wine_to_w32_result" ; then if test -z "$func_convert_core_path_wine_to_w32_result"; then func_convert_core_path_wine_to_w32_result="$func_convert_core_file_wine_to_w32_result" else func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" fi fi done IFS=$oldIFS fi } # end: func_convert_core_path_wine_to_w32 # func_cygpath ARGS... # Wrapper around calling the cygpath program via LT_CYGPATH. This is used when # when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) # $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or # (2), returns the Cygwin file name or path in func_cygpath_result (input # file name or path is assumed to be in w32 format, as previously converted # from $build's *nix or MSYS format). In case (3), returns the w32 file name # or path in func_cygpath_result (input file name or path is assumed to be in # Cygwin format). Returns an empty string on error. # # ARGS are passed to cygpath, with the last one being the file name or path to # be converted. # # Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH # environment variable; do not put it in $PATH. func_cygpath () { $opt_debug if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` if test "$?" -ne 0; then # on failure, ensure result is empty func_cygpath_result= fi else func_cygpath_result= func_error "LT_CYGPATH is empty or specifies non-existent file: \`$LT_CYGPATH'" fi } #end: func_cygpath # func_convert_core_msys_to_w32 ARG # Convert file name or path ARG from MSYS format to w32 format. Return # result in func_convert_core_msys_to_w32_result. func_convert_core_msys_to_w32 () { $opt_debug # awkward: cmd appends spaces to result func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"` } #end: func_convert_core_msys_to_w32 # func_convert_file_check ARG1 ARG2 # Verify that ARG1 (a file name in $build format) was converted to $host # format in ARG2. Otherwise, emit an error message, but continue (resetting # func_to_host_file_result to ARG1). func_convert_file_check () { $opt_debug if test -z "$2" && test -n "$1" ; then func_error "Could not determine host file name corresponding to" func_error " \`$1'" func_error "Continuing, but uninstalled executables may not work." # Fallback: func_to_host_file_result="$1" fi } # end func_convert_file_check # func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH # Verify that FROM_PATH (a path in $build format) was converted to $host # format in TO_PATH. Otherwise, emit an error message, but continue, resetting # func_to_host_file_result to a simplistic fallback value (see below). func_convert_path_check () { $opt_debug if test -z "$4" && test -n "$3"; then func_error "Could not determine the host path corresponding to" func_error " \`$3'" func_error "Continuing, but uninstalled executables may not work." # Fallback. This is a deliberately simplistic "conversion" and # should not be "improved". See libtool.info. if test "x$1" != "x$2"; then lt_replace_pathsep_chars="s|$1|$2|g" func_to_host_path_result=`echo "$3" | $SED -e "$lt_replace_pathsep_chars"` else func_to_host_path_result="$3" fi fi } # end func_convert_path_check # func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG # Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT # and appending REPL if ORIG matches BACKPAT. func_convert_path_front_back_pathsep () { $opt_debug case $4 in $1 ) func_to_host_path_result="$3$func_to_host_path_result" ;; esac case $4 in $2 ) func_append func_to_host_path_result "$3" ;; esac } # end func_convert_path_front_back_pathsep ################################################## # $build to $host FILE NAME CONVERSION FUNCTIONS # ################################################## # invoked via `$to_host_file_cmd ARG' # # In each case, ARG is the path to be converted from $build to $host format. # Result will be available in $func_to_host_file_result. # func_to_host_file ARG # Converts the file name ARG from $build format to $host format. Return result # in func_to_host_file_result. func_to_host_file () { $opt_debug $to_host_file_cmd "$1" } # end func_to_host_file # func_to_tool_file ARG LAZY # converts the file name ARG from $build format to toolchain format. Return # result in func_to_tool_file_result. If the conversion in use is listed # in (the comma separated) LAZY, no conversion takes place. func_to_tool_file () { $opt_debug case ,$2, in *,"$to_tool_file_cmd",*) func_to_tool_file_result=$1 ;; *) $to_tool_file_cmd "$1" func_to_tool_file_result=$func_to_host_file_result ;; esac } # end func_to_tool_file # func_convert_file_noop ARG # Copy ARG to func_to_host_file_result. func_convert_file_noop () { func_to_host_file_result="$1" } # end func_convert_file_noop # func_convert_file_msys_to_w32 ARG # Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic # conversion to w32 is not available inside the cwrapper. Returns result in # func_to_host_file_result. func_convert_file_msys_to_w32 () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then func_convert_core_msys_to_w32 "$1" func_to_host_file_result="$func_convert_core_msys_to_w32_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_msys_to_w32 # func_convert_file_cygwin_to_w32 ARG # Convert file name ARG from Cygwin to w32 format. Returns result in # func_to_host_file_result. func_convert_file_cygwin_to_w32 () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then # because $build is cygwin, we call "the" cygpath in $PATH; no need to use # LT_CYGPATH in this case. func_to_host_file_result=`cygpath -m "$1"` fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_cygwin_to_w32 # func_convert_file_nix_to_w32 ARG # Convert file name ARG from *nix to w32 format. Requires a wine environment # and a working winepath. Returns result in func_to_host_file_result. func_convert_file_nix_to_w32 () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then func_convert_core_file_wine_to_w32 "$1" func_to_host_file_result="$func_convert_core_file_wine_to_w32_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_nix_to_w32 # func_convert_file_msys_to_cygwin ARG # Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. # Returns result in func_to_host_file_result. func_convert_file_msys_to_cygwin () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then func_convert_core_msys_to_w32 "$1" func_cygpath -u "$func_convert_core_msys_to_w32_result" func_to_host_file_result="$func_cygpath_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_msys_to_cygwin # func_convert_file_nix_to_cygwin ARG # Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed # in a wine environment, working winepath, and LT_CYGPATH set. Returns result # in func_to_host_file_result. func_convert_file_nix_to_cygwin () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. func_convert_core_file_wine_to_w32 "$1" func_cygpath -u "$func_convert_core_file_wine_to_w32_result" func_to_host_file_result="$func_cygpath_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_nix_to_cygwin ############################################# # $build to $host PATH CONVERSION FUNCTIONS # ############################################# # invoked via `$to_host_path_cmd ARG' # # In each case, ARG is the path to be converted from $build to $host format. # The result will be available in $func_to_host_path_result. # # Path separators are also converted from $build format to $host format. If # ARG begins or ends with a path separator character, it is preserved (but # converted to $host format) on output. # # All path conversion functions are named using the following convention: # file name conversion function : func_convert_file_X_to_Y () # path conversion function : func_convert_path_X_to_Y () # where, for any given $build/$host combination the 'X_to_Y' value is the # same. If conversion functions are added for new $build/$host combinations, # the two new functions must follow this pattern, or func_init_to_host_path_cmd # will break. # func_init_to_host_path_cmd # Ensures that function "pointer" variable $to_host_path_cmd is set to the # appropriate value, based on the value of $to_host_file_cmd. to_host_path_cmd= func_init_to_host_path_cmd () { $opt_debug if test -z "$to_host_path_cmd"; then func_stripname 'func_convert_file_' '' "$to_host_file_cmd" to_host_path_cmd="func_convert_path_${func_stripname_result}" fi } # func_to_host_path ARG # Converts the path ARG from $build format to $host format. Return result # in func_to_host_path_result. func_to_host_path () { $opt_debug func_init_to_host_path_cmd $to_host_path_cmd "$1" } # end func_to_host_path # func_convert_path_noop ARG # Copy ARG to func_to_host_path_result. func_convert_path_noop () { func_to_host_path_result="$1" } # end func_convert_path_noop # func_convert_path_msys_to_w32 ARG # Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic # conversion to w32 is not available inside the cwrapper. Returns result in # func_to_host_path_result. func_convert_path_msys_to_w32 () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # Remove leading and trailing path separator characters from ARG. MSYS # behavior is inconsistent here; cygpath turns them into '.;' and ';.'; # and winepath ignores them completely. func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" func_to_host_path_result="$func_convert_core_msys_to_w32_result" func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_msys_to_w32 # func_convert_path_cygwin_to_w32 ARG # Convert path ARG from Cygwin to w32 format. Returns result in # func_to_host_file_result. func_convert_path_cygwin_to_w32 () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_cygwin_to_w32 # func_convert_path_nix_to_w32 ARG # Convert path ARG from *nix to w32 format. Requires a wine environment and # a working winepath. Returns result in func_to_host_file_result. func_convert_path_nix_to_w32 () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" func_to_host_path_result="$func_convert_core_path_wine_to_w32_result" func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_nix_to_w32 # func_convert_path_msys_to_cygwin ARG # Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. # Returns result in func_to_host_file_result. func_convert_path_msys_to_cygwin () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" func_cygpath -u -p "$func_convert_core_msys_to_w32_result" func_to_host_path_result="$func_cygpath_result" func_convert_path_check : : \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" : "$1" fi } # end func_convert_path_msys_to_cygwin # func_convert_path_nix_to_cygwin ARG # Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a # a wine environment, working winepath, and LT_CYGPATH set. Returns result in # func_to_host_file_result. func_convert_path_nix_to_cygwin () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # Remove leading and trailing path separator characters from # ARG. msys behavior is inconsistent here, cygpath turns them # into '.;' and ';.', and winepath ignores them completely. func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" func_to_host_path_result="$func_cygpath_result" func_convert_path_check : : \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" : "$1" fi } # end func_convert_path_nix_to_cygwin # func_mode_compile arg... func_mode_compile () { $opt_debug # Get the compilation command and the source file. base_compile= srcfile="$nonopt" # always keep a non-empty value in "srcfile" suppress_opt=yes suppress_output= arg_mode=normal libobj= later= pie_flag= for arg do case $arg_mode in arg ) # do not "continue". Instead, add this to base_compile lastarg="$arg" arg_mode=normal ;; target ) libobj="$arg" arg_mode=normal continue ;; normal ) # Accept any command-line options. case $arg in -o) test -n "$libobj" && \ func_fatal_error "you cannot specify \`-o' more than once" arg_mode=target continue ;; -pie | -fpie | -fPIE) func_append pie_flag " $arg" continue ;; -shared | -static | -prefer-pic | -prefer-non-pic) func_append later " $arg" continue ;; -no-suppress) suppress_opt=no continue ;; -Xcompiler) arg_mode=arg # the next one goes into the "base_compile" arg list continue # The current "srcfile" will either be retained or ;; # replaced later. I would guess that would be a bug. -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result lastarg= save_ifs="$IFS"; IFS=',' for arg in $args; do IFS="$save_ifs" func_append_quoted lastarg "$arg" done IFS="$save_ifs" func_stripname ' ' '' "$lastarg" lastarg=$func_stripname_result # Add the arguments to base_compile. func_append base_compile " $lastarg" continue ;; *) # Accept the current argument as the source file. # The previous "srcfile" becomes the current argument. # lastarg="$srcfile" srcfile="$arg" ;; esac # case $arg ;; esac # case $arg_mode # Aesthetically quote the previous argument. func_append_quoted base_compile "$lastarg" done # for arg case $arg_mode in arg) func_fatal_error "you must specify an argument for -Xcompile" ;; target) func_fatal_error "you must specify a target with \`-o'" ;; *) # Get the name of the library object. test -z "$libobj" && { func_basename "$srcfile" libobj="$func_basename_result" } ;; esac # Recognize several different file suffixes. # If the user specifies -o file.o, it is replaced with file.lo case $libobj in *.[cCFSifmso] | \ *.ada | *.adb | *.ads | *.asm | \ *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup) func_xform "$libobj" libobj=$func_xform_result ;; esac case $libobj in *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; *) func_fatal_error "cannot determine name of library object from \`$libobj'" ;; esac func_infer_tag $base_compile for arg in $later; do case $arg in -shared) test "$build_libtool_libs" != yes && \ func_fatal_configuration "can not build a shared library" build_old_libs=no continue ;; -static) build_libtool_libs=no build_old_libs=yes continue ;; -prefer-pic) pic_mode=yes continue ;; -prefer-non-pic) pic_mode=no continue ;; esac done func_quote_for_eval "$libobj" test "X$libobj" != "X$func_quote_for_eval_result" \ && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ && func_warning "libobj name \`$libobj' may not contain shell special characters." func_dirname_and_basename "$obj" "/" "" objname="$func_basename_result" xdir="$func_dirname_result" lobj=${xdir}$objdir/$objname test -z "$base_compile" && \ func_fatal_help "you must specify a compilation command" # Delete any leftover library objects. if test "$build_old_libs" = yes; then removelist="$obj $lobj $libobj ${libobj}T" else removelist="$lobj $libobj ${libobj}T" fi # On Cygwin there's no "real" PIC flag so we must build both object types case $host_os in cygwin* | mingw* | pw32* | os2* | cegcc*) pic_mode=default ;; esac if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then # non-PIC code in shared libraries is not supported pic_mode=default fi # Calculate the filename of the output object if compiler does # not support -o with -c if test "$compiler_c_o" = no; then output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext} lockfile="$output_obj.lock" else output_obj= need_locks=no lockfile= fi # Lock this critical section if it is needed # We use this script file to make the link, it avoids creating a new file if test "$need_locks" = yes; then until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done elif test "$need_locks" = warn; then if test -f "$lockfile"; then $ECHO "\ *** ERROR, $lockfile exists and contains: `cat $lockfile 2>/dev/null` This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi func_append removelist " $output_obj" $ECHO "$srcfile" > "$lockfile" fi $opt_dry_run || $RM $removelist func_append removelist " $lockfile" trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 srcfile=$func_to_tool_file_result func_quote_for_eval "$srcfile" qsrcfile=$func_quote_for_eval_result # Only build a PIC object if we are building libtool libraries. if test "$build_libtool_libs" = yes; then # Without this assignment, base_compile gets emptied. fbsd_hideous_sh_bug=$base_compile if test "$pic_mode" != no; then command="$base_compile $qsrcfile $pic_flag" else # Don't build PIC code command="$base_compile $qsrcfile" fi func_mkdir_p "$xdir$objdir" if test -z "$output_obj"; then # Place PIC objects in $objdir func_append command " -o $lobj" fi func_show_eval_locale "$command" \ 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' if test "$need_locks" = warn && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed, then go on to compile the next one if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then func_show_eval '$MV "$output_obj" "$lobj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi # Allow error messages only from the first compilation. if test "$suppress_opt" = yes; then suppress_output=' >/dev/null 2>&1' fi fi # Only build a position-dependent object if we build old libraries. if test "$build_old_libs" = yes; then if test "$pic_mode" != yes; then # Don't build PIC code command="$base_compile $qsrcfile$pie_flag" else command="$base_compile $qsrcfile $pic_flag" fi if test "$compiler_c_o" = yes; then func_append command " -o $obj" fi # Suppress compiler output if we already did a PIC compilation. func_append command "$suppress_output" func_show_eval_locale "$command" \ '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' if test "$need_locks" = warn && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then func_show_eval '$MV "$output_obj" "$obj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi fi $opt_dry_run || { func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" # Unlock the critical section if it was locked if test "$need_locks" != no; then removelist=$lockfile $RM "$lockfile" fi } exit $EXIT_SUCCESS } $opt_help || { test "$opt_mode" = compile && func_mode_compile ${1+"$@"} } func_mode_help () { # We need to display help for each of the modes. case $opt_mode in "") # Generic help is extracted from the usage comments # at the start of this file. func_help ;; clean) $ECHO \ "Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... Remove files from the build directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, object or program, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; compile) $ECHO \ "Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE Compile a source file into a libtool library object. This mode accepts the following additional options: -o OUTPUT-FILE set the output file name to OUTPUT-FILE -no-suppress do not suppress compiler output for multiple passes -prefer-pic try to build PIC objects only -prefer-non-pic try to build non-PIC objects only -shared do not build a \`.o' file suitable for static linking -static only build a \`.o' file suitable for static linking -Wc,FLAG pass FLAG directly to the compiler COMPILE-COMMAND is a command to be used in creating a \`standard' object file from the given SOURCEFILE. The output file name is determined by removing the directory component from SOURCEFILE, then substituting the C source code suffix \`.c' with the library object suffix, \`.lo'." ;; execute) $ECHO \ "Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... Automatically set library path, then run a program. This mode accepts the following additional options: -dlopen FILE add the directory containing FILE to the library path This mode sets the library path environment variable according to \`-dlopen' flags. If any of the ARGS are libtool executable wrappers, then they are translated into their corresponding uninstalled binary, and any of their required library directories are added to the library path. Then, COMMAND is executed, with ARGS as arguments." ;; finish) $ECHO \ "Usage: $progname [OPTION]... --mode=finish [LIBDIR]... Complete the installation of libtool libraries. Each LIBDIR is a directory that contains libtool libraries. The commands that this mode executes may require superuser privileges. Use the \`--dry-run' option if you just want to see what would be executed." ;; install) $ECHO \ "Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... Install executables or libraries. INSTALL-COMMAND is the installation command. The first component should be either the \`install' or \`cp' program. The following components of INSTALL-COMMAND are treated specially: -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation The rest of the components are interpreted as arguments to that command (only BSD-compatible install options are recognized)." ;; link) $ECHO \ "Usage: $progname [OPTION]... --mode=link LINK-COMMAND... Link object files or libraries together to form another library, or to create an executable program. LINK-COMMAND is a command using the C compiler that you would use to create a program from several object files. The following components of LINK-COMMAND are treated specially: -all-static do not do any dynamic linking at all -avoid-version do not add a version suffix if possible -bindir BINDIR specify path to binaries directory (for systems where libraries must be found in the PATH setting at runtime) -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) -export-symbols SYMFILE try to export only the symbols listed in SYMFILE -export-symbols-regex REGEX try to export only the symbols matching REGEX -LLIBDIR search LIBDIR for required installed libraries -lNAME OUTPUT-FILE requires the installed library libNAME -module build a library that can dlopened -no-fast-install disable the fast-install mode -no-install link a not-installable executable -no-undefined declare that a library does not refer to external symbols -o OUTPUT-FILE create OUTPUT-FILE from the specified objects -objectlist FILE Use a list of object files found in FILE to specify objects -precious-files-regex REGEX don't remove output files matching REGEX -release RELEASE specify package release information -rpath LIBDIR the created library will eventually be installed in LIBDIR -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries -shared only do dynamic linking of libtool libraries -shrext SUFFIX override the standard shared library file extension -static do not do any dynamic linking of uninstalled libtool libraries -static-libtool-libs do not do any dynamic linking of libtool libraries -version-info CURRENT[:REVISION[:AGE]] specify library version info [each variable defaults to 0] -weak LIBNAME declare that the target provides the LIBNAME interface -Wc,FLAG -Xcompiler FLAG pass linker-specific FLAG directly to the compiler -Wl,FLAG -Xlinker FLAG pass linker-specific FLAG directly to the linker -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) All other options (arguments beginning with \`-') are ignored. Every other argument is treated as a filename. Files ending in \`.la' are treated as uninstalled libtool libraries, other files are standard or library object files. If the OUTPUT-FILE ends in \`.la', then a libtool library is created, only library objects (\`.lo' files) may be specified, and \`-rpath' is required, except when creating a convenience library. If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created using \`ar' and \`ranlib', or on Windows using \`lib'. If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file is created, otherwise an executable program is created." ;; uninstall) $ECHO \ "Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... Remove libraries from an installation directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; *) func_fatal_help "invalid operation mode \`$opt_mode'" ;; esac echo $ECHO "Try \`$progname --help' for more information about other modes." } # Now that we've collected a possible --mode arg, show help if necessary if $opt_help; then if test "$opt_help" = :; then func_mode_help else { func_help noexit for opt_mode in compile link execute install finish uninstall clean; do func_mode_help done } | sed -n '1p; 2,$s/^Usage:/ or: /p' { func_help noexit for opt_mode in compile link execute install finish uninstall clean; do echo func_mode_help done } | sed '1d /^When reporting/,/^Report/{ H d } $x /information about other modes/d /more detailed .*MODE/d s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' fi exit $? fi # func_mode_execute arg... func_mode_execute () { $opt_debug # The first argument is the command name. cmd="$nonopt" test -z "$cmd" && \ func_fatal_help "you must specify a COMMAND" # Handle -dlopen flags immediately. for file in $opt_dlopen; do test -f "$file" \ || func_fatal_help "\`$file' is not a file" dir= case $file in *.la) func_resolve_sysroot "$file" file=$func_resolve_sysroot_result # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "\`$lib' is not a valid libtool archive" # Read the libtool library. dlname= library_names= func_source "$file" # Skip this library if it cannot be dlopened. if test -z "$dlname"; then # Warn if it was a shared library. test -n "$library_names" && \ func_warning "\`$file' was not linked with \`-export-dynamic'" continue fi func_dirname "$file" "" "." dir="$func_dirname_result" if test -f "$dir/$objdir/$dlname"; then func_append dir "/$objdir" else if test ! -f "$dir/$dlname"; then func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" fi fi ;; *.lo) # Just add the directory containing the .lo file. func_dirname "$file" "" "." dir="$func_dirname_result" ;; *) func_warning "\`-dlopen' is ignored for non-libtool libraries and objects" continue ;; esac # Get the absolute pathname. absdir=`cd "$dir" && pwd` test -n "$absdir" && dir="$absdir" # Now add the directory to shlibpath_var. if eval "test -z \"\$$shlibpath_var\""; then eval "$shlibpath_var=\"\$dir\"" else eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" fi done # This variable tells wrapper scripts just to set shlibpath_var # rather than running their programs. libtool_execute_magic="$magic" # Check if any of the arguments is a wrapper script. args= for file do case $file in -* | *.la | *.lo ) ;; *) # Do a test to see if this is really a libtool program. if func_ltwrapper_script_p "$file"; then func_source "$file" # Transform arg to wrapped name. file="$progdir/$program" elif func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" func_source "$func_ltwrapper_scriptname_result" # Transform arg to wrapped name. file="$progdir/$program" fi ;; esac # Quote arguments (to preserve shell metacharacters). func_append_quoted args "$file" done if test "X$opt_dry_run" = Xfalse; then if test -n "$shlibpath_var"; then # Export the shlibpath_var. eval "export $shlibpath_var" fi # Restore saved environment variables for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${save_$lt_var+set}\" = set; then $lt_var=\$save_$lt_var; export $lt_var else $lt_unset $lt_var fi" done # Now prepare to actually exec the command. exec_cmd="\$cmd$args" else # Display what would be done. if test -n "$shlibpath_var"; then eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" echo "export $shlibpath_var" fi $ECHO "$cmd$args" exit $EXIT_SUCCESS fi } test "$opt_mode" = execute && func_mode_execute ${1+"$@"} # func_mode_finish arg... func_mode_finish () { $opt_debug libs= libdirs= admincmds= for opt in "$nonopt" ${1+"$@"} do if test -d "$opt"; then func_append libdirs " $opt" elif test -f "$opt"; then if func_lalib_unsafe_p "$opt"; then func_append libs " $opt" else func_warning "\`$opt' is not a valid libtool archive" fi else func_fatal_error "invalid argument \`$opt'" fi done if test -n "$libs"; then if test -n "$lt_sysroot"; then sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" else sysroot_cmd= fi # Remove sysroot references if $opt_dry_run; then for lib in $libs; do echo "removing references to $lt_sysroot and \`=' prefixes from $lib" done else tmpdir=`func_mktempdir` for lib in $libs; do sed -e "${sysroot_cmd} s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ > $tmpdir/tmp-la mv -f $tmpdir/tmp-la $lib done ${RM}r "$tmpdir" fi fi if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then for libdir in $libdirs; do if test -n "$finish_cmds"; then # Do each command in the finish commands. func_execute_cmds "$finish_cmds" 'admincmds="$admincmds '"$cmd"'"' fi if test -n "$finish_eval"; then # Do the single finish_eval. eval cmds=\"$finish_eval\" $opt_dry_run || eval "$cmds" || func_append admincmds " $cmds" fi done fi # Exit here if they wanted silent mode. $opt_silent && exit $EXIT_SUCCESS if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then echo "----------------------------------------------------------------------" echo "Libraries have been installed in:" for libdir in $libdirs; do $ECHO " $libdir" done echo echo "If you ever happen to want to link against installed libraries" echo "in a given directory, LIBDIR, you must either use libtool, and" echo "specify the full pathname of the library, or use the \`-LLIBDIR'" echo "flag during linking and do at least one of the following:" if test -n "$shlibpath_var"; then echo " - add LIBDIR to the \`$shlibpath_var' environment variable" echo " during execution" fi if test -n "$runpath_var"; then echo " - add LIBDIR to the \`$runpath_var' environment variable" echo " during linking" fi if test -n "$hardcode_libdir_flag_spec"; then libdir=LIBDIR eval flag=\"$hardcode_libdir_flag_spec\" $ECHO " - use the \`$flag' linker flag" fi if test -n "$admincmds"; then $ECHO " - have your system administrator run these commands:$admincmds" fi if test -f /etc/ld.so.conf; then echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" fi echo echo "See any operating system documentation about shared libraries for" case $host in solaris2.[6789]|solaris2.1[0-9]) echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" echo "pages." ;; *) echo "more information, such as the ld(1) and ld.so(8) manual pages." ;; esac echo "----------------------------------------------------------------------" fi exit $EXIT_SUCCESS } test "$opt_mode" = finish && func_mode_finish ${1+"$@"} # func_mode_install arg... func_mode_install () { $opt_debug # There may be an optional sh(1) argument at the beginning of # install_prog (especially on Windows NT). if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || # Allow the use of GNU shtool's install command. case $nonopt in *shtool*) :;; *) false;; esac; then # Aesthetically quote it. func_quote_for_eval "$nonopt" install_prog="$func_quote_for_eval_result " arg=$1 shift else install_prog= arg=$nonopt fi # The real first argument should be the name of the installation program. # Aesthetically quote it. func_quote_for_eval "$arg" func_append install_prog "$func_quote_for_eval_result" install_shared_prog=$install_prog case " $install_prog " in *[\\\ /]cp\ *) install_cp=: ;; *) install_cp=false ;; esac # We need to accept at least all the BSD install flags. dest= files= opts= prev= install_type= isdir=no stripme= no_mode=: for arg do arg2= if test -n "$dest"; then func_append files " $dest" dest=$arg continue fi case $arg in -d) isdir=yes ;; -f) if $install_cp; then :; else prev=$arg fi ;; -g | -m | -o) prev=$arg ;; -s) stripme=" -s" continue ;; -*) ;; *) # If the previous option needed an argument, then skip it. if test -n "$prev"; then if test "x$prev" = x-m && test -n "$install_override_mode"; then arg2=$install_override_mode no_mode=false fi prev= else dest=$arg continue fi ;; esac # Aesthetically quote the argument. func_quote_for_eval "$arg" func_append install_prog " $func_quote_for_eval_result" if test -n "$arg2"; then func_quote_for_eval "$arg2" fi func_append install_shared_prog " $func_quote_for_eval_result" done test -z "$install_prog" && \ func_fatal_help "you must specify an install program" test -n "$prev" && \ func_fatal_help "the \`$prev' option requires an argument" if test -n "$install_override_mode" && $no_mode; then if $install_cp; then :; else func_quote_for_eval "$install_override_mode" func_append install_shared_prog " -m $func_quote_for_eval_result" fi fi if test -z "$files"; then if test -z "$dest"; then func_fatal_help "no file or destination specified" else func_fatal_help "you must specify a destination" fi fi # Strip any trailing slash from the destination. func_stripname '' '/' "$dest" dest=$func_stripname_result # Check to see that the destination is a directory. test -d "$dest" && isdir=yes if test "$isdir" = yes; then destdir="$dest" destname= else func_dirname_and_basename "$dest" "" "." destdir="$func_dirname_result" destname="$func_basename_result" # Not a directory, so check to see that there is only one file specified. set dummy $files; shift test "$#" -gt 1 && \ func_fatal_help "\`$dest' is not a directory" fi case $destdir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) for file in $files; do case $file in *.lo) ;; *) func_fatal_help "\`$destdir' must be an absolute directory name" ;; esac done ;; esac # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" staticlibs= future_libdirs= current_libdirs= for file in $files; do # Do each installation. case $file in *.$libext) # Do the static libraries later. func_append staticlibs " $file" ;; *.la) func_resolve_sysroot "$file" file=$func_resolve_sysroot_result # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "\`$file' is not a valid libtool archive" library_names= old_library= relink_command= func_source "$file" # Add the libdir to current_libdirs if it is the destination. if test "X$destdir" = "X$libdir"; then case "$current_libdirs " in *" $libdir "*) ;; *) func_append current_libdirs " $libdir" ;; esac else # Note the libdir as a future libdir. case "$future_libdirs " in *" $libdir "*) ;; *) func_append future_libdirs " $libdir" ;; esac fi func_dirname "$file" "/" "" dir="$func_dirname_result" func_append dir "$objdir" if test -n "$relink_command"; then # Determine the prefix the user has applied to our future dir. inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` # Don't allow the user to place us outside of our expected # location b/c this prevents finding dependent libraries that # are installed to the same prefix. # At present, this check doesn't affect windows .dll's that # are installed into $libdir/../bin (currently, that works fine) # but it's something to keep an eye on. test "$inst_prefix_dir" = "$destdir" && \ func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir" if test -n "$inst_prefix_dir"; then # Stick the inst_prefix_dir data into the link command. relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` else relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` fi func_warning "relinking \`$file'" func_show_eval "$relink_command" \ 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"' fi # See the names of the shared library. set dummy $library_names; shift if test -n "$1"; then realname="$1" shift srcname="$realname" test -n "$relink_command" && srcname="$realname"T # Install the shared library and build the symlinks. func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ 'exit $?' tstripme="$stripme" case $host_os in cygwin* | mingw* | pw32* | cegcc*) case $realname in *.dll.a) tstripme="" ;; esac ;; esac if test -n "$tstripme" && test -n "$striplib"; then func_show_eval "$striplib $destdir/$realname" 'exit $?' fi if test "$#" -gt 0; then # Delete the old symlinks, and create new ones. # Try `ln -sf' first, because the `ln' binary might depend on # the symlink we replace! Solaris /bin/ln does not understand -f, # so we also need to try rm && ln -s. for linkname do test "$linkname" != "$realname" \ && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" done fi # Do each command in the postinstall commands. lib="$destdir/$realname" func_execute_cmds "$postinstall_cmds" 'exit $?' fi # Install the pseudo-library for information purposes. func_basename "$file" name="$func_basename_result" instname="$dir/$name"i func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' # Maybe install the static library, too. test -n "$old_library" && func_append staticlibs " $dir/$old_library" ;; *.lo) # Install (i.e. copy) a libtool object. # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else func_basename "$file" destfile="$func_basename_result" destfile="$destdir/$destfile" fi # Deduce the name of the destination old-style object file. case $destfile in *.lo) func_lo2o "$destfile" staticdest=$func_lo2o_result ;; *.$objext) staticdest="$destfile" destfile= ;; *) func_fatal_help "cannot copy a libtool object to \`$destfile'" ;; esac # Install the libtool object if requested. test -n "$destfile" && \ func_show_eval "$install_prog $file $destfile" 'exit $?' # Install the old object if enabled. if test "$build_old_libs" = yes; then # Deduce the name of the old-style object file. func_lo2o "$file" staticobj=$func_lo2o_result func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' fi exit $EXIT_SUCCESS ;; *) # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else func_basename "$file" destfile="$func_basename_result" destfile="$destdir/$destfile" fi # If the file is missing, and there is a .exe on the end, strip it # because it is most likely a libtool script we actually want to # install stripped_ext="" case $file in *.exe) if test ! -f "$file"; then func_stripname '' '.exe' "$file" file=$func_stripname_result stripped_ext=".exe" fi ;; esac # Do a test to see if this is really a libtool program. case $host in *cygwin* | *mingw*) if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" wrapper=$func_ltwrapper_scriptname_result else func_stripname '' '.exe' "$file" wrapper=$func_stripname_result fi ;; *) wrapper=$file ;; esac if func_ltwrapper_script_p "$wrapper"; then notinst_deplibs= relink_command= func_source "$wrapper" # Check the variables that should have been set. test -z "$generated_by_libtool_version" && \ func_fatal_error "invalid libtool wrapper script \`$wrapper'" finalize=yes for lib in $notinst_deplibs; do # Check to see that each library is installed. libdir= if test -f "$lib"; then func_source "$lib" fi libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test if test -n "$libdir" && test ! -f "$libfile"; then func_warning "\`$lib' has not been installed in \`$libdir'" finalize=no fi done relink_command= func_source "$wrapper" outputname= if test "$fast_install" = no && test -n "$relink_command"; then $opt_dry_run || { if test "$finalize" = yes; then tmpdir=`func_mktempdir` func_basename "$file$stripped_ext" file="$func_basename_result" outputname="$tmpdir/$file" # Replace the output file specification. relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` $opt_silent || { func_quote_for_expand "$relink_command" eval "func_echo $func_quote_for_expand_result" } if eval "$relink_command"; then : else func_error "error: relink \`$file' with the above command before installing it" $opt_dry_run || ${RM}r "$tmpdir" continue fi file="$outputname" else func_warning "cannot relink \`$file'" fi } else # Install the binary that we compiled earlier. file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` fi fi # remove .exe since cygwin /usr/bin/install will append another # one anyway case $install_prog,$host in */usr/bin/install*,*cygwin*) case $file:$destfile in *.exe:*.exe) # this is ok ;; *.exe:*) destfile=$destfile.exe ;; *:*.exe) func_stripname '' '.exe' "$destfile" destfile=$func_stripname_result ;; esac ;; esac func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' $opt_dry_run || if test -n "$outputname"; then ${RM}r "$tmpdir" fi ;; esac done for file in $staticlibs; do func_basename "$file" name="$func_basename_result" # Set up the ranlib parameters. oldlib="$destdir/$name" func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 tool_oldlib=$func_to_tool_file_result func_show_eval "$install_prog \$file \$oldlib" 'exit $?' if test -n "$stripme" && test -n "$old_striplib"; then func_show_eval "$old_striplib $tool_oldlib" 'exit $?' fi # Do each command in the postinstall commands. func_execute_cmds "$old_postinstall_cmds" 'exit $?' done test -n "$future_libdirs" && \ func_warning "remember to run \`$progname --finish$future_libdirs'" if test -n "$current_libdirs"; then # Maybe just do a dry run. $opt_dry_run && current_libdirs=" -n$current_libdirs" exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' else exit $EXIT_SUCCESS fi } test "$opt_mode" = install && func_mode_install ${1+"$@"} # func_generate_dlsyms outputname originator pic_p # Extract symbols from dlprefiles and create ${outputname}S.o with # a dlpreopen symbol table. func_generate_dlsyms () { $opt_debug my_outputname="$1" my_originator="$2" my_pic_p="${3-no}" my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'` my_dlsyms= if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then if test -n "$NM" && test -n "$global_symbol_pipe"; then my_dlsyms="${my_outputname}S.c" else func_error "not configured to extract global symbols from dlpreopened files" fi fi if test -n "$my_dlsyms"; then case $my_dlsyms in "") ;; *.c) # Discover the nlist of each of the dlfiles. nlist="$output_objdir/${my_outputname}.nm" func_show_eval "$RM $nlist ${nlist}S ${nlist}T" # Parse the name list into a source file. func_verbose "creating $output_objdir/$my_dlsyms" $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ /* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */ /* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */ #ifdef __cplusplus extern \"C\" { #endif #if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) #pragma GCC diagnostic ignored \"-Wstrict-prototypes\" #endif /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT_DLSYM_CONST #elif defined(__osf__) /* This system does not cope well with relocations in const data. */ # define LT_DLSYM_CONST #else # define LT_DLSYM_CONST const #endif /* External symbol declarations for the compiler. */\ " if test "$dlself" = yes; then func_verbose "generating symbol list for \`$output'" $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" # Add our own program objects to the symbol list. progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` for progfile in $progfiles; do func_to_tool_file "$progfile" func_convert_file_msys_to_w32 func_verbose "extracting global C symbols from \`$func_to_tool_file_result'" $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'" done if test -n "$exclude_expsyms"; then $opt_dry_run || { eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi if test -n "$export_symbols_regex"; then $opt_dry_run || { eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi # Prepare the list of exported symbols if test -z "$export_symbols"; then export_symbols="$output_objdir/$outputname.exp" $opt_dry_run || { $RM $export_symbols eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' ;; esac } else $opt_dry_run || { eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' ;; esac } fi fi for dlprefile in $dlprefiles; do func_verbose "extracting global C symbols from \`$dlprefile'" func_basename "$dlprefile" name="$func_basename_result" case $host in *cygwin* | *mingw* | *cegcc* ) # if an import library, we need to obtain dlname if func_win32_import_lib_p "$dlprefile"; then func_tr_sh "$dlprefile" eval "curr_lafile=\$libfile_$func_tr_sh_result" dlprefile_dlbasename="" if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then # Use subshell, to avoid clobbering current variable values dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` if test -n "$dlprefile_dlname" ; then func_basename "$dlprefile_dlname" dlprefile_dlbasename="$func_basename_result" else # no lafile. user explicitly requested -dlpreopen . $sharedlib_from_linklib_cmd "$dlprefile" dlprefile_dlbasename=$sharedlib_from_linklib_result fi fi $opt_dry_run || { if test -n "$dlprefile_dlbasename" ; then eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' else func_warning "Could not compute DLL name from $name" eval '$ECHO ": $name " >> "$nlist"' fi func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" } else # not an import lib $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" } fi ;; *) $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" } ;; esac done $opt_dry_run || { # Make sure we have at least an empty file. test -f "$nlist" || : > "$nlist" if test -n "$exclude_expsyms"; then $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T $MV "$nlist"T "$nlist" fi # Try sorting and uniquifying the output. if $GREP -v "^: " < "$nlist" | if sort -k 3 /dev/null 2>&1; then sort -k 3 else sort +2 fi | uniq > "$nlist"S; then : else $GREP -v "^: " < "$nlist" > "$nlist"S fi if test -f "$nlist"S; then eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' else echo '/* NONE */' >> "$output_objdir/$my_dlsyms" fi echo >> "$output_objdir/$my_dlsyms" "\ /* The mapping between symbol names and symbols. */ typedef struct { const char *name; void *address; } lt_dlsymlist; extern LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[]; LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[] = {\ { \"$my_originator\", (void *) 0 }," case $need_lib_prefix in no) eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; *) eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; esac echo >> "$output_objdir/$my_dlsyms" "\ {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt_${my_prefix}_LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif\ " } # !$opt_dry_run pic_flag_for_symtable= case "$compile_command " in *" -static "*) ;; *) case $host in # compiling the symbol table file with pic_flag works around # a FreeBSD bug that causes programs to crash when -lm is # linked before any other PIC object. But we must not use # pic_flag when linking with -static. The problem exists in # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; *-*-hpux*) pic_flag_for_symtable=" $pic_flag" ;; *) if test "X$my_pic_p" != Xno; then pic_flag_for_symtable=" $pic_flag" fi ;; esac ;; esac symtab_cflags= for arg in $LTCFLAGS; do case $arg in -pie | -fpie | -fPIE) ;; *) func_append symtab_cflags " $arg" ;; esac done # Now compile the dynamic symbol file. func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' # Clean up the generated files. func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"' # Transform the symbol file into the correct name. symfileobj="$output_objdir/${my_outputname}S.$objext" case $host in *cygwin* | *mingw* | *cegcc* ) if test -f "$output_objdir/$my_outputname.def"; then compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` else compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` fi ;; *) compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` ;; esac ;; *) func_fatal_error "unknown suffix for \`$my_dlsyms'" ;; esac else # We keep going just in case the user didn't refer to # lt_preloaded_symbols. The linker will fail if global_symbol_pipe # really was required. # Nullify the symbol file. compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"` finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` fi } # func_win32_libid arg # return the library type of file 'arg' # # Need a lot of goo to handle *both* DLLs and import libs # Has to be a shell function in order to 'eat' the argument # that is supplied when $file_magic_command is called. # Despite the name, also deal with 64 bit binaries. func_win32_libid () { $opt_debug win32_libid_type="unknown" win32_fileres=`file -L $1 2>/dev/null` case $win32_fileres in *ar\ archive\ import\ library*) # definitely import win32_libid_type="x86 archive import" ;; *ar\ archive*) # could be an import, or static # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then func_to_tool_file "$1" func_convert_file_msys_to_w32 win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | $SED -n -e ' 1,100{ / I /{ s,.*,import, p q } }'` case $win32_nmres in import*) win32_libid_type="x86 archive import";; *) win32_libid_type="x86 archive static";; esac fi ;; *DLL*) win32_libid_type="x86 DLL" ;; *executable*) # but shell scripts are "executable" too... case $win32_fileres in *MS\ Windows\ PE\ Intel*) win32_libid_type="x86 DLL" ;; esac ;; esac $ECHO "$win32_libid_type" } # func_cygming_dll_for_implib ARG # # Platform-specific function to extract the # name of the DLL associated with the specified # import library ARG. # Invoked by eval'ing the libtool variable # $sharedlib_from_linklib_cmd # Result is available in the variable # $sharedlib_from_linklib_result func_cygming_dll_for_implib () { $opt_debug sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` } # func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs # # The is the core of a fallback implementation of a # platform-specific function to extract the name of the # DLL associated with the specified import library LIBNAME. # # SECTION_NAME is either .idata$6 or .idata$7, depending # on the platform and compiler that created the implib. # # Echos the name of the DLL associated with the # specified import library. func_cygming_dll_for_implib_fallback_core () { $opt_debug match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` $OBJDUMP -s --section "$1" "$2" 2>/dev/null | $SED '/^Contents of section '"$match_literal"':/{ # Place marker at beginning of archive member dllname section s/.*/====MARK====/ p d } # These lines can sometimes be longer than 43 characters, but # are always uninteresting /:[ ]*file format pe[i]\{,1\}-/d /^In archive [^:]*:/d # Ensure marker is printed /^====MARK====/p # Remove all lines with less than 43 characters /^.\{43\}/!d # From remaining lines, remove first 43 characters s/^.\{43\}//' | $SED -n ' # Join marker and all lines until next marker into a single line /^====MARK====/ b para H $ b para b :para x s/\n//g # Remove the marker s/^====MARK====// # Remove trailing dots and whitespace s/[\. \t]*$// # Print /./p' | # we now have a list, one entry per line, of the stringified # contents of the appropriate section of all members of the # archive which possess that section. Heuristic: eliminate # all those which have a first or second character that is # a '.' (that is, objdump's representation of an unprintable # character.) This should work for all archives with less than # 0x302f exports -- but will fail for DLLs whose name actually # begins with a literal '.' or a single character followed by # a '.'. # # Of those that remain, print the first one. $SED -e '/^\./d;/^.\./d;q' } # func_cygming_gnu_implib_p ARG # This predicate returns with zero status (TRUE) if # ARG is a GNU/binutils-style import library. Returns # with nonzero status (FALSE) otherwise. func_cygming_gnu_implib_p () { $opt_debug func_to_tool_file "$1" func_convert_file_msys_to_w32 func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` test -n "$func_cygming_gnu_implib_tmp" } # func_cygming_ms_implib_p ARG # This predicate returns with zero status (TRUE) if # ARG is an MS-style import library. Returns # with nonzero status (FALSE) otherwise. func_cygming_ms_implib_p () { $opt_debug func_to_tool_file "$1" func_convert_file_msys_to_w32 func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` test -n "$func_cygming_ms_implib_tmp" } # func_cygming_dll_for_implib_fallback ARG # Platform-specific function to extract the # name of the DLL associated with the specified # import library ARG. # # This fallback implementation is for use when $DLLTOOL # does not support the --identify-strict option. # Invoked by eval'ing the libtool variable # $sharedlib_from_linklib_cmd # Result is available in the variable # $sharedlib_from_linklib_result func_cygming_dll_for_implib_fallback () { $opt_debug if func_cygming_gnu_implib_p "$1" ; then # binutils import library sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` elif func_cygming_ms_implib_p "$1" ; then # ms-generated import library sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` else # unknown sharedlib_from_linklib_result="" fi } # func_extract_an_archive dir oldlib func_extract_an_archive () { $opt_debug f_ex_an_ar_dir="$1"; shift f_ex_an_ar_oldlib="$1" if test "$lock_old_archive_extraction" = yes; then lockfile=$f_ex_an_ar_oldlib.lock until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done fi func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ 'stat=$?; rm -f "$lockfile"; exit $stat' if test "$lock_old_archive_extraction" = yes; then $opt_dry_run || rm -f "$lockfile" fi if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then : else func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" fi } # func_extract_archives gentop oldlib ... func_extract_archives () { $opt_debug my_gentop="$1"; shift my_oldlibs=${1+"$@"} my_oldobjs="" my_xlib="" my_xabs="" my_xdir="" for my_xlib in $my_oldlibs; do # Extract the objects. case $my_xlib in [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; *) my_xabs=`pwd`"/$my_xlib" ;; esac func_basename "$my_xlib" my_xlib="$func_basename_result" my_xlib_u=$my_xlib while :; do case " $extracted_archives " in *" $my_xlib_u "*) func_arith $extracted_serial + 1 extracted_serial=$func_arith_result my_xlib_u=lt$extracted_serial-$my_xlib ;; *) break ;; esac done extracted_archives="$extracted_archives $my_xlib_u" my_xdir="$my_gentop/$my_xlib_u" func_mkdir_p "$my_xdir" case $host in *-darwin*) func_verbose "Extracting $my_xabs" # Do not bother doing anything if just a dry run $opt_dry_run || { darwin_orig_dir=`pwd` cd $my_xdir || exit $? darwin_archive=$my_xabs darwin_curdir=`pwd` darwin_base_archive=`basename "$darwin_archive"` darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` if test -n "$darwin_arches"; then darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` darwin_arch= func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" for darwin_arch in $darwin_arches ; do func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}" $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" func_extract_an_archive "`pwd`" "${darwin_base_archive}" cd "$darwin_curdir" $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" done # $darwin_arches ## Okay now we've a bunch of thin objects, gotta fatten them up :) darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u` darwin_file= darwin_files= for darwin_file in $darwin_filelist; do darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP` $LIPO -create -output "$darwin_file" $darwin_files done # $darwin_filelist $RM -rf unfat-$$ cd "$darwin_orig_dir" else cd $darwin_orig_dir func_extract_an_archive "$my_xdir" "$my_xabs" fi # $darwin_arches } # !$opt_dry_run ;; *) func_extract_an_archive "$my_xdir" "$my_xabs" ;; esac my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP` done func_extract_archives_result="$my_oldobjs" } # func_emit_wrapper [arg=no] # # Emit a libtool wrapper script on stdout. # Don't directly open a file because we may want to # incorporate the script contents within a cygwin/mingw # wrapper executable. Must ONLY be called from within # func_mode_link because it depends on a number of variables # set therein. # # ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR # variable will take. If 'yes', then the emitted script # will assume that the directory in which it is stored is # the $objdir directory. This is a cygwin/mingw-specific # behavior. func_emit_wrapper () { func_emit_wrapper_arg1=${1-no} $ECHO "\ #! $SHELL # $output - temporary wrapper script for $objdir/$outputname # Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION # # The $output program cannot be directly executed until all the libtool # libraries that it depends on are installed. # # This wrapper script should never be moved out of the build directory. # If it is, it will not operate correctly. # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. sed_quote_subst='$sed_quote_subst' # Be Bourne compatible if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH relink_command=\"$relink_command\" # This environment variable determines our operation mode. if test \"\$libtool_install_magic\" = \"$magic\"; then # install mode needs the following variables: generated_by_libtool_version='$macro_version' notinst_deplibs='$notinst_deplibs' else # When we are sourced in execute mode, \$file and \$ECHO are already set. if test \"\$libtool_execute_magic\" != \"$magic\"; then file=\"\$0\"" qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` $ECHO "\ # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$1 _LTECHO_EOF' } ECHO=\"$qECHO\" fi # Very basic option parsing. These options are (a) specific to # the libtool wrapper, (b) are identical between the wrapper # /script/ and the wrapper /executable/ which is used only on # windows platforms, and (c) all begin with the string "--lt-" # (application programs are unlikely to have options which match # this pattern). # # There are only two supported options: --lt-debug and # --lt-dump-script. There is, deliberately, no --lt-help. # # The first argument to this parsing function should be the # script's $0 value, followed by "$@". lt_option_debug= func_parse_lt_options () { lt_script_arg0=\$0 shift for lt_opt do case \"\$lt_opt\" in --lt-debug) lt_option_debug=1 ;; --lt-dump-script) lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` cat \"\$lt_dump_D/\$lt_dump_F\" exit 0 ;; --lt-*) \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 exit 1 ;; esac done # Print the debug banner immediately: if test -n \"\$lt_option_debug\"; then echo \"${outputname}:${output}:\${LINENO}: libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\" 1>&2 fi } # Used when --lt-debug. Prints its arguments to stdout # (redirection is the responsibility of the caller) func_lt_dump_args () { lt_dump_args_N=1; for lt_arg do \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[\$lt_dump_args_N]: \$lt_arg\" lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` done } # Core function for launching the target application func_exec_program_core () { " case $host in # Backslashes separate directories on plain windows *-*-mingw | *-*-os2* | *-cegcc*) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir\\\\\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} " ;; *) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir/\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir/\$program\" \${1+\"\$@\"} " ;; esac $ECHO "\ \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 exit 1 } # A function to encapsulate launching the target application # Strips options in the --lt-* namespace from \$@ and # launches target application with the remaining arguments. func_exec_program () { case \" \$* \" in *\\ --lt-*) for lt_wr_arg do case \$lt_wr_arg in --lt-*) ;; *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; esac shift done ;; esac func_exec_program_core \${1+\"\$@\"} } # Parse options func_parse_lt_options \"\$0\" \${1+\"\$@\"} # Find the directory that this script lives in. thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\` test \"x\$thisdir\" = \"x\$file\" && thisdir=. # Follow symbolic links until we get to the real thisdir. file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\` while test -n \"\$file\"; do destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\` # If there was a directory component, then change thisdir. if test \"x\$destdir\" != \"x\$file\"; then case \"\$destdir\" in [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; *) thisdir=\"\$thisdir/\$destdir\" ;; esac fi file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\` file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` done # Usually 'no', except on cygwin/mingw when embedded into # the cwrapper. WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then # special case for '.' if test \"\$thisdir\" = \".\"; then thisdir=\`pwd\` fi # remove .libs from thisdir case \"\$thisdir\" in *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; $objdir ) thisdir=. ;; esac fi # Try to get the absolute directory name. absdir=\`cd \"\$thisdir\" && pwd\` test -n \"\$absdir\" && thisdir=\"\$absdir\" " if test "$fast_install" = yes; then $ECHO "\ program=lt-'$outputname'$exeext progdir=\"\$thisdir/$objdir\" if test ! -f \"\$progdir/\$program\" || { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ test \"X\$file\" != \"X\$progdir/\$program\"; }; then file=\"\$\$-\$program\" if test ! -d \"\$progdir\"; then $MKDIR \"\$progdir\" else $RM \"\$progdir/\$file\" fi" $ECHO "\ # relink executable if necessary if test -n \"\$relink_command\"; then if relink_command_output=\`eval \$relink_command 2>&1\`; then : else $ECHO \"\$relink_command_output\" >&2 $RM \"\$progdir/\$file\" exit 1 fi fi $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || { $RM \"\$progdir/\$program\"; $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } $RM \"\$progdir/\$file\" fi" else $ECHO "\ program='$outputname' progdir=\"\$thisdir/$objdir\" " fi $ECHO "\ if test -f \"\$progdir/\$program\"; then" # fixup the dll searchpath if we need to. # # Fix the DLL searchpath if we need to. Do this before prepending # to shlibpath, because on Windows, both are PATH and uninstalled # libraries must come first. if test -n "$dllsearchpath"; then $ECHO "\ # Add the dll search path components to the executable PATH PATH=$dllsearchpath:\$PATH " fi # Export our shlibpath_var if we have one. if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then $ECHO "\ # Add our own library path to $shlibpath_var $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" # Some systems cannot cope with colon-terminated $shlibpath_var # The second colon is a workaround for a bug in BeOS R4 sed $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\` export $shlibpath_var " fi $ECHO "\ if test \"\$libtool_execute_magic\" != \"$magic\"; then # Run the actual program with our arguments. func_exec_program \${1+\"\$@\"} fi else # The program doesn't exist. \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 exit 1 fi fi\ " } # func_emit_cwrapperexe_src # emit the source code for a wrapper executable on stdout # Must ONLY be called from within func_mode_link because # it depends on a number of variable set therein. func_emit_cwrapperexe_src () { cat < #include #ifdef _MSC_VER # include # include # include #else # include # include # ifdef __CYGWIN__ # include # endif #endif #include #include #include #include #include #include #include #include /* declarations of non-ANSI functions */ #if defined(__MINGW32__) # ifdef __STRICT_ANSI__ int _putenv (const char *); # endif #elif defined(__CYGWIN__) # ifdef __STRICT_ANSI__ char *realpath (const char *, char *); int putenv (char *); int setenv (const char *, const char *, int); # endif /* #elif defined (other platforms) ... */ #endif /* portability defines, excluding path handling macros */ #if defined(_MSC_VER) # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv # define S_IXUSR _S_IEXEC # ifndef _INTPTR_T_DEFINED # define _INTPTR_T_DEFINED # define intptr_t int # endif #elif defined(__MINGW32__) # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv #elif defined(__CYGWIN__) # define HAVE_SETENV # define FOPEN_WB "wb" /* #elif defined (other platforms) ... */ #endif #if defined(PATH_MAX) # define LT_PATHMAX PATH_MAX #elif defined(MAXPATHLEN) # define LT_PATHMAX MAXPATHLEN #else # define LT_PATHMAX 1024 #endif #ifndef S_IXOTH # define S_IXOTH 0 #endif #ifndef S_IXGRP # define S_IXGRP 0 #endif /* path handling portability macros */ #ifndef DIR_SEPARATOR # define DIR_SEPARATOR '/' # define PATH_SEPARATOR ':' #endif #if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ defined (__OS2__) # define HAVE_DOS_BASED_FILE_SYSTEM # define FOPEN_WB "wb" # ifndef DIR_SEPARATOR_2 # define DIR_SEPARATOR_2 '\\' # endif # ifndef PATH_SEPARATOR_2 # define PATH_SEPARATOR_2 ';' # endif #endif #ifndef DIR_SEPARATOR_2 # define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) #else /* DIR_SEPARATOR_2 */ # define IS_DIR_SEPARATOR(ch) \ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) #endif /* DIR_SEPARATOR_2 */ #ifndef PATH_SEPARATOR_2 # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) #else /* PATH_SEPARATOR_2 */ # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) #endif /* PATH_SEPARATOR_2 */ #ifndef FOPEN_WB # define FOPEN_WB "w" #endif #ifndef _O_BINARY # define _O_BINARY 0 #endif #define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) #define XFREE(stale) do { \ if (stale) { free ((void *) stale); stale = 0; } \ } while (0) #if defined(LT_DEBUGWRAPPER) static int lt_debug = 1; #else static int lt_debug = 0; #endif const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ void *xmalloc (size_t num); char *xstrdup (const char *string); const char *base_name (const char *name); char *find_executable (const char *wrapper); char *chase_symlinks (const char *pathspec); int make_executable (const char *path); int check_executable (const char *path); char *strendzap (char *str, const char *pat); void lt_debugprintf (const char *file, int line, const char *fmt, ...); void lt_fatal (const char *file, int line, const char *message, ...); static const char *nonnull (const char *s); static const char *nonempty (const char *s); void lt_setenv (const char *name, const char *value); char *lt_extend_str (const char *orig_value, const char *add, int to_end); void lt_update_exe_path (const char *name, const char *value); void lt_update_lib_path (const char *name, const char *value); char **prepare_spawn (char **argv); void lt_dump_script (FILE *f); EOF cat <= 0) && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return 1; else return 0; } int make_executable (const char *path) { int rval = 0; struct stat st; lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", nonempty (path)); if ((!path) || (!*path)) return 0; if (stat (path, &st) >= 0) { rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); } return rval; } /* Searches for the full path of the wrapper. Returns newly allocated full path name if found, NULL otherwise Does not chase symlinks, even on platforms that support them. */ char * find_executable (const char *wrapper) { int has_slash = 0; const char *p; const char *p_next; /* static buffer for getcwd */ char tmp[LT_PATHMAX + 1]; int tmp_len; char *concat_name; lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", nonempty (wrapper)); if ((wrapper == NULL) || (*wrapper == '\0')) return NULL; /* Absolute path? */ #if defined (HAVE_DOS_BASED_FILE_SYSTEM) if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } else { #endif if (IS_DIR_SEPARATOR (wrapper[0])) { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } #if defined (HAVE_DOS_BASED_FILE_SYSTEM) } #endif for (p = wrapper; *p; p++) if (*p == '/') { has_slash = 1; break; } if (!has_slash) { /* no slashes; search PATH */ const char *path = getenv ("PATH"); if (path != NULL) { for (p = path; *p; p = p_next) { const char *q; size_t p_len; for (q = p; *q; q++) if (IS_PATH_SEPARATOR (*q)) break; p_len = q - p; p_next = (*q == '\0' ? q : q + 1); if (p_len == 0) { /* empty path: current directory */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); } else { concat_name = XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, p, p_len); concat_name[p_len] = '/'; strcpy (concat_name + p_len + 1, wrapper); } if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } } /* not found in PATH; assume curdir */ } /* Relative path | not found in path: prepend cwd */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); return NULL; } char * chase_symlinks (const char *pathspec) { #ifndef S_ISLNK return xstrdup (pathspec); #else char buf[LT_PATHMAX]; struct stat s; char *tmp_pathspec = xstrdup (pathspec); char *p; int has_symlinks = 0; while (strlen (tmp_pathspec) && !has_symlinks) { lt_debugprintf (__FILE__, __LINE__, "checking path component for symlinks: %s\n", tmp_pathspec); if (lstat (tmp_pathspec, &s) == 0) { if (S_ISLNK (s.st_mode) != 0) { has_symlinks = 1; break; } /* search backwards for last DIR_SEPARATOR */ p = tmp_pathspec + strlen (tmp_pathspec) - 1; while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) p--; if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) { /* no more DIR_SEPARATORS left */ break; } *p = '\0'; } else { lt_fatal (__FILE__, __LINE__, "error accessing file \"%s\": %s", tmp_pathspec, nonnull (strerror (errno))); } } XFREE (tmp_pathspec); if (!has_symlinks) { return xstrdup (pathspec); } tmp_pathspec = realpath (pathspec, buf); if (tmp_pathspec == 0) { lt_fatal (__FILE__, __LINE__, "could not follow symlinks for %s", pathspec); } return xstrdup (tmp_pathspec); #endif } char * strendzap (char *str, const char *pat) { size_t len, patlen; assert (str != NULL); assert (pat != NULL); len = strlen (str); patlen = strlen (pat); if (patlen <= len) { str += len - patlen; if (strcmp (str, pat) == 0) *str = '\0'; } return str; } void lt_debugprintf (const char *file, int line, const char *fmt, ...) { va_list args; if (lt_debug) { (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); va_start (args, fmt); (void) vfprintf (stderr, fmt, args); va_end (args); } } static void lt_error_core (int exit_status, const char *file, int line, const char *mode, const char *message, va_list ap) { fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); vfprintf (stderr, message, ap); fprintf (stderr, ".\n"); if (exit_status >= 0) exit (exit_status); } void lt_fatal (const char *file, int line, const char *message, ...) { va_list ap; va_start (ap, message); lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); va_end (ap); } static const char * nonnull (const char *s) { return s ? s : "(null)"; } static const char * nonempty (const char *s) { return (s && !*s) ? "(empty)" : nonnull (s); } void lt_setenv (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_setenv) setting '%s' to '%s'\n", nonnull (name), nonnull (value)); { #ifdef HAVE_SETENV /* always make a copy, for consistency with !HAVE_SETENV */ char *str = xstrdup (value); setenv (name, str, 1); #else int len = strlen (name) + 1 + strlen (value) + 1; char *str = XMALLOC (char, len); sprintf (str, "%s=%s", name, value); if (putenv (str) != EXIT_SUCCESS) { XFREE (str); } #endif } } char * lt_extend_str (const char *orig_value, const char *add, int to_end) { char *new_value; if (orig_value && *orig_value) { int orig_value_len = strlen (orig_value); int add_len = strlen (add); new_value = XMALLOC (char, add_len + orig_value_len + 1); if (to_end) { strcpy (new_value, orig_value); strcpy (new_value + orig_value_len, add); } else { strcpy (new_value, add); strcpy (new_value + add_len, orig_value); } } else { new_value = xstrdup (add); } return new_value; } void lt_update_exe_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); /* some systems can't cope with a ':'-terminated path #' */ int len = strlen (new_value); while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1])) { new_value[len-1] = '\0'; } lt_setenv (name, new_value); XFREE (new_value); } } void lt_update_lib_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); lt_setenv (name, new_value); XFREE (new_value); } } EOF case $host_os in mingw*) cat <<"EOF" /* Prepares an argument vector before calling spawn(). Note that spawn() does not by itself call the command interpreter (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&v); v.dwPlatformId == VER_PLATFORM_WIN32_NT; }) ? "cmd.exe" : "command.com"). Instead it simply concatenates the arguments, separated by ' ', and calls CreateProcess(). We must quote the arguments since Win32 CreateProcess() interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a special way: - Space and tab are interpreted as delimiters. They are not treated as delimiters if they are surrounded by double quotes: "...". - Unescaped double quotes are removed from the input. Their only effect is that within double quotes, space and tab are treated like normal characters. - Backslashes not followed by double quotes are not special. - But 2*n+1 backslashes followed by a double quote become n backslashes followed by a double quote (n >= 0): \" -> " \\\" -> \" \\\\\" -> \\" */ #define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" #define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" char ** prepare_spawn (char **argv) { size_t argc; char **new_argv; size_t i; /* Count number of arguments. */ for (argc = 0; argv[argc] != NULL; argc++) ; /* Allocate new argument vector. */ new_argv = XMALLOC (char *, argc + 1); /* Put quoted arguments into the new argument vector. */ for (i = 0; i < argc; i++) { const char *string = argv[i]; if (string[0] == '\0') new_argv[i] = xstrdup ("\"\""); else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) { int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); size_t length; unsigned int backslashes; const char *s; char *quoted_string; char *p; length = 0; backslashes = 0; if (quote_around) length++; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') length += backslashes + 1; length++; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) length += backslashes + 1; quoted_string = XMALLOC (char, length + 1); p = quoted_string; backslashes = 0; if (quote_around) *p++ = '"'; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') { unsigned int j; for (j = backslashes + 1; j > 0; j--) *p++ = '\\'; } *p++ = c; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) { unsigned int j; for (j = backslashes; j > 0; j--) *p++ = '\\'; *p++ = '"'; } *p = '\0'; new_argv[i] = quoted_string; } else new_argv[i] = (char *) string; } new_argv[argc] = NULL; return new_argv; } EOF ;; esac cat <<"EOF" void lt_dump_script (FILE* f) { EOF func_emit_wrapper yes | $SED -n -e ' s/^\(.\{79\}\)\(..*\)/\1\ \2/ h s/\([\\"]\)/\\\1/g s/$/\\n/ s/\([^\n]*\).*/ fputs ("\1", f);/p g D' cat <<"EOF" } EOF } # end: func_emit_cwrapperexe_src # func_win32_import_lib_p ARG # True if ARG is an import lib, as indicated by $file_magic_cmd func_win32_import_lib_p () { $opt_debug case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in *import*) : ;; *) false ;; esac } # func_mode_link arg... func_mode_link () { $opt_debug case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) # It is impossible to link a dll without this setting, and # we shouldn't force the makefile maintainer to figure out # which system we are compiling for in order to pass an extra # flag for every libtool invocation. # allow_undefined=no # FIXME: Unfortunately, there are problems with the above when trying # to make a dll which has undefined symbols, in which case not # even a static library is built. For now, we need to specify # -no-undefined on the libtool link line when we can be certain # that all symbols are satisfied, otherwise we get a static library. allow_undefined=yes ;; *) allow_undefined=yes ;; esac libtool_args=$nonopt base_compile="$nonopt $@" compile_command=$nonopt finalize_command=$nonopt compile_rpath= finalize_rpath= compile_shlibpath= finalize_shlibpath= convenience= old_convenience= deplibs= old_deplibs= compiler_flags= linker_flags= dllsearchpath= lib_search_path=`pwd` inst_prefix_dir= new_inherited_linker_flags= avoid_version=no bindir= dlfiles= dlprefiles= dlself=no export_dynamic=no export_symbols= export_symbols_regex= generated= libobjs= ltlibs= module=no no_install=no objs= non_pic_objects= precious_files_regex= prefer_static_libs=no preload=no prev= prevarg= release= rpath= xrpath= perm_rpath= temp_rpath= thread_safe=no vinfo= vinfo_number=no weak_libs= single_module="${wl}-single_module" func_infer_tag $base_compile # We need to know -static, to get the right output filenames. for arg do case $arg in -shared) test "$build_libtool_libs" != yes && \ func_fatal_configuration "can not build a shared library" build_old_libs=no break ;; -all-static | -static | -static-libtool-libs) case $arg in -all-static) if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then func_warning "complete static linking is impossible in this configuration" fi if test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; -static) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=built ;; -static-libtool-libs) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; esac build_libtool_libs=no build_old_libs=yes break ;; esac done # See if our shared archives depend on static archives. test -n "$old_archive_from_new_cmds" && build_old_libs=yes # Go through the arguments, transforming them on the way. while test "$#" -gt 0; do arg="$1" shift func_quote_for_eval "$arg" qarg=$func_quote_for_eval_unquoted_result func_append libtool_args " $func_quote_for_eval_result" # If the previous option needs an argument, assign it. if test -n "$prev"; then case $prev in output) func_append compile_command " @OUTPUT@" func_append finalize_command " @OUTPUT@" ;; esac case $prev in bindir) bindir="$arg" prev= continue ;; dlfiles|dlprefiles) if test "$preload" = no; then # Add the symbol object into the linking commands. func_append compile_command " @SYMFILE@" func_append finalize_command " @SYMFILE@" preload=yes fi case $arg in *.la | *.lo) ;; # We handle these cases below. force) if test "$dlself" = no; then dlself=needless export_dynamic=yes fi prev= continue ;; self) if test "$prev" = dlprefiles; then dlself=yes elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then dlself=yes else dlself=needless export_dynamic=yes fi prev= continue ;; *) if test "$prev" = dlfiles; then func_append dlfiles " $arg" else func_append dlprefiles " $arg" fi prev= continue ;; esac ;; expsyms) export_symbols="$arg" test -f "$arg" \ || func_fatal_error "symbol file \`$arg' does not exist" prev= continue ;; expsyms_regex) export_symbols_regex="$arg" prev= continue ;; framework) case $host in *-*-darwin*) case "$deplibs " in *" $qarg.ltframework "*) ;; *) func_append deplibs " $qarg.ltframework" # this is fixed later ;; esac ;; esac prev= continue ;; inst_prefix) inst_prefix_dir="$arg" prev= continue ;; objectlist) if test -f "$arg"; then save_arg=$arg moreargs= for fil in `cat "$save_arg"` do # func_append moreargs " $fil" arg=$fil # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test "$pic_object" = none && test "$non_pic_object" = none; then func_fatal_error "cannot find name of object for \`$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then func_append dlfiles " $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object="$pic_object" func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "\`$arg' is not a valid libtool object" fi fi done else func_fatal_error "link input file \`$arg' does not exist" fi arg=$save_arg prev= continue ;; precious_regex) precious_files_regex="$arg" prev= continue ;; release) release="-$arg" prev= continue ;; rpath | xrpath) # We need an absolute path. case $arg in [\\/]* | [A-Za-z]:[\\/]*) ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac if test "$prev" = rpath; then case "$rpath " in *" $arg "*) ;; *) func_append rpath " $arg" ;; esac else case "$xrpath " in *" $arg "*) ;; *) func_append xrpath " $arg" ;; esac fi prev= continue ;; shrext) shrext_cmds="$arg" prev= continue ;; weak) func_append weak_libs " $arg" prev= continue ;; xcclinker) func_append linker_flags " $qarg" func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xcompiler) func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xlinker) func_append linker_flags " $qarg" func_append compiler_flags " $wl$qarg" prev= func_append compile_command " $wl$qarg" func_append finalize_command " $wl$qarg" continue ;; *) eval "$prev=\"\$arg\"" prev= continue ;; esac fi # test -n "$prev" prevarg="$arg" case $arg in -all-static) if test -n "$link_static_flag"; then # See comment for -static flag below, for more details. func_append compile_command " $link_static_flag" func_append finalize_command " $link_static_flag" fi continue ;; -allow-undefined) # FIXME: remove this flag sometime in the future. func_fatal_error "\`-allow-undefined' must not be used because it is the default" ;; -avoid-version) avoid_version=yes continue ;; -bindir) prev=bindir continue ;; -dlopen) prev=dlfiles continue ;; -dlpreopen) prev=dlprefiles continue ;; -export-dynamic) export_dynamic=yes continue ;; -export-symbols | -export-symbols-regex) if test -n "$export_symbols" || test -n "$export_symbols_regex"; then func_fatal_error "more than one -exported-symbols argument is not allowed" fi if test "X$arg" = "X-export-symbols"; then prev=expsyms else prev=expsyms_regex fi continue ;; -framework) prev=framework continue ;; -inst-prefix-dir) prev=inst_prefix continue ;; # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* # so, if we see these flags be careful not to treat them like -L -L[A-Z][A-Z]*:*) case $with_gcc/$host in no/*-*-irix* | /*-*-irix*) func_append compile_command " $arg" func_append finalize_command " $arg" ;; esac continue ;; -L*) func_stripname "-L" '' "$arg" if test -z "$func_stripname_result"; then if test "$#" -gt 0; then func_fatal_error "require no space between \`-L' and \`$1'" else func_fatal_error "need path for \`-L' option" fi fi func_resolve_sysroot "$func_stripname_result" dir=$func_resolve_sysroot_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) absdir=`cd "$dir" && pwd` test -z "$absdir" && \ func_fatal_error "cannot determine absolute directory name of \`$dir'" dir="$absdir" ;; esac case "$deplibs " in *" -L$dir "* | *" $arg "*) # Will only happen for absolute or sysroot arguments ;; *) # Preserve sysroot, but never include relative directories case $dir in [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; *) func_append deplibs " -L$dir" ;; esac func_append lib_search_path " $dir" ;; esac case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` case :$dllsearchpath: in *":$dir:"*) ;; ::) dllsearchpath=$dir;; *) func_append dllsearchpath ":$dir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) func_append dllsearchpath ":$testbindir";; esac ;; esac continue ;; -l*) if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) # These systems don't actually have a C or math library (as such) continue ;; *-*-os2*) # These systems don't actually have a C library (as such) test "X$arg" = "X-lc" && continue ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. test "X$arg" = "X-lc" && continue ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C and math libraries are in the System framework func_append deplibs " System.ltframework" continue ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype test "X$arg" = "X-lc" && continue ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work test "X$arg" = "X-lc" && continue ;; esac elif test "X$arg" = "X-lc_r"; then case $host in *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc_r directly, use -pthread flag. continue ;; esac fi func_append deplibs " $arg" continue ;; -module) module=yes continue ;; # Tru64 UNIX uses -model [arg] to determine the layout of C++ # classes, name mangling, and exception handling. # Darwin uses the -arch flag to determine output architecture. -model|-arch|-isysroot|--sysroot) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" prev=xcompiler continue ;; -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" case "$new_inherited_linker_flags " in *" $arg "*) ;; * ) func_append new_inherited_linker_flags " $arg" ;; esac continue ;; -multi_module) single_module="${wl}-multi_module" continue ;; -no-fast-install) fast_install=no continue ;; -no-install) case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) # The PATH hackery in wrapper scripts is required on Windows # and Darwin in order for the loader to find any dlls it needs. func_warning "\`-no-install' is ignored for $host" func_warning "assuming \`-no-fast-install' instead" fast_install=no ;; *) no_install=yes ;; esac continue ;; -no-undefined) allow_undefined=no continue ;; -objectlist) prev=objectlist continue ;; -o) prev=output ;; -precious-files-regex) prev=precious_regex continue ;; -release) prev=release continue ;; -rpath) prev=rpath continue ;; -R) prev=xrpath continue ;; -R*) func_stripname '-R' '' "$arg" dir=$func_stripname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; =*) func_stripname '=' '' "$dir" dir=$lt_sysroot$func_stripname_result ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac case "$xrpath " in *" $dir "*) ;; *) func_append xrpath " $dir" ;; esac continue ;; -shared) # The effects of -shared are defined in a previous loop. continue ;; -shrext) prev=shrext continue ;; -static | -static-libtool-libs) # The effects of -static are defined in a previous loop. # We used to do the same as -all-static on platforms that # didn't have a PIC flag, but the assumption that the effects # would be equivalent was wrong. It would break on at least # Digital Unix and AIX. continue ;; -thread-safe) thread_safe=yes continue ;; -version-info) prev=vinfo continue ;; -version-number) prev=vinfo vinfo_number=yes continue ;; -weak) prev=weak continue ;; -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" func_quote_for_eval "$flag" func_append arg " $func_quote_for_eval_result" func_append compiler_flags " $func_quote_for_eval_result" done IFS="$save_ifs" func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Wl,*) func_stripname '-Wl,' '' "$arg" args=$func_stripname_result arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" func_quote_for_eval "$flag" func_append arg " $wl$func_quote_for_eval_result" func_append compiler_flags " $wl$func_quote_for_eval_result" func_append linker_flags " $func_quote_for_eval_result" done IFS="$save_ifs" func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Xcompiler) prev=xcompiler continue ;; -Xlinker) prev=xlinker continue ;; -XCClinker) prev=xcclinker continue ;; # -msg_* for osf cc -msg_*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; # Flags to be passed through unchanged, with rationale: # -64, -mips[0-9] enable 64-bit mode for the SGI compiler # -r[0-9][0-9]* specify processor for the SGI compiler # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler # +DA*, +DD* enable 64-bit mode for the HP compiler # -q* compiler args for the IBM compiler # -m*, -t[45]*, -txscale* architecture-specific flags for GCC # -F/path path to uninstalled frameworks, gcc on darwin # -p, -pg, --coverage, -fprofile-* profiling flags for GCC # @file GCC response files # -tp=* Portland pgcc target processor selection # --sysroot=* for sysroot support # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ -O*|-flto*|-fwhopr*|-fuse-linker-plugin) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" func_append compile_command " $arg" func_append finalize_command " $arg" func_append compiler_flags " $arg" continue ;; # Some other compiler flag. -* | +*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; *.$objext) # A standard object. func_append objs " $arg" ;; *.lo) # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test "$pic_object" = none && test "$non_pic_object" = none; then func_fatal_error "cannot find name of object for \`$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then func_append dlfiles " $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object="$pic_object" func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "\`$arg' is not a valid libtool object" fi fi ;; *.$libext) # An archive. func_append deplibs " $arg" func_append old_deplibs " $arg" continue ;; *.la) # A libtool-controlled library. func_resolve_sysroot "$arg" if test "$prev" = dlfiles; then # This library was specified with -dlopen. func_append dlfiles " $func_resolve_sysroot_result" prev= elif test "$prev" = dlprefiles; then # The library was specified with -dlpreopen. func_append dlprefiles " $func_resolve_sysroot_result" prev= else func_append deplibs " $func_resolve_sysroot_result" fi continue ;; # Some other compiler argument. *) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; esac # arg # Now actually substitute the argument into the commands. if test -n "$arg"; then func_append compile_command " $arg" func_append finalize_command " $arg" fi done # argument parsing loop test -n "$prev" && \ func_fatal_help "the \`$prevarg' option requires an argument" if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then eval arg=\"$export_dynamic_flag_spec\" func_append compile_command " $arg" func_append finalize_command " $arg" fi oldlibs= # calculate the name of the file, without its directory func_basename "$output" outputname="$func_basename_result" libobjs_save="$libobjs" if test -n "$shlibpath_var"; then # get the directories listed in $shlibpath_var eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\` else shlib_search_path= fi eval sys_lib_search_path=\"$sys_lib_search_path_spec\" eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" func_dirname "$output" "/" "" output_objdir="$func_dirname_result$objdir" func_to_tool_file "$output_objdir/" tool_output_objdir=$func_to_tool_file_result # Create the object directory. func_mkdir_p "$output_objdir" # Determine the type of output case $output in "") func_fatal_help "you must specify an output file" ;; *.$libext) linkmode=oldlib ;; *.lo | *.$objext) linkmode=obj ;; *.la) linkmode=lib ;; *) linkmode=prog ;; # Anything else should be a program. esac specialdeplibs= libs= # Find all interdependent deplibs by searching for libraries # that are linked more than once (e.g. -la -lb -la) for deplib in $deplibs; do if $opt_preserve_dup_deps ; then case "$libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append libs " $deplib" done if test "$linkmode" = lib; then libs="$predeps $libs $compiler_lib_search_path $postdeps" # Compute libraries that are listed more than once in $predeps # $postdeps and mark them as special (i.e., whose duplicates are # not to be eliminated). pre_post_deps= if $opt_duplicate_compiler_generated_deps; then for pre_post_dep in $predeps $postdeps; do case "$pre_post_deps " in *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;; esac func_append pre_post_deps " $pre_post_dep" done fi pre_post_deps= fi deplibs= newdependency_libs= newlib_search_path= need_relink=no # whether we're linking any uninstalled libtool libraries notinst_deplibs= # not-installed libtool libraries notinst_path= # paths that contain not-installed libtool libraries case $linkmode in lib) passes="conv dlpreopen link" for file in $dlfiles $dlprefiles; do case $file in *.la) ;; *) func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file" ;; esac done ;; prog) compile_deplibs= finalize_deplibs= alldeplibs=no newdlfiles= newdlprefiles= passes="conv scan dlopen dlpreopen link" ;; *) passes="conv" ;; esac for pass in $passes; do # The preopen pass in lib mode reverses $deplibs; put it back here # so that -L comes before libs that need it for instance... if test "$linkmode,$pass" = "lib,link"; then ## FIXME: Find the place where the list is rebuilt in the wrong ## order, and fix it there properly tmp_deplibs= for deplib in $deplibs; do tmp_deplibs="$deplib $tmp_deplibs" done deplibs="$tmp_deplibs" fi if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan"; then libs="$deplibs" deplibs= fi if test "$linkmode" = prog; then case $pass in dlopen) libs="$dlfiles" ;; dlpreopen) libs="$dlprefiles" ;; link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; esac fi if test "$linkmode,$pass" = "lib,dlpreopen"; then # Collect and forward deplibs of preopened libtool libs for lib in $dlprefiles; do # Ignore non-libtool-libs dependency_libs= func_resolve_sysroot "$lib" case $lib in *.la) func_source "$func_resolve_sysroot_result" ;; esac # Collect preopened libtool deplibs, except any this library # has declared as weak libs for deplib in $dependency_libs; do func_basename "$deplib" deplib_base=$func_basename_result case " $weak_libs " in *" $deplib_base "*) ;; *) func_append deplibs " $deplib" ;; esac done done libs="$dlprefiles" fi if test "$pass" = dlopen; then # Collect dlpreopened libraries save_deplibs="$deplibs" deplibs= fi for deplib in $libs; do lib= found=no case $deplib in -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append compiler_flags " $deplib" if test "$linkmode" = lib ; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -l*) if test "$linkmode" != lib && test "$linkmode" != prog; then func_warning "\`-l' is ignored for archives/objects" continue fi func_stripname '-l' '' "$deplib" name=$func_stripname_result if test "$linkmode" = lib; then searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" else searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" fi for searchdir in $searchdirs; do for search_ext in .la $std_shrext .so .a; do # Search the libtool library lib="$searchdir/lib${name}${search_ext}" if test -f "$lib"; then if test "$search_ext" = ".la"; then found=yes else found=no fi break 2 fi done done if test "$found" != yes; then # deplib doesn't seem to be a libtool library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue else # deplib is a libtool library # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, # We need to do some special things here, and not later. if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $deplib "*) if func_lalib_p "$lib"; then library_names= old_library= func_source "$lib" for l in $old_library $library_names; do ll="$l" done if test "X$ll" = "X$old_library" ; then # only static version available found=no func_dirname "$lib" "" "." ladir="$func_dirname_result" lib=$ladir/$old_library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue fi fi ;; *) ;; esac fi fi ;; # -l *.ltframework) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" if test "$linkmode" = lib ; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -L*) case $linkmode in lib) deplibs="$deplib $deplibs" test "$pass" = conv && continue newdependency_libs="$deplib $newdependency_libs" func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; prog) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi if test "$pass" = scan; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; *) func_warning "\`-L' is ignored for archives/objects" ;; esac # linkmode continue ;; # -L -R*) if test "$pass" = link; then func_stripname '-R' '' "$deplib" func_resolve_sysroot "$func_stripname_result" dir=$func_resolve_sysroot_result # Make sure the xrpath contains only unique directories. case "$xrpath " in *" $dir "*) ;; *) func_append xrpath " $dir" ;; esac fi deplibs="$deplib $deplibs" continue ;; *.la) func_resolve_sysroot "$deplib" lib=$func_resolve_sysroot_result ;; *.$libext) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi case $linkmode in lib) # Linking convenience modules into shared libraries is allowed, # but linking other static libraries is non-portable. case " $dlpreconveniencelibs " in *" $deplib "*) ;; *) valid_a_lib=no case $deplibs_check_method in match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ | $EGREP "$match_pattern_regex" > /dev/null; then valid_a_lib=yes fi ;; pass_all) valid_a_lib=yes ;; esac if test "$valid_a_lib" != yes; then echo $ECHO "*** Warning: Trying to link with static lib archive $deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because the file extensions .$libext of this argument makes me believe" echo "*** that it is just a static archive that I should not use here." else echo $ECHO "*** Warning: Linking the shared library $output against the" $ECHO "*** static library $deplib is not portable!" deplibs="$deplib $deplibs" fi ;; esac continue ;; prog) if test "$pass" != link; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi continue ;; esac # linkmode ;; # *.$libext *.lo | *.$objext) if test "$pass" = conv; then deplibs="$deplib $deplibs" elif test "$linkmode" = prog; then if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlopen support or we're linking statically, # we need to preload. func_append newdlprefiles " $deplib" compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append newdlfiles " $deplib" fi fi continue ;; %DEPLIBS%) alldeplibs=yes continue ;; esac # case $deplib if test "$found" = yes || test -f "$lib"; then : else func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'" fi # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$lib" \ || func_fatal_error "\`$lib' is not a valid libtool archive" func_dirname "$lib" "" "." ladir="$func_dirname_result" dlname= dlopen= dlpreopen= libdir= library_names= old_library= inherited_linker_flags= # If the library was installed with an old release of libtool, # it will not redefine variables installed, or shouldnotlink installed=yes shouldnotlink=no avoidtemprpath= # Read the .la file func_source "$lib" # Convert "-framework foo" to "foo.ltframework" if test -n "$inherited_linker_flags"; then tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do case " $new_inherited_linker_flags " in *" $tmp_inherited_linker_flag "*) ;; *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";; esac done fi dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan" || { test "$linkmode" != prog && test "$linkmode" != lib; }; then test -n "$dlopen" && func_append dlfiles " $dlopen" test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" fi if test "$pass" = conv; then # Only check for convenience libraries deplibs="$lib $deplibs" if test -z "$libdir"; then if test -z "$old_library"; then func_fatal_error "cannot find name of link library for \`$lib'" fi # It is a libtool convenience library, so add in its objects. func_append convenience " $ladir/$objdir/$old_library" func_append old_convenience " $ladir/$objdir/$old_library" elif test "$linkmode" != prog && test "$linkmode" != lib; then func_fatal_error "\`$lib' is not a convenience library" fi tmp_libs= for deplib in $dependency_libs; do deplibs="$deplib $deplibs" if $opt_preserve_dup_deps ; then case "$tmp_libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append tmp_libs " $deplib" done continue fi # $pass = conv # Get the name of the library we link against. linklib= if test -n "$old_library" && { test "$prefer_static_libs" = yes || test "$prefer_static_libs,$installed" = "built,no"; }; then linklib=$old_library else for l in $old_library $library_names; do linklib="$l" done fi if test -z "$linklib"; then func_fatal_error "cannot find name of link library for \`$lib'" fi # This library was specified with -dlopen. if test "$pass" = dlopen; then if test -z "$libdir"; then func_fatal_error "cannot -dlopen a convenience library: \`$lib'" fi if test -z "$dlname" || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlname, no dlopen support or we're linking # statically, we need to preload. We also need to preload any # dependent libraries so libltdl's deplib preloader doesn't # bomb out in the load deplibs phase. func_append dlprefiles " $lib $dependency_libs" else func_append newdlfiles " $lib" fi continue fi # $pass = dlopen # We need an absolute path. case $ladir in [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; *) abs_ladir=`cd "$ladir" && pwd` if test -z "$abs_ladir"; then func_warning "cannot determine absolute directory name of \`$ladir'" func_warning "passing it literally to the linker, although it might fail" abs_ladir="$ladir" fi ;; esac func_basename "$lib" laname="$func_basename_result" # Find the relevant object directory and library name. if test "X$installed" = Xyes; then if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then func_warning "library \`$lib' was moved." dir="$ladir" absdir="$abs_ladir" libdir="$abs_ladir" else dir="$lt_sysroot$libdir" absdir="$lt_sysroot$libdir" fi test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes else if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then dir="$ladir" absdir="$abs_ladir" # Remove this search path later func_append notinst_path " $abs_ladir" else dir="$ladir/$objdir" absdir="$abs_ladir/$objdir" # Remove this search path later func_append notinst_path " $abs_ladir" fi fi # $installed = yes func_stripname 'lib' '.la' "$laname" name=$func_stripname_result # This library was specified with -dlpreopen. if test "$pass" = dlpreopen; then if test -z "$libdir" && test "$linkmode" = prog; then func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'" fi case "$host" in # special handling for platforms with PE-DLLs. *cygwin* | *mingw* | *cegcc* ) # Linker will automatically link against shared library if both # static and shared are present. Therefore, ensure we extract # symbols from the import library if a shared library is present # (otherwise, the dlopen module name will be incorrect). We do # this by putting the import library name into $newdlprefiles. # We recover the dlopen module name by 'saving' the la file # name in a special purpose variable, and (later) extracting the # dlname from the la file. if test -n "$dlname"; then func_tr_sh "$dir/$linklib" eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname" func_append newdlprefiles " $dir/$linklib" else func_append newdlprefiles " $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ func_append dlpreconveniencelibs " $dir/$old_library" fi ;; * ) # Prefer using a static library (so that no silly _DYNAMIC symbols # are required to link). if test -n "$old_library"; then func_append newdlprefiles " $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ func_append dlpreconveniencelibs " $dir/$old_library" # Otherwise, use the dlname, so that lt_dlopen finds it. elif test -n "$dlname"; then func_append newdlprefiles " $dir/$dlname" else func_append newdlprefiles " $dir/$linklib" fi ;; esac fi # $pass = dlpreopen if test -z "$libdir"; then # Link the convenience library if test "$linkmode" = lib; then deplibs="$dir/$old_library $deplibs" elif test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$dir/$old_library $compile_deplibs" finalize_deplibs="$dir/$old_library $finalize_deplibs" else deplibs="$lib $deplibs" # used for prog,scan pass fi continue fi if test "$linkmode" = prog && test "$pass" != link; then func_append newlib_search_path " $ladir" deplibs="$lib $deplibs" linkalldeplibs=no if test "$link_all_deplibs" != no || test -z "$library_names" || test "$build_libtool_libs" = no; then linkalldeplibs=yes fi tmp_libs= for deplib in $dependency_libs; do case $deplib in -L*) func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; esac # Need to link against all dependency_libs? if test "$linkalldeplibs" = yes; then deplibs="$deplib $deplibs" else # Need to hardcode shared library paths # or/and link against static libraries newdependency_libs="$deplib $newdependency_libs" fi if $opt_preserve_dup_deps ; then case "$tmp_libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append tmp_libs " $deplib" done # for deplib continue fi # $linkmode = prog... if test "$linkmode,$pass" = "prog,link"; then if test -n "$library_names" && { { test "$prefer_static_libs" = no || test "$prefer_static_libs,$installed" = "built,yes"; } || test -z "$old_library"; }; then # We need to hardcode the library path if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then # Make sure the rpath contains only unique directories. case "$temp_rpath:" in *"$absdir:"*) ;; *) func_append temp_rpath "$absdir:" ;; esac fi # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) func_append compile_rpath " $absdir" ;; esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac ;; esac fi # $linkmode,$pass = prog,link... if test "$alldeplibs" = yes && { test "$deplibs_check_method" = pass_all || { test "$build_libtool_libs" = yes && test -n "$library_names"; }; }; then # We only need to search for static libraries continue fi fi link_static=no # Whether the deplib will be linked statically use_static_libs=$prefer_static_libs if test "$use_static_libs" = built && test "$installed" = yes; then use_static_libs=no fi if test -n "$library_names" && { test "$use_static_libs" = no || test -z "$old_library"; }; then case $host in *cygwin* | *mingw* | *cegcc*) # No point in relinking DLLs because paths are not encoded func_append notinst_deplibs " $lib" need_relink=no ;; *) if test "$installed" = no; then func_append notinst_deplibs " $lib" need_relink=yes fi ;; esac # This is a shared library # Warn about portability, can't link against -module's on some # systems (darwin). Don't bleat about dlopened modules though! dlopenmodule="" for dlpremoduletest in $dlprefiles; do if test "X$dlpremoduletest" = "X$lib"; then dlopenmodule="$dlpremoduletest" break fi done if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then echo if test "$linkmode" = prog; then $ECHO "*** Warning: Linking the executable $output against the loadable module" else $ECHO "*** Warning: Linking the shared library $output against the loadable module" fi $ECHO "*** $linklib is not portable!" fi if test "$linkmode" = lib && test "$hardcode_into_libs" = yes; then # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) func_append compile_rpath " $absdir" ;; esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac ;; esac fi if test -n "$old_archive_from_expsyms_cmds"; then # figure out the soname set dummy $library_names shift realname="$1" shift libname=`eval "\\$ECHO \"$libname_spec\""` # use dlname if we got it. it's perfectly good, no? if test -n "$dlname"; then soname="$dlname" elif test -n "$soname_spec"; then # bleh windows case $host in *cygwin* | mingw* | *cegcc*) func_arith $current - $age major=$func_arith_result versuffix="-$major" ;; esac eval soname=\"$soname_spec\" else soname="$realname" fi # Make a new name for the extract_expsyms_cmds to use soroot="$soname" func_basename "$soroot" soname="$func_basename_result" func_stripname 'lib' '.dll' "$soname" newlib=libimp-$func_stripname_result.a # If the library has no export list, then create one now if test -f "$output_objdir/$soname-def"; then : else func_verbose "extracting exported symbol list from \`$soname'" func_execute_cmds "$extract_expsyms_cmds" 'exit $?' fi # Create $newlib if test -f "$output_objdir/$newlib"; then :; else func_verbose "generating import library for \`$soname'" func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' fi # make sure the library variables are pointing to the new library dir=$output_objdir linklib=$newlib fi # test -n "$old_archive_from_expsyms_cmds" if test "$linkmode" = prog || test "$opt_mode" != relink; then add_shlibpath= add_dir= add= lib_linked=yes case $hardcode_action in immediate | unsupported) if test "$hardcode_direct" = no; then add="$dir/$linklib" case $host in *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; *-*-sysv4*uw2*) add_dir="-L$dir" ;; *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ *-*-unixware7*) add_dir="-L$dir" ;; *-*-darwin* ) # if the lib is a (non-dlopened) module then we can not # link against it, someone is ignoring the earlier warnings if /usr/bin/file -L $add 2> /dev/null | $GREP ": [^:]* bundle" >/dev/null ; then if test "X$dlopenmodule" != "X$lib"; then $ECHO "*** Warning: lib $linklib is a module, not a shared library" if test -z "$old_library" ; then echo echo "*** And there doesn't seem to be a static archive available" echo "*** The link will probably fail, sorry" else add="$dir/$old_library" fi elif test -n "$old_library"; then add="$dir/$old_library" fi fi esac elif test "$hardcode_minus_L" = no; then case $host in *-*-sunos*) add_shlibpath="$dir" ;; esac add_dir="-L$dir" add="-l$name" elif test "$hardcode_shlibpath_var" = no; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; relink) if test "$hardcode_direct" = yes && test "$hardcode_direct_absolute" = no; then add="$dir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$absdir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; *) lib_linked=no ;; esac if test "$lib_linked" != yes; then func_fatal_configuration "unsupported hardcode properties" fi if test -n "$add_shlibpath"; then case :$compile_shlibpath: in *":$add_shlibpath:"*) ;; *) func_append compile_shlibpath "$add_shlibpath:" ;; esac fi if test "$linkmode" = prog; then test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" test -n "$add" && compile_deplibs="$add $compile_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" if test "$hardcode_direct" != yes && test "$hardcode_minus_L" != yes && test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac fi fi fi if test "$linkmode" = prog || test "$opt_mode" = relink; then add_shlibpath= add_dir= add= # Finalize command for both is simple: just hardcode it. if test "$hardcode_direct" = yes && test "$hardcode_direct_absolute" = no; then add="$libdir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$libdir" add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac add="-l$name" elif test "$hardcode_automatic" = yes; then if test -n "$inst_prefix_dir" && test -f "$inst_prefix_dir$libdir/$linklib" ; then add="$inst_prefix_dir$libdir/$linklib" else add="$libdir/$linklib" fi else # We cannot seem to hardcode it, guess we'll fake it. add_dir="-L$libdir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi add="-l$name" fi if test "$linkmode" = prog; then test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" test -n "$add" && finalize_deplibs="$add $finalize_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" fi fi elif test "$linkmode" = prog; then # Here we assume that one of hardcode_direct or hardcode_minus_L # is not unsupported. This is valid on all known static and # shared platforms. if test "$hardcode_direct" != unsupported; then test -n "$old_library" && linklib="$old_library" compile_deplibs="$dir/$linklib $compile_deplibs" finalize_deplibs="$dir/$linklib $finalize_deplibs" else compile_deplibs="-l$name -L$dir $compile_deplibs" finalize_deplibs="-l$name -L$dir $finalize_deplibs" fi elif test "$build_libtool_libs" = yes; then # Not a shared library if test "$deplibs_check_method" != pass_all; then # We're trying link a shared library against a static one # but the system doesn't support it. # Just print a warning and add the library to dependency_libs so # that the program can be linked against the static library. echo $ECHO "*** Warning: This system can not link to static lib archive $lib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have." if test "$module" = yes; then echo "*** But as you try to build a module library, libtool will still create " echo "*** a static module, that should work as long as the dlopening application" echo "*** is linked with the -dlopen flag to resolve symbols at runtime." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using \`nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi else deplibs="$dir/$old_library $deplibs" link_static=yes fi fi # link shared/static library? if test "$linkmode" = lib; then if test -n "$dependency_libs" && { test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes || test "$link_static" = yes; }; then # Extract -R from dependency_libs temp_deplibs= for libdir in $dependency_libs; do case $libdir in -R*) func_stripname '-R' '' "$libdir" temp_xrpath=$func_stripname_result case " $xrpath " in *" $temp_xrpath "*) ;; *) func_append xrpath " $temp_xrpath";; esac;; *) func_append temp_deplibs " $libdir";; esac done dependency_libs="$temp_deplibs" fi func_append newlib_search_path " $absdir" # Link against this library test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" # ... and its dependency_libs tmp_libs= for deplib in $dependency_libs; do newdependency_libs="$deplib $newdependency_libs" case $deplib in -L*) func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result";; *) func_resolve_sysroot "$deplib" ;; esac if $opt_preserve_dup_deps ; then case "$tmp_libs " in *" $func_resolve_sysroot_result "*) func_append specialdeplibs " $func_resolve_sysroot_result" ;; esac fi func_append tmp_libs " $func_resolve_sysroot_result" done if test "$link_all_deplibs" != no; then # Add the search paths of all dependency libraries for deplib in $dependency_libs; do path= case $deplib in -L*) path="$deplib" ;; *.la) func_resolve_sysroot "$deplib" deplib=$func_resolve_sysroot_result func_dirname "$deplib" "" "." dir=$func_dirname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; *) absdir=`cd "$dir" && pwd` if test -z "$absdir"; then func_warning "cannot determine absolute directory name of \`$dir'" absdir="$dir" fi ;; esac if $GREP "^installed=no" $deplib > /dev/null; then case $host in *-*-darwin*) depdepl= eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` if test -n "$deplibrary_names" ; then for tmp in $deplibrary_names ; do depdepl=$tmp done if test -f "$absdir/$objdir/$depdepl" ; then depdepl="$absdir/$objdir/$depdepl" darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` if test -z "$darwin_install_name"; then darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` fi func_append compiler_flags " ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" func_append linker_flags " -dylib_file ${darwin_install_name}:${depdepl}" path= fi fi ;; *) path="-L$absdir/$objdir" ;; esac else eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` test -z "$libdir" && \ func_fatal_error "\`$deplib' is not a valid libtool archive" test "$absdir" != "$libdir" && \ func_warning "\`$deplib' seems to be moved" path="-L$absdir" fi ;; esac case " $deplibs " in *" $path "*) ;; *) deplibs="$path $deplibs" ;; esac done fi # link_all_deplibs != no fi # linkmode = lib done # for deplib in $libs if test "$pass" = link; then if test "$linkmode" = "prog"; then compile_deplibs="$new_inherited_linker_flags $compile_deplibs" finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" else compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` fi fi dependency_libs="$newdependency_libs" if test "$pass" = dlpreopen; then # Link the dlpreopened libraries before other libraries for deplib in $save_deplibs; do deplibs="$deplib $deplibs" done fi if test "$pass" != dlopen; then if test "$pass" != conv; then # Make sure lib_search_path contains only unique directories. lib_search_path= for dir in $newlib_search_path; do case "$lib_search_path " in *" $dir "*) ;; *) func_append lib_search_path " $dir" ;; esac done newlib_search_path= fi if test "$linkmode,$pass" != "prog,link"; then vars="deplibs" else vars="compile_deplibs finalize_deplibs" fi for var in $vars dependency_libs; do # Add libraries to $var in reverse order eval tmp_libs=\"\$$var\" new_libs= for deplib in $tmp_libs; do # FIXME: Pedantically, this is the right thing to do, so # that some nasty dependency loop isn't accidentally # broken: #new_libs="$deplib $new_libs" # Pragmatically, this seems to cause very few problems in # practice: case $deplib in -L*) new_libs="$deplib $new_libs" ;; -R*) ;; *) # And here is the reason: when a library appears more # than once as an explicit dependence of a library, or # is implicitly linked in more than once by the # compiler, it is considered special, and multiple # occurrences thereof are not removed. Compare this # with having the same library being listed as a # dependency of multiple other libraries: in this case, # we know (pedantically, we assume) the library does not # need to be listed more than once, so we keep only the # last copy. This is not always right, but it is rare # enough that we require users that really mean to play # such unportable linking tricks to link the library # using -Wl,-lname, so that libtool does not consider it # for duplicate removal. case " $specialdeplibs " in *" $deplib "*) new_libs="$deplib $new_libs" ;; *) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$deplib $new_libs" ;; esac ;; esac ;; esac done tmp_libs= for deplib in $new_libs; do case $deplib in -L*) case " $tmp_libs " in *" $deplib "*) ;; *) func_append tmp_libs " $deplib" ;; esac ;; *) func_append tmp_libs " $deplib" ;; esac done eval $var=\"$tmp_libs\" done # for var fi # Last step: remove runtime libs from dependency_libs # (they stay in deplibs) tmp_libs= for i in $dependency_libs ; do case " $predeps $postdeps $compiler_lib_search_path " in *" $i "*) i="" ;; esac if test -n "$i" ; then func_append tmp_libs " $i" fi done dependency_libs=$tmp_libs done # for pass if test "$linkmode" = prog; then dlfiles="$newdlfiles" fi if test "$linkmode" = prog || test "$linkmode" = lib; then dlprefiles="$newdlprefiles" fi case $linkmode in oldlib) if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then func_warning "\`-dlopen' is ignored for archives" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "\`-l' and \`-L' are ignored for archives" ;; esac test -n "$rpath" && \ func_warning "\`-rpath' is ignored for archives" test -n "$xrpath" && \ func_warning "\`-R' is ignored for archives" test -n "$vinfo" && \ func_warning "\`-version-info/-version-number' is ignored for archives" test -n "$release" && \ func_warning "\`-release' is ignored for archives" test -n "$export_symbols$export_symbols_regex" && \ func_warning "\`-export-symbols' is ignored for archives" # Now set the variables for building old libraries. build_libtool_libs=no oldlibs="$output" func_append objs "$old_deplibs" ;; lib) # Make sure we only generate libraries of the form `libNAME.la'. case $outputname in lib*) func_stripname 'lib' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" ;; *) test "$module" = no && \ func_fatal_help "libtool library \`$output' must begin with \`lib'" if test "$need_lib_prefix" != no; then # Add the "lib" prefix for modules if required func_stripname '' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" else func_stripname '' '.la' "$outputname" libname=$func_stripname_result fi ;; esac if test -n "$objs"; then if test "$deplibs_check_method" != pass_all; then func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs" else echo $ECHO "*** Warning: Linking the shared library $output against the non-libtool" $ECHO "*** objects $objs is not portable!" func_append libobjs " $objs" fi fi test "$dlself" != no && \ func_warning "\`-dlopen self' is ignored for libtool libraries" set dummy $rpath shift test "$#" -gt 1 && \ func_warning "ignoring multiple \`-rpath's for a libtool library" install_libdir="$1" oldlibs= if test -z "$rpath"; then if test "$build_libtool_libs" = yes; then # Building a libtool convenience library. # Some compilers have problems with a `.al' extension so # convenience libraries should have the same extension an # archive normally would. oldlibs="$output_objdir/$libname.$libext $oldlibs" build_libtool_libs=convenience build_old_libs=yes fi test -n "$vinfo" && \ func_warning "\`-version-info/-version-number' is ignored for convenience libraries" test -n "$release" && \ func_warning "\`-release' is ignored for convenience libraries" else # Parse the version information argument. save_ifs="$IFS"; IFS=':' set dummy $vinfo 0 0 0 shift IFS="$save_ifs" test -n "$7" && \ func_fatal_help "too many parameters to \`-version-info'" # convert absolute version numbers to libtool ages # this retains compatibility with .la files and attempts # to make the code below a bit more comprehensible case $vinfo_number in yes) number_major="$1" number_minor="$2" number_revision="$3" # # There are really only two kinds -- those that # use the current revision as the major version # and those that subtract age and use age as # a minor version. But, then there is irix # which has an extra 1 added just for fun # case $version_type in # correct linux to gnu/linux during the next big refactor darwin|linux|osf|windows|none) func_arith $number_major + $number_minor current=$func_arith_result age="$number_minor" revision="$number_revision" ;; freebsd-aout|freebsd-elf|qnx|sunos) current="$number_major" revision="$number_minor" age="0" ;; irix|nonstopux) func_arith $number_major + $number_minor current=$func_arith_result age="$number_minor" revision="$number_minor" lt_irix_increment=no ;; esac ;; no) current="$1" revision="$2" age="$3" ;; esac # Check that each of the things are valid numbers. case $current in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "CURRENT \`$current' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac case $revision in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "REVISION \`$revision' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac case $age in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "AGE \`$age' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac if test "$age" -gt "$current"; then func_error "AGE \`$age' is greater than the current interface number \`$current'" func_fatal_error "\`$vinfo' is not valid version information" fi # Calculate the version variables. major= versuffix= verstring= case $version_type in none) ;; darwin) # Like Linux, but with the current version available in # verstring for coding it into the library header func_arith $current - $age major=.$func_arith_result versuffix="$major.$age.$revision" # Darwin ld doesn't like 0 for these options... func_arith $current + 1 minor_current=$func_arith_result xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" ;; freebsd-aout) major=".$current" versuffix=".$current.$revision"; ;; freebsd-elf) major=".$current" versuffix=".$current" ;; irix | nonstopux) if test "X$lt_irix_increment" = "Xno"; then func_arith $current - $age else func_arith $current - $age + 1 fi major=$func_arith_result case $version_type in nonstopux) verstring_prefix=nonstopux ;; *) verstring_prefix=sgi ;; esac verstring="$verstring_prefix$major.$revision" # Add in all the interfaces that we are compatible with. loop=$revision while test "$loop" -ne 0; do func_arith $revision - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring="$verstring_prefix$major.$iface:$verstring" done # Before this point, $major must not contain `.'. major=.$major versuffix="$major.$revision" ;; linux) # correct to gnu/linux during the next big refactor func_arith $current - $age major=.$func_arith_result versuffix="$major.$age.$revision" ;; osf) func_arith $current - $age major=.$func_arith_result versuffix=".$current.$age.$revision" verstring="$current.$age.$revision" # Add in all the interfaces that we are compatible with. loop=$age while test "$loop" -ne 0; do func_arith $current - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring="$verstring:${iface}.0" done # Make executables depend on our current version. func_append verstring ":${current}.0" ;; qnx) major=".$current" versuffix=".$current" ;; sunos) major=".$current" versuffix=".$current.$revision" ;; windows) # Use '-' rather than '.', since we only want one # extension on DOS 8.3 filesystems. func_arith $current - $age major=$func_arith_result versuffix="-$major" ;; *) func_fatal_configuration "unknown library version type \`$version_type'" ;; esac # Clear the version info if we defaulted, and they specified a release. if test -z "$vinfo" && test -n "$release"; then major= case $version_type in darwin) # we can't check for "0.0" in archive_cmds due to quoting # problems, so we reset it completely verstring= ;; *) verstring="0.0" ;; esac if test "$need_version" = no; then versuffix= else versuffix=".0.0" fi fi # Remove version info from name if versioning should be avoided if test "$avoid_version" = yes && test "$need_version" = no; then major= versuffix= verstring="" fi # Check to see if the archive will have undefined symbols. if test "$allow_undefined" = yes; then if test "$allow_undefined_flag" = unsupported; then func_warning "undefined symbols not allowed in $host shared libraries" build_libtool_libs=no build_old_libs=yes fi else # Don't allow undefined symbols. allow_undefined_flag="$no_undefined_flag" fi fi func_generate_dlsyms "$libname" "$libname" "yes" func_append libobjs " $symfileobj" test "X$libobjs" = "X " && libobjs= if test "$opt_mode" != relink; then # Remove our outputs, but don't remove object files since they # may have been created when compiling PIC objects. removelist= tempremovelist=`$ECHO "$output_objdir/*"` for p in $tempremovelist; do case $p in *.$objext | *.gcno) ;; $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) if test "X$precious_files_regex" != "X"; then if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 then continue fi fi func_append removelist " $p" ;; *) ;; esac done test -n "$removelist" && \ func_show_eval "${RM}r \$removelist" fi # Now set the variables for building old libraries. if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then func_append oldlibs " $output_objdir/$libname.$libext" # Transform .lo files to .o files. oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP` fi # Eliminate all temporary directories. #for path in $notinst_path; do # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"` #done if test -n "$xrpath"; then # If the user specified any rpath flags, then add them. temp_xrpath= for libdir in $xrpath; do func_replace_sysroot "$libdir" func_append temp_xrpath " -R$func_replace_sysroot_result" case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac done if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then dependency_libs="$temp_xrpath $dependency_libs" fi fi # Make sure dlfiles contains only unique files that won't be dlpreopened old_dlfiles="$dlfiles" dlfiles= for lib in $old_dlfiles; do case " $dlprefiles $dlfiles " in *" $lib "*) ;; *) func_append dlfiles " $lib" ;; esac done # Make sure dlprefiles contains only unique files old_dlprefiles="$dlprefiles" dlprefiles= for lib in $old_dlprefiles; do case "$dlprefiles " in *" $lib "*) ;; *) func_append dlprefiles " $lib" ;; esac done if test "$build_libtool_libs" = yes; then if test -n "$rpath"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) # these systems don't actually have a c library (as such)! ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C library is in the System framework func_append deplibs " System.ltframework" ;; *-*-netbsd*) # Don't link with libc until the a.out ld.so is fixed. ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work ;; *) # Add libc to deplibs on all other systems if necessary. if test "$build_libtool_need_lc" = "yes"; then func_append deplibs " -lc" fi ;; esac fi # Transform deplibs into only deplibs that can be linked in shared. name_save=$name libname_save=$libname release_save=$release versuffix_save=$versuffix major_save=$major # I'm not sure if I'm treating the release correctly. I think # release should show up in the -l (ie -lgmp5) so we don't want to # add it in twice. Is that correct? release="" versuffix="" major="" newdeplibs= droppeddeps=no case $deplibs_check_method in pass_all) # Don't check for shared/static. Everything works. # This might be a little naive. We might want to check # whether the library exists or not. But this is on # osf3 & osf4 and I'm not really sure... Just # implementing what was already the behavior. newdeplibs=$deplibs ;; test_compile) # This code stresses the "libraries are programs" paradigm to its # limits. Maybe even breaks it. We compile a program, linking it # against the deplibs as a proxy for the library. Then we can check # whether they linked in statically or dynamically with ldd. $opt_dry_run || $RM conftest.c cat > conftest.c </dev/null` $nocaseglob else potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` fi for potent_lib in $potential_libs; do # Follow soft links. if ls -lLd "$potent_lib" 2>/dev/null | $GREP " -> " >/dev/null; then continue fi # The statement above tries to avoid entering an # endless loop below, in case of cyclic links. # We might still enter an endless loop, since a link # loop can be closed while we follow links, # but so what? potlib="$potent_lib" while test -h "$potlib" 2>/dev/null; do potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` case $potliblink in [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; *) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";; esac done if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | $SED -e 10q | $EGREP "$file_magic_regex" > /dev/null; then func_append newdeplibs " $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $ECHO "*** with $libname but no candidates were found. (...for file magic test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a file magic. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` for a_deplib in $deplibs; do case $a_deplib in -l*) func_stripname -l '' "$a_deplib" name=$func_stripname_result if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $a_deplib "*) func_append newdeplibs " $a_deplib" a_deplib="" ;; esac fi if test -n "$a_deplib" ; then libname=`eval "\\$ECHO \"$libname_spec\""` for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do potential_libs=`ls $i/$libname[.-]* 2>/dev/null` for potent_lib in $potential_libs; do potlib="$potent_lib" # see symlink-check above in file_magic test if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \ $EGREP "$match_pattern_regex" > /dev/null; then func_append newdeplibs " $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a regex pattern. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; none | unknown | *) newdeplibs="" tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then for i in $predeps $postdeps ; do # can't use Xsed below, because $i might contain '/' tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"` done fi case $tmp_deplibs in *[!\ \ ]*) echo if test "X$deplibs_check_method" = "Xnone"; then echo "*** Warning: inter-library dependencies are not supported in this platform." else echo "*** Warning: inter-library dependencies are not known to be supported." fi echo "*** All declared inter-library dependencies are being dropped." droppeddeps=yes ;; esac ;; esac versuffix=$versuffix_save major=$major_save release=$release_save libname=$libname_save name=$name_save case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library with the System framework newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac if test "$droppeddeps" = yes; then if test "$module" = yes; then echo echo "*** Warning: libtool could not satisfy all declared inter-library" $ECHO "*** dependencies of module $libname. Therefore, libtool will create" echo "*** a static module, that should work as long as the dlopening" echo "*** application is linked with the -dlopen flag." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using \`nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi else echo "*** The inter-library dependencies that have been dropped here will be" echo "*** automatically added whenever a program is linked with this library" echo "*** or is declared to -dlopen it." if test "$allow_undefined" = no; then echo echo "*** Since this library must not contain undefined symbols," echo "*** because either the platform does not support them or" echo "*** it was explicitly requested with -no-undefined," echo "*** libtool will only create a static version of it." if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi fi fi # Done checking deplibs! deplibs=$newdeplibs fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" case $host in *-*-darwin*) newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $deplibs " in *" -L$path/$objdir "*) func_append new_libs " -L$path/$objdir" ;; esac ;; esac done for deplib in $deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) func_append new_libs " $deplib" ;; esac ;; *) func_append new_libs " $deplib" ;; esac done deplibs="$new_libs" # All the library-specific variables (install_libdir is set above). library_names= old_library= dlname= # Test again, we may have decided not to build it any more if test "$build_libtool_libs" = yes; then # Remove ${wl} instances when linking with ld. # FIXME: should test the right _cmds variable. case $archive_cmds in *\$LD\ *) wl= ;; esac if test "$hardcode_into_libs" = yes; then # Hardcode the library paths hardcode_libdirs= dep_rpath= rpath="$finalize_rpath" test "$opt_mode" != relink && rpath="$compile_rpath$rpath" for libdir in $rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then func_replace_sysroot "$libdir" libdir=$func_replace_sysroot_result if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append dep_rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) func_append perm_rpath " $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval "dep_rpath=\"$hardcode_libdir_flag_spec\"" fi if test -n "$runpath_var" && test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do func_append rpath "$dir:" done eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" fi test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" fi shlibpath="$finalize_shlibpath" test "$opt_mode" != relink && shlibpath="$compile_shlibpath$shlibpath" if test -n "$shlibpath"; then eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" fi # Get the real and link names of the library. eval shared_ext=\"$shrext_cmds\" eval library_names=\"$library_names_spec\" set dummy $library_names shift realname="$1" shift if test -n "$soname_spec"; then eval soname=\"$soname_spec\" else soname="$realname" fi if test -z "$dlname"; then dlname=$soname fi lib="$output_objdir/$realname" linknames= for link do func_append linknames " $link" done # Use standard objects if they are pic test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` test "X$libobjs" = "X " && libobjs= delfiles= if test -n "$export_symbols" && test -n "$include_expsyms"; then $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" export_symbols="$output_objdir/$libname.uexp" func_append delfiles " $export_symbols" fi orig_export_symbols= case $host_os in cygwin* | mingw* | cegcc*) if test -n "$export_symbols" && test -z "$export_symbols_regex"; then # exporting using user supplied symfile if test "x`$SED 1q $export_symbols`" != xEXPORTS; then # and it's NOT already a .def file. Must figure out # which of the given symbols are data symbols and tag # them as such. So, trigger use of export_symbols_cmds. # export_symbols gets reassigned inside the "prepare # the list of exported symbols" if statement, so the # include_expsyms logic still works. orig_export_symbols="$export_symbols" export_symbols= always_export_symbols=yes fi fi ;; esac # Prepare the list of exported symbols if test -z "$export_symbols"; then if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then func_verbose "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $opt_dry_run || $RM $export_symbols cmds=$export_symbols_cmds save_ifs="$IFS"; IFS='~' for cmd1 in $cmds; do IFS="$save_ifs" # Take the normal branch if the nm_file_list_spec branch # doesn't work or if tool conversion is not needed. case $nm_file_list_spec~$to_tool_file_cmd in *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*) try_normal_branch=yes eval cmd=\"$cmd1\" func_len " $cmd" len=$func_len_result ;; *) try_normal_branch=no ;; esac if test "$try_normal_branch" = yes \ && { test "$len" -lt "$max_cmd_len" \ || test "$max_cmd_len" -le -1; } then func_show_eval "$cmd" 'exit $?' skipped_export=false elif test -n "$nm_file_list_spec"; then func_basename "$output" output_la=$func_basename_result save_libobjs=$libobjs save_output=$output output=${output_objdir}/${output_la}.nm func_to_tool_file "$output" libobjs=$nm_file_list_spec$func_to_tool_file_result func_append delfiles " $output" func_verbose "creating $NM input file list: $output" for obj in $save_libobjs; do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" done > "$output" eval cmd=\"$cmd1\" func_show_eval "$cmd" 'exit $?' output=$save_output libobjs=$save_libobjs skipped_export=false else # The command line is too long to execute in one step. func_verbose "using reloadable object file for export list..." skipped_export=: # Break out early, otherwise skipped_export may be # set to false by a later but shorter cmd. break fi done IFS="$save_ifs" if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi fi if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols="$export_symbols" test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi tmp_deplibs= for test_deplib in $deplibs; do case " $convenience " in *" $test_deplib "*) ;; *) func_append tmp_deplibs " $test_deplib" ;; esac done deplibs="$tmp_deplibs" if test -n "$convenience"; then if test -n "$whole_archive_flag_spec" && test "$compiler_needs_object" = yes && test -z "$libobjs"; then # extract the archives, so we have objects to list. # TODO: could optimize this to just extract one archive. whole_archive_flag_spec= fi if test -n "$whole_archive_flag_spec"; then save_libobjs=$libobjs eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= else gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $convenience func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi fi if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then eval flag=\"$thread_safe_flag_spec\" func_append linker_flags " $flag" fi # Make a backup of the uninstalled library when relinking if test "$opt_mode" = relink; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? fi # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then eval test_cmds=\"$module_expsym_cmds\" cmds=$module_expsym_cmds else eval test_cmds=\"$module_cmds\" cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then eval test_cmds=\"$archive_expsym_cmds\" cmds=$archive_expsym_cmds else eval test_cmds=\"$archive_cmds\" cmds=$archive_cmds fi fi if test "X$skipped_export" != "X:" && func_len " $test_cmds" && len=$func_len_result && test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then : else # The command line is too long to link in one step, link piecewise # or, if using GNU ld and skipped_export is not :, use a linker # script. # Save the value of $output and $libobjs because we want to # use them later. If we have whole_archive_flag_spec, we # want to use save_libobjs as it was before # whole_archive_flag_spec was expanded, because we can't # assume the linker understands whole_archive_flag_spec. # This may have to be revisited, in case too many # convenience libraries get linked in and end up exceeding # the spec. if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then save_libobjs=$libobjs fi save_output=$output func_basename "$output" output_la=$func_basename_result # Clear the reloadable object creation command queue and # initialize k to one. test_cmds= concat_cmds= objlist= last_robj= k=1 if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then output=${output_objdir}/${output_la}.lnkscript func_verbose "creating GNU ld script: $output" echo 'INPUT (' > $output for obj in $save_libobjs do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" >> $output done echo ')' >> $output func_append delfiles " $output" func_to_tool_file "$output" output=$func_to_tool_file_result elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then output=${output_objdir}/${output_la}.lnk func_verbose "creating linker input file list: $output" : > $output set x $save_libobjs shift firstobj= if test "$compiler_needs_object" = yes; then firstobj="$1 " shift fi for obj do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" >> $output done func_append delfiles " $output" func_to_tool_file "$output" output=$firstobj\"$file_list_spec$func_to_tool_file_result\" else if test -n "$save_libobjs"; then func_verbose "creating reloadable object files..." output=$output_objdir/$output_la-${k}.$objext eval test_cmds=\"$reload_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 # Loop over the list of objects to be linked. for obj in $save_libobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result if test "X$objlist" = X || test "$len" -lt "$max_cmd_len"; then func_append objlist " $obj" else # The command $test_cmds is almost too long, add a # command to the queue. if test "$k" -eq 1 ; then # The first file doesn't have a previous command to add. reload_objs=$objlist eval concat_cmds=\"$reload_cmds\" else # All subsequent reloadable object files will link in # the last one created. reload_objs="$objlist $last_robj" eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\" fi last_robj=$output_objdir/$output_la-${k}.$objext func_arith $k + 1 k=$func_arith_result output=$output_objdir/$output_la-${k}.$objext objlist=" $obj" func_len " $last_robj" func_arith $len0 + $func_len_result len=$func_arith_result fi done # Handle the remaining objects by creating one last # reloadable object file. All subsequent reloadable object # files will link in the last one created. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ reload_objs="$objlist $last_robj" eval concat_cmds=\"\${concat_cmds}$reload_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\" fi func_append delfiles " $output" else output= fi if ${skipped_export-false}; then func_verbose "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $opt_dry_run || $RM $export_symbols libobjs=$output # Append the command to create the export file. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" fi fi test -n "$save_libobjs" && func_verbose "creating a temporary reloadable object file: $output" # Loop through the commands generated above and execute them. save_ifs="$IFS"; IFS='~' for cmd in $concat_cmds; do IFS="$save_ifs" $opt_silent || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test "$opt_mode" = relink; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS="$save_ifs" if test -n "$export_symbols_regex" && ${skipped_export-false}; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi if ${skipped_export-false}; then if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols="$export_symbols" test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi fi libobjs=$output # Restore the value of output. output=$save_output if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= fi # Expand the library linking commands again to reset the # value of $libobjs for piecewise linking. # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then cmds=$module_expsym_cmds else cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then cmds=$archive_expsym_cmds else cmds=$archive_cmds fi fi fi if test -n "$delfiles"; then # Append the command to remove temporary files to $cmds. eval cmds=\"\$cmds~\$RM $delfiles\" fi # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $dlprefiles func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" $opt_silent || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test "$opt_mode" = relink; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS="$save_ifs" # Restore the uninstalled library and exit if test "$opt_mode" = relink; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? if test -n "$convenience"; then if test -z "$whole_archive_flag_spec"; then func_show_eval '${RM}r "$gentop"' fi fi exit $EXIT_SUCCESS fi # Create links to the real library. for linkname in $linknames; do if test "$realname" != "$linkname"; then func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' fi done # If -module or -export-dynamic was specified, set the dlname. if test "$module" = yes || test "$export_dynamic" = yes; then # On all known operating systems, these are identical. dlname="$soname" fi fi ;; obj) if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then func_warning "\`-dlopen' is ignored for objects" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "\`-l' and \`-L' are ignored for objects" ;; esac test -n "$rpath" && \ func_warning "\`-rpath' is ignored for objects" test -n "$xrpath" && \ func_warning "\`-R' is ignored for objects" test -n "$vinfo" && \ func_warning "\`-version-info' is ignored for objects" test -n "$release" && \ func_warning "\`-release' is ignored for objects" case $output in *.lo) test -n "$objs$old_deplibs" && \ func_fatal_error "cannot build library object \`$output' from non-libtool objects" libobj=$output func_lo2o "$libobj" obj=$func_lo2o_result ;; *) libobj= obj="$output" ;; esac # Delete the old objects. $opt_dry_run || $RM $obj $libobj # Objects from convenience libraries. This assumes # single-version convenience libraries. Whenever we create # different ones for PIC/non-PIC, this we'll have to duplicate # the extraction. reload_conv_objs= gentop= # reload_cmds runs $LD directly, so let us get rid of # -Wl from whole_archive_flag_spec and hope we can get by with # turning comma into space.. wl= if test -n "$convenience"; then if test -n "$whole_archive_flag_spec"; then eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` else gentop="$output_objdir/${obj}x" func_append generated " $gentop" func_extract_archives $gentop $convenience reload_conv_objs="$reload_objs $func_extract_archives_result" fi fi # If we're not building shared, we need to use non_pic_objs test "$build_libtool_libs" != yes && libobjs="$non_pic_objects" # Create the old-style object. reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test output="$obj" func_execute_cmds "$reload_cmds" 'exit $?' # Exit if we aren't doing a library object file. if test -z "$libobj"; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS fi if test "$build_libtool_libs" != yes; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi # Create an invalid libtool object if no PIC, so that we don't # accidentally link it into a program. # $show "echo timestamp > $libobj" # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? exit $EXIT_SUCCESS fi if test -n "$pic_flag" || test "$pic_mode" != default; then # Only do commands if we really have different PIC objects. reload_objs="$libobjs $reload_conv_objs" output="$libobj" func_execute_cmds "$reload_cmds" 'exit $?' fi if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS ;; prog) case $host in *cygwin*) func_stripname '' '.exe' "$output" output=$func_stripname_result.exe;; esac test -n "$vinfo" && \ func_warning "\`-version-info' is ignored for programs" test -n "$release" && \ func_warning "\`-release' is ignored for programs" test "$preload" = yes \ && test "$dlopen_support" = unknown \ && test "$dlopen_self" = unknown \ && test "$dlopen_self_static" = unknown && \ func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support." case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library is the System framework compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac case $host in *-*-darwin*) # Don't allow lazy linking, it breaks C++ global constructors # But is supposedly fixed on 10.4 or later (yay!). if test "$tagname" = CXX ; then case ${MACOSX_DEPLOYMENT_TARGET-10.0} in 10.[0123]) func_append compile_command " ${wl}-bind_at_load" func_append finalize_command " ${wl}-bind_at_load" ;; esac fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $compile_deplibs " in *" -L$path/$objdir "*) func_append new_libs " -L$path/$objdir" ;; esac ;; esac done for deplib in $compile_deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) func_append new_libs " $deplib" ;; esac ;; *) func_append new_libs " $deplib" ;; esac done compile_deplibs="$new_libs" func_append compile_command " $compile_deplibs" func_append finalize_command " $finalize_deplibs" if test -n "$rpath$xrpath"; then # If the user specified any rpath flags, then add them. for libdir in $rpath $xrpath; do # This is the magic to use -rpath. case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac done fi # Now hardcode the library paths rpath= hardcode_libdirs= for libdir in $compile_rpath $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) func_append perm_rpath " $libdir" ;; esac fi case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` case :$dllsearchpath: in *":$libdir:"*) ;; ::) dllsearchpath=$libdir;; *) func_append dllsearchpath ":$libdir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) func_append dllsearchpath ":$testbindir";; esac ;; esac done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi compile_rpath="$rpath" rpath= hardcode_libdirs= for libdir in $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$finalize_perm_rpath " in *" $libdir "*) ;; *) func_append finalize_perm_rpath " $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi finalize_rpath="$rpath" if test -n "$libobjs" && test "$build_old_libs" = yes; then # Transform all the library objects into standard objects. compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` fi func_generate_dlsyms "$outputname" "@PROGRAM@" "no" # template prelinking step if test -n "$prelink_cmds"; then func_execute_cmds "$prelink_cmds" 'exit $?' fi wrappers_required=yes case $host in *cegcc* | *mingw32ce*) # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. wrappers_required=no ;; *cygwin* | *mingw* ) if test "$build_libtool_libs" != yes; then wrappers_required=no fi ;; *) if test "$need_relink" = no || test "$build_libtool_libs" != yes; then wrappers_required=no fi ;; esac if test "$wrappers_required" = no; then # Replace the output file specification. compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` link_command="$compile_command$compile_rpath" # We have no uninstalled library dependencies, so finalize right now. exit_status=0 func_show_eval "$link_command" 'exit_status=$?' if test -n "$postlink_cmds"; then func_to_tool_file "$output" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi # Delete the generated files. if test -f "$output_objdir/${outputname}S.${objext}"; then func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"' fi exit $exit_status fi if test -n "$compile_shlibpath$finalize_shlibpath"; then compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" fi if test -n "$finalize_shlibpath"; then finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" fi compile_var= finalize_var= if test -n "$runpath_var"; then if test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do func_append rpath "$dir:" done compile_var="$runpath_var=\"$rpath\$$runpath_var\" " fi if test -n "$finalize_perm_rpath"; then # We should set the runpath_var. rpath= for dir in $finalize_perm_rpath; do func_append rpath "$dir:" done finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " fi fi if test "$no_install" = yes; then # We don't need to create a wrapper script. link_command="$compile_var$compile_command$compile_rpath" # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` # Delete the old output file. $opt_dry_run || $RM $output # Link the executable and exit func_show_eval "$link_command" 'exit $?' if test -n "$postlink_cmds"; then func_to_tool_file "$output" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi exit $EXIT_SUCCESS fi if test "$hardcode_action" = relink; then # Fast installation is not supported link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" func_warning "this platform does not like uninstalled shared libraries" func_warning "\`$output' will be relinked during installation" else if test "$fast_install" != no; then link_command="$finalize_var$compile_command$finalize_rpath" if test "$fast_install" = yes; then relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` else # fast_install is set to needless relink_command= fi else link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" fi fi # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` # Delete the old output files. $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname func_show_eval "$link_command" 'exit $?' if test -n "$postlink_cmds"; then func_to_tool_file "$output_objdir/$outputname" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi # Now create the wrapper script. func_verbose "creating $output" # Quote the relink command for shipping. if test -n "$relink_command"; then # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done relink_command="(cd `pwd`; $relink_command)" relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` fi # Only actually do things if not in dry run mode. $opt_dry_run || { # win32 will think the script is a binary if it has # a .exe suffix, so we strip it off here. case $output in *.exe) func_stripname '' '.exe' "$output" output=$func_stripname_result ;; esac # test for cygwin because mv fails w/o .exe extensions case $host in *cygwin*) exeext=.exe func_stripname '' '.exe' "$outputname" outputname=$func_stripname_result ;; *) exeext= ;; esac case $host in *cygwin* | *mingw* ) func_dirname_and_basename "$output" "" "." output_name=$func_basename_result output_path=$func_dirname_result cwrappersource="$output_path/$objdir/lt-$output_name.c" cwrapper="$output_path/$output_name.exe" $RM $cwrappersource $cwrapper trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 func_emit_cwrapperexe_src > $cwrappersource # The wrapper executable is built using the $host compiler, # because it contains $host paths and files. If cross- # compiling, it, like the target executable, must be # executed on the $host or under an emulation environment. $opt_dry_run || { $LTCC $LTCFLAGS -o $cwrapper $cwrappersource $STRIP $cwrapper } # Now, create the wrapper script for func_source use: func_ltwrapper_scriptname $cwrapper $RM $func_ltwrapper_scriptname_result trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 $opt_dry_run || { # note: this script will not be executed, so do not chmod. if test "x$build" = "x$host" ; then $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result else func_emit_wrapper no > $func_ltwrapper_scriptname_result fi } ;; * ) $RM $output trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 func_emit_wrapper no > $output chmod +x $output ;; esac } exit $EXIT_SUCCESS ;; esac # See if we need to build an old-fashioned archive. for oldlib in $oldlibs; do if test "$build_libtool_libs" = convenience; then oldobjs="$libobjs_save $symfileobj" addlibs="$convenience" build_libtool_libs=no else if test "$build_libtool_libs" = module; then oldobjs="$libobjs_save" build_libtool_libs=no else oldobjs="$old_deplibs $non_pic_objects" if test "$preload" = yes && test -f "$symfileobj"; then func_append oldobjs " $symfileobj" fi fi addlibs="$old_convenience" fi if test -n "$addlibs"; then gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $addlibs func_append oldobjs " $func_extract_archives_result" fi # Do each command in the archive commands. if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then cmds=$old_archive_from_new_cmds else # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $dlprefiles func_append oldobjs " $func_extract_archives_result" fi # POSIX demands no paths to be encoded in archives. We have # to avoid creating archives with duplicate basenames if we # might have to extract them afterwards, e.g., when creating a # static archive out of a convenience library, or when linking # the entirety of a libtool archive into another (currently # not supported by libtool). if (for obj in $oldobjs do func_basename "$obj" $ECHO "$func_basename_result" done | sort | sort -uc >/dev/null 2>&1); then : else echo "copying selected object files to avoid basename conflicts..." gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_mkdir_p "$gentop" save_oldobjs=$oldobjs oldobjs= counter=1 for obj in $save_oldobjs do func_basename "$obj" objbase="$func_basename_result" case " $oldobjs " in " ") oldobjs=$obj ;; *[\ /]"$objbase "*) while :; do # Make sure we don't pick an alternate name that also # overlaps. newobj=lt$counter-$objbase func_arith $counter + 1 counter=$func_arith_result case " $oldobjs " in *[\ /]"$newobj "*) ;; *) if test ! -f "$gentop/$newobj"; then break; fi ;; esac done func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" func_append oldobjs " $gentop/$newobj" ;; *) func_append oldobjs " $obj" ;; esac done fi func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 tool_oldlib=$func_to_tool_file_result eval cmds=\"$old_archive_cmds\" func_len " $cmds" len=$func_len_result if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then cmds=$old_archive_cmds elif test -n "$archiver_list_spec"; then func_verbose "using command file archive linking..." for obj in $oldobjs do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" done > $output_objdir/$libname.libcmd func_to_tool_file "$output_objdir/$libname.libcmd" oldobjs=" $archiver_list_spec$func_to_tool_file_result" cmds=$old_archive_cmds else # the command line is too long to link in one step, link in parts func_verbose "using piecewise archive linking..." save_RANLIB=$RANLIB RANLIB=: objlist= concat_cmds= save_oldobjs=$oldobjs oldobjs= # Is there a better way of finding the last object in the list? for obj in $save_oldobjs do last_oldobj=$obj done eval test_cmds=\"$old_archive_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 for obj in $save_oldobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result func_append objlist " $obj" if test "$len" -lt "$max_cmd_len"; then : else # the above command should be used before it gets too long oldobjs=$objlist if test "$obj" = "$last_oldobj" ; then RANLIB=$save_RANLIB fi test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" objlist= len=$len0 fi done RANLIB=$save_RANLIB oldobjs=$objlist if test "X$oldobjs" = "X" ; then eval cmds=\"\$concat_cmds\" else eval cmds=\"\$concat_cmds~\$old_archive_cmds\" fi fi fi func_execute_cmds "$cmds" 'exit $?' done test -n "$generated" && \ func_show_eval "${RM}r$generated" # Now create the libtool archive. case $output in *.la) old_library= test "$build_old_libs" = yes && old_library="$libname.$libext" func_verbose "creating $output" # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done # Quote the link command for shipping. relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` if test "$hardcode_automatic" = yes ; then relink_command= fi # Only create the output if not a dry run. $opt_dry_run || { for installed in no yes; do if test "$installed" = yes; then if test -z "$install_libdir"; then break fi output="$output_objdir/$outputname"i # Replace all uninstalled libtool libraries with the installed ones newdependency_libs= for deplib in $dependency_libs; do case $deplib in *.la) func_basename "$deplib" name="$func_basename_result" func_resolve_sysroot "$deplib" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result` test -z "$libdir" && \ func_fatal_error "\`$deplib' is not a valid libtool archive" func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name" ;; -L*) func_stripname -L '' "$deplib" func_replace_sysroot "$func_stripname_result" func_append newdependency_libs " -L$func_replace_sysroot_result" ;; -R*) func_stripname -R '' "$deplib" func_replace_sysroot "$func_stripname_result" func_append newdependency_libs " -R$func_replace_sysroot_result" ;; *) func_append newdependency_libs " $deplib" ;; esac done dependency_libs="$newdependency_libs" newdlfiles= for lib in $dlfiles; do case $lib in *.la) func_basename "$lib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "\`$lib' is not a valid libtool archive" func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name" ;; *) func_append newdlfiles " $lib" ;; esac done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do case $lib in *.la) # Only pass preopened files to the pseudo-archive (for # eventual linking with the app. that links it) if we # didn't already link the preopened objects directly into # the library: func_basename "$lib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "\`$lib' is not a valid libtool archive" func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name" ;; esac done dlprefiles="$newdlprefiles" else newdlfiles= for lib in $dlfiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac func_append newdlfiles " $abs" done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac func_append newdlprefiles " $abs" done dlprefiles="$newdlprefiles" fi $RM $output # place dlname in correct position for cygwin # In fact, it would be nice if we could use this code for all target # systems that can't hard-code library paths into their executables # and that have no shared library path variable independent of PATH, # but it turns out we can't easily determine that from inspecting # libtool variables, so we have to hard-code the OSs to which it # applies here; at the moment, that means platforms that use the PE # object format with DLL files. See the long comment at the top of # tests/bindir.at for full details. tdlname=$dlname case $host,$output,$installed,$module,$dlname in *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) # If a -bindir argument was supplied, place the dll there. if test "x$bindir" != x ; then func_relative_path "$install_libdir" "$bindir" tdlname=$func_relative_path_result$dlname else # Otherwise fall back on heuristic. tdlname=../bin/$dlname fi ;; esac $ECHO > $output "\ # $outputname - a libtool library file # Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION # # Please DO NOT delete this file! # It is necessary for linking the library. # The name that we can dlopen(3). dlname='$tdlname' # Names of this library. library_names='$library_names' # The name of the static archive. old_library='$old_library' # Linker flags that can not go in dependency_libs. inherited_linker_flags='$new_inherited_linker_flags' # Libraries that this one depends upon. dependency_libs='$dependency_libs' # Names of additional weak libraries provided by this library weak_library_names='$weak_libs' # Version information for $libname. current=$current age=$age revision=$revision # Is this an already installed library? installed=$installed # Should we warn about portability when linking against -modules? shouldnotlink=$module # Files to dlopen/dlpreopen dlopen='$dlfiles' dlpreopen='$dlprefiles' # Directory that this library needs to be installed in: libdir='$install_libdir'" if test "$installed" = no && test "$need_relink" = yes; then $ECHO >> $output "\ relink_command=\"$relink_command\"" fi done } # Do a symbolic link so that the libtool archive can be found in # LD_LIBRARY_PATH before the program is installed. func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' ;; esac exit $EXIT_SUCCESS } { test "$opt_mode" = link || test "$opt_mode" = relink; } && func_mode_link ${1+"$@"} # func_mode_uninstall arg... func_mode_uninstall () { $opt_debug RM="$nonopt" files= rmforce= exit_status=0 # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" for arg do case $arg in -f) func_append RM " $arg"; rmforce=yes ;; -*) func_append RM " $arg" ;; *) func_append files " $arg" ;; esac done test -z "$RM" && \ func_fatal_help "you must specify an RM program" rmdirs= for file in $files; do func_dirname "$file" "" "." dir="$func_dirname_result" if test "X$dir" = X.; then odir="$objdir" else odir="$dir/$objdir" fi func_basename "$file" name="$func_basename_result" test "$opt_mode" = uninstall && odir="$dir" # Remember odir for removal later, being careful to avoid duplicates if test "$opt_mode" = clean; then case " $rmdirs " in *" $odir "*) ;; *) func_append rmdirs " $odir" ;; esac fi # Don't error if the file doesn't exist and rm -f was used. if { test -L "$file"; } >/dev/null 2>&1 || { test -h "$file"; } >/dev/null 2>&1 || test -f "$file"; then : elif test -d "$file"; then exit_status=1 continue elif test "$rmforce" = yes; then continue fi rmfiles="$file" case $name in *.la) # Possibly a libtool archive, so verify it. if func_lalib_p "$file"; then func_source $dir/$name # Delete the libtool libraries and symlinks. for n in $library_names; do func_append rmfiles " $odir/$n" done test -n "$old_library" && func_append rmfiles " $odir/$old_library" case "$opt_mode" in clean) case " $library_names " in *" $dlname "*) ;; *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;; esac test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i" ;; uninstall) if test -n "$library_names"; then # Do each command in the postuninstall commands. func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' fi if test -n "$old_library"; then # Do each command in the old_postuninstall commands. func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' fi # FIXME: should reinstall the best remaining shared library. ;; esac fi ;; *.lo) # Possibly a libtool object, so verify it. if func_lalib_p "$file"; then # Read the .lo file func_source $dir/$name # Add PIC object to the list of files to remove. if test -n "$pic_object" && test "$pic_object" != none; then func_append rmfiles " $dir/$pic_object" fi # Add non-PIC object to the list of files to remove. if test -n "$non_pic_object" && test "$non_pic_object" != none; then func_append rmfiles " $dir/$non_pic_object" fi fi ;; *) if test "$opt_mode" = clean ; then noexename=$name case $file in *.exe) func_stripname '' '.exe' "$file" file=$func_stripname_result func_stripname '' '.exe' "$name" noexename=$func_stripname_result # $file with .exe has already been added to rmfiles, # add $file without .exe func_append rmfiles " $file" ;; esac # Do a test to see if this is a libtool program. if func_ltwrapper_p "$file"; then if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" relink_command= func_source $func_ltwrapper_scriptname_result func_append rmfiles " $func_ltwrapper_scriptname_result" else relink_command= func_source $dir/$noexename fi # note $name still contains .exe if it was in $file originally # as does the version of $file that was added into $rmfiles func_append rmfiles " $odir/$name $odir/${name}S.${objext}" if test "$fast_install" = yes && test -n "$relink_command"; then func_append rmfiles " $odir/lt-$name" fi if test "X$noexename" != "X$name" ; then func_append rmfiles " $odir/lt-${noexename}.c" fi fi fi ;; esac func_show_eval "$RM $rmfiles" 'exit_status=1' done # Try to remove the ${objdir}s in the directories where we deleted files for dir in $rmdirs; do if test -d "$dir"; then func_show_eval "rmdir $dir >/dev/null 2>&1" fi done exit $exit_status } { test "$opt_mode" = uninstall || test "$opt_mode" = clean; } && func_mode_uninstall ${1+"$@"} test -z "$opt_mode" && { help="$generic_help" func_fatal_help "you must specify a MODE" } test -z "$exec_cmd" && \ func_fatal_help "invalid operation mode \`$opt_mode'" if test -n "$exec_cmd"; then eval exec "$exec_cmd" exit $EXIT_FAILURE fi exit $exit_status # The TAGs below are defined such that we never get into a situation # in which we disable both kinds of libraries. Given conflicting # choices, we go for a static library, that is the most portable, # since we can't tell whether shared libraries were disabled because # the user asked for that or because the platform doesn't support # them. This is particularly important on AIX, because we don't # support having both static and shared libraries enabled at the same # time on that platform, so we default to a shared-only configuration. # If a disable-shared tag is given, we'll fallback to a static-only # configuration. But we'll never go from static-only to shared-only. # ### BEGIN LIBTOOL TAG CONFIG: disable-shared build_libtool_libs=no build_old_libs=yes # ### END LIBTOOL TAG CONFIG: disable-shared # ### BEGIN LIBTOOL TAG CONFIG: disable-static build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` # ### END LIBTOOL TAG CONFIG: disable-static # Local Variables: # mode:shell-script # sh-indentation:2 # End: # vi:sw=2 openocd-0.7.0/INSTALL0000644000175000001440000003660512141414275011126 00000000000000Installation Instructions ************************* Copyright (C) 1994-1996, 1999-2002, 2004-2012 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. This file is offered as-is, without warranty of any kind. Basic Installation ================== Briefly, the shell commands `./configure; make; make install' should configure, build, and install this package. The following more-detailed instructions are generic; see the `README' file for instructions specific to this package. Some packages provide this `INSTALL' file but do not implement all of the features documented below. The lack of an optional feature in a given package is not necessarily a bug. More recommendations for GNU packages can be found in *note Makefile Conventions: (standards)Makefile Conventions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves the results of its tests to speed up reconfiguring. Caching is disabled by default to prevent problems with accidental use of stale cache files. If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If you are using the cache, and at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create `configure' by a program called `autoconf'. You need `configure.ac' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. Running `configure' might take a while. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package, generally using the just-built uninstalled binaries. 4. Type `make install' to install the programs and any data files and documentation. When installing into a prefix owned by root, it is recommended that the package be configured and built as a regular user, and only the `make install' phase executed with root privileges. 5. Optionally, type `make installcheck' to repeat any self-tests, but this time using the binaries in their final installed location. This target does not install anything. Running this target as a regular user, particularly if the prior `make install' required root privileges, verifies that the installation completed correctly. 6. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. 7. Often, you can also type `make uninstall' to remove the installed files again. In practice, not all packages have tested that uninstallation works correctly, even though it is required by the GNU Coding Standards. 8. Some packages, particularly those that use Automake, provide `make distcheck', which can by used by developers to test that all other targets like `make install' and `make uninstall' work correctly. This target is generally not run by end users. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. Run `./configure --help' for details on some of the pertinent environment variables. You can give `configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c99 CFLAGS=-g LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you can use GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. This is known as a "VPATH" build. With a non-GNU `make', it is safer to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. On MacOS X 10.5 and later systems, you can create libraries and executables that work on multiple system types--known as "fat" or "universal" binaries--by specifying multiple `-arch' options to the compiler but only a single `-arch' option to the preprocessor. Like this: ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CPP="gcc -E" CXXCPP="g++ -E" This is not guaranteed to produce working output in all cases, you may have to build one architecture at a time and combine the results using the `lipo' tool if you have problems. Installation Names ================== By default, `make install' installs the package's commands under `/usr/local/bin', include files under `/usr/local/include', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PREFIX', where PREFIX must be an absolute file name. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you pass the option `--exec-prefix=PREFIX' to `configure', the package uses PREFIX as the prefix for installing programs and libraries. Documentation and other data files still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=DIR' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. In general, the default for these options is expressed in terms of `${prefix}', so that specifying just `--prefix' will affect all of the other directory specifications that were not explicitly provided. The most portable way to affect installation locations is to pass the correct locations to `configure'; however, many packages provide one or both of the following shortcuts of passing variable assignments to the `make install' command line to change installation locations without having to reconfigure or recompile. The first method involves providing an override variable for each affected directory. For example, `make install prefix=/alternate/directory' will choose an alternate location for all directory configuration variables that were expressed in terms of `${prefix}'. Any directories that were specified during `configure', but not in terms of `${prefix}', must each be overridden at install time for the entire installation to be relocated. The approach of makefile variable overrides for each directory variable is required by the GNU Coding Standards, and ideally causes no recompilation. However, some platforms have known limitations with the semantics of shared libraries that end up requiring recompilation when using this method, particularly noticeable in packages that use GNU Libtool. The second method involves providing the `DESTDIR' variable. For example, `make install DESTDIR=/alternate/directory' will prepend `/alternate/directory' before all installation names. The approach of `DESTDIR' overrides is not required by the GNU Coding Standards, and does not work on platforms that have drive letters. On the other hand, it does better at avoiding recompilation issues, and works well even when some directory options were not specified in terms of `${prefix}' at `configure' time. Optional Features ================= If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Some packages offer the ability to configure how verbose the execution of `make' will be. For these packages, running `./configure --enable-silent-rules' sets the default to minimal output, which can be overridden with `make V=1'; while running `./configure --disable-silent-rules' sets the default to verbose, which can be overridden with `make V=0'. Particular systems ================== On HP-UX, the default C compiler is not ANSI C compatible. If GNU CC is not installed, it is recommended to use the following options in order to use an ANSI C compiler: ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" and if that doesn't work, install pre-built binaries of GCC for HP-UX. HP-UX `make' updates targets which have the same time stamps as their prerequisites, which makes it generally unusable when shipped generated files such as `configure' are involved. Use GNU `make' instead. On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot parse its `' header file. The option `-nodtk' can be used as a workaround. If GNU CC is not installed, it is therefore recommended to try ./configure CC="cc" and if that doesn't work, try ./configure CC="cc -nodtk" On Solaris, don't put `/usr/ucb' early in your `PATH'. This directory contains several dysfunctional programs; working variants of these programs are available in `/usr/bin'. So, if you need `/usr/ucb' in your `PATH', put it _after_ `/usr/bin'. On Haiku, software installed for all users goes in `/boot/common', not `/usr/local'. It is recommended to use the following options: ./configure --prefix=/boot/common Specifying the System Type ========================== There may be some features `configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, `configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the `--build=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should use the option `--target=TYPE' to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with `--host=TYPE'. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc causes the specified `gcc' to be used as the C compiler (unless it is overridden in the site shell script). Unfortunately, this technique does not work for `CONFIG_SHELL' due to an Autoconf limitation. Until the limitation is lifted, you can use this workaround: CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash `configure' Invocation ====================== `configure' recognizes the following options to control how it operates. `--help' `-h' Print a summary of all of the options to `configure', and exit. `--help=short' `--help=recursive' Print a summary of the options unique to this package's `configure', and exit. The `short' variant lists options used only in the top level, while the `recursive' variant lists options also present in any nested packages. `--version' `-V' Print the version of Autoconf used to generate the `configure' script, and exit. `--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally `config.cache'. FILE defaults to `/dev/null' to disable caching. `--config-cache' `-C' Alias for `--cache-file=config.cache'. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `--prefix=DIR' Use DIR as the installation prefix. *note Installation Names:: for more details, including other options available for fine-tuning the installation locations. `--no-create' `-n' Run the configure checks, but stop before creating any output files. `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. openocd-0.7.0/Makefile.in0000644000175000001440000007210012141414275012130 00000000000000# Makefile.in generated by automake 1.13.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2012 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = . DIST_COMMON = INSTALL NEWS README AUTHORS ChangeLog \ $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/configure $(am__configure_deps) \ $(srcdir)/config.h.in $(nobase_dist_pkgdata_DATA) COPYING TODO \ compile config.guess config.sub install-sh missing ltmain.sh ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/config_subdir.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_HEADER = config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(pkgdatadir)" DATA = $(nobase_dist_pkgdata_DATA) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ cscope distdir dist dist-all distcheck am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \ $(LISP)config.h.in # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags CSCOPE = cscope DIST_SUBDIRS = src doc jimtcl DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ if test -d "$(distdir)"; then \ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -rf "$(distdir)" \ || { sleep 5 && rm -rf "$(distdir)"; }; \ else :; fi am__post_remove_distdir = $(am__remove_distdir) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" DIST_ARCHIVES = $(distdir).tar.gz $(distdir).tar.bz2 $(distdir).zip GZIP_ENV = --best DIST_TARGETS = dist-bzip2 dist-gzip dist-zip distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CC_FOR_BUILD = @CC_FOR_BUILD@ CFLAGS = @CFLAGS@ CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@ FGREP = @FGREP@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ doxygen_as_html = @doxygen_as_html@ doxygen_as_pdf = @doxygen_as_pdf@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ subdirs = @subdirs@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ # not a GNU package. You can remove this line, if # have all needed files, that a GNU package needs AUTOMAKE_OPTIONS = gnu 1.6 # make sure we pass the correct jimtcl flags to distcheck DISTCHECK_CONFIGURE_FLAGS = --disable-install-jim nobase_dist_pkgdata_DATA = \ contrib/libdcc/dcc_stdio.c \ contrib/libdcc/dcc_stdio.h \ contrib/libdcc/example.c \ contrib/libdcc/README \ contrib/openocd.udev @INTERNAL_JIMTCL_FALSE@SUBDIRS = src doc @INTERNAL_JIMTCL_TRUE@SUBDIRS = jimtcl src doc EXTRA_DIST = \ BUGS \ HACKING \ NEWTAPS \ README.Win32 \ Doxyfile.in \ tools/logger.pl \ contrib/loaders THE_MANUAL = doxygen/latex/refman.pdf TCL_PATH = tcl # command to find paths of script files, relative to TCL_PATH TCL_FILES = find $(srcdir)/$(TCL_PATH) -name '*.cfg' -o -name '*.tcl' -o -name '*.txt' | \ sed -e 's,^$(srcdir)/$(TCL_PATH),,' DISTCLEANFILES = doxygen.log MAINTAINERCLEANFILES = \ $(srcdir)/INSTALL \ $(srcdir)/configure \ $(srcdir)/Makefile.in \ $(srcdir)/depcomp \ $(srcdir)/config.guess \ $(srcdir)/config.sub \ $(srcdir)/config.h.in \ $(srcdir)/config.h.in~ \ $(srcdir)/compile \ $(srcdir)/ltmain.sh \ $(srcdir)/missing \ $(srcdir)/aclocal.m4 \ $(srcdir)/install-sh all: config.h $(MAKE) $(AM_MAKEFLAGS) all-recursive .SUFFIXES: am--refresh: Makefile @: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): config.h: stamp-h1 @if test ! -f $@; then rm -f stamp-h1; else :; fi @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) stamp-h1; else :; fi stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status @rm -f stamp-h1 cd $(top_builddir) && $(SHELL) ./config.status config.h $(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) rm -f stamp-h1 touch $@ distclean-hdr: -rm -f config.h stamp-h1 mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool config.lt install-nobase_dist_pkgdataDATA: $(nobase_dist_pkgdata_DATA) @$(NORMAL_INSTALL) @list='$(nobase_dist_pkgdata_DATA)'; test -n "$(pkgdatadir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pkgdatadir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pkgdatadir)" || exit 1; \ fi; \ $(am__nobase_list) | while read dir files; do \ xfiles=; for file in $$files; do \ if test -f "$$file"; then xfiles="$$xfiles $$file"; \ else xfiles="$$xfiles $(srcdir)/$$file"; fi; done; \ test -z "$$xfiles" || { \ test "x$$dir" = x. || { \ echo " $(MKDIR_P) '$(DESTDIR)$(pkgdatadir)/$$dir'"; \ $(MKDIR_P) "$(DESTDIR)$(pkgdatadir)/$$dir"; }; \ echo " $(INSTALL_DATA) $$xfiles '$(DESTDIR)$(pkgdatadir)/$$dir'"; \ $(INSTALL_DATA) $$xfiles "$(DESTDIR)$(pkgdatadir)/$$dir" || exit $$?; }; \ done uninstall-nobase_dist_pkgdataDATA: @$(NORMAL_UNINSTALL) @list='$(nobase_dist_pkgdata_DATA)'; test -n "$(pkgdatadir)" || list=; \ $(am__nobase_strip_setup); files=`$(am__nobase_strip)`; \ dir='$(DESTDIR)$(pkgdatadir)'; $(am__uninstall_files_from_dir) # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail= failcom='exit 1'; \ for f in x $$MAKEFLAGS; do \ case $$f in \ *=* | --[!k]*);; \ *k*) failcom='fail=yes';; \ esac; \ done; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscope: cscope.files test ! -s cscope.files \ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) clean-cscope: -rm -f cscope.files cscope.files: clean-cscope cscopelist cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -rm -f cscope.out cscope.in.out cscope.po.out cscope.files distdir: $(DISTFILES) $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$(top_distdir)" distdir="$(distdir)" \ dist-hook -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__post_remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 $(am__post_remove_distdir) dist-lzip: distdir tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz $(am__post_remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__post_remove_distdir) dist-tarZ: distdir tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__post_remove_distdir) dist-shar: distdir shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz $(am__post_remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__post_remove_distdir) dist dist-all: $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' $(am__post_remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lz*) \ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac chmod -R a-w $(distdir) chmod u+w $(distdir) mkdir $(distdir)/_build $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build \ && ../configure --srcdir=.. --prefix="$$dc_install_base" \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ && cd "$$am__cwd" \ || exit 1 $(am__post_remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @test -n '$(distuninstallcheck_dir)' || { \ echo 'ERROR: trying to run $@ with an empty' \ '$$(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ $(am__cd) '$(distuninstallcheck_dir)' || { \ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am check: check-recursive all-am: Makefile $(DATA) config.h installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(pkgdatadir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -f Makefile distclean-am: clean-am distclean-generic distclean-hdr \ distclean-libtool distclean-local distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-nobase_dist_pkgdataDATA @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) install-data-hook install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-nobase_dist_pkgdataDATA @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) uninstall-hook .MAKE: $(am__recursive_targets) all install-am install-data-am \ install-strip uninstall-am .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ am--refresh check check-am clean clean-cscope clean-generic \ clean-libtool cscope cscopelist-am ctags ctags-am dist \ dist-all dist-bzip2 dist-gzip dist-hook dist-lzip dist-shar \ dist-tarZ dist-xz dist-zip distcheck distclean \ distclean-generic distclean-hdr distclean-libtool \ distclean-local distclean-tags distcleancheck distdir \ distuninstallcheck dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am \ install-data-hook install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-nobase_dist_pkgdataDATA \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags tags-am uninstall uninstall-am uninstall-hook \ uninstall-nobase_dist_pkgdataDATA libtool: $(LIBTOOL_DEPS) $(SHELL) ./config.status --recheck docs: pdf html doxygen Doxyfile: $(srcdir)/Doxyfile.in @echo "Creating $@ from $<..." @( \ echo "### @@@ -= DO NOT EDIT THIS FILE =- @@@ ###" && \ echo "### @@@ Make changes to Doxyfile.in @@@ ###" && \ sed -e 's,@srcdir\@,$(srcdir),' \ -e 's,@builddir\@,$(builddir),' \ -e 's,@doxygen_as_html\@,$(doxygen_as_html),' \ -e 's,@doxygen_as_pdf\@,$(doxygen_as_pdf),' $< \ ) > $@ doxygen:: $(MAKE) Doxyfile doxygen Doxyfile 2>&1 | perl $(srcdir)/tools/logger.pl > doxygen.log @if [ -f doxygen/latex/refman.tex ]; then \ echo "Creating $(THE_MANUAL)..."; \ $(MAKE) $(THE_MANUAL); \ else \ echo "Skipping Doxygen PDF..."; \ fi $(THE_MANUAL): %.pdf: %.tex -cd $$(dirname $*) && pdflatex $$(basename $*) -cd $$(dirname $*) && pdflatex $$(basename $*) dist-hook: if test -d $(srcdir)/.git -a \( ! -e $(distdir)/ChangeLog -o -w $(distdir)/ChangeLog \) ; then \ git --git-dir $(srcdir)/.git log | $(srcdir)/tools/git2cl/git2cl > $(distdir)/ChangeLog ; \ fi for i in $$($(TCL_FILES)); do \ j="$(distdir)/$(TCL_PATH)/$$i" && \ mkdir -p "$$(dirname $$j)" && \ $(INSTALL_DATA) $(srcdir)/$(TCL_PATH)/$$i $$j; \ done install-data-hook: for i in $$($(TCL_FILES)); do \ j="$(DESTDIR)$(pkgdatadir)/scripts/$$i" && \ mkdir -p "$$(dirname $$j)" && \ $(INSTALL_DATA) $(srcdir)/$(TCL_PATH)/$$i $$j; \ done uninstall-hook: rm -rf $(DESTDIR)$(pkgdatadir)/scripts distclean-local: rm -rf Doxyfile doxygen rm -f $(srcdir)/jimtcl/configure.gnu # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: openocd-0.7.0/NEWTAPS0000644000175000001440000000757512134336410011141 00000000000000Reporting Unknown JTAG TAP IDS ------------------------------ If OpenOCD reports an UNKNOWN or Unexpected Tap ID please report it to the development mailing list - However - keep reading. openocd-devel@lists.sourceforge.net. ======================================== About "UNEXPECTED" tap ids. Before reporting an "UNEXPECTED TAP ID" - take a closer look. Perhaps you have your OpenOCD configured the wrong way, maybe you have the tap configured the wrong way? Or something else is wrong. (Remember: OpenOCD does not stop if the tap is not present) This "tap id check" is there for a purpose. The goal is to help get the *right* configuration. The idea is this: Every JTAG tap is suppose to have "a unique 32bit tap id" number. They are suppose to be "sort of unique" but they are not. There are no guarantees. Version Number Changes: Sometimes, the tap ID only differs by VERSION number. If so - it's not a big deal. Please do report this information. We'd like to know about it. For example Error: ERROR: Tap: s3c4510.cpu - Expected id: 0x3f0f0f0f, Got: 0x1f0f0f0f Error: ERROR: expected: mfg: 0x787, part: 0xf0f0, ver: 0x3 Error: ERROR: got: mfg: 0x787, part: 0xf0f0, ver: 0x1 ======================================== Updating the Tap ID number your self Why do this? You just want the warning to go away. And don't want to update your version/instance of OpenOCD. On simple systems, to fix this problem, in your "openocd.cfg" file, override the tap id. Depending on the tap, add one of these 3 commands: set CPUTAPID newvalue or set BSTAPID newvalue or set FLASHTAPID newvalue or set ETMTAPID newvalue Where "newvalue" is the new value you are seeing. On complex systems, (with many taps and chips) you probably have a custom configuration file. Its is more complicated, you're going to have to read through the configuration files ======================================== What to send: Cut & paste the output of OpenOCD that pointed you at this file. Please include the VERSION number of OpenOCD you are using. And please include the information below. ======================================== A) The JTAG TAP ID code. This is always a 32bit hex number. Examples: 0x1f0f0f0f - is an old ARM7TDMI 0x3f0f0f0f - is a newer ARM7TDMI 0x3ba00477 - is an ARM cortex M3 Some chips have multiple JTAG taps - be sure to list each one individually - ORDER is important! ======================================== B) The maker of the part Examples: Xilinx, Atmel, ST Micro Systems, Freescale ======================================== C) The family of parts it belongs to Examples: "NXP LPC Series" "Atmel SAM7 Series" ======================================== D) The actual part number on the package For example: "S3C45101x01" ======================================== E) What type of board it is. ie: a "commercial off the self eval board" that one can purchase (as opposed to your private internal custom board) For example: ST Micro systems has Eval boards, so does Analog Devices Or - if it is inside something "hackers like to hack" that information is helpful too. For example: A consumer GPS unit or a cellphone ======================================== (F) The maker of the board ie: Olimex, LogicPD, Freescale(eval board) ======================================== (G) Identifying information on the board. Not good: "iar red ST eval board" Really good: "IAR STR912-SK evaluation board" ======================================== (H) Are there other interesting (JTAG) chips on the board? ie: An FPGA or CPLD ... ======================================== (I) What target config files need updating? In fact it's best if you submit a patch with those updates. Most of the other information listed here is just to help create a good patch. ======================================== openocd-0.7.0/Doxyfile.in0000644000175000001440000017335112134336410012204 00000000000000# Doxyfile 1.5.8 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = OpenOCD # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = doxygen # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, # Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), # Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, # Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, # Spanish, Swedish, and Ukrainian. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = YES # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = NO # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = YES # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 4 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for # Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources only. Doxygen will then generate output that is more tailored for # Fortran. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for # VHDL. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it parses. # With this tag you can assign which parser to use for a given extension. # Doxygen has a built-in mapping, but you can override or extend it using this tag. # The format is ext=language, where ext is a file extension, and language is one of # the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, # Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat # .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), # use: inc=Fortran f=C EXTENSION_MAPPING = # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate getter # and setter methods for a property. Setting this option to YES (the default) # will make doxygen to replace the get and set methods by a property in the # documentation. This will only work if the methods are indeed getting or # setting a simple type. If this is not the case, or you want to show the # methods anyway, you should set this option to NO. IDL_PROPERTY_SUPPORT = NO # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically # be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. TYPEDEF_HIDES_STRUCT = NO # The SYMBOL_CACHE_SIZE determines the size of the internal cache use to # determine which symbols to keep in memory and which to flush to disk. # When the cache is full, less often used symbols will be written to disk. # For small to medium size projects (<1000 input files) the default value is # probably good enough. For larger projects a too small cache size can cause # doxygen to be busy swapping symbols to and from disk most of the time # causing a significant performance penality. # If the system has enough physical memory increasing the cache will improve the # performance by keeping more symbols in memory. Note that the value works on # a logarithmic scale so increasing the size by one will rougly double the # memory usage. The cache size is given by this formula: # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, # corresponding to a cache size of 2^16 = 65536 symbols SYMBOL_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base # name of the file that contains the anonymous namespace. By default # anonymous namespace are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = NO # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = YES # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the # Namespaces page. # This will remove the Namespaces entry from the Quick Index # and from the Folder Tree View (if specified). The default is YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by # doxygen. The layout file controls the global structure of the generated output files # in an output format independent way. The create the layout file that represents # doxygen's defaults, run doxygen with the -l option. You can optionally specify a # file name after the option, if omitted DoxygenLayout.xml will be used as the name # of the layout file. LAYOUT_FILE = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be abled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text " # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = @srcdir@/doc/manual \ @srcdir@/TODO \ @srcdir@/BUGS \ @srcdir@/HACKING \ @srcdir@/src \ @builddir@/config.h # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 FILE_PATTERNS = *.h \ *.c \ *.txt # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. # If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. # Doxygen will compare the file name with each pattern and apply the # filter if there is a match. # The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. # Otherwise they will link to the documentation. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = YES # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = @doxygen_as_html@ # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. For this to work a browser that supports # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). HTML_DYNAMIC_SECTIONS = NO # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 # integrated development environment, introduced with OSX 10.5 (Leopard). # To create a documentation set, doxygen will generate a Makefile in the # HTML output directory. Running make will produce the docset in that # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. GENERATE_DOCSET = NO # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the # feed. A documentation feed provides an umbrella under which multiple # documentation sets from a single provider (such as a company or product suite) # can be grouped. DOCSET_FEEDNAME = "Doxygen generated docs" # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that # should uniquely identify the documentation set bundle. This should be a # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. DOCSET_BUNDLE_ID = org.doxygen.Project # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING # is used to encode HtmlHelp index (hhk), content (hhc) and project file # content. CHM_INDEX_ENCODING = # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER # are set, an additional index file will be generated that can be used as input for # Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated # HTML documentation. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can # be used to specify the file name of the resulting .qch file. # The path specified is relative to the HTML output folder. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#namespace QHP_NAMESPACE = # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#virtual-folders QHP_VIRTUAL_FOLDER = doc # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. # For more information please see # http://doc.trolltech.com/qthelpproject.html#custom-filters QHP_CUST_FILTER_NAME = # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see # Qt Help Project / Custom Filters. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's # filter section matches. # Qt Help Project / Filter Attributes. QHP_SECT_FILTER_ATTRS = # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can # be used to specify the location of Qt's qhelpgenerator. # If non-empty doxygen will try to run qhelpgenerator on the generated # .qhp file. QHG_LOCATION = # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. # If the tag value is set to FRAME, a side panel will be generated # containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. Other possible values # for this tag are: HIERARCHIES, which will generate the Groups, Directories, # and Class Hierarchy pages using a tree view instead of an ordered list; # ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which # disables this behavior completely. For backwards compatibility with previous # releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE # respectively. GENERATE_TREEVIEW = YES # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 # Use this tag to change the font size of Latex formulas included # as images in the HTML documentation. The default is 10. Note that # when you change the font size after a successful doxygen run you need # to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. FORMULA_FONTSIZE = 10 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = @doxygen_as_pdf@ # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = pdflatex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = YES # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = YES # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = YES # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. # This is useful # if you want to understand what is going on. # On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = *.h # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = HAVE_CONFIG_H # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the # documentation. The MSCGEN_PATH tag allows you to specify the directory where # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = YES # By default doxygen will write a font called FreeSans.ttf to the output # directory and reference it in all dot files that doxygen generates. This # font does not include all possible unicode characters however, so when you need # these (or just want a differently looking font) you can specify the font name # using DOT_FONTNAME. You need need to make sure dot is able to find the font, # which can be done by putting it in a standard location or by setting the # DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory # containing the font. DOT_FONTNAME = FreeSans # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. # The default size is 10pt. DOT_FONTSIZE = 10 # By default doxygen will tell dot to use the output directory to look for the # FreeSans.ttf font (which doxygen will put there itself). If you specify a # different font using DOT_FONTNAME you can set the path where dot # can find it using this tag. DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT options are set to YES then # doxygen will generate a call dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # doxygen will generate a caller dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the # number of direct children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, because dot on Windows does not # seem to support this out of the box. Warning: Depending on the platform used, # enabling this option may lead to badly anti-aliased labels on the edges of # a graph (i.e. they become hard to read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Options related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO openocd-0.7.0/tools/0000755000175000001440000000000012141414411011273 500000000000000openocd-0.7.0/tools/logger.pl0000644000175000001440000000162512134336410013037 00000000000000#!/usr/bin/perl # logger.pl: masks long meaningless output with pretty lines of dots # Details: 1) reads lines from STDIN and echos them on STDOUT, # 2) print a '.' to STDERR every $N lines. # 3) print a newline after a sequence of $C dots use strict; use warnings; # make sure all output gets displayed immediately $| = 1; # TODO: add -n and -c options w/ zero checks) # line and column limits my $N = 10; my $C = 72; # current line and column counters my $n = 0; my $c = 0; # read all lines from STDIN while () { # echo line to output print STDOUT $_; # echo line to console if it is important if (/(Warning|Error)/) { print STDERR "\n" if $c; print STDERR $_; $c = 0; } # only display progress every Nth step next if ++$n % $N; print STDERR "."; # wrap at column C to provide fixed-width rows of dots print STDERR "\n" unless ++$c % $C; } print STDERR "\n" if $c; openocd-0.7.0/config_subdir.m40000644000175000001440000000145412134336410013142 00000000000000dnl dnl If needed, define the m4_ifblank and m4_ifnblank macros from autoconf 2.64 dnl This allows us to run with earlier Autoconfs as well. ifdef([m4_ifblank],[],[ m4_define([m4_ifblank], [m4_if(m4_translit([[$1]], [ ][ ][ ]), [], [$2], [$3])])]) dnl ifdef([m4_ifnblank],[],[ m4_define([m4_ifnblank], [m4_if(m4_translit([[$1]], [ ][ ][ ]), [], [$3], [$2])])]) dnl dnl AC_CONFIG_SUBDIRS does not allow configure options to be passed dnl to subdirs, this function allows that by creating a configure.gnu dnl script that prepends configure options and then calls the real dnl configure script AC_DEFUN([AX_CONFIG_SUBDIR_OPTION], [ AC_CONFIG_SUBDIRS([$1]) m4_ifblank([$2], [rm -f $srcdir/$1/configure.gnu], [printf "#!/bin/sh "\$"SHELL "../$srcdir/$1/configure" $2 \""\$"@"\" > "$srcdir/$1/configure.gnu" ]) ]) openocd-0.7.0/config.h.in0000644000175000001440000001762512141414274012120 00000000000000/* config.h.in. Generated from configure.ac by autoheader. */ /* Define if building universal (internal helper macro) */ #undef AC_APPLE_UNIVERSAL_BUILD /* 0 if you don't want the Amontec JTAG-Accelerator driver. */ #undef BUILD_AMTJTAGACCEL /* 0 if you don't want the ARM-JTAG-EW JTAG driver. */ #undef BUILD_ARMJTAGEW /* 0 if you don't want at91rm9200. */ #undef BUILD_AT91RM9200 /* 0 if you don't want a bitbang interface. */ #undef BUILD_BITBANG /* 0 if you don't want a bitq interface. */ #undef BUILD_BITQ /* 0 if you don't want the Buspirate JTAG driver. */ #undef BUILD_BUSPIRATE /* 0 if you don't want dummy driver. */ #undef BUILD_DUMMY /* 0 if you don't want ep93xx. */ #undef BUILD_EP93XX /* 0 if you don't want ftd2xx ft2232. */ #undef BUILD_FT2232_FTD2XX /* Support FT2232H/FT4232HS with FTD2XX or libftdi. */ #undef BUILD_FT2232_HIGHSPEED /* 0 if you don't want libftdi ft2232. */ #undef BUILD_FT2232_LIBFTDI /* 0 if you don't want ftdi. */ #undef BUILD_FTDI /* 0 if you don't want the Gateworks GW16012 driver. */ #undef BUILD_GW16012 /* 0 if you don't want the High Level JTAG driver. */ #undef BUILD_HLADAPTER /* 0 if you don't want the J-Link JTAG driver. */ #undef BUILD_JLINK /* Use the dummy minidriver. */ #undef BUILD_MINIDRIVER_DUMMY /* 0 if you don't want the OpenOCD+trace ETM capture driver. */ #undef BUILD_OOCD_TRACE /* 0 if you don't want the estick/opendous JTAG driver. */ #undef BUILD_OPENDOUS /* 0 if you don't want the OSBDM driver. */ #undef BUILD_OSBDM /* 0 if you don't want parport. */ #undef BUILD_PARPORT /* 0 if you don't want the ASIX PRESTO driver using FTD2XX. */ #undef BUILD_PRESTO_FTD2XX /* 0 if you don't want the ASIX PRESTO driver using libftdi. */ #undef BUILD_PRESTO_LIBFTDI /* 0 if you don't want the Remote Bitbang JTAG driver. */ #undef BUILD_REMOTE_BITBANG /* 0 if you don't want the RLink JTAG driver. */ #undef BUILD_RLINK /* 0 if you don't want SysfsGPIO driver. */ #undef BUILD_SYSFSGPIO /* 0 if you don't want the ULINK JTAG driver. */ #undef BUILD_ULINK /* 0 if you don't want the usbprog JTAG driver. */ #undef BUILD_USBPROG /* 0 if you don't want ftd2xx usb_blaster. */ #undef BUILD_USB_BLASTER_FTD2XX /* 0 if you don't want libftdi usb_blaster. */ #undef BUILD_USB_BLASTER_LIBFTDI /* 0 if you don't want the Versaloon-Link JTAG driver. */ #undef BUILD_VSLLINK /* 0 if you don't want ZY1000. */ #undef BUILD_ZY1000 /* 0 if you don't want ZY1000 JTAG master registers. */ #undef BUILD_ZY1000_MASTER /* Support FT232H with FTD2XX or libftdi. */ #undef HAS_ENUM_FT232H /* Define to 1 if you have the header file. */ #undef HAVE_ARPA_INET_H /* Define to 1 if you have the header file. */ #undef HAVE_DIRENT_H /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H /* Define to 1 if you have the header file. */ #undef HAVE_ELF_H /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H /* Define to 1 if you have the `gettimeofday' function. */ #undef HAVE_GETTIMEOFDAY /* Define to 1 if you have the header file. */ #undef HAVE_IFADDRS_H /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_JTAG_MINIDRIVER_H /* Define if you have libusb-1.0 */ #undef HAVE_LIBUSB1 /* Define to 1 if the system has the type 'long long int'. */ #undef HAVE_LONG_LONG_INT /* Define to 1 if you have the header file. */ #undef HAVE_MALLOC_H /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the header file. */ #undef HAVE_NETDB_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IN_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_TCP_H /* Define to 1 if you have the header file. */ #undef HAVE_NET_IF_H /* Define to 1 if you have the header file. */ #undef HAVE_PTHREAD_H /* Define to 1 if stdbool.h conforms to C99. */ #undef HAVE_STDBOOL_H /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the `strndup' function. */ #undef HAVE_STRNDUP /* Define to 1 if you have the `strnlen' function. */ #undef HAVE_STRNLEN /* Define to 1 if you have the header file. */ #undef HAVE_SYS_IOCTL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_IO_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_PARAM_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_POLL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SELECT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKET_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TIME_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to 1 if the system has the type 'unsigned long long int'. */ #undef HAVE_UNSIGNED_LONG_LONG_INT /* Define to 1 if you have the header file. */ #undef HAVE_USB_H /* Define to 1 if you have the `usleep' function. */ #undef HAVE_USLEEP /* Define to 1 if you have the `vasprintf' function. */ #undef HAVE_VASPRINTF /* Define to 1 if the system has the type `_Bool'. */ #undef HAVE__BOOL /* 0 if not building for Cygwin. */ #undef IS_CYGWIN /* 0 if not building for Darwin. */ #undef IS_DARWIN /* 1 if building for MinGW. */ #undef IS_MINGW /* 0 if not building for Win32. */ #undef IS_WIN32 /* Define to the sub-directory in which libtool stores uninstalled libraries. */ #undef LT_OBJDIR /* Define to 1 if assertions should be disabled. */ #undef NDEBUG /* Must declare 'environ' to use it. */ #undef NEED_ENVIRON_EXTERN /* Define to 1 if your C compiler doesn't accept -c and -o together. */ #undef NO_MINUS_C_MINUS_O /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* 0 if you don't want parport to use giveio. */ #undef PARPORT_USE_GIVEIO /* 0 if you don't want parport to use ppdev. */ #undef PARPORT_USE_PPDEV /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Define to 1 if you can safely include both and . */ #undef TIME_WITH_SYS_TIME /* Version number of package */ #undef VERSION /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel). */ #if defined AC_APPLE_UNIVERSAL_BUILD # if defined __BIG_ENDIAN__ # define WORDS_BIGENDIAN 1 # endif #else # ifndef WORDS_BIGENDIAN # undef WORDS_BIGENDIAN # endif #endif /* Include malloc free space in logging */ #undef _DEBUG_FREE_SPACE_ /* Print verbose JTAG I/O messages */ #undef _DEBUG_JTAG_IO_ /* Print verbose USB communication messages */ #undef _DEBUG_USB_COMMS_ /* Print verbose USB I/O messages */ #undef _DEBUG_USB_IO_ /* Use GNU C library extensions (e.g. stdndup). */ #undef _GNU_SOURCE /* Define to empty if `const' does not conform to ANSI C. */ #undef const #include #include #include openocd-0.7.0/depcomp0000755000175000001440000005570312141414275011452 00000000000000#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2012-10-18.11; # UTC # Copyright (C) 1999-2013 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # 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 Alexandre Oliva . case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by 'PROGRAMS ARGS'. object Object file output by 'PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputting dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac # Get the directory component of the given path, and save it in the # global variables '$dir'. Note that this directory component will # be either empty or ending with a '/' character. This is deliberate. set_dir_from () { case $1 in */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; *) dir=;; esac } # Get the suffix-stripped basename of the given path, and save it the # global variable '$base'. set_base_from () { base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` } # If no dependency file was actually created by the compiler invocation, # we still have to create a dummy depfile, to avoid errors with the # Makefile "include basename.Plo" scheme. make_dummy_depfile () { echo "#dummy" > "$depfile" } # Factor out some common post-processing of the generated depfile. # Requires the auxiliary global variable '$tmpdepfile' to be set. aix_post_process_depfile () { # If the compiler actually managed to produce a dependency file, # post-process it. if test -f "$tmpdepfile"; then # Each line is of the form 'foo.o: dependency.h'. # Do two passes, one to just change these to # $object: dependency.h # and one to simply output # dependency.h: # which is needed to avoid the deleted-header problem. { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" } > "$depfile" rm -f "$tmpdepfile" else make_dummy_depfile fi } # A tabulation character. tab=' ' # A newline character. nl=' ' # Character ranges might be problematic outside the C locale. # These definitions help. upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ lower=abcdefghijklmnopqrstuvwxyz digits=0123456789 alpha=${upper}${lower} if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Avoid interferences from the environment. gccflag= dashmflag= # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi cygpath_u="cygpath -u -f -" if test "$depmode" = msvcmsys; then # This is just like msvisualcpp but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvisualcpp fi if test "$depmode" = msvc7msys; then # This is just like msvc7 but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvc7 fi if test "$depmode" = xlc; then # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. gccflag=-qmakedep=gcc,-MF depmode=gcc fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. ## Unfortunately, FreeBSD c89 acceptance of flags depends upon ## the command line argument order; so add the flags where they ## appear in depend2.am. Note that the slowdown incurred here ## affects only configure: in makefiles, %FASTDEP% shortcuts this. for arg do case $arg in -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; *) set fnord "$@" "$arg" ;; esac shift # fnord shift # $arg done "$@" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. ## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. ## (see the conditional assignment to $gccflag above). ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). Also, it might not be ## supported by the other compilers which use the 'gcc' depmode. ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The second -e expression handles DOS-style file names with drive # letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the "deleted header file" problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. ## Some versions of gcc put a space before the ':'. On the theory ## that the space means something, we add a space to the output as ## well. hp depmode also adds that space, but also prefixes the VPATH ## to the object. Take care to not repeat it in the output. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like '#:fec' to the end of the # dependency line. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ | tr "$nl" ' ' >> "$depfile" echo >> "$depfile" # The second pass generates a dummy entry for each header file. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" ;; xlc) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts '$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.u tmpdepfile2=$base.u tmpdepfile3=$dir.libs/$base.u "$@" -Wc,-M else tmpdepfile1=$dir$base.u tmpdepfile2=$dir$base.u tmpdepfile3=$dir$base.u "$@" -M fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done aix_post_process_depfile ;; tcc) # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 # FIXME: That version still under development at the moment of writing. # Make that this statement remains true also for stable, released # versions. # It will wrap lines (doesn't matter whether long or short) with a # trailing '\', as in: # # foo.o : \ # foo.c \ # foo.h \ # # It will put a trailing '\' even on the last line, and will use leading # spaces rather than leading tabs (at least since its commit 0394caf7 # "Emit spaces for -MD"). "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. # We have to change lines of the first kind to '$object: \'. sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" # And for each line of the second kind, we have to emit a 'dep.h:' # dummy dependency, to avoid the deleted-header problem. sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" rm -f "$tmpdepfile" ;; ## The order of this option in the case statement is important, since the ## shell code in configure will try each of these formats in the order ## listed in this file. A plain '-MD' option would be understood by many ## compilers, so we must ensure this comes after the gcc and icc options. pgcc) # Portland's C compiler understands '-MD'. # Will always output deps to 'file.d' where file is the root name of the # source file under compilation, even if file resides in a subdirectory. # The object file name does not affect the name of the '.d' file. # pgcc 10.2 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using '\' : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... set_dir_from "$object" # Use the source, not the object, to determine the base name, since # that's sadly what pgcc will do too. set_base_from "$source" tmpdepfile=$base.d # For projects that build the same source file twice into different object # files, the pgcc approach of using the *source* file root name can cause # problems in parallel builds. Use a locking strategy to avoid stomping on # the same $tmpdepfile. lockdir=$base.d-lock trap " echo '$0: caught signal, cleaning up...' >&2 rmdir '$lockdir' exit 1 " 1 2 13 15 numtries=100 i=$numtries while test $i -gt 0; do # mkdir is a portable test-and-set. if mkdir "$lockdir" 2>/dev/null; then # This process acquired the lock. "$@" -MD stat=$? # Release the lock. rmdir "$lockdir" break else # If the lock is being held by a different process, wait # until the winning process is done or we timeout. while test -d "$lockdir" && test $i -gt 0; do sleep 1 i=`expr $i - 1` done fi i=`expr $i - 1` done trap - 1 2 13 15 if test $i -le 0; then echo "$0: failed to acquire lock after $numtries attempts" >&2 echo "$0: check lockdir '$lockdir'" >&2 exit 1 fi if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp2) # The "hp" stanza above does not work with aCC (C++) and HP's ia64 # compilers, which have integrated preprocessors. The correct option # to use with these is +Maked; it writes dependencies to a file named # 'foo.d', which lands next to the object file, wherever that # happens to be. # Much of this is similar to the tru64 case; see comments there. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d "$@" -Wc,+Maked else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d "$@" +Maked fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" # Add 'dependent.h:' lines. sed -ne '2,${ s/^ *// s/ \\*$// s/$/:/ p }' "$tmpdepfile" >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" "$tmpdepfile2" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in 'foo.d' instead, so we check for that too. # Subdirectories are respected. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then # Libtool generates 2 separate objects for the 2 libraries. These # two compilations output dependencies in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir$base.o.d # libtool 1.5 tmpdepfile2=$dir.libs/$base.o.d # Likewise. tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d "$@" -MD fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done # Same post-processing that is required for AIX mode. aix_post_process_depfile ;; msvc7) if test "$libtool" = yes; then showIncludes=-Wc,-showIncludes else showIncludes=-showIncludes fi "$@" $showIncludes > "$tmpdepfile" stat=$? grep -v '^Note: including file: ' "$tmpdepfile" if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The first sed program below extracts the file names and escapes # backslashes for cygpath. The second sed program outputs the file # name when reading, but also accumulates all include files in the # hold buffer in order to output them again at the end. This only # works with sed implementations that can handle large buffers. sed < "$tmpdepfile" -n ' /^Note: including file: *\(.*\)/ { s//\1/ s/\\/\\\\/g p }' | $cygpath_u | sort -u | sed -n ' s/ /\\ /g s/\(.*\)/'"$tab"'\1 \\/p s/.\(.*\) \\/\1:/ H $ { s/.*/'"$tab"'/ G p }' >> "$depfile" rm -f "$tmpdepfile" ;; msvc7msys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for ':' # in the target name. This is to cope with DOS-style filenames: # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. "$@" $dashmflag | sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this sed invocation # correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # X makedepend shift cleared=no eat=no for arg do case $cleared in no) set ""; shift cleared=yes ;; esac if test $eat = yes; then eat=no continue fi case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -arch) eat=yes ;; -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix=`echo "$object" | sed 's/^.*\././'` touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" # makedepend may prepend the VPATH from the source file name to the object. # No need to regex-escape $object, excess matching of '.' is harmless. sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process the last invocation # correctly. Breaking it into two sed invocations is a workaround. sed '1,2d' "$tmpdepfile" \ | tr ' ' "$nl" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E \ | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi IFS=" " for arg do case "$arg" in -o) shift ;; $object) shift ;; "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E 2>/dev/null | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" echo "$tab" >> "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; msvcmsys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: openocd-0.7.0/jimtcl/0000755000175000001440000000000012141414413011417 500000000000000openocd-0.7.0/jimtcl/.project0000644000175000001440000000030412134336723013014 00000000000000 jim openocd-0.7.0/jimtcl/STYLE0000644000175000001440000000326212134336723012176 00000000000000This file summarizes the C style used for Jim. Copyright (C) 2005 Salvatore Sanfilippo. ----------- INDENTATION ----------- Indentation is 4 spaces, no smart-tabs are used (i.e. two indentation steps of 4 spaces will not be converted into a real tab, but 8 spaces). --------------- FUNCTIONS NAMES --------------- Functions names of exported functions are in the form: Jim_ExportedFunctionName() The prefix is "Jim_", every word composing the function name is capitalized. Not exported functions that are of general interest for the Jim core, like JimFreeInterp() are capitalized the same way, but the prefix used for this functions is "Jim" instead of "Jim_". Another example is: JimNotExportedFunction() Not exported functions that are not general, like functions implementing hashtables or Jim objects methods can be named in any prefix as long as capitalization rules are followed, like in: ListSetIndex() --------------- VARIABLES NAMES --------------- Global variables follow the same names convention of functions. Local variables have usually short names. A counter is just 'i', or 'j', or something like this. When a longer name is required, composed of more words, capitalization is used, but the first word starts in lowcase: thisIsALogVarName ---- GOTO ---- Goto is allowed every time it makes the code cleaner, like in complex functions that need to handle exceptions, there is often an "err" label at the end of the function where allocated resources are freed before to exit with an error. Goto is also used in order to escape multiple nested loops. ---------- C FEATURES ---------- Only C89 ANSI C is allowed. C99 features can't be used currently. GCC extensions are not allowed. openocd-0.7.0/jimtcl/jim.c0000644000175000001440000162770112134336723012311 00000000000000 /* Jim - A small embeddable Tcl interpreter * * Copyright 2005 Salvatore Sanfilippo * Copyright 2005 Clemens Hintze * Copyright 2005 patthoyts - Pat Thoyts * Copyright 2008,2009 oharboe - Øyvind Harboe - oyvind.harboe@zylin.com * Copyright 2008 Andrew Lunn * Copyright 2008 Duane Ellis * Copyright 2008 Uwe Klein * Copyright 2008 Steve Bennett * Copyright 2009 Nico Coesel * Copyright 2009 Zachary T Welch zw@superlucidity.net * Copyright 2009 David Brownell * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation * are those of the authors and should not be interpreted as representing * official policies, either expressed or implied, of the Jim Tcl Project. **/ #define JIM_OPTIMIZATION /* comment to avoid optimizations and reduce size */ #include #include #include #include #include #include #include #include #include #include #include "jim.h" #include "jimautoconf.h" #include "utf8.h" #ifdef HAVE_SYS_TIME_H #include #endif #ifdef HAVE_BACKTRACE #include #endif #ifdef HAVE_CRT_EXTERNS_H #include #endif /* For INFINITY, even if math functions are not enabled */ #include /* We may decide to switch to using $[...] after all, so leave it as an option */ /*#define EXPRSUGAR_BRACKET*/ /* For the no-autoconf case */ #ifndef TCL_LIBRARY #define TCL_LIBRARY "." #endif #ifndef TCL_PLATFORM_OS #define TCL_PLATFORM_OS "unknown" #endif #ifndef TCL_PLATFORM_PLATFORM #define TCL_PLATFORM_PLATFORM "unknown" #endif #ifndef TCL_PLATFORM_PATH_SEPARATOR #define TCL_PLATFORM_PATH_SEPARATOR ":" #endif /*#define DEBUG_SHOW_SCRIPT*/ /*#define DEBUG_SHOW_SCRIPT_TOKENS*/ /*#define DEBUG_SHOW_SUBST*/ /*#define DEBUG_SHOW_EXPR*/ /*#define DEBUG_SHOW_EXPR_TOKENS*/ /*#define JIM_DEBUG_GC*/ #ifdef JIM_MAINTAINER #define JIM_DEBUG_COMMAND #define JIM_DEBUG_PANIC #endif /* Maximum size of an integer */ #define JIM_INTEGER_SPACE 24 const char *jim_tt_name(int type); #ifdef JIM_DEBUG_PANIC static void JimPanicDump(int panic_condition, const char *fmt, ...); #define JimPanic(X) JimPanicDump X #else #define JimPanic(X) #endif /* ----------------------------------------------------------------------------- * Global variables * ---------------------------------------------------------------------------*/ /* A shared empty string for the objects string representation. * Jim_InvalidateStringRep knows about it and doesn't try to free it. */ static char JimEmptyStringRep[] = ""; /* ----------------------------------------------------------------------------- * Required prototypes of not exported functions * ---------------------------------------------------------------------------*/ static void JimChangeCallFrameId(Jim_Interp *interp, Jim_CallFrame *cf); static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int flags); static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int listindex, Jim_Obj *newObjPtr, int flags); static int JimDeleteLocalProcs(Jim_Interp *interp, Jim_Stack *localCommands); static Jim_Obj *JimExpandDictSugar(Jim_Interp *interp, Jim_Obj *objPtr); static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr); static Jim_Obj **JimDictPairs(Jim_Obj *dictPtr, int *len); static void JimSetFailedEnumResult(Jim_Interp *interp, const char *arg, const char *badtype, const char *prefix, const char *const *tablePtr, const char *name); static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, int argc, Jim_Obj *const *argv); static int JimGetWideNoErr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr); static int JimSign(jim_wide w); static int JimValidName(Jim_Interp *interp, const char *type, Jim_Obj *nameObjPtr); static void JimPrngSeed(Jim_Interp *interp, unsigned char *seed, int seedLen); static void JimRandomBytes(Jim_Interp *interp, void *dest, unsigned int len); /* Fast access to the int (wide) value of an object which is known to be of int type */ #define JimWideValue(objPtr) (objPtr)->internalRep.wideValue #define JimObjTypeName(O) ((O)->typePtr ? (O)->typePtr->name : "none") static int utf8_tounicode_case(const char *s, int *uc, int upper) { int l = utf8_tounicode(s, uc); if (upper) { *uc = utf8_upper(*uc); } return l; } /* These can be used in addition to JIM_CASESENS/JIM_NOCASE */ #define JIM_CHARSET_SCAN 2 #define JIM_CHARSET_GLOB 0 /** * pattern points to a string like "[^a-z\ub5]" * * The pattern may contain trailing chars, which are ignored. * * The pattern is matched against unicode char 'c'. * * If (flags & JIM_NOCASE), case is ignored when matching. * If (flags & JIM_CHARSET_SCAN), the considers ^ and ] special at the start * of the charset, per scan, rather than glob/string match. * * If the unicode char 'c' matches that set, returns a pointer to the ']' character, * or the null character if the ']' is missing. * * Returns NULL on no match. */ static const char *JimCharsetMatch(const char *pattern, int c, int flags) { int not = 0; int pchar; int match = 0; int nocase = 0; if (flags & JIM_NOCASE) { nocase++; c = utf8_upper(c); } if (flags & JIM_CHARSET_SCAN) { if (*pattern == '^') { not++; pattern++; } /* Special case. If the first char is ']', it is part of the set */ if (*pattern == ']') { goto first; } } while (*pattern && *pattern != ']') { /* Exact match */ if (pattern[0] == '\\') { first: pattern += utf8_tounicode_case(pattern, &pchar, nocase); } else { /* Is this a range? a-z */ int start; int end; pattern += utf8_tounicode_case(pattern, &start, nocase); if (pattern[0] == '-' && pattern[1]) { /* skip '-' */ pattern += utf8_tounicode(pattern, &pchar); pattern += utf8_tounicode_case(pattern, &end, nocase); /* Handle reversed range too */ if ((c >= start && c <= end) || (c >= end && c <= start)) { match = 1; } continue; } pchar = start; } if (pchar == c) { match = 1; } } if (not) { match = !match; } return match ? pattern : NULL; } /* Glob-style pattern matching. */ /* Note: string *must* be valid UTF-8 sequences */ static int JimGlobMatch(const char *pattern, const char *string, int nocase) { int c; int pchar; while (*pattern) { switch (pattern[0]) { case '*': while (pattern[1] == '*') { pattern++; } pattern++; if (!pattern[0]) { return 1; /* match */ } while (*string) { /* Recursive call - Does the remaining pattern match anywhere? */ if (JimGlobMatch(pattern, string, nocase)) return 1; /* match */ string += utf8_tounicode(string, &c); } return 0; /* no match */ case '?': string += utf8_tounicode(string, &c); break; case '[': { string += utf8_tounicode(string, &c); pattern = JimCharsetMatch(pattern + 1, c, nocase ? JIM_NOCASE : 0); if (!pattern) { return 0; } if (!*pattern) { /* Ran out of pattern (no ']') */ continue; } break; } case '\\': if (pattern[1]) { pattern++; } /* fall through */ default: string += utf8_tounicode_case(string, &c, nocase); utf8_tounicode_case(pattern, &pchar, nocase); if (pchar != c) { return 0; } break; } pattern += utf8_tounicode_case(pattern, &pchar, nocase); if (!*string) { while (*pattern == '*') { pattern++; } break; } } if (!*pattern && !*string) { return 1; } return 0; } /** * string comparison works on binary data. * * Note that the lengths are byte lengths, not char lengths. */ static int JimStringCompare(const char *s1, int l1, const char *s2, int l2) { if (l1 < l2) { return memcmp(s1, s2, l1) <= 0 ? -1 : 1; } else if (l2 < l1) { return memcmp(s1, s2, l2) >= 0 ? 1 : -1; } else { return JimSign(memcmp(s1, s2, l1)); } } /** * Compare null terminated strings, up to a maximum of 'maxchars' characters, * (or end of string if 'maxchars' is -1). * * Returns -1, 0, 1 for s1 < s2, s1 == s2, s1 > s2 respectively. */ static int JimStringCompareLen(const char *s1, const char *s2, int maxchars, int nocase) { while (*s1 && *s2 && maxchars) { int c1, c2; s1 += utf8_tounicode_case(s1, &c1, nocase); s2 += utf8_tounicode_case(s2, &c2, nocase); if (c1 != c2) { return JimSign(c1 - c2); } maxchars--; } if (!maxchars) { return 0; } /* One string or both terminated */ if (*s1) { return 1; } if (*s2) { return -1; } return 0; } /* Search 's1' inside 's2', starting to search from char 'index' of 's2'. * The index of the first occurrence of s1 in s2 is returned. * If s1 is not found inside s2, -1 is returned. */ static int JimStringFirst(const char *s1, int l1, const char *s2, int l2, int idx) { int i; int l1bytelen; if (!l1 || !l2 || l1 > l2) { return -1; } if (idx < 0) idx = 0; s2 += utf8_index(s2, idx); l1bytelen = utf8_index(s1, l1); for (i = idx; i <= l2 - l1; i++) { int c; if (memcmp(s2, s1, l1bytelen) == 0) { return i; } s2 += utf8_tounicode(s2, &c); } return -1; } /** * Note: Lengths and return value are in bytes, not chars. */ static int JimStringLast(const char *s1, int l1, const char *s2, int l2) { const char *p; if (!l1 || !l2 || l1 > l2) return -1; /* Now search for the needle */ for (p = s2 + l2 - 1; p != s2 - 1; p--) { if (*p == *s1 && memcmp(s1, p, l1) == 0) { return p - s2; } } return -1; } #ifdef JIM_UTF8 /** * Note: Lengths and return value are in chars. */ static int JimStringLastUtf8(const char *s1, int l1, const char *s2, int l2) { int n = JimStringLast(s1, utf8_index(s1, l1), s2, utf8_index(s2, l2)); if (n > 0) { n = utf8_strlen(s2, n); } return n; } #endif static int JimWideToString(char *buf, jim_wide wideValue) { int pos = 0; if (wideValue == 0) { buf[pos++] = '0'; } else { char tmp[JIM_INTEGER_SPACE]; int num = 0; int i; if (wideValue < 0) { buf[pos++] = '-'; /* -106 % 10 may be -6 or 4! */ i = wideValue % 10; tmp[num++] = (i > 0) ? (10 - i) : -i; wideValue /= -10; } while (wideValue) { tmp[num++] = wideValue % 10; wideValue /= 10; } for (i = 0; i < num; i++) { buf[pos++] = '0' + tmp[num - i - 1]; } } buf[pos] = 0; return pos; } /** * After an strtol()/strtod()-like conversion, * check whether something was converted and that * the only thing left is white space. * * Returns JIM_OK or JIM_ERR. */ static int JimCheckConversion(const char *str, const char *endptr) { if (str[0] == '\0' || str == endptr) { return JIM_ERR; } if (endptr[0] != '\0') { while (*endptr) { if (!isspace(UCHAR(*endptr))) { return JIM_ERR; } endptr++; } } return JIM_OK; } /* Parses the front of a number to determine it's sign and base * Returns the index to start parsing according to the given base */ static int JimNumberBase(const char *str, int *base, int *sign) { int i = 0; *base = 10; while (isspace(UCHAR(str[i]))) { i++; } if (str[i] == '-') { *sign = -1; i++; } else { if (str[i] == '+') { i++; } *sign = 1; } if (str[i] != '0') { /* base 10 */ return 0; } /* We have 0, so see if we can convert it */ switch (str[i + 1]) { case 'x': case 'X': *base = 16; break; case 'o': case 'O': *base = 8; break; case 'b': case 'B': *base = 2; break; default: return 0; } i += 2; /* Ensure that (e.g.) 0x-5 fails to parse */ if (str[i] != '-' && str[i] != '+' && !isspace(UCHAR(str[i]))) { /* Parse according to this base */ return i; } /* Parse as base 10 */ return 10; } /* Converts a number as per strtol(..., 0) except leading zeros do *not* * imply octal. Instead, decimal is assumed unless the number begins with 0x, 0o or 0b */ static long jim_strtol(const char *str, char **endptr) { int sign; int base; int i = JimNumberBase(str, &base, &sign); if (base != 10) { long value = strtol(str + i, endptr, base); if (endptr == NULL || *endptr != str + i) { return value * sign; } } /* Can just do a regular base-10 conversion */ return strtol(str, endptr, 10); } /* Converts a number as per strtoull(..., 0) except leading zeros do *not* * imply octal. Instead, decimal is assumed unless the number begins with 0x, 0o or 0b */ static jim_wide jim_strtoull(const char *str, char **endptr) { #ifdef HAVE_LONG_LONG int sign; int base; int i = JimNumberBase(str, &base, &sign); if (base != 10) { jim_wide value = strtoull(str + i, endptr, base); if (endptr == NULL || *endptr != str + i) { return value * sign; } } /* Can just do a regular base-10 conversion */ return strtoull(str, endptr, 10); #else return (unsigned long)jim_strtol(str, endptr); #endif } int Jim_StringToWide(const char *str, jim_wide * widePtr, int base) { char *endptr; if (base) { *widePtr = strtoull(str, &endptr, base); } else { *widePtr = jim_strtoull(str, &endptr); } return JimCheckConversion(str, endptr); } int Jim_DoubleToString(char *buf, double doubleValue) { int len; int i; len = sprintf(buf, "%.12g", doubleValue); /* Add a final ".0" if necessary */ for (i = 0; i < len; i++) { if (buf[i] == '.' || buf[i] == 'e') { #if defined(JIM_SPRINTF_DOUBLE_NEEDS_FIX) /* If 'buf' ends in e-0nn or e+0nn, remove * the 0 after the + or - and reduce the length by 1 */ char *e = strchr(buf, 'e'); if (e && (e[1] == '-' || e[1] == '+') && e[2] == '0') { /* Move it up */ e += 2; memmove(e, e + 1, len - (e - buf)); return len - 1; } #endif return len; } /* inf or Infinity -> Inf, nan -> Nan */ if (buf[i] == 'i' || buf[i] == 'I' || buf[i] == 'n' || buf[i] == 'N') { buf[i] = toupper(UCHAR(buf[i])); buf[i + 3] = 0; return i + 3; } } buf[i++] = '.'; buf[i++] = '0'; buf[i] = '\0'; return i; } int Jim_StringToDouble(const char *str, double *doublePtr) { char *endptr; /* Callers can check for underflow via ERANGE */ errno = 0; *doublePtr = strtod(str, &endptr); return JimCheckConversion(str, endptr); } static jim_wide JimPowWide(jim_wide b, jim_wide e) { jim_wide i, res = 1; if ((b == 0 && e != 0) || (e < 0)) return 0; for (i = 0; i < e; i++) { res *= b; } return res; } /* ----------------------------------------------------------------------------- * Special functions * ---------------------------------------------------------------------------*/ #ifdef JIM_DEBUG_PANIC void JimPanicDump(int condition, const char *fmt, ...) { va_list ap; if (!condition) { return; } va_start(ap, fmt); fprintf(stderr, JIM_NL "JIM INTERPRETER PANIC: "); vfprintf(stderr, fmt, ap); fprintf(stderr, JIM_NL JIM_NL); va_end(ap); #ifdef HAVE_BACKTRACE { void *array[40]; int size, i; char **strings; size = backtrace(array, 40); strings = backtrace_symbols(array, size); for (i = 0; i < size; i++) fprintf(stderr, "[backtrace] %s" JIM_NL, strings[i]); fprintf(stderr, "[backtrace] Include the above lines and the output" JIM_NL); fprintf(stderr, "[backtrace] of 'nm ' in the bug report." JIM_NL); } #endif exit(1); } #endif /* ----------------------------------------------------------------------------- * Memory allocation * ---------------------------------------------------------------------------*/ void *Jim_Alloc(int size) { return size ? malloc(size) : NULL; } void Jim_Free(void *ptr) { free(ptr); } void *Jim_Realloc(void *ptr, int size) { return realloc(ptr, size); } char *Jim_StrDup(const char *s) { return strdup(s); } char *Jim_StrDupLen(const char *s, int l) { char *copy = Jim_Alloc(l + 1); memcpy(copy, s, l + 1); copy[l] = 0; /* Just to be sure, original could be substring */ return copy; } /* ----------------------------------------------------------------------------- * Time related functions * ---------------------------------------------------------------------------*/ /* Returns microseconds of CPU used since start. */ static jim_wide JimClock(void) { struct timeval tv; gettimeofday(&tv, NULL); return (jim_wide) tv.tv_sec * 1000000 + tv.tv_usec; } /* ----------------------------------------------------------------------------- * Hash Tables * ---------------------------------------------------------------------------*/ /* -------------------------- private prototypes ---------------------------- */ static void JimExpandHashTableIfNeeded(Jim_HashTable *ht); static unsigned int JimHashTableNextPower(unsigned int size); static Jim_HashEntry *JimInsertHashEntry(Jim_HashTable *ht, const void *key, int replace); /* -------------------------- hash functions -------------------------------- */ /* Thomas Wang's 32 bit Mix Function */ unsigned int Jim_IntHashFunction(unsigned int key) { key += ~(key << 15); key ^= (key >> 10); key += (key << 3); key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16); return key; } /* Generic hash function (we are using to multiply by 9 and add the byte * as Tcl) */ unsigned int Jim_GenHashFunction(const unsigned char *buf, int len) { unsigned int h = 0; while (len--) h += (h << 3) + *buf++; return h; } /* ----------------------------- API implementation ------------------------- */ /* reset a hashtable already initialized with ht_init(). * NOTE: This function should only called by ht_destroy(). */ static void JimResetHashTable(Jim_HashTable *ht) { ht->table = NULL; ht->size = 0; ht->sizemask = 0; ht->used = 0; ht->collisions = 0; } static void JimInitHashTableIterator(Jim_HashTable *ht, Jim_HashTableIterator *iter) { iter->ht = ht; iter->index = -1; iter->entry = NULL; iter->nextEntry = NULL; } /* Initialize the hash table */ int Jim_InitHashTable(Jim_HashTable *ht, const Jim_HashTableType *type, void *privDataPtr) { JimResetHashTable(ht); ht->type = type; ht->privdata = privDataPtr; return JIM_OK; } /* Resize the table to the minimal size that contains all the elements, * but with the invariant of a USER/BUCKETS ration near to <= 1 */ void Jim_ResizeHashTable(Jim_HashTable *ht) { int minimal = ht->used; if (minimal < JIM_HT_INITIAL_SIZE) minimal = JIM_HT_INITIAL_SIZE; Jim_ExpandHashTable(ht, minimal); } /* Expand or create the hashtable */ void Jim_ExpandHashTable(Jim_HashTable *ht, unsigned int size) { Jim_HashTable n; /* the new hashtable */ unsigned int realsize = JimHashTableNextPower(size), i; /* the size is invalid if it is smaller than the number of * elements already inside the hashtable */ if (size <= ht->used) return; Jim_InitHashTable(&n, ht->type, ht->privdata); n.size = realsize; n.sizemask = realsize - 1; n.table = Jim_Alloc(realsize * sizeof(Jim_HashEntry *)); /* Initialize all the pointers to NULL */ memset(n.table, 0, realsize * sizeof(Jim_HashEntry *)); /* Copy all the elements from the old to the new table: * note that if the old hash table is empty ht->used is zero, * so Jim_ExpandHashTable just creates an empty hash table. */ n.used = ht->used; for (i = 0; ht->used > 0; i++) { Jim_HashEntry *he, *nextHe; if (ht->table[i] == NULL) continue; /* For each hash entry on this slot... */ he = ht->table[i]; while (he) { unsigned int h; nextHe = he->next; /* Get the new element index */ h = Jim_HashKey(ht, he->key) & n.sizemask; he->next = n.table[h]; n.table[h] = he; ht->used--; /* Pass to the next element */ he = nextHe; } } assert(ht->used == 0); Jim_Free(ht->table); /* Remap the new hashtable in the old */ *ht = n; } /* Add an element to the target hash table */ int Jim_AddHashEntry(Jim_HashTable *ht, const void *key, void *val) { Jim_HashEntry *entry; /* Get the index of the new element, or -1 if * the element already exists. */ entry = JimInsertHashEntry(ht, key, 0); if (entry == NULL) return JIM_ERR; /* Set the hash entry fields. */ Jim_SetHashKey(ht, entry, key); Jim_SetHashVal(ht, entry, val); return JIM_OK; } /* Add an element, discarding the old if the key already exists */ int Jim_ReplaceHashEntry(Jim_HashTable *ht, const void *key, void *val) { int existed; Jim_HashEntry *entry; /* Get the index of the new element, or -1 if * the element already exists. */ entry = JimInsertHashEntry(ht, key, 1); if (entry->key) { /* It already exists, so replace the value */ Jim_FreeEntryVal(ht, entry); existed = 1; } else { /* Doesn't exist, so set the key */ Jim_SetHashKey(ht, entry, key); existed = 0; } Jim_SetHashVal(ht, entry, val); return existed; } /* Search and remove an element */ int Jim_DeleteHashEntry(Jim_HashTable *ht, const void *key) { unsigned int h; Jim_HashEntry *he, *prevHe; if (ht->used == 0) return JIM_ERR; h = Jim_HashKey(ht, key) & ht->sizemask; he = ht->table[h]; prevHe = NULL; while (he) { if (Jim_CompareHashKeys(ht, key, he->key)) { /* Unlink the element from the list */ if (prevHe) prevHe->next = he->next; else ht->table[h] = he->next; Jim_FreeEntryKey(ht, he); Jim_FreeEntryVal(ht, he); Jim_Free(he); ht->used--; return JIM_OK; } prevHe = he; he = he->next; } return JIM_ERR; /* not found */ } /* Destroy an entire hash table */ int Jim_FreeHashTable(Jim_HashTable *ht) { unsigned int i; /* Free all the elements */ for (i = 0; ht->used > 0; i++) { Jim_HashEntry *he, *nextHe; if ((he = ht->table[i]) == NULL) continue; while (he) { nextHe = he->next; Jim_FreeEntryKey(ht, he); Jim_FreeEntryVal(ht, he); Jim_Free(he); ht->used--; he = nextHe; } } /* Free the table and the allocated cache structure */ Jim_Free(ht->table); /* Re-initialize the table */ JimResetHashTable(ht); return JIM_OK; /* never fails */ } Jim_HashEntry *Jim_FindHashEntry(Jim_HashTable *ht, const void *key) { Jim_HashEntry *he; unsigned int h; if (ht->used == 0) return NULL; h = Jim_HashKey(ht, key) & ht->sizemask; he = ht->table[h]; while (he) { if (Jim_CompareHashKeys(ht, key, he->key)) return he; he = he->next; } return NULL; } Jim_HashTableIterator *Jim_GetHashTableIterator(Jim_HashTable *ht) { Jim_HashTableIterator *iter = Jim_Alloc(sizeof(*iter)); JimInitHashTableIterator(ht, iter); return iter; } Jim_HashEntry *Jim_NextHashEntry(Jim_HashTableIterator *iter) { while (1) { if (iter->entry == NULL) { iter->index++; if (iter->index >= (signed)iter->ht->size) break; iter->entry = iter->ht->table[iter->index]; } else { iter->entry = iter->nextEntry; } if (iter->entry) { /* We need to save the 'next' here, the iterator user * may delete the entry we are returning. */ iter->nextEntry = iter->entry->next; return iter->entry; } } return NULL; } /* ------------------------- private functions ------------------------------ */ /* Expand the hash table if needed */ static void JimExpandHashTableIfNeeded(Jim_HashTable *ht) { /* If the hash table is empty expand it to the intial size, * if the table is "full" dobule its size. */ if (ht->size == 0) Jim_ExpandHashTable(ht, JIM_HT_INITIAL_SIZE); if (ht->size == ht->used) Jim_ExpandHashTable(ht, ht->size * 2); } /* Our hash table capability is a power of two */ static unsigned int JimHashTableNextPower(unsigned int size) { unsigned int i = JIM_HT_INITIAL_SIZE; if (size >= 2147483648U) return 2147483648U; while (1) { if (i >= size) return i; i *= 2; } } /* Returns the index of a free slot that can be populated with * an hash entry for the given 'key'. * If the key already exists, -1 is returned. */ static Jim_HashEntry *JimInsertHashEntry(Jim_HashTable *ht, const void *key, int replace) { unsigned int h; Jim_HashEntry *he; /* Expand the hashtable if needed */ JimExpandHashTableIfNeeded(ht); /* Compute the key hash value */ h = Jim_HashKey(ht, key) & ht->sizemask; /* Search if this slot does not already contain the given key */ he = ht->table[h]; while (he) { if (Jim_CompareHashKeys(ht, key, he->key)) return replace ? he : NULL; he = he->next; } /* Allocates the memory and stores key */ he = Jim_Alloc(sizeof(*he)); he->next = ht->table[h]; ht->table[h] = he; ht->used++; he->key = NULL; return he; } /* ----------------------- StringCopy Hash Table Type ------------------------*/ static unsigned int JimStringCopyHTHashFunction(const void *key) { return Jim_GenHashFunction(key, strlen(key)); } static void *JimStringCopyHTDup(void *privdata, const void *key) { return strdup(key); } static int JimStringCopyHTKeyCompare(void *privdata, const void *key1, const void *key2) { return strcmp(key1, key2) == 0; } static void JimStringCopyHTKeyDestructor(void *privdata, void *key) { Jim_Free(key); } static const Jim_HashTableType JimPackageHashTableType = { JimStringCopyHTHashFunction, /* hash function */ JimStringCopyHTDup, /* key dup */ NULL, /* val dup */ JimStringCopyHTKeyCompare, /* key compare */ JimStringCopyHTKeyDestructor, /* key destructor */ NULL /* val destructor */ }; typedef struct AssocDataValue { Jim_InterpDeleteProc *delProc; void *data; } AssocDataValue; static void JimAssocDataHashTableValueDestructor(void *privdata, void *data) { AssocDataValue *assocPtr = (AssocDataValue *) data; if (assocPtr->delProc != NULL) assocPtr->delProc((Jim_Interp *)privdata, assocPtr->data); Jim_Free(data); } static const Jim_HashTableType JimAssocDataHashTableType = { JimStringCopyHTHashFunction, /* hash function */ JimStringCopyHTDup, /* key dup */ NULL, /* val dup */ JimStringCopyHTKeyCompare, /* key compare */ JimStringCopyHTKeyDestructor, /* key destructor */ JimAssocDataHashTableValueDestructor /* val destructor */ }; /* ----------------------------------------------------------------------------- * Stack - This is a simple generic stack implementation. It is used for * example in the 'expr' expression compiler. * ---------------------------------------------------------------------------*/ void Jim_InitStack(Jim_Stack *stack) { stack->len = 0; stack->maxlen = 0; stack->vector = NULL; } void Jim_FreeStack(Jim_Stack *stack) { Jim_Free(stack->vector); } int Jim_StackLen(Jim_Stack *stack) { return stack->len; } void Jim_StackPush(Jim_Stack *stack, void *element) { int neededLen = stack->len + 1; if (neededLen > stack->maxlen) { stack->maxlen = neededLen < 20 ? 20 : neededLen * 2; stack->vector = Jim_Realloc(stack->vector, sizeof(void *) * stack->maxlen); } stack->vector[stack->len] = element; stack->len++; } void *Jim_StackPop(Jim_Stack *stack) { if (stack->len == 0) return NULL; stack->len--; return stack->vector[stack->len]; } void *Jim_StackPeek(Jim_Stack *stack) { if (stack->len == 0) return NULL; return stack->vector[stack->len - 1]; } void Jim_FreeStackElements(Jim_Stack *stack, void (*freeFunc) (void *ptr)) { int i; for (i = 0; i < stack->len; i++) freeFunc(stack->vector[i]); } /* ----------------------------------------------------------------------------- * Parser * ---------------------------------------------------------------------------*/ /* Token types */ #define JIM_TT_NONE 0 /* No token returned */ #define JIM_TT_STR 1 /* simple string */ #define JIM_TT_ESC 2 /* string that needs escape chars conversion */ #define JIM_TT_VAR 3 /* var substitution */ #define JIM_TT_DICTSUGAR 4 /* Syntax sugar for [dict get], $foo(bar) */ #define JIM_TT_CMD 5 /* command substitution */ /* Note: Keep these three together for TOKEN_IS_SEP() */ #define JIM_TT_SEP 6 /* word separator. arg is # of tokens. -ve if {*} */ #define JIM_TT_EOL 7 /* line separator */ #define JIM_TT_EOF 8 /* end of script */ #define JIM_TT_LINE 9 /* special 'start-of-line' token. arg is # of arguments to the command. -ve if {*} */ #define JIM_TT_WORD 10 /* special 'start-of-word' token. arg is # of tokens to combine. -ve if {*} */ /* Additional token types needed for expressions */ #define JIM_TT_SUBEXPR_START 11 #define JIM_TT_SUBEXPR_END 12 #define JIM_TT_SUBEXPR_COMMA 13 #define JIM_TT_EXPR_INT 14 #define JIM_TT_EXPR_DOUBLE 15 #define JIM_TT_EXPRSUGAR 16 /* $(expression) */ /* Operator token types start here */ #define JIM_TT_EXPR_OP 20 #define TOKEN_IS_SEP(type) (type >= JIM_TT_SEP && type <= JIM_TT_EOF) /* Parser states */ #define JIM_PS_DEF 0 /* Default state */ #define JIM_PS_QUOTE 1 /* Inside "" */ #define JIM_PS_DICTSUGAR 2 /* Tokenising abc(def) into 4 separate tokens */ /* Parser context structure. The same context is used both to parse * Tcl scripts and lists. */ struct JimParserCtx { const char *p; /* Pointer to the point of the program we are parsing */ int len; /* Remaining length */ int linenr; /* Current line number */ const char *tstart; const char *tend; /* Returned token is at tstart-tend in 'prg'. */ int tline; /* Line number of the returned token */ int tt; /* Token type */ int eof; /* Non zero if EOF condition is true. */ int state; /* Parser state */ int comment; /* Non zero if the next chars may be a comment. */ char missing; /* At end of parse, ' ' if complete, '{' if braces incomplete, '"' if quotes incomplete */ int missingline; /* Line number starting the missing token */ }; /** * Results of missing quotes, braces, etc. from parsing. */ struct JimParseResult { char missing; /* From JimParserCtx.missing */ int line; /* From JimParserCtx.missingline */ }; static int JimParseScript(struct JimParserCtx *pc); static int JimParseSep(struct JimParserCtx *pc); static int JimParseEol(struct JimParserCtx *pc); static int JimParseCmd(struct JimParserCtx *pc); static int JimParseQuote(struct JimParserCtx *pc); static int JimParseVar(struct JimParserCtx *pc); static int JimParseBrace(struct JimParserCtx *pc); static int JimParseStr(struct JimParserCtx *pc); static int JimParseComment(struct JimParserCtx *pc); static void JimParseSubCmd(struct JimParserCtx *pc); static int JimParseSubQuote(struct JimParserCtx *pc); static void JimParseSubCmd(struct JimParserCtx *pc); static Jim_Obj *JimParserGetTokenObj(Jim_Interp *interp, struct JimParserCtx *pc); /* Initialize a parser context. * 'prg' is a pointer to the program text, linenr is the line * number of the first line contained in the program. */ static void JimParserInit(struct JimParserCtx *pc, const char *prg, int len, int linenr) { pc->p = prg; pc->len = len; pc->tstart = NULL; pc->tend = NULL; pc->tline = 0; pc->tt = JIM_TT_NONE; pc->eof = 0; pc->state = JIM_PS_DEF; pc->linenr = linenr; pc->comment = 1; pc->missing = ' '; pc->missingline = linenr; } static int JimParseScript(struct JimParserCtx *pc) { while (1) { /* the while is used to reiterate with continue if needed */ if (!pc->len) { pc->tstart = pc->p; pc->tend = pc->p - 1; pc->tline = pc->linenr; pc->tt = JIM_TT_EOL; pc->eof = 1; return JIM_OK; } switch (*(pc->p)) { case '\\': if (*(pc->p + 1) == '\n' && pc->state == JIM_PS_DEF) { return JimParseSep(pc); } pc->comment = 0; return JimParseStr(pc); case ' ': case '\t': case '\r': case '\f': if (pc->state == JIM_PS_DEF) return JimParseSep(pc); pc->comment = 0; return JimParseStr(pc); case '\n': case ';': pc->comment = 1; if (pc->state == JIM_PS_DEF) return JimParseEol(pc); return JimParseStr(pc); case '[': pc->comment = 0; return JimParseCmd(pc); case '$': pc->comment = 0; if (JimParseVar(pc) == JIM_ERR) { /* An orphan $. Create as a separate token */ pc->tstart = pc->tend = pc->p++; pc->len--; pc->tt = JIM_TT_ESC; } return JIM_OK; case '#': if (pc->comment) { JimParseComment(pc); continue; } return JimParseStr(pc); default: pc->comment = 0; return JimParseStr(pc); } return JIM_OK; } } static int JimParseSep(struct JimParserCtx *pc) { pc->tstart = pc->p; pc->tline = pc->linenr; while (isspace(UCHAR(*pc->p)) || (*pc->p == '\\' && *(pc->p + 1) == '\n')) { if (*pc->p == '\n') { break; } if (*pc->p == '\\') { pc->p++; pc->len--; pc->linenr++; } pc->p++; pc->len--; } pc->tend = pc->p - 1; pc->tt = JIM_TT_SEP; return JIM_OK; } static int JimParseEol(struct JimParserCtx *pc) { pc->tstart = pc->p; pc->tline = pc->linenr; while (isspace(UCHAR(*pc->p)) || *pc->p == ';') { if (*pc->p == '\n') pc->linenr++; pc->p++; pc->len--; } pc->tend = pc->p - 1; pc->tt = JIM_TT_EOL; return JIM_OK; } /* ** Here are the rules for parsing: ** {braced expression} ** - Count open and closing braces ** - Backslash escapes meaning of braces ** ** "quoted expression" ** - First double quote at start of word terminates the expression ** - Backslash escapes quote and bracket ** - [commands brackets] are counted/nested ** - command rules apply within [brackets], not quoting rules (i.e. quotes have their own rules) ** ** [command expression] ** - Count open and closing brackets ** - Backslash escapes quote, bracket and brace ** - [commands brackets] are counted/nested ** - "quoted expressions" are parsed according to quoting rules ** - {braced expressions} are parsed according to brace rules ** ** For everything, backslash escapes the next char, newline increments current line */ /** * Parses a braced expression starting at pc->p. * * Positions the parser at the end of the braced expression, * sets pc->tend and possibly pc->missing. */ static void JimParseSubBrace(struct JimParserCtx *pc) { int level = 1; /* Skip the brace */ pc->p++; pc->len--; while (pc->len) { switch (*pc->p) { case '\\': if (pc->len > 1) { if (*++pc->p == '\n') { pc->linenr++; } pc->len--; } break; case '{': level++; break; case '}': if (--level == 0) { pc->tend = pc->p - 1; pc->p++; pc->len--; return; } break; case '\n': pc->linenr++; break; } pc->p++; pc->len--; } pc->missing = '{'; pc->missingline = pc->tline; pc->tend = pc->p - 1; } /** * Parses a quoted expression starting at pc->p. * * Positions the parser at the end of the quoted expression, * sets pc->tend and possibly pc->missing. * * Returns the type of the token of the string, * either JIM_TT_ESC (if it contains values which need to be [subst]ed) * or JIM_TT_STR. */ static int JimParseSubQuote(struct JimParserCtx *pc) { int tt = JIM_TT_STR; int line = pc->tline; /* Skip the quote */ pc->p++; pc->len--; while (pc->len) { switch (*pc->p) { case '\\': if (pc->len > 1) { if (*++pc->p == '\n') { pc->linenr++; } pc->len--; tt = JIM_TT_ESC; } break; case '"': pc->tend = pc->p - 1; pc->p++; pc->len--; return tt; case '[': JimParseSubCmd(pc); tt = JIM_TT_ESC; continue; case '\n': pc->linenr++; break; case '$': tt = JIM_TT_ESC; break; } pc->p++; pc->len--; } pc->missing = '"'; pc->missingline = line; pc->tend = pc->p - 1; return tt; } /** * Parses a [command] expression starting at pc->p. * * Positions the parser at the end of the command expression, * sets pc->tend and possibly pc->missing. */ static void JimParseSubCmd(struct JimParserCtx *pc) { int level = 1; int startofword = 1; int line = pc->tline; /* Skip the bracket */ pc->p++; pc->len--; while (pc->len) { switch (*pc->p) { case '\\': if (pc->len > 1) { if (*++pc->p == '\n') { pc->linenr++; } pc->len--; } break; case '[': level++; break; case ']': if (--level == 0) { pc->tend = pc->p - 1; pc->p++; pc->len--; return; } break; case '"': if (startofword) { JimParseSubQuote(pc); continue; } break; case '{': JimParseSubBrace(pc); startofword = 0; continue; case '\n': pc->linenr++; break; } startofword = isspace(UCHAR(*pc->p)); pc->p++; pc->len--; } pc->missing = '['; pc->missingline = line; pc->tend = pc->p - 1; } static int JimParseBrace(struct JimParserCtx *pc) { pc->tstart = pc->p + 1; pc->tline = pc->linenr; pc->tt = JIM_TT_STR; JimParseSubBrace(pc); return JIM_OK; } static int JimParseCmd(struct JimParserCtx *pc) { pc->tstart = pc->p + 1; pc->tline = pc->linenr; pc->tt = JIM_TT_CMD; JimParseSubCmd(pc); return JIM_OK; } static int JimParseQuote(struct JimParserCtx *pc) { pc->tstart = pc->p + 1; pc->tline = pc->linenr; pc->tt = JimParseSubQuote(pc); return JIM_OK; } static int JimParseVar(struct JimParserCtx *pc) { /* skip the $ */ pc->p++; pc->len--; #ifdef EXPRSUGAR_BRACKET if (*pc->p == '[') { /* Parse $[...] expr shorthand syntax */ JimParseCmd(pc); pc->tt = JIM_TT_EXPRSUGAR; return JIM_OK; } #endif pc->tstart = pc->p; pc->tt = JIM_TT_VAR; pc->tline = pc->linenr; if (*pc->p == '{') { pc->tstart = ++pc->p; pc->len--; while (pc->len && *pc->p != '}') { if (*pc->p == '\n') { pc->linenr++; } pc->p++; pc->len--; } pc->tend = pc->p - 1; if (pc->len) { pc->p++; pc->len--; } } else { while (1) { /* Skip double colon, but not single colon! */ if (pc->p[0] == ':' && pc->p[1] == ':') { while (*pc->p == ':') { pc->p++; pc->len--; } continue; } /* Note that any char >= 0x80 must be part of a utf-8 char. * We consider all unicode points outside of ASCII as letters */ if (isalnum(UCHAR(*pc->p)) || *pc->p == '_' || UCHAR(*pc->p) >= 0x80) { pc->p++; pc->len--; continue; } break; } /* Parse [dict get] syntax sugar. */ if (*pc->p == '(') { int count = 1; const char *paren = NULL; pc->tt = JIM_TT_DICTSUGAR; while (count && pc->len) { pc->p++; pc->len--; if (*pc->p == '\\' && pc->len >= 1) { pc->p++; pc->len--; } else if (*pc->p == '(') { count++; } else if (*pc->p == ')') { paren = pc->p; count--; } } if (count == 0) { pc->p++; pc->len--; } else if (paren) { /* Did not find a matching paren. Back up */ paren++; pc->len += (pc->p - paren); pc->p = paren; } #ifndef EXPRSUGAR_BRACKET if (*pc->tstart == '(') { pc->tt = JIM_TT_EXPRSUGAR; } #endif } pc->tend = pc->p - 1; } /* Check if we parsed just the '$' character. * That's not a variable so an error is returned * to tell the state machine to consider this '$' just * a string. */ if (pc->tstart == pc->p) { pc->p--; pc->len++; return JIM_ERR; } return JIM_OK; } static int JimParseStr(struct JimParserCtx *pc) { if (pc->tt == JIM_TT_SEP || pc->tt == JIM_TT_EOL || pc->tt == JIM_TT_NONE || pc->tt == JIM_TT_STR) { /* Starting a new word */ if (*pc->p == '{') { return JimParseBrace(pc); } if (*pc->p == '"') { pc->state = JIM_PS_QUOTE; pc->p++; pc->len--; /* In case the end quote is missing */ pc->missingline = pc->tline; } } pc->tstart = pc->p; pc->tline = pc->linenr; while (1) { if (pc->len == 0) { if (pc->state == JIM_PS_QUOTE) { pc->missing = '"'; } pc->tend = pc->p - 1; pc->tt = JIM_TT_ESC; return JIM_OK; } switch (*pc->p) { case '\\': if (pc->state == JIM_PS_DEF && *(pc->p + 1) == '\n') { pc->tend = pc->p - 1; pc->tt = JIM_TT_ESC; return JIM_OK; } if (pc->len >= 2) { if (*(pc->p + 1) == '\n') { pc->linenr++; } pc->p++; pc->len--; } break; case '(': /* If the following token is not '$' just keep going */ if (pc->len > 1 && pc->p[1] != '$') { break; } case ')': /* Only need a separate ')' token if the previous was a var */ if (*pc->p == '(' || pc->tt == JIM_TT_VAR) { if (pc->p == pc->tstart) { /* At the start of the token, so just return this char */ pc->p++; pc->len--; } pc->tend = pc->p - 1; pc->tt = JIM_TT_ESC; return JIM_OK; } break; case '$': case '[': pc->tend = pc->p - 1; pc->tt = JIM_TT_ESC; return JIM_OK; case ' ': case '\t': case '\n': case '\r': case '\f': case ';': if (pc->state == JIM_PS_DEF) { pc->tend = pc->p - 1; pc->tt = JIM_TT_ESC; return JIM_OK; } else if (*pc->p == '\n') { pc->linenr++; } break; case '"': if (pc->state == JIM_PS_QUOTE) { pc->tend = pc->p - 1; pc->tt = JIM_TT_ESC; pc->p++; pc->len--; pc->state = JIM_PS_DEF; return JIM_OK; } break; } pc->p++; pc->len--; } return JIM_OK; /* unreached */ } static int JimParseComment(struct JimParserCtx *pc) { while (*pc->p) { if (*pc->p == '\n') { pc->linenr++; if (*(pc->p - 1) != '\\') { pc->p++; pc->len--; return JIM_OK; } } pc->p++; pc->len--; } return JIM_OK; } /* xdigitval and odigitval are helper functions for JimEscape() */ static int xdigitval(int c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'f') return c - 'a' + 10; if (c >= 'A' && c <= 'F') return c - 'A' + 10; return -1; } static int odigitval(int c) { if (c >= '0' && c <= '7') return c - '0'; return -1; } /* Perform Tcl escape substitution of 's', storing the result * string into 'dest'. The escaped string is guaranteed to * be the same length or shorted than the source string. * Slen is the length of the string at 's', if it's -1 the string * length will be calculated by the function. * * The function returns the length of the resulting string. */ static int JimEscape(char *dest, const char *s, int slen) { char *p = dest; int i, len; if (slen == -1) slen = strlen(s); for (i = 0; i < slen; i++) { switch (s[i]) { case '\\': switch (s[i + 1]) { case 'a': *p++ = 0x7; i++; break; case 'b': *p++ = 0x8; i++; break; case 'f': *p++ = 0xc; i++; break; case 'n': *p++ = 0xa; i++; break; case 'r': *p++ = 0xd; i++; break; case 't': *p++ = 0x9; i++; break; case 'u': case 'U': case 'x': /* A unicode or hex sequence. * \x Expect 1-2 hex chars and convert to hex. * \u Expect 1-4 hex chars and convert to utf-8. * \U Expect 1-8 hex chars and convert to utf-8. * \u{NNN} supports 1-6 hex chars and convert to utf-8. * An invalid sequence means simply the escaped char. */ { unsigned val = 0; int k; int maxchars = 2; i++; if (s[i] == 'U') { maxchars = 8; } else if (s[i] == 'u') { if (s[i + 1] == '{') { maxchars = 6; i++; } else { maxchars = 4; } } for (k = 0; k < maxchars; k++) { int c = xdigitval(s[i + k + 1]); if (c == -1) { break; } val = (val << 4) | c; } /* The \u{nnn} syntax supports up to 21 bit codepoints. */ if (s[i] == '{') { if (k == 0 || val > 0x1fffff || s[i + k + 1] != '}') { /* Back up */ i--; k = 0; } else { /* Skip the closing brace */ k++; } } if (k) { /* Got a valid sequence, so convert */ if (s[i] == 'x') { *p++ = val; } else { p += utf8_fromunicode(p, val); } i += k; break; } /* Not a valid codepoint, just an escaped char */ *p++ = s[i]; } break; case 'v': *p++ = 0xb; i++; break; case '\0': *p++ = '\\'; i++; break; case '\n': /* Replace all spaces and tabs after backslash newline with a single space*/ *p++ = ' '; do { i++; } while (s[i + 1] == ' ' || s[i + 1] == '\t'); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': /* octal escape */ { int val = 0; int c = odigitval(s[i + 1]); val = c; c = odigitval(s[i + 2]); if (c == -1) { *p++ = val; i++; break; } val = (val * 8) + c; c = odigitval(s[i + 3]); if (c == -1) { *p++ = val; i += 2; break; } val = (val * 8) + c; *p++ = val; i += 3; } break; default: *p++ = s[i + 1]; i++; break; } break; default: *p++ = s[i]; break; } } len = p - dest; *p = '\0'; return len; } /* Returns a dynamically allocated copy of the current token in the * parser context. The function performs conversion of escapes if * the token is of type JIM_TT_ESC. * * Note that after the conversion, tokens that are grouped with * braces in the source code, are always recognizable from the * identical string obtained in a different way from the type. * * For example the string: * * {*}$a * * will return as first token "*", of type JIM_TT_STR * * While the string: * * *$a * * will return as first token "*", of type JIM_TT_ESC */ static Jim_Obj *JimParserGetTokenObj(Jim_Interp *interp, struct JimParserCtx *pc) { const char *start, *end; char *token; int len; start = pc->tstart; end = pc->tend; if (start > end) { len = 0; token = Jim_Alloc(1); token[0] = '\0'; } else { len = (end - start) + 1; token = Jim_Alloc(len + 1); if (pc->tt != JIM_TT_ESC) { /* No escape conversion needed? Just copy it. */ memcpy(token, start, len); token[len] = '\0'; } else { /* Else convert the escape chars. */ len = JimEscape(token, start, len); } } return Jim_NewStringObjNoAlloc(interp, token, len); } /* Parses the given string to determine if it represents a complete script. * * This is useful for interactive shells implementation, for [info complete]. * * If 'stateCharPtr' != NULL, the function stores ' ' on complete script, * '{' on scripts incomplete missing one or more '}' to be balanced. * '[' on scripts incomplete missing one or more ']' to be balanced. * '"' on scripts incomplete missing a '"' char. * * If the script is complete, 1 is returned, otherwise 0. */ int Jim_ScriptIsComplete(const char *s, int len, char *stateCharPtr) { struct JimParserCtx parser; JimParserInit(&parser, s, len, 1); while (!parser.eof) { JimParseScript(&parser); } if (stateCharPtr) { *stateCharPtr = parser.missing; } return parser.missing == ' '; } /* ----------------------------------------------------------------------------- * Tcl Lists parsing * ---------------------------------------------------------------------------*/ static int JimParseListSep(struct JimParserCtx *pc); static int JimParseListStr(struct JimParserCtx *pc); static int JimParseListQuote(struct JimParserCtx *pc); static int JimParseList(struct JimParserCtx *pc) { if (isspace(UCHAR(*pc->p))) { return JimParseListSep(pc); } switch (*pc->p) { case '"': return JimParseListQuote(pc); case '{': return JimParseBrace(pc); default: if (pc->len) { return JimParseListStr(pc); } break; } pc->tstart = pc->tend = pc->p; pc->tline = pc->linenr; pc->tt = JIM_TT_EOL; pc->eof = 1; return JIM_OK; } static int JimParseListSep(struct JimParserCtx *pc) { pc->tstart = pc->p; pc->tline = pc->linenr; while (isspace(UCHAR(*pc->p))) { if (*pc->p == '\n') { pc->linenr++; } pc->p++; pc->len--; } pc->tend = pc->p - 1; pc->tt = JIM_TT_SEP; return JIM_OK; } static int JimParseListQuote(struct JimParserCtx *pc) { pc->p++; pc->len--; pc->tstart = pc->p; pc->tline = pc->linenr; pc->tt = JIM_TT_STR; while (pc->len) { switch (*pc->p) { case '\\': pc->tt = JIM_TT_ESC; if (--pc->len == 0) { /* Trailing backslash */ pc->tend = pc->p; return JIM_OK; } pc->p++; break; case '\n': pc->linenr++; break; case '"': pc->tend = pc->p - 1; pc->p++; pc->len--; return JIM_OK; } pc->p++; pc->len--; } pc->tend = pc->p - 1; return JIM_OK; } static int JimParseListStr(struct JimParserCtx *pc) { pc->tstart = pc->p; pc->tline = pc->linenr; pc->tt = JIM_TT_STR; while (pc->len) { if (isspace(UCHAR(*pc->p))) { pc->tend = pc->p - 1; return JIM_OK; } if (*pc->p == '\\') { if (--pc->len == 0) { /* Trailing backslash */ pc->tend = pc->p; return JIM_OK; } pc->tt = JIM_TT_ESC; pc->p++; } pc->p++; pc->len--; } pc->tend = pc->p - 1; return JIM_OK; } /* ----------------------------------------------------------------------------- * Jim_Obj related functions * ---------------------------------------------------------------------------*/ /* Return a new initialized object. */ Jim_Obj *Jim_NewObj(Jim_Interp *interp) { Jim_Obj *objPtr; /* -- Check if there are objects in the free list -- */ if (interp->freeList != NULL) { /* -- Unlink the object from the free list -- */ objPtr = interp->freeList; interp->freeList = objPtr->nextObjPtr; } else { /* -- No ready to use objects: allocate a new one -- */ objPtr = Jim_Alloc(sizeof(*objPtr)); } /* Object is returned with refCount of 0. Every * kind of GC implemented should take care to don't try * to scan objects with refCount == 0. */ objPtr->refCount = 0; /* All the other fields are left not initialized to save time. * The caller will probably want to set them to the right * value anyway. */ /* -- Put the object into the live list -- */ objPtr->prevObjPtr = NULL; objPtr->nextObjPtr = interp->liveList; if (interp->liveList) interp->liveList->prevObjPtr = objPtr; interp->liveList = objPtr; return objPtr; } /* Free an object. Actually objects are never freed, but * just moved to the free objects list, where they will be * reused by Jim_NewObj(). */ void Jim_FreeObj(Jim_Interp *interp, Jim_Obj *objPtr) { /* Check if the object was already freed, panic. */ JimPanic((objPtr->refCount != 0, "!!!Object %p freed with bad refcount %d, type=%s", objPtr, objPtr->refCount, objPtr->typePtr ? objPtr->typePtr->name : "")); /* Free the internal representation */ Jim_FreeIntRep(interp, objPtr); /* Free the string representation */ if (objPtr->bytes != NULL) { if (objPtr->bytes != JimEmptyStringRep) Jim_Free(objPtr->bytes); } /* Unlink the object from the live objects list */ if (objPtr->prevObjPtr) objPtr->prevObjPtr->nextObjPtr = objPtr->nextObjPtr; if (objPtr->nextObjPtr) objPtr->nextObjPtr->prevObjPtr = objPtr->prevObjPtr; if (interp->liveList == objPtr) interp->liveList = objPtr->nextObjPtr; /* Link the object into the free objects list */ objPtr->prevObjPtr = NULL; objPtr->nextObjPtr = interp->freeList; if (interp->freeList) interp->freeList->prevObjPtr = objPtr; interp->freeList = objPtr; objPtr->refCount = -1; } /* Invalidate the string representation of an object. */ void Jim_InvalidateStringRep(Jim_Obj *objPtr) { if (objPtr->bytes != NULL) { if (objPtr->bytes != JimEmptyStringRep) Jim_Free(objPtr->bytes); } objPtr->bytes = NULL; } /* Duplicate an object. The returned object has refcount = 0. */ Jim_Obj *Jim_DuplicateObj(Jim_Interp *interp, Jim_Obj *objPtr) { Jim_Obj *dupPtr; dupPtr = Jim_NewObj(interp); if (objPtr->bytes == NULL) { /* Object does not have a valid string representation. */ dupPtr->bytes = NULL; } else if (objPtr->length == 0) { /* Zero length, so don't even bother with the type-specific dup, since all zero length objects look the same */ dupPtr->bytes = JimEmptyStringRep; dupPtr->length = 0; dupPtr->typePtr = NULL; return dupPtr; } else { dupPtr->bytes = Jim_Alloc(objPtr->length + 1); dupPtr->length = objPtr->length; /* Copy the null byte too */ memcpy(dupPtr->bytes, objPtr->bytes, objPtr->length + 1); } /* By default, the new object has the same type as the old object */ dupPtr->typePtr = objPtr->typePtr; if (objPtr->typePtr != NULL) { if (objPtr->typePtr->dupIntRepProc == NULL) { dupPtr->internalRep = objPtr->internalRep; } else { /* The dup proc may set a different type, e.g. NULL */ objPtr->typePtr->dupIntRepProc(interp, objPtr, dupPtr); } } return dupPtr; } /* Return the string representation for objPtr. If the object * string representation is invalid, calls the method to create * a new one starting from the internal representation of the object. */ const char *Jim_GetString(Jim_Obj *objPtr, int *lenPtr) { if (objPtr->bytes == NULL) { /* Invalid string repr. Generate it. */ JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name)); objPtr->typePtr->updateStringProc(objPtr); } if (lenPtr) *lenPtr = objPtr->length; return objPtr->bytes; } /* Just returns the length of the object's string rep */ int Jim_Length(Jim_Obj *objPtr) { if (objPtr->bytes == NULL) { /* Invalid string repr. Generate it. */ JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name)); objPtr->typePtr->updateStringProc(objPtr); } return objPtr->length; } /* Just returns the length of the object's string rep */ const char *Jim_String(Jim_Obj *objPtr) { if (objPtr->bytes == NULL) { /* Invalid string repr. Generate it. */ JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name)); objPtr->typePtr->updateStringProc(objPtr); } return objPtr->bytes; } static void FreeDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *objPtr); static void DupDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr); static const Jim_ObjType dictSubstObjType = { "dict-substitution", FreeDictSubstInternalRep, DupDictSubstInternalRep, NULL, JIM_TYPE_NONE, }; static void FreeInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *objPtr) { Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.indexObjPtr); } static const Jim_ObjType interpolatedObjType = { "interpolated", FreeInterpolatedInternalRep, NULL, NULL, JIM_TYPE_NONE, }; /* ----------------------------------------------------------------------------- * String Object * ---------------------------------------------------------------------------*/ static void DupStringInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr); static int SetStringFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr); static const Jim_ObjType stringObjType = { "string", NULL, DupStringInternalRep, NULL, JIM_TYPE_REFERENCES, }; static void DupStringInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr) { JIM_NOTUSED(interp); /* This is a bit subtle: the only caller of this function * should be Jim_DuplicateObj(), that will copy the * string representaion. After the copy, the duplicated * object will not have more room in teh buffer than * srcPtr->length bytes. So we just set it to length. */ dupPtr->internalRep.strValue.maxLength = srcPtr->length; dupPtr->internalRep.strValue.charLength = srcPtr->internalRep.strValue.charLength; } static int SetStringFromAny(Jim_Interp *interp, Jim_Obj *objPtr) { if (objPtr->typePtr != &stringObjType) { /* Get a fresh string representation. */ if (objPtr->bytes == NULL) { /* Invalid string repr. Generate it. */ JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name)); objPtr->typePtr->updateStringProc(objPtr); } /* Free any other internal representation. */ Jim_FreeIntRep(interp, objPtr); /* Set it as string, i.e. just set the maxLength field. */ objPtr->typePtr = &stringObjType; objPtr->internalRep.strValue.maxLength = objPtr->length; /* Don't know the utf-8 length yet */ objPtr->internalRep.strValue.charLength = -1; } return JIM_OK; } /** * Returns the length of the object string in chars, not bytes. * * These may be different for a utf-8 string. */ int Jim_Utf8Length(Jim_Interp *interp, Jim_Obj *objPtr) { #ifdef JIM_UTF8 SetStringFromAny(interp, objPtr); if (objPtr->internalRep.strValue.charLength < 0) { objPtr->internalRep.strValue.charLength = utf8_strlen(objPtr->bytes, objPtr->length); } return objPtr->internalRep.strValue.charLength; #else return Jim_Length(objPtr); #endif } /* len is in bytes -- see also Jim_NewStringObjUtf8() */ Jim_Obj *Jim_NewStringObj(Jim_Interp *interp, const char *s, int len) { Jim_Obj *objPtr = Jim_NewObj(interp); /* Need to find out how many bytes the string requires */ if (len == -1) len = strlen(s); /* Alloc/Set the string rep. */ if (len == 0) { objPtr->bytes = JimEmptyStringRep; objPtr->length = 0; } else { objPtr->bytes = Jim_Alloc(len + 1); objPtr->length = len; memcpy(objPtr->bytes, s, len); objPtr->bytes[len] = '\0'; } /* No typePtr field for the vanilla string object. */ objPtr->typePtr = NULL; return objPtr; } /* charlen is in characters -- see also Jim_NewStringObj() */ Jim_Obj *Jim_NewStringObjUtf8(Jim_Interp *interp, const char *s, int charlen) { #ifdef JIM_UTF8 /* Need to find out how many bytes the string requires */ int bytelen = utf8_index(s, charlen); Jim_Obj *objPtr = Jim_NewStringObj(interp, s, bytelen); /* Remember the utf8 length, so set the type */ objPtr->typePtr = &stringObjType; objPtr->internalRep.strValue.maxLength = bytelen; objPtr->internalRep.strValue.charLength = charlen; return objPtr; #else return Jim_NewStringObj(interp, s, charlen); #endif } /* This version does not try to duplicate the 's' pointer, but * use it directly. */ Jim_Obj *Jim_NewStringObjNoAlloc(Jim_Interp *interp, char *s, int len) { Jim_Obj *objPtr = Jim_NewObj(interp); objPtr->bytes = s; objPtr->length = len == -1 ? strlen(s) : len; objPtr->typePtr = NULL; return objPtr; } /* Low-level string append. Use it only against objects * of type "string". */ static void StringAppendString(Jim_Obj *objPtr, const char *str, int len) { int needlen; if (len == -1) len = strlen(str); needlen = objPtr->length + len; if (objPtr->internalRep.strValue.maxLength < needlen || objPtr->internalRep.strValue.maxLength == 0) { needlen *= 2; /* Inefficient to malloc() for less than 8 bytes */ if (needlen < 7) { needlen = 7; } if (objPtr->bytes == JimEmptyStringRep) { objPtr->bytes = Jim_Alloc(needlen + 1); } else { objPtr->bytes = Jim_Realloc(objPtr->bytes, needlen + 1); } objPtr->internalRep.strValue.maxLength = needlen; } memcpy(objPtr->bytes + objPtr->length, str, len); objPtr->bytes[objPtr->length + len] = '\0'; if (objPtr->internalRep.strValue.charLength >= 0) { /* Update the utf-8 char length */ objPtr->internalRep.strValue.charLength += utf8_strlen(objPtr->bytes + objPtr->length, len); } objPtr->length += len; } /* Higher level API to append strings to objects. */ void Jim_AppendString(Jim_Interp *interp, Jim_Obj *objPtr, const char *str, int len) { JimPanic((Jim_IsShared(objPtr), "Jim_AppendString called with shared object")); SetStringFromAny(interp, objPtr); StringAppendString(objPtr, str, len); } void Jim_AppendObj(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *appendObjPtr) { int len; const char *str; str = Jim_GetString(appendObjPtr, &len); Jim_AppendString(interp, objPtr, str, len); } void Jim_AppendStrings(Jim_Interp *interp, Jim_Obj *objPtr, ...) { va_list ap; SetStringFromAny(interp, objPtr); va_start(ap, objPtr); while (1) { char *s = va_arg(ap, char *); if (s == NULL) break; Jim_AppendString(interp, objPtr, s, -1); } va_end(ap); } int Jim_StringEqObj(Jim_Obj *aObjPtr, Jim_Obj *bObjPtr) { const char *aStr, *bStr; int aLen, bLen; if (aObjPtr == bObjPtr) return 1; aStr = Jim_GetString(aObjPtr, &aLen); bStr = Jim_GetString(bObjPtr, &bLen); if (aLen != bLen) return 0; return JimStringCompare(aStr, aLen, bStr, bLen) == 0; } int Jim_StringMatchObj(Jim_Interp *interp, Jim_Obj *patternObjPtr, Jim_Obj *objPtr, int nocase) { return JimGlobMatch(Jim_String(patternObjPtr), Jim_String(objPtr), nocase); } int Jim_StringCompareObj(Jim_Interp *interp, Jim_Obj *firstObjPtr, Jim_Obj *secondObjPtr, int nocase) { int l1, l2; const char *s1 = Jim_GetString(firstObjPtr, &l1); const char *s2 = Jim_GetString(secondObjPtr, &l2); if (nocase) { /* Do a character compare for nocase */ return JimStringCompareLen(s1, s2, -1, nocase); } return JimStringCompare(s1, l1, s2, l2); } /** * Like Jim_StringCompareObj() except compares to a maximum of the length of firstObjPtr. */ int Jim_StringCompareLenObj(Jim_Interp *interp, Jim_Obj *firstObjPtr, Jim_Obj *secondObjPtr, int nocase) { const char *s1 = Jim_String(firstObjPtr); const char *s2 = Jim_String(secondObjPtr); return JimStringCompareLen(s1, s2, Jim_Utf8Length(interp, firstObjPtr), nocase); } /* Convert a range, as returned by Jim_GetRange(), into * an absolute index into an object of the specified length. * This function may return negative values, or values * bigger or equal to the length of the list if the index * is out of range. */ static int JimRelToAbsIndex(int len, int idx) { if (idx < 0) return len + idx; return idx; } /* Convert a pair of index (*firstPtr, *lastPtr) as normalized by JimRelToAbsIndex(), * into form suitable for implementation of commands like [string range] and [lrange]. * * The resulting range is guaranteed to address valid elements of * the structure. * */ static void JimRelToAbsRange(int len, int *firstPtr, int *lastPtr, int *rangeLenPtr) { int rangeLen; if (*firstPtr > *lastPtr) { rangeLen = 0; } else { rangeLen = *lastPtr - *firstPtr + 1; if (rangeLen) { if (*firstPtr < 0) { rangeLen += *firstPtr; *firstPtr = 0; } if (*lastPtr >= len) { rangeLen -= (*lastPtr - (len - 1)); *lastPtr = len - 1; } } } if (rangeLen < 0) rangeLen = 0; *rangeLenPtr = rangeLen; } static int JimStringGetRange(Jim_Interp *interp, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr, int len, int *first, int *last, int *range) { if (Jim_GetIndex(interp, firstObjPtr, first) != JIM_OK) { return JIM_ERR; } if (Jim_GetIndex(interp, lastObjPtr, last) != JIM_OK) { return JIM_ERR; } *first = JimRelToAbsIndex(len, *first); *last = JimRelToAbsIndex(len, *last); JimRelToAbsRange(len, first, last, range); return JIM_OK; } Jim_Obj *Jim_StringByteRangeObj(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr) { int first, last; const char *str; int rangeLen; int bytelen; str = Jim_GetString(strObjPtr, &bytelen); if (JimStringGetRange(interp, firstObjPtr, lastObjPtr, bytelen, &first, &last, &rangeLen) != JIM_OK) { return NULL; } if (first == 0 && rangeLen == bytelen) { return strObjPtr; } return Jim_NewStringObj(interp, str + first, rangeLen); } Jim_Obj *Jim_StringRangeObj(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr) { #ifdef JIM_UTF8 int first, last; const char *str; int len, rangeLen; int bytelen; str = Jim_GetString(strObjPtr, &bytelen); len = Jim_Utf8Length(interp, strObjPtr); if (JimStringGetRange(interp, firstObjPtr, lastObjPtr, len, &first, &last, &rangeLen) != JIM_OK) { return NULL; } if (first == 0 && rangeLen == len) { return strObjPtr; } if (len == bytelen) { /* ASCII optimisation */ return Jim_NewStringObj(interp, str + first, rangeLen); } return Jim_NewStringObjUtf8(interp, str + utf8_index(str, first), rangeLen); #else return Jim_StringByteRangeObj(interp, strObjPtr, firstObjPtr, lastObjPtr); #endif } Jim_Obj *JimStringReplaceObj(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr, Jim_Obj *newStrObj) { int first, last; const char *str; int len, rangeLen; Jim_Obj *objPtr; len = Jim_Utf8Length(interp, strObjPtr); if (JimStringGetRange(interp, firstObjPtr, lastObjPtr, len, &first, &last, &rangeLen) != JIM_OK) { return NULL; } if (last < first) { return strObjPtr; } str = Jim_String(strObjPtr); /* Before part */ objPtr = Jim_NewStringObjUtf8(interp, str, first); /* Replacement */ if (newStrObj) { Jim_AppendObj(interp, objPtr, newStrObj); } /* After part */ Jim_AppendString(interp, objPtr, str + utf8_index(str, last + 1), len - last - 1); return objPtr; } static void JimStrCopyUpperLower(char *dest, const char *str, int uc) { while (*str) { int c; str += utf8_tounicode(str, &c); dest += utf8_fromunicode(dest, uc ? utf8_upper(c) : utf8_lower(c)); } *dest = 0; } static Jim_Obj *JimStringToLower(Jim_Interp *interp, Jim_Obj *strObjPtr) { char *buf; int len; const char *str; SetStringFromAny(interp, strObjPtr); str = Jim_GetString(strObjPtr, &len); #ifdef JIM_UTF8 /* Case mapping can change the utf-8 length of the string. * But at worst it will be by one extra byte per char */ len *= 2; #endif buf = Jim_Alloc(len + 1); JimStrCopyUpperLower(buf, str, 0); return Jim_NewStringObjNoAlloc(interp, buf, -1); } static Jim_Obj *JimStringToUpper(Jim_Interp *interp, Jim_Obj *strObjPtr) { char *buf; const char *str; int len; if (strObjPtr->typePtr != &stringObjType) { SetStringFromAny(interp, strObjPtr); } str = Jim_GetString(strObjPtr, &len); #ifdef JIM_UTF8 /* Case mapping can change the utf-8 length of the string. * But at worst it will be by one extra byte per char */ len *= 2; #endif buf = Jim_Alloc(len + 1); JimStrCopyUpperLower(buf, str, 1); return Jim_NewStringObjNoAlloc(interp, buf, -1); } static Jim_Obj *JimStringToTitle(Jim_Interp *interp, Jim_Obj *strObjPtr) { char *buf, *p; int len; int c; const char *str; str = Jim_GetString(strObjPtr, &len); if (len == 0) { return strObjPtr; } #ifdef JIM_UTF8 /* Case mapping can change the utf-8 length of the string. * But at worst it will be by one extra byte per char */ len *= 2; #endif buf = p = Jim_Alloc(len + 1); str += utf8_tounicode(str, &c); p += utf8_fromunicode(p, utf8_title(c)); JimStrCopyUpperLower(p, str, 0); return Jim_NewStringObjNoAlloc(interp, buf, -1); } /* Similar to memchr() except searches a UTF-8 string 'str' of byte length 'len' * for unicode character 'c'. * Returns the position if found or NULL if not */ static const char *utf8_memchr(const char *str, int len, int c) { #ifdef JIM_UTF8 while (len) { int sc; int n = utf8_tounicode(str, &sc); if (sc == c) { return str; } str += n; len -= n; } return NULL; #else return memchr(str, c, len); #endif } /** * Searches for the first non-trim char in string (str, len) * * If none is found, returns just past the last char. * * Lengths are in bytes. */ static const char *JimFindTrimLeft(const char *str, int len, const char *trimchars, int trimlen) { while (len) { int c; int n = utf8_tounicode(str, &c); if (utf8_memchr(trimchars, trimlen, c) == NULL) { /* Not a trim char, so stop */ break; } str += n; len -= n; } return str; } /** * Searches backwards for a non-trim char in string (str, len). * * Returns a pointer to just after the non-trim char, or NULL if not found. * * Lengths are in bytes. */ static const char *JimFindTrimRight(const char *str, int len, const char *trimchars, int trimlen) { str += len; while (len) { int c; int n = utf8_prev_len(str, len); len -= n; str -= n; n = utf8_tounicode(str, &c); if (utf8_memchr(trimchars, trimlen, c) == NULL) { return str + n; } } return NULL; } static const char default_trim_chars[] = " \t\n\r"; /* sizeof() here includes the null byte */ static int default_trim_chars_len = sizeof(default_trim_chars); static Jim_Obj *JimStringTrimLeft(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr) { int len; const char *str = Jim_GetString(strObjPtr, &len); const char *trimchars = default_trim_chars; int trimcharslen = default_trim_chars_len; const char *newstr; if (trimcharsObjPtr) { trimchars = Jim_GetString(trimcharsObjPtr, &trimcharslen); } newstr = JimFindTrimLeft(str, len, trimchars, trimcharslen); if (newstr == str) { return strObjPtr; } return Jim_NewStringObj(interp, newstr, len - (newstr - str)); } static Jim_Obj *JimStringTrimRight(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr) { int len; const char *trimchars = default_trim_chars; int trimcharslen = default_trim_chars_len; const char *nontrim; if (trimcharsObjPtr) { trimchars = Jim_GetString(trimcharsObjPtr, &trimcharslen); } SetStringFromAny(interp, strObjPtr); len = Jim_Length(strObjPtr); nontrim = JimFindTrimRight(strObjPtr->bytes, len, trimchars, trimcharslen); if (nontrim == NULL) { /* All trim, so return a zero-length string */ return Jim_NewEmptyStringObj(interp); } if (nontrim == strObjPtr->bytes + len) { return strObjPtr; } if (Jim_IsShared(strObjPtr)) { strObjPtr = Jim_NewStringObj(interp, strObjPtr->bytes, (nontrim - strObjPtr->bytes)); } else { /* Can modify this string in place */ strObjPtr->bytes[nontrim - strObjPtr->bytes] = 0; strObjPtr->length = (nontrim - strObjPtr->bytes); } return strObjPtr; } static Jim_Obj *JimStringTrim(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr) { /* First trim left. */ Jim_Obj *objPtr = JimStringTrimLeft(interp, strObjPtr, trimcharsObjPtr); /* Now trim right */ strObjPtr = JimStringTrimRight(interp, objPtr, trimcharsObjPtr); if (objPtr != strObjPtr) { /* Note that we don't want this object to be leaked */ Jim_IncrRefCount(objPtr); Jim_DecrRefCount(interp, objPtr); } return strObjPtr; } static int JimStringIs(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *strClass, int strict) { static const char * const strclassnames[] = { "integer", "alpha", "alnum", "ascii", "digit", "double", "lower", "upper", "space", "xdigit", "control", "print", "graph", "punct", NULL }; enum { STR_IS_INTEGER, STR_IS_ALPHA, STR_IS_ALNUM, STR_IS_ASCII, STR_IS_DIGIT, STR_IS_DOUBLE, STR_IS_LOWER, STR_IS_UPPER, STR_IS_SPACE, STR_IS_XDIGIT, STR_IS_CONTROL, STR_IS_PRINT, STR_IS_GRAPH, STR_IS_PUNCT }; int strclass; int len; int i; const char *str; int (*isclassfunc)(int c) = NULL; if (Jim_GetEnum(interp, strClass, strclassnames, &strclass, "class", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) { return JIM_ERR; } str = Jim_GetString(strObjPtr, &len); if (len == 0) { Jim_SetResultInt(interp, !strict); return JIM_OK; } switch (strclass) { case STR_IS_INTEGER: { jim_wide w; Jim_SetResultInt(interp, JimGetWideNoErr(interp, strObjPtr, &w) == JIM_OK); return JIM_OK; } case STR_IS_DOUBLE: { double d; Jim_SetResultInt(interp, Jim_GetDouble(interp, strObjPtr, &d) == JIM_OK && errno != ERANGE); return JIM_OK; } case STR_IS_ALPHA: isclassfunc = isalpha; break; case STR_IS_ALNUM: isclassfunc = isalnum; break; case STR_IS_ASCII: isclassfunc = isascii; break; case STR_IS_DIGIT: isclassfunc = isdigit; break; case STR_IS_LOWER: isclassfunc = islower; break; case STR_IS_UPPER: isclassfunc = isupper; break; case STR_IS_SPACE: isclassfunc = isspace; break; case STR_IS_XDIGIT: isclassfunc = isxdigit; break; case STR_IS_CONTROL: isclassfunc = iscntrl; break; case STR_IS_PRINT: isclassfunc = isprint; break; case STR_IS_GRAPH: isclassfunc = isgraph; break; case STR_IS_PUNCT: isclassfunc = ispunct; break; default: return JIM_ERR; } for (i = 0; i < len; i++) { if (!isclassfunc(str[i])) { Jim_SetResultInt(interp, 0); return JIM_OK; } } Jim_SetResultInt(interp, 1); return JIM_OK; } /* ----------------------------------------------------------------------------- * Compared String Object * ---------------------------------------------------------------------------*/ /* This is strange object that allows to compare a C literal string * with a Jim object in very short time if the same comparison is done * multiple times. For example every time the [if] command is executed, * Jim has to check if a given argument is "else". This comparions if * the code has no errors are true most of the times, so we can cache * inside the object the pointer of the string of the last matching * comparison. Because most C compilers perform literal sharing, * so that: char *x = "foo", char *y = "foo", will lead to x == y, * this works pretty well even if comparisons are at different places * inside the C code. */ static const Jim_ObjType comparedStringObjType = { "compared-string", NULL, NULL, NULL, JIM_TYPE_REFERENCES, }; /* The only way this object is exposed to the API is via the following * function. Returns true if the string and the object string repr. * are the same, otherwise zero is returned. * * Note: this isn't binary safe, but it hardly needs to be.*/ int Jim_CompareStringImmediate(Jim_Interp *interp, Jim_Obj *objPtr, const char *str) { if (objPtr->typePtr == &comparedStringObjType && objPtr->internalRep.ptr == str) return 1; else { const char *objStr = Jim_String(objPtr); if (strcmp(str, objStr) != 0) return 0; if (objPtr->typePtr != &comparedStringObjType) { Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &comparedStringObjType; } objPtr->internalRep.ptr = (char *)str; /*ATTENTION: const cast */ return 1; } } static int qsortCompareStringPointers(const void *a, const void *b) { char *const *sa = (char *const *)a; char *const *sb = (char *const *)b; return strcmp(*sa, *sb); } /* ----------------------------------------------------------------------------- * Source Object * * This object is just a string from the language point of view, but * in the internal representation it contains the filename and line number * where this given token was read. This information is used by * Jim_EvalObj() if the object passed happens to be of type "source". * * This allows to propagate the information about line numbers and file * names and give error messages with absolute line numbers. * * Note that this object uses shared strings for filenames, and the * pointer to the filename together with the line number is taken into * the space for the "inline" internal representation of the Jim_Object, * so there is almost memory zero-overhead. * * Also the object will be converted to something else if the given * token it represents in the source file is not something to be * evaluated (not a script), and will be specialized in some other way, * so the time overhead is also null. * ---------------------------------------------------------------------------*/ static void FreeSourceInternalRep(Jim_Interp *interp, Jim_Obj *objPtr); static void DupSourceInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr); static const Jim_ObjType sourceObjType = { "source", FreeSourceInternalRep, DupSourceInternalRep, NULL, JIM_TYPE_REFERENCES, }; void FreeSourceInternalRep(Jim_Interp *interp, Jim_Obj *objPtr) { Jim_DecrRefCount(interp, objPtr->internalRep.sourceValue.fileNameObj); } void DupSourceInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr) { dupPtr->internalRep.sourceValue = srcPtr->internalRep.sourceValue; Jim_IncrRefCount(dupPtr->internalRep.sourceValue.fileNameObj); } static void JimSetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *fileNameObj, int lineNumber) { JimPanic((Jim_IsShared(objPtr), "JimSetSourceInfo called with shared object")); JimPanic((objPtr->typePtr == &sourceObjType, "JimSetSourceInfo called with non-source object")); Jim_IncrRefCount(fileNameObj); objPtr->internalRep.sourceValue.fileNameObj = fileNameObj; objPtr->internalRep.sourceValue.lineNumber = lineNumber; objPtr->typePtr = &sourceObjType; } /* ----------------------------------------------------------------------------- * Script Object * ---------------------------------------------------------------------------*/ static const Jim_ObjType scriptLineObjType = { "scriptline", NULL, NULL, NULL, 0, }; static Jim_Obj *JimNewScriptLineObj(Jim_Interp *interp, int argc, int line) { Jim_Obj *objPtr; #ifdef DEBUG_SHOW_SCRIPT char buf[100]; snprintf(buf, sizeof(buf), "line=%d, argc=%d", line, argc); objPtr = Jim_NewStringObj(interp, buf, -1); #else objPtr = Jim_NewEmptyStringObj(interp); #endif objPtr->typePtr = &scriptLineObjType; objPtr->internalRep.scriptLineValue.argc = argc; objPtr->internalRep.scriptLineValue.line = line; return objPtr; } #define JIM_CMDSTRUCT_EXPAND -1 static void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr); static void DupScriptInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr); static int SetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr, struct JimParseResult *result); static const Jim_ObjType scriptObjType = { "script", FreeScriptInternalRep, DupScriptInternalRep, NULL, JIM_TYPE_REFERENCES, }; /* The ScriptToken structure represents every token into a scriptObj. * Every token contains an associated Jim_Obj that can be specialized * by commands operating on it. */ typedef struct ScriptToken { int type; Jim_Obj *objPtr; } ScriptToken; /* This is the script object internal representation. An array of * ScriptToken structures, including a pre-computed representation of the * command length and arguments. * * For example the script: * * puts hello * set $i $x$y [foo]BAR * * will produce a ScriptObj with the following Tokens: * * LIN 2 * ESC puts * ESC hello * LIN 4 * ESC set * VAR i * WRD 2 * VAR x * VAR y * WRD 2 * CMD foo * ESC BAR * * "puts hello" has two args (LIN 2), composed of single tokens. * (Note that the WRD token is omitted for the common case of a single token.) * * "set $i $x$y [foo]BAR" has four (LIN 4) args, the first word * has 1 token (ESC SET), and the last has two tokens (WRD 2 CMD foo ESC BAR) * * The precomputation of the command structure makes Jim_Eval() faster, * and simpler because there aren't dynamic lengths / allocations. * * -- {expand}/{*} handling -- * * Expand is handled in a special way. * * If a "word" begins with {*}, the word token count is -ve. * * For example the command: * * list {*}{a b} * * Will produce the following cmdstruct array: * * LIN 2 * ESC list * WRD -1 * STR a b * * Note that the 'LIN' token also contains the source information for the * first word of the line for error reporting purposes * * -- the substFlags field of the structure -- * * The scriptObj structure is used to represent both "script" objects * and "subst" objects. In the second case, the there are no LIN and WRD * tokens. Instead SEP and EOL tokens are added as-is. * In addition, the field 'substFlags' is used to represent the flags used to turn * the string into the internal representation used to perform the * substitution. If this flags are not what the application requires * the scriptObj is created again. For example the script: * * subst -nocommands $string * subst -novariables $string * * Will recreate the internal representation of the $string object * two times. */ typedef struct ScriptObj { int len; /* Length as number of tokens. */ ScriptToken *token; /* Tokens array. */ int substFlags; /* flags used for the compilation of "subst" objects */ int inUse; /* Used to share a ScriptObj. Currently only used by Jim_EvalObj() as protection against shimmering of the currently evaluated object. */ Jim_Obj *fileNameObj; int firstline; /* Line number of the first line */ int linenr; /* Line number of the current line */ } ScriptObj; void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr) { int i; struct ScriptObj *script = (void *)objPtr->internalRep.ptr; script->inUse--; if (script->inUse != 0) return; for (i = 0; i < script->len; i++) { Jim_DecrRefCount(interp, script->token[i].objPtr); } Jim_Free(script->token); Jim_DecrRefCount(interp, script->fileNameObj); Jim_Free(script); } void DupScriptInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr) { JIM_NOTUSED(interp); JIM_NOTUSED(srcPtr); /* Just returns an simple string. */ dupPtr->typePtr = NULL; } /* A simple parser token. * All the simple tokens for the script point into the same script string rep. */ typedef struct { const char *token; /* Pointer to the start of the token */ int len; /* Length of this token */ int type; /* Token type */ int line; /* Line number */ } ParseToken; /* A list of parsed tokens representing a script. * Tokens are added to this list as the script is parsed. * It grows as needed. */ typedef struct { /* Start with a statically allocated list of tokens which will be expanded with realloc if needed */ ParseToken *list; /* Array of tokens */ int size; /* Current size of the list */ int count; /* Number of entries used */ ParseToken static_list[20]; /* Small initial token space to avoid allocation */ } ParseTokenList; static void ScriptTokenListInit(ParseTokenList *tokenlist) { tokenlist->list = tokenlist->static_list; tokenlist->size = sizeof(tokenlist->static_list) / sizeof(ParseToken); tokenlist->count = 0; } static void ScriptTokenListFree(ParseTokenList *tokenlist) { if (tokenlist->list != tokenlist->static_list) { Jim_Free(tokenlist->list); } } /** * Adds the new token to the tokenlist. * The token has the given length, type and line number. * The token list is resized as necessary. */ static void ScriptAddToken(ParseTokenList *tokenlist, const char *token, int len, int type, int line) { ParseToken *t; if (tokenlist->count == tokenlist->size) { /* Resize the list */ tokenlist->size *= 2; if (tokenlist->list != tokenlist->static_list) { tokenlist->list = Jim_Realloc(tokenlist->list, tokenlist->size * sizeof(*tokenlist->list)); } else { /* The list needs to become allocated */ tokenlist->list = Jim_Alloc(tokenlist->size * sizeof(*tokenlist->list)); memcpy(tokenlist->list, tokenlist->static_list, tokenlist->count * sizeof(*tokenlist->list)); } } t = &tokenlist->list[tokenlist->count++]; t->token = token; t->len = len; t->type = type; t->line = line; } /* Counts the number of adjoining non-separator. * * Returns -ve if the first token is the expansion * operator (in which case the count doesn't include * that token). */ static int JimCountWordTokens(ParseToken *t) { int expand = 1; int count = 0; /* Is the first word {*} or {expand}? */ if (t->type == JIM_TT_STR && !TOKEN_IS_SEP(t[1].type)) { if ((t->len == 1 && *t->token == '*') || (t->len == 6 && strncmp(t->token, "expand", 6) == 0)) { /* Create an expand token */ expand = -1; t++; } } /* Now count non-separator words */ while (!TOKEN_IS_SEP(t->type)) { t++; count++; } return count * expand; } /** * Create a script/subst object from the given token. */ static Jim_Obj *JimMakeScriptObj(Jim_Interp *interp, const ParseToken *t) { Jim_Obj *objPtr; if (t->type == JIM_TT_ESC && memchr(t->token, '\\', t->len) != NULL) { /* Convert the backlash escapes . */ int len = t->len; char *str = Jim_Alloc(len + 1); len = JimEscape(str, t->token, len); objPtr = Jim_NewStringObjNoAlloc(interp, str, len); } else { /* REVIST: Strictly, JIM_TT_STR should replace * with a single space. This is currently not done. */ objPtr = Jim_NewStringObj(interp, t->token, t->len); } return objPtr; } /** * Takes a tokenlist and creates the allocated list of script tokens * in script->token, of length script->len. * * Unnecessary tokens are discarded, and LINE and WORD tokens are inserted * as required. * * Also sets script->line to the line number of the first token */ static void ScriptObjAddTokens(Jim_Interp *interp, struct ScriptObj *script, ParseTokenList *tokenlist) { int i; struct ScriptToken *token; /* Number of tokens so far for the current command */ int lineargs = 0; /* This is the first token for the current command */ ScriptToken *linefirst; int count; int linenr; #ifdef DEBUG_SHOW_SCRIPT_TOKENS printf("==== Tokens ====\n"); for (i = 0; i < tokenlist->count; i++) { printf("[%2d]@%d %s '%.*s'\n", i, tokenlist->list[i].line, jim_tt_name(tokenlist->list[i].type), tokenlist->list[i].len, tokenlist->list[i].token); } #endif /* May need up to one extra script token for each EOL in the worst case */ count = tokenlist->count; for (i = 0; i < tokenlist->count; i++) { if (tokenlist->list[i].type == JIM_TT_EOL) { count++; } } linenr = script->firstline = tokenlist->list[0].line; token = script->token = Jim_Alloc(sizeof(ScriptToken) * count); /* This is the first token for the current command */ linefirst = token++; for (i = 0; i < tokenlist->count; ) { /* Look ahead to find out how many tokens make up the next word */ int wordtokens; /* Skip any leading separators */ while (tokenlist->list[i].type == JIM_TT_SEP) { i++; } wordtokens = JimCountWordTokens(tokenlist->list + i); if (wordtokens == 0) { /* None, so at end of line */ if (lineargs) { linefirst->type = JIM_TT_LINE; linefirst->objPtr = JimNewScriptLineObj(interp, lineargs, linenr); Jim_IncrRefCount(linefirst->objPtr); /* Reset for new line */ lineargs = 0; linefirst = token++; } i++; continue; } else if (wordtokens != 1) { /* More than 1, or {expand}, so insert a WORD token */ token->type = JIM_TT_WORD; token->objPtr = Jim_NewIntObj(interp, wordtokens); Jim_IncrRefCount(token->objPtr); token++; if (wordtokens < 0) { /* Skip the expand token */ i++; wordtokens = -wordtokens - 1; lineargs--; } } if (lineargs == 0) { /* First real token on the line, so record the line number */ linenr = tokenlist->list[i].line; } lineargs++; /* Add each non-separator word token to the line */ while (wordtokens--) { const ParseToken *t = &tokenlist->list[i++]; token->type = t->type; token->objPtr = JimMakeScriptObj(interp, t); Jim_IncrRefCount(token->objPtr); /* Every object is initially a string, but the * internal type may be specialized during execution of the * script. */ JimSetSourceInfo(interp, token->objPtr, script->fileNameObj, t->line); token++; } } if (lineargs == 0) { token--; } script->len = token - script->token; assert(script->len < count); #ifdef DEBUG_SHOW_SCRIPT printf("==== Script (%s) ====\n", Jim_String(script->fileNameObj)); for (i = 0; i < script->len; i++) { const ScriptToken *t = &script->token[i]; printf("[%2d] %s %s\n", i, jim_tt_name(t->type), Jim_String(t->objPtr)); } #endif } /** * Similar to ScriptObjAddTokens(), but for subst objects. */ static void SubstObjAddTokens(Jim_Interp *interp, struct ScriptObj *script, ParseTokenList *tokenlist) { int i; struct ScriptToken *token; token = script->token = Jim_Alloc(sizeof(ScriptToken) * tokenlist->count); for (i = 0; i < tokenlist->count; i++) { const ParseToken *t = &tokenlist->list[i]; /* Create a token for 't' */ token->type = t->type; token->objPtr = JimMakeScriptObj(interp, t); Jim_IncrRefCount(token->objPtr); token++; } script->len = i; } /* This method takes the string representation of an object * as a Tcl script, and generates the pre-parsed internal representation * of the script. */ static int SetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr, struct JimParseResult *result) { int scriptTextLen; const char *scriptText = Jim_GetString(objPtr, &scriptTextLen); struct JimParserCtx parser; struct ScriptObj *script; ParseTokenList tokenlist; int line = 1; /* Try to get information about filename / line number */ if (objPtr->typePtr == &sourceObjType) { line = objPtr->internalRep.sourceValue.lineNumber; } /* Initially parse the script into tokens (in tokenlist) */ ScriptTokenListInit(&tokenlist); JimParserInit(&parser, scriptText, scriptTextLen, line); while (!parser.eof) { JimParseScript(&parser); ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt, parser.tline); } if (result && parser.missing != ' ') { ScriptTokenListFree(&tokenlist); result->missing = parser.missing; result->line = parser.missingline; return JIM_ERR; } /* Add a final EOF token */ ScriptAddToken(&tokenlist, scriptText + scriptTextLen, 0, JIM_TT_EOF, 0); /* Create the "real" script tokens from the initial token list */ script = Jim_Alloc(sizeof(*script)); memset(script, 0, sizeof(*script)); script->inUse = 1; if (objPtr->typePtr == &sourceObjType) { script->fileNameObj = objPtr->internalRep.sourceValue.fileNameObj; } else { script->fileNameObj = interp->emptyObj; } Jim_IncrRefCount(script->fileNameObj); ScriptObjAddTokens(interp, script, &tokenlist); /* No longer need the token list */ ScriptTokenListFree(&tokenlist); /* Free the old internal rep and set the new one. */ Jim_FreeIntRep(interp, objPtr); Jim_SetIntRepPtr(objPtr, script); objPtr->typePtr = &scriptObjType; return JIM_OK; } ScriptObj *Jim_GetScript(Jim_Interp *interp, Jim_Obj *objPtr) { if (objPtr == interp->emptyObj) { /* Avoid converting emptyObj to a script. use nullScriptObj instead. */ objPtr = interp->nullScriptObj; } if (objPtr->typePtr != &scriptObjType || ((struct ScriptObj *)Jim_GetIntRepPtr(objPtr))->substFlags) { SetScriptFromAny(interp, objPtr, NULL); } return (ScriptObj *) Jim_GetIntRepPtr(objPtr); } /* ----------------------------------------------------------------------------- * Commands * ---------------------------------------------------------------------------*/ static void JimIncrCmdRefCount(Jim_Cmd *cmdPtr) { cmdPtr->inUse++; } static void JimDecrCmdRefCount(Jim_Interp *interp, Jim_Cmd *cmdPtr) { if (--cmdPtr->inUse == 0) { if (cmdPtr->isproc) { Jim_DecrRefCount(interp, cmdPtr->u.proc.argListObjPtr); Jim_DecrRefCount(interp, cmdPtr->u.proc.bodyObjPtr); Jim_DecrRefCount(interp, cmdPtr->u.proc.nsObj); if (cmdPtr->u.proc.staticVars) { Jim_FreeHashTable(cmdPtr->u.proc.staticVars); Jim_Free(cmdPtr->u.proc.staticVars); } } else { /* native (C) */ if (cmdPtr->u.native.delProc) { cmdPtr->u.native.delProc(interp, cmdPtr->u.native.privData); } } if (cmdPtr->prevCmd) { /* Delete any pushed command too */ JimDecrCmdRefCount(interp, cmdPtr->prevCmd); } Jim_Free(cmdPtr); } } /* Variables HashTable Type. * * Keys are dynamic allocated strings, Values are Jim_Var structures. */ /* Variables HashTable Type. * * Keys are dynamic allocated strings, Values are Jim_Var structures. */ static void JimVariablesHTValDestructor(void *interp, void *val) { Jim_DecrRefCount(interp, ((Jim_Var *)val)->objPtr); Jim_Free(val); } static const Jim_HashTableType JimVariablesHashTableType = { JimStringCopyHTHashFunction, /* hash function */ JimStringCopyHTDup, /* key dup */ NULL, /* val dup */ JimStringCopyHTKeyCompare, /* key compare */ JimStringCopyHTKeyDestructor, /* key destructor */ JimVariablesHTValDestructor /* val destructor */ }; /* Commands HashTable Type. * * Keys are dynamic allocated strings, Values are Jim_Cmd structures. */ static void JimCommandsHT_ValDestructor(void *interp, void *val) { JimDecrCmdRefCount(interp, val); } static const Jim_HashTableType JimCommandsHashTableType = { JimStringCopyHTHashFunction, /* hash function */ JimStringCopyHTDup, /* key dup */ NULL, /* val dup */ JimStringCopyHTKeyCompare, /* key compare */ JimStringCopyHTKeyDestructor, /* key destructor */ JimCommandsHT_ValDestructor /* val destructor */ }; /* ------------------------- Commands related functions --------------------- */ #ifdef jim_ext_namespace /** * Returns the "unscoped" version of the given namespace. * That is, the fully qualfied name without the leading :: * The returned value is either nsObj, or an object with a zero ref count. */ static Jim_Obj *JimQualifyNameObj(Jim_Interp *interp, Jim_Obj *nsObj) { const char *name = Jim_String(nsObj); if (name[0] == ':' && name[1] == ':') { /* This command is being defined in the global namespace */ while (*++name == ':') { } nsObj = Jim_NewStringObj(interp, name, -1); } else if (Jim_Length(interp->framePtr->nsObj)) { /* This command is being defined in a non-global namespace */ nsObj = Jim_DuplicateObj(interp, interp->framePtr->nsObj); Jim_AppendStrings(interp, nsObj, "::", name, NULL); } return nsObj; } /** * An efficient version of JimQualifyNameObj() where the name is * available (and needed) as a 'const char *'. * Avoids creating an object if not necessary. * The object stored in *objPtrPtr should be disposed of with JimFreeQualifiedName() after use. */ static const char *JimQualifyName(Jim_Interp *interp, const char *name, Jim_Obj **objPtrPtr) { Jim_Obj *objPtr = interp->emptyObj; if (name[0] == ':' && name[1] == ':') { /* This command is being defined in the global namespace */ while (*++name == ':') { } } else if (Jim_Length(interp->framePtr->nsObj)) { /* This command is being defined in a non-global namespace */ objPtr = Jim_DuplicateObj(interp, interp->framePtr->nsObj); Jim_AppendStrings(interp, objPtr, "::", name, NULL); name = Jim_String(objPtr); } Jim_IncrRefCount(objPtr); *objPtrPtr = objPtr; return name; } #define JimFreeQualifiedName(INTERP, OBJ) Jim_DecrRefCount((INTERP), (OBJ)) #else /* We can be more efficient in the no-namespace case */ #define JimQualifyName(INTERP, NAME, DUMMY) (((NAME)[0] == ':' && (NAME)[1] == ':') ? (NAME) + 2 : (NAME)) #define JimFreeQualifiedName(INTERP, DUMMY) (void)(DUMMY) #endif static int JimCreateCommand(Jim_Interp *interp, const char *name, Jim_Cmd *cmd) { /* It may already exist, so we try to delete the old one. * Note that reference count means that it won't be deleted yet if * it exists in the call stack. * * BUT, if 'local' is in force, instead of deleting the existing * proc, we stash a reference to the old proc here. */ Jim_HashEntry *he = Jim_FindHashEntry(&interp->commands, name); if (he) { /* There was an old cmd with the same name, * so this requires a 'proc epoch' update. */ /* If a procedure with the same name didn't exist there is no need * to increment the 'proc epoch' because creation of a new procedure * can never affect existing cached commands. We don't do * negative caching. */ Jim_InterpIncrProcEpoch(interp); } if (he && interp->local) { /* Push this command over the top of the previous one */ cmd->prevCmd = he->u.val; he->u.val = cmd; } else { if (he) { /* Replace the existing command */ Jim_DeleteHashEntry(&interp->commands, name); } Jim_AddHashEntry(&interp->commands, name, cmd); } return JIM_OK; } int Jim_CreateCommand(Jim_Interp *interp, const char *cmdNameStr, Jim_CmdProc cmdProc, void *privData, Jim_DelCmdProc delProc) { Jim_Cmd *cmdPtr = Jim_Alloc(sizeof(*cmdPtr)); /* Store the new details for this command */ memset(cmdPtr, 0, sizeof(*cmdPtr)); cmdPtr->inUse = 1; cmdPtr->u.native.delProc = delProc; cmdPtr->u.native.cmdProc = cmdProc; cmdPtr->u.native.privData = privData; JimCreateCommand(interp, cmdNameStr, cmdPtr); return JIM_OK; } static int JimCreateProcedureStatics(Jim_Interp *interp, Jim_Cmd *cmdPtr, Jim_Obj *staticsListObjPtr) { int len, i; len = Jim_ListLength(interp, staticsListObjPtr); if (len == 0) { return JIM_OK; } cmdPtr->u.proc.staticVars = Jim_Alloc(sizeof(Jim_HashTable)); Jim_InitHashTable(cmdPtr->u.proc.staticVars, &JimVariablesHashTableType, interp); for (i = 0; i < len; i++) { Jim_Obj *objPtr = NULL, *initObjPtr = NULL, *nameObjPtr = NULL; Jim_Var *varPtr; int subLen; Jim_ListIndex(interp, staticsListObjPtr, i, &objPtr, JIM_NONE); /* Check if it's composed of two elements. */ subLen = Jim_ListLength(interp, objPtr); if (subLen == 1 || subLen == 2) { /* Try to get the variable value from the current * environment. */ Jim_ListIndex(interp, objPtr, 0, &nameObjPtr, JIM_NONE); if (subLen == 1) { initObjPtr = Jim_GetVariable(interp, nameObjPtr, JIM_NONE); if (initObjPtr == NULL) { Jim_SetResultFormatted(interp, "variable for initialization of static \"%#s\" not found in the local context", nameObjPtr); return JIM_ERR; } } else { Jim_ListIndex(interp, objPtr, 1, &initObjPtr, JIM_NONE); } if (JimValidName(interp, "static variable", nameObjPtr) != JIM_OK) { return JIM_ERR; } varPtr = Jim_Alloc(sizeof(*varPtr)); varPtr->objPtr = initObjPtr; Jim_IncrRefCount(initObjPtr); varPtr->linkFramePtr = NULL; if (Jim_AddHashEntry(cmdPtr->u.proc.staticVars, Jim_String(nameObjPtr), varPtr) != JIM_OK) { Jim_SetResultFormatted(interp, "static variable name \"%#s\" duplicated in statics list", nameObjPtr); Jim_DecrRefCount(interp, initObjPtr); Jim_Free(varPtr); return JIM_ERR; } } else { Jim_SetResultFormatted(interp, "too many fields in static specifier \"%#s\"", objPtr); return JIM_ERR; } } return JIM_OK; } static void JimUpdateProcNamespace(Jim_Interp *interp, Jim_Cmd *cmdPtr, const char *cmdname) { #ifdef jim_ext_namespace if (cmdPtr->isproc) { /* XXX: Really need JimNamespaceSplit() */ const char *pt = strrchr(cmdname, ':'); if (pt && pt != cmdname && pt[-1] == ':') { Jim_DecrRefCount(interp, cmdPtr->u.proc.nsObj); cmdPtr->u.proc.nsObj = Jim_NewStringObj(interp, cmdname, pt - cmdname - 1); Jim_IncrRefCount(cmdPtr->u.proc.nsObj); if (Jim_FindHashEntry(&interp->commands, pt + 1)) { /* This commands shadows a global command, so a proc epoch update is required */ Jim_InterpIncrProcEpoch(interp); } } } #endif } static Jim_Cmd *JimCreateProcedureCmd(Jim_Interp *interp, Jim_Obj *argListObjPtr, Jim_Obj *staticsListObjPtr, Jim_Obj *bodyObjPtr, Jim_Obj *nsObj) { Jim_Cmd *cmdPtr; int argListLen; int i; argListLen = Jim_ListLength(interp, argListObjPtr); /* Allocate space for both the command pointer and the arg list */ cmdPtr = Jim_Alloc(sizeof(*cmdPtr) + sizeof(struct Jim_ProcArg) * argListLen); memset(cmdPtr, 0, sizeof(*cmdPtr)); cmdPtr->inUse = 1; cmdPtr->isproc = 1; cmdPtr->u.proc.argListObjPtr = argListObjPtr; cmdPtr->u.proc.argListLen = argListLen; cmdPtr->u.proc.bodyObjPtr = bodyObjPtr; cmdPtr->u.proc.argsPos = -1; cmdPtr->u.proc.arglist = (struct Jim_ProcArg *)(cmdPtr + 1); cmdPtr->u.proc.nsObj = nsObj ? nsObj : interp->emptyObj; Jim_IncrRefCount(argListObjPtr); Jim_IncrRefCount(bodyObjPtr); Jim_IncrRefCount(cmdPtr->u.proc.nsObj); /* Create the statics hash table. */ if (staticsListObjPtr && JimCreateProcedureStatics(interp, cmdPtr, staticsListObjPtr) != JIM_OK) { goto err; } /* Parse the args out into arglist, validating as we go */ /* Examine the argument list for default parameters and 'args' */ for (i = 0; i < argListLen; i++) { Jim_Obj *argPtr; Jim_Obj *nameObjPtr; Jim_Obj *defaultObjPtr; int len; /* Examine a parameter */ Jim_ListIndex(interp, argListObjPtr, i, &argPtr, JIM_NONE); len = Jim_ListLength(interp, argPtr); if (len == 0) { Jim_SetResultString(interp, "argument with no name", -1); err: JimDecrCmdRefCount(interp, cmdPtr); return NULL; } if (len > 2) { Jim_SetResultFormatted(interp, "too many fields in argument specifier \"%#s\"", argPtr); goto err; } if (len == 2) { /* Optional parameter */ Jim_ListIndex(interp, argPtr, 0, &nameObjPtr, JIM_NONE); Jim_ListIndex(interp, argPtr, 1, &defaultObjPtr, JIM_NONE); } else { /* Required parameter */ nameObjPtr = argPtr; defaultObjPtr = NULL; } if (Jim_CompareStringImmediate(interp, nameObjPtr, "args")) { if (cmdPtr->u.proc.argsPos >= 0) { Jim_SetResultString(interp, "'args' specified more than once", -1); goto err; } cmdPtr->u.proc.argsPos = i; } else { if (len == 2) { cmdPtr->u.proc.optArity++; } else { cmdPtr->u.proc.reqArity++; } } cmdPtr->u.proc.arglist[i].nameObjPtr = nameObjPtr; cmdPtr->u.proc.arglist[i].defaultObjPtr = defaultObjPtr; } return cmdPtr; } int Jim_DeleteCommand(Jim_Interp *interp, const char *name) { int ret = JIM_OK; Jim_Obj *qualifiedNameObj; const char *qualname = JimQualifyName(interp, name, &qualifiedNameObj); if (Jim_DeleteHashEntry(&interp->commands, qualname) == JIM_ERR) { Jim_SetResultFormatted(interp, "can't delete \"%s\": command doesn't exist", name); ret = JIM_ERR; } else { Jim_InterpIncrProcEpoch(interp); } JimFreeQualifiedName(interp, qualifiedNameObj); return ret; } int Jim_RenameCommand(Jim_Interp *interp, const char *oldName, const char *newName) { int ret = JIM_ERR; Jim_HashEntry *he; Jim_Cmd *cmdPtr; Jim_Obj *qualifiedOldNameObj; Jim_Obj *qualifiedNewNameObj; const char *fqold; const char *fqnew; if (newName[0] == 0) { return Jim_DeleteCommand(interp, oldName); } fqold = JimQualifyName(interp, oldName, &qualifiedOldNameObj); fqnew = JimQualifyName(interp, newName, &qualifiedNewNameObj); /* Does it exist? */ he = Jim_FindHashEntry(&interp->commands, fqold); if (he == NULL) { Jim_SetResultFormatted(interp, "can't rename \"%s\": command doesn't exist", oldName); } else if (Jim_FindHashEntry(&interp->commands, fqnew)) { Jim_SetResultFormatted(interp, "can't rename to \"%s\": command already exists", newName); } else { /* Add the new name first */ cmdPtr = he->u.val; JimIncrCmdRefCount(cmdPtr); JimUpdateProcNamespace(interp, cmdPtr, fqnew); Jim_AddHashEntry(&interp->commands, fqnew, cmdPtr); /* Now remove the old name */ Jim_DeleteHashEntry(&interp->commands, fqold); /* Increment the epoch */ Jim_InterpIncrProcEpoch(interp); ret = JIM_OK; } JimFreeQualifiedName(interp, qualifiedOldNameObj); JimFreeQualifiedName(interp, qualifiedNewNameObj); return ret; } /* ----------------------------------------------------------------------------- * Command object * ---------------------------------------------------------------------------*/ static void FreeCommandInternalRep(Jim_Interp *interp, Jim_Obj *objPtr) { Jim_DecrRefCount(interp, objPtr->internalRep.cmdValue.nsObj); } static void DupCommandInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr) { dupPtr->internalRep.cmdValue = srcPtr->internalRep.cmdValue; dupPtr->typePtr = srcPtr->typePtr; Jim_IncrRefCount(dupPtr->internalRep.cmdValue.nsObj); } static const Jim_ObjType commandObjType = { "command", FreeCommandInternalRep, DupCommandInternalRep, NULL, JIM_TYPE_REFERENCES, }; /* This function returns the command structure for the command name * stored in objPtr. It tries to specialize the objPtr to contain * a cached info instead to perform the lookup into the hash table * every time. The information cached may not be uptodate, in such * a case the lookup is performed and the cache updated. * * Respects the 'upcall' setting */ Jim_Cmd *Jim_GetCommand(Jim_Interp *interp, Jim_Obj *objPtr, int flags) { Jim_Cmd *cmd; /* In order to be valid, the proc epoch must match and * the lookup must have occurred in the same namespace */ if (objPtr->typePtr != &commandObjType || objPtr->internalRep.cmdValue.procEpoch != interp->procEpoch #ifdef jim_ext_namespace || !Jim_StringEqObj(objPtr->internalRep.cmdValue.nsObj, interp->framePtr->nsObj) #endif ) { /* Not cached or out of date, so lookup */ /* Do we need to try the local namespace? */ const char *name = Jim_String(objPtr); Jim_HashEntry *he; if (name[0] == ':' && name[1] == ':') { while (*++name == ':') { } } #ifdef jim_ext_namespace else if (Jim_Length(interp->framePtr->nsObj)) { /* This command is being defined in a non-global namespace */ Jim_Obj *nameObj = Jim_DuplicateObj(interp, interp->framePtr->nsObj); Jim_AppendStrings(interp, nameObj, "::", name, NULL); he = Jim_FindHashEntry(&interp->commands, Jim_String(nameObj)); Jim_FreeNewObj(interp, nameObj); if (he) { goto found; } } #endif /* Lookup in the global namespace */ he = Jim_FindHashEntry(&interp->commands, name); if (he == NULL) { if (flags & JIM_ERRMSG) { Jim_SetResultFormatted(interp, "invalid command name \"%#s\"", objPtr); } return NULL; } #ifdef jim_ext_namespace found: #endif cmd = (Jim_Cmd *)he->u.val; /* Free the old internal repr and set the new one. */ Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &commandObjType; objPtr->internalRep.cmdValue.procEpoch = interp->procEpoch; objPtr->internalRep.cmdValue.cmdPtr = cmd; objPtr->internalRep.cmdValue.nsObj = interp->framePtr->nsObj; Jim_IncrRefCount(interp->framePtr->nsObj); } else { cmd = objPtr->internalRep.cmdValue.cmdPtr; } while (cmd->u.proc.upcall) { cmd = cmd->prevCmd; } return cmd; } /* ----------------------------------------------------------------------------- * Variables * ---------------------------------------------------------------------------*/ /* ----------------------------------------------------------------------------- * Variable object * ---------------------------------------------------------------------------*/ #define JIM_DICT_SUGAR 100 /* Only returned by SetVariableFromAny() */ static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr); static const Jim_ObjType variableObjType = { "variable", NULL, NULL, NULL, JIM_TYPE_REFERENCES, }; /** * Check that the name does not contain embedded nulls. * * Variable and procedure names are maniplated as null terminated strings, so * don't allow names with embedded nulls. */ static int JimValidName(Jim_Interp *interp, const char *type, Jim_Obj *nameObjPtr) { /* Variable names and proc names can't contain embedded nulls */ if (nameObjPtr->typePtr != &variableObjType) { int len; const char *str = Jim_GetString(nameObjPtr, &len); if (memchr(str, '\0', len)) { Jim_SetResultFormatted(interp, "%s name contains embedded null", type); return JIM_ERR; } } return JIM_OK; } /* This method should be called only by the variable API. * It returns JIM_OK on success (variable already exists), * JIM_ERR if it does not exists, JIM_DICT_SUGAR if it's not * a variable name, but syntax glue for [dict] i.e. the last * character is ')' */ static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr) { const char *varName; Jim_CallFrame *framePtr; Jim_HashEntry *he; int global; int len; /* Check if the object is already an uptodate variable */ if (objPtr->typePtr == &variableObjType) { framePtr = objPtr->internalRep.varValue.global ? interp->topFramePtr : interp->framePtr; if (objPtr->internalRep.varValue.callFrameId == framePtr->id) { /* nothing to do */ return JIM_OK; } /* Need to re-resolve the variable in the updated callframe */ } else if (objPtr->typePtr == &dictSubstObjType) { return JIM_DICT_SUGAR; } else if (JimValidName(interp, "variable", objPtr) != JIM_OK) { return JIM_ERR; } varName = Jim_GetString(objPtr, &len); /* Make sure it's not syntax glue to get/set dict. */ if (len && varName[len - 1] == ')' && strchr(varName, '(') != NULL) { return JIM_DICT_SUGAR; } if (varName[0] == ':' && varName[1] == ':') { while (*++varName == ':') { } global = 1; framePtr = interp->topFramePtr; } else { global = 0; framePtr = interp->framePtr; } /* Resolve this name in the variables hash table */ he = Jim_FindHashEntry(&framePtr->vars, varName); if (he == NULL) { if (!global && framePtr->staticVars) { /* Try with static vars. */ he = Jim_FindHashEntry(framePtr->staticVars, varName); } if (he == NULL) { return JIM_ERR; } } /* Free the old internal repr and set the new one. */ Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &variableObjType; objPtr->internalRep.varValue.callFrameId = framePtr->id; objPtr->internalRep.varValue.varPtr = he->u.val; objPtr->internalRep.varValue.global = global; return JIM_OK; } /* -------------------- Variables related functions ------------------------- */ static int JimDictSugarSet(Jim_Interp *interp, Jim_Obj *ObjPtr, Jim_Obj *valObjPtr); static Jim_Obj *JimDictSugarGet(Jim_Interp *interp, Jim_Obj *ObjPtr, int flags); static Jim_Var *JimCreateVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr) { const char *name; Jim_CallFrame *framePtr; int global; /* New variable to create */ Jim_Var *var = Jim_Alloc(sizeof(*var)); var->objPtr = valObjPtr; Jim_IncrRefCount(valObjPtr); var->linkFramePtr = NULL; name = Jim_String(nameObjPtr); if (name[0] == ':' && name[1] == ':') { while (*++name == ':') { } framePtr = interp->topFramePtr; global = 1; } else { framePtr = interp->framePtr; global = 0; } /* Insert the new variable */ Jim_AddHashEntry(&framePtr->vars, name, var); /* Make the object int rep a variable */ Jim_FreeIntRep(interp, nameObjPtr); nameObjPtr->typePtr = &variableObjType; nameObjPtr->internalRep.varValue.callFrameId = framePtr->id; nameObjPtr->internalRep.varValue.varPtr = var; nameObjPtr->internalRep.varValue.global = global; return var; } /* For now that's dummy. Variables lookup should be optimized * in many ways, with caching of lookups, and possibly with * a table of pre-allocated vars in every CallFrame for local vars. * All the caching should also have an 'epoch' mechanism similar * to the one used by Tcl for procedures lookup caching. */ int Jim_SetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr) { int err; Jim_Var *var; switch (SetVariableFromAny(interp, nameObjPtr)) { case JIM_DICT_SUGAR: return JimDictSugarSet(interp, nameObjPtr, valObjPtr); case JIM_ERR: if (JimValidName(interp, "variable", nameObjPtr) != JIM_OK) { return JIM_ERR; } JimCreateVariable(interp, nameObjPtr, valObjPtr); break; case JIM_OK: var = nameObjPtr->internalRep.varValue.varPtr; if (var->linkFramePtr == NULL) { Jim_IncrRefCount(valObjPtr); Jim_DecrRefCount(interp, var->objPtr); var->objPtr = valObjPtr; } else { /* Else handle the link */ Jim_CallFrame *savedCallFrame; savedCallFrame = interp->framePtr; interp->framePtr = var->linkFramePtr; err = Jim_SetVariable(interp, var->objPtr, valObjPtr); interp->framePtr = savedCallFrame; if (err != JIM_OK) return err; } } return JIM_OK; } int Jim_SetVariableStr(Jim_Interp *interp, const char *name, Jim_Obj *objPtr) { Jim_Obj *nameObjPtr; int result; nameObjPtr = Jim_NewStringObj(interp, name, -1); Jim_IncrRefCount(nameObjPtr); result = Jim_SetVariable(interp, nameObjPtr, objPtr); Jim_DecrRefCount(interp, nameObjPtr); return result; } int Jim_SetGlobalVariableStr(Jim_Interp *interp, const char *name, Jim_Obj *objPtr) { Jim_CallFrame *savedFramePtr; int result; savedFramePtr = interp->framePtr; interp->framePtr = interp->topFramePtr; result = Jim_SetVariableStr(interp, name, objPtr); interp->framePtr = savedFramePtr; return result; } int Jim_SetVariableStrWithStr(Jim_Interp *interp, const char *name, const char *val) { Jim_Obj *nameObjPtr, *valObjPtr; int result; nameObjPtr = Jim_NewStringObj(interp, name, -1); valObjPtr = Jim_NewStringObj(interp, val, -1); Jim_IncrRefCount(nameObjPtr); Jim_IncrRefCount(valObjPtr); result = Jim_SetVariable(interp, nameObjPtr, valObjPtr); Jim_DecrRefCount(interp, nameObjPtr); Jim_DecrRefCount(interp, valObjPtr); return result; } int Jim_SetVariableLink(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *targetNameObjPtr, Jim_CallFrame *targetCallFrame) { const char *varName; const char *targetName; Jim_CallFrame *framePtr; Jim_Var *varPtr; /* Check for an existing variable or link */ switch (SetVariableFromAny(interp, nameObjPtr)) { case JIM_DICT_SUGAR: /* XXX: This message seem unnecessarily verbose, but it matches Tcl */ Jim_SetResultFormatted(interp, "bad variable name \"%#s\": upvar won't create a scalar variable that looks like an array element", nameObjPtr); return JIM_ERR; case JIM_OK: varPtr = nameObjPtr->internalRep.varValue.varPtr; if (varPtr->linkFramePtr == NULL) { Jim_SetResultFormatted(interp, "variable \"%#s\" already exists", nameObjPtr); return JIM_ERR; } /* It exists, but is a link, so first delete the link */ varPtr->linkFramePtr = NULL; break; } /* Resolve the call frames for both variables */ /* XXX: SetVariableFromAny() already did this! */ varName = Jim_String(nameObjPtr); if (varName[0] == ':' && varName[1] == ':') { while (*++varName == ':') { } /* Linking a global var does nothing */ framePtr = interp->topFramePtr; } else { framePtr = interp->framePtr; } targetName = Jim_String(targetNameObjPtr); if (targetName[0] == ':' && targetName[1] == ':') { while (*++targetName == ':') { } targetNameObjPtr = Jim_NewStringObj(interp, targetName, -1); targetCallFrame = interp->topFramePtr; } Jim_IncrRefCount(targetNameObjPtr); if (framePtr->level < targetCallFrame->level) { Jim_SetResultFormatted(interp, "bad variable name \"%#s\": upvar won't create namespace variable that refers to procedure variable", nameObjPtr); Jim_DecrRefCount(interp, targetNameObjPtr); return JIM_ERR; } /* Check for cycles. */ if (framePtr == targetCallFrame) { Jim_Obj *objPtr = targetNameObjPtr; /* Cycles are only possible with 'uplevel 0' */ while (1) { if (strcmp(Jim_String(objPtr), varName) == 0) { Jim_SetResultString(interp, "can't upvar from variable to itself", -1); Jim_DecrRefCount(interp, targetNameObjPtr); return JIM_ERR; } if (SetVariableFromAny(interp, objPtr) != JIM_OK) break; varPtr = objPtr->internalRep.varValue.varPtr; if (varPtr->linkFramePtr != targetCallFrame) break; objPtr = varPtr->objPtr; } } /* Perform the binding */ Jim_SetVariable(interp, nameObjPtr, targetNameObjPtr); /* We are now sure 'nameObjPtr' type is variableObjType */ nameObjPtr->internalRep.varValue.varPtr->linkFramePtr = targetCallFrame; Jim_DecrRefCount(interp, targetNameObjPtr); return JIM_OK; } /* Return the Jim_Obj pointer associated with a variable name, * or NULL if the variable was not found in the current context. * The same optimization discussed in the comment to the * 'SetVariable' function should apply here. * * If JIM_UNSHARED is set and the variable is an array element (dict sugar) * in a dictionary which is shared, the array variable value is duplicated first. * This allows the array element to be updated (e.g. append, lappend) without * affecting other references to the dictionary. */ Jim_Obj *Jim_GetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags) { switch (SetVariableFromAny(interp, nameObjPtr)) { case JIM_OK:{ Jim_Var *varPtr = nameObjPtr->internalRep.varValue.varPtr; if (varPtr->linkFramePtr == NULL) { return varPtr->objPtr; } else { Jim_Obj *objPtr; /* The variable is a link? Resolve it. */ Jim_CallFrame *savedCallFrame = interp->framePtr; interp->framePtr = varPtr->linkFramePtr; objPtr = Jim_GetVariable(interp, varPtr->objPtr, flags); interp->framePtr = savedCallFrame; if (objPtr) { return objPtr; } /* Error, so fall through to the error message */ } } break; case JIM_DICT_SUGAR: /* [dict] syntax sugar. */ return JimDictSugarGet(interp, nameObjPtr, flags); } if (flags & JIM_ERRMSG) { Jim_SetResultFormatted(interp, "can't read \"%#s\": no such variable", nameObjPtr); } return NULL; } Jim_Obj *Jim_GetGlobalVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags) { Jim_CallFrame *savedFramePtr; Jim_Obj *objPtr; savedFramePtr = interp->framePtr; interp->framePtr = interp->topFramePtr; objPtr = Jim_GetVariable(interp, nameObjPtr, flags); interp->framePtr = savedFramePtr; return objPtr; } Jim_Obj *Jim_GetVariableStr(Jim_Interp *interp, const char *name, int flags) { Jim_Obj *nameObjPtr, *varObjPtr; nameObjPtr = Jim_NewStringObj(interp, name, -1); Jim_IncrRefCount(nameObjPtr); varObjPtr = Jim_GetVariable(interp, nameObjPtr, flags); Jim_DecrRefCount(interp, nameObjPtr); return varObjPtr; } Jim_Obj *Jim_GetGlobalVariableStr(Jim_Interp *interp, const char *name, int flags) { Jim_CallFrame *savedFramePtr; Jim_Obj *objPtr; savedFramePtr = interp->framePtr; interp->framePtr = interp->topFramePtr; objPtr = Jim_GetVariableStr(interp, name, flags); interp->framePtr = savedFramePtr; return objPtr; } /* Unset a variable. * Note: On success unset invalidates all the variable objects created * in the current call frame incrementing. */ int Jim_UnsetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags) { Jim_Var *varPtr; int retval; Jim_CallFrame *framePtr; retval = SetVariableFromAny(interp, nameObjPtr); if (retval == JIM_DICT_SUGAR) { /* [dict] syntax sugar. */ return JimDictSugarSet(interp, nameObjPtr, NULL); } else if (retval == JIM_OK) { varPtr = nameObjPtr->internalRep.varValue.varPtr; /* If it's a link call UnsetVariable recursively */ if (varPtr->linkFramePtr) { framePtr = interp->framePtr; interp->framePtr = varPtr->linkFramePtr; retval = Jim_UnsetVariable(interp, varPtr->objPtr, JIM_NONE); interp->framePtr = framePtr; } else { const char *name = Jim_String(nameObjPtr); if (nameObjPtr->internalRep.varValue.global) { name += 2; framePtr = interp->topFramePtr; } else { framePtr = interp->framePtr; } retval = Jim_DeleteHashEntry(&framePtr->vars, name); if (retval == JIM_OK) { /* Change the callframe id, invalidating var lookup caching */ JimChangeCallFrameId(interp, framePtr); } } } if (retval != JIM_OK && (flags & JIM_ERRMSG)) { Jim_SetResultFormatted(interp, "can't unset \"%#s\": no such variable", nameObjPtr); } return retval; } /* ---------- Dict syntax sugar (similar to array Tcl syntax) -------------- */ /* Given a variable name for [dict] operation syntax sugar, * this function returns two objects, the first with the name * of the variable to set, and the second with the rispective key. * For example "foo(bar)" will return objects with string repr. of * "foo" and "bar". * * The returned objects have refcount = 1. The function can't fail. */ static void JimDictSugarParseVarKey(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj **varPtrPtr, Jim_Obj **keyPtrPtr) { const char *str, *p; int len, keyLen; Jim_Obj *varObjPtr, *keyObjPtr; str = Jim_GetString(objPtr, &len); p = strchr(str, '('); JimPanic((p == NULL, "JimDictSugarParseVarKey() called for non-dict-sugar (%s)", str)); varObjPtr = Jim_NewStringObj(interp, str, p - str); p++; keyLen = (str + len) - p; if (str[len - 1] == ')') { keyLen--; } /* Create the objects with the variable name and key. */ keyObjPtr = Jim_NewStringObj(interp, p, keyLen); Jim_IncrRefCount(varObjPtr); Jim_IncrRefCount(keyObjPtr); *varPtrPtr = varObjPtr; *keyPtrPtr = keyObjPtr; } /* Helper of Jim_SetVariable() to deal with dict-syntax variable names. * Also used by Jim_UnsetVariable() with valObjPtr = NULL. */ static int JimDictSugarSet(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *valObjPtr) { int err; SetDictSubstFromAny(interp, objPtr); err = Jim_SetDictKeysVector(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr, &objPtr->internalRep.dictSubstValue.indexObjPtr, 1, valObjPtr, JIM_MUSTEXIST); if (err == JIM_OK) { /* Don't keep an extra ref to the result */ Jim_SetEmptyResult(interp); } else { if (!valObjPtr) { /* Better error message for unset a(2) where a exists but a(2) doesn't */ if (Jim_GetVariable(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr, JIM_NONE)) { Jim_SetResultFormatted(interp, "can't unset \"%#s\": no such element in array", objPtr); return err; } } /* Make the error more informative and Tcl-compatible */ Jim_SetResultFormatted(interp, "can't %s \"%#s\": variable isn't array", (valObjPtr ? "set" : "unset"), objPtr); } return err; } /** * Expands the array variable (dict sugar) and returns the result, or NULL on error. * * If JIM_UNSHARED is set and the dictionary is shared, it will be duplicated * and stored back to the variable before expansion. */ static Jim_Obj *JimDictExpandArrayVariable(Jim_Interp *interp, Jim_Obj *varObjPtr, Jim_Obj *keyObjPtr, int flags) { Jim_Obj *dictObjPtr; Jim_Obj *resObjPtr = NULL; int ret; dictObjPtr = Jim_GetVariable(interp, varObjPtr, JIM_ERRMSG); if (!dictObjPtr) { return NULL; } ret = Jim_DictKey(interp, dictObjPtr, keyObjPtr, &resObjPtr, JIM_NONE); if (ret != JIM_OK) { resObjPtr = NULL; if (ret < 0) { Jim_SetResultFormatted(interp, "can't read \"%#s(%#s)\": variable isn't array", varObjPtr, keyObjPtr); } else { Jim_SetResultFormatted(interp, "can't read \"%#s(%#s)\": no such element in array", varObjPtr, keyObjPtr); } } else if ((flags & JIM_UNSHARED) && Jim_IsShared(dictObjPtr)) { dictObjPtr = Jim_DuplicateObj(interp, dictObjPtr); if (Jim_SetVariable(interp, varObjPtr, dictObjPtr) != JIM_OK) { /* This can probably never happen */ JimPanic((1, "SetVariable failed for JIM_UNSHARED")); } /* We know that the key exists. Get the result in the now-unshared dictionary */ Jim_DictKey(interp, dictObjPtr, keyObjPtr, &resObjPtr, JIM_NONE); } return resObjPtr; } /* Helper of Jim_GetVariable() to deal with dict-syntax variable names */ static Jim_Obj *JimDictSugarGet(Jim_Interp *interp, Jim_Obj *objPtr, int flags) { SetDictSubstFromAny(interp, objPtr); return JimDictExpandArrayVariable(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr, objPtr->internalRep.dictSubstValue.indexObjPtr, flags); } /* --------- $var(INDEX) substitution, using a specialized object ----------- */ void FreeDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *objPtr) { Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr); Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.indexObjPtr); } void DupDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr) { JIM_NOTUSED(interp); dupPtr->internalRep.dictSubstValue.varNameObjPtr = srcPtr->internalRep.dictSubstValue.varNameObjPtr; dupPtr->internalRep.dictSubstValue.indexObjPtr = srcPtr->internalRep.dictSubstValue.indexObjPtr; dupPtr->typePtr = &dictSubstObjType; } /* Note: The object *must* be in dict-sugar format */ static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr) { if (objPtr->typePtr != &dictSubstObjType) { Jim_Obj *varObjPtr, *keyObjPtr; if (objPtr->typePtr == &interpolatedObjType) { /* An interpolated object in dict-sugar form */ varObjPtr = objPtr->internalRep.dictSubstValue.varNameObjPtr; keyObjPtr = objPtr->internalRep.dictSubstValue.indexObjPtr; Jim_IncrRefCount(varObjPtr); Jim_IncrRefCount(keyObjPtr); } else { JimDictSugarParseVarKey(interp, objPtr, &varObjPtr, &keyObjPtr); } Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &dictSubstObjType; objPtr->internalRep.dictSubstValue.varNameObjPtr = varObjPtr; objPtr->internalRep.dictSubstValue.indexObjPtr = keyObjPtr; } } /* This function is used to expand [dict get] sugar in the form * of $var(INDEX). The function is mainly used by Jim_EvalObj() * to deal with tokens of type JIM_TT_DICTSUGAR. objPtr points to an * object that is *guaranteed* to be in the form VARNAME(INDEX). * The 'index' part is [subst]ituted, and is used to lookup a key inside * the [dict]ionary contained in variable VARNAME. */ static Jim_Obj *JimExpandDictSugar(Jim_Interp *interp, Jim_Obj *objPtr) { Jim_Obj *resObjPtr = NULL; Jim_Obj *substKeyObjPtr = NULL; SetDictSubstFromAny(interp, objPtr); if (Jim_SubstObj(interp, objPtr->internalRep.dictSubstValue.indexObjPtr, &substKeyObjPtr, JIM_NONE) != JIM_OK) { return NULL; } Jim_IncrRefCount(substKeyObjPtr); resObjPtr = JimDictExpandArrayVariable(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr, substKeyObjPtr, 0); Jim_DecrRefCount(interp, substKeyObjPtr); return resObjPtr; } static Jim_Obj *JimExpandExprSugar(Jim_Interp *interp, Jim_Obj *objPtr) { Jim_Obj *resultObjPtr; if (Jim_EvalExpression(interp, objPtr, &resultObjPtr) == JIM_OK) { /* Note that the result has a ref count of 1, but we need a ref count of 0 */ resultObjPtr->refCount--; return resultObjPtr; } return NULL; } /* ----------------------------------------------------------------------------- * CallFrame * ---------------------------------------------------------------------------*/ static Jim_CallFrame *JimCreateCallFrame(Jim_Interp *interp, Jim_CallFrame *parent, Jim_Obj *nsObj) { Jim_CallFrame *cf; if (interp->freeFramesList) { cf = interp->freeFramesList; interp->freeFramesList = cf->next; } else { cf = Jim_Alloc(sizeof(*cf)); cf->vars.table = NULL; } cf->id = interp->callFrameEpoch++; cf->parent = parent; cf->level = parent ? parent->level + 1 : 0; cf->argv = NULL; cf->argc = 0; cf->procArgsObjPtr = NULL; cf->procBodyObjPtr = NULL; cf->next = NULL; cf->staticVars = NULL; cf->localCommands = NULL; cf->nsObj = nsObj; Jim_IncrRefCount(nsObj); if (cf->vars.table == NULL) Jim_InitHashTable(&cf->vars, &JimVariablesHashTableType, interp); return cf; } /* Used to invalidate every caching related to callframe stability. */ static void JimChangeCallFrameId(Jim_Interp *interp, Jim_CallFrame *cf) { cf->id = interp->callFrameEpoch++; } static int JimDeleteLocalProcs(Jim_Interp *interp, Jim_Stack *localCommands) { /* Delete any local procs */ if (localCommands) { Jim_Obj *cmdNameObj; while ((cmdNameObj = Jim_StackPop(localCommands)) != NULL) { Jim_HashEntry *he; Jim_Obj *fqObjName; const char *fqname = JimQualifyName(interp, Jim_String(cmdNameObj), &fqObjName); he = Jim_FindHashEntry(&interp->commands, fqname); if (he) { Jim_Cmd *cmd = he->u.val; if (cmd->prevCmd) { Jim_Cmd *prevCmd = cmd->prevCmd; cmd->prevCmd = NULL; /* Delete the old command */ JimDecrCmdRefCount(interp, cmd); /* And restore the original */ he->u.val = prevCmd; } else { Jim_DeleteHashEntry(&interp->commands, fqname); Jim_InterpIncrProcEpoch(interp); } } Jim_DecrRefCount(interp, cmdNameObj); JimFreeQualifiedName(interp, fqObjName); } Jim_FreeStack(localCommands); Jim_Free(localCommands); } return JIM_OK; } #define JIM_FCF_NONE 0 /* no flags */ #define JIM_FCF_NOHT 1 /* don't free the hash table */ static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int flags) { if (cf->procArgsObjPtr) Jim_DecrRefCount(interp, cf->procArgsObjPtr); if (cf->procBodyObjPtr) Jim_DecrRefCount(interp, cf->procBodyObjPtr); Jim_DecrRefCount(interp, cf->nsObj); if (!(flags & JIM_FCF_NOHT)) Jim_FreeHashTable(&cf->vars); else { int i; Jim_HashEntry **table = cf->vars.table, *he; for (i = 0; i < JIM_HT_INITIAL_SIZE; i++) { he = table[i]; while (he != NULL) { Jim_HashEntry *nextEntry = he->next; Jim_Var *varPtr = (void *)he->u.val; Jim_DecrRefCount(interp, varPtr->objPtr); Jim_Free(he->u.val); Jim_Free((void *)he->key); /* ATTENTION: const cast */ Jim_Free(he); table[i] = NULL; he = nextEntry; } } cf->vars.used = 0; } JimDeleteLocalProcs(interp, cf->localCommands); cf->next = interp->freeFramesList; interp->freeFramesList = cf; } /* ----------------------------------------------------------------------------- * References * ---------------------------------------------------------------------------*/ #ifdef JIM_REFERENCES /* References HashTable Type. * * Keys are unsigned long integers, dynamically allocated for now but in the * future it's worth to cache this 4 bytes objects. Values are pointers * to Jim_References. */ static void JimReferencesHTValDestructor(void *interp, void *val) { Jim_Reference *refPtr = (void *)val; Jim_DecrRefCount(interp, refPtr->objPtr); if (refPtr->finalizerCmdNamePtr != NULL) { Jim_DecrRefCount(interp, refPtr->finalizerCmdNamePtr); } Jim_Free(val); } static unsigned int JimReferencesHTHashFunction(const void *key) { /* Only the least significant bits are used. */ const unsigned long *widePtr = key; unsigned int intValue = (unsigned int)*widePtr; return Jim_IntHashFunction(intValue); } static void *JimReferencesHTKeyDup(void *privdata, const void *key) { void *copy = Jim_Alloc(sizeof(unsigned long)); JIM_NOTUSED(privdata); memcpy(copy, key, sizeof(unsigned long)); return copy; } static int JimReferencesHTKeyCompare(void *privdata, const void *key1, const void *key2) { JIM_NOTUSED(privdata); return memcmp(key1, key2, sizeof(unsigned long)) == 0; } static void JimReferencesHTKeyDestructor(void *privdata, void *key) { JIM_NOTUSED(privdata); Jim_Free(key); } static const Jim_HashTableType JimReferencesHashTableType = { JimReferencesHTHashFunction, /* hash function */ JimReferencesHTKeyDup, /* key dup */ NULL, /* val dup */ JimReferencesHTKeyCompare, /* key compare */ JimReferencesHTKeyDestructor, /* key destructor */ JimReferencesHTValDestructor /* val destructor */ }; /* ----------------------------------------------------------------------------- * Reference object type and References API * ---------------------------------------------------------------------------*/ /* The string representation of references has two features in order * to make the GC faster. The first is that every reference starts * with a non common character '<', in order to make the string matching * faster. The second is that the reference string rep is 42 characters * in length, this allows to avoid to check every object with a string * repr < 42, and usually there aren't many of these objects. */ #define JIM_REFERENCE_SPACE (35+JIM_REFERENCE_TAGLEN) static int JimFormatReference(char *buf, Jim_Reference *refPtr, unsigned long id) { const char *fmt = ".%020lu>"; sprintf(buf, fmt, refPtr->tag, id); return JIM_REFERENCE_SPACE; } static void UpdateStringOfReference(struct Jim_Obj *objPtr); static const Jim_ObjType referenceObjType = { "reference", NULL, NULL, UpdateStringOfReference, JIM_TYPE_REFERENCES, }; void UpdateStringOfReference(struct Jim_Obj *objPtr) { int len; char buf[JIM_REFERENCE_SPACE + 1]; Jim_Reference *refPtr; refPtr = objPtr->internalRep.refValue.refPtr; len = JimFormatReference(buf, refPtr, objPtr->internalRep.refValue.id); objPtr->bytes = Jim_Alloc(len + 1); memcpy(objPtr->bytes, buf, len + 1); objPtr->length = len; } /* returns true if 'c' is a valid reference tag character. * i.e. inside the range [_a-zA-Z0-9] */ static int isrefchar(int c) { return (c == '_' || isalnum(c)); } static int SetReferenceFromAny(Jim_Interp *interp, Jim_Obj *objPtr) { unsigned long value; int i, len; const char *str, *start, *end; char refId[21]; Jim_Reference *refPtr; Jim_HashEntry *he; char *endptr; /* Get the string representation */ str = Jim_GetString(objPtr, &len); /* Check if it looks like a reference */ if (len < JIM_REFERENCE_SPACE) goto badformat; /* Trim spaces */ start = str; end = str + len - 1; while (*start == ' ') start++; while (*end == ' ' && end > start) end--; if (end - start + 1 != JIM_REFERENCE_SPACE) goto badformat; /* .%020> */ if (memcmp(start, "references, &value); if (he == NULL) { Jim_SetResultFormatted(interp, "invalid reference id \"%#s\"", objPtr); return JIM_ERR; } refPtr = he->u.val; /* Free the old internal repr and set the new one. */ Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &referenceObjType; objPtr->internalRep.refValue.id = value; objPtr->internalRep.refValue.refPtr = refPtr; return JIM_OK; badformat: Jim_SetResultFormatted(interp, "expected reference but got \"%#s\"", objPtr); return JIM_ERR; } /* Returns a new reference pointing to objPtr, having cmdNamePtr * as finalizer command (or NULL if there is no finalizer). * The returned reference object has refcount = 0. */ Jim_Obj *Jim_NewReference(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *tagPtr, Jim_Obj *cmdNamePtr) { struct Jim_Reference *refPtr; unsigned long id; Jim_Obj *refObjPtr; const char *tag; int tagLen, i; /* Perform the Garbage Collection if needed. */ Jim_CollectIfNeeded(interp); refPtr = Jim_Alloc(sizeof(*refPtr)); refPtr->objPtr = objPtr; Jim_IncrRefCount(objPtr); refPtr->finalizerCmdNamePtr = cmdNamePtr; if (cmdNamePtr) Jim_IncrRefCount(cmdNamePtr); id = interp->referenceNextId++; Jim_AddHashEntry(&interp->references, &id, refPtr); refObjPtr = Jim_NewObj(interp); refObjPtr->typePtr = &referenceObjType; refObjPtr->bytes = NULL; refObjPtr->internalRep.refValue.id = id; refObjPtr->internalRep.refValue.refPtr = refPtr; interp->referenceNextId++; /* Set the tag. Trimmed at JIM_REFERENCE_TAGLEN. Everything * that does not pass the 'isrefchar' test is replaced with '_' */ tag = Jim_GetString(tagPtr, &tagLen); if (tagLen > JIM_REFERENCE_TAGLEN) tagLen = JIM_REFERENCE_TAGLEN; for (i = 0; i < JIM_REFERENCE_TAGLEN; i++) { if (i < tagLen && isrefchar(tag[i])) refPtr->tag[i] = tag[i]; else refPtr->tag[i] = '_'; } refPtr->tag[JIM_REFERENCE_TAGLEN] = '\0'; return refObjPtr; } Jim_Reference *Jim_GetReference(Jim_Interp *interp, Jim_Obj *objPtr) { if (objPtr->typePtr != &referenceObjType && SetReferenceFromAny(interp, objPtr) == JIM_ERR) return NULL; return objPtr->internalRep.refValue.refPtr; } int Jim_SetFinalizer(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *cmdNamePtr) { Jim_Reference *refPtr; if ((refPtr = Jim_GetReference(interp, objPtr)) == NULL) return JIM_ERR; Jim_IncrRefCount(cmdNamePtr); if (refPtr->finalizerCmdNamePtr) Jim_DecrRefCount(interp, refPtr->finalizerCmdNamePtr); refPtr->finalizerCmdNamePtr = cmdNamePtr; return JIM_OK; } int Jim_GetFinalizer(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj **cmdNamePtrPtr) { Jim_Reference *refPtr; if ((refPtr = Jim_GetReference(interp, objPtr)) == NULL) return JIM_ERR; *cmdNamePtrPtr = refPtr->finalizerCmdNamePtr; return JIM_OK; } /* ----------------------------------------------------------------------------- * References Garbage Collection * ---------------------------------------------------------------------------*/ /* This the hash table type for the "MARK" phase of the GC */ static const Jim_HashTableType JimRefMarkHashTableType = { JimReferencesHTHashFunction, /* hash function */ JimReferencesHTKeyDup, /* key dup */ NULL, /* val dup */ JimReferencesHTKeyCompare, /* key compare */ JimReferencesHTKeyDestructor, /* key destructor */ NULL /* val destructor */ }; /* Performs the garbage collection. */ int Jim_Collect(Jim_Interp *interp) { int collected = 0; #ifndef JIM_BOOTSTRAP Jim_HashTable marks; Jim_HashTableIterator htiter; Jim_HashEntry *he; Jim_Obj *objPtr; /* Avoid recursive calls */ if (interp->lastCollectId == -1) { /* Jim_Collect() already running. Return just now. */ return 0; } interp->lastCollectId = -1; /* Mark all the references found into the 'mark' hash table. * The references are searched in every live object that * is of a type that can contain references. */ Jim_InitHashTable(&marks, &JimRefMarkHashTableType, NULL); objPtr = interp->liveList; while (objPtr) { if (objPtr->typePtr == NULL || objPtr->typePtr->flags & JIM_TYPE_REFERENCES) { const char *str, *p; int len; /* If the object is of type reference, to get the * Id is simple... */ if (objPtr->typePtr == &referenceObjType) { Jim_AddHashEntry(&marks, &objPtr->internalRep.refValue.id, NULL); #ifdef JIM_DEBUG_GC printf("MARK (reference): %d refcount: %d" JIM_NL, (int)objPtr->internalRep.refValue.id, objPtr->refCount); #endif objPtr = objPtr->nextObjPtr; continue; } /* Get the string repr of the object we want * to scan for references. */ p = str = Jim_GetString(objPtr, &len); /* Skip objects too little to contain references. */ if (len < JIM_REFERENCE_SPACE) { objPtr = objPtr->nextObjPtr; continue; } /* Extract references from the object string repr. */ while (1) { int i; unsigned long id; if ((p = strstr(p, "nextObjPtr; } /* Run the references hash table to destroy every reference that * is not referenced outside (not present in the mark HT). */ JimInitHashTableIterator(&interp->references, &htiter); while ((he = Jim_NextHashEntry(&htiter)) != NULL) { const unsigned long *refId; Jim_Reference *refPtr; refId = he->key; /* Check if in the mark phase we encountered * this reference. */ if (Jim_FindHashEntry(&marks, refId) == NULL) { #ifdef JIM_DEBUG_GC printf("COLLECTING %d" JIM_NL, (int)*refId); #endif collected++; /* Drop the reference, but call the * finalizer first if registered. */ refPtr = he->u.val; if (refPtr->finalizerCmdNamePtr) { char *refstr = Jim_Alloc(JIM_REFERENCE_SPACE + 1); Jim_Obj *objv[3], *oldResult; JimFormatReference(refstr, refPtr, *refId); objv[0] = refPtr->finalizerCmdNamePtr; objv[1] = Jim_NewStringObjNoAlloc(interp, refstr, JIM_REFERENCE_SPACE); objv[2] = refPtr->objPtr; /* Drop the reference itself */ /* Avoid the finaliser being freed here */ Jim_IncrRefCount(objv[0]); /* Don't remove the reference from the hash table just yet * since that will free refPtr, and hence refPtr->objPtr */ /* Call the finalizer. Errors ignored. */ oldResult = interp->result; Jim_IncrRefCount(oldResult); Jim_EvalObjVector(interp, 3, objv); Jim_SetResult(interp, oldResult); Jim_DecrRefCount(interp, oldResult); Jim_DeleteHashEntry(&interp->references, refId); Jim_DecrRefCount(interp, objv[0]); } else { Jim_DeleteHashEntry(&interp->references, refId); } } } Jim_FreeHashTable(&marks); interp->lastCollectId = interp->referenceNextId; interp->lastCollectTime = time(NULL); #endif /* JIM_BOOTSTRAP */ return collected; } #define JIM_COLLECT_ID_PERIOD 5000 #define JIM_COLLECT_TIME_PERIOD 300 void Jim_CollectIfNeeded(Jim_Interp *interp) { unsigned long elapsedId; int elapsedTime; elapsedId = interp->referenceNextId - interp->lastCollectId; elapsedTime = time(NULL) - interp->lastCollectTime; if (elapsedId > JIM_COLLECT_ID_PERIOD || elapsedTime > JIM_COLLECT_TIME_PERIOD) { Jim_Collect(interp); } } #endif static int JimIsBigEndian(void) { union { unsigned short s; unsigned char c[2]; } uval = {0x0102}; return uval.c[0] == 1; } /* ----------------------------------------------------------------------------- * Interpreter related functions * ---------------------------------------------------------------------------*/ Jim_Interp *Jim_CreateInterp(void) { Jim_Interp *i = Jim_Alloc(sizeof(*i)); memset(i, 0, sizeof(*i)); i->maxCallFrameDepth = JIM_MAX_CALLFRAME_DEPTH; i->maxEvalDepth = JIM_MAX_EVAL_DEPTH; i->lastCollectTime = time(NULL); /* Note that we can create objects only after the * interpreter liveList and freeList pointers are * initialized to NULL. */ Jim_InitHashTable(&i->commands, &JimCommandsHashTableType, i); #ifdef JIM_REFERENCES Jim_InitHashTable(&i->references, &JimReferencesHashTableType, i); #endif Jim_InitHashTable(&i->assocData, &JimAssocDataHashTableType, i); Jim_InitHashTable(&i->packages, &JimPackageHashTableType, NULL); i->emptyObj = Jim_NewEmptyStringObj(i); i->trueObj = Jim_NewIntObj(i, 1); i->falseObj = Jim_NewIntObj(i, 0); i->framePtr = i->topFramePtr = JimCreateCallFrame(i, NULL, i->emptyObj); i->errorFileNameObj = i->emptyObj; i->result = i->emptyObj; i->stackTrace = Jim_NewListObj(i, NULL, 0); i->unknown = Jim_NewStringObj(i, "unknown", -1); i->errorProc = i->emptyObj; i->currentScriptObj = Jim_NewEmptyStringObj(i); i->nullScriptObj = Jim_NewEmptyStringObj(i); Jim_IncrRefCount(i->emptyObj); Jim_IncrRefCount(i->errorFileNameObj); Jim_IncrRefCount(i->result); Jim_IncrRefCount(i->stackTrace); Jim_IncrRefCount(i->unknown); Jim_IncrRefCount(i->currentScriptObj); Jim_IncrRefCount(i->nullScriptObj); Jim_IncrRefCount(i->errorProc); Jim_IncrRefCount(i->trueObj); Jim_IncrRefCount(i->falseObj); /* Initialize key variables every interpreter should contain */ Jim_SetVariableStrWithStr(i, JIM_LIBPATH, TCL_LIBRARY); Jim_SetVariableStrWithStr(i, JIM_INTERACTIVE, "0"); Jim_SetVariableStrWithStr(i, "tcl_platform(os)", TCL_PLATFORM_OS); Jim_SetVariableStrWithStr(i, "tcl_platform(platform)", TCL_PLATFORM_PLATFORM); Jim_SetVariableStrWithStr(i, "tcl_platform(pathSeparator)", TCL_PLATFORM_PATH_SEPARATOR); Jim_SetVariableStrWithStr(i, "tcl_platform(byteOrder)", JimIsBigEndian() ? "bigEndian" : "littleEndian"); Jim_SetVariableStrWithStr(i, "tcl_platform(threaded)", "0"); Jim_SetVariableStr(i, "tcl_platform(pointerSize)", Jim_NewIntObj(i, sizeof(void *))); Jim_SetVariableStr(i, "tcl_platform(wordSize)", Jim_NewIntObj(i, sizeof(jim_wide))); return i; } void Jim_FreeInterp(Jim_Interp *i) { Jim_CallFrame *cf = i->framePtr, *prevcf, *nextcf; Jim_Obj *objPtr, *nextObjPtr; Jim_DecrRefCount(i, i->emptyObj); Jim_DecrRefCount(i, i->trueObj); Jim_DecrRefCount(i, i->falseObj); Jim_DecrRefCount(i, i->result); Jim_DecrRefCount(i, i->stackTrace); Jim_DecrRefCount(i, i->errorProc); Jim_DecrRefCount(i, i->unknown); Jim_DecrRefCount(i, i->errorFileNameObj); Jim_DecrRefCount(i, i->currentScriptObj); Jim_DecrRefCount(i, i->nullScriptObj); Jim_FreeHashTable(&i->commands); #ifdef JIM_REFERENCES Jim_FreeHashTable(&i->references); #endif Jim_FreeHashTable(&i->packages); Jim_Free(i->prngState); Jim_FreeHashTable(&i->assocData); /* Free the call frames list */ while (cf) { prevcf = cf->parent; JimFreeCallFrame(i, cf, JIM_FCF_NONE); cf = prevcf; } /* Check that the live object list is empty, otherwise * there is a memory leak. */ if (i->liveList != NULL) { objPtr = i->liveList; printf(JIM_NL "-------------------------------------" JIM_NL); printf("Objects still in the free list:" JIM_NL); while (objPtr) { const char *type = objPtr->typePtr ? objPtr->typePtr->name : "string"; if (objPtr->bytes && strlen(objPtr->bytes) > 20) { printf("%p (%d) %-10s: '%.20s...'" JIM_NL, (void *)objPtr, objPtr->refCount, type, objPtr->bytes); } else { printf("%p (%d) %-10s: '%s'" JIM_NL, (void *)objPtr, objPtr->refCount, type, objPtr->bytes ? objPtr->bytes : "(null)"); } if (objPtr->typePtr == &sourceObjType) { printf("FILE %s LINE %d" JIM_NL, Jim_String(objPtr->internalRep.sourceValue.fileNameObj), objPtr->internalRep.sourceValue.lineNumber); } objPtr = objPtr->nextObjPtr; } printf("-------------------------------------" JIM_NL JIM_NL); JimPanic((1, "Live list non empty freeing the interpreter! Leak?")); } /* Free all the freed objects. */ objPtr = i->freeList; while (objPtr) { nextObjPtr = objPtr->nextObjPtr; Jim_Free(objPtr); objPtr = nextObjPtr; } /* Free cached CallFrame structures */ cf = i->freeFramesList; while (cf) { nextcf = cf->next; if (cf->vars.table != NULL) Jim_Free(cf->vars.table); Jim_Free(cf); cf = nextcf; } #ifdef jim_ext_load Jim_FreeLoadHandles(i); #endif /* Free the interpreter structure. */ Jim_Free(i); } /* Returns the call frame relative to the level represented by * levelObjPtr. If levelObjPtr == NULL, the * level is assumed to be '1'. * * This function accepts the 'level' argument in the form * of the commands [uplevel] and [upvar]. * * For a function accepting a relative integer as level suitable * for implementation of [info level ?level?] check the * JimGetCallFrameByInteger() function. * * Returns NULL on error. */ Jim_CallFrame *Jim_GetCallFrameByLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr) { long level; const char *str; Jim_CallFrame *framePtr; if (levelObjPtr) { str = Jim_String(levelObjPtr); if (str[0] == '#') { char *endptr; level = jim_strtol(str + 1, &endptr); if (str[1] == '\0' || endptr[0] != '\0') { level = -1; } } else { if (Jim_GetLong(interp, levelObjPtr, &level) != JIM_OK || level < 0) { level = -1; } else { /* Convert from a relative to an absolute level */ level = interp->framePtr->level - level; } } } else { str = "1"; /* Needed to format the error message. */ level = interp->framePtr->level - 1; } if (level == 0) { return interp->topFramePtr; } if (level > 0) { /* Lookup */ for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parent) { if (framePtr->level == level) { return framePtr; } } } Jim_SetResultFormatted(interp, "bad level \"%s\"", str); return NULL; } /* Similar to Jim_GetCallFrameByLevel() but the level is specified * as a relative integer like in the [info level ?level?] command. **/ static Jim_CallFrame *JimGetCallFrameByInteger(Jim_Interp *interp, Jim_Obj *levelObjPtr) { long level; Jim_CallFrame *framePtr; if (Jim_GetLong(interp, levelObjPtr, &level) == JIM_OK) { if (level <= 0) { /* Convert from a relative to an absolute level */ level = interp->framePtr->level + level; } if (level == 0) { return interp->topFramePtr; } /* Lookup */ for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parent) { if (framePtr->level == level) { return framePtr; } } } Jim_SetResultFormatted(interp, "bad level \"%#s\"", levelObjPtr); return NULL; } static void JimResetStackTrace(Jim_Interp *interp) { Jim_DecrRefCount(interp, interp->stackTrace); interp->stackTrace = Jim_NewListObj(interp, NULL, 0); Jim_IncrRefCount(interp->stackTrace); } static void JimSetStackTrace(Jim_Interp *interp, Jim_Obj *stackTraceObj) { int len; /* Increment reference first in case these are the same object */ Jim_IncrRefCount(stackTraceObj); Jim_DecrRefCount(interp, interp->stackTrace); interp->stackTrace = stackTraceObj; interp->errorFlag = 1; /* This is a bit ugly. * If the filename of the last entry of the stack trace is empty, * the next stack level should be added. */ len = Jim_ListLength(interp, interp->stackTrace); if (len >= 3) { Jim_Obj *filenameObj; Jim_ListIndex(interp, interp->stackTrace, len - 2, &filenameObj, JIM_NONE); Jim_GetString(filenameObj, &len); if (!Jim_Length(filenameObj)) { interp->addStackTrace = 1; } } } /* Returns 1 if the stack trace information was used or 0 if not */ static void JimAppendStackTrace(Jim_Interp *interp, const char *procname, Jim_Obj *fileNameObj, int linenr) { if (strcmp(procname, "unknown") == 0) { procname = ""; } if (!*procname && !Jim_Length(fileNameObj)) { /* No useful info here */ return; } if (Jim_IsShared(interp->stackTrace)) { Jim_DecrRefCount(interp, interp->stackTrace); interp->stackTrace = Jim_DuplicateObj(interp, interp->stackTrace); Jim_IncrRefCount(interp->stackTrace); } /* If we have no procname but the previous element did, merge with that frame */ if (!*procname && Jim_Length(fileNameObj)) { /* Just a filename. Check the previous entry */ int len = Jim_ListLength(interp, interp->stackTrace); if (len >= 3) { Jim_Obj *objPtr; if (Jim_ListIndex(interp, interp->stackTrace, len - 3, &objPtr, JIM_NONE) == JIM_OK && Jim_Length(objPtr)) { /* Yes, the previous level had procname */ if (Jim_ListIndex(interp, interp->stackTrace, len - 2, &objPtr, JIM_NONE) == JIM_OK && !Jim_Length(objPtr)) { /* But no filename, so merge the new info with that frame */ ListSetIndex(interp, interp->stackTrace, len - 2, fileNameObj, 0); ListSetIndex(interp, interp->stackTrace, len - 1, Jim_NewIntObj(interp, linenr), 0); return; } } } } Jim_ListAppendElement(interp, interp->stackTrace, Jim_NewStringObj(interp, procname, -1)); Jim_ListAppendElement(interp, interp->stackTrace, fileNameObj); Jim_ListAppendElement(interp, interp->stackTrace, Jim_NewIntObj(interp, linenr)); } int Jim_SetAssocData(Jim_Interp *interp, const char *key, Jim_InterpDeleteProc * delProc, void *data) { AssocDataValue *assocEntryPtr = (AssocDataValue *) Jim_Alloc(sizeof(AssocDataValue)); assocEntryPtr->delProc = delProc; assocEntryPtr->data = data; return Jim_AddHashEntry(&interp->assocData, key, assocEntryPtr); } void *Jim_GetAssocData(Jim_Interp *interp, const char *key) { Jim_HashEntry *entryPtr = Jim_FindHashEntry(&interp->assocData, key); if (entryPtr != NULL) { AssocDataValue *assocEntryPtr = (AssocDataValue *) entryPtr->u.val; return assocEntryPtr->data; } return NULL; } int Jim_DeleteAssocData(Jim_Interp *interp, const char *key) { return Jim_DeleteHashEntry(&interp->assocData, key); } int Jim_GetExitCode(Jim_Interp *interp) { return interp->exitCode; } /* ----------------------------------------------------------------------------- * Integer object * ---------------------------------------------------------------------------*/ static void UpdateStringOfInt(struct Jim_Obj *objPtr); static int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags); static const Jim_ObjType intObjType = { "int", NULL, NULL, UpdateStringOfInt, JIM_TYPE_NONE, }; /* A coerced double is closer to an int than a double. * It is an int value temporarily masquerading as a double value. * i.e. it has the same string value as an int and Jim_GetWide() * succeeds, but also Jim_GetDouble() returns the value directly. */ static const Jim_ObjType coercedDoubleObjType = { "coerced-double", NULL, NULL, UpdateStringOfInt, JIM_TYPE_NONE, }; static void UpdateStringOfInt(struct Jim_Obj *objPtr) { int len; char buf[JIM_INTEGER_SPACE + 1]; len = JimWideToString(buf, JimWideValue(objPtr)); objPtr->bytes = Jim_Alloc(len + 1); memcpy(objPtr->bytes, buf, len + 1); objPtr->length = len; } int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags) { jim_wide wideValue; const char *str; if (objPtr->typePtr == &coercedDoubleObjType) { /* Simple switcheroo */ objPtr->typePtr = &intObjType; return JIM_OK; } /* Get the string representation */ str = Jim_String(objPtr); /* Try to convert into a jim_wide */ if (Jim_StringToWide(str, &wideValue, 0) != JIM_OK) { if (flags & JIM_ERRMSG) { Jim_SetResultFormatted(interp, "expected integer but got \"%#s\"", objPtr); } return JIM_ERR; } if ((wideValue == JIM_WIDE_MIN || wideValue == JIM_WIDE_MAX) && errno == ERANGE) { Jim_SetResultString(interp, "Integer value too big to be represented", -1); return JIM_ERR; } /* Free the old internal repr and set the new one. */ Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &intObjType; objPtr->internalRep.wideValue = wideValue; return JIM_OK; } #ifdef JIM_OPTIMIZATION static int JimIsWide(Jim_Obj *objPtr) { return objPtr->typePtr == &intObjType; } #endif int Jim_GetWide(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr) { if (objPtr->typePtr != &intObjType && SetIntFromAny(interp, objPtr, JIM_ERRMSG) == JIM_ERR) return JIM_ERR; *widePtr = JimWideValue(objPtr); return JIM_OK; } /* Get a wide but does not set an error if the format is bad. */ static int JimGetWideNoErr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr) { if (objPtr->typePtr != &intObjType && SetIntFromAny(interp, objPtr, JIM_NONE) == JIM_ERR) return JIM_ERR; *widePtr = JimWideValue(objPtr); return JIM_OK; } int Jim_GetLong(Jim_Interp *interp, Jim_Obj *objPtr, long *longPtr) { jim_wide wideValue; int retval; retval = Jim_GetWide(interp, objPtr, &wideValue); if (retval == JIM_OK) { *longPtr = (long)wideValue; return JIM_OK; } return JIM_ERR; } Jim_Obj *Jim_NewIntObj(Jim_Interp *interp, jim_wide wideValue) { Jim_Obj *objPtr; objPtr = Jim_NewObj(interp); objPtr->typePtr = &intObjType; objPtr->bytes = NULL; objPtr->internalRep.wideValue = wideValue; return objPtr; } /* ----------------------------------------------------------------------------- * Double object * ---------------------------------------------------------------------------*/ #define JIM_DOUBLE_SPACE 30 static void UpdateStringOfDouble(struct Jim_Obj *objPtr); static int SetDoubleFromAny(Jim_Interp *interp, Jim_Obj *objPtr); static const Jim_ObjType doubleObjType = { "double", NULL, NULL, UpdateStringOfDouble, JIM_TYPE_NONE, }; void UpdateStringOfDouble(struct Jim_Obj *objPtr) { int len; char buf[JIM_DOUBLE_SPACE + 1]; len = Jim_DoubleToString(buf, objPtr->internalRep.doubleValue); objPtr->bytes = Jim_Alloc(len + 1); memcpy(objPtr->bytes, buf, len + 1); objPtr->length = len; } int SetDoubleFromAny(Jim_Interp *interp, Jim_Obj *objPtr) { double doubleValue; jim_wide wideValue; const char *str; /* Preserve the string representation. * Needed so we can convert back to int without loss */ str = Jim_String(objPtr); #ifdef HAVE_LONG_LONG /* Assume a 53 bit mantissa */ #define MIN_INT_IN_DOUBLE -(1LL << 53) #define MAX_INT_IN_DOUBLE -(MIN_INT_IN_DOUBLE + 1) if (objPtr->typePtr == &intObjType && JimWideValue(objPtr) >= MIN_INT_IN_DOUBLE && JimWideValue(objPtr) <= MAX_INT_IN_DOUBLE) { /* Direct conversion to coerced double */ objPtr->typePtr = &coercedDoubleObjType; return JIM_OK; } else #endif if (Jim_StringToWide(str, &wideValue, 10) == JIM_OK) { /* Managed to convert to an int, so we can use this as a cooerced double */ Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &coercedDoubleObjType; objPtr->internalRep.wideValue = wideValue; return JIM_OK; } else { /* Try to convert into a double */ if (Jim_StringToDouble(str, &doubleValue) != JIM_OK) { Jim_SetResultFormatted(interp, "expected number but got \"%#s\"", objPtr); return JIM_ERR; } /* Free the old internal repr and set the new one. */ Jim_FreeIntRep(interp, objPtr); } objPtr->typePtr = &doubleObjType; objPtr->internalRep.doubleValue = doubleValue; return JIM_OK; } int Jim_GetDouble(Jim_Interp *interp, Jim_Obj *objPtr, double *doublePtr) { if (objPtr->typePtr == &coercedDoubleObjType) { *doublePtr = JimWideValue(objPtr); return JIM_OK; } if (objPtr->typePtr != &doubleObjType && SetDoubleFromAny(interp, objPtr) == JIM_ERR) return JIM_ERR; if (objPtr->typePtr == &coercedDoubleObjType) { *doublePtr = JimWideValue(objPtr); } else { *doublePtr = objPtr->internalRep.doubleValue; } return JIM_OK; } Jim_Obj *Jim_NewDoubleObj(Jim_Interp *interp, double doubleValue) { Jim_Obj *objPtr; objPtr = Jim_NewObj(interp); objPtr->typePtr = &doubleObjType; objPtr->bytes = NULL; objPtr->internalRep.doubleValue = doubleValue; return objPtr; } /* ----------------------------------------------------------------------------- * List object * ---------------------------------------------------------------------------*/ static void ListInsertElements(Jim_Obj *listPtr, int idx, int elemc, Jim_Obj *const *elemVec); static void ListAppendElement(Jim_Obj *listPtr, Jim_Obj *objPtr); static void FreeListInternalRep(Jim_Interp *interp, Jim_Obj *objPtr); static void DupListInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr); static void UpdateStringOfList(struct Jim_Obj *objPtr); static int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr); /* Note that while the elements of the list may contain references, * the list object itself can't. This basically means that the * list object string representation as a whole can't contain references * that are not presents in the single elements. */ static const Jim_ObjType listObjType = { "list", FreeListInternalRep, DupListInternalRep, UpdateStringOfList, JIM_TYPE_NONE, }; void FreeListInternalRep(Jim_Interp *interp, Jim_Obj *objPtr) { int i; for (i = 0; i < objPtr->internalRep.listValue.len; i++) { Jim_DecrRefCount(interp, objPtr->internalRep.listValue.ele[i]); } Jim_Free(objPtr->internalRep.listValue.ele); } void DupListInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr) { int i; JIM_NOTUSED(interp); dupPtr->internalRep.listValue.len = srcPtr->internalRep.listValue.len; dupPtr->internalRep.listValue.maxLen = srcPtr->internalRep.listValue.maxLen; dupPtr->internalRep.listValue.ele = Jim_Alloc(sizeof(Jim_Obj *) * srcPtr->internalRep.listValue.maxLen); memcpy(dupPtr->internalRep.listValue.ele, srcPtr->internalRep.listValue.ele, sizeof(Jim_Obj *) * srcPtr->internalRep.listValue.len); for (i = 0; i < dupPtr->internalRep.listValue.len; i++) { Jim_IncrRefCount(dupPtr->internalRep.listValue.ele[i]); } dupPtr->typePtr = &listObjType; } /* The following function checks if a given string can be encoded * into a list element without any kind of quoting, surrounded by braces, * or using escapes to quote. */ #define JIM_ELESTR_SIMPLE 0 #define JIM_ELESTR_BRACE 1 #define JIM_ELESTR_QUOTE 2 static unsigned char ListElementQuotingType(const char *s, int len) { int i, level, blevel, trySimple = 1; /* Try with the SIMPLE case */ if (len == 0) return JIM_ELESTR_BRACE; if (s[0] == '"' || s[0] == '{') { trySimple = 0; goto testbrace; } for (i = 0; i < len; i++) { switch (s[i]) { case ' ': case '$': case '"': case '[': case ']': case ';': case '\\': case '\r': case '\n': case '\t': case '\f': case '\v': trySimple = 0; case '{': case '}': goto testbrace; } } return JIM_ELESTR_SIMPLE; testbrace: /* Test if it's possible to do with braces */ if (s[len - 1] == '\\') return JIM_ELESTR_QUOTE; level = 0; blevel = 0; for (i = 0; i < len; i++) { switch (s[i]) { case '{': level++; break; case '}': level--; if (level < 0) return JIM_ELESTR_QUOTE; break; case '[': blevel++; break; case ']': blevel--; break; case '\\': if (s[i + 1] == '\n') return JIM_ELESTR_QUOTE; else if (s[i + 1] != '\0') i++; break; } } if (blevel < 0) { return JIM_ELESTR_QUOTE; } if (level == 0) { if (!trySimple) return JIM_ELESTR_BRACE; for (i = 0; i < len; i++) { switch (s[i]) { case ' ': case '$': case '"': case '[': case ']': case ';': case '\\': case '\r': case '\n': case '\t': case '\f': case '\v': return JIM_ELESTR_BRACE; break; } } return JIM_ELESTR_SIMPLE; } return JIM_ELESTR_QUOTE; } /* Backslashes-escapes the null-terminated string 's' into the buffer at 'q' * The buffer must be at least strlen(s) * 2 + 1 bytes long for the worst-case * scenario. * Returns the length of the result. */ static int BackslashQuoteString(const char *s, char *q) { char *p = q; while (*s) { switch (*s) { case ' ': case '$': case '"': case '[': case ']': case '{': case '}': case ';': case '\\': *p++ = '\\'; *p++ = *s++; break; case '\n': *p++ = '\\'; *p++ = 'n'; s++; break; case '\r': *p++ = '\\'; *p++ = 'r'; s++; break; case '\t': *p++ = '\\'; *p++ = 't'; s++; break; case '\f': *p++ = '\\'; *p++ = 'f'; s++; break; case '\v': *p++ = '\\'; *p++ = 'v'; s++; break; default: *p++ = *s++; break; } } *p = '\0'; return p - q; } static void JimMakeListStringRep(Jim_Obj *objPtr, Jim_Obj **objv, int objc) { #define STATIC_QUOTING_LEN 32 int i, bufLen, realLength; const char *strRep; char *p; unsigned char *quotingType, staticQuoting[STATIC_QUOTING_LEN]; /* Estimate the space needed. */ if (objc > STATIC_QUOTING_LEN) { quotingType = Jim_Alloc(objc); } else { quotingType = staticQuoting; } bufLen = 0; for (i = 0; i < objc; i++) { int len; strRep = Jim_GetString(objv[i], &len); quotingType[i] = ListElementQuotingType(strRep, len); switch (quotingType[i]) { case JIM_ELESTR_SIMPLE: if (i != 0 || strRep[0] != '#') { bufLen += len; break; } /* Special case '#' on first element needs braces */ quotingType[i] = JIM_ELESTR_BRACE; /* fall through */ case JIM_ELESTR_BRACE: bufLen += len + 2; break; case JIM_ELESTR_QUOTE: bufLen += len * 2; break; } bufLen++; /* elements separator. */ } bufLen++; /* Generate the string rep. */ p = objPtr->bytes = Jim_Alloc(bufLen + 1); realLength = 0; for (i = 0; i < objc; i++) { int len, qlen; strRep = Jim_GetString(objv[i], &len); switch (quotingType[i]) { case JIM_ELESTR_SIMPLE: memcpy(p, strRep, len); p += len; realLength += len; break; case JIM_ELESTR_BRACE: *p++ = '{'; memcpy(p, strRep, len); p += len; *p++ = '}'; realLength += len + 2; break; case JIM_ELESTR_QUOTE: if (i == 0 && strRep[0] == '#') { *p++ = '\\'; realLength++; } qlen = BackslashQuoteString(strRep, p); p += qlen; realLength += qlen; break; } /* Add a separating space */ if (i + 1 != objc) { *p++ = ' '; realLength++; } } *p = '\0'; /* nul term. */ objPtr->length = realLength; if (quotingType != staticQuoting) { Jim_Free(quotingType); } } static void UpdateStringOfList(struct Jim_Obj *objPtr) { JimMakeListStringRep(objPtr, objPtr->internalRep.listValue.ele, objPtr->internalRep.listValue.len); } static int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr) { struct JimParserCtx parser; const char *str; int strLen; Jim_Obj *fileNameObj; int linenr; if (objPtr->typePtr == &listObjType) { return JIM_OK; } /* Optimise dict -> list for unshared object. Note that this may only save a little time, but * it also preserves any source location of the dict elements * which can be very useful */ if (Jim_IsDict(objPtr) && !Jim_IsShared(objPtr)) { Jim_Obj **listObjPtrPtr; int len; int i; listObjPtrPtr = JimDictPairs(objPtr, &len); for (i = 0; i < len; i++) { Jim_IncrRefCount(listObjPtrPtr[i]); } /* Now just switch the internal rep */ Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &listObjType; objPtr->internalRep.listValue.len = len; objPtr->internalRep.listValue.maxLen = len; objPtr->internalRep.listValue.ele = listObjPtrPtr; return JIM_OK; } /* Try to preserve information about filename / line number */ if (objPtr->typePtr == &sourceObjType) { fileNameObj = objPtr->internalRep.sourceValue.fileNameObj; linenr = objPtr->internalRep.sourceValue.lineNumber; } else { fileNameObj = interp->emptyObj; linenr = 1; } Jim_IncrRefCount(fileNameObj); /* Get the string representation */ str = Jim_GetString(objPtr, &strLen); /* Free the old internal repr just now and initialize the * new one just now. The string->list conversion can't fail. */ Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &listObjType; objPtr->internalRep.listValue.len = 0; objPtr->internalRep.listValue.maxLen = 0; objPtr->internalRep.listValue.ele = NULL; /* Convert into a list */ if (strLen) { JimParserInit(&parser, str, strLen, linenr); while (!parser.eof) { Jim_Obj *elementPtr; JimParseList(&parser); if (parser.tt != JIM_TT_STR && parser.tt != JIM_TT_ESC) continue; elementPtr = JimParserGetTokenObj(interp, &parser); JimSetSourceInfo(interp, elementPtr, fileNameObj, parser.tline); ListAppendElement(objPtr, elementPtr); } } Jim_DecrRefCount(interp, fileNameObj); return JIM_OK; } Jim_Obj *Jim_NewListObj(Jim_Interp *interp, Jim_Obj *const *elements, int len) { Jim_Obj *objPtr; objPtr = Jim_NewObj(interp); objPtr->typePtr = &listObjType; objPtr->bytes = NULL; objPtr->internalRep.listValue.ele = NULL; objPtr->internalRep.listValue.len = 0; objPtr->internalRep.listValue.maxLen = 0; if (len) { ListInsertElements(objPtr, 0, len, elements); } return objPtr; } /* Return a vector of Jim_Obj with the elements of a Jim list, and the * length of the vector. Note that the user of this function should make * sure that the list object can't shimmer while the vector returned * is in use, this vector is the one stored inside the internal representation * of the list object. This function is not exported, extensions should * always access to the List object elements using Jim_ListIndex(). */ static void JimListGetElements(Jim_Interp *interp, Jim_Obj *listObj, int *listLen, Jim_Obj ***listVec) { *listLen = Jim_ListLength(interp, listObj); *listVec = listObj->internalRep.listValue.ele; } /* Sorting uses ints, but commands may return wide */ static int JimSign(jim_wide w) { if (w == 0) { return 0; } else if (w < 0) { return -1; } return 1; } /* ListSortElements type values */ struct lsort_info { jmp_buf jmpbuf; Jim_Obj *command; Jim_Interp *interp; enum { JIM_LSORT_ASCII, JIM_LSORT_NOCASE, JIM_LSORT_INTEGER, JIM_LSORT_COMMAND } type; int order; int index; int indexed; int (*subfn)(Jim_Obj **, Jim_Obj **); }; static struct lsort_info *sort_info; static int ListSortIndexHelper(Jim_Obj **lhsObj, Jim_Obj **rhsObj) { Jim_Obj *lObj, *rObj; if (Jim_ListIndex(sort_info->interp, *lhsObj, sort_info->index, &lObj, JIM_ERRMSG) != JIM_OK || Jim_ListIndex(sort_info->interp, *rhsObj, sort_info->index, &rObj, JIM_ERRMSG) != JIM_OK) { longjmp(sort_info->jmpbuf, JIM_ERR); } return sort_info->subfn(&lObj, &rObj); } /* Sort the internal rep of a list. */ static int ListSortString(Jim_Obj **lhsObj, Jim_Obj **rhsObj) { return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 0) * sort_info->order; } static int ListSortStringNoCase(Jim_Obj **lhsObj, Jim_Obj **rhsObj) { return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 1) * sort_info->order; } static int ListSortInteger(Jim_Obj **lhsObj, Jim_Obj **rhsObj) { jim_wide lhs = 0, rhs = 0; if (Jim_GetWide(sort_info->interp, *lhsObj, &lhs) != JIM_OK || Jim_GetWide(sort_info->interp, *rhsObj, &rhs) != JIM_OK) { longjmp(sort_info->jmpbuf, JIM_ERR); } return JimSign(lhs - rhs) * sort_info->order; } static int ListSortCommand(Jim_Obj **lhsObj, Jim_Obj **rhsObj) { Jim_Obj *compare_script; int rc; jim_wide ret = 0; /* This must be a valid list */ compare_script = Jim_DuplicateObj(sort_info->interp, sort_info->command); Jim_ListAppendElement(sort_info->interp, compare_script, *lhsObj); Jim_ListAppendElement(sort_info->interp, compare_script, *rhsObj); rc = Jim_EvalObj(sort_info->interp, compare_script); if (rc != JIM_OK || Jim_GetWide(sort_info->interp, Jim_GetResult(sort_info->interp), &ret) != JIM_OK) { longjmp(sort_info->jmpbuf, rc); } return JimSign(ret) * sort_info->order; } /* Sort a list *in place*. MUST be called with non-shared objects. */ static int ListSortElements(Jim_Interp *interp, Jim_Obj *listObjPtr, struct lsort_info *info) { struct lsort_info *prev_info; typedef int (qsort_comparator) (const void *, const void *); int (*fn) (Jim_Obj **, Jim_Obj **); Jim_Obj **vector; int len; int rc; JimPanic((Jim_IsShared(listObjPtr), "Jim_ListSortElements called with shared object")); SetListFromAny(interp, listObjPtr); /* Allow lsort to be called reentrantly */ prev_info = sort_info; sort_info = info; vector = listObjPtr->internalRep.listValue.ele; len = listObjPtr->internalRep.listValue.len; switch (info->type) { case JIM_LSORT_ASCII: fn = ListSortString; break; case JIM_LSORT_NOCASE: fn = ListSortStringNoCase; break; case JIM_LSORT_INTEGER: fn = ListSortInteger; break; case JIM_LSORT_COMMAND: fn = ListSortCommand; break; default: fn = NULL; /* avoid warning */ JimPanic((1, "ListSort called with invalid sort type")); } if (info->indexed) { /* Need to interpose a "list index" function */ info->subfn = fn; fn = ListSortIndexHelper; } if ((rc = setjmp(info->jmpbuf)) == 0) { qsort(vector, len, sizeof(Jim_Obj *), (qsort_comparator *) fn); } Jim_InvalidateStringRep(listObjPtr); sort_info = prev_info; return rc; } /* This is the low-level function to insert elements into a list. * The higher-level Jim_ListInsertElements() performs shared object * check and invalidate the string repr. This version is used * in the internals of the List Object and is not exported. * * NOTE: this function can be called only against objects * with internal type of List. * * An insertion point (idx) of -1 means end-of-list. */ static void ListInsertElements(Jim_Obj *listPtr, int idx, int elemc, Jim_Obj *const *elemVec) { int currentLen = listPtr->internalRep.listValue.len; int requiredLen = currentLen + elemc; int i; Jim_Obj **point; if (requiredLen > listPtr->internalRep.listValue.maxLen) { if (requiredLen < 2) { /* Don't do allocations of under 4 pointers. */ requiredLen = 4; } else { requiredLen *= 2; } listPtr->internalRep.listValue.ele = Jim_Realloc(listPtr->internalRep.listValue.ele, sizeof(Jim_Obj *) * requiredLen); listPtr->internalRep.listValue.maxLen = requiredLen; } if (idx < 0) { idx = currentLen; } point = listPtr->internalRep.listValue.ele + idx; memmove(point + elemc, point, (currentLen - idx) * sizeof(Jim_Obj *)); for (i = 0; i < elemc; ++i) { point[i] = elemVec[i]; Jim_IncrRefCount(point[i]); } listPtr->internalRep.listValue.len += elemc; } /* Convenience call to ListInsertElements() to append a single element. */ static void ListAppendElement(Jim_Obj *listPtr, Jim_Obj *objPtr) { ListInsertElements(listPtr, -1, 1, &objPtr); } /* Appends every element of appendListPtr into listPtr. * Both have to be of the list type. * Convenience call to ListInsertElements() */ static void ListAppendList(Jim_Obj *listPtr, Jim_Obj *appendListPtr) { ListInsertElements(listPtr, -1, appendListPtr->internalRep.listValue.len, appendListPtr->internalRep.listValue.ele); } void Jim_ListAppendElement(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *objPtr) { JimPanic((Jim_IsShared(listPtr), "Jim_ListAppendElement called with shared object")); SetListFromAny(interp, listPtr); Jim_InvalidateStringRep(listPtr); ListAppendElement(listPtr, objPtr); } void Jim_ListAppendList(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *appendListPtr) { JimPanic((Jim_IsShared(listPtr), "Jim_ListAppendList called with shared object")); SetListFromAny(interp, listPtr); SetListFromAny(interp, appendListPtr); Jim_InvalidateStringRep(listPtr); ListAppendList(listPtr, appendListPtr); } int Jim_ListLength(Jim_Interp *interp, Jim_Obj *objPtr) { SetListFromAny(interp, objPtr); return objPtr->internalRep.listValue.len; } void Jim_ListInsertElements(Jim_Interp *interp, Jim_Obj *listPtr, int idx, int objc, Jim_Obj *const *objVec) { JimPanic((Jim_IsShared(listPtr), "Jim_ListInsertElement called with shared object")); SetListFromAny(interp, listPtr); if (idx >= 0 && idx > listPtr->internalRep.listValue.len) idx = listPtr->internalRep.listValue.len; else if (idx < 0) idx = 0; Jim_InvalidateStringRep(listPtr); ListInsertElements(listPtr, idx, objc, objVec); } Jim_Obj *Jim_ListGetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx) { SetListFromAny(interp, listPtr); if ((idx >= 0 && idx >= listPtr->internalRep.listValue.len) || (idx < 0 && (-idx - 1) >= listPtr->internalRep.listValue.len)) { return NULL; } if (idx < 0) idx = listPtr->internalRep.listValue.len + idx; return listPtr->internalRep.listValue.ele[idx]; } int Jim_ListIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx, Jim_Obj **objPtrPtr, int flags) { *objPtrPtr = Jim_ListGetIndex(interp, listPtr, idx); if (*objPtrPtr == NULL) { if (flags & JIM_ERRMSG) { Jim_SetResultString(interp, "list index out of range", -1); } return JIM_ERR; } return JIM_OK; } static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx, Jim_Obj *newObjPtr, int flags) { SetListFromAny(interp, listPtr); if ((idx >= 0 && idx >= listPtr->internalRep.listValue.len) || (idx < 0 && (-idx - 1) >= listPtr->internalRep.listValue.len)) { if (flags & JIM_ERRMSG) { Jim_SetResultString(interp, "list index out of range", -1); } return JIM_ERR; } if (idx < 0) idx = listPtr->internalRep.listValue.len + idx; Jim_DecrRefCount(interp, listPtr->internalRep.listValue.ele[idx]); listPtr->internalRep.listValue.ele[idx] = newObjPtr; Jim_IncrRefCount(newObjPtr); return JIM_OK; } /* Modify the list stored into the variable named 'varNamePtr' * setting the element specified by the 'indexc' indexes objects in 'indexv', * with the new element 'newObjptr'. */ int Jim_SetListIndex(Jim_Interp *interp, Jim_Obj *varNamePtr, Jim_Obj *const *indexv, int indexc, Jim_Obj *newObjPtr) { Jim_Obj *varObjPtr, *objPtr, *listObjPtr; int shared, i, idx; varObjPtr = objPtr = Jim_GetVariable(interp, varNamePtr, JIM_ERRMSG | JIM_UNSHARED); if (objPtr == NULL) return JIM_ERR; if ((shared = Jim_IsShared(objPtr))) varObjPtr = objPtr = Jim_DuplicateObj(interp, objPtr); for (i = 0; i < indexc - 1; i++) { listObjPtr = objPtr; if (Jim_GetIndex(interp, indexv[i], &idx) != JIM_OK) goto err; if (Jim_ListIndex(interp, listObjPtr, idx, &objPtr, JIM_ERRMSG) != JIM_OK) { goto err; } if (Jim_IsShared(objPtr)) { objPtr = Jim_DuplicateObj(interp, objPtr); ListSetIndex(interp, listObjPtr, idx, objPtr, JIM_NONE); } Jim_InvalidateStringRep(listObjPtr); } if (Jim_GetIndex(interp, indexv[indexc - 1], &idx) != JIM_OK) goto err; if (ListSetIndex(interp, objPtr, idx, newObjPtr, JIM_ERRMSG) == JIM_ERR) goto err; Jim_InvalidateStringRep(objPtr); Jim_InvalidateStringRep(varObjPtr); if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK) goto err; Jim_SetResult(interp, varObjPtr); return JIM_OK; err: if (shared) { Jim_FreeNewObj(interp, varObjPtr); } return JIM_ERR; } Jim_Obj *Jim_ListJoin(Jim_Interp *interp, Jim_Obj *listObjPtr, const char *joinStr, int joinStrLen) { int i; int listLen = Jim_ListLength(interp, listObjPtr); Jim_Obj *resObjPtr = Jim_NewEmptyStringObj(interp); for (i = 0; i < listLen; ) { Jim_Obj *objPtr; Jim_ListIndex(interp, listObjPtr, i, &objPtr, JIM_NONE); Jim_AppendObj(interp, resObjPtr, objPtr); if (++i != listLen) { Jim_AppendString(interp, resObjPtr, joinStr, joinStrLen); } } return resObjPtr; } Jim_Obj *Jim_ConcatObj(Jim_Interp *interp, int objc, Jim_Obj *const *objv) { int i; /* If all the objects in objv are lists, * it's possible to return a list as result, that's the * concatenation of all the lists. */ for (i = 0; i < objc; i++) { if (!Jim_IsList(objv[i])) break; } if (i == objc) { Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0); for (i = 0; i < objc; i++) ListAppendList(objPtr, objv[i]); return objPtr; } else { /* Else... we have to glue strings together */ int len = 0, objLen; char *bytes, *p; /* Compute the length */ for (i = 0; i < objc; i++) { Jim_GetString(objv[i], &objLen); len += objLen; } if (objc) len += objc - 1; /* Create the string rep, and a string object holding it. */ p = bytes = Jim_Alloc(len + 1); for (i = 0; i < objc; i++) { const char *s = Jim_GetString(objv[i], &objLen); /* Remove leading space */ while (objLen && (*s == ' ' || *s == '\t' || *s == '\n')) { s++; objLen--; len--; } /* And trailing space */ while (objLen && (s[objLen - 1] == ' ' || s[objLen - 1] == '\n' || s[objLen - 1] == '\t')) { /* Handle trailing backslash-space case */ if (objLen > 1 && s[objLen - 2] == '\\') { break; } objLen--; len--; } memcpy(p, s, objLen); p += objLen; if (objLen && i + 1 != objc) { *p++ = ' '; } else if (i + 1 != objc) { /* Drop the space calcuated for this * element that is instead null. */ len--; } } *p = '\0'; return Jim_NewStringObjNoAlloc(interp, bytes, len); } } /* Returns a list composed of the elements in the specified range. * first and start are directly accepted as Jim_Objects and * processed for the end?-index? case. */ Jim_Obj *Jim_ListRange(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr) { int first, last; int len, rangeLen; if (Jim_GetIndex(interp, firstObjPtr, &first) != JIM_OK || Jim_GetIndex(interp, lastObjPtr, &last) != JIM_OK) return NULL; len = Jim_ListLength(interp, listObjPtr); /* will convert into list */ first = JimRelToAbsIndex(len, first); last = JimRelToAbsIndex(len, last); JimRelToAbsRange(len, &first, &last, &rangeLen); if (first == 0 && last == len) { return listObjPtr; } return Jim_NewListObj(interp, listObjPtr->internalRep.listValue.ele + first, rangeLen); } /* ----------------------------------------------------------------------------- * Dict object * ---------------------------------------------------------------------------*/ static void FreeDictInternalRep(Jim_Interp *interp, Jim_Obj *objPtr); static void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr); static void UpdateStringOfDict(struct Jim_Obj *objPtr); static int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr); /* Dict HashTable Type. * * Keys and Values are Jim objects. */ static unsigned int JimObjectHTHashFunction(const void *key) { int len; const char *str = Jim_GetString((Jim_Obj *)key, &len); return Jim_GenHashFunction((const unsigned char *)str, len); } static int JimObjectHTKeyCompare(void *privdata, const void *key1, const void *key2) { return Jim_StringEqObj((Jim_Obj *)key1, (Jim_Obj *)key2); } static void JimObjectHTKeyValDestructor(void *interp, void *val) { Jim_DecrRefCount(interp, (Jim_Obj *)val); } static const Jim_HashTableType JimDictHashTableType = { JimObjectHTHashFunction, /* hash function */ NULL, /* key dup */ NULL, /* val dup */ JimObjectHTKeyCompare, /* key compare */ JimObjectHTKeyValDestructor, /* key destructor */ JimObjectHTKeyValDestructor /* val destructor */ }; /* Note that while the elements of the dict may contain references, * the list object itself can't. This basically means that the * dict object string representation as a whole can't contain references * that are not presents in the single elements. */ static const Jim_ObjType dictObjType = { "dict", FreeDictInternalRep, DupDictInternalRep, UpdateStringOfDict, JIM_TYPE_NONE, }; void FreeDictInternalRep(Jim_Interp *interp, Jim_Obj *objPtr) { JIM_NOTUSED(interp); Jim_FreeHashTable(objPtr->internalRep.ptr); Jim_Free(objPtr->internalRep.ptr); } void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr) { Jim_HashTable *ht, *dupHt; Jim_HashTableIterator htiter; Jim_HashEntry *he; /* Create a new hash table */ ht = srcPtr->internalRep.ptr; dupHt = Jim_Alloc(sizeof(*dupHt)); Jim_InitHashTable(dupHt, &JimDictHashTableType, interp); if (ht->size != 0) Jim_ExpandHashTable(dupHt, ht->size); /* Copy every element from the source to the dup hash table */ JimInitHashTableIterator(ht, &htiter); while ((he = Jim_NextHashEntry(&htiter)) != NULL) { const Jim_Obj *keyObjPtr = he->key; Jim_Obj *valObjPtr = he->u.val; Jim_IncrRefCount((Jim_Obj *)keyObjPtr); /* ATTENTION: const cast */ Jim_IncrRefCount(valObjPtr); Jim_AddHashEntry(dupHt, keyObjPtr, valObjPtr); } dupPtr->internalRep.ptr = dupHt; dupPtr->typePtr = &dictObjType; } static Jim_Obj **JimDictPairs(Jim_Obj *dictPtr, int *len) { Jim_HashTable *ht; Jim_HashTableIterator htiter; Jim_HashEntry *he; Jim_Obj **objv; int i; ht = dictPtr->internalRep.ptr; /* Turn the hash table into a flat vector of Jim_Objects. */ objv = Jim_Alloc((ht->used * 2) * sizeof(Jim_Obj *)); JimInitHashTableIterator(ht, &htiter); i = 0; while ((he = Jim_NextHashEntry(&htiter)) != NULL) { objv[i++] = (Jim_Obj *)he->key; objv[i++] = he->u.val; } *len = i; return objv; } static void UpdateStringOfDict(struct Jim_Obj *objPtr) { /* Turn the hash table into a flat vector of Jim_Objects. */ int len; Jim_Obj **objv = JimDictPairs(objPtr, &len); JimMakeListStringRep(objPtr, objv, len); Jim_Free(objv); } static int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr) { int listlen; if (objPtr->typePtr == &dictObjType) { return JIM_OK; } /* Get the string representation. Do this first so we don't * change order in case of fast conversion to dict. */ Jim_String(objPtr); /* For simplicity, convert a non-list object to a list and then to a dict */ listlen = Jim_ListLength(interp, objPtr); if (listlen % 2) { Jim_SetResultString(interp, "missing value to go with key", -1); return JIM_ERR; } else { /* Now it is easy to convert to a dict from a list, and it can't fail */ Jim_HashTable *ht; int i; ht = Jim_Alloc(sizeof(*ht)); Jim_InitHashTable(ht, &JimDictHashTableType, interp); for (i = 0; i < listlen; i += 2) { Jim_Obj *keyObjPtr; Jim_Obj *valObjPtr; Jim_ListIndex(interp, objPtr, i, &keyObjPtr, JIM_NONE); Jim_ListIndex(interp, objPtr, i + 1, &valObjPtr, JIM_NONE); Jim_IncrRefCount(keyObjPtr); Jim_IncrRefCount(valObjPtr); if (Jim_AddHashEntry(ht, keyObjPtr, valObjPtr) != JIM_OK) { Jim_HashEntry *he; he = Jim_FindHashEntry(ht, keyObjPtr); Jim_DecrRefCount(interp, keyObjPtr); /* ATTENTION: const cast */ Jim_DecrRefCount(interp, (Jim_Obj *)he->u.val); he->u.val = valObjPtr; } } Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &dictObjType; objPtr->internalRep.ptr = ht; return JIM_OK; } } /* Dict object API */ /* Add an element to a dict. objPtr must be of the "dict" type. * The higer-level exported function is Jim_DictAddElement(). * If an element with the specified key already exists, the value * associated is replaced with the new one. * * if valueObjPtr == NULL, the key is instead removed if it exists. */ static int DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr) { Jim_HashTable *ht = objPtr->internalRep.ptr; if (valueObjPtr == NULL) { /* unset */ return Jim_DeleteHashEntry(ht, keyObjPtr); } Jim_IncrRefCount(keyObjPtr); Jim_IncrRefCount(valueObjPtr); if (Jim_ReplaceHashEntry(ht, keyObjPtr, valueObjPtr)) { /* Value existed, so need to decrement key ref count */ Jim_DecrRefCount(interp, keyObjPtr); } return JIM_OK; } /* Add an element, higher-level interface for DictAddElement(). * If valueObjPtr == NULL, the key is removed if it exists. */ int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr) { int retcode; JimPanic((Jim_IsShared(objPtr), "Jim_DictAddElement called with shared object")); if (SetDictFromAny(interp, objPtr) != JIM_OK) { return JIM_ERR; } retcode = DictAddElement(interp, objPtr, keyObjPtr, valueObjPtr); Jim_InvalidateStringRep(objPtr); return retcode; } Jim_Obj *Jim_NewDictObj(Jim_Interp *interp, Jim_Obj *const *elements, int len) { Jim_Obj *objPtr; int i; JimPanic((len % 2, "Jim_NewDictObj() 'len' argument must be even")); objPtr = Jim_NewObj(interp); objPtr->typePtr = &dictObjType; objPtr->bytes = NULL; objPtr->internalRep.ptr = Jim_Alloc(sizeof(Jim_HashTable)); Jim_InitHashTable(objPtr->internalRep.ptr, &JimDictHashTableType, interp); for (i = 0; i < len; i += 2) DictAddElement(interp, objPtr, elements[i], elements[i + 1]); return objPtr; } /* Return the value associated to the specified dict key * Note: Returns JIM_OK if OK, JIM_ERR if entry not found or -1 if can't create dict value */ int Jim_DictKey(Jim_Interp *interp, Jim_Obj *dictPtr, Jim_Obj *keyPtr, Jim_Obj **objPtrPtr, int flags) { Jim_HashEntry *he; Jim_HashTable *ht; if (SetDictFromAny(interp, dictPtr) != JIM_OK) { return -1; } ht = dictPtr->internalRep.ptr; if ((he = Jim_FindHashEntry(ht, keyPtr)) == NULL) { if (flags & JIM_ERRMSG) { Jim_SetResultFormatted(interp, "key \"%#s\" not known in dictionary", keyPtr); } return JIM_ERR; } *objPtrPtr = he->u.val; return JIM_OK; } /* Return an allocated array of key/value pairs for the dictionary. Stores the length in *len */ int Jim_DictPairs(Jim_Interp *interp, Jim_Obj *dictPtr, Jim_Obj ***objPtrPtr, int *len) { if (SetDictFromAny(interp, dictPtr) != JIM_OK) { return JIM_ERR; } *objPtrPtr = JimDictPairs(dictPtr, len); return JIM_OK; } /* Return the value associated to the specified dict keys */ int Jim_DictKeysVector(Jim_Interp *interp, Jim_Obj *dictPtr, Jim_Obj *const *keyv, int keyc, Jim_Obj **objPtrPtr, int flags) { int i; if (keyc == 0) { *objPtrPtr = dictPtr; return JIM_OK; } for (i = 0; i < keyc; i++) { Jim_Obj *objPtr; int rc = Jim_DictKey(interp, dictPtr, keyv[i], &objPtr, flags); if (rc != JIM_OK) { return rc; } dictPtr = objPtr; } *objPtrPtr = dictPtr; return JIM_OK; } /* Modify the dict stored into the variable named 'varNamePtr' * setting the element specified by the 'keyc' keys objects in 'keyv', * with the new value of the element 'newObjPtr'. * * If newObjPtr == NULL the operation is to remove the given key * from the dictionary. * * If flags & JIM_ERRMSG, then failure to remove the key is considered an error * and JIM_ERR is returned. Otherwise it is ignored and JIM_OK is returned. */ int Jim_SetDictKeysVector(Jim_Interp *interp, Jim_Obj *varNamePtr, Jim_Obj *const *keyv, int keyc, Jim_Obj *newObjPtr, int flags) { Jim_Obj *varObjPtr, *objPtr, *dictObjPtr; int shared, i; varObjPtr = objPtr = Jim_GetVariable(interp, varNamePtr, flags); if (objPtr == NULL) { if (newObjPtr == NULL && (flags & JIM_MUSTEXIST)) { /* Cannot remove a key from non existing var */ return JIM_ERR; } varObjPtr = objPtr = Jim_NewDictObj(interp, NULL, 0); if (Jim_SetVariable(interp, varNamePtr, objPtr) != JIM_OK) { Jim_FreeNewObj(interp, varObjPtr); return JIM_ERR; } } if ((shared = Jim_IsShared(objPtr))) varObjPtr = objPtr = Jim_DuplicateObj(interp, objPtr); for (i = 0; i < keyc; i++) { dictObjPtr = objPtr; /* Check if it's a valid dictionary */ if (SetDictFromAny(interp, dictObjPtr) != JIM_OK) { goto err; } if (i == keyc - 1) { /* Last key: Note that error on unset with missing last key is OK */ if (Jim_DictAddElement(interp, objPtr, keyv[keyc - 1], newObjPtr) != JIM_OK) { if (newObjPtr || (flags & JIM_MUSTEXIST)) { goto err; } } break; } /* Check if the given key exists. */ Jim_InvalidateStringRep(dictObjPtr); if (Jim_DictKey(interp, dictObjPtr, keyv[i], &objPtr, newObjPtr ? JIM_NONE : JIM_ERRMSG) == JIM_OK) { /* This key exists at the current level. * Make sure it's not shared!. */ if (Jim_IsShared(objPtr)) { objPtr = Jim_DuplicateObj(interp, objPtr); DictAddElement(interp, dictObjPtr, keyv[i], objPtr); } } else { /* Key not found. If it's an [unset] operation * this is an error. Only the last key may not * exist. */ if (newObjPtr == NULL) { goto err; } /* Otherwise set an empty dictionary * as key's value. */ objPtr = Jim_NewDictObj(interp, NULL, 0); DictAddElement(interp, dictObjPtr, keyv[i], objPtr); } } Jim_InvalidateStringRep(objPtr); Jim_InvalidateStringRep(varObjPtr); if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK) { goto err; } Jim_SetResult(interp, varObjPtr); return JIM_OK; err: if (shared) { Jim_FreeNewObj(interp, varObjPtr); } return JIM_ERR; } /* ----------------------------------------------------------------------------- * Index object * ---------------------------------------------------------------------------*/ static void UpdateStringOfIndex(struct Jim_Obj *objPtr); static int SetIndexFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr); static const Jim_ObjType indexObjType = { "index", NULL, NULL, UpdateStringOfIndex, JIM_TYPE_NONE, }; void UpdateStringOfIndex(struct Jim_Obj *objPtr) { int len; char buf[JIM_INTEGER_SPACE + 1]; if (objPtr->internalRep.intValue >= 0) len = sprintf(buf, "%d", objPtr->internalRep.intValue); else if (objPtr->internalRep.intValue == -1) len = sprintf(buf, "end"); else { len = sprintf(buf, "end%d", objPtr->internalRep.intValue + 1); } objPtr->bytes = Jim_Alloc(len + 1); memcpy(objPtr->bytes, buf, len + 1); objPtr->length = len; } int SetIndexFromAny(Jim_Interp *interp, Jim_Obj *objPtr) { int idx, end = 0; const char *str; char *endptr; /* Get the string representation */ str = Jim_String(objPtr); /* Try to convert into an index */ if (strncmp(str, "end", 3) == 0) { end = 1; str += 3; idx = 0; } else { idx = jim_strtol(str, &endptr); if (endptr == str) { goto badindex; } str = endptr; } /* Now str may include or + or - */ if (*str == '+' || *str == '-') { int sign = (*str == '+' ? 1 : -1); idx += sign * jim_strtol(++str, &endptr); if (str == endptr || *endptr) { goto badindex; } str = endptr; } /* The only thing left should be spaces */ while (isspace(UCHAR(*str))) { str++; } if (*str) { goto badindex; } if (end) { if (idx > 0) { idx = INT_MAX; } else { /* end-1 is repesented as -2 */ idx--; } } else if (idx < 0) { idx = -INT_MAX; } /* Free the old internal repr and set the new one. */ Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &indexObjType; objPtr->internalRep.intValue = idx; return JIM_OK; badindex: Jim_SetResultFormatted(interp, "bad index \"%#s\": must be integer?[+-]integer? or end?[+-]integer?", objPtr); return JIM_ERR; } int Jim_GetIndex(Jim_Interp *interp, Jim_Obj *objPtr, int *indexPtr) { /* Avoid shimmering if the object is an integer. */ if (objPtr->typePtr == &intObjType) { jim_wide val = JimWideValue(objPtr); if (!(val < LONG_MIN) && !(val > LONG_MAX)) { *indexPtr = (val < 0) ? -INT_MAX : (long)val;; return JIM_OK; } } if (objPtr->typePtr != &indexObjType && SetIndexFromAny(interp, objPtr) == JIM_ERR) return JIM_ERR; *indexPtr = objPtr->internalRep.intValue; return JIM_OK; } /* ----------------------------------------------------------------------------- * Return Code Object. * ---------------------------------------------------------------------------*/ /* NOTE: These must be kept in the same order as JIM_OK, JIM_ERR, ... */ static const char * const jimReturnCodes[] = { "ok", "error", "return", "break", "continue", "signal", "exit", "eval", NULL }; #define jimReturnCodesSize (sizeof(jimReturnCodes)/sizeof(*jimReturnCodes)) static int SetReturnCodeFromAny(Jim_Interp *interp, Jim_Obj *objPtr); static const Jim_ObjType returnCodeObjType = { "return-code", NULL, NULL, NULL, JIM_TYPE_NONE, }; /* Converts a (standard) return code to a string. Returns "?" for * non-standard return codes. */ const char *Jim_ReturnCode(int code) { if (code < 0 || code >= (int)jimReturnCodesSize) { return "?"; } else { return jimReturnCodes[code]; } } int SetReturnCodeFromAny(Jim_Interp *interp, Jim_Obj *objPtr) { int returnCode; jim_wide wideValue; /* Try to convert into an integer */ if (JimGetWideNoErr(interp, objPtr, &wideValue) != JIM_ERR) returnCode = (int)wideValue; else if (Jim_GetEnum(interp, objPtr, jimReturnCodes, &returnCode, NULL, JIM_NONE) != JIM_OK) { Jim_SetResultFormatted(interp, "expected return code but got \"%#s\"", objPtr); return JIM_ERR; } /* Free the old internal repr and set the new one. */ Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &returnCodeObjType; objPtr->internalRep.intValue = returnCode; return JIM_OK; } int Jim_GetReturnCode(Jim_Interp *interp, Jim_Obj *objPtr, int *intPtr) { if (objPtr->typePtr != &returnCodeObjType && SetReturnCodeFromAny(interp, objPtr) == JIM_ERR) return JIM_ERR; *intPtr = objPtr->internalRep.intValue; return JIM_OK; } /* ----------------------------------------------------------------------------- * Expression Parsing * ---------------------------------------------------------------------------*/ static int JimParseExprOperator(struct JimParserCtx *pc); static int JimParseExprNumber(struct JimParserCtx *pc); static int JimParseExprIrrational(struct JimParserCtx *pc); /* Exrp's Stack machine operators opcodes. */ /* Binary operators (numbers) */ enum { /* Continues on from the JIM_TT_ space */ /* Operations */ JIM_EXPROP_MUL = JIM_TT_EXPR_OP, /* 20 */ JIM_EXPROP_DIV, JIM_EXPROP_MOD, JIM_EXPROP_SUB, JIM_EXPROP_ADD, JIM_EXPROP_LSHIFT, JIM_EXPROP_RSHIFT, JIM_EXPROP_ROTL, JIM_EXPROP_ROTR, JIM_EXPROP_LT, JIM_EXPROP_GT, JIM_EXPROP_LTE, JIM_EXPROP_GTE, JIM_EXPROP_NUMEQ, JIM_EXPROP_NUMNE, JIM_EXPROP_BITAND, /* 35 */ JIM_EXPROP_BITXOR, JIM_EXPROP_BITOR, /* Note must keep these together */ JIM_EXPROP_LOGICAND, /* 38 */ JIM_EXPROP_LOGICAND_LEFT, JIM_EXPROP_LOGICAND_RIGHT, /* and these */ JIM_EXPROP_LOGICOR, /* 41 */ JIM_EXPROP_LOGICOR_LEFT, JIM_EXPROP_LOGICOR_RIGHT, /* and these */ /* Ternary operators */ JIM_EXPROP_TERNARY, /* 44 */ JIM_EXPROP_TERNARY_LEFT, JIM_EXPROP_TERNARY_RIGHT, /* and these */ JIM_EXPROP_COLON, /* 47 */ JIM_EXPROP_COLON_LEFT, JIM_EXPROP_COLON_RIGHT, JIM_EXPROP_POW, /* 50 */ /* Binary operators (strings) */ JIM_EXPROP_STREQ, /* 51 */ JIM_EXPROP_STRNE, JIM_EXPROP_STRIN, JIM_EXPROP_STRNI, /* Unary operators (numbers) */ JIM_EXPROP_NOT, /* 55 */ JIM_EXPROP_BITNOT, JIM_EXPROP_UNARYMINUS, JIM_EXPROP_UNARYPLUS, /* Functions */ JIM_EXPROP_FUNC_FIRST, /* 59 */ JIM_EXPROP_FUNC_INT = JIM_EXPROP_FUNC_FIRST, JIM_EXPROP_FUNC_ABS, JIM_EXPROP_FUNC_DOUBLE, JIM_EXPROP_FUNC_ROUND, JIM_EXPROP_FUNC_RAND, JIM_EXPROP_FUNC_SRAND, /* math functions from libm */ JIM_EXPROP_FUNC_SIN, /* 64 */ JIM_EXPROP_FUNC_COS, JIM_EXPROP_FUNC_TAN, JIM_EXPROP_FUNC_ASIN, JIM_EXPROP_FUNC_ACOS, JIM_EXPROP_FUNC_ATAN, JIM_EXPROP_FUNC_SINH, JIM_EXPROP_FUNC_COSH, JIM_EXPROP_FUNC_TANH, JIM_EXPROP_FUNC_CEIL, JIM_EXPROP_FUNC_FLOOR, JIM_EXPROP_FUNC_EXP, JIM_EXPROP_FUNC_LOG, JIM_EXPROP_FUNC_LOG10, JIM_EXPROP_FUNC_SQRT, JIM_EXPROP_FUNC_POW, }; struct JimExprState { Jim_Obj **stack; int stacklen; int opcode; int skip; }; /* Operators table */ typedef struct Jim_ExprOperator { const char *name; int (*funcop) (Jim_Interp *interp, struct JimExprState * e); unsigned char precedence; unsigned char arity; unsigned char lazy; unsigned char namelen; } Jim_ExprOperator; static void ExprPush(struct JimExprState *e, Jim_Obj *obj) { Jim_IncrRefCount(obj); e->stack[e->stacklen++] = obj; } static Jim_Obj *ExprPop(struct JimExprState *e) { return e->stack[--e->stacklen]; } static int JimExprOpNumUnary(Jim_Interp *interp, struct JimExprState *e) { int intresult = 0; int rc = JIM_OK; Jim_Obj *A = ExprPop(e); double dA, dC = 0; jim_wide wA, wC = 0; if ((A->typePtr != &doubleObjType || A->bytes) && JimGetWideNoErr(interp, A, &wA) == JIM_OK) { intresult = 1; switch (e->opcode) { case JIM_EXPROP_FUNC_INT: wC = wA; break; case JIM_EXPROP_FUNC_ROUND: wC = wA; break; case JIM_EXPROP_FUNC_DOUBLE: dC = wA; intresult = 0; break; case JIM_EXPROP_FUNC_ABS: wC = wA >= 0 ? wA : -wA; break; case JIM_EXPROP_UNARYMINUS: wC = -wA; break; case JIM_EXPROP_UNARYPLUS: wC = wA; break; case JIM_EXPROP_NOT: wC = !wA; break; default: abort(); } } else if ((rc = Jim_GetDouble(interp, A, &dA)) == JIM_OK) { switch (e->opcode) { case JIM_EXPROP_FUNC_INT: wC = dA; intresult = 1; break; case JIM_EXPROP_FUNC_ROUND: wC = dA < 0 ? (dA - 0.5) : (dA + 0.5); intresult = 1; break; case JIM_EXPROP_FUNC_DOUBLE: dC = dA; break; case JIM_EXPROP_FUNC_ABS: dC = dA >= 0 ? dA : -dA; break; case JIM_EXPROP_UNARYMINUS: dC = -dA; break; case JIM_EXPROP_UNARYPLUS: dC = dA; break; case JIM_EXPROP_NOT: wC = !dA; intresult = 1; break; default: abort(); } } if (rc == JIM_OK) { if (intresult) { ExprPush(e, Jim_NewIntObj(interp, wC)); } else { ExprPush(e, Jim_NewDoubleObj(interp, dC)); } } Jim_DecrRefCount(interp, A); return rc; } static double JimRandDouble(Jim_Interp *interp) { unsigned long x; JimRandomBytes(interp, &x, sizeof(x)); return (double)x / (unsigned long)~0; } static int JimExprOpIntUnary(Jim_Interp *interp, struct JimExprState *e) { Jim_Obj *A = ExprPop(e); jim_wide wA; int rc = Jim_GetWide(interp, A, &wA); if (rc == JIM_OK) { switch (e->opcode) { case JIM_EXPROP_BITNOT: ExprPush(e, Jim_NewIntObj(interp, ~wA)); break; case JIM_EXPROP_FUNC_SRAND: JimPrngSeed(interp, (unsigned char *)&wA, sizeof(wA)); ExprPush(e, Jim_NewDoubleObj(interp, JimRandDouble(interp))); break; default: abort(); } } Jim_DecrRefCount(interp, A); return rc; } static int JimExprOpNone(Jim_Interp *interp, struct JimExprState *e) { JimPanic((e->opcode != JIM_EXPROP_FUNC_RAND, "JimExprOpNone only support rand()")); ExprPush(e, Jim_NewDoubleObj(interp, JimRandDouble(interp))); return JIM_OK; } #ifdef JIM_MATH_FUNCTIONS static int JimExprOpDoubleUnary(Jim_Interp *interp, struct JimExprState *e) { int rc; Jim_Obj *A = ExprPop(e); double dA, dC; rc = Jim_GetDouble(interp, A, &dA); if (rc == JIM_OK) { switch (e->opcode) { case JIM_EXPROP_FUNC_SIN: dC = sin(dA); break; case JIM_EXPROP_FUNC_COS: dC = cos(dA); break; case JIM_EXPROP_FUNC_TAN: dC = tan(dA); break; case JIM_EXPROP_FUNC_ASIN: dC = asin(dA); break; case JIM_EXPROP_FUNC_ACOS: dC = acos(dA); break; case JIM_EXPROP_FUNC_ATAN: dC = atan(dA); break; case JIM_EXPROP_FUNC_SINH: dC = sinh(dA); break; case JIM_EXPROP_FUNC_COSH: dC = cosh(dA); break; case JIM_EXPROP_FUNC_TANH: dC = tanh(dA); break; case JIM_EXPROP_FUNC_CEIL: dC = ceil(dA); break; case JIM_EXPROP_FUNC_FLOOR: dC = floor(dA); break; case JIM_EXPROP_FUNC_EXP: dC = exp(dA); break; case JIM_EXPROP_FUNC_LOG: dC = log(dA); break; case JIM_EXPROP_FUNC_LOG10: dC = log10(dA); break; case JIM_EXPROP_FUNC_SQRT: dC = sqrt(dA); break; default: abort(); } ExprPush(e, Jim_NewDoubleObj(interp, dC)); } Jim_DecrRefCount(interp, A); return rc; } #endif /* A binary operation on two ints */ static int JimExprOpIntBin(Jim_Interp *interp, struct JimExprState *e) { Jim_Obj *B = ExprPop(e); Jim_Obj *A = ExprPop(e); jim_wide wA, wB; int rc = JIM_ERR; if (Jim_GetWide(interp, A, &wA) == JIM_OK && Jim_GetWide(interp, B, &wB) == JIM_OK) { jim_wide wC; rc = JIM_OK; switch (e->opcode) { case JIM_EXPROP_LSHIFT: wC = wA << wB; break; case JIM_EXPROP_RSHIFT: wC = wA >> wB; break; case JIM_EXPROP_BITAND: wC = wA & wB; break; case JIM_EXPROP_BITXOR: wC = wA ^ wB; break; case JIM_EXPROP_BITOR: wC = wA | wB; break; case JIM_EXPROP_MOD: if (wB == 0) { wC = 0; Jim_SetResultString(interp, "Division by zero", -1); rc = JIM_ERR; } else { /* * From Tcl 8.x * * This code is tricky: C doesn't guarantee much * about the quotient or remainder, but Tcl does. * The remainder always has the same sign as the * divisor and a smaller absolute value. */ int negative = 0; if (wB < 0) { wB = -wB; wA = -wA; negative = 1; } wC = wA % wB; if (wC < 0) { wC += wB; } if (negative) { wC = -wC; } } break; case JIM_EXPROP_ROTL: case JIM_EXPROP_ROTR:{ /* uint32_t would be better. But not everyone has inttypes.h? */ unsigned long uA = (unsigned long)wA; unsigned long uB = (unsigned long)wB; const unsigned int S = sizeof(unsigned long) * 8; /* Shift left by the word size or more is undefined. */ uB %= S; if (e->opcode == JIM_EXPROP_ROTR) { uB = S - uB; } wC = (unsigned long)(uA << uB) | (uA >> (S - uB)); break; } default: abort(); } ExprPush(e, Jim_NewIntObj(interp, wC)); } Jim_DecrRefCount(interp, A); Jim_DecrRefCount(interp, B); return rc; } /* A binary operation on two ints or two doubles (or two strings for some ops) */ static int JimExprOpBin(Jim_Interp *interp, struct JimExprState *e) { int intresult = 0; int rc = JIM_OK; double dA, dB, dC = 0; jim_wide wA, wB, wC = 0; Jim_Obj *B = ExprPop(e); Jim_Obj *A = ExprPop(e); if ((A->typePtr != &doubleObjType || A->bytes) && (B->typePtr != &doubleObjType || B->bytes) && JimGetWideNoErr(interp, A, &wA) == JIM_OK && JimGetWideNoErr(interp, B, &wB) == JIM_OK) { /* Both are ints */ intresult = 1; switch (e->opcode) { case JIM_EXPROP_POW: case JIM_EXPROP_FUNC_POW: wC = JimPowWide(wA, wB); break; case JIM_EXPROP_ADD: wC = wA + wB; break; case JIM_EXPROP_SUB: wC = wA - wB; break; case JIM_EXPROP_MUL: wC = wA * wB; break; case JIM_EXPROP_DIV: if (wB == 0) { Jim_SetResultString(interp, "Division by zero", -1); rc = JIM_ERR; } else { /* * From Tcl 8.x * * This code is tricky: C doesn't guarantee much * about the quotient or remainder, but Tcl does. * The remainder always has the same sign as the * divisor and a smaller absolute value. */ if (wB < 0) { wB = -wB; wA = -wA; } wC = wA / wB; if (wA % wB < 0) { wC--; } } break; case JIM_EXPROP_LT: wC = wA < wB; break; case JIM_EXPROP_GT: wC = wA > wB; break; case JIM_EXPROP_LTE: wC = wA <= wB; break; case JIM_EXPROP_GTE: wC = wA >= wB; break; case JIM_EXPROP_NUMEQ: wC = wA == wB; break; case JIM_EXPROP_NUMNE: wC = wA != wB; break; default: abort(); } } else if (Jim_GetDouble(interp, A, &dA) == JIM_OK && Jim_GetDouble(interp, B, &dB) == JIM_OK) { switch (e->opcode) { case JIM_EXPROP_POW: case JIM_EXPROP_FUNC_POW: #ifdef JIM_MATH_FUNCTIONS dC = pow(dA, dB); #else Jim_SetResultString(interp, "unsupported", -1); rc = JIM_ERR; #endif break; case JIM_EXPROP_ADD: dC = dA + dB; break; case JIM_EXPROP_SUB: dC = dA - dB; break; case JIM_EXPROP_MUL: dC = dA * dB; break; case JIM_EXPROP_DIV: if (dB == 0) { #ifdef INFINITY dC = dA < 0 ? -INFINITY : INFINITY; #else dC = (dA < 0 ? -1.0 : 1.0) * strtod("Inf", NULL); #endif } else { dC = dA / dB; } break; case JIM_EXPROP_LT: wC = dA < dB; intresult = 1; break; case JIM_EXPROP_GT: wC = dA > dB; intresult = 1; break; case JIM_EXPROP_LTE: wC = dA <= dB; intresult = 1; break; case JIM_EXPROP_GTE: wC = dA >= dB; intresult = 1; break; case JIM_EXPROP_NUMEQ: wC = dA == dB; intresult = 1; break; case JIM_EXPROP_NUMNE: wC = dA != dB; intresult = 1; break; default: abort(); } } else { /* Handle the string case */ /* REVISIT: Could optimise the eq/ne case by checking lengths */ int i = Jim_StringCompareObj(interp, A, B, 0); intresult = 1; switch (e->opcode) { case JIM_EXPROP_LT: wC = i < 0; break; case JIM_EXPROP_GT: wC = i > 0; break; case JIM_EXPROP_LTE: wC = i <= 0; break; case JIM_EXPROP_GTE: wC = i >= 0; break; case JIM_EXPROP_NUMEQ: wC = i == 0; break; case JIM_EXPROP_NUMNE: wC = i != 0; break; default: rc = JIM_ERR; break; } } if (rc == JIM_OK) { if (intresult) { ExprPush(e, Jim_NewIntObj(interp, wC)); } else { ExprPush(e, Jim_NewDoubleObj(interp, dC)); } } Jim_DecrRefCount(interp, A); Jim_DecrRefCount(interp, B); return rc; } static int JimSearchList(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_Obj *valObj) { int listlen; int i; listlen = Jim_ListLength(interp, listObjPtr); for (i = 0; i < listlen; i++) { Jim_Obj *objPtr; Jim_ListIndex(interp, listObjPtr, i, &objPtr, JIM_NONE); if (Jim_StringEqObj(objPtr, valObj)) { return 1; } } return 0; } static int JimExprOpStrBin(Jim_Interp *interp, struct JimExprState *e) { Jim_Obj *B = ExprPop(e); Jim_Obj *A = ExprPop(e); jim_wide wC; switch (e->opcode) { case JIM_EXPROP_STREQ: case JIM_EXPROP_STRNE: { int Alen, Blen; const char *sA = Jim_GetString(A, &Alen); const char *sB = Jim_GetString(B, &Blen); if (e->opcode == JIM_EXPROP_STREQ) { wC = (Alen == Blen && memcmp(sA, sB, Alen) == 0); } else { wC = (Alen != Blen || memcmp(sA, sB, Alen) != 0); } break; } case JIM_EXPROP_STRIN: wC = JimSearchList(interp, B, A); break; case JIM_EXPROP_STRNI: wC = !JimSearchList(interp, B, A); break; default: abort(); } ExprPush(e, Jim_NewIntObj(interp, wC)); Jim_DecrRefCount(interp, A); Jim_DecrRefCount(interp, B); return JIM_OK; } static int ExprBool(Jim_Interp *interp, Jim_Obj *obj) { long l; double d; if (Jim_GetLong(interp, obj, &l) == JIM_OK) { return l != 0; } if (Jim_GetDouble(interp, obj, &d) == JIM_OK) { return d != 0; } return -1; } static int JimExprOpAndLeft(Jim_Interp *interp, struct JimExprState *e) { Jim_Obj *skip = ExprPop(e); Jim_Obj *A = ExprPop(e); int rc = JIM_OK; switch (ExprBool(interp, A)) { case 0: /* false, so skip RHS opcodes with a 0 result */ e->skip = JimWideValue(skip); ExprPush(e, Jim_NewIntObj(interp, 0)); break; case 1: /* true so continue */ break; case -1: /* Invalid */ rc = JIM_ERR; } Jim_DecrRefCount(interp, A); Jim_DecrRefCount(interp, skip); return rc; } static int JimExprOpOrLeft(Jim_Interp *interp, struct JimExprState *e) { Jim_Obj *skip = ExprPop(e); Jim_Obj *A = ExprPop(e); int rc = JIM_OK; switch (ExprBool(interp, A)) { case 0: /* false, so do nothing */ break; case 1: /* true so skip RHS opcodes with a 1 result */ e->skip = JimWideValue(skip); ExprPush(e, Jim_NewIntObj(interp, 1)); break; case -1: /* Invalid */ rc = JIM_ERR; break; } Jim_DecrRefCount(interp, A); Jim_DecrRefCount(interp, skip); return rc; } static int JimExprOpAndOrRight(Jim_Interp *interp, struct JimExprState *e) { Jim_Obj *A = ExprPop(e); int rc = JIM_OK; switch (ExprBool(interp, A)) { case 0: ExprPush(e, Jim_NewIntObj(interp, 0)); break; case 1: ExprPush(e, Jim_NewIntObj(interp, 1)); break; case -1: /* Invalid */ rc = JIM_ERR; break; } Jim_DecrRefCount(interp, A); return rc; } static int JimExprOpTernaryLeft(Jim_Interp *interp, struct JimExprState *e) { Jim_Obj *skip = ExprPop(e); Jim_Obj *A = ExprPop(e); int rc = JIM_OK; /* Repush A */ ExprPush(e, A); switch (ExprBool(interp, A)) { case 0: /* false, skip RHS opcodes */ e->skip = JimWideValue(skip); /* Push a dummy value */ ExprPush(e, Jim_NewIntObj(interp, 0)); break; case 1: /* true so do nothing */ break; case -1: /* Invalid */ rc = JIM_ERR; break; } Jim_DecrRefCount(interp, A); Jim_DecrRefCount(interp, skip); return rc; } static int JimExprOpColonLeft(Jim_Interp *interp, struct JimExprState *e) { Jim_Obj *skip = ExprPop(e); Jim_Obj *B = ExprPop(e); Jim_Obj *A = ExprPop(e); /* No need to check for A as non-boolean */ if (ExprBool(interp, A)) { /* true, so skip RHS opcodes */ e->skip = JimWideValue(skip); /* Repush B as the answer */ ExprPush(e, B); } Jim_DecrRefCount(interp, skip); Jim_DecrRefCount(interp, A); Jim_DecrRefCount(interp, B); return JIM_OK; } static int JimExprOpNull(Jim_Interp *interp, struct JimExprState *e) { return JIM_OK; } enum { LAZY_NONE, LAZY_OP, LAZY_LEFT, LAZY_RIGHT }; /* name - precedence - arity - opcode * * This array *must* be kept in sync with the JIM_EXPROP enum. * * The following macro pre-computes the string length at compile time. */ #define OPRINIT(N, P, A, F, L) {N, F, P, A, L, sizeof(N) - 1} static const struct Jim_ExprOperator Jim_ExprOperators[] = { OPRINIT("*", 110, 2, JimExprOpBin, LAZY_NONE), OPRINIT("/", 110, 2, JimExprOpBin, LAZY_NONE), OPRINIT("%", 110, 2, JimExprOpIntBin, LAZY_NONE), OPRINIT("-", 100, 2, JimExprOpBin, LAZY_NONE), OPRINIT("+", 100, 2, JimExprOpBin, LAZY_NONE), OPRINIT("<<", 90, 2, JimExprOpIntBin, LAZY_NONE), OPRINIT(">>", 90, 2, JimExprOpIntBin, LAZY_NONE), OPRINIT("<<<", 90, 2, JimExprOpIntBin, LAZY_NONE), OPRINIT(">>>", 90, 2, JimExprOpIntBin, LAZY_NONE), OPRINIT("<", 80, 2, JimExprOpBin, LAZY_NONE), OPRINIT(">", 80, 2, JimExprOpBin, LAZY_NONE), OPRINIT("<=", 80, 2, JimExprOpBin, LAZY_NONE), OPRINIT(">=", 80, 2, JimExprOpBin, LAZY_NONE), OPRINIT("==", 70, 2, JimExprOpBin, LAZY_NONE), OPRINIT("!=", 70, 2, JimExprOpBin, LAZY_NONE), OPRINIT("&", 50, 2, JimExprOpIntBin, LAZY_NONE), OPRINIT("^", 49, 2, JimExprOpIntBin, LAZY_NONE), OPRINIT("|", 48, 2, JimExprOpIntBin, LAZY_NONE), OPRINIT("&&", 10, 2, NULL, LAZY_OP), OPRINIT(NULL, 10, 2, JimExprOpAndLeft, LAZY_LEFT), OPRINIT(NULL, 10, 2, JimExprOpAndOrRight, LAZY_RIGHT), OPRINIT("||", 9, 2, NULL, LAZY_OP), OPRINIT(NULL, 9, 2, JimExprOpOrLeft, LAZY_LEFT), OPRINIT(NULL, 9, 2, JimExprOpAndOrRight, LAZY_RIGHT), OPRINIT("?", 5, 2, JimExprOpNull, LAZY_OP), OPRINIT(NULL, 5, 2, JimExprOpTernaryLeft, LAZY_LEFT), OPRINIT(NULL, 5, 2, JimExprOpNull, LAZY_RIGHT), OPRINIT(":", 5, 2, JimExprOpNull, LAZY_OP), OPRINIT(NULL, 5, 2, JimExprOpColonLeft, LAZY_LEFT), OPRINIT(NULL, 5, 2, JimExprOpNull, LAZY_RIGHT), OPRINIT("**", 250, 2, JimExprOpBin, LAZY_NONE), OPRINIT("eq", 60, 2, JimExprOpStrBin, LAZY_NONE), OPRINIT("ne", 60, 2, JimExprOpStrBin, LAZY_NONE), OPRINIT("in", 55, 2, JimExprOpStrBin, LAZY_NONE), OPRINIT("ni", 55, 2, JimExprOpStrBin, LAZY_NONE), OPRINIT("!", 150, 1, JimExprOpNumUnary, LAZY_NONE), OPRINIT("~", 150, 1, JimExprOpIntUnary, LAZY_NONE), OPRINIT(NULL, 150, 1, JimExprOpNumUnary, LAZY_NONE), OPRINIT(NULL, 150, 1, JimExprOpNumUnary, LAZY_NONE), OPRINIT("int", 200, 1, JimExprOpNumUnary, LAZY_NONE), OPRINIT("abs", 200, 1, JimExprOpNumUnary, LAZY_NONE), OPRINIT("double", 200, 1, JimExprOpNumUnary, LAZY_NONE), OPRINIT("round", 200, 1, JimExprOpNumUnary, LAZY_NONE), OPRINIT("rand", 200, 0, JimExprOpNone, LAZY_NONE), OPRINIT("srand", 200, 1, JimExprOpIntUnary, LAZY_NONE), #ifdef JIM_MATH_FUNCTIONS OPRINIT("sin", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), OPRINIT("cos", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), OPRINIT("tan", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), OPRINIT("asin", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), OPRINIT("acos", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), OPRINIT("atan", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), OPRINIT("sinh", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), OPRINIT("cosh", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), OPRINIT("tanh", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), OPRINIT("ceil", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), OPRINIT("floor", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), OPRINIT("exp", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), OPRINIT("log", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), OPRINIT("log10", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), OPRINIT("sqrt", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), OPRINIT("pow", 200, 2, JimExprOpBin, LAZY_NONE), #endif }; #undef OPRINIT #define JIM_EXPR_OPERATORS_NUM \ (sizeof(Jim_ExprOperators)/sizeof(struct Jim_ExprOperator)) static int JimParseExpression(struct JimParserCtx *pc) { /* Discard spaces and quoted newline */ while (isspace(UCHAR(*pc->p)) || (*(pc->p) == '\\' && *(pc->p + 1) == '\n')) { if (*pc->p == '\n') { pc->linenr++; } pc->p++; pc->len--; } if (pc->len == 0) { pc->tstart = pc->tend = pc->p; pc->tline = pc->linenr; pc->tt = JIM_TT_EOL; pc->eof = 1; return JIM_OK; } switch (*(pc->p)) { case '(': pc->tt = JIM_TT_SUBEXPR_START; goto singlechar; case ')': pc->tt = JIM_TT_SUBEXPR_END; goto singlechar; case ',': pc->tt = JIM_TT_SUBEXPR_COMMA; singlechar: pc->tstart = pc->tend = pc->p; pc->tline = pc->linenr; pc->p++; pc->len--; break; case '[': return JimParseCmd(pc); case '$': if (JimParseVar(pc) == JIM_ERR) return JimParseExprOperator(pc); else { /* Don't allow expr sugar in expressions */ if (pc->tt == JIM_TT_EXPRSUGAR) { return JIM_ERR; } return JIM_OK; } break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '.': return JimParseExprNumber(pc); case '"': return JimParseQuote(pc); case '{': return JimParseBrace(pc); case 'N': case 'I': case 'n': case 'i': if (JimParseExprIrrational(pc) == JIM_ERR) return JimParseExprOperator(pc); break; default: return JimParseExprOperator(pc); break; } return JIM_OK; } static int JimParseExprNumber(struct JimParserCtx *pc) { int allowdot = 1; int base = 10; /* Assume an integer for now */ pc->tt = JIM_TT_EXPR_INT; pc->tstart = pc->p; pc->tline = pc->linenr; /* Parse initial 0 */ if (pc->p[0] == '0') { switch (pc->p[1]) { case 'x': case 'X': base = 16; allowdot = 0; pc->p += 2; pc->len -= 2; break; case 'o': case 'O': base = 8; allowdot = 0; pc->p += 2; pc->len -= 2; break; case 'b': case 'B': base = 2; allowdot = 0; pc->p += 2; pc->len -= 2; break; } } while (isdigit(UCHAR(*pc->p)) || (base == 16 && isxdigit(UCHAR(*pc->p))) || (base == 8 && *pc->p >= '0' && *pc->p <= '7') || (base == 2 && (*pc->p == '0' || *pc->p == '1')) || (allowdot && *pc->p == '.') ) { if (*pc->p == '.') { allowdot = 0; pc->tt = JIM_TT_EXPR_DOUBLE; } pc->p++; pc->len--; if (base == 10 && (*pc->p == 'e' || *pc->p == 'E') && (pc->p[1] == '-' || pc->p[1] == '+' || isdigit(UCHAR(pc->p[1])))) { pc->p += 2; pc->len -= 2; pc->tt = JIM_TT_EXPR_DOUBLE; } } pc->tend = pc->p - 1; return JIM_OK; } static int JimParseExprIrrational(struct JimParserCtx *pc) { const char *Tokens[] = { "NaN", "nan", "NAN", "Inf", "inf", "INF", NULL }; const char **token; for (token = Tokens; *token != NULL; token++) { int len = strlen(*token); if (strncmp(*token, pc->p, len) == 0) { pc->tstart = pc->p; pc->tend = pc->p + len - 1; pc->p += len; pc->len -= len; pc->tline = pc->linenr; pc->tt = JIM_TT_EXPR_DOUBLE; return JIM_OK; } } return JIM_ERR; } static int JimParseExprOperator(struct JimParserCtx *pc) { int i; int bestIdx = -1, bestLen = 0; /* Try to get the longest match. */ for (i = 0; i < (signed)JIM_EXPR_OPERATORS_NUM; i++) { const char * const opname = Jim_ExprOperators[i].name; const int oplen = Jim_ExprOperators[i].namelen; if (opname == NULL || opname[0] != pc->p[0]) { continue; } if (oplen > bestLen && strncmp(opname, pc->p, oplen) == 0) { bestIdx = i + JIM_TT_EXPR_OP; bestLen = oplen; } } if (bestIdx == -1) { return JIM_ERR; } /* Validate paretheses around function arguments */ if (bestIdx >= JIM_EXPROP_FUNC_FIRST) { const char *p = pc->p + bestLen; int len = pc->len - bestLen; while (len && isspace(UCHAR(*p))) { len--; p++; } if (*p != '(') { return JIM_ERR; } } pc->tstart = pc->p; pc->tend = pc->p + bestLen - 1; pc->p += bestLen; pc->len -= bestLen; pc->tline = pc->linenr; pc->tt = bestIdx; return JIM_OK; } static const struct Jim_ExprOperator *JimExprOperatorInfoByOpcode(int opcode) { static Jim_ExprOperator dummy_op; if (opcode < JIM_TT_EXPR_OP) { return &dummy_op; } return &Jim_ExprOperators[opcode - JIM_TT_EXPR_OP]; } const char *jim_tt_name(int type) { static const char * const tt_names[JIM_TT_EXPR_OP] = { "NIL", "STR", "ESC", "VAR", "ARY", "CMD", "SEP", "EOL", "EOF", "LIN", "WRD", "(((", ")))", ",,,", "INT", "DBL", "$()" }; if (type < JIM_TT_EXPR_OP) { return tt_names[type]; } else { const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(type); static char buf[20]; if (op->name) { return op->name; } sprintf(buf, "(%d)", type); return buf; } } /* ----------------------------------------------------------------------------- * Expression Object * ---------------------------------------------------------------------------*/ static void FreeExprInternalRep(Jim_Interp *interp, Jim_Obj *objPtr); static void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr); static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr); static const Jim_ObjType exprObjType = { "expression", FreeExprInternalRep, DupExprInternalRep, NULL, JIM_TYPE_REFERENCES, }; /* Expr bytecode structure */ typedef struct ExprByteCode { ScriptToken *token; /* Tokens array. */ int len; /* Length as number of tokens. */ int inUse; /* Used for sharing. */ } ExprByteCode; static void ExprFreeByteCode(Jim_Interp *interp, ExprByteCode * expr) { int i; for (i = 0; i < expr->len; i++) { Jim_DecrRefCount(interp, expr->token[i].objPtr); } Jim_Free(expr->token); Jim_Free(expr); } static void FreeExprInternalRep(Jim_Interp *interp, Jim_Obj *objPtr) { ExprByteCode *expr = (void *)objPtr->internalRep.ptr; if (expr) { if (--expr->inUse != 0) { return; } ExprFreeByteCode(interp, expr); } } static void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr) { JIM_NOTUSED(interp); JIM_NOTUSED(srcPtr); /* Just returns an simple string. */ dupPtr->typePtr = NULL; } /* Check if an expr program looks correct. */ static int ExprCheckCorrectness(ExprByteCode * expr) { int i; int stacklen = 0; int ternary = 0; /* Try to check if there are stack underflows, * and make sure at the end of the program there is * a single result on the stack. */ for (i = 0; i < expr->len; i++) { ScriptToken *t = &expr->token[i]; const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(t->type); stacklen -= op->arity; if (stacklen < 0) { break; } if (t->type == JIM_EXPROP_TERNARY || t->type == JIM_EXPROP_TERNARY_LEFT) { ternary++; } else if (t->type == JIM_EXPROP_COLON || t->type == JIM_EXPROP_COLON_LEFT) { ternary--; } /* All operations and operands add one to the stack */ stacklen++; } if (stacklen != 1 || ternary != 0) { return JIM_ERR; } return JIM_OK; } /* This procedure converts every occurrence of || and && opereators * in lazy unary versions. * * a b || is converted into: * * a |L b |R * * a b && is converted into: * * a &L b &R * * "|L" checks if 'a' is true: * 1) if it is true pushes 1 and skips instructions to reach * the opcode just after |R. * 2) if it is false does nothing. * "|R" checks if 'b' is true: * 1) if it is true pushes 1, otherwise pushes 0. * * "&L" checks if 'a' is true: * 1) if it is true does nothing. * 2) If it is false pushes 0 and skips instructions to reach * the opcode just after &R * "&R" checks if 'a' is true: * if it is true pushes 1, otherwise pushes 0. */ static int ExprAddLazyOperator(Jim_Interp *interp, ExprByteCode * expr, ParseToken *t) { int i; int leftindex, arity, offset; /* Search for the end of the first operator */ leftindex = expr->len - 1; arity = 1; while (arity) { ScriptToken *tt = &expr->token[leftindex]; if (tt->type >= JIM_TT_EXPR_OP) { arity += JimExprOperatorInfoByOpcode(tt->type)->arity; } arity--; if (--leftindex < 0) { return JIM_ERR; } } leftindex++; /* Move them up */ memmove(&expr->token[leftindex + 2], &expr->token[leftindex], sizeof(*expr->token) * (expr->len - leftindex)); expr->len += 2; offset = (expr->len - leftindex) - 1; /* Now we rely on the fact the the left and right version have opcodes * 1 and 2 after the main opcode respectively */ expr->token[leftindex + 1].type = t->type + 1; expr->token[leftindex + 1].objPtr = interp->emptyObj; expr->token[leftindex].type = JIM_TT_EXPR_INT; expr->token[leftindex].objPtr = Jim_NewIntObj(interp, offset); /* Now add the 'R' operator */ expr->token[expr->len].objPtr = interp->emptyObj; expr->token[expr->len].type = t->type + 2; expr->len++; /* Do we need to adjust the skip count for any &L, |L, ?L or :L in the left operand? */ for (i = leftindex - 1; i > 0; i--) { const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(expr->token[i].type); if (op->lazy == LAZY_LEFT) { if (JimWideValue(expr->token[i - 1].objPtr) + i - 1 >= leftindex) { JimWideValue(expr->token[i - 1].objPtr) += 2; } } } return JIM_OK; } static int ExprAddOperator(Jim_Interp *interp, ExprByteCode * expr, ParseToken *t) { struct ScriptToken *token = &expr->token[expr->len]; const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(t->type); if (op->lazy == LAZY_OP) { if (ExprAddLazyOperator(interp, expr, t) != JIM_OK) { Jim_SetResultFormatted(interp, "Expression has bad operands to %s", op->name); return JIM_ERR; } } else { token->objPtr = interp->emptyObj; token->type = t->type; expr->len++; } return JIM_OK; } /** * Returns the index of the COLON_LEFT to the left of 'right_index' * taking into account nesting. * * The expression *must* be well formed, thus a COLON_LEFT will always be found. */ static int ExprTernaryGetColonLeftIndex(ExprByteCode *expr, int right_index) { int ternary_count = 1; right_index--; while (right_index > 1) { if (expr->token[right_index].type == JIM_EXPROP_TERNARY_LEFT) { ternary_count--; } else if (expr->token[right_index].type == JIM_EXPROP_COLON_RIGHT) { ternary_count++; } else if (expr->token[right_index].type == JIM_EXPROP_COLON_LEFT && ternary_count == 1) { return right_index; } right_index--; } /*notreached*/ return -1; } /** * Find the left/right indices for the ternary expression to the left of 'right_index'. * * Returns 1 if found, and fills in *prev_right_index and *prev_left_index. * Otherwise returns 0. */ static int ExprTernaryGetMoveIndices(ExprByteCode *expr, int right_index, int *prev_right_index, int *prev_left_index) { int i = right_index - 1; int ternary_count = 1; while (i > 1) { if (expr->token[i].type == JIM_EXPROP_TERNARY_LEFT) { if (--ternary_count == 0 && expr->token[i - 2].type == JIM_EXPROP_COLON_RIGHT) { *prev_right_index = i - 2; *prev_left_index = ExprTernaryGetColonLeftIndex(expr, *prev_right_index); return 1; } } else if (expr->token[i].type == JIM_EXPROP_COLON_RIGHT) { if (ternary_count == 0) { return 0; } ternary_count++; } i--; } return 0; } /* * ExprTernaryReorderExpression description * ======================================== * * ?: is right-to-left associative which doesn't work with the stack-based * expression engine. The fix is to reorder the bytecode. * * The expression: * * expr 1?2:0?3:4 * * Has initial bytecode: * * '1' '2' (40=TERNARY_LEFT) '2' (41=TERNARY_RIGHT) '2' (43=COLON_LEFT) '0' (44=COLON_RIGHT) * '2' (40=TERNARY_LEFT) '3' (41=TERNARY_RIGHT) '2' (43=COLON_LEFT) '4' (44=COLON_RIGHT) * * The fix involves simulating this expression instead: * * expr 1?2:(0?3:4) * * With the following bytecode: * * '1' '2' (40=TERNARY_LEFT) '2' (41=TERNARY_RIGHT) '10' (43=COLON_LEFT) '0' '2' (40=TERNARY_LEFT) * '3' (41=TERNARY_RIGHT) '2' (43=COLON_LEFT) '4' (44=COLON_RIGHT) (44=COLON_RIGHT) * * i.e. The token COLON_RIGHT at index 8 is moved towards the end of the stack, all tokens above 8 * are shifted down and the skip count of the token JIM_EXPROP_COLON_LEFT at index 5 is * incremented by the amount tokens shifted down. The token JIM_EXPROP_COLON_RIGHT that is moved * is identified as immediately preceeding a token JIM_EXPROP_TERNARY_LEFT * * ExprTernaryReorderExpression works thus as follows : * - start from the end of the stack * - while walking towards the beginning of the stack * if token=JIM_EXPROP_COLON_RIGHT then * find the associated token JIM_EXPROP_TERNARY_LEFT, which allows to * find the associated token previous(JIM_EXPROP_COLON_RIGHT) * find the associated token previous(JIM_EXPROP_LEFT_RIGHT) * if all found then * perform the rotation * update the skip count of the token previous(JIM_EXPROP_LEFT_RIGHT) * end if * end if * * Note: care has to be taken for nested ternary constructs!!! */ static void ExprTernaryReorderExpression(Jim_Interp *interp, ExprByteCode *expr) { int i; for (i = expr->len - 1; i > 1; i--) { int prev_right_index; int prev_left_index; int j; ScriptToken tmp; if (expr->token[i].type != JIM_EXPROP_COLON_RIGHT) { continue; } /* COLON_RIGHT found: get the indexes needed to move the tokens in the stack (if any) */ if (ExprTernaryGetMoveIndices(expr, i, &prev_right_index, &prev_left_index) == 0) { continue; } /* ** rotate tokens down ** ** +-> [i] : JIM_EXPROP_COLON_RIGHT ** | | | ** | V V ** | [...] : ... ** | | | ** | V V ** | [...] : ... ** | | | ** | V V ** +- [prev_right_index] : JIM_EXPROP_COLON_RIGHT */ tmp = expr->token[prev_right_index]; for (j = prev_right_index; j < i; j++) { expr->token[j] = expr->token[j + 1]; } expr->token[i] = tmp; /* Increment the 'skip' count associated to the previous JIM_EXPROP_COLON_LEFT token * * This is 'colon left increment' = i - prev_right_index * * [prev_left_index] : JIM_EXPROP_LEFT_RIGHT * [prev_left_index-1] : skip_count * */ JimWideValue(expr->token[prev_left_index-1].objPtr) += (i - prev_right_index); /* Adjust for i-- in the loop */ i++; } } static ExprByteCode *ExprCreateByteCode(Jim_Interp *interp, const ParseTokenList *tokenlist, Jim_Obj *fileNameObj) { Jim_Stack stack; ExprByteCode *expr; int ok = 1; int i; int prevtt = JIM_TT_NONE; int have_ternary = 0; /* -1 for EOL */ int count = tokenlist->count - 1; expr = Jim_Alloc(sizeof(*expr)); expr->inUse = 1; expr->len = 0; Jim_InitStack(&stack); /* Need extra bytecodes for lazy operators. * Also check for the ternary operator */ for (i = 0; i < tokenlist->count; i++) { ParseToken *t = &tokenlist->list[i]; const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(t->type); if (op->lazy == LAZY_OP) { count += 2; /* Ternary is a lazy op but also needs reordering */ if (t->type == JIM_EXPROP_TERNARY) { have_ternary = 1; } } } expr->token = Jim_Alloc(sizeof(ScriptToken) * count); for (i = 0; i < tokenlist->count && ok; i++) { ParseToken *t = &tokenlist->list[i]; /* Next token will be stored here */ struct ScriptToken *token = &expr->token[expr->len]; if (t->type == JIM_TT_EOL) { break; } switch (t->type) { case JIM_TT_STR: case JIM_TT_ESC: case JIM_TT_VAR: case JIM_TT_DICTSUGAR: case JIM_TT_EXPRSUGAR: case JIM_TT_CMD: token->type = t->type; strexpr: token->objPtr = Jim_NewStringObj(interp, t->token, t->len); if (t->type == JIM_TT_CMD) { /* Only commands need source info */ JimSetSourceInfo(interp, token->objPtr, fileNameObj, t->line); } expr->len++; break; case JIM_TT_EXPR_INT: case JIM_TT_EXPR_DOUBLE: { char *endptr; if (t->type == JIM_TT_EXPR_INT) { token->objPtr = Jim_NewIntObj(interp, jim_strtoull(t->token, &endptr)); } else { token->objPtr = Jim_NewDoubleObj(interp, strtod(t->token, &endptr)); } if (endptr != t->token + t->len) { /* Conversion failed, so just store it as a string */ Jim_FreeNewObj(interp, token->objPtr); token->type = JIM_TT_STR; goto strexpr; } token->type = t->type; expr->len++; } break; case JIM_TT_SUBEXPR_START: Jim_StackPush(&stack, t); prevtt = JIM_TT_NONE; continue; case JIM_TT_SUBEXPR_COMMA: /* Simple approach. Comma is simply ignored */ continue; case JIM_TT_SUBEXPR_END: ok = 0; while (Jim_StackLen(&stack)) { ParseToken *tt = Jim_StackPop(&stack); if (tt->type == JIM_TT_SUBEXPR_START) { ok = 1; break; } if (ExprAddOperator(interp, expr, tt) != JIM_OK) { goto err; } } if (!ok) { Jim_SetResultString(interp, "Unexpected close parenthesis", -1); goto err; } break; default:{ /* Must be an operator */ const struct Jim_ExprOperator *op; ParseToken *tt; /* Convert -/+ to unary minus or unary plus if necessary */ if (prevtt == JIM_TT_NONE || prevtt >= JIM_TT_EXPR_OP) { if (t->type == JIM_EXPROP_SUB) { t->type = JIM_EXPROP_UNARYMINUS; } else if (t->type == JIM_EXPROP_ADD) { t->type = JIM_EXPROP_UNARYPLUS; } } op = JimExprOperatorInfoByOpcode(t->type); /* Now handle precedence */ while ((tt = Jim_StackPeek(&stack)) != NULL) { const struct Jim_ExprOperator *tt_op = JimExprOperatorInfoByOpcode(tt->type); /* Note that right-to-left associativity of ?: operator is handled later */ if (op->arity != 1 && tt_op->precedence >= op->precedence) { if (ExprAddOperator(interp, expr, tt) != JIM_OK) { ok = 0; goto err; } Jim_StackPop(&stack); } else { break; } } Jim_StackPush(&stack, t); break; } } prevtt = t->type; } /* Reduce any remaining subexpr */ while (Jim_StackLen(&stack)) { ParseToken *tt = Jim_StackPop(&stack); if (tt->type == JIM_TT_SUBEXPR_START) { ok = 0; Jim_SetResultString(interp, "Missing close parenthesis", -1); goto err; } if (ExprAddOperator(interp, expr, tt) != JIM_OK) { ok = 0; goto err; } } if (have_ternary) { ExprTernaryReorderExpression(interp, expr); } err: /* Free the stack used for the compilation. */ Jim_FreeStack(&stack); for (i = 0; i < expr->len; i++) { Jim_IncrRefCount(expr->token[i].objPtr); } if (!ok) { ExprFreeByteCode(interp, expr); return NULL; } return expr; } /* This method takes the string representation of an expression * and generates a program for the Expr's stack-based VM. */ static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr) { int exprTextLen; const char *exprText; struct JimParserCtx parser; struct ExprByteCode *expr; ParseTokenList tokenlist; int line; Jim_Obj *fileNameObj; int rc = JIM_ERR; /* Try to get information about filename / line number */ if (objPtr->typePtr == &sourceObjType) { fileNameObj = objPtr->internalRep.sourceValue.fileNameObj; line = objPtr->internalRep.sourceValue.lineNumber; } else { fileNameObj = interp->emptyObj; line = 1; } Jim_IncrRefCount(fileNameObj); exprText = Jim_GetString(objPtr, &exprTextLen); /* Initially tokenise the expression into tokenlist */ ScriptTokenListInit(&tokenlist); JimParserInit(&parser, exprText, exprTextLen, line); while (!parser.eof) { if (JimParseExpression(&parser) != JIM_OK) { ScriptTokenListFree(&tokenlist); invalidexpr: Jim_SetResultFormatted(interp, "syntax error in expression: \"%#s\"", objPtr); expr = NULL; goto err; } ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt, parser.tline); } #ifdef DEBUG_SHOW_EXPR_TOKENS { int i; printf("==== Expr Tokens ====\n"); for (i = 0; i < tokenlist.count; i++) { printf("[%2d]@%d %s '%.*s'\n", i, tokenlist.list[i].line, jim_tt_name(tokenlist.list[i].type), tokenlist.list[i].len, tokenlist.list[i].token); } } #endif /* Now create the expression bytecode from the tokenlist */ expr = ExprCreateByteCode(interp, &tokenlist, fileNameObj); /* No longer need the token list */ ScriptTokenListFree(&tokenlist); if (!expr) { goto err; } #ifdef DEBUG_SHOW_EXPR { int i; printf("==== Expr ====\n"); for (i = 0; i < expr->len; i++) { ScriptToken *t = &expr->token[i]; printf("[%2d] %s '%s'\n", i, jim_tt_name(t->type), Jim_String(t->objPtr)); } } #endif /* Check program correctness. */ if (ExprCheckCorrectness(expr) != JIM_OK) { ExprFreeByteCode(interp, expr); goto invalidexpr; } rc = JIM_OK; err: /* Free the old internal rep and set the new one. */ Jim_DecrRefCount(interp, fileNameObj); Jim_FreeIntRep(interp, objPtr); Jim_SetIntRepPtr(objPtr, expr); objPtr->typePtr = &exprObjType; return rc; } static ExprByteCode *JimGetExpression(Jim_Interp *interp, Jim_Obj *objPtr) { if (objPtr->typePtr != &exprObjType) { if (SetExprFromAny(interp, objPtr) != JIM_OK) { return NULL; } } return (ExprByteCode *) Jim_GetIntRepPtr(objPtr); } /* ----------------------------------------------------------------------------- * Expressions evaluation. * Jim uses a specialized stack-based virtual machine for expressions, * that takes advantage of the fact that expr's operators * can't be redefined. * * Jim_EvalExpression() uses the bytecode compiled by * SetExprFromAny() method of the "expression" object. * * On success a Tcl Object containing the result of the evaluation * is stored into expResultPtrPtr (having refcount of 1), and JIM_OK is * returned. * On error the function returns a retcode != to JIM_OK and set a suitable * error on the interp. * ---------------------------------------------------------------------------*/ #define JIM_EE_STATICSTACK_LEN 10 int Jim_EvalExpression(Jim_Interp *interp, Jim_Obj *exprObjPtr, Jim_Obj **exprResultPtrPtr) { ExprByteCode *expr; Jim_Obj *staticStack[JIM_EE_STATICSTACK_LEN]; int i; int retcode = JIM_OK; struct JimExprState e; expr = JimGetExpression(interp, exprObjPtr); if (!expr) { return JIM_ERR; /* error in expression. */ } #ifdef JIM_OPTIMIZATION /* Check for one of the following common expressions used by while/for * * CONST * $a * !$a * $a < CONST, $a < $b * $a <= CONST, $a <= $b * $a > CONST, $a > $b * $a >= CONST, $a >= $b * $a != CONST, $a != $b * $a == CONST, $a == $b */ { Jim_Obj *objPtr; /* STEP 1 -- Check if there are the conditions to run the specialized * version of while */ switch (expr->len) { case 1: if (expr->token[0].type == JIM_TT_EXPR_INT) { *exprResultPtrPtr = expr->token[0].objPtr; Jim_IncrRefCount(*exprResultPtrPtr); return JIM_OK; } if (expr->token[0].type == JIM_TT_VAR) { objPtr = Jim_GetVariable(interp, expr->token[0].objPtr, JIM_ERRMSG); if (objPtr) { *exprResultPtrPtr = objPtr; Jim_IncrRefCount(*exprResultPtrPtr); return JIM_OK; } } break; case 2: if (expr->token[1].type == JIM_EXPROP_NOT && expr->token[0].type == JIM_TT_VAR) { jim_wide wideValue; objPtr = Jim_GetVariable(interp, expr->token[0].objPtr, JIM_NONE); if (objPtr && JimIsWide(objPtr) && Jim_GetWide(interp, objPtr, &wideValue) == JIM_OK) { *exprResultPtrPtr = wideValue ? interp->falseObj : interp->trueObj; Jim_IncrRefCount(*exprResultPtrPtr); return JIM_OK; } } break; case 3: if (expr->token[0].type == JIM_TT_VAR && (expr->token[1].type == JIM_TT_EXPR_INT || expr->token[1].type == JIM_TT_VAR)) { switch (expr->token[2].type) { case JIM_EXPROP_LT: case JIM_EXPROP_LTE: case JIM_EXPROP_GT: case JIM_EXPROP_GTE: case JIM_EXPROP_NUMEQ: case JIM_EXPROP_NUMNE:{ /* optimise ok */ jim_wide wideValueA; jim_wide wideValueB; objPtr = Jim_GetVariable(interp, expr->token[0].objPtr, JIM_NONE); if (objPtr && JimIsWide(objPtr) && Jim_GetWide(interp, objPtr, &wideValueA) == JIM_OK) { if (expr->token[1].type == JIM_TT_VAR) { objPtr = Jim_GetVariable(interp, expr->token[1].objPtr, JIM_NONE); } else { objPtr = expr->token[1].objPtr; } if (objPtr && JimIsWide(objPtr) && Jim_GetWide(interp, objPtr, &wideValueB) == JIM_OK) { int cmpRes; switch (expr->token[2].type) { case JIM_EXPROP_LT: cmpRes = wideValueA < wideValueB; break; case JIM_EXPROP_LTE: cmpRes = wideValueA <= wideValueB; break; case JIM_EXPROP_GT: cmpRes = wideValueA > wideValueB; break; case JIM_EXPROP_GTE: cmpRes = wideValueA >= wideValueB; break; case JIM_EXPROP_NUMEQ: cmpRes = wideValueA == wideValueB; break; case JIM_EXPROP_NUMNE: cmpRes = wideValueA != wideValueB; break; default: /*notreached */ cmpRes = 0; } *exprResultPtrPtr = cmpRes ? interp->trueObj : interp->falseObj; Jim_IncrRefCount(*exprResultPtrPtr); return JIM_OK; } } } } } break; } } #endif /* In order to avoid that the internal repr gets freed due to * shimmering of the exprObjPtr's object, we make the internal rep * shared. */ expr->inUse++; /* The stack-based expr VM itself */ /* Stack allocation. Expr programs have the feature that * a program of length N can't require a stack longer than * N. */ if (expr->len > JIM_EE_STATICSTACK_LEN) e.stack = Jim_Alloc(sizeof(Jim_Obj *) * expr->len); else e.stack = staticStack; e.stacklen = 0; /* Execute every instruction */ for (i = 0; i < expr->len && retcode == JIM_OK; i++) { Jim_Obj *objPtr; switch (expr->token[i].type) { case JIM_TT_EXPR_INT: case JIM_TT_EXPR_DOUBLE: case JIM_TT_STR: ExprPush(&e, expr->token[i].objPtr); break; case JIM_TT_VAR: objPtr = Jim_GetVariable(interp, expr->token[i].objPtr, JIM_ERRMSG); if (objPtr) { ExprPush(&e, objPtr); } else { retcode = JIM_ERR; } break; case JIM_TT_DICTSUGAR: objPtr = JimExpandDictSugar(interp, expr->token[i].objPtr); if (objPtr) { ExprPush(&e, objPtr); } else { retcode = JIM_ERR; } break; case JIM_TT_ESC: retcode = Jim_SubstObj(interp, expr->token[i].objPtr, &objPtr, JIM_NONE); if (retcode == JIM_OK) { ExprPush(&e, objPtr); } break; case JIM_TT_CMD: retcode = Jim_EvalObj(interp, expr->token[i].objPtr); if (retcode == JIM_OK) { ExprPush(&e, Jim_GetResult(interp)); } break; default:{ /* Find and execute the operation */ e.skip = 0; e.opcode = expr->token[i].type; retcode = JimExprOperatorInfoByOpcode(e.opcode)->funcop(interp, &e); /* Skip some opcodes if necessary */ i += e.skip; continue; } } } expr->inUse--; if (retcode == JIM_OK) { *exprResultPtrPtr = ExprPop(&e); } else { for (i = 0; i < e.stacklen; i++) { Jim_DecrRefCount(interp, e.stack[i]); } } if (e.stack != staticStack) { Jim_Free(e.stack); } return retcode; } int Jim_GetBoolFromExpr(Jim_Interp *interp, Jim_Obj *exprObjPtr, int *boolPtr) { int retcode; jim_wide wideValue; double doubleValue; Jim_Obj *exprResultPtr; retcode = Jim_EvalExpression(interp, exprObjPtr, &exprResultPtr); if (retcode != JIM_OK) return retcode; if (JimGetWideNoErr(interp, exprResultPtr, &wideValue) != JIM_OK) { if (Jim_GetDouble(interp, exprResultPtr, &doubleValue) != JIM_OK) { Jim_DecrRefCount(interp, exprResultPtr); return JIM_ERR; } else { Jim_DecrRefCount(interp, exprResultPtr); *boolPtr = doubleValue != 0; return JIM_OK; } } *boolPtr = wideValue != 0; Jim_DecrRefCount(interp, exprResultPtr); return JIM_OK; } /* ----------------------------------------------------------------------------- * ScanFormat String Object * ---------------------------------------------------------------------------*/ /* This Jim_Obj will held a parsed representation of a format string passed to * the Jim_ScanString command. For error diagnostics, the scanformat string has * to be parsed in its entirely first and then, if correct, can be used for * scanning. To avoid endless re-parsing, the parsed representation will be * stored in an internal representation and re-used for performance reason. */ /* A ScanFmtPartDescr will held the information of /one/ part of the whole * scanformat string. This part will later be used to extract information * out from the string to be parsed by Jim_ScanString */ typedef struct ScanFmtPartDescr { char *arg; /* Specification of a CHARSET conversion */ char *prefix; /* Prefix to be scanned literally before conversion */ size_t width; /* Maximal width of input to be converted */ int pos; /* -1 - no assign, 0 - natural pos, >0 - XPG3 pos */ char type; /* Type of conversion (e.g. c, d, f) */ char modifier; /* Modify type (e.g. l - long, h - short */ } ScanFmtPartDescr; /* The ScanFmtStringObj will hold the internal representation of a scanformat * string parsed and separated in part descriptions. Furthermore it contains * the original string representation of the scanformat string to allow for * fast update of the Jim_Obj's string representation part. * * As an add-on the internal object representation adds some scratch pad area * for usage by Jim_ScanString to avoid endless allocating and freeing of * memory for purpose of string scanning. * * The error member points to a static allocated string in case of a mal- * formed scanformat string or it contains '0' (NULL) in case of a valid * parse representation. * * The whole memory of the internal representation is allocated as a single * area of memory that will be internally separated. So freeing and duplicating * of such an object is cheap */ typedef struct ScanFmtStringObj { jim_wide size; /* Size of internal repr in bytes */ char *stringRep; /* Original string representation */ size_t count; /* Number of ScanFmtPartDescr contained */ size_t convCount; /* Number of conversions that will assign */ size_t maxPos; /* Max position index if XPG3 is used */ const char *error; /* Ptr to error text (NULL if no error */ char *scratch; /* Some scratch pad used by Jim_ScanString */ ScanFmtPartDescr descr[1]; /* The vector of partial descriptions */ } ScanFmtStringObj; static void FreeScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *objPtr); static void DupScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr); static void UpdateStringOfScanFmt(Jim_Obj *objPtr); static const Jim_ObjType scanFmtStringObjType = { "scanformatstring", FreeScanFmtInternalRep, DupScanFmtInternalRep, UpdateStringOfScanFmt, JIM_TYPE_NONE, }; void FreeScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *objPtr) { JIM_NOTUSED(interp); Jim_Free((char *)objPtr->internalRep.ptr); objPtr->internalRep.ptr = 0; } void DupScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr) { size_t size = (size_t) ((ScanFmtStringObj *) srcPtr->internalRep.ptr)->size; ScanFmtStringObj *newVec = (ScanFmtStringObj *) Jim_Alloc(size); JIM_NOTUSED(interp); memcpy(newVec, srcPtr->internalRep.ptr, size); dupPtr->internalRep.ptr = newVec; dupPtr->typePtr = &scanFmtStringObjType; } void UpdateStringOfScanFmt(Jim_Obj *objPtr) { char *bytes = ((ScanFmtStringObj *) objPtr->internalRep.ptr)->stringRep; objPtr->bytes = Jim_StrDup(bytes); objPtr->length = strlen(bytes); } /* SetScanFmtFromAny will parse a given string and create the internal * representation of the format specification. In case of an error * the error data member of the internal representation will be set * to an descriptive error text and the function will be left with * JIM_ERR to indicate unsucessful parsing (aka. malformed scanformat * specification */ static int SetScanFmtFromAny(Jim_Interp *interp, Jim_Obj *objPtr) { ScanFmtStringObj *fmtObj; char *buffer; int maxCount, i, approxSize, lastPos = -1; const char *fmt = objPtr->bytes; int maxFmtLen = objPtr->length; const char *fmtEnd = fmt + maxFmtLen; int curr; Jim_FreeIntRep(interp, objPtr); /* Count how many conversions could take place maximally */ for (i = 0, maxCount = 0; i < maxFmtLen; ++i) if (fmt[i] == '%') ++maxCount; /* Calculate an approximation of the memory necessary */ approxSize = sizeof(ScanFmtStringObj) /* Size of the container */ +(maxCount + 1) * sizeof(ScanFmtPartDescr) /* Size of all partials */ +maxFmtLen * sizeof(char) + 3 + 1 /* Scratch + "%n" + '\0' */ + maxFmtLen * sizeof(char) + 1 /* Original stringrep */ + maxFmtLen * sizeof(char) /* Arg for CHARSETs */ +(maxCount + 1) * sizeof(char) /* '\0' for every partial */ +1; /* safety byte */ fmtObj = (ScanFmtStringObj *) Jim_Alloc(approxSize); memset(fmtObj, 0, approxSize); fmtObj->size = approxSize; fmtObj->maxPos = 0; fmtObj->scratch = (char *)&fmtObj->descr[maxCount + 1]; fmtObj->stringRep = fmtObj->scratch + maxFmtLen + 3 + 1; memcpy(fmtObj->stringRep, fmt, maxFmtLen); buffer = fmtObj->stringRep + maxFmtLen + 1; objPtr->internalRep.ptr = fmtObj; objPtr->typePtr = &scanFmtStringObjType; for (i = 0, curr = 0; fmt < fmtEnd; ++fmt) { int width = 0, skip; ScanFmtPartDescr *descr = &fmtObj->descr[curr]; fmtObj->count++; descr->width = 0; /* Assume width unspecified */ /* Overread and store any "literal" prefix */ if (*fmt != '%' || fmt[1] == '%') { descr->type = 0; descr->prefix = &buffer[i]; for (; fmt < fmtEnd; ++fmt) { if (*fmt == '%') { if (fmt[1] != '%') break; ++fmt; } buffer[i++] = *fmt; } buffer[i++] = 0; } /* Skip the conversion introducing '%' sign */ ++fmt; /* End reached due to non-conversion literal only? */ if (fmt >= fmtEnd) goto done; descr->pos = 0; /* Assume "natural" positioning */ if (*fmt == '*') { descr->pos = -1; /* Okay, conversion will not be assigned */ ++fmt; } else fmtObj->convCount++; /* Otherwise count as assign-conversion */ /* Check if next token is a number (could be width or pos */ if (sscanf(fmt, "%d%n", &width, &skip) == 1) { fmt += skip; /* Was the number a XPG3 position specifier? */ if (descr->pos != -1 && *fmt == '$') { int prev; ++fmt; descr->pos = width; width = 0; /* Look if "natural" postioning and XPG3 one was mixed */ if ((lastPos == 0 && descr->pos > 0) || (lastPos > 0 && descr->pos == 0)) { fmtObj->error = "cannot mix \"%\" and \"%n$\" conversion specifiers"; return JIM_ERR; } /* Look if this position was already used */ for (prev = 0; prev < curr; ++prev) { if (fmtObj->descr[prev].pos == -1) continue; if (fmtObj->descr[prev].pos == descr->pos) { fmtObj->error = "variable is assigned by multiple \"%n$\" conversion specifiers"; return JIM_ERR; } } /* Try to find a width after the XPG3 specifier */ if (sscanf(fmt, "%d%n", &width, &skip) == 1) { descr->width = width; fmt += skip; } if (descr->pos > 0 && (size_t) descr->pos > fmtObj->maxPos) fmtObj->maxPos = descr->pos; } else { /* Number was not a XPG3, so it has to be a width */ descr->width = width; } } /* If positioning mode was undetermined yet, fix this */ if (lastPos == -1) lastPos = descr->pos; /* Handle CHARSET conversion type ... */ if (*fmt == '[') { int swapped = 1, beg = i, end, j; descr->type = '['; descr->arg = &buffer[i]; ++fmt; if (*fmt == '^') buffer[i++] = *fmt++; if (*fmt == ']') buffer[i++] = *fmt++; while (*fmt && *fmt != ']') buffer[i++] = *fmt++; if (*fmt != ']') { fmtObj->error = "unmatched [ in format string"; return JIM_ERR; } end = i; buffer[i++] = 0; /* In case a range fence was given "backwards", swap it */ while (swapped) { swapped = 0; for (j = beg + 1; j < end - 1; ++j) { if (buffer[j] == '-' && buffer[j - 1] > buffer[j + 1]) { char tmp = buffer[j - 1]; buffer[j - 1] = buffer[j + 1]; buffer[j + 1] = tmp; swapped = 1; } } } } else { /* Remember any valid modifier if given */ if (strchr("hlL", *fmt) != 0) descr->modifier = tolower((int)*fmt++); descr->type = *fmt; if (strchr("efgcsndoxui", *fmt) == 0) { fmtObj->error = "bad scan conversion character"; return JIM_ERR; } else if (*fmt == 'c' && descr->width != 0) { fmtObj->error = "field width may not be specified in %c " "conversion"; return JIM_ERR; } else if (*fmt == 'u' && descr->modifier == 'l') { fmtObj->error = "unsigned wide not supported"; return JIM_ERR; } } curr++; } done: return JIM_OK; } /* Some accessor macros to allow lowlevel access to fields of internal repr */ #define FormatGetCnvCount(_fo_) \ ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->convCount #define FormatGetMaxPos(_fo_) \ ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->maxPos #define FormatGetError(_fo_) \ ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->error /* JimScanAString is used to scan an unspecified string that ends with * next WS, or a string that is specified via a charset. * */ static Jim_Obj *JimScanAString(Jim_Interp *interp, const char *sdescr, const char *str) { char *buffer = Jim_StrDup(str); char *p = buffer; while (*str) { int c; int n; if (!sdescr && isspace(UCHAR(*str))) break; /* EOS via WS if unspecified */ n = utf8_tounicode(str, &c); if (sdescr && !JimCharsetMatch(sdescr, c, JIM_CHARSET_SCAN)) break; while (n--) *p++ = *str++; } *p = 0; return Jim_NewStringObjNoAlloc(interp, buffer, p - buffer); } /* ScanOneEntry will scan one entry out of the string passed as argument. * It use the sscanf() function for this task. After extracting and * converting of the value, the count of scanned characters will be * returned of -1 in case of no conversion tool place and string was * already scanned thru */ static int ScanOneEntry(Jim_Interp *interp, const char *str, int pos, int strLen, ScanFmtStringObj * fmtObj, long idx, Jim_Obj **valObjPtr) { const char *tok; const ScanFmtPartDescr *descr = &fmtObj->descr[idx]; size_t scanned = 0; size_t anchor = pos; int i; Jim_Obj *tmpObj = NULL; /* First pessimistically assume, we will not scan anything :-) */ *valObjPtr = 0; if (descr->prefix) { /* There was a prefix given before the conversion, skip it and adjust * the string-to-be-parsed accordingly */ /* XXX: Should be checking strLen, not str[pos] */ for (i = 0; pos < strLen && descr->prefix[i]; ++i) { /* If prefix require, skip WS */ if (isspace(UCHAR(descr->prefix[i]))) while (pos < strLen && isspace(UCHAR(str[pos]))) ++pos; else if (descr->prefix[i] != str[pos]) break; /* Prefix do not match here, leave the loop */ else ++pos; /* Prefix matched so far, next round */ } if (pos >= strLen) { return -1; /* All of str consumed: EOF condition */ } else if (descr->prefix[i] != 0) return 0; /* Not whole prefix consumed, no conversion possible */ } /* For all but following conversion, skip leading WS */ if (descr->type != 'c' && descr->type != '[' && descr->type != 'n') while (isspace(UCHAR(str[pos]))) ++pos; /* Determine how much skipped/scanned so far */ scanned = pos - anchor; /* %c is a special, simple case. no width */ if (descr->type == 'n') { /* Return pseudo conversion means: how much scanned so far? */ *valObjPtr = Jim_NewIntObj(interp, anchor + scanned); } else if (pos >= strLen) { /* Cannot scan anything, as str is totally consumed */ return -1; } else if (descr->type == 'c') { int c; scanned += utf8_tounicode(&str[pos], &c); *valObjPtr = Jim_NewIntObj(interp, c); return scanned; } else { /* Processing of conversions follows ... */ if (descr->width > 0) { /* Do not try to scan as fas as possible but only the given width. * To ensure this, we copy the part that should be scanned. */ size_t sLen = utf8_strlen(&str[pos], strLen - pos); size_t tLen = descr->width > sLen ? sLen : descr->width; tmpObj = Jim_NewStringObjUtf8(interp, str + pos, tLen); tok = tmpObj->bytes; } else { /* As no width was given, simply refer to the original string */ tok = &str[pos]; } switch (descr->type) { case 'd': case 'o': case 'x': case 'u': case 'i':{ char *endp; /* Position where the number finished */ jim_wide w; int base = descr->type == 'o' ? 8 : descr->type == 'x' ? 16 : descr->type == 'i' ? 0 : 10; /* Try to scan a number with the given base */ if (base == 0) { w = jim_strtoull(tok, &endp); } else { w = strtoull(tok, &endp, base); } if (endp != tok) { /* There was some number sucessfully scanned! */ *valObjPtr = Jim_NewIntObj(interp, w); /* Adjust the number-of-chars scanned so far */ scanned += endp - tok; } else { /* Nothing was scanned. We have to determine if this * happened due to e.g. prefix mismatch or input str * exhausted */ scanned = *tok ? 0 : -1; } break; } case 's': case '[':{ *valObjPtr = JimScanAString(interp, descr->arg, tok); scanned += Jim_Length(*valObjPtr); break; } case 'e': case 'f': case 'g':{ char *endp; double value = strtod(tok, &endp); if (endp != tok) { /* There was some number sucessfully scanned! */ *valObjPtr = Jim_NewDoubleObj(interp, value); /* Adjust the number-of-chars scanned so far */ scanned += endp - tok; } else { /* Nothing was scanned. We have to determine if this * happened due to e.g. prefix mismatch or input str * exhausted */ scanned = *tok ? 0 : -1; } break; } } /* If a substring was allocated (due to pre-defined width) do not * forget to free it */ if (tmpObj) { Jim_FreeNewObj(interp, tmpObj); } } return scanned; } /* Jim_ScanString is the workhorse of string scanning. It will scan a given * string and returns all converted (and not ignored) values in a list back * to the caller. If an error occured, a NULL pointer will be returned */ Jim_Obj *Jim_ScanString(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *fmtObjPtr, int flags) { size_t i, pos; int scanned = 1; const char *str = Jim_String(strObjPtr); int strLen = Jim_Utf8Length(interp, strObjPtr); Jim_Obj *resultList = 0; Jim_Obj **resultVec = 0; int resultc; Jim_Obj *emptyStr = 0; ScanFmtStringObj *fmtObj; /* This should never happen. The format object should already be of the correct type */ JimPanic((fmtObjPtr->typePtr != &scanFmtStringObjType, "Jim_ScanString() for non-scan format")); fmtObj = (ScanFmtStringObj *) fmtObjPtr->internalRep.ptr; /* Check if format specification was valid */ if (fmtObj->error != 0) { if (flags & JIM_ERRMSG) Jim_SetResultString(interp, fmtObj->error, -1); return 0; } /* Allocate a new "shared" empty string for all unassigned conversions */ emptyStr = Jim_NewEmptyStringObj(interp); Jim_IncrRefCount(emptyStr); /* Create a list and fill it with empty strings up to max specified XPG3 */ resultList = Jim_NewListObj(interp, NULL, 0); if (fmtObj->maxPos > 0) { for (i = 0; i < fmtObj->maxPos; ++i) Jim_ListAppendElement(interp, resultList, emptyStr); JimListGetElements(interp, resultList, &resultc, &resultVec); } /* Now handle every partial format description */ for (i = 0, pos = 0; i < fmtObj->count; ++i) { ScanFmtPartDescr *descr = &(fmtObj->descr[i]); Jim_Obj *value = 0; /* Only last type may be "literal" w/o conversion - skip it! */ if (descr->type == 0) continue; /* As long as any conversion could be done, we will proceed */ if (scanned > 0) scanned = ScanOneEntry(interp, str, pos, strLen, fmtObj, i, &value); /* In case our first try results in EOF, we will leave */ if (scanned == -1 && i == 0) goto eof; /* Advance next pos-to-be-scanned for the amount scanned already */ pos += scanned; /* value == 0 means no conversion took place so take empty string */ if (value == 0) value = Jim_NewEmptyStringObj(interp); /* If value is a non-assignable one, skip it */ if (descr->pos == -1) { Jim_FreeNewObj(interp, value); } else if (descr->pos == 0) /* Otherwise append it to the result list if no XPG3 was given */ Jim_ListAppendElement(interp, resultList, value); else if (resultVec[descr->pos - 1] == emptyStr) { /* But due to given XPG3, put the value into the corr. slot */ Jim_DecrRefCount(interp, resultVec[descr->pos - 1]); Jim_IncrRefCount(value); resultVec[descr->pos - 1] = value; } else { /* Otherwise, the slot was already used - free obj and ERROR */ Jim_FreeNewObj(interp, value); goto err; } } Jim_DecrRefCount(interp, emptyStr); return resultList; eof: Jim_DecrRefCount(interp, emptyStr); Jim_FreeNewObj(interp, resultList); return (Jim_Obj *)EOF; err: Jim_DecrRefCount(interp, emptyStr); Jim_FreeNewObj(interp, resultList); return 0; } /* ----------------------------------------------------------------------------- * Pseudo Random Number Generation * ---------------------------------------------------------------------------*/ /* Initialize the sbox with the numbers from 0 to 255 */ static void JimPrngInit(Jim_Interp *interp) { #define PRNG_SEED_SIZE 256 int i; unsigned int *seed; time_t t = time(NULL); interp->prngState = Jim_Alloc(sizeof(Jim_PrngState)); seed = Jim_Alloc(PRNG_SEED_SIZE * sizeof(*seed)); for (i = 0; i < PRNG_SEED_SIZE; i++) { seed[i] = (rand() ^ t ^ clock()); } JimPrngSeed(interp, (unsigned char *)seed, PRNG_SEED_SIZE * sizeof(*seed)); Jim_Free(seed); } /* Generates N bytes of random data */ static void JimRandomBytes(Jim_Interp *interp, void *dest, unsigned int len) { Jim_PrngState *prng; unsigned char *destByte = (unsigned char *)dest; unsigned int si, sj, x; /* initialization, only needed the first time */ if (interp->prngState == NULL) JimPrngInit(interp); prng = interp->prngState; /* generates 'len' bytes of pseudo-random numbers */ for (x = 0; x < len; x++) { prng->i = (prng->i + 1) & 0xff; si = prng->sbox[prng->i]; prng->j = (prng->j + si) & 0xff; sj = prng->sbox[prng->j]; prng->sbox[prng->i] = sj; prng->sbox[prng->j] = si; *destByte++ = prng->sbox[(si + sj) & 0xff]; } } /* Re-seed the generator with user-provided bytes */ static void JimPrngSeed(Jim_Interp *interp, unsigned char *seed, int seedLen) { int i; Jim_PrngState *prng; /* initialization, only needed the first time */ if (interp->prngState == NULL) JimPrngInit(interp); prng = interp->prngState; /* Set the sbox[i] with i */ for (i = 0; i < 256; i++) prng->sbox[i] = i; /* Now use the seed to perform a random permutation of the sbox */ for (i = 0; i < seedLen; i++) { unsigned char t; t = prng->sbox[i & 0xFF]; prng->sbox[i & 0xFF] = prng->sbox[seed[i]]; prng->sbox[seed[i]] = t; } prng->i = prng->j = 0; /* discard at least the first 256 bytes of stream. * borrow the seed buffer for this */ for (i = 0; i < 256; i += seedLen) { JimRandomBytes(interp, seed, seedLen); } } /* [incr] */ static int Jim_IncrCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { jim_wide wideValue, increment = 1; Jim_Obj *intObjPtr; if (argc != 2 && argc != 3) { Jim_WrongNumArgs(interp, 1, argv, "varName ?increment?"); return JIM_ERR; } if (argc == 3) { if (Jim_GetWide(interp, argv[2], &increment) != JIM_OK) return JIM_ERR; } intObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED); if (!intObjPtr) { /* Set missing variable to 0 */ wideValue = 0; } else if (Jim_GetWide(interp, intObjPtr, &wideValue) != JIM_OK) { return JIM_ERR; } if (!intObjPtr || Jim_IsShared(intObjPtr)) { intObjPtr = Jim_NewIntObj(interp, wideValue + increment); if (Jim_SetVariable(interp, argv[1], intObjPtr) != JIM_OK) { Jim_FreeNewObj(interp, intObjPtr); return JIM_ERR; } } else { /* Can do it the quick way */ Jim_InvalidateStringRep(intObjPtr); JimWideValue(intObjPtr) = wideValue + increment; /* The following step is required in order to invalidate the * string repr of "FOO" if the var name is on the form of "FOO(IDX)" */ if (argv[1]->typePtr != &variableObjType) { /* Note that this can't fail since GetVariable already succeeded */ Jim_SetVariable(interp, argv[1], intObjPtr); } } Jim_SetResult(interp, intObjPtr); return JIM_OK; } /* ----------------------------------------------------------------------------- * Eval * ---------------------------------------------------------------------------*/ #define JIM_EVAL_SARGV_LEN 8 /* static arguments vector length */ #define JIM_EVAL_SINTV_LEN 8 /* static interpolation vector length */ /* Handle calls to the [unknown] command */ static int JimUnknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int retcode; /* If JimUnknown() is recursively called too many times... * done here */ if (interp->unknown_called > 50) { return JIM_ERR; } /* The object interp->unknown just contains * the "unknown" string, it is used in order to * avoid to lookup the unknown command every time * but instead to cache the result. */ /* If the [unknown] command does not exist ... */ if (Jim_GetCommand(interp, interp->unknown, JIM_NONE) == NULL) return JIM_ERR; interp->unknown_called++; /* XXX: Are we losing fileNameObj and linenr? */ retcode = Jim_EvalObjPrefix(interp, interp->unknown, argc, argv); interp->unknown_called--; return retcode; } static int JimInvokeCommand(Jim_Interp *interp, int objc, Jim_Obj *const *objv) { int retcode; Jim_Cmd *cmdPtr = Jim_GetCommand(interp, objv[0], JIM_ERRMSG); if (cmdPtr == NULL) { return JimUnknown(interp, objc, objv); } if (interp->evalDepth == interp->maxEvalDepth) { Jim_SetResultString(interp, "Infinite eval recursion", -1); return JIM_ERR; } interp->evalDepth++; /* Call it -- Make sure result is an empty object. */ JimIncrCmdRefCount(cmdPtr); Jim_SetEmptyResult(interp); if (cmdPtr->isproc) { retcode = JimCallProcedure(interp, cmdPtr, objc, objv); } else { interp->cmdPrivData = cmdPtr->u.native.privData; retcode = cmdPtr->u.native.cmdProc(interp, objc, objv); } JimDecrCmdRefCount(interp, cmdPtr); interp->evalDepth--; return retcode; } /* Eval the object vector 'objv' composed of 'objc' elements. * Every element is used as single argument. * Jim_EvalObj() will call this function every time its object * argument is of "list" type, with no string representation. * * This is possible because the string representation of a * list object generated by the UpdateStringOfList is made * in a way that ensures that every list element is a different * command argument. */ int Jim_EvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv) { int i, retcode; /* Incr refcount of arguments. */ for (i = 0; i < objc; i++) Jim_IncrRefCount(objv[i]); retcode = JimInvokeCommand(interp, objc, objv); /* Decr refcount of arguments and return the retcode */ for (i = 0; i < objc; i++) Jim_DecrRefCount(interp, objv[i]); return retcode; } /** * Invokes 'prefix' as a command with the objv array as arguments. */ int Jim_EvalObjPrefix(Jim_Interp *interp, Jim_Obj *prefix, int objc, Jim_Obj *const *objv) { int ret; Jim_Obj **nargv = Jim_Alloc((objc + 1) * sizeof(*nargv)); nargv[0] = prefix; memcpy(&nargv[1], &objv[0], sizeof(nargv[0]) * objc); ret = Jim_EvalObjVector(interp, objc + 1, nargv); Jim_Free(nargv); return ret; } static void JimAddErrorToStack(Jim_Interp *interp, int retcode, ScriptObj *script) { int rc = retcode; if (rc == JIM_ERR && !interp->errorFlag) { /* This is the first error, so save the file/line information and reset the stack */ interp->errorFlag = 1; Jim_IncrRefCount(script->fileNameObj); Jim_DecrRefCount(interp, interp->errorFileNameObj); interp->errorFileNameObj = script->fileNameObj; interp->errorLine = script->linenr; JimResetStackTrace(interp); /* Always add a level where the error first occurs */ interp->addStackTrace++; } /* Now if this is an "interesting" level, add it to the stack trace */ if (rc == JIM_ERR && interp->addStackTrace > 0) { /* Add the stack info for the current level */ JimAppendStackTrace(interp, Jim_String(interp->errorProc), script->fileNameObj, script->linenr); /* Note: if we didn't have a filename for this level, * don't clear the addStackTrace flag * so we can pick it up at the next level */ if (Jim_Length(script->fileNameObj)) { interp->addStackTrace = 0; } Jim_DecrRefCount(interp, interp->errorProc); interp->errorProc = interp->emptyObj; Jim_IncrRefCount(interp->errorProc); } else if (rc == JIM_RETURN && interp->returnCode == JIM_ERR) { /* Propagate the addStackTrace value through 'return -code error' */ } else { interp->addStackTrace = 0; } } static int JimSubstOneToken(Jim_Interp *interp, const ScriptToken *token, Jim_Obj **objPtrPtr) { Jim_Obj *objPtr; switch (token->type) { case JIM_TT_STR: case JIM_TT_ESC: objPtr = token->objPtr; break; case JIM_TT_VAR: objPtr = Jim_GetVariable(interp, token->objPtr, JIM_ERRMSG); break; case JIM_TT_DICTSUGAR: objPtr = JimExpandDictSugar(interp, token->objPtr); break; case JIM_TT_EXPRSUGAR: objPtr = JimExpandExprSugar(interp, token->objPtr); break; case JIM_TT_CMD: switch (Jim_EvalObj(interp, token->objPtr)) { case JIM_OK: case JIM_RETURN: objPtr = interp->result; break; case JIM_BREAK: /* Stop substituting */ return JIM_BREAK; case JIM_CONTINUE: /* just skip this one */ return JIM_CONTINUE; default: return JIM_ERR; } break; default: JimPanic((1, "default token type (%d) reached " "in Jim_SubstObj().", token->type)); objPtr = NULL; break; } if (objPtr) { *objPtrPtr = objPtr; return JIM_OK; } return JIM_ERR; } /* Interpolate the given tokens into a unique Jim_Obj returned by reference * via *objPtrPtr. This function is only called by Jim_EvalObj() and Jim_SubstObj() * The returned object has refcount = 0. */ static Jim_Obj *JimInterpolateTokens(Jim_Interp *interp, const ScriptToken * token, int tokens, int flags) { int totlen = 0, i; Jim_Obj **intv; Jim_Obj *sintv[JIM_EVAL_SINTV_LEN]; Jim_Obj *objPtr; char *s; if (tokens <= JIM_EVAL_SINTV_LEN) intv = sintv; else intv = Jim_Alloc(sizeof(Jim_Obj *) * tokens); /* Compute every token forming the argument * in the intv objects vector. */ for (i = 0; i < tokens; i++) { switch (JimSubstOneToken(interp, &token[i], &intv[i])) { case JIM_OK: case JIM_RETURN: break; case JIM_BREAK: if (flags & JIM_SUBST_FLAG) { /* Stop here */ tokens = i; continue; } /* XXX: Should probably set an error about break outside loop */ /* fall through to error */ case JIM_CONTINUE: if (flags & JIM_SUBST_FLAG) { intv[i] = NULL; continue; } /* XXX: Ditto continue outside loop */ /* fall through to error */ default: while (i--) { Jim_DecrRefCount(interp, intv[i]); } if (intv != sintv) { Jim_Free(intv); } return NULL; } Jim_IncrRefCount(intv[i]); Jim_String(intv[i]); totlen += intv[i]->length; } /* Fast path return for a single token */ if (tokens == 1 && intv[0] && intv == sintv) { Jim_DecrRefCount(interp, intv[0]); return intv[0]; } /* Concatenate every token in an unique * object. */ objPtr = Jim_NewStringObjNoAlloc(interp, NULL, 0); if (tokens == 4 && token[0].type == JIM_TT_ESC && token[1].type == JIM_TT_ESC && token[2].type == JIM_TT_VAR) { /* May be able to do fast interpolated object -> dictSubst */ objPtr->typePtr = &interpolatedObjType; objPtr->internalRep.dictSubstValue.varNameObjPtr = token[0].objPtr; objPtr->internalRep.dictSubstValue.indexObjPtr = intv[2]; Jim_IncrRefCount(intv[2]); } s = objPtr->bytes = Jim_Alloc(totlen + 1); objPtr->length = totlen; for (i = 0; i < tokens; i++) { if (intv[i]) { memcpy(s, intv[i]->bytes, intv[i]->length); s += intv[i]->length; Jim_DecrRefCount(interp, intv[i]); } } objPtr->bytes[totlen] = '\0'; /* Free the intv vector if not static. */ if (intv != sintv) { Jim_Free(intv); } return objPtr; } /* listPtr *must* be a list. * The contents of the list is evaluated with the first element as the command and * the remaining elements as the arguments. */ static int JimEvalObjList(Jim_Interp *interp, Jim_Obj *listPtr) { int retcode = JIM_OK; if (listPtr->internalRep.listValue.len) { Jim_IncrRefCount(listPtr); retcode = JimInvokeCommand(interp, listPtr->internalRep.listValue.len, listPtr->internalRep.listValue.ele); Jim_DecrRefCount(interp, listPtr); } return retcode; } int Jim_EvalObjList(Jim_Interp *interp, Jim_Obj *listPtr) { SetListFromAny(interp, listPtr); return JimEvalObjList(interp, listPtr); } int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr) { int i; ScriptObj *script; ScriptToken *token; int retcode = JIM_OK; Jim_Obj *sargv[JIM_EVAL_SARGV_LEN], **argv = NULL; Jim_Obj *prevScriptObj; /* If the object is of type "list", with no string rep we can call * a specialized version of Jim_EvalObj() */ if (Jim_IsList(scriptObjPtr) && scriptObjPtr->bytes == NULL) { return JimEvalObjList(interp, scriptObjPtr); } Jim_IncrRefCount(scriptObjPtr); /* Make sure it's shared. */ script = Jim_GetScript(interp, scriptObjPtr); /* Reset the interpreter result. This is useful to * return the empty result in the case of empty program. */ Jim_SetEmptyResult(interp); token = script->token; #ifdef JIM_OPTIMIZATION /* Check for one of the following common scripts used by for, while * * {} * incr a */ if (script->len == 0) { Jim_DecrRefCount(interp, scriptObjPtr); return JIM_OK; } if (script->len == 3 && token[1].objPtr->typePtr == &commandObjType && token[1].objPtr->internalRep.cmdValue.cmdPtr->isproc == 0 && token[1].objPtr->internalRep.cmdValue.cmdPtr->u.native.cmdProc == Jim_IncrCoreCommand && token[2].objPtr->typePtr == &variableObjType) { Jim_Obj *objPtr = Jim_GetVariable(interp, token[2].objPtr, JIM_NONE); if (objPtr && !Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) { JimWideValue(objPtr)++; Jim_InvalidateStringRep(objPtr); Jim_DecrRefCount(interp, scriptObjPtr); Jim_SetResult(interp, objPtr); return JIM_OK; } } #endif /* Now we have to make sure the internal repr will not be * freed on shimmering. * * Think for example to this: * * set x {llength $x; ... some more code ...}; eval $x * * In order to preserve the internal rep, we increment the * inUse field of the script internal rep structure. */ script->inUse++; /* Stash the current script */ prevScriptObj = interp->currentScriptObj; interp->currentScriptObj = scriptObjPtr; interp->errorFlag = 0; argv = sargv; /* Execute every command sequentially until the end of the script * or an error occurs. */ for (i = 0; i < script->len && retcode == JIM_OK; ) { int argc; int j; /* First token of the line is always JIM_TT_LINE */ argc = token[i].objPtr->internalRep.scriptLineValue.argc; script->linenr = token[i].objPtr->internalRep.scriptLineValue.line; /* Allocate the arguments vector if required */ if (argc > JIM_EVAL_SARGV_LEN) argv = Jim_Alloc(sizeof(Jim_Obj *) * argc); /* Skip the JIM_TT_LINE token */ i++; /* Populate the arguments objects. * If an error occurs, retcode will be set and * 'j' will be set to the number of args expanded */ for (j = 0; j < argc; j++) { long wordtokens = 1; int expand = 0; Jim_Obj *wordObjPtr = NULL; if (token[i].type == JIM_TT_WORD) { wordtokens = JimWideValue(token[i++].objPtr); if (wordtokens < 0) { expand = 1; wordtokens = -wordtokens; } } if (wordtokens == 1) { /* Fast path if the token does not * need interpolation */ switch (token[i].type) { case JIM_TT_ESC: case JIM_TT_STR: wordObjPtr = token[i].objPtr; break; case JIM_TT_VAR: wordObjPtr = Jim_GetVariable(interp, token[i].objPtr, JIM_ERRMSG); break; case JIM_TT_EXPRSUGAR: wordObjPtr = JimExpandExprSugar(interp, token[i].objPtr); break; case JIM_TT_DICTSUGAR: wordObjPtr = JimExpandDictSugar(interp, token[i].objPtr); break; case JIM_TT_CMD: retcode = Jim_EvalObj(interp, token[i].objPtr); if (retcode == JIM_OK) { wordObjPtr = Jim_GetResult(interp); } break; default: JimPanic((1, "default token type reached " "in Jim_EvalObj().")); } } else { /* For interpolation we call a helper * function to do the work for us. */ wordObjPtr = JimInterpolateTokens(interp, token + i, wordtokens, JIM_NONE); } if (!wordObjPtr) { if (retcode == JIM_OK) { retcode = JIM_ERR; } break; } Jim_IncrRefCount(wordObjPtr); i += wordtokens; if (!expand) { argv[j] = wordObjPtr; } else { /* Need to expand wordObjPtr into multiple args from argv[j] ... */ int len = Jim_ListLength(interp, wordObjPtr); int newargc = argc + len - 1; int k; if (len > 1) { if (argv == sargv) { if (newargc > JIM_EVAL_SARGV_LEN) { argv = Jim_Alloc(sizeof(*argv) * newargc); memcpy(argv, sargv, sizeof(*argv) * j); } } else { /* Need to realloc to make room for (len - 1) more entries */ argv = Jim_Realloc(argv, sizeof(*argv) * newargc); } } /* Now copy in the expanded version */ for (k = 0; k < len; k++) { argv[j++] = wordObjPtr->internalRep.listValue.ele[k]; Jim_IncrRefCount(wordObjPtr->internalRep.listValue.ele[k]); } /* The original object reference is no longer needed, * after the expansion it is no longer present on * the argument vector, but the single elements are * in its place. */ Jim_DecrRefCount(interp, wordObjPtr); /* And update the indexes */ j--; argc += len - 1; } } if (retcode == JIM_OK && argc) { /* Invoke the command */ retcode = JimInvokeCommand(interp, argc, argv); if (interp->signal_level && interp->sigmask) { /* Check for a signal after each command */ retcode = JIM_SIGNAL; } } /* Finished with the command, so decrement ref counts of each argument */ while (j-- > 0) { Jim_DecrRefCount(interp, argv[j]); } if (argv != sargv) { Jim_Free(argv); argv = sargv; } } /* Possibly add to the error stack trace */ JimAddErrorToStack(interp, retcode, script); /* Restore the current script */ interp->currentScriptObj = prevScriptObj; /* Note that we don't have to decrement inUse, because the * following code transfers our use of the reference again to * the script object. */ Jim_FreeIntRep(interp, scriptObjPtr); scriptObjPtr->typePtr = &scriptObjType; Jim_SetIntRepPtr(scriptObjPtr, script); Jim_DecrRefCount(interp, scriptObjPtr); return retcode; } static int JimSetProcArg(Jim_Interp *interp, Jim_Obj *argNameObj, Jim_Obj *argValObj) { int retcode; /* If argObjPtr begins with '&', do an automatic upvar */ const char *varname = Jim_String(argNameObj); if (*varname == '&') { /* First check that the target variable exists */ Jim_Obj *objPtr; Jim_CallFrame *savedCallFrame = interp->framePtr; interp->framePtr = interp->framePtr->parent; objPtr = Jim_GetVariable(interp, argValObj, JIM_ERRMSG); interp->framePtr = savedCallFrame; if (!objPtr) { return JIM_ERR; } /* It exists, so perform the binding. */ objPtr = Jim_NewStringObj(interp, varname + 1, -1); Jim_IncrRefCount(objPtr); retcode = Jim_SetVariableLink(interp, objPtr, argValObj, interp->framePtr->parent); Jim_DecrRefCount(interp, objPtr); } else { retcode = Jim_SetVariable(interp, argNameObj, argValObj); } return retcode; } /** * Sets the interp result to be an error message indicating the required proc args. */ static void JimSetProcWrongArgs(Jim_Interp *interp, Jim_Obj *procNameObj, Jim_Cmd *cmd) { /* Create a nice error message, consistent with Tcl 8.5 */ Jim_Obj *argmsg = Jim_NewStringObj(interp, "", 0); int i; for (i = 0; i < cmd->u.proc.argListLen; i++) { Jim_AppendString(interp, argmsg, " ", 1); if (i == cmd->u.proc.argsPos) { if (cmd->u.proc.arglist[i].defaultObjPtr) { /* Renamed args */ Jim_AppendString(interp, argmsg, "?", 1); Jim_AppendObj(interp, argmsg, cmd->u.proc.arglist[i].defaultObjPtr); Jim_AppendString(interp, argmsg, " ...?", -1); } else { /* We have plain args */ Jim_AppendString(interp, argmsg, "?arg...?", -1); } } else { if (cmd->u.proc.arglist[i].defaultObjPtr) { Jim_AppendString(interp, argmsg, "?", 1); Jim_AppendObj(interp, argmsg, cmd->u.proc.arglist[i].nameObjPtr); Jim_AppendString(interp, argmsg, "?", 1); } else { const char *arg = Jim_String(cmd->u.proc.arglist[i].nameObjPtr); if (*arg == '&') { arg++; } Jim_AppendString(interp, argmsg, arg, -1); } } } Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s%#s\"", procNameObj, argmsg); Jim_FreeNewObj(interp, argmsg); } #ifdef jim_ext_namespace /* * [namespace eval] */ int Jim_EvalNamespace(Jim_Interp *interp, Jim_Obj *scriptObj, Jim_Obj *nsObj) { Jim_CallFrame *callFramePtr; int retcode; /* Create a new callframe */ callFramePtr = JimCreateCallFrame(interp, interp->framePtr, nsObj); callFramePtr->argv = &interp->emptyObj; callFramePtr->argc = 0; callFramePtr->procArgsObjPtr = NULL; callFramePtr->procBodyObjPtr = scriptObj; callFramePtr->staticVars = NULL; callFramePtr->fileNameObj = interp->emptyObj; callFramePtr->line = 0; Jim_IncrRefCount(scriptObj); interp->framePtr = callFramePtr; /* Check if there are too nested calls */ if (interp->framePtr->level == interp->maxCallFrameDepth) { Jim_SetResultString(interp, "Too many nested calls. Infinite recursion?", -1); retcode = JIM_ERR; } else { /* Eval the body */ retcode = Jim_EvalObj(interp, scriptObj); } /* Destroy the callframe */ interp->framePtr = interp->framePtr->parent; if (callFramePtr->vars.size != JIM_HT_INITIAL_SIZE) { JimFreeCallFrame(interp, callFramePtr, JIM_FCF_NONE); } else { JimFreeCallFrame(interp, callFramePtr, JIM_FCF_NOHT); } return retcode; } #endif /* Call a procedure implemented in Tcl. * It's possible to speed-up a lot this function, currently * the callframes are not cached, but allocated and * destroied every time. What is expecially costly is * to create/destroy the local vars hash table every time. * * This can be fixed just implementing callframes caching * in JimCreateCallFrame() and JimFreeCallFrame(). */ static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, int argc, Jim_Obj *const *argv) { Jim_CallFrame *callFramePtr; int i, d, retcode, optargs; Jim_Stack *localCommands; ScriptObj *script; /* Check arity */ if (argc - 1 < cmd->u.proc.reqArity || (cmd->u.proc.argsPos < 0 && argc - 1 > cmd->u.proc.reqArity + cmd->u.proc.optArity)) { JimSetProcWrongArgs(interp, argv[0], cmd); return JIM_ERR; } if (Jim_Length(cmd->u.proc.bodyObjPtr) == 0) { /* Optimise for procedure with no body - useful for optional debugging */ return JIM_OK; } /* Check if there are too nested calls */ if (interp->framePtr->level == interp->maxCallFrameDepth) { Jim_SetResultString(interp, "Too many nested calls. Infinite recursion?", -1); return JIM_ERR; } /* Create a new callframe */ callFramePtr = JimCreateCallFrame(interp, interp->framePtr, cmd->u.proc.nsObj); callFramePtr->argv = argv; callFramePtr->argc = argc; callFramePtr->procArgsObjPtr = cmd->u.proc.argListObjPtr; callFramePtr->procBodyObjPtr = cmd->u.proc.bodyObjPtr; callFramePtr->staticVars = cmd->u.proc.staticVars; /* Remember where we were called from. */ script = Jim_GetScript(interp, interp->currentScriptObj); callFramePtr->fileNameObj = script->fileNameObj; callFramePtr->line = script->linenr; Jim_IncrRefCount(cmd->u.proc.argListObjPtr); Jim_IncrRefCount(cmd->u.proc.bodyObjPtr); interp->framePtr = callFramePtr; /* How many optional args are available */ optargs = (argc - 1 - cmd->u.proc.reqArity); /* Step 'i' along the actual args, and step 'd' along the formal args */ i = 1; for (d = 0; d < cmd->u.proc.argListLen; d++) { Jim_Obj *nameObjPtr = cmd->u.proc.arglist[d].nameObjPtr; if (d == cmd->u.proc.argsPos) { /* assign $args */ Jim_Obj *listObjPtr; int argsLen = 0; if (cmd->u.proc.reqArity + cmd->u.proc.optArity < argc - 1) { argsLen = argc - 1 - (cmd->u.proc.reqArity + cmd->u.proc.optArity); } listObjPtr = Jim_NewListObj(interp, &argv[i], argsLen); /* It is possible to rename args. */ if (cmd->u.proc.arglist[d].defaultObjPtr) { nameObjPtr =cmd->u.proc.arglist[d].defaultObjPtr; } retcode = Jim_SetVariable(interp, nameObjPtr, listObjPtr); if (retcode != JIM_OK) { goto badargset; } i += argsLen; continue; } /* Optional or required? */ if (cmd->u.proc.arglist[d].defaultObjPtr == NULL || optargs-- > 0) { retcode = JimSetProcArg(interp, nameObjPtr, argv[i++]); } else { /* Ran out, so use the default */ retcode = Jim_SetVariable(interp, nameObjPtr, cmd->u.proc.arglist[d].defaultObjPtr); } if (retcode != JIM_OK) { goto badargset; } } /* Eval the body */ retcode = Jim_EvalObj(interp, cmd->u.proc.bodyObjPtr); badargset: /* Destroy the callframe */ /* But first remove the local commands */ localCommands = callFramePtr->localCommands; callFramePtr->localCommands = NULL; interp->framePtr = interp->framePtr->parent; if (callFramePtr->vars.size != JIM_HT_INITIAL_SIZE) { JimFreeCallFrame(interp, callFramePtr, JIM_FCF_NONE); } else { JimFreeCallFrame(interp, callFramePtr, JIM_FCF_NOHT); } /* Handle the JIM_EVAL return code */ while (retcode == JIM_EVAL) { Jim_Obj *resultScriptObjPtr = Jim_GetResult(interp); Jim_IncrRefCount(resultScriptObjPtr); /* Result must be a list */ JimPanic((!Jim_IsList(resultScriptObjPtr), "tailcall (JIM_EVAL) returned non-list")); retcode = JimEvalObjList(interp, resultScriptObjPtr); if (retcode == JIM_RETURN) { /* If the result of the tailcall invokes 'return', push * it up to the caller */ interp->returnLevel++; } Jim_DecrRefCount(interp, resultScriptObjPtr); } /* Handle the JIM_RETURN return code */ if (retcode == JIM_RETURN) { if (--interp->returnLevel <= 0) { retcode = interp->returnCode; interp->returnCode = JIM_OK; interp->returnLevel = 0; } } else if (retcode == JIM_ERR) { interp->addStackTrace++; Jim_DecrRefCount(interp, interp->errorProc); interp->errorProc = argv[0]; Jim_IncrRefCount(interp->errorProc); } /* Finally delete local procs */ JimDeleteLocalProcs(interp, localCommands); return retcode; } int Jim_EvalSource(Jim_Interp *interp, const char *filename, int lineno, const char *script) { int retval; Jim_Obj *scriptObjPtr; scriptObjPtr = Jim_NewStringObj(interp, script, -1); Jim_IncrRefCount(scriptObjPtr); if (filename) { Jim_Obj *prevScriptObj; JimSetSourceInfo(interp, scriptObjPtr, Jim_NewStringObj(interp, filename, -1), lineno); prevScriptObj = interp->currentScriptObj; interp->currentScriptObj = scriptObjPtr; retval = Jim_EvalObj(interp, scriptObjPtr); interp->currentScriptObj = prevScriptObj; } else { retval = Jim_EvalObj(interp, scriptObjPtr); } Jim_DecrRefCount(interp, scriptObjPtr); return retval; } int Jim_Eval(Jim_Interp *interp, const char *script) { return Jim_EvalObj(interp, Jim_NewStringObj(interp, script, -1)); } /* Execute script in the scope of the global level */ int Jim_EvalGlobal(Jim_Interp *interp, const char *script) { int retval; Jim_CallFrame *savedFramePtr = interp->framePtr; interp->framePtr = interp->topFramePtr; retval = Jim_Eval(interp, script); interp->framePtr = savedFramePtr; return retval; } int Jim_EvalFileGlobal(Jim_Interp *interp, const char *filename) { int retval; Jim_CallFrame *savedFramePtr = interp->framePtr; interp->framePtr = interp->topFramePtr; retval = Jim_EvalFile(interp, filename); interp->framePtr = savedFramePtr; return retval; } #include int Jim_EvalFile(Jim_Interp *interp, const char *filename) { FILE *fp; char *buf; Jim_Obj *scriptObjPtr; Jim_Obj *prevScriptObj; struct stat sb; int retcode; int readlen; struct JimParseResult result; if (stat(filename, &sb) != 0 || (fp = fopen(filename, "rt")) == NULL) { Jim_SetResultFormatted(interp, "couldn't read file \"%s\": %s", filename, strerror(errno)); return JIM_ERR; } if (sb.st_size == 0) { fclose(fp); return JIM_OK; } buf = Jim_Alloc(sb.st_size + 1); readlen = fread(buf, 1, sb.st_size, fp); if (ferror(fp)) { fclose(fp); Jim_Free(buf); Jim_SetResultFormatted(interp, "failed to load file \"%s\": %s", filename, strerror(errno)); return JIM_ERR; } fclose(fp); buf[readlen] = 0; scriptObjPtr = Jim_NewStringObjNoAlloc(interp, buf, readlen); JimSetSourceInfo(interp, scriptObjPtr, Jim_NewStringObj(interp, filename, -1), 1); Jim_IncrRefCount(scriptObjPtr); /* Now check the script for unmatched braces, etc. */ if (SetScriptFromAny(interp, scriptObjPtr, &result) == JIM_ERR) { const char *msg; char linebuf[20]; switch (result.missing) { case '[': msg = "unmatched \"[\""; break; case '{': msg = "missing close-brace"; break; case '"': default: msg = "missing quote"; break; } snprintf(linebuf, sizeof(linebuf), "%d", result.line); Jim_SetResultFormatted(interp, "%s in \"%s\" at line %s", msg, filename, linebuf); Jim_DecrRefCount(interp, scriptObjPtr); return JIM_ERR; } prevScriptObj = interp->currentScriptObj; interp->currentScriptObj = scriptObjPtr; retcode = Jim_EvalObj(interp, scriptObjPtr); /* Handle the JIM_RETURN return code */ if (retcode == JIM_RETURN) { if (--interp->returnLevel <= 0) { retcode = interp->returnCode; interp->returnCode = JIM_OK; interp->returnLevel = 0; } } if (retcode == JIM_ERR) { /* EvalFile changes context, so add a stack frame here */ interp->addStackTrace++; } interp->currentScriptObj = prevScriptObj; Jim_DecrRefCount(interp, scriptObjPtr); return retcode; } /* ----------------------------------------------------------------------------- * Subst * ---------------------------------------------------------------------------*/ static void JimParseSubst(struct JimParserCtx *pc, int flags) { pc->tstart = pc->p; pc->tline = pc->linenr; if (pc->len == 0) { pc->tend = pc->p; pc->tt = JIM_TT_EOL; pc->eof = 1; return; } if (*pc->p == '[' && !(flags & JIM_SUBST_NOCMD)) { JimParseCmd(pc); return; } if (*pc->p == '$' && !(flags & JIM_SUBST_NOVAR)) { if (JimParseVar(pc) == JIM_OK) { return; } /* Not a var, so treat as a string */ pc->tstart = pc->p; flags |= JIM_SUBST_NOVAR; } while (pc->len) { if (*pc->p == '$' && !(flags & JIM_SUBST_NOVAR)) { break; } if (*pc->p == '[' && !(flags & JIM_SUBST_NOCMD)) { break; } if (*pc->p == '\\' && pc->len > 1) { pc->p++; pc->len--; } pc->p++; pc->len--; } pc->tend = pc->p - 1; pc->tt = (flags & JIM_SUBST_NOESC) ? JIM_TT_STR : JIM_TT_ESC; } /* The subst object type reuses most of the data structures and functions * of the script object. Script's data structures are a bit more complex * for what is needed for [subst]itution tasks, but the reuse helps to * deal with a single data structure at the cost of some more memory * usage for substitutions. */ /* This method takes the string representation of an object * as a Tcl string where to perform [subst]itution, and generates * the pre-parsed internal representation. */ static int SetSubstFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr, int flags) { int scriptTextLen; const char *scriptText = Jim_GetString(objPtr, &scriptTextLen); struct JimParserCtx parser; struct ScriptObj *script = Jim_Alloc(sizeof(*script)); ParseTokenList tokenlist; /* Initially parse the subst into tokens (in tokenlist) */ ScriptTokenListInit(&tokenlist); JimParserInit(&parser, scriptText, scriptTextLen, 1); while (1) { JimParseSubst(&parser, flags); if (parser.eof) { /* Note that subst doesn't need the EOL token */ break; } ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt, parser.tline); } /* Create the "real" subst/script tokens from the initial token list */ script->inUse = 1; script->substFlags = flags; script->fileNameObj = interp->emptyObj; Jim_IncrRefCount(script->fileNameObj); SubstObjAddTokens(interp, script, &tokenlist); /* No longer need the token list */ ScriptTokenListFree(&tokenlist); #ifdef DEBUG_SHOW_SUBST { int i; printf("==== Subst ====\n"); for (i = 0; i < script->len; i++) { printf("[%2d] %s '%s'\n", i, jim_tt_name(script->token[i].type), Jim_String(script->token[i].objPtr)); } } #endif /* Free the old internal rep and set the new one. */ Jim_FreeIntRep(interp, objPtr); Jim_SetIntRepPtr(objPtr, script); objPtr->typePtr = &scriptObjType; return JIM_OK; } static ScriptObj *Jim_GetSubst(Jim_Interp *interp, Jim_Obj *objPtr, int flags) { if (objPtr->typePtr != &scriptObjType || ((ScriptObj *)Jim_GetIntRepPtr(objPtr))->substFlags != flags) SetSubstFromAny(interp, objPtr, flags); return (ScriptObj *) Jim_GetIntRepPtr(objPtr); } /* Performs commands,variables,blackslashes substitution, * storing the result object (with refcount 0) into * resObjPtrPtr. */ int Jim_SubstObj(Jim_Interp *interp, Jim_Obj *substObjPtr, Jim_Obj **resObjPtrPtr, int flags) { ScriptObj *script = Jim_GetSubst(interp, substObjPtr, flags); Jim_IncrRefCount(substObjPtr); /* Make sure it's shared. */ /* In order to preserve the internal rep, we increment the * inUse field of the script internal rep structure. */ script->inUse++; *resObjPtrPtr = JimInterpolateTokens(interp, script->token, script->len, flags); script->inUse--; Jim_DecrRefCount(interp, substObjPtr); if (*resObjPtrPtr == NULL) { return JIM_ERR; } return JIM_OK; } /* ----------------------------------------------------------------------------- * Core commands utility functions * ---------------------------------------------------------------------------*/ void Jim_WrongNumArgs(Jim_Interp *interp, int argc, Jim_Obj *const *argv, const char *msg) { Jim_Obj *objPtr; Jim_Obj *listObjPtr = Jim_NewListObj(interp, argv, argc); if (*msg) { Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, msg, -1)); } Jim_IncrRefCount(listObjPtr); objPtr = Jim_ListJoin(interp, listObjPtr, " ", 1); Jim_DecrRefCount(interp, listObjPtr); Jim_IncrRefCount(objPtr); Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s\"", objPtr); Jim_DecrRefCount(interp, objPtr); } /** * May add the key and/or value to the list. */ typedef void JimHashtableIteratorCallbackType(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_HashEntry *he, int type); #define JimTrivialMatch(pattern) (strpbrk((pattern), "*[?\\") == NULL) /** * For each key of the hash table 'ht' (with string keys) which matches the glob pattern (all if NULL), * invoke the callback to add entries to a list. * Returns the list. */ static Jim_Obj *JimHashtablePatternMatch(Jim_Interp *interp, Jim_HashTable *ht, Jim_Obj *patternObjPtr, JimHashtableIteratorCallbackType *callback, int type) { Jim_HashEntry *he; Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0); /* Check for the non-pattern case. We can do this much more efficiently. */ if (patternObjPtr && JimTrivialMatch(Jim_String(patternObjPtr))) { he = Jim_FindHashEntry(ht, Jim_String(patternObjPtr)); if (he) { callback(interp, listObjPtr, he, type); } } else { Jim_HashTableIterator htiter; JimInitHashTableIterator(ht, &htiter); while ((he = Jim_NextHashEntry(&htiter)) != NULL) { if (patternObjPtr == NULL || JimGlobMatch(Jim_String(patternObjPtr), he->key, 0)) { callback(interp, listObjPtr, he, type); } } } return listObjPtr; } /* Keep these in order */ #define JIM_CMDLIST_COMMANDS 0 #define JIM_CMDLIST_PROCS 1 #define JIM_CMDLIST_CHANNELS 2 /** * Adds matching command names (procs, channels) to the list. */ static void JimCommandMatch(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_HashEntry *he, int type) { Jim_Cmd *cmdPtr = (Jim_Cmd *)he->u.val; Jim_Obj *objPtr; if (type == JIM_CMDLIST_PROCS && !cmdPtr->isproc) { /* not a proc */ return; } objPtr = Jim_NewStringObj(interp, he->key, -1); Jim_IncrRefCount(objPtr); if (type != JIM_CMDLIST_CHANNELS || Jim_AioFilehandle(interp, objPtr)) { Jim_ListAppendElement(interp, listObjPtr, objPtr); } Jim_DecrRefCount(interp, objPtr); } /* type is JIM_CMDLIST_xxx */ static Jim_Obj *JimCommandsList(Jim_Interp *interp, Jim_Obj *patternObjPtr, int type) { return JimHashtablePatternMatch(interp, &interp->commands, patternObjPtr, JimCommandMatch, type); } /* Keep these in order */ #define JIM_VARLIST_GLOBALS 0 #define JIM_VARLIST_LOCALS 1 #define JIM_VARLIST_VARS 2 #define JIM_VARLIST_VALUES 0x1000 /** * Adds matching variable names to the list. */ static void JimVariablesMatch(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_HashEntry *he, int type) { Jim_Var *varPtr = (Jim_Var *)he->u.val; if (type != JIM_VARLIST_LOCALS || varPtr->linkFramePtr == NULL) { Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, he->key, -1)); if (type & JIM_VARLIST_VALUES) { Jim_ListAppendElement(interp, listObjPtr, varPtr->objPtr); } } } /* mode is JIM_VARLIST_xxx */ static Jim_Obj *JimVariablesList(Jim_Interp *interp, Jim_Obj *patternObjPtr, int mode) { if (mode == JIM_VARLIST_LOCALS && interp->framePtr == interp->topFramePtr) { /* For [info locals], if we are at top level an emtpy list * is returned. I don't agree, but we aim at compatibility (SS) */ return interp->emptyObj; } else { Jim_CallFrame *framePtr = (mode == JIM_VARLIST_GLOBALS) ? interp->topFramePtr : interp->framePtr; return JimHashtablePatternMatch(interp, &framePtr->vars, patternObjPtr, JimVariablesMatch, mode); } } static int JimInfoLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr, Jim_Obj **objPtrPtr, int info_level_cmd) { Jim_CallFrame *targetCallFrame; targetCallFrame = JimGetCallFrameByInteger(interp, levelObjPtr); if (targetCallFrame == NULL) { return JIM_ERR; } /* No proc call at toplevel callframe */ if (targetCallFrame == interp->topFramePtr) { Jim_SetResultFormatted(interp, "bad level \"%#s\"", levelObjPtr); return JIM_ERR; } if (info_level_cmd) { *objPtrPtr = Jim_NewListObj(interp, targetCallFrame->argv, targetCallFrame->argc); } else { Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0); Jim_ListAppendElement(interp, listObj, targetCallFrame->argv[0]); Jim_ListAppendElement(interp, listObj, targetCallFrame->fileNameObj); Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, targetCallFrame->line)); *objPtrPtr = listObj; } return JIM_OK; } /* ----------------------------------------------------------------------------- * Core commands * ---------------------------------------------------------------------------*/ /* fake [puts] -- not the real puts, just for debugging. */ static int Jim_PutsCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 2 && argc != 3) { Jim_WrongNumArgs(interp, 1, argv, "?-nonewline? string"); return JIM_ERR; } if (argc == 3) { if (!Jim_CompareStringImmediate(interp, argv[1], "-nonewline")) { Jim_SetResultString(interp, "The second argument must " "be -nonewline", -1); return JIM_ERR; } else { fputs(Jim_String(argv[2]), stdout); } } else { puts(Jim_String(argv[1])); } return JIM_OK; } /* Helper for [+] and [*] */ static int JimAddMulHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int op) { jim_wide wideValue, res; double doubleValue, doubleRes; int i; res = (op == JIM_EXPROP_ADD) ? 0 : 1; for (i = 1; i < argc; i++) { if (Jim_GetWide(interp, argv[i], &wideValue) != JIM_OK) goto trydouble; if (op == JIM_EXPROP_ADD) res += wideValue; else res *= wideValue; } Jim_SetResultInt(interp, res); return JIM_OK; trydouble: doubleRes = (double)res; for (; i < argc; i++) { if (Jim_GetDouble(interp, argv[i], &doubleValue) != JIM_OK) return JIM_ERR; if (op == JIM_EXPROP_ADD) doubleRes += doubleValue; else doubleRes *= doubleValue; } Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes)); return JIM_OK; } /* Helper for [-] and [/] */ static int JimSubDivHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int op) { jim_wide wideValue, res = 0; double doubleValue, doubleRes = 0; int i = 2; if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "number ?number ... number?"); return JIM_ERR; } else if (argc == 2) { /* The arity = 2 case is different. For [- x] returns -x, * while [/ x] returns 1/x. */ if (Jim_GetWide(interp, argv[1], &wideValue) != JIM_OK) { if (Jim_GetDouble(interp, argv[1], &doubleValue) != JIM_OK) { return JIM_ERR; } else { if (op == JIM_EXPROP_SUB) doubleRes = -doubleValue; else doubleRes = 1.0 / doubleValue; Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes)); return JIM_OK; } } if (op == JIM_EXPROP_SUB) { res = -wideValue; Jim_SetResultInt(interp, res); } else { doubleRes = 1.0 / wideValue; Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes)); } return JIM_OK; } else { if (Jim_GetWide(interp, argv[1], &res) != JIM_OK) { if (Jim_GetDouble(interp, argv[1], &doubleRes) != JIM_OK) { return JIM_ERR; } else { goto trydouble; } } } for (i = 2; i < argc; i++) { if (Jim_GetWide(interp, argv[i], &wideValue) != JIM_OK) { doubleRes = (double)res; goto trydouble; } if (op == JIM_EXPROP_SUB) res -= wideValue; else res /= wideValue; } Jim_SetResultInt(interp, res); return JIM_OK; trydouble: for (; i < argc; i++) { if (Jim_GetDouble(interp, argv[i], &doubleValue) != JIM_OK) return JIM_ERR; if (op == JIM_EXPROP_SUB) doubleRes -= doubleValue; else doubleRes /= doubleValue; } Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes)); return JIM_OK; } /* [+] */ static int Jim_AddCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { return JimAddMulHelper(interp, argc, argv, JIM_EXPROP_ADD); } /* [*] */ static int Jim_MulCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { return JimAddMulHelper(interp, argc, argv, JIM_EXPROP_MUL); } /* [-] */ static int Jim_SubCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { return JimSubDivHelper(interp, argc, argv, JIM_EXPROP_SUB); } /* [/] */ static int Jim_DivCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { return JimSubDivHelper(interp, argc, argv, JIM_EXPROP_DIV); } /* [set] */ static int Jim_SetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 2 && argc != 3) { Jim_WrongNumArgs(interp, 1, argv, "varName ?newValue?"); return JIM_ERR; } if (argc == 2) { Jim_Obj *objPtr; objPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG); if (!objPtr) return JIM_ERR; Jim_SetResult(interp, objPtr); return JIM_OK; } /* argc == 3 case. */ if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK) return JIM_ERR; Jim_SetResult(interp, argv[2]); return JIM_OK; } /* [unset] * * unset ?-nocomplain? ?--? ?varName ...? */ static int Jim_UnsetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int i = 1; int complain = 1; while (i < argc) { if (Jim_CompareStringImmediate(interp, argv[i], "--")) { i++; break; } if (Jim_CompareStringImmediate(interp, argv[i], "-nocomplain")) { complain = 0; i++; continue; } break; } while (i < argc) { if (Jim_UnsetVariable(interp, argv[i], complain ? JIM_ERRMSG : JIM_NONE) != JIM_OK && complain) { return JIM_ERR; } i++; } return JIM_OK; } /* [while] */ static int Jim_WhileCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 3) { Jim_WrongNumArgs(interp, 1, argv, "condition body"); return JIM_ERR; } /* The general purpose implementation of while starts here */ while (1) { int boolean, retval; if ((retval = Jim_GetBoolFromExpr(interp, argv[1], &boolean)) != JIM_OK) return retval; if (!boolean) break; if ((retval = Jim_EvalObj(interp, argv[2])) != JIM_OK) { switch (retval) { case JIM_BREAK: goto out; break; case JIM_CONTINUE: continue; break; default: return retval; } } } out: Jim_SetEmptyResult(interp); return JIM_OK; } /* [for] */ static int Jim_ForCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int retval; int boolean = 1; Jim_Obj *varNamePtr = NULL; Jim_Obj *stopVarNamePtr = NULL; if (argc != 5) { Jim_WrongNumArgs(interp, 1, argv, "start test next body"); return JIM_ERR; } /* Do the initialisation */ if ((retval = Jim_EvalObj(interp, argv[1])) != JIM_OK) { return retval; } /* And do the first test now. Better for optimisation * if we can do next/test at the bottom of the loop */ retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean); /* Ready to do the body as follows: * while (1) { * body // check retcode * next // check retcode * test // check retcode/test bool * } */ #ifdef JIM_OPTIMIZATION /* Check if the for is on the form: * for ... {$i < CONST} {incr i} * for ... {$i < $j} {incr i} */ if (retval == JIM_OK && boolean) { ScriptObj *incrScript; ExprByteCode *expr; jim_wide stop, currentVal; Jim_Obj *objPtr; int cmpOffset; /* Do it only if there aren't shared arguments */ expr = JimGetExpression(interp, argv[2]); incrScript = Jim_GetScript(interp, argv[3]); /* Ensure proper lengths to start */ if (incrScript->len != 3 || !expr || expr->len != 3) { goto evalstart; } /* Ensure proper token types. */ if (incrScript->token[1].type != JIM_TT_ESC || expr->token[0].type != JIM_TT_VAR || (expr->token[1].type != JIM_TT_EXPR_INT && expr->token[1].type != JIM_TT_VAR)) { goto evalstart; } if (expr->token[2].type == JIM_EXPROP_LT) { cmpOffset = 0; } else if (expr->token[2].type == JIM_EXPROP_LTE) { cmpOffset = 1; } else { goto evalstart; } /* Update command must be incr */ if (!Jim_CompareStringImmediate(interp, incrScript->token[1].objPtr, "incr")) { goto evalstart; } /* incr, expression must be about the same variable */ if (!Jim_StringEqObj(incrScript->token[2].objPtr, expr->token[0].objPtr)) { goto evalstart; } /* Get the stop condition (must be a variable or integer) */ if (expr->token[1].type == JIM_TT_EXPR_INT) { if (Jim_GetWide(interp, expr->token[1].objPtr, &stop) == JIM_ERR) { goto evalstart; } } else { stopVarNamePtr = expr->token[1].objPtr; Jim_IncrRefCount(stopVarNamePtr); /* Keep the compiler happy */ stop = 0; } /* Initialization */ varNamePtr = expr->token[0].objPtr; Jim_IncrRefCount(varNamePtr); objPtr = Jim_GetVariable(interp, varNamePtr, JIM_NONE); if (objPtr == NULL || Jim_GetWide(interp, objPtr, ¤tVal) != JIM_OK) { goto testcond; } /* --- OPTIMIZED FOR --- */ while (retval == JIM_OK) { /* === Check condition === */ /* Note that currentVal is already set here */ /* Immediate or Variable? get the 'stop' value if the latter. */ if (stopVarNamePtr) { objPtr = Jim_GetVariable(interp, stopVarNamePtr, JIM_NONE); if (objPtr == NULL || Jim_GetWide(interp, objPtr, &stop) != JIM_OK) { goto testcond; } } if (currentVal >= stop + cmpOffset) { break; } /* Eval body */ retval = Jim_EvalObj(interp, argv[4]); if (retval == JIM_OK || retval == JIM_CONTINUE) { retval = JIM_OK; objPtr = Jim_GetVariable(interp, varNamePtr, JIM_ERRMSG); /* Increment */ if (objPtr == NULL) { retval = JIM_ERR; goto out; } if (!Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) { currentVal = ++JimWideValue(objPtr); Jim_InvalidateStringRep(objPtr); } else { if (Jim_GetWide(interp, objPtr, ¤tVal) != JIM_OK || Jim_SetVariable(interp, varNamePtr, Jim_NewIntObj(interp, ++currentVal)) != JIM_OK) { goto evalnext; } } } } goto out; } evalstart: #endif while (boolean && (retval == JIM_OK || retval == JIM_CONTINUE)) { /* Body */ retval = Jim_EvalObj(interp, argv[4]); if (retval == JIM_OK || retval == JIM_CONTINUE) { /* increment */ evalnext: retval = Jim_EvalObj(interp, argv[3]); if (retval == JIM_OK || retval == JIM_CONTINUE) { /* test */ testcond: retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean); } } } out: if (stopVarNamePtr) { Jim_DecrRefCount(interp, stopVarNamePtr); } if (varNamePtr) { Jim_DecrRefCount(interp, varNamePtr); } if (retval == JIM_CONTINUE || retval == JIM_BREAK || retval == JIM_OK) { Jim_SetEmptyResult(interp); return JIM_OK; } return retval; } /* [loop] */ static int Jim_LoopCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int retval; jim_wide i; jim_wide limit; jim_wide incr = 1; Jim_Obj *bodyObjPtr; if (argc != 5 && argc != 6) { Jim_WrongNumArgs(interp, 1, argv, "var first limit ?incr? body"); return JIM_ERR; } if (Jim_GetWide(interp, argv[2], &i) != JIM_OK || Jim_GetWide(interp, argv[3], &limit) != JIM_OK || (argc == 6 && Jim_GetWide(interp, argv[4], &incr) != JIM_OK)) { return JIM_ERR; } bodyObjPtr = (argc == 5) ? argv[4] : argv[5]; retval = Jim_SetVariable(interp, argv[1], argv[2]); while (((i < limit && incr > 0) || (i > limit && incr < 0)) && retval == JIM_OK) { retval = Jim_EvalObj(interp, bodyObjPtr); if (retval == JIM_OK || retval == JIM_CONTINUE) { Jim_Obj *objPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG); retval = JIM_OK; /* Increment */ i += incr; if (objPtr && !Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) { if (argv[1]->typePtr != &variableObjType) { if (Jim_SetVariable(interp, argv[1], objPtr) != JIM_OK) { return JIM_ERR; } } JimWideValue(objPtr) = i; Jim_InvalidateStringRep(objPtr); /* The following step is required in order to invalidate the * string repr of "FOO" if the var name is of the form of "FOO(IDX)" */ if (argv[1]->typePtr != &variableObjType) { if (Jim_SetVariable(interp, argv[1], objPtr) != JIM_OK) { retval = JIM_ERR; break; } } } else { objPtr = Jim_NewIntObj(interp, i); retval = Jim_SetVariable(interp, argv[1], objPtr); if (retval != JIM_OK) { Jim_FreeNewObj(interp, objPtr); } } } } if (retval == JIM_OK || retval == JIM_CONTINUE || retval == JIM_BREAK) { Jim_SetEmptyResult(interp); return JIM_OK; } return retval; } /* List iterators make it easy to iterate over a list. * At some point iterators will be expanded to support generators. */ typedef struct { Jim_Obj *objPtr; int idx; } Jim_ListIter; /** * Initialise the iterator at the start of the list. */ static void JimListIterInit(Jim_ListIter *iter, Jim_Obj *objPtr) { iter->objPtr = objPtr; iter->idx = 0; } /** * Returns the next object from the list, or NULL on end-of-list. */ static Jim_Obj *JimListIterNext(Jim_Interp *interp, Jim_ListIter *iter) { if (iter->idx >= Jim_ListLength(interp, iter->objPtr)) { return NULL; } return iter->objPtr->internalRep.listValue.ele[iter->idx++]; } /** * Returns 1 if end-of-list has been reached. */ static int JimListIterDone(Jim_Interp *interp, Jim_ListIter *iter) { return iter->idx >= Jim_ListLength(interp, iter->objPtr); } /* foreach + lmap implementation. */ static int JimForeachMapHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int doMap) { int result = JIM_ERR; int i, numargs; Jim_ListIter twoiters[2]; /* Avoid allocation for a single list */ Jim_ListIter *iters; Jim_Obj *script; Jim_Obj *resultObj; if (argc < 4 || argc % 2 != 0) { Jim_WrongNumArgs(interp, 1, argv, "varList list ?varList list ...? script"); return JIM_ERR; } script = argv[argc - 1]; /* Last argument is a script */ numargs = (argc - 1 - 1); /* argc - 'foreach' - script */ if (numargs == 2) { iters = twoiters; } else { iters = Jim_Alloc(numargs * sizeof(*iters)); } for (i = 0; i < numargs; i++) { JimListIterInit(&iters[i], argv[i + 1]); if (i % 2 == 0 && JimListIterDone(interp, &iters[i])) { Jim_SetResultString(interp, "foreach varlist is empty", -1); return JIM_ERR; } } if (doMap) { resultObj = Jim_NewListObj(interp, NULL, 0); } else { resultObj = interp->emptyObj; } Jim_IncrRefCount(resultObj); while (1) { /* Have we expired all lists? */ for (i = 0; i < numargs; i += 2) { if (!JimListIterDone(interp, &iters[i + 1])) { break; } } if (i == numargs) { /* All done */ break; } /* For each list */ for (i = 0; i < numargs; i += 2) { Jim_Obj *varName; /* foreach var */ JimListIterInit(&iters[i], argv[i + 1]); while ((varName = JimListIterNext(interp, &iters[i])) != NULL) { Jim_Obj *valObj = JimListIterNext(interp, &iters[i + 1]); if (!valObj) { /* Ran out, so store the empty string */ valObj = interp->emptyObj; } /* Avoid shimmering */ Jim_IncrRefCount(valObj); result = Jim_SetVariable(interp, varName, valObj); Jim_DecrRefCount(interp, valObj); if (result != JIM_OK) { goto err; } } } switch (result = Jim_EvalObj(interp, script)) { case JIM_OK: if (doMap) { Jim_ListAppendElement(interp, resultObj, interp->result); } break; case JIM_CONTINUE: break; case JIM_BREAK: goto out; default: goto err; } } out: result = JIM_OK; Jim_SetResult(interp, resultObj); err: Jim_DecrRefCount(interp, resultObj); if (numargs > 2) { Jim_Free(iters); } return result; } /* [foreach] */ static int Jim_ForeachCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { return JimForeachMapHelper(interp, argc, argv, 0); } /* [lmap] */ static int Jim_LmapCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { return JimForeachMapHelper(interp, argc, argv, 1); } /* [lassign] */ static int Jim_LassignCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int result = JIM_ERR; int i; Jim_ListIter iter; Jim_Obj *resultObj; if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "varList list ?varName ...?"); return JIM_ERR; } JimListIterInit(&iter, argv[1]); for (i = 2; i < argc; i++) { Jim_Obj *valObj = JimListIterNext(interp, &iter); result = Jim_SetVariable(interp, argv[i], valObj ? valObj : interp->emptyObj); if (result != JIM_OK) { return result; } } resultObj = Jim_NewListObj(interp, NULL, 0); while (!JimListIterDone(interp, &iter)) { Jim_ListAppendElement(interp, resultObj, JimListIterNext(interp, &iter)); } Jim_SetResult(interp, resultObj); return JIM_OK; } /* [if] */ static int Jim_IfCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int boolean, retval, current = 1, falsebody = 0; if (argc >= 3) { while (1) { /* Far not enough arguments given! */ if (current >= argc) goto err; if ((retval = Jim_GetBoolFromExpr(interp, argv[current++], &boolean)) != JIM_OK) return retval; /* There lacks something, isn't it? */ if (current >= argc) goto err; if (Jim_CompareStringImmediate(interp, argv[current], "then")) current++; /* Tsk tsk, no then-clause? */ if (current >= argc) goto err; if (boolean) return Jim_EvalObj(interp, argv[current]); /* Ok: no else-clause follows */ if (++current >= argc) { Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); return JIM_OK; } falsebody = current++; if (Jim_CompareStringImmediate(interp, argv[falsebody], "else")) { /* IIICKS - else-clause isn't last cmd? */ if (current != argc - 1) goto err; return Jim_EvalObj(interp, argv[current]); } else if (Jim_CompareStringImmediate(interp, argv[falsebody], "elseif")) /* Ok: elseif follows meaning all the stuff * again (how boring...) */ continue; /* OOPS - else-clause is not last cmd? */ else if (falsebody != argc - 1) goto err; return Jim_EvalObj(interp, argv[falsebody]); } return JIM_OK; } err: Jim_WrongNumArgs(interp, 1, argv, "condition ?then? trueBody ?elseif ...? ?else? falseBody"); return JIM_ERR; } /* Returns 1 if match, 0 if no match or - on error (e.g. -JIM_ERR, -JIM_BREAK)*/ int Jim_CommandMatchObj(Jim_Interp *interp, Jim_Obj *commandObj, Jim_Obj *patternObj, Jim_Obj *stringObj, int nocase) { Jim_Obj *parms[4]; int argc = 0; long eq; int rc; parms[argc++] = commandObj; if (nocase) { parms[argc++] = Jim_NewStringObj(interp, "-nocase", -1); } parms[argc++] = patternObj; parms[argc++] = stringObj; rc = Jim_EvalObjVector(interp, argc, parms); if (rc != JIM_OK || Jim_GetLong(interp, Jim_GetResult(interp), &eq) != JIM_OK) { eq = -rc; } return eq; } enum { SWITCH_EXACT, SWITCH_GLOB, SWITCH_RE, SWITCH_CMD }; /* [switch] */ static int Jim_SwitchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int matchOpt = SWITCH_EXACT, opt = 1, patCount, i; Jim_Obj *command = 0, *const *caseList = 0, *strObj; Jim_Obj *script = 0; if (argc < 3) { wrongnumargs: Jim_WrongNumArgs(interp, 1, argv, "?options? string " "pattern body ... ?default body? or " "{pattern body ?pattern body ...?}"); return JIM_ERR; } for (opt = 1; opt < argc; ++opt) { const char *option = Jim_String(argv[opt]); if (*option != '-') break; else if (strncmp(option, "--", 2) == 0) { ++opt; break; } else if (strncmp(option, "-exact", 2) == 0) matchOpt = SWITCH_EXACT; else if (strncmp(option, "-glob", 2) == 0) matchOpt = SWITCH_GLOB; else if (strncmp(option, "-regexp", 2) == 0) matchOpt = SWITCH_RE; else if (strncmp(option, "-command", 2) == 0) { matchOpt = SWITCH_CMD; if ((argc - opt) < 2) goto wrongnumargs; command = argv[++opt]; } else { Jim_SetResultFormatted(interp, "bad option \"%#s\": must be -exact, -glob, -regexp, -command procname or --", argv[opt]); return JIM_ERR; } if ((argc - opt) < 2) goto wrongnumargs; } strObj = argv[opt++]; patCount = argc - opt; if (patCount == 1) { Jim_Obj **vector; JimListGetElements(interp, argv[opt], &patCount, &vector); caseList = vector; } else caseList = &argv[opt]; if (patCount == 0 || patCount % 2 != 0) goto wrongnumargs; for (i = 0; script == 0 && i < patCount; i += 2) { Jim_Obj *patObj = caseList[i]; if (!Jim_CompareStringImmediate(interp, patObj, "default") || i < (patCount - 2)) { switch (matchOpt) { case SWITCH_EXACT: if (Jim_StringEqObj(strObj, patObj)) script = caseList[i + 1]; break; case SWITCH_GLOB: if (Jim_StringMatchObj(interp, patObj, strObj, 0)) script = caseList[i + 1]; break; case SWITCH_RE: command = Jim_NewStringObj(interp, "regexp", -1); /* Fall thru intentionally */ case SWITCH_CMD:{ int rc = Jim_CommandMatchObj(interp, command, patObj, strObj, 0); /* After the execution of a command we need to * make sure to reconvert the object into a list * again. Only for the single-list style [switch]. */ if (argc - opt == 1) { Jim_Obj **vector; JimListGetElements(interp, argv[opt], &patCount, &vector); caseList = vector; } /* command is here already decref'd */ if (rc < 0) { return -rc; } if (rc) script = caseList[i + 1]; break; } } } else { script = caseList[i + 1]; } } for (; i < patCount && Jim_CompareStringImmediate(interp, script, "-"); i += 2) script = caseList[i + 1]; if (script && Jim_CompareStringImmediate(interp, script, "-")) { Jim_SetResultFormatted(interp, "no body specified for pattern \"%#s\"", caseList[i - 2]); return JIM_ERR; } Jim_SetEmptyResult(interp); if (script) { return Jim_EvalObj(interp, script); } return JIM_OK; } /* [list] */ static int Jim_ListCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *listObjPtr; listObjPtr = Jim_NewListObj(interp, argv + 1, argc - 1); Jim_SetResult(interp, listObjPtr); return JIM_OK; } /* [lindex] */ static int Jim_LindexCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *objPtr, *listObjPtr; int i; int idx; if (argc < 3) { Jim_WrongNumArgs(interp, 1, argv, "list index ?...?"); return JIM_ERR; } objPtr = argv[1]; Jim_IncrRefCount(objPtr); for (i = 2; i < argc; i++) { listObjPtr = objPtr; if (Jim_GetIndex(interp, argv[i], &idx) != JIM_OK) { Jim_DecrRefCount(interp, listObjPtr); return JIM_ERR; } if (Jim_ListIndex(interp, listObjPtr, idx, &objPtr, JIM_NONE) != JIM_OK) { /* Returns an empty object if the index * is out of range. */ Jim_DecrRefCount(interp, listObjPtr); Jim_SetEmptyResult(interp); return JIM_OK; } Jim_IncrRefCount(objPtr); Jim_DecrRefCount(interp, listObjPtr); } Jim_SetResult(interp, objPtr); Jim_DecrRefCount(interp, objPtr); return JIM_OK; } /* [llength] */ static int Jim_LlengthCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 2) { Jim_WrongNumArgs(interp, 1, argv, "list"); return JIM_ERR; } Jim_SetResultInt(interp, Jim_ListLength(interp, argv[1])); return JIM_OK; } /* [lsearch] */ static int Jim_LsearchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { static const char * const options[] = { "-bool", "-not", "-nocase", "-exact", "-glob", "-regexp", "-all", "-inline", "-command", NULL }; enum { OPT_BOOL, OPT_NOT, OPT_NOCASE, OPT_EXACT, OPT_GLOB, OPT_REGEXP, OPT_ALL, OPT_INLINE, OPT_COMMAND }; int i; int opt_bool = 0; int opt_not = 0; int opt_nocase = 0; int opt_all = 0; int opt_inline = 0; int opt_match = OPT_EXACT; int listlen; int rc = JIM_OK; Jim_Obj *listObjPtr = NULL; Jim_Obj *commandObj = NULL; if (argc < 3) { wrongargs: Jim_WrongNumArgs(interp, 1, argv, "?-exact|-glob|-regexp|-command 'command'? ?-bool|-inline? ?-not? ?-nocase? ?-all? list value"); return JIM_ERR; } for (i = 1; i < argc - 2; i++) { int option; if (Jim_GetEnum(interp, argv[i], options, &option, NULL, JIM_ERRMSG) != JIM_OK) { return JIM_ERR; } switch (option) { case OPT_BOOL: opt_bool = 1; opt_inline = 0; break; case OPT_NOT: opt_not = 1; break; case OPT_NOCASE: opt_nocase = 1; break; case OPT_INLINE: opt_inline = 1; opt_bool = 0; break; case OPT_ALL: opt_all = 1; break; case OPT_COMMAND: if (i >= argc - 2) { goto wrongargs; } commandObj = argv[++i]; /* fallthru */ case OPT_EXACT: case OPT_GLOB: case OPT_REGEXP: opt_match = option; break; } } argv += i; if (opt_all) { listObjPtr = Jim_NewListObj(interp, NULL, 0); } if (opt_match == OPT_REGEXP) { commandObj = Jim_NewStringObj(interp, "regexp", -1); } if (commandObj) { Jim_IncrRefCount(commandObj); } listlen = Jim_ListLength(interp, argv[0]); for (i = 0; i < listlen; i++) { Jim_Obj *objPtr; int eq = 0; Jim_ListIndex(interp, argv[0], i, &objPtr, JIM_NONE); switch (opt_match) { case OPT_EXACT: eq = Jim_StringCompareObj(interp, argv[1], objPtr, opt_nocase) == 0; break; case OPT_GLOB: eq = Jim_StringMatchObj(interp, argv[1], objPtr, opt_nocase); break; case OPT_REGEXP: case OPT_COMMAND: eq = Jim_CommandMatchObj(interp, commandObj, argv[1], objPtr, opt_nocase); if (eq < 0) { if (listObjPtr) { Jim_FreeNewObj(interp, listObjPtr); } rc = JIM_ERR; goto done; } break; } /* If we have a non-match with opt_bool, opt_not, !opt_all, can't exit early */ if (!eq && opt_bool && opt_not && !opt_all) { continue; } if ((!opt_bool && eq == !opt_not) || (opt_bool && (eq || opt_all))) { /* Got a match (or non-match for opt_not), or (opt_bool && opt_all) */ Jim_Obj *resultObj; if (opt_bool) { resultObj = Jim_NewIntObj(interp, eq ^ opt_not); } else if (!opt_inline) { resultObj = Jim_NewIntObj(interp, i); } else { resultObj = objPtr; } if (opt_all) { Jim_ListAppendElement(interp, listObjPtr, resultObj); } else { Jim_SetResult(interp, resultObj); goto done; } } } if (opt_all) { Jim_SetResult(interp, listObjPtr); } else { /* No match */ if (opt_bool) { Jim_SetResultBool(interp, opt_not); } else if (!opt_inline) { Jim_SetResultInt(interp, -1); } } done: if (commandObj) { Jim_DecrRefCount(interp, commandObj); } return rc; } /* [lappend] */ static int Jim_LappendCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *listObjPtr; int shared, i; if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "varName ?value value ...?"); return JIM_ERR; } listObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED); if (!listObjPtr) { /* Create the list if it does not exists */ listObjPtr = Jim_NewListObj(interp, NULL, 0); if (Jim_SetVariable(interp, argv[1], listObjPtr) != JIM_OK) { Jim_FreeNewObj(interp, listObjPtr); return JIM_ERR; } } shared = Jim_IsShared(listObjPtr); if (shared) listObjPtr = Jim_DuplicateObj(interp, listObjPtr); for (i = 2; i < argc; i++) Jim_ListAppendElement(interp, listObjPtr, argv[i]); if (Jim_SetVariable(interp, argv[1], listObjPtr) != JIM_OK) { if (shared) Jim_FreeNewObj(interp, listObjPtr); return JIM_ERR; } Jim_SetResult(interp, listObjPtr); return JIM_OK; } /* [linsert] */ static int Jim_LinsertCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int idx, len; Jim_Obj *listPtr; if (argc < 3) { Jim_WrongNumArgs(interp, 1, argv, "list index ?element ...?"); return JIM_ERR; } listPtr = argv[1]; if (Jim_IsShared(listPtr)) listPtr = Jim_DuplicateObj(interp, listPtr); if (Jim_GetIndex(interp, argv[2], &idx) != JIM_OK) goto err; len = Jim_ListLength(interp, listPtr); if (idx >= len) idx = len; else if (idx < 0) idx = len + idx + 1; Jim_ListInsertElements(interp, listPtr, idx, argc - 3, &argv[3]); Jim_SetResult(interp, listPtr); return JIM_OK; err: if (listPtr != argv[1]) { Jim_FreeNewObj(interp, listPtr); } return JIM_ERR; } /* [lreplace] */ static int Jim_LreplaceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int first, last, len, rangeLen; Jim_Obj *listObj; Jim_Obj *newListObj; if (argc < 4) { Jim_WrongNumArgs(interp, 1, argv, "list first last ?element ...?"); return JIM_ERR; } if (Jim_GetIndex(interp, argv[2], &first) != JIM_OK || Jim_GetIndex(interp, argv[3], &last) != JIM_OK) { return JIM_ERR; } listObj = argv[1]; len = Jim_ListLength(interp, listObj); first = JimRelToAbsIndex(len, first); last = JimRelToAbsIndex(len, last); JimRelToAbsRange(len, &first, &last, &rangeLen); /* Now construct a new list which consists of: * */ /* Check to see if trying to replace past the end of the list */ if (first < len) { /* OK. Not past the end */ } else if (len == 0) { /* Special for empty list, adjust first to 0 */ first = 0; } else { Jim_SetResultString(interp, "list doesn't contain element ", -1); Jim_AppendObj(interp, Jim_GetResult(interp), argv[2]); return JIM_ERR; } /* Add the first set of elements */ newListObj = Jim_NewListObj(interp, listObj->internalRep.listValue.ele, first); /* Add supplied elements */ ListInsertElements(newListObj, -1, argc - 4, argv + 4); /* Add the remaining elements */ ListInsertElements(newListObj, -1, len - first - rangeLen, listObj->internalRep.listValue.ele + first + rangeLen); Jim_SetResult(interp, newListObj); return JIM_OK; } /* [lset] */ static int Jim_LsetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc < 3) { Jim_WrongNumArgs(interp, 1, argv, "listVar ?index...? newVal"); return JIM_ERR; } else if (argc == 3) { if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK) return JIM_ERR; Jim_SetResult(interp, argv[2]); return JIM_OK; } if (Jim_SetListIndex(interp, argv[1], argv + 2, argc - 3, argv[argc - 1]) == JIM_ERR) return JIM_ERR; return JIM_OK; } /* [lsort] */ static int Jim_LsortCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const argv[]) { static const char * const options[] = { "-ascii", "-nocase", "-increasing", "-decreasing", "-command", "-integer", "-index", NULL }; enum { OPT_ASCII, OPT_NOCASE, OPT_INCREASING, OPT_DECREASING, OPT_COMMAND, OPT_INTEGER, OPT_INDEX }; Jim_Obj *resObj; int i; int retCode; struct lsort_info info; if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "?options? list"); return JIM_ERR; } info.type = JIM_LSORT_ASCII; info.order = 1; info.indexed = 0; info.command = NULL; info.interp = interp; for (i = 1; i < (argc - 1); i++) { int option; if (Jim_GetEnum(interp, argv[i], options, &option, NULL, JIM_ERRMSG) != JIM_OK) return JIM_ERR; switch (option) { case OPT_ASCII: info.type = JIM_LSORT_ASCII; break; case OPT_NOCASE: info.type = JIM_LSORT_NOCASE; break; case OPT_INTEGER: info.type = JIM_LSORT_INTEGER; break; case OPT_INCREASING: info.order = 1; break; case OPT_DECREASING: info.order = -1; break; case OPT_COMMAND: if (i >= (argc - 2)) { Jim_SetResultString(interp, "\"-command\" option must be followed by comparison command", -1); return JIM_ERR; } info.type = JIM_LSORT_COMMAND; info.command = argv[i + 1]; i++; break; case OPT_INDEX: if (i >= (argc - 2)) { Jim_SetResultString(interp, "\"-index\" option must be followed by list index", -1); return JIM_ERR; } if (Jim_GetIndex(interp, argv[i + 1], &info.index) != JIM_OK) { return JIM_ERR; } info.indexed = 1; i++; break; } } resObj = Jim_DuplicateObj(interp, argv[argc - 1]); retCode = ListSortElements(interp, resObj, &info); if (retCode == JIM_OK) { Jim_SetResult(interp, resObj); } else { Jim_FreeNewObj(interp, resObj); } return retCode; } /* [append] */ static int Jim_AppendCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *stringObjPtr; int i; if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "varName ?value value ...?"); return JIM_ERR; } if (argc == 2) { stringObjPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG); if (!stringObjPtr) return JIM_ERR; } else { int freeobj = 0; stringObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED); if (!stringObjPtr) { /* Create the string if it doesn't exist */ stringObjPtr = Jim_NewEmptyStringObj(interp); freeobj = 1; } else if (Jim_IsShared(stringObjPtr)) { freeobj = 1; stringObjPtr = Jim_DuplicateObj(interp, stringObjPtr); } for (i = 2; i < argc; i++) { Jim_AppendObj(interp, stringObjPtr, argv[i]); } if (Jim_SetVariable(interp, argv[1], stringObjPtr) != JIM_OK) { if (freeobj) { Jim_FreeNewObj(interp, stringObjPtr); } return JIM_ERR; } } Jim_SetResult(interp, stringObjPtr); return JIM_OK; } /* [debug] */ static int Jim_DebugCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { #if defined(JIM_DEBUG_COMMAND) && !defined(JIM_BOOTSTRAP) static const char * const options[] = { "refcount", "objcount", "objects", "invstr", "scriptlen", "exprlen", "exprbc", "show", NULL }; enum { OPT_REFCOUNT, OPT_OBJCOUNT, OPT_OBJECTS, OPT_INVSTR, OPT_SCRIPTLEN, OPT_EXPRLEN, OPT_EXPRBC, OPT_SHOW, }; int option; if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "subcommand ?...?"); return JIM_ERR; } if (Jim_GetEnum(interp, argv[1], options, &option, "subcommand", JIM_ERRMSG) != JIM_OK) return JIM_ERR; if (option == OPT_REFCOUNT) { if (argc != 3) { Jim_WrongNumArgs(interp, 2, argv, "object"); return JIM_ERR; } Jim_SetResultInt(interp, argv[2]->refCount); return JIM_OK; } else if (option == OPT_OBJCOUNT) { int freeobj = 0, liveobj = 0; char buf[256]; Jim_Obj *objPtr; if (argc != 2) { Jim_WrongNumArgs(interp, 2, argv, ""); return JIM_ERR; } /* Count the number of free objects. */ objPtr = interp->freeList; while (objPtr) { freeobj++; objPtr = objPtr->nextObjPtr; } /* Count the number of live objects. */ objPtr = interp->liveList; while (objPtr) { liveobj++; objPtr = objPtr->nextObjPtr; } /* Set the result string and return. */ sprintf(buf, "free %d used %d", freeobj, liveobj); Jim_SetResultString(interp, buf, -1); return JIM_OK; } else if (option == OPT_OBJECTS) { Jim_Obj *objPtr, *listObjPtr, *subListObjPtr; /* Count the number of live objects. */ objPtr = interp->liveList; listObjPtr = Jim_NewListObj(interp, NULL, 0); while (objPtr) { char buf[128]; const char *type = objPtr->typePtr ? objPtr->typePtr->name : ""; subListObjPtr = Jim_NewListObj(interp, NULL, 0); sprintf(buf, "%p", objPtr); Jim_ListAppendElement(interp, subListObjPtr, Jim_NewStringObj(interp, buf, -1)); Jim_ListAppendElement(interp, subListObjPtr, Jim_NewStringObj(interp, type, -1)); Jim_ListAppendElement(interp, subListObjPtr, Jim_NewIntObj(interp, objPtr->refCount)); Jim_ListAppendElement(interp, subListObjPtr, objPtr); Jim_ListAppendElement(interp, listObjPtr, subListObjPtr); objPtr = objPtr->nextObjPtr; } Jim_SetResult(interp, listObjPtr); return JIM_OK; } else if (option == OPT_INVSTR) { Jim_Obj *objPtr; if (argc != 3) { Jim_WrongNumArgs(interp, 2, argv, "object"); return JIM_ERR; } objPtr = argv[2]; if (objPtr->typePtr != NULL) Jim_InvalidateStringRep(objPtr); Jim_SetEmptyResult(interp); return JIM_OK; } else if (option == OPT_SHOW) { const char *s; int len, charlen; if (argc != 3) { Jim_WrongNumArgs(interp, 2, argv, "object"); return JIM_ERR; } s = Jim_GetString(argv[2], &len); #ifdef JIM_UTF8 charlen = utf8_strlen(s, len); #else charlen = len; #endif printf("refcount: %d, type: %s\n", argv[2]->refCount, JimObjTypeName(argv[2])); printf("chars (%d): <<%s>>\n", charlen, s); printf("bytes (%d):", len); while (len--) { printf(" %02x", (unsigned char)*s++); } printf("\n"); return JIM_OK; } else if (option == OPT_SCRIPTLEN) { ScriptObj *script; if (argc != 3) { Jim_WrongNumArgs(interp, 2, argv, "script"); return JIM_ERR; } script = Jim_GetScript(interp, argv[2]); Jim_SetResultInt(interp, script->len); return JIM_OK; } else if (option == OPT_EXPRLEN) { ExprByteCode *expr; if (argc != 3) { Jim_WrongNumArgs(interp, 2, argv, "expression"); return JIM_ERR; } expr = JimGetExpression(interp, argv[2]); if (expr == NULL) return JIM_ERR; Jim_SetResultInt(interp, expr->len); return JIM_OK; } else if (option == OPT_EXPRBC) { Jim_Obj *objPtr; ExprByteCode *expr; int i; if (argc != 3) { Jim_WrongNumArgs(interp, 2, argv, "expression"); return JIM_ERR; } expr = JimGetExpression(interp, argv[2]); if (expr == NULL) return JIM_ERR; objPtr = Jim_NewListObj(interp, NULL, 0); for (i = 0; i < expr->len; i++) { const char *type; const Jim_ExprOperator *op; Jim_Obj *obj = expr->token[i].objPtr; switch (expr->token[i].type) { case JIM_TT_EXPR_INT: type = "int"; break; case JIM_TT_EXPR_DOUBLE: type = "double"; break; case JIM_TT_CMD: type = "command"; break; case JIM_TT_VAR: type = "variable"; break; case JIM_TT_DICTSUGAR: type = "dictsugar"; break; case JIM_TT_EXPRSUGAR: type = "exprsugar"; break; case JIM_TT_ESC: type = "subst"; break; case JIM_TT_STR: type = "string"; break; default: op = JimExprOperatorInfoByOpcode(expr->token[i].type); if (op == NULL) { type = "private"; } else { type = "operator"; } obj = Jim_NewStringObj(interp, op ? op->name : "", -1); break; } Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, type, -1)); Jim_ListAppendElement(interp, objPtr, obj); } Jim_SetResult(interp, objPtr); return JIM_OK; } else { Jim_SetResultString(interp, "bad option. Valid options are refcount, " "objcount, objects, invstr", -1); return JIM_ERR; } /* unreached */ #endif /* JIM_BOOTSTRAP */ #if !defined(JIM_DEBUG_COMMAND) Jim_SetResultString(interp, "unsupported", -1); return JIM_ERR; #endif } /* [eval] */ static int Jim_EvalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int rc; if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "script ?...?"); return JIM_ERR; } if (argc == 2) { rc = Jim_EvalObj(interp, argv[1]); } else { rc = Jim_EvalObj(interp, Jim_ConcatObj(interp, argc - 1, argv + 1)); } if (rc == JIM_ERR) { /* eval is "interesting", so add a stack frame here */ interp->addStackTrace++; } return rc; } /* [uplevel] */ static int Jim_UplevelCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc >= 2) { int retcode; Jim_CallFrame *savedCallFrame, *targetCallFrame; Jim_Obj *objPtr; const char *str; /* Save the old callframe pointer */ savedCallFrame = interp->framePtr; /* Lookup the target frame pointer */ str = Jim_String(argv[1]); if ((str[0] >= '0' && str[0] <= '9') || str[0] == '#') { targetCallFrame =Jim_GetCallFrameByLevel(interp, argv[1]); argc--; argv++; } else { targetCallFrame = Jim_GetCallFrameByLevel(interp, NULL); } if (targetCallFrame == NULL) { return JIM_ERR; } if (argc < 2) { argv--; Jim_WrongNumArgs(interp, 1, argv, "?level? command ?arg ...?"); return JIM_ERR; } /* Eval the code in the target callframe. */ interp->framePtr = targetCallFrame; if (argc == 2) { retcode = Jim_EvalObj(interp, argv[1]); } else { objPtr = Jim_ConcatObj(interp, argc - 1, argv + 1); Jim_IncrRefCount(objPtr); retcode = Jim_EvalObj(interp, objPtr); Jim_DecrRefCount(interp, objPtr); } interp->framePtr = savedCallFrame; return retcode; } else { Jim_WrongNumArgs(interp, 1, argv, "?level? command ?arg ...?"); return JIM_ERR; } } /* [expr] */ static int Jim_ExprCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *exprResultPtr; int retcode; if (argc == 2) { retcode = Jim_EvalExpression(interp, argv[1], &exprResultPtr); } else if (argc > 2) { Jim_Obj *objPtr; objPtr = Jim_ConcatObj(interp, argc - 1, argv + 1); Jim_IncrRefCount(objPtr); retcode = Jim_EvalExpression(interp, objPtr, &exprResultPtr); Jim_DecrRefCount(interp, objPtr); } else { Jim_WrongNumArgs(interp, 1, argv, "expression ?...?"); return JIM_ERR; } if (retcode != JIM_OK) return retcode; Jim_SetResult(interp, exprResultPtr); Jim_DecrRefCount(interp, exprResultPtr); return JIM_OK; } /* [break] */ static int Jim_BreakCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 1) { Jim_WrongNumArgs(interp, 1, argv, ""); return JIM_ERR; } return JIM_BREAK; } /* [continue] */ static int Jim_ContinueCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 1) { Jim_WrongNumArgs(interp, 1, argv, ""); return JIM_ERR; } return JIM_CONTINUE; } /* [return] */ static int Jim_ReturnCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int i; Jim_Obj *stackTraceObj = NULL; Jim_Obj *errorCodeObj = NULL; int returnCode = JIM_OK; long level = 1; for (i = 1; i < argc - 1; i += 2) { if (Jim_CompareStringImmediate(interp, argv[i], "-code")) { if (Jim_GetReturnCode(interp, argv[i + 1], &returnCode) == JIM_ERR) { return JIM_ERR; } } else if (Jim_CompareStringImmediate(interp, argv[i], "-errorinfo")) { stackTraceObj = argv[i + 1]; } else if (Jim_CompareStringImmediate(interp, argv[i], "-errorcode")) { errorCodeObj = argv[i + 1]; } else if (Jim_CompareStringImmediate(interp, argv[i], "-level")) { if (Jim_GetLong(interp, argv[i + 1], &level) != JIM_OK || level < 0) { Jim_SetResultFormatted(interp, "bad level \"%#s\"", argv[i + 1]); return JIM_ERR; } } else { break; } } if (i != argc - 1 && i != argc) { Jim_WrongNumArgs(interp, 1, argv, "?-code code? ?-errorinfo stacktrace? ?-level level? ?result?"); } /* If a stack trace is supplied and code is error, set the stack trace */ if (stackTraceObj && returnCode == JIM_ERR) { JimSetStackTrace(interp, stackTraceObj); } /* If an error code list is supplied, set the global $errorCode */ if (errorCodeObj && returnCode == JIM_ERR) { Jim_SetGlobalVariableStr(interp, "errorCode", errorCodeObj); } interp->returnCode = returnCode; interp->returnLevel = level; if (i == argc - 1) { Jim_SetResult(interp, argv[i]); } return JIM_RETURN; } /* [tailcall] */ static int Jim_TailcallCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_SetResult(interp, Jim_NewListObj(interp, argv + 1, argc - 1)); return JIM_EVAL; } static int JimAliasCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *cmdList; Jim_Obj *prefixListObj = Jim_CmdPrivData(interp); /* prefixListObj is a list to which the args need to be appended */ cmdList = Jim_DuplicateObj(interp, prefixListObj); ListInsertElements(cmdList, -1, argc - 1, argv + 1); return JimEvalObjList(interp, cmdList); } static void JimAliasCmdDelete(Jim_Interp *interp, void *privData) { Jim_Obj *prefixListObj = privData; Jim_DecrRefCount(interp, prefixListObj); } static int Jim_AliasCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *prefixListObj; const char *newname; if (argc < 3) { Jim_WrongNumArgs(interp, 1, argv, "newname command ?args ...?"); return JIM_ERR; } prefixListObj = Jim_NewListObj(interp, argv + 2, argc - 2); Jim_IncrRefCount(prefixListObj); newname = Jim_String(argv[1]); if (newname[0] == ':' && newname[1] == ':') { while (*++newname == ':') { } } Jim_SetResult(interp, argv[1]); return Jim_CreateCommand(interp, newname, JimAliasCmd, prefixListObj, JimAliasCmdDelete); } /* [proc] */ static int Jim_ProcCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Cmd *cmd; if (argc != 4 && argc != 5) { Jim_WrongNumArgs(interp, 1, argv, "name arglist ?statics? body"); return JIM_ERR; } if (JimValidName(interp, "procedure", argv[1]) != JIM_OK) { return JIM_ERR; } if (argc == 4) { cmd = JimCreateProcedureCmd(interp, argv[2], NULL, argv[3], NULL); } else { cmd = JimCreateProcedureCmd(interp, argv[2], argv[3], argv[4], NULL); } if (cmd) { /* Add the new command */ Jim_Obj *qualifiedCmdNameObj; const char *cmdname = JimQualifyName(interp, Jim_String(argv[1]), &qualifiedCmdNameObj); JimCreateCommand(interp, cmdname, cmd); /* Calculate and set the namespace for this proc */ JimUpdateProcNamespace(interp, cmd, cmdname); JimFreeQualifiedName(interp, qualifiedCmdNameObj); /* Unlike Tcl, set the name of the proc as the result */ Jim_SetResult(interp, argv[1]); return JIM_OK; } return JIM_ERR; } /* [local] */ static int Jim_LocalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int retcode; /* Evaluate the arguments with 'local' in force */ interp->local++; retcode = Jim_EvalObjVector(interp, argc - 1, argv + 1); interp->local--; /* If OK, and the result is a proc, add it to the list of local procs */ if (retcode == 0) { Jim_Obj *cmdNameObj = Jim_GetResult(interp); if (Jim_GetCommand(interp, cmdNameObj, JIM_ERRMSG) == NULL) { return JIM_ERR; } if (interp->framePtr->localCommands == NULL) { interp->framePtr->localCommands = Jim_Alloc(sizeof(*interp->framePtr->localCommands)); Jim_InitStack(interp->framePtr->localCommands); } Jim_IncrRefCount(cmdNameObj); Jim_StackPush(interp->framePtr->localCommands, cmdNameObj); } return retcode; } /* [upcall] */ static int Jim_UpcallCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "cmd ?args ...?"); return JIM_ERR; } else { int retcode; Jim_Cmd *cmdPtr = Jim_GetCommand(interp, argv[1], JIM_ERRMSG); if (cmdPtr == NULL || !cmdPtr->isproc || !cmdPtr->prevCmd) { Jim_SetResultFormatted(interp, "no previous command: \"%#s\"", argv[1]); return JIM_ERR; } /* OK. Mark this command as being in an upcall */ cmdPtr->u.proc.upcall++; JimIncrCmdRefCount(cmdPtr); /* Invoke the command as normal */ retcode = Jim_EvalObjVector(interp, argc - 1, argv + 1); /* No longer in an upcall */ cmdPtr->u.proc.upcall--; JimDecrCmdRefCount(interp, cmdPtr); return retcode; } } /* [apply] */ static int Jim_ApplyCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "lambdaExpr ?arg ...?"); return JIM_ERR; } else { int ret; Jim_Cmd *cmd; Jim_Obj *argListObjPtr; Jim_Obj *bodyObjPtr; Jim_Obj *nsObj = NULL; Jim_Obj **nargv; int len = Jim_ListLength(interp, argv[1]); if (len != 2 && len != 3) { Jim_SetResultFormatted(interp, "can't interpret \"%#s\" as a lambda expression", argv[1]); return JIM_ERR; } if (len == 3) { #ifdef jim_ext_namespace /* Need to canonicalise the given namespace. */ nsObj = JimQualifyNameObj(interp, Jim_ListGetIndex(interp, argv[1], 2)); #else Jim_SetResultString(interp, "namespaces not enabled", -1); return JIM_ERR; #endif } argListObjPtr = Jim_ListGetIndex(interp, argv[1], 0); bodyObjPtr = Jim_ListGetIndex(interp, argv[1], 1); cmd = JimCreateProcedureCmd(interp, argListObjPtr, NULL, bodyObjPtr, nsObj); if (cmd) { /* Create a new argv array with a dummy argv[0], for error messages */ nargv = Jim_Alloc((argc - 2 + 1) * sizeof(*nargv)); nargv[0] = Jim_NewStringObj(interp, "apply lambdaExpr", -1); Jim_IncrRefCount(nargv[0]); memcpy(&nargv[1], argv + 2, (argc - 2) * sizeof(*nargv)); ret = JimCallProcedure(interp, cmd, argc - 2 + 1, nargv); Jim_DecrRefCount(interp, nargv[0]); Jim_Free(nargv); JimDecrCmdRefCount(interp, cmd); return ret; } return JIM_ERR; } } /* [concat] */ static int Jim_ConcatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_SetResult(interp, Jim_ConcatObj(interp, argc - 1, argv + 1)); return JIM_OK; } /* [upvar] */ static int Jim_UpvarCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int i; Jim_CallFrame *targetCallFrame; /* Lookup the target frame pointer */ if (argc > 3 && (argc % 2 == 0)) { targetCallFrame = Jim_GetCallFrameByLevel(interp, argv[1]); argc--; argv++; } else { targetCallFrame = Jim_GetCallFrameByLevel(interp, NULL); } if (targetCallFrame == NULL) { return JIM_ERR; } /* Check for arity */ if (argc < 3) { Jim_WrongNumArgs(interp, 1, argv, "?level? otherVar localVar ?otherVar localVar ...?"); return JIM_ERR; } /* Now... for every other/local couple: */ for (i = 1; i < argc; i += 2) { if (Jim_SetVariableLink(interp, argv[i + 1], argv[i], targetCallFrame) != JIM_OK) return JIM_ERR; } return JIM_OK; } /* [global] */ static int Jim_GlobalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int i; if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "varName ?varName ...?"); return JIM_ERR; } /* Link every var to the toplevel having the same name */ if (interp->framePtr->level == 0) return JIM_OK; /* global at toplevel... */ for (i = 1; i < argc; i++) { /* global ::blah does nothing */ const char *name = Jim_String(argv[i]); if (name[0] != ':' || name[1] != ':') { if (Jim_SetVariableLink(interp, argv[i], argv[i], interp->topFramePtr) != JIM_OK) return JIM_ERR; } } return JIM_OK; } /* does the [string map] operation. On error NULL is returned, * otherwise a new string object with the result, having refcount = 0, * is returned. */ static Jim_Obj *JimStringMap(Jim_Interp *interp, Jim_Obj *mapListObjPtr, Jim_Obj *objPtr, int nocase) { int numMaps; const char *str, *noMatchStart = NULL; int strLen, i; Jim_Obj *resultObjPtr; numMaps = Jim_ListLength(interp, mapListObjPtr); if (numMaps % 2) { Jim_SetResultString(interp, "list must contain an even number of elements", -1); return NULL; } str = Jim_String(objPtr); strLen = Jim_Utf8Length(interp, objPtr); /* Map it */ resultObjPtr = Jim_NewStringObj(interp, "", 0); while (strLen) { for (i = 0; i < numMaps; i += 2) { Jim_Obj *objPtr; const char *k; int kl; Jim_ListIndex(interp, mapListObjPtr, i, &objPtr, JIM_NONE); k = Jim_String(objPtr); kl = Jim_Utf8Length(interp, objPtr); if (strLen >= kl && kl) { int rc; rc = JimStringCompareLen(str, k, kl, nocase); if (rc == 0) { if (noMatchStart) { Jim_AppendString(interp, resultObjPtr, noMatchStart, str - noMatchStart); noMatchStart = NULL; } Jim_ListIndex(interp, mapListObjPtr, i + 1, &objPtr, JIM_NONE); Jim_AppendObj(interp, resultObjPtr, objPtr); str += utf8_index(str, kl); strLen -= kl; break; } } } if (i == numMaps) { /* no match */ int c; if (noMatchStart == NULL) noMatchStart = str; str += utf8_tounicode(str, &c); strLen--; } } if (noMatchStart) { Jim_AppendString(interp, resultObjPtr, noMatchStart, str - noMatchStart); } return resultObjPtr; } /* [string] */ static int Jim_StringCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int len; int opt_case = 1; int option; static const char * const options[] = { "bytelength", "length", "compare", "match", "equal", "is", "byterange", "range", "replace", "map", "repeat", "reverse", "index", "first", "last", "trim", "trimleft", "trimright", "tolower", "toupper", "totitle", NULL }; enum { OPT_BYTELENGTH, OPT_LENGTH, OPT_COMPARE, OPT_MATCH, OPT_EQUAL, OPT_IS, OPT_BYTERANGE, OPT_RANGE, OPT_REPLACE, OPT_MAP, OPT_REPEAT, OPT_REVERSE, OPT_INDEX, OPT_FIRST, OPT_LAST, OPT_TRIM, OPT_TRIMLEFT, OPT_TRIMRIGHT, OPT_TOLOWER, OPT_TOUPPER, OPT_TOTITLE }; static const char * const nocase_options[] = { "-nocase", NULL }; static const char * const nocase_length_options[] = { "-nocase", "-length", NULL }; if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "option ?arguments ...?"); return JIM_ERR; } if (Jim_GetEnum(interp, argv[1], options, &option, NULL, JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) return JIM_ERR; switch (option) { case OPT_LENGTH: case OPT_BYTELENGTH: if (argc != 3) { Jim_WrongNumArgs(interp, 2, argv, "string"); return JIM_ERR; } if (option == OPT_LENGTH) { len = Jim_Utf8Length(interp, argv[2]); } else { len = Jim_Length(argv[2]); } Jim_SetResultInt(interp, len); return JIM_OK; case OPT_COMPARE: case OPT_EQUAL: { /* n is the number of remaining option args */ long opt_length = -1; int n = argc - 4; int i = 2; while (n > 0) { int subopt; if (Jim_GetEnum(interp, argv[i++], nocase_length_options, &subopt, NULL, JIM_ENUM_ABBREV) != JIM_OK) { badcompareargs: Jim_WrongNumArgs(interp, 2, argv, "?-nocase? ?-length int? string1 string2"); return JIM_ERR; } if (subopt == 0) { /* -nocase */ opt_case = 0; n--; } else { /* -length */ if (n < 2) { goto badcompareargs; } if (Jim_GetLong(interp, argv[i++], &opt_length) != JIM_OK) { return JIM_ERR; } n -= 2; } } if (n) { goto badcompareargs; } argv += argc - 2; if (opt_length < 0 && option != OPT_COMPARE && opt_case) { /* Fast version - [string equal], case sensitive, no length */ Jim_SetResultBool(interp, Jim_StringEqObj(argv[0], argv[1])); } else { if (opt_length >= 0) { n = JimStringCompareLen(Jim_String(argv[0]), Jim_String(argv[1]), opt_length, !opt_case); } else { n = Jim_StringCompareObj(interp, argv[0], argv[1], !opt_case); } Jim_SetResultInt(interp, option == OPT_COMPARE ? n : n == 0); } return JIM_OK; } case OPT_MATCH: if (argc != 4 && (argc != 5 || Jim_GetEnum(interp, argv[2], nocase_options, &opt_case, NULL, JIM_ENUM_ABBREV) != JIM_OK)) { Jim_WrongNumArgs(interp, 2, argv, "?-nocase? pattern string"); return JIM_ERR; } if (opt_case == 0) { argv++; } Jim_SetResultBool(interp, Jim_StringMatchObj(interp, argv[2], argv[3], !opt_case)); return JIM_OK; case OPT_MAP:{ Jim_Obj *objPtr; if (argc != 4 && (argc != 5 || Jim_GetEnum(interp, argv[2], nocase_options, &opt_case, NULL, JIM_ENUM_ABBREV) != JIM_OK)) { Jim_WrongNumArgs(interp, 2, argv, "?-nocase? mapList string"); return JIM_ERR; } if (opt_case == 0) { argv++; } objPtr = JimStringMap(interp, argv[2], argv[3], !opt_case); if (objPtr == NULL) { return JIM_ERR; } Jim_SetResult(interp, objPtr); return JIM_OK; } case OPT_RANGE: case OPT_BYTERANGE:{ Jim_Obj *objPtr; if (argc != 5) { Jim_WrongNumArgs(interp, 2, argv, "string first last"); return JIM_ERR; } if (option == OPT_RANGE) { objPtr = Jim_StringRangeObj(interp, argv[2], argv[3], argv[4]); } else { objPtr = Jim_StringByteRangeObj(interp, argv[2], argv[3], argv[4]); } if (objPtr == NULL) { return JIM_ERR; } Jim_SetResult(interp, objPtr); return JIM_OK; } case OPT_REPLACE:{ Jim_Obj *objPtr; if (argc != 5 && argc != 6) { Jim_WrongNumArgs(interp, 2, argv, "string first last ?string?"); return JIM_ERR; } objPtr = JimStringReplaceObj(interp, argv[2], argv[3], argv[4], argc == 6 ? argv[5] : NULL); if (objPtr == NULL) { return JIM_ERR; } Jim_SetResult(interp, objPtr); return JIM_OK; } case OPT_REPEAT:{ Jim_Obj *objPtr; jim_wide count; if (argc != 4) { Jim_WrongNumArgs(interp, 2, argv, "string count"); return JIM_ERR; } if (Jim_GetWide(interp, argv[3], &count) != JIM_OK) { return JIM_ERR; } objPtr = Jim_NewStringObj(interp, "", 0); if (count > 0) { while (count--) { Jim_AppendObj(interp, objPtr, argv[2]); } } Jim_SetResult(interp, objPtr); return JIM_OK; } case OPT_REVERSE:{ char *buf, *p; const char *str; int len; int i; if (argc != 3) { Jim_WrongNumArgs(interp, 2, argv, "string"); return JIM_ERR; } str = Jim_GetString(argv[2], &len); buf = Jim_Alloc(len + 1); p = buf + len; *p = 0; for (i = 0; i < len; ) { int c; int l = utf8_tounicode(str, &c); memcpy(p - l, str, l); p -= l; i += l; str += l; } Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, buf, len)); return JIM_OK; } case OPT_INDEX:{ int idx; const char *str; if (argc != 4) { Jim_WrongNumArgs(interp, 2, argv, "string index"); return JIM_ERR; } if (Jim_GetIndex(interp, argv[3], &idx) != JIM_OK) { return JIM_ERR; } str = Jim_String(argv[2]); len = Jim_Utf8Length(interp, argv[2]); if (idx != INT_MIN && idx != INT_MAX) { idx = JimRelToAbsIndex(len, idx); } if (idx < 0 || idx >= len || str == NULL) { Jim_SetResultString(interp, "", 0); } else if (len == Jim_Length(argv[2])) { /* ASCII optimisation */ Jim_SetResultString(interp, str + idx, 1); } else { int c; int i = utf8_index(str, idx); Jim_SetResultString(interp, str + i, utf8_tounicode(str + i, &c)); } return JIM_OK; } case OPT_FIRST: case OPT_LAST:{ int idx = 0, l1, l2; const char *s1, *s2; if (argc != 4 && argc != 5) { Jim_WrongNumArgs(interp, 2, argv, "subString string ?index?"); return JIM_ERR; } s1 = Jim_String(argv[2]); s2 = Jim_String(argv[3]); l1 = Jim_Utf8Length(interp, argv[2]); l2 = Jim_Utf8Length(interp, argv[3]); if (argc == 5) { if (Jim_GetIndex(interp, argv[4], &idx) != JIM_OK) { return JIM_ERR; } idx = JimRelToAbsIndex(l2, idx); } else if (option == OPT_LAST) { idx = l2; } if (option == OPT_FIRST) { Jim_SetResultInt(interp, JimStringFirst(s1, l1, s2, l2, idx)); } else { #ifdef JIM_UTF8 Jim_SetResultInt(interp, JimStringLastUtf8(s1, l1, s2, idx)); #else Jim_SetResultInt(interp, JimStringLast(s1, l1, s2, idx)); #endif } return JIM_OK; } case OPT_TRIM: case OPT_TRIMLEFT: case OPT_TRIMRIGHT:{ Jim_Obj *trimchars; if (argc != 3 && argc != 4) { Jim_WrongNumArgs(interp, 2, argv, "string ?trimchars?"); return JIM_ERR; } trimchars = (argc == 4 ? argv[3] : NULL); if (option == OPT_TRIM) { Jim_SetResult(interp, JimStringTrim(interp, argv[2], trimchars)); } else if (option == OPT_TRIMLEFT) { Jim_SetResult(interp, JimStringTrimLeft(interp, argv[2], trimchars)); } else if (option == OPT_TRIMRIGHT) { Jim_SetResult(interp, JimStringTrimRight(interp, argv[2], trimchars)); } return JIM_OK; } case OPT_TOLOWER: case OPT_TOUPPER: case OPT_TOTITLE: if (argc != 3) { Jim_WrongNumArgs(interp, 2, argv, "string"); return JIM_ERR; } if (option == OPT_TOLOWER) { Jim_SetResult(interp, JimStringToLower(interp, argv[2])); } else if (option == OPT_TOUPPER) { Jim_SetResult(interp, JimStringToUpper(interp, argv[2])); } else { Jim_SetResult(interp, JimStringToTitle(interp, argv[2])); } return JIM_OK; case OPT_IS: if (argc == 4 || (argc == 5 && Jim_CompareStringImmediate(interp, argv[3], "-strict"))) { return JimStringIs(interp, argv[argc - 1], argv[2], argc == 5); } Jim_WrongNumArgs(interp, 2, argv, "class ?-strict? str"); return JIM_ERR; } return JIM_OK; } /* [time] */ static int Jim_TimeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { long i, count = 1; jim_wide start, elapsed; char buf[60]; const char *fmt = "%" JIM_WIDE_MODIFIER " microseconds per iteration"; if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "script ?count?"); return JIM_ERR; } if (argc == 3) { if (Jim_GetLong(interp, argv[2], &count) != JIM_OK) return JIM_ERR; } if (count < 0) return JIM_OK; i = count; start = JimClock(); while (i-- > 0) { int retval; retval = Jim_EvalObj(interp, argv[1]); if (retval != JIM_OK) { return retval; } } elapsed = JimClock() - start; sprintf(buf, fmt, count == 0 ? 0 : elapsed / count); Jim_SetResultString(interp, buf, -1); return JIM_OK; } /* [exit] */ static int Jim_ExitCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { long exitCode = 0; if (argc > 2) { Jim_WrongNumArgs(interp, 1, argv, "?exitCode?"); return JIM_ERR; } if (argc == 2) { if (Jim_GetLong(interp, argv[1], &exitCode) != JIM_OK) return JIM_ERR; } interp->exitCode = exitCode; return JIM_EXIT; } /* [catch] */ static int Jim_CatchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int exitCode = 0; int i; int sig = 0; /* Which return codes are ignored (passed through)? By default, only exit, eval and signal */ jim_wide ignore_mask = (1 << JIM_EXIT) | (1 << JIM_EVAL) | (1 << JIM_SIGNAL); static const int max_ignore_code = sizeof(ignore_mask) * 8; /* Reset the error code before catch. * Note that this is not strictly correct. */ Jim_SetGlobalVariableStr(interp, "errorCode", Jim_NewStringObj(interp, "NONE", -1)); for (i = 1; i < argc - 1; i++) { const char *arg = Jim_String(argv[i]); jim_wide option; int ignore; /* It's a pity we can't use Jim_GetEnum here :-( */ if (strcmp(arg, "--") == 0) { i++; break; } if (*arg != '-') { break; } if (strncmp(arg, "-no", 3) == 0) { arg += 3; ignore = 1; } else { arg++; ignore = 0; } if (Jim_StringToWide(arg, &option, 10) != JIM_OK) { option = -1; } if (option < 0) { option = Jim_FindByName(arg, jimReturnCodes, jimReturnCodesSize); } if (option < 0) { goto wrongargs; } if (ignore) { ignore_mask |= (1 << option); } else { ignore_mask &= ~(1 << option); } } argc -= i; if (argc < 1 || argc > 3) { wrongargs: Jim_WrongNumArgs(interp, 1, argv, "?-?no?code ... --? script ?resultVarName? ?optionVarName?"); return JIM_ERR; } argv += i; if ((ignore_mask & (1 << JIM_SIGNAL)) == 0) { sig++; } interp->signal_level += sig; if (interp->signal_level && interp->sigmask) { /* If a signal is set, don't even try to execute the body */ exitCode = JIM_SIGNAL; } else { exitCode = Jim_EvalObj(interp, argv[0]); } interp->signal_level -= sig; /* Catch or pass through? Only the first 32/64 codes can be passed through */ if (exitCode >= 0 && exitCode < max_ignore_code && ((1 << exitCode) & ignore_mask)) { /* Not caught, pass it up */ return exitCode; } if (sig && exitCode == JIM_SIGNAL) { /* Catch the signal at this level */ if (interp->signal_set_result) { interp->signal_set_result(interp, interp->sigmask); } else { Jim_SetResultInt(interp, interp->sigmask); } interp->sigmask = 0; } if (argc >= 2) { if (Jim_SetVariable(interp, argv[1], Jim_GetResult(interp)) != JIM_OK) { return JIM_ERR; } if (argc == 3) { Jim_Obj *optListObj = Jim_NewListObj(interp, NULL, 0); Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-code", -1)); Jim_ListAppendElement(interp, optListObj, Jim_NewIntObj(interp, exitCode == JIM_RETURN ? interp->returnCode : exitCode)); Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-level", -1)); Jim_ListAppendElement(interp, optListObj, Jim_NewIntObj(interp, interp->returnLevel)); if (exitCode == JIM_ERR) { Jim_Obj *errorCode; Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-errorinfo", -1)); Jim_ListAppendElement(interp, optListObj, interp->stackTrace); errorCode = Jim_GetGlobalVariableStr(interp, "errorCode", JIM_NONE); if (errorCode) { Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-errorcode", -1)); Jim_ListAppendElement(interp, optListObj, errorCode); } } if (Jim_SetVariable(interp, argv[2], optListObj) != JIM_OK) { return JIM_ERR; } } } Jim_SetResultInt(interp, exitCode); return JIM_OK; } #ifdef JIM_REFERENCES /* [ref] */ static int Jim_RefCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 3 && argc != 4) { Jim_WrongNumArgs(interp, 1, argv, "string tag ?finalizer?"); return JIM_ERR; } if (argc == 3) { Jim_SetResult(interp, Jim_NewReference(interp, argv[1], argv[2], NULL)); } else { Jim_SetResult(interp, Jim_NewReference(interp, argv[1], argv[2], argv[3])); } return JIM_OK; } /* [getref] */ static int Jim_GetrefCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Reference *refPtr; if (argc != 2) { Jim_WrongNumArgs(interp, 1, argv, "reference"); return JIM_ERR; } if ((refPtr = Jim_GetReference(interp, argv[1])) == NULL) return JIM_ERR; Jim_SetResult(interp, refPtr->objPtr); return JIM_OK; } /* [setref] */ static int Jim_SetrefCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Reference *refPtr; if (argc != 3) { Jim_WrongNumArgs(interp, 1, argv, "reference newValue"); return JIM_ERR; } if ((refPtr = Jim_GetReference(interp, argv[1])) == NULL) return JIM_ERR; Jim_IncrRefCount(argv[2]); Jim_DecrRefCount(interp, refPtr->objPtr); refPtr->objPtr = argv[2]; Jim_SetResult(interp, argv[2]); return JIM_OK; } /* [collect] */ static int Jim_CollectCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 1) { Jim_WrongNumArgs(interp, 1, argv, ""); return JIM_ERR; } Jim_SetResultInt(interp, Jim_Collect(interp)); /* Free all the freed objects. */ while (interp->freeList) { Jim_Obj *nextObjPtr = interp->freeList->nextObjPtr; Jim_Free(interp->freeList); interp->freeList = nextObjPtr; } return JIM_OK; } /* [finalize] reference ?newValue? */ static int Jim_FinalizeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 2 && argc != 3) { Jim_WrongNumArgs(interp, 1, argv, "reference ?finalizerProc?"); return JIM_ERR; } if (argc == 2) { Jim_Obj *cmdNamePtr; if (Jim_GetFinalizer(interp, argv[1], &cmdNamePtr) != JIM_OK) return JIM_ERR; if (cmdNamePtr != NULL) /* otherwise the null string is returned. */ Jim_SetResult(interp, cmdNamePtr); } else { if (Jim_SetFinalizer(interp, argv[1], argv[2]) != JIM_OK) return JIM_ERR; Jim_SetResult(interp, argv[2]); } return JIM_OK; } /* [info references] */ static int JimInfoReferences(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *listObjPtr; Jim_HashTableIterator htiter; Jim_HashEntry *he; listObjPtr = Jim_NewListObj(interp, NULL, 0); JimInitHashTableIterator(&interp->references, &htiter); while ((he = Jim_NextHashEntry(&htiter)) != NULL) { char buf[JIM_REFERENCE_SPACE + 1]; Jim_Reference *refPtr = he->u.val; const unsigned long *refId = he->key; JimFormatReference(buf, refPtr, *refId); Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, buf, -1)); } Jim_SetResult(interp, listObjPtr); return JIM_OK; } #endif /* [rename] */ static int Jim_RenameCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 3) { Jim_WrongNumArgs(interp, 1, argv, "oldName newName"); return JIM_ERR; } if (JimValidName(interp, "new procedure", argv[2])) { return JIM_ERR; } return Jim_RenameCommand(interp, Jim_String(argv[1]), Jim_String(argv[2])); } #define JIM_DICTMATCH_VALUES 0x0001 typedef void JimDictMatchCallbackType(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_HashEntry *he, int type); static void JimDictMatchKeys(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_HashEntry *he, int type) { Jim_ListAppendElement(interp, listObjPtr, (Jim_Obj *)he->key); if (type & JIM_DICTMATCH_VALUES) { Jim_ListAppendElement(interp, listObjPtr, (Jim_Obj *)he->u.val); } } /** * Like JimHashtablePatternMatch, but for dictionaries. */ static Jim_Obj *JimDictPatternMatch(Jim_Interp *interp, Jim_HashTable *ht, Jim_Obj *patternObjPtr, JimDictMatchCallbackType *callback, int type) { Jim_HashEntry *he; Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0); /* Check for the non-pattern case. We can do this much more efficiently. */ Jim_HashTableIterator htiter; JimInitHashTableIterator(ht, &htiter); while ((he = Jim_NextHashEntry(&htiter)) != NULL) { if (patternObjPtr == NULL || JimGlobMatch(Jim_String(patternObjPtr), Jim_String((Jim_Obj *)he->key), 0)) { callback(interp, listObjPtr, he, type); } } return listObjPtr; } int Jim_DictKeys(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObjPtr) { if (SetDictFromAny(interp, objPtr) != JIM_OK) { return JIM_ERR; } Jim_SetResult(interp, JimDictPatternMatch(interp, objPtr->internalRep.ptr, patternObjPtr, JimDictMatchKeys, 0)); return JIM_OK; } int Jim_DictValues(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObjPtr) { if (SetDictFromAny(interp, objPtr) != JIM_OK) { return JIM_ERR; } Jim_SetResult(interp, JimDictPatternMatch(interp, objPtr->internalRep.ptr, patternObjPtr, JimDictMatchKeys, JIM_DICTMATCH_VALUES)); return JIM_OK; } int Jim_DictSize(Jim_Interp *interp, Jim_Obj *objPtr) { if (SetDictFromAny(interp, objPtr) != JIM_OK) { return -1; } return ((Jim_HashTable *)objPtr->internalRep.ptr)->used; } /* [dict] */ static int Jim_DictCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *objPtr; int option; static const char * const options[] = { "create", "get", "set", "unset", "exists", "keys", "merge", "size", "with", NULL }; enum { OPT_CREATE, OPT_GET, OPT_SET, OPT_UNSET, OPT_EXIST, OPT_KEYS, OPT_MERGE, OPT_SIZE, OPT_WITH, }; if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "subcommand ?arguments ...?"); return JIM_ERR; } if (Jim_GetEnum(interp, argv[1], options, &option, "subcommand", JIM_ERRMSG) != JIM_OK) { return JIM_ERR; } switch (option) { case OPT_GET: if (argc < 3) { Jim_WrongNumArgs(interp, 2, argv, "varName ?key ...?"); return JIM_ERR; } if (Jim_DictKeysVector(interp, argv[2], argv + 3, argc - 3, &objPtr, JIM_ERRMSG) != JIM_OK) { return JIM_ERR; } Jim_SetResult(interp, objPtr); return JIM_OK; case OPT_SET: if (argc < 5) { Jim_WrongNumArgs(interp, 2, argv, "varName key ?key ...? value"); return JIM_ERR; } return Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 4, argv[argc - 1], JIM_ERRMSG); case OPT_EXIST: if (argc < 3) { Jim_WrongNumArgs(interp, 2, argv, "varName ?key ...?"); return JIM_ERR; } Jim_SetResultBool(interp, Jim_DictKeysVector(interp, argv[2], argv + 3, argc - 3, &objPtr, JIM_ERRMSG) == JIM_OK); return JIM_OK; case OPT_UNSET: if (argc < 4) { Jim_WrongNumArgs(interp, 2, argv, "varName key ?key ...?"); return JIM_ERR; } return Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 3, NULL, JIM_NONE); case OPT_KEYS: if (argc != 3 && argc != 4) { Jim_WrongNumArgs(interp, 2, argv, "dictVar ?pattern?"); return JIM_ERR; } return Jim_DictKeys(interp, argv[2], argc == 4 ? argv[3] : NULL); case OPT_SIZE: { int size; if (argc != 3) { Jim_WrongNumArgs(interp, 2, argv, "dictVar"); return JIM_ERR; } size = Jim_DictSize(interp, argv[2]); if (size < 0) { return JIM_ERR; } Jim_SetResultInt(interp, size); return JIM_OK; } case OPT_MERGE: if (argc == 2) { return JIM_OK; } else if (SetDictFromAny(interp, argv[2]) != JIM_OK) { return JIM_ERR; } else { return Jim_EvalPrefix(interp, "dict merge", argc - 2, argv + 2); } case OPT_WITH: if (argc < 4) { Jim_WrongNumArgs(interp, 2, argv, "dictVar ?key ...? script"); return JIM_ERR; } else if (Jim_GetVariable(interp, argv[2], JIM_ERRMSG) == NULL) { return JIM_ERR; } else { return Jim_EvalPrefix(interp, "dict with", argc - 2, argv + 2); } case OPT_CREATE: if (argc % 2) { Jim_WrongNumArgs(interp, 2, argv, "?key value ...?"); return JIM_ERR; } objPtr = Jim_NewDictObj(interp, argv + 2, argc - 2); Jim_SetResult(interp, objPtr); return JIM_OK; } return JIM_ERR; } /* [subst] */ static int Jim_SubstCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { static const char * const options[] = { "-nobackslashes", "-nocommands", "-novariables", NULL }; enum { OPT_NOBACKSLASHES, OPT_NOCOMMANDS, OPT_NOVARIABLES }; int i; int flags = JIM_SUBST_FLAG; Jim_Obj *objPtr; if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "?options? string"); return JIM_ERR; } for (i = 1; i < (argc - 1); i++) { int option; if (Jim_GetEnum(interp, argv[i], options, &option, NULL, JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) { return JIM_ERR; } switch (option) { case OPT_NOBACKSLASHES: flags |= JIM_SUBST_NOESC; break; case OPT_NOCOMMANDS: flags |= JIM_SUBST_NOCMD; break; case OPT_NOVARIABLES: flags |= JIM_SUBST_NOVAR; break; } } if (Jim_SubstObj(interp, argv[argc - 1], &objPtr, flags) != JIM_OK) { return JIM_ERR; } Jim_SetResult(interp, objPtr); return JIM_OK; } /* [info] */ static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int cmd; Jim_Obj *objPtr; int mode = 0; static const char * const commands[] = { "body", "statics", "commands", "procs", "channels", "exists", "globals", "level", "frame", "locals", "vars", "version", "patchlevel", "complete", "args", "hostname", "script", "source", "stacktrace", "nameofexecutable", "returncodes", "references", "alias", NULL }; enum { INFO_BODY, INFO_STATICS, INFO_COMMANDS, INFO_PROCS, INFO_CHANNELS, INFO_EXISTS, INFO_GLOBALS, INFO_LEVEL, INFO_FRAME, INFO_LOCALS, INFO_VARS, INFO_VERSION, INFO_PATCHLEVEL, INFO_COMPLETE, INFO_ARGS, INFO_HOSTNAME, INFO_SCRIPT, INFO_SOURCE, INFO_STACKTRACE, INFO_NAMEOFEXECUTABLE, INFO_RETURNCODES, INFO_REFERENCES, INFO_ALIAS }; #ifdef jim_ext_namespace int nons = 0; if (argc > 2 && Jim_CompareStringImmediate(interp, argv[1], "-nons")) { /* This is for internal use only */ argc--; argv++; nons = 1; } #endif if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "subcommand ?args ...?"); return JIM_ERR; } if (Jim_GetEnum(interp, argv[1], commands, &cmd, "subcommand", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) { return JIM_ERR; } /* Test for the the most common commands first, just in case it makes a difference */ switch (cmd) { case INFO_EXISTS: if (argc != 3) { Jim_WrongNumArgs(interp, 2, argv, "varName"); return JIM_ERR; } Jim_SetResultBool(interp, Jim_GetVariable(interp, argv[2], 0) != NULL); break; case INFO_ALIAS:{ Jim_Cmd *cmdPtr; if (argc != 3) { Jim_WrongNumArgs(interp, 2, argv, "command"); return JIM_ERR; } if ((cmdPtr = Jim_GetCommand(interp, argv[2], JIM_ERRMSG)) == NULL) { return JIM_ERR; } if (cmdPtr->isproc || cmdPtr->u.native.cmdProc != JimAliasCmd) { Jim_SetResultFormatted(interp, "command \"%#s\" is not an alias", argv[2]); return JIM_ERR; } Jim_SetResult(interp, (Jim_Obj *)cmdPtr->u.native.privData); return JIM_OK; } case INFO_CHANNELS: mode++; /* JIM_CMDLIST_CHANNELS */ #ifndef jim_ext_aio Jim_SetResultString(interp, "aio not enabled", -1); return JIM_ERR; #endif case INFO_PROCS: mode++; /* JIM_CMDLIST_PROCS */ case INFO_COMMANDS: /* mode 0 => JIM_CMDLIST_COMMANDS */ if (argc != 2 && argc != 3) { Jim_WrongNumArgs(interp, 2, argv, "?pattern?"); return JIM_ERR; } #ifdef jim_ext_namespace if (!nons) { if (Jim_Length(interp->framePtr->nsObj) || (argc == 3 && JimGlobMatch("::*", Jim_String(argv[2]), 0))) { return Jim_EvalPrefix(interp, "namespace info", argc - 1, argv + 1); } } #endif Jim_SetResult(interp, JimCommandsList(interp, (argc == 3) ? argv[2] : NULL, mode)); break; case INFO_VARS: mode++; /* JIM_VARLIST_VARS */ case INFO_LOCALS: mode++; /* JIM_VARLIST_LOCALS */ case INFO_GLOBALS: /* mode 0 => JIM_VARLIST_GLOBALS */ if (argc != 2 && argc != 3) { Jim_WrongNumArgs(interp, 2, argv, "?pattern?"); return JIM_ERR; } #ifdef jim_ext_namespace if (!nons) { if (Jim_Length(interp->framePtr->nsObj) || (argc == 3 && JimGlobMatch("::*", Jim_String(argv[2]), 0))) { return Jim_EvalPrefix(interp, "namespace info", argc - 1, argv + 1); } } #endif Jim_SetResult(interp, JimVariablesList(interp, argc == 3 ? argv[2] : NULL, mode)); break; case INFO_SCRIPT: if (argc != 2) { Jim_WrongNumArgs(interp, 2, argv, ""); return JIM_ERR; } Jim_SetResult(interp, Jim_GetScript(interp, interp->currentScriptObj)->fileNameObj); break; case INFO_SOURCE:{ int line; Jim_Obj *resObjPtr; Jim_Obj *fileNameObj; if (argc != 3) { Jim_WrongNumArgs(interp, 2, argv, "source"); return JIM_ERR; } if (argv[2]->typePtr == &sourceObjType) { fileNameObj = argv[2]->internalRep.sourceValue.fileNameObj; line = argv[2]->internalRep.sourceValue.lineNumber; } else if (argv[2]->typePtr == &scriptObjType) { ScriptObj *script = Jim_GetScript(interp, argv[2]); fileNameObj = script->fileNameObj; line = script->firstline; } else { fileNameObj = interp->emptyObj; line = 1; } resObjPtr = Jim_NewListObj(interp, NULL, 0); Jim_ListAppendElement(interp, resObjPtr, fileNameObj); Jim_ListAppendElement(interp, resObjPtr, Jim_NewIntObj(interp, line)); Jim_SetResult(interp, resObjPtr); break; } case INFO_STACKTRACE: Jim_SetResult(interp, interp->stackTrace); break; case INFO_LEVEL: case INFO_FRAME: switch (argc) { case 2: Jim_SetResultInt(interp, interp->framePtr->level); break; case 3: if (JimInfoLevel(interp, argv[2], &objPtr, cmd == INFO_LEVEL) != JIM_OK) { return JIM_ERR; } Jim_SetResult(interp, objPtr); break; default: Jim_WrongNumArgs(interp, 2, argv, "?levelNum?"); return JIM_ERR; } break; case INFO_BODY: case INFO_STATICS: case INFO_ARGS:{ Jim_Cmd *cmdPtr; if (argc != 3) { Jim_WrongNumArgs(interp, 2, argv, "procname"); return JIM_ERR; } if ((cmdPtr = Jim_GetCommand(interp, argv[2], JIM_ERRMSG)) == NULL) { return JIM_ERR; } if (!cmdPtr->isproc) { Jim_SetResultFormatted(interp, "command \"%#s\" is not a procedure", argv[2]); return JIM_ERR; } switch (cmd) { case INFO_BODY: Jim_SetResult(interp, cmdPtr->u.proc.bodyObjPtr); break; case INFO_ARGS: Jim_SetResult(interp, cmdPtr->u.proc.argListObjPtr); break; case INFO_STATICS: if (cmdPtr->u.proc.staticVars) { int mode = JIM_VARLIST_LOCALS | JIM_VARLIST_VALUES; Jim_SetResult(interp, JimHashtablePatternMatch(interp, cmdPtr->u.proc.staticVars, NULL, JimVariablesMatch, mode)); } break; } break; } case INFO_VERSION: case INFO_PATCHLEVEL:{ char buf[(JIM_INTEGER_SPACE * 2) + 1]; sprintf(buf, "%d.%d", JIM_VERSION / 100, JIM_VERSION % 100); Jim_SetResultString(interp, buf, -1); break; } case INFO_COMPLETE: if (argc != 3 && argc != 4) { Jim_WrongNumArgs(interp, 2, argv, "script ?missing?"); return JIM_ERR; } else { int len; const char *s = Jim_GetString(argv[2], &len); char missing; Jim_SetResultBool(interp, Jim_ScriptIsComplete(s, len, &missing)); if (missing != ' ' && argc == 4) { Jim_SetVariable(interp, argv[3], Jim_NewStringObj(interp, &missing, 1)); } } break; case INFO_HOSTNAME: /* Redirect to os.gethostname if it exists */ return Jim_Eval(interp, "os.gethostname"); case INFO_NAMEOFEXECUTABLE: /* Redirect to Tcl proc */ return Jim_Eval(interp, "{info nameofexecutable}"); case INFO_RETURNCODES: if (argc == 2) { int i; Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0); for (i = 0; jimReturnCodes[i]; i++) { Jim_ListAppendElement(interp, listObjPtr, Jim_NewIntObj(interp, i)); Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, jimReturnCodes[i], -1)); } Jim_SetResult(interp, listObjPtr); } else if (argc == 3) { long code; const char *name; if (Jim_GetLong(interp, argv[2], &code) != JIM_OK) { return JIM_ERR; } name = Jim_ReturnCode(code); if (*name == '?') { Jim_SetResultInt(interp, code); } else { Jim_SetResultString(interp, name, -1); } } else { Jim_WrongNumArgs(interp, 2, argv, "?code?"); return JIM_ERR; } break; case INFO_REFERENCES: #ifdef JIM_REFERENCES return JimInfoReferences(interp, argc, argv); #else Jim_SetResultString(interp, "not supported", -1); return JIM_ERR; #endif } return JIM_OK; } /* [exists] */ static int Jim_ExistsCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *objPtr; int result = 0; static const char * const options[] = { "-command", "-proc", "-alias", "-var", NULL }; enum { OPT_COMMAND, OPT_PROC, OPT_ALIAS, OPT_VAR }; int option; if (argc == 2) { option = OPT_VAR; objPtr = argv[1]; } else if (argc == 3) { if (Jim_GetEnum(interp, argv[1], options, &option, NULL, JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) { return JIM_ERR; } objPtr = argv[2]; } else { Jim_WrongNumArgs(interp, 1, argv, "?option? name"); return JIM_ERR; } if (option == OPT_VAR) { result = Jim_GetVariable(interp, objPtr, 0) != NULL; } else { /* Now different kinds of commands */ Jim_Cmd *cmd = Jim_GetCommand(interp, objPtr, JIM_NONE); if (cmd) { switch (option) { case OPT_COMMAND: result = 1; break; case OPT_ALIAS: result = cmd->isproc == 0 && cmd->u.native.cmdProc == JimAliasCmd; break; case OPT_PROC: result = cmd->isproc; break; } } } Jim_SetResultBool(interp, result); return JIM_OK; } /* [split] */ static int Jim_SplitCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { const char *str, *splitChars, *noMatchStart; int splitLen, strLen; Jim_Obj *resObjPtr; int c; int len; if (argc != 2 && argc != 3) { Jim_WrongNumArgs(interp, 1, argv, "string ?splitChars?"); return JIM_ERR; } str = Jim_GetString(argv[1], &len); if (len == 0) { return JIM_OK; } strLen = Jim_Utf8Length(interp, argv[1]); /* Init */ if (argc == 2) { splitChars = " \n\t\r"; splitLen = 4; } else { splitChars = Jim_String(argv[2]); splitLen = Jim_Utf8Length(interp, argv[2]); } noMatchStart = str; resObjPtr = Jim_NewListObj(interp, NULL, 0); /* Split */ if (splitLen) { Jim_Obj *objPtr; while (strLen--) { const char *sc = splitChars; int scLen = splitLen; int sl = utf8_tounicode(str, &c); while (scLen--) { int pc; sc += utf8_tounicode(sc, &pc); if (c == pc) { objPtr = Jim_NewStringObj(interp, noMatchStart, (str - noMatchStart)); Jim_ListAppendElement(interp, resObjPtr, objPtr); noMatchStart = str + sl; break; } } str += sl; } objPtr = Jim_NewStringObj(interp, noMatchStart, (str - noMatchStart)); Jim_ListAppendElement(interp, resObjPtr, objPtr); } else { /* This handles the special case of splitchars eq {} * Optimise by sharing common (ASCII) characters */ Jim_Obj **commonObj = NULL; #define NUM_COMMON (128 - 9) while (strLen--) { int n = utf8_tounicode(str, &c); #ifdef JIM_OPTIMIZATION if (c >= 9 && c < 128) { /* Common ASCII char. Note that 9 is the tab character */ c -= 9; if (!commonObj) { commonObj = Jim_Alloc(sizeof(*commonObj) * NUM_COMMON); memset(commonObj, 0, sizeof(*commonObj) * NUM_COMMON); } if (!commonObj[c]) { commonObj[c] = Jim_NewStringObj(interp, str, 1); } Jim_ListAppendElement(interp, resObjPtr, commonObj[c]); str++; continue; } #endif Jim_ListAppendElement(interp, resObjPtr, Jim_NewStringObjUtf8(interp, str, 1)); str += n; } Jim_Free(commonObj); } Jim_SetResult(interp, resObjPtr); return JIM_OK; } /* [join] */ static int Jim_JoinCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { const char *joinStr; int joinStrLen; if (argc != 2 && argc != 3) { Jim_WrongNumArgs(interp, 1, argv, "list ?joinString?"); return JIM_ERR; } /* Init */ if (argc == 2) { joinStr = " "; joinStrLen = 1; } else { joinStr = Jim_GetString(argv[2], &joinStrLen); } Jim_SetResult(interp, Jim_ListJoin(interp, argv[1], joinStr, joinStrLen)); return JIM_OK; } /* [format] */ static int Jim_FormatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *objPtr; if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "formatString ?arg arg ...?"); return JIM_ERR; } objPtr = Jim_FormatString(interp, argv[1], argc - 2, argv + 2); if (objPtr == NULL) return JIM_ERR; Jim_SetResult(interp, objPtr); return JIM_OK; } /* [scan] */ static int Jim_ScanCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *listPtr, **outVec; int outc, i; if (argc < 3) { Jim_WrongNumArgs(interp, 1, argv, "string format ?varName varName ...?"); return JIM_ERR; } if (argv[2]->typePtr != &scanFmtStringObjType) SetScanFmtFromAny(interp, argv[2]); if (FormatGetError(argv[2]) != 0) { Jim_SetResultString(interp, FormatGetError(argv[2]), -1); return JIM_ERR; } if (argc > 3) { int maxPos = FormatGetMaxPos(argv[2]); int count = FormatGetCnvCount(argv[2]); if (maxPos > argc - 3) { Jim_SetResultString(interp, "\"%n$\" argument index out of range", -1); return JIM_ERR; } else if (count > argc - 3) { Jim_SetResultString(interp, "different numbers of variable names and " "field specifiers", -1); return JIM_ERR; } else if (count < argc - 3) { Jim_SetResultString(interp, "variable is not assigned by any " "conversion specifiers", -1); return JIM_ERR; } } listPtr = Jim_ScanString(interp, argv[1], argv[2], JIM_ERRMSG); if (listPtr == 0) return JIM_ERR; if (argc > 3) { int rc = JIM_OK; int count = 0; if (listPtr != 0 && listPtr != (Jim_Obj *)EOF) { int len = Jim_ListLength(interp, listPtr); if (len != 0) { JimListGetElements(interp, listPtr, &outc, &outVec); for (i = 0; i < outc; ++i) { if (Jim_Length(outVec[i]) > 0) { ++count; if (Jim_SetVariable(interp, argv[3 + i], outVec[i]) != JIM_OK) { rc = JIM_ERR; } } } } Jim_FreeNewObj(interp, listPtr); } else { count = -1; } if (rc == JIM_OK) { Jim_SetResultInt(interp, count); } return rc; } else { if (listPtr == (Jim_Obj *)EOF) { Jim_SetResult(interp, Jim_NewListObj(interp, 0, 0)); return JIM_OK; } Jim_SetResult(interp, listPtr); } return JIM_OK; } /* [error] */ static int Jim_ErrorCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 2 && argc != 3) { Jim_WrongNumArgs(interp, 1, argv, "message ?stacktrace?"); return JIM_ERR; } Jim_SetResult(interp, argv[1]); if (argc == 3) { JimSetStackTrace(interp, argv[2]); return JIM_ERR; } interp->addStackTrace++; return JIM_ERR; } /* [lrange] */ static int Jim_LrangeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *objPtr; if (argc != 4) { Jim_WrongNumArgs(interp, 1, argv, "list first last"); return JIM_ERR; } if ((objPtr = Jim_ListRange(interp, argv[1], argv[2], argv[3])) == NULL) return JIM_ERR; Jim_SetResult(interp, objPtr); return JIM_OK; } /* [lrepeat] */ static int Jim_LrepeatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *objPtr; long count; if (argc < 2 || Jim_GetLong(interp, argv[1], &count) != JIM_OK || count < 0) { Jim_WrongNumArgs(interp, 1, argv, "count ?value ...?"); return JIM_ERR; } if (count == 0 || argc == 2) { return JIM_OK; } argc -= 2; argv += 2; objPtr = Jim_NewListObj(interp, argv, argc); while (--count) { ListInsertElements(objPtr, -1, argc, argv); } Jim_SetResult(interp, objPtr); return JIM_OK; } char **Jim_GetEnviron(void) { #if defined(HAVE__NSGETENVIRON) return *_NSGetEnviron(); #else #if !defined(NO_ENVIRON_EXTERN) extern char **environ; #endif return environ; #endif } void Jim_SetEnviron(char **env) { #if defined(HAVE__NSGETENVIRON) *_NSGetEnviron() = env; #else #if !defined(NO_ENVIRON_EXTERN) extern char **environ; #endif environ = env; #endif } /* [env] */ static int Jim_EnvCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { const char *key; const char *val; if (argc == 1) { char **e = Jim_GetEnviron(); int i; Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0); for (i = 0; e[i]; i++) { const char *equals = strchr(e[i], '='); if (equals) { Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, e[i], equals - e[i])); Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, equals + 1, -1)); } } Jim_SetResult(interp, listObjPtr); return JIM_OK; } if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "varName ?default?"); return JIM_ERR; } key = Jim_String(argv[1]); val = getenv(key); if (val == NULL) { if (argc < 3) { Jim_SetResultFormatted(interp, "environment variable \"%#s\" does not exist", argv[1]); return JIM_ERR; } val = Jim_String(argv[2]); } Jim_SetResult(interp, Jim_NewStringObj(interp, val, -1)); return JIM_OK; } /* [source] */ static int Jim_SourceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int retval; if (argc != 2) { Jim_WrongNumArgs(interp, 1, argv, "fileName"); return JIM_ERR; } retval = Jim_EvalFile(interp, Jim_String(argv[1])); if (retval == JIM_RETURN) return JIM_OK; return retval; } /* [lreverse] */ static int Jim_LreverseCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *revObjPtr, **ele; int len; if (argc != 2) { Jim_WrongNumArgs(interp, 1, argv, "list"); return JIM_ERR; } JimListGetElements(interp, argv[1], &len, &ele); len--; revObjPtr = Jim_NewListObj(interp, NULL, 0); while (len >= 0) ListAppendElement(revObjPtr, ele[len--]); Jim_SetResult(interp, revObjPtr); return JIM_OK; } static int JimRangeLen(jim_wide start, jim_wide end, jim_wide step) { jim_wide len; if (step == 0) return -1; if (start == end) return 0; else if (step > 0 && start > end) return -1; else if (step < 0 && end > start) return -1; len = end - start; if (len < 0) len = -len; /* abs(len) */ if (step < 0) step = -step; /* abs(step) */ len = 1 + ((len - 1) / step); /* We can truncate safely to INT_MAX, the range command * will always return an error for a such long range * because Tcl lists can't be so long. */ if (len > INT_MAX) len = INT_MAX; return (int)((len < 0) ? -1 : len); } /* [range] */ static int Jim_RangeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { jim_wide start = 0, end, step = 1; int len, i; Jim_Obj *objPtr; if (argc < 2 || argc > 4) { Jim_WrongNumArgs(interp, 1, argv, "?start? end ?step?"); return JIM_ERR; } if (argc == 2) { if (Jim_GetWide(interp, argv[1], &end) != JIM_OK) return JIM_ERR; } else { if (Jim_GetWide(interp, argv[1], &start) != JIM_OK || Jim_GetWide(interp, argv[2], &end) != JIM_OK) return JIM_ERR; if (argc == 4 && Jim_GetWide(interp, argv[3], &step) != JIM_OK) return JIM_ERR; } if ((len = JimRangeLen(start, end, step)) == -1) { Jim_SetResultString(interp, "Invalid (infinite?) range specified", -1); return JIM_ERR; } objPtr = Jim_NewListObj(interp, NULL, 0); for (i = 0; i < len; i++) ListAppendElement(objPtr, Jim_NewIntObj(interp, start + i * step)); Jim_SetResult(interp, objPtr); return JIM_OK; } /* [rand] */ static int Jim_RandCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { jim_wide min = 0, max = 0, len, maxMul; if (argc < 1 || argc > 3) { Jim_WrongNumArgs(interp, 1, argv, "?min? max"); return JIM_ERR; } if (argc == 1) { max = JIM_WIDE_MAX; } else if (argc == 2) { if (Jim_GetWide(interp, argv[1], &max) != JIM_OK) return JIM_ERR; } else if (argc == 3) { if (Jim_GetWide(interp, argv[1], &min) != JIM_OK || Jim_GetWide(interp, argv[2], &max) != JIM_OK) return JIM_ERR; } len = max-min; if (len < 0) { Jim_SetResultString(interp, "Invalid arguments (max < min)", -1); return JIM_ERR; } maxMul = JIM_WIDE_MAX - (len ? (JIM_WIDE_MAX%len) : 0); while (1) { jim_wide r; JimRandomBytes(interp, &r, sizeof(jim_wide)); if (r < 0 || r >= maxMul) continue; r = (len == 0) ? 0 : r%len; Jim_SetResultInt(interp, min+r); return JIM_OK; } } static const struct { const char *name; Jim_CmdProc cmdProc; } Jim_CoreCommandsTable[] = { {"alias", Jim_AliasCoreCommand}, {"set", Jim_SetCoreCommand}, {"unset", Jim_UnsetCoreCommand}, {"puts", Jim_PutsCoreCommand}, {"+", Jim_AddCoreCommand}, {"*", Jim_MulCoreCommand}, {"-", Jim_SubCoreCommand}, {"/", Jim_DivCoreCommand}, {"incr", Jim_IncrCoreCommand}, {"while", Jim_WhileCoreCommand}, {"loop", Jim_LoopCoreCommand}, {"for", Jim_ForCoreCommand}, {"foreach", Jim_ForeachCoreCommand}, {"lmap", Jim_LmapCoreCommand}, {"lassign", Jim_LassignCoreCommand}, {"if", Jim_IfCoreCommand}, {"switch", Jim_SwitchCoreCommand}, {"list", Jim_ListCoreCommand}, {"lindex", Jim_LindexCoreCommand}, {"lset", Jim_LsetCoreCommand}, {"lsearch", Jim_LsearchCoreCommand}, {"llength", Jim_LlengthCoreCommand}, {"lappend", Jim_LappendCoreCommand}, {"linsert", Jim_LinsertCoreCommand}, {"lreplace", Jim_LreplaceCoreCommand}, {"lsort", Jim_LsortCoreCommand}, {"append", Jim_AppendCoreCommand}, {"debug", Jim_DebugCoreCommand}, {"eval", Jim_EvalCoreCommand}, {"uplevel", Jim_UplevelCoreCommand}, {"expr", Jim_ExprCoreCommand}, {"break", Jim_BreakCoreCommand}, {"continue", Jim_ContinueCoreCommand}, {"proc", Jim_ProcCoreCommand}, {"concat", Jim_ConcatCoreCommand}, {"return", Jim_ReturnCoreCommand}, {"upvar", Jim_UpvarCoreCommand}, {"global", Jim_GlobalCoreCommand}, {"string", Jim_StringCoreCommand}, {"time", Jim_TimeCoreCommand}, {"exit", Jim_ExitCoreCommand}, {"catch", Jim_CatchCoreCommand}, #ifdef JIM_REFERENCES {"ref", Jim_RefCoreCommand}, {"getref", Jim_GetrefCoreCommand}, {"setref", Jim_SetrefCoreCommand}, {"finalize", Jim_FinalizeCoreCommand}, {"collect", Jim_CollectCoreCommand}, #endif {"rename", Jim_RenameCoreCommand}, {"dict", Jim_DictCoreCommand}, {"subst", Jim_SubstCoreCommand}, {"info", Jim_InfoCoreCommand}, {"exists", Jim_ExistsCoreCommand}, {"split", Jim_SplitCoreCommand}, {"join", Jim_JoinCoreCommand}, {"format", Jim_FormatCoreCommand}, {"scan", Jim_ScanCoreCommand}, {"error", Jim_ErrorCoreCommand}, {"lrange", Jim_LrangeCoreCommand}, {"lrepeat", Jim_LrepeatCoreCommand}, {"env", Jim_EnvCoreCommand}, {"source", Jim_SourceCoreCommand}, {"lreverse", Jim_LreverseCoreCommand}, {"range", Jim_RangeCoreCommand}, {"rand", Jim_RandCoreCommand}, {"tailcall", Jim_TailcallCoreCommand}, {"local", Jim_LocalCoreCommand}, {"upcall", Jim_UpcallCoreCommand}, {"apply", Jim_ApplyCoreCommand}, {NULL, NULL}, }; void Jim_RegisterCoreCommands(Jim_Interp *interp) { int i = 0; while (Jim_CoreCommandsTable[i].name != NULL) { Jim_CreateCommand(interp, Jim_CoreCommandsTable[i].name, Jim_CoreCommandsTable[i].cmdProc, NULL, NULL); i++; } } /* ----------------------------------------------------------------------------- * Interactive prompt * ---------------------------------------------------------------------------*/ void Jim_MakeErrorMessage(Jim_Interp *interp) { Jim_Obj *argv[2]; argv[0] = Jim_NewStringObj(interp, "errorInfo", -1); argv[1] = interp->result; Jim_EvalObjVector(interp, 2, argv); } static void JimSetFailedEnumResult(Jim_Interp *interp, const char *arg, const char *badtype, const char *prefix, const char *const *tablePtr, const char *name) { int count; char **tablePtrSorted; int i; for (count = 0; tablePtr[count]; count++) { } if (name == NULL) { name = "option"; } Jim_SetResultFormatted(interp, "%s%s \"%s\": must be ", badtype, name, arg); tablePtrSorted = Jim_Alloc(sizeof(char *) * count); memcpy(tablePtrSorted, tablePtr, sizeof(char *) * count); qsort(tablePtrSorted, count, sizeof(char *), qsortCompareStringPointers); for (i = 0; i < count; i++) { if (i + 1 == count && count > 1) { Jim_AppendString(interp, Jim_GetResult(interp), "or ", -1); } Jim_AppendStrings(interp, Jim_GetResult(interp), prefix, tablePtrSorted[i], NULL); if (i + 1 != count) { Jim_AppendString(interp, Jim_GetResult(interp), ", ", -1); } } Jim_Free(tablePtrSorted); } int Jim_GetEnum(Jim_Interp *interp, Jim_Obj *objPtr, const char *const *tablePtr, int *indexPtr, const char *name, int flags) { const char *bad = "bad "; const char *const *entryPtr = NULL; int i; int match = -1; int arglen; const char *arg = Jim_GetString(objPtr, &arglen); *indexPtr = -1; for (entryPtr = tablePtr, i = 0; *entryPtr != NULL; entryPtr++, i++) { if (Jim_CompareStringImmediate(interp, objPtr, *entryPtr)) { /* Found an exact match */ *indexPtr = i; return JIM_OK; } if (flags & JIM_ENUM_ABBREV) { /* Accept an unambiguous abbreviation. * Note that '-' doesnt' consitute a valid abbreviation */ if (strncmp(arg, *entryPtr, arglen) == 0) { if (*arg == '-' && arglen == 1) { break; } if (match >= 0) { bad = "ambiguous "; goto ambiguous; } match = i; } } } /* If we had an unambiguous partial match */ if (match >= 0) { *indexPtr = match; return JIM_OK; } ambiguous: if (flags & JIM_ERRMSG) { JimSetFailedEnumResult(interp, arg, bad, "", tablePtr, name); } return JIM_ERR; } int Jim_FindByName(const char *name, const char * const array[], size_t len) { int i; for (i = 0; i < (int)len; i++) { if (array[i] && strcmp(array[i], name) == 0) { return i; } } return -1; } int Jim_IsDict(Jim_Obj *objPtr) { return objPtr->typePtr == &dictObjType; } int Jim_IsList(Jim_Obj *objPtr) { return objPtr->typePtr == &listObjType; } /** * Very simple printf-like formatting, designed for error messages. * * The format may contain up to 5 '%s' or '%#s', corresponding to variable arguments. * The resulting string is created and set as the result. * * Each '%s' should correspond to a regular string parameter. * Each '%#s' should correspond to a (Jim_Obj *) parameter. * Any other printf specifier is not allowed (but %% is allowed for the % character). * * e.g. Jim_SetResultFormatted(interp, "Bad option \"%#s\" in proc \"%#s\"", optionObjPtr, procNamePtr); * * Note: We take advantage of the fact that printf has the same behaviour for both %s and %#s */ void Jim_SetResultFormatted(Jim_Interp *interp, const char *format, ...) { /* Initial space needed */ int len = strlen(format); int extra = 0; int n = 0; const char *params[5]; char *buf; va_list args; int i; va_start(args, format); for (i = 0; i < len && n < 5; i++) { int l; if (strncmp(format + i, "%s", 2) == 0) { params[n] = va_arg(args, char *); l = strlen(params[n]); } else if (strncmp(format + i, "%#s", 3) == 0) { Jim_Obj *objPtr = va_arg(args, Jim_Obj *); params[n] = Jim_GetString(objPtr, &l); } else { if (format[i] == '%') { i++; } continue; } n++; extra += l; } len += extra; buf = Jim_Alloc(len + 1); len = snprintf(buf, len + 1, format, params[0], params[1], params[2], params[3], params[4]); Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, buf, len)); } /* stubs */ #ifndef jim_ext_package int Jim_PackageProvide(Jim_Interp *interp, const char *name, const char *ver, int flags) { return JIM_OK; } #endif #ifndef jim_ext_aio FILE *Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *fhObj) { Jim_SetResultString(interp, "aio not enabled", -1); return NULL; } #endif /* * Local Variables: *** * c-basic-offset: 4 *** * tab-width: 4 *** * End: *** */ openocd-0.7.0/jimtcl/make-load-static-exts.tcl0000644000175000001440000000160412134336723016155 00000000000000#!/usr/bin/env tclsh # Usage: make-load-static-exts extname ... >load-static-exts.c # Creates load-static-exts.c based on the configured static extensions # There are some dependencies on static extensions which require # a certain load order. Do this by setting priorities and sorting. array set pri { stdlib 0 readdir 1 glob 2 oo 1 tree 2 pack 1 binary 2 } foreach i $argv { set p 1 if {[info exists pri($i)]} { set p $pri($i) } lappend exts [list $p $i] } set exts [lsort $exts] puts { /* autogenerated - do not edit */ #include "jim.h" #include "jimautoconf.h" int Jim_InitStaticExtensions(Jim_Interp *interp) } puts \{ foreach e $exts { set ext [lindex $e 1] puts "\textern int Jim_${ext}Init(Jim_Interp *);" } foreach e $exts { set ext [lindex $e 1] puts "\tJim_${ext}Init(interp);" } puts "\treturn JIM_OK;" puts \} openocd-0.7.0/jimtcl/jim-eventloop.h0000644000175000001440000000713412134336723014316 00000000000000/* Jim - A small embeddable Tcl interpreter * * Copyright 2005 Salvatore Sanfilippo * Copyright 2005 Clemens Hintze * Copyright 2005 patthoyts - Pat Thoyts * Copyright 2008 oharboe - Øyvind Harboe - oyvind.harboe@zylin.com * Copyright 2008 Andrew Lunn * Copyright 2008 Duane Ellis * Copyright 2008 Uwe Klein * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation * are those of the authors and should not be interpreted as representing * official policies, either expressed or implied, of the Jim Tcl Project. **/ /* ------ USAGE ------- * * In order to use this file from other extensions include it in every * file where you need to call the eventloop API, also in the init * function of your extension call Jim_ImportEventloopAPI(interp) * after the Jim_InitExtension() call. * * See the UDP extension as example. */ #ifndef __JIM_EVENTLOOP_H__ #define __JIM_EVENTLOOP_H__ #include typedef int Jim_FileProc(Jim_Interp *interp, void *clientData, int mask); typedef int Jim_SignalProc(Jim_Interp *interp, void *clientData, void *msg); typedef void Jim_TimeProc(Jim_Interp *interp, void *clientData); typedef void Jim_EventFinalizerProc(Jim_Interp *interp, void *clientData); /* File event structure */ #define JIM_EVENT_READABLE 1 #define JIM_EVENT_WRITABLE 2 #define JIM_EVENT_EXCEPTION 4 JIM_EXPORT void Jim_CreateFileHandler (Jim_Interp *interp, FILE *handle, int mask, Jim_FileProc *proc, void *clientData, Jim_EventFinalizerProc *finalizerProc); JIM_EXPORT void Jim_DeleteFileHandler (Jim_Interp *interp, FILE *handle); JIM_EXPORT jim_wide Jim_CreateTimeHandler (Jim_Interp *interp, jim_wide milliseconds, Jim_TimeProc *proc, void *clientData, Jim_EventFinalizerProc *finalizerProc); JIM_EXPORT jim_wide Jim_DeleteTimeHandler (Jim_Interp *interp, jim_wide id); #define JIM_FILE_EVENTS 1 #define JIM_TIME_EVENTS 2 #define JIM_ALL_EVENTS (JIM_FILE_EVENTS|JIM_TIME_EVENTS) #define JIM_DONT_WAIT 4 JIM_EXPORT int Jim_ProcessEvents (Jim_Interp *interp, int flags); JIM_EXPORT int Jim_EvalObjBackground (Jim_Interp *interp, Jim_Obj *scriptObjPtr); int Jim_eventloopInit(Jim_Interp *interp); #endif /* __JIM_EVENTLOOP_H__ */ openocd-0.7.0/jimtcl/jim-subcmd.c0000644000175000001440000001372412134336723013555 00000000000000#include #include #include /** * Implements the common 'commands' subcommand */ static int subcmd_null(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { /* Nothing to do, since the result has already been created */ return JIM_OK; } /** * Do-nothing command to support -commands and -usage */ static const jim_subcmd_type dummy_subcmd = { "dummy", NULL, subcmd_null, 0, 0, JIM_MODFLAG_HIDDEN }; static void add_commands(Jim_Interp *interp, const jim_subcmd_type * ct, const char *sep) { const char *s = ""; for (; ct->cmd; ct++) { if (!(ct->flags & JIM_MODFLAG_HIDDEN)) { Jim_AppendStrings(interp, Jim_GetResult(interp), s, ct->cmd, NULL); s = sep; } } } static void bad_subcmd(Jim_Interp *interp, const jim_subcmd_type * command_table, const char *type, Jim_Obj *cmd, Jim_Obj *subcmd) { Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); Jim_AppendStrings(interp, Jim_GetResult(interp), Jim_String(cmd), ", ", type, " command \"", Jim_String(subcmd), "\": should be ", NULL); add_commands(interp, command_table, ", "); } static void show_cmd_usage(Jim_Interp *interp, const jim_subcmd_type * command_table, int argc, Jim_Obj *const *argv) { Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); Jim_AppendStrings(interp, Jim_GetResult(interp), "Usage: \"", Jim_String(argv[0]), " command ... \", where command is one of: ", NULL); add_commands(interp, command_table, ", "); } static void add_cmd_usage(Jim_Interp *interp, const jim_subcmd_type * ct, Jim_Obj *cmd) { if (cmd) { Jim_AppendStrings(interp, Jim_GetResult(interp), Jim_String(cmd), " ", NULL); } Jim_AppendStrings(interp, Jim_GetResult(interp), ct->cmd, NULL); if (ct->args && *ct->args) { Jim_AppendStrings(interp, Jim_GetResult(interp), " ", ct->args, NULL); } } static void set_wrong_args(Jim_Interp *interp, const jim_subcmd_type * command_table, Jim_Obj *subcmd) { Jim_SetResultString(interp, "wrong # args: should be \"", -1); add_cmd_usage(interp, command_table, subcmd); Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL); } const jim_subcmd_type *Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type * command_table, int argc, Jim_Obj *const *argv) { const jim_subcmd_type *ct; const jim_subcmd_type *partial = 0; int cmdlen; Jim_Obj *cmd; const char *cmdstr; const char *cmdname; int help = 0; cmdname = Jim_String(argv[0]); if (argc < 2) { Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); Jim_AppendStrings(interp, Jim_GetResult(interp), "wrong # args: should be \"", cmdname, " command ...\"\n", NULL); Jim_AppendStrings(interp, Jim_GetResult(interp), "Use \"", cmdname, " -help ?command?\" for help", NULL); return 0; } cmd = argv[1]; /* Check for the help command */ if (Jim_CompareStringImmediate(interp, cmd, "-help")) { if (argc == 2) { /* Usage for the command, not the subcommand */ show_cmd_usage(interp, command_table, argc, argv); return &dummy_subcmd; } help = 1; /* Skip the 'help' command */ cmd = argv[2]; } /* Check for special builtin '-commands' command first */ if (Jim_CompareStringImmediate(interp, cmd, "-commands")) { /* Build the result here */ Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); add_commands(interp, command_table, " "); return &dummy_subcmd; } cmdstr = Jim_GetString(cmd, &cmdlen); for (ct = command_table; ct->cmd; ct++) { if (Jim_CompareStringImmediate(interp, cmd, ct->cmd)) { /* Found an exact match */ break; } if (strncmp(cmdstr, ct->cmd, cmdlen) == 0) { if (partial) { /* Ambiguous */ if (help) { /* Just show the top level help here */ show_cmd_usage(interp, command_table, argc, argv); return &dummy_subcmd; } bad_subcmd(interp, command_table, "ambiguous", argv[0], argv[1 + help]); return 0; } partial = ct; } continue; } /* If we had an unambiguous partial match */ if (partial && !ct->cmd) { ct = partial; } if (!ct->cmd) { /* No matching command */ if (help) { /* Just show the top level help here */ show_cmd_usage(interp, command_table, argc, argv); return &dummy_subcmd; } bad_subcmd(interp, command_table, "unknown", argv[0], argv[1 + help]); return 0; } if (help) { Jim_SetResultString(interp, "Usage: ", -1); /* subcmd */ add_cmd_usage(interp, ct, argv[0]); return &dummy_subcmd; } /* Check the number of args */ if (argc - 2 < ct->minargs || (ct->maxargs >= 0 && argc - 2 > ct->maxargs)) { Jim_SetResultString(interp, "wrong # args: should be \"", -1); /* subcmd */ add_cmd_usage(interp, ct, argv[0]); Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL); return 0; } /* Good command */ return ct; } int Jim_CallSubCmd(Jim_Interp *interp, const jim_subcmd_type * ct, int argc, Jim_Obj *const *argv) { int ret = JIM_ERR; if (ct) { if (ct->flags & JIM_MODFLAG_FULLARGV) { ret = ct->function(interp, argc, argv); } else { ret = ct->function(interp, argc - 2, argv + 2); } if (ret < 0) { set_wrong_args(interp, ct, argv[0]); ret = JIM_ERR; } } return ret; } int Jim_SubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { const jim_subcmd_type *ct = Jim_ParseSubCmd(interp, (const jim_subcmd_type *)Jim_CmdPrivData(interp), argc, argv); return Jim_CallSubCmd(interp, ct, argc, argv); } openocd-0.7.0/jimtcl/tests/0000755000175000001440000000000012141414413012561 500000000000000openocd-0.7.0/jimtcl/tests/prefix.test0000644000175000001440000001146612134336723014720 00000000000000# Commands covered: tcl::prefix # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # Copyright (c) 2001 by Kevin B. Kenny. All rights reserved. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. source [file dirname [info script]]/testing.tcl needs cmd tcl::prefix prefix testConstraint namespace [expr {[info commands namespace] ne ""}] test string-26.1 {tcl::prefix, too few args} -body { tcl::prefix match a } -returnCodes 1 -match glob -result {wrong # args: should be "tcl::prefix match ?options*? table string"} test string-26.2 {tcl::prefix, bad args} -body { tcl::prefix match a b c } -returnCodes 1 -result {bad option "a": must be -error, -exact, or -message} test string-26.2.1 {tcl::prefix, empty table} -body { tcl::prefix match {} foo } -returnCodes 1 -result {bad option "foo": no valid options} test string-26.3.1 {tcl::prefix, bad args} -body { tcl::prefix match -error "x" -exact str1 str2 } -returnCodes 1 -match glob -result * test string-26.3.2 {tcl::prefix, bad args} -body { tcl::prefix match -error str1 str2 } -returnCodes 1 -result {missing error options} test string-26.4 {tcl::prefix, bad args} -body { tcl::prefix match -message str1 str2 } -returnCodes 1 -result {missing message} test string-26.5 {tcl::prefix} { tcl::prefix match {apa bepa cepa depa} cepa } cepa test string-26.6 {tcl::prefix} { tcl::prefix match {apa bepa cepa depa} be } bepa test string-26.7 {tcl::prefix} -body { tcl::prefix match -exact {apa bepa cepa depa} be } -returnCodes 1 -result {bad option "be": must be apa, bepa, cepa, or depa} test string-26.8 {tcl::prefix} -body { tcl::prefix match -message switch {apa bear bepa depa} be } -returnCodes 1 -result {ambiguous switch "be": must be apa, bear, bepa, or depa} test string-26.9 {tcl::prefix} -body { tcl::prefix match -error {} {apa bepa bear depa} be } -returnCodes 0 -result {} test string-26.10 {tcl::prefix} -body { tcl::prefix match -error {-level 1} {apa bear bepa depa} be } -returnCodes 2 -result {ambiguous option "be": must be apa, bear, bepa, or depa} test string-27.1 {tcl::prefix all, too few args} -body { tcl::prefix all a } -returnCodes 1 -result {wrong # args: should be "tcl::prefix all table string"} test string-27.2 {tcl::prefix all, bad args} -body { tcl::prefix all a b c } -returnCodes 1 -result {wrong # args: should be "tcl::prefix all table string"} test string-27.4 {tcl::prefix all} { tcl::prefix all {apa bepa cepa depa} c } cepa test string-27.5 {tcl::prefix all} { tcl::prefix all {apa bepa cepa depa} cepa } cepa test string-27.6 {tcl::prefix all} { tcl::prefix all {apa bepa cepa depa} cepax } {} test string-27.7 {tcl::prefix all} { tcl::prefix all {apa aska appa} a } {apa aska appa} test string-27.8 {tcl::prefix all} { tcl::prefix all {apa aska appa} ap } {apa appa} test string-27.9 {tcl::prefix all} { tcl::prefix all {apa aska appa} p } {} test string-27.10 {tcl::prefix all} { tcl::prefix all {apa aska appa} {} } {apa aska appa} test string-28.1 {tcl::prefix longest, too few args} -body { tcl::prefix longest a } -returnCodes 1 -result {wrong # args: should be "tcl::prefix longest table string"} test string-28.2 {tcl::prefix longest, bad args} -body { tcl::prefix longest a b c } -returnCodes 1 -result {wrong # args: should be "tcl::prefix longest table string"} test string-28.4 {tcl::prefix longest} { tcl::prefix longest {apa bepa cepa depa} c } cepa test string-28.5 {tcl::prefix longest} { tcl::prefix longest {apa bepa cepa depa} cepa } cepa test string-28.6 {tcl::prefix longest} { tcl::prefix longest {apa bepa cepa depa} cepax } {} test string-28.7 {tcl::prefix longest} { tcl::prefix longest {apa aska appa} a } a test string-28.8 {tcl::prefix longest} { tcl::prefix longest {apa aska appa} ap } ap test string-28.9 {tcl::prefix longest} { tcl::prefix longest {apa bska appa} a } ap test string-28.10 {tcl::prefix longest} { tcl::prefix longest {apa bska appa} {} } {} test string-28.11 {tcl::prefix longest} { tcl::prefix longest {{} bska appa} {} } {} test string-28.12 {tcl::prefix longest} { tcl::prefix longest {apa {} appa} {} } {} test string-28.13 {tcl::prefix longest} { # Test UTF8 handling tcl::prefix longest {ax\x90 bep ax\x91} a } ax test string-29.1 {tcl::prefix from another namespace} namespace { namespace eval abc { tcl::prefix longest {apa bepa cepa depa} cepa } } cepa testreport openocd-0.7.0/jimtcl/tests/procref.test0000644000175000001440000000157612134336723015064 00000000000000# Tests auto-upref with the "&name" syntax source [file dirname [info script]]/testing.tcl needs constraint jim proc a1 {&b c} { append b b append c c } proc a2 {&b {dummy 3} &c} { append b b append c c } proc a3 {&b(c)} { append b(c) b_c } # This is treated as a normal var "&b" proc a4 {{&b x}} { append &b B } set B 1 set C 1 test procref-1.1 {Basic test} { a1 B $C set B } {1b} test procref-1.2 {Basic test} { a1 B $C set B } {1bb} test procref-1.3 {Unset var} -body { a1 unsetB $C } -returnCodes error -result {can't read "unsetB": no such variable} test procref-1.4 {Left and right args are refs} { a2 B C list $B $C } {1bbb 1c} test procref-1.5 {Invalid arg} -body { a3 B } -returnCodes error -result {bad variable name "b(c)": upvar won't create a scalar variable that looks like an array element} test procref-1.6 {Default arg as ref} { a4 } xB testreport openocd-0.7.0/jimtcl/tests/utftcl.test0000644000175000001440000001647012134336723014724 00000000000000# This file contains a collection of tests for tclUtf.c # Sourcing this file into Tcl runs the tests and generates output for # errors. No output means no errors were found. # # Copyright (c) 1997 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # RCS: @(#) $Id: utf.test,v 1.14 2007/05/02 01:37:28 kennykb Exp $ source [file dirname [info script]]/testing.tcl needs constraint utf8 catch {unset x} test utf-1.1 {Tcl_UniCharToUtf: 1 byte sequences} { set x \x01 } [bytestring "\x01"] test utf-1.2 {Tcl_UniCharToUtf: 2 byte sequences} { set x "\u80" } [bytestring "\xc2\x80"] test utf-1.3 {Tcl_UniCharToUtf: 2 byte sequences} { set x "\ue0" } [bytestring "\xc3\xa0"] test utf-1.4 {Tcl_UniCharToUtf: 3 byte sequences} { set x "\u4e4e" } [bytestring "\xe4\xb9\x8e"] test utf-1.5 {Tcl_UniCharToUtf: negative Tcl_UniChar} { string length [format %c -1] } 1 test utf-2.1 {Tcl_UtfToUniChar: low ascii} { string length "abc" } {3} test utf-2.2 {Tcl_UtfToUniChar: naked trail bytes} { string length [bytestring "\x82\x83\x84"] } {3} test utf-2.3 {Tcl_UtfToUniChar: lead (2-byte) followed by non-trail} { string length [bytestring "\xC2"] } {1} test utf-2.4 {Tcl_UtfToUniChar: lead (2-byte) followed by trail} { string length [bytestring "\xC2\xa2"] } {1} test utf-2.5 {Tcl_UtfToUniChar: lead (3-byte) followed by non-trail} { string length [bytestring "\xE2"] } {1} test utf-2.6 {Tcl_UtfToUniChar: lead (3-byte) followed by 1 trail} { string length [bytestring "\xE2\xA2"] } {2} test utf-2.7 {Tcl_UtfToUniChar: lead (3-byte) followed by 2 trail} { string length [bytestring "\xE4\xb9\x8e"] } {1} # Note that Tcl may or may not support utf-8 sequences >= 4 bytes test utf-2.9 {Tcl_UtfToUniChar: 4-byte UTF sequence} { string length [bytestring "\xF4\xA2\xA2\xA2"] } {1} test utf-3.1 {Tcl_UtfCharComplete} { } {} proc testnumutfchars {a {n ""}} { string length $a } test utf-4.1 {Tcl_NumUtfChars: zero length} { testnumutfchars "" } {0} test utf-4.2 {Tcl_NumUtfChars: length 1} { testnumutfchars [bytestring "\xC2\xA2"] } {1} test utf-4.3 {Tcl_NumUtfChars: long string} { testnumutfchars [bytestring "abc\xC2\xA2\xe4\xb9\x8e\uA2\u4e4e"] } {7} test utf-4.4 {Tcl_NumUtfChars: #u0000} { testnumutfchars [bytestring "\xC0\x80"] } {1} test utf-4.5 {Tcl_NumUtfChars: zero length, calc len} { testnumutfchars "" 1 } {0} test utf-4.6 {Tcl_NumUtfChars: length 1, calc len} { testnumutfchars [bytestring "\xC2\xA2"] 1 } {1} test utf-4.7 {Tcl_NumUtfChars: long string, calc len} { testnumutfchars [bytestring "abc\xC2\xA2\xe4\xb9\x8e\uA2\u4e4e"] 1 } {7} test utf-4.8 {Tcl_NumUtfChars: #u0000, calc len} { testnumutfchars [bytestring "\xC0\x80"] 1 } {1} test utf-5.1 {Tcl_UtfFindFirsts} { } {} test utf-6.1 {Tcl_UtfNext} { } {} test utf-7.1 {Tcl_UtfPrev} { } {} test utf-8.1 {Tcl_UniCharAtIndex: index = 0} { string index abcd 0 } {a} test utf-8.2 {Tcl_UniCharAtIndex: index = 0} { string index \u4e4e\u25a 0 } "\u4e4e" test utf-8.3 {Tcl_UniCharAtIndex: index > 0} { string index abcd 2 } {c} test utf-8.4 {Tcl_UniCharAtIndex: index > 0} { string index \u4e4e\u25a\uff\u543 2 } "\uff" test utf-9.1 {Tcl_UtfAtIndex: index = 0} { string range abcd 0 2 } {abc} test utf-9.2 {Tcl_UtfAtIndex: index > 0} { string range \u4e4e\u25a\xff\u543klmnop 1 5 } "\u25a\xff\u543kl" test utf-10.1 {Tcl_UtfBackslash: dst == NULL} { set x \n } { } test utf-10.2 {Tcl_UtfBackslash: \u subst} { set x \ua2 } [bytestring "\xc2\xa2"] test utf-10.3 {Tcl_UtfBackslash: longer \u subst} { set x \u4e21 } [bytestring "\xe4\xb8\xa1"] test utf-10.4 {Tcl_UtfBackslash: stops at first non-hex} { set x \u4e2k } "[bytestring \xd3\xa2]k" test utf-10.5 {Tcl_UtfBackslash: stops after 4 hex chars} { set x \u4e216 } "[bytestring \xe4\xb8\xa1]6" proc bsCheck {char num} { global errNum test utf-10.$errNum {backslash substitution} { scan $char %c value set value } $num incr errNum } set errNum 6 bsCheck \b 8 bsCheck \e 101 bsCheck \f 12 bsCheck \n 10 bsCheck \r 13 bsCheck \t 9 bsCheck \v 11 bsCheck \{ 123 bsCheck \} 125 bsCheck \[ 91 bsCheck \] 93 bsCheck \$ 36 bsCheck \ 32 bsCheck \; 59 bsCheck \\ 92 bsCheck \Ca 67 bsCheck \Ma 77 bsCheck \CMa 67 # prior to 8.3, this returned 8, as \8 as accepted as an # octal value - but it isn't! [Bug: 3975] bsCheck \8a 56 bsCheck \14 12 bsCheck \141 97 bsCheck b\0 98 bsCheck \x 120 bsCheck \ua 10 bsCheck \uA 10 bsCheck \u41 65 bsCheck \u 117 bsCheck \uk 117 bsCheck \u41 65 bsCheck \ua 10 bsCheck \uA 10 bsCheck \340 224 bsCheck \ua1 161 bsCheck \u4e21 20001 test utf-11.1 {Tcl_UtfToUpper} { string toupper {} } {} test utf-11.2 {Tcl_UtfToUpper} { string toupper abc } ABC test utf-11.3 {Tcl_UtfToUpper} { string toupper \u00e3ab } \u00c3AB test utf-11.4 {Tcl_UtfToUpper} { string toupper \u01e3ab } \u01e2AB test utf-12.1 {Tcl_UtfToLower} { string tolower {} } {} test utf-12.2 {Tcl_UtfToLower} { string tolower ABC } abc test utf-12.3 {Tcl_UtfToLower} { string tolower \u00c3AB } \u00e3ab test utf-12.4 {Tcl_UtfToLower} { string tolower \u01e2AB } \u01e3ab test utf-14.1 {Tcl_UtfNcasecmp} { string compare -nocase a b } -1 test utf-14.2 {Tcl_UtfNcasecmp} { string compare -nocase b a } 1 test utf-14.3 {Tcl_UtfNcasecmp} { string compare -nocase B a } 1 test utf-14.4 {Tcl_UtfNcasecmp} { string compare -nocase aBcB abca } 1 test utf-15.1 {Tcl_UniCharToUpper, negative delta} { string toupper aA } AA test utf-15.2 {Tcl_UniCharToUpper, positive delta} { string toupper \u0178\u00ff } \u0178\u0178 test utf-15.3 {Tcl_UniCharToUpper, no delta} { string toupper ! } ! test utf-16.1 {Tcl_UniCharToLower, negative delta} { string tolower aA } aa test utf-16.2 {Tcl_UniCharToLower, positive delta} { string tolower \u0178\u00ff } \u00ff\u00ff test utf-17.1 {Tcl_UniCharToLower, no delta} { string tolower ! } ! #test utf-21.1 {TclUniCharIsAlnum} { # # this returns 1 with Unicode 3 compliance # string is alnum \u1040\u021f #} {1} #test utf-21.2 {unicode alnum char in regc_locale.c} { # # this returns 1 with Unicode 3 compliance # list [regexp {^[[:alnum:]]+$} \u1040\u021f] [regexp {^\w+$} \u1040\u021f] #} {1 1} #test utf-22.1 {TclUniCharIsWordChar} { # string wordend "xyz123_bar fg" 0 #} 10 #test utf-22.2 {TclUniCharIsWordChar} { # string wordend "x\u5080z123_bar\u203c fg" 0 #} 10 #test utf-23.1 {TclUniCharIsAlpha} { # # this returns 1 with Unicode 3 compliance # string is alpha \u021f #} {1} #test utf-23.2 {unicode alpha char in regc_locale.c} { # # this returns 1 with Unicode 3 compliance # regexp {^[[:alpha:]]+$} \u021f #} {1} # #test utf-24.1 {TclUniCharIsDigit} { # # this returns 1 with Unicode 3 compliance # string is digit \u1040 #} {1} #test utf-24.2 {unicode digit char in regc_locale.c} { # # this returns 1 with Unicode 3 compliance # list [regexp {^[[:digit:]]+$} \u1040] [regexp {^\d+$} \u1040] #} {1 1} # #test utf-24.3 {TclUniCharIsSpace} { # # this returns 1 with Unicode 3 compliance # string is space \u1680 #} {1} #test utf-24.4 {unicode space char in regc_locale.c} { # # this returns 1 with Unicode 3 compliance # list [regexp {^[[:space:]]+$} \u1680] [regexp {^\s+$} \u1680] #} {1 1} testreport openocd-0.7.0/jimtcl/tests/misc.test0000644000175000001440000002424612134336723014356 00000000000000source [file dirname [info script]]/testing.tcl needs constraint jim needs cmd gets tclcompat needs cmd array catch {unset a b} test regr-1.1 "Double dereference arrays" { array set a {one ONE two TWO three THREE} array set b {ONE 1 TWO 2 THREE 3} set chan two set b($a($chan)) } {2} # Will assert on exit if the bug exists test regr-1.2 "Reference count shared literals" { proc a {} { while {1} {break} } a rename a "" return 1 } {1} test regr-1.3 "Invalid for expression" jim { # Crashes with invalid expression catch { for {set i 0} {$i < n} {incr i} { set a(b) $i set a(c) $i break } } } 1 test regr-1.4 "format double percent" { format (%d%%) 12 } {(12%)} test regr-1.5 "lassign with empty list" { unset -nocomplain a b c lassign {} a b c info exists c } {1} test io-1.1 "Read last line with no newline" { set lines 0 set f [open $testdir/testio.in] while {[gets $f buf] >= 0} { incr lines } close $f list $lines } {2} set g1 1 set g2 2 array set g3 {4 5 6 7} proc test_unset {} { test unset-1.1 "Simple var" { set g4 4 list [catch {unset g4; info exists g4} msg] $msg } {0 0} test unset-1.2 "Simple var" { list [catch {unset g4; info exists g4} msg] $msg } {1 {can't unset "g4": no such variable}} test unset-1.3 "Simple var" { list [catch {unset g2; info exists g2} msg] $msg } {1 {can't unset "g2": no such variable}} test unset-1.4 "Global via global" { global g1 list [catch {unset g1; info exists g1} msg] $msg } {0 0} test unset-1.5 "Global error" { list [catch {unset ::g2; info exists ::g2} msg] $msg } {0 0} test unset-1.6 "Global array" { list [catch {unset ::g3; info exists ::g3} msg] $msg } {0 0} test unset-1.7 "Simple var -nocomplain" { list [catch {unset -nocomplain g2; info exists g2} msg] $msg } {0 0} test unset-1.8 "Simple var --" { list [catch {unset -- g2; info exists g2} msg] $msg } {1 {can't unset "g2": no such variable}} test unset-1.9 "Simple var -nocomplain --" { set g2 1 list [catch {unset -nocomplain -- g2; info exists g2} msg] $msg } {0 0} test unset-1.10 "Var named -nocomplain with --" { set -nocomplain 1 list [catch {unset -- -nocomplain; info exists -nocomplain} msg] $msg } {0 0} test unset-1.11 "Unset no args" { list [catch {unset} msg] $msg } {0 {}} } test_unset test lrepeat-1.1 "Basic tests" { lrepeat 1 a } {a} test lrepeat-1.2 "Basic tests" { lrepeat 1 a b } {a b} test lrepeat-1.3 "Basic tests" { lrepeat 2 a b } {a b a b} test lrepeat-1.4 "Basic tests" { lrepeat 2 a } {a a} test lrepeat-1.5 "Errors" { catch {lrepeat} } {1} test lrepeat-1.6 "Errors" { lrepeat 1 } {} test lrepeat-1.7 "Errors" { lrepeat 0 a b } {} test lrepeat-1.8 "Errors" { catch {lrepeat -10 a} } {1} test lindex-1.1 "Integer" { lindex {a b c} 0 } a test lindex-1.2 "Integer" { lindex {a b c} 2 } c test lindex-1.3 "Integer" { lindex {a b c} -1 } {} test lindex-1.4 "Integer" { lindex {a b c} 4 } {} test lindex-1.5 "end" { lindex {a b c} end } c test lindex-1.6 "end" { lindex {a b c} end-1 } b test lindex-1.7 "end" { lindex {a b c} end-4 } {} test lindex-1.8 "end + " { lindex {a b c} end+1 } {} test lindex-1.9 "end + " { lindex {a b c} end+-1 } b test lindex-1.10 "end - errors" { catch {lindex {a b c} end-} } 1 test lindex-1.11 "end - errors" { catch {lindex {a b c} end-blah} } 1 test lindex-1.12 "int+int, int-int" { lindex {a b c} 0+4 } {} test lindex-1.13 "int+int, int-int" { lindex {a b c} 3-1 } c test lindex-1.14 "int+int, int-int" { lindex {a b c} 1--1 } c test lindex-1.15 "int+int, int-int" { set l {a b c} lindex $l [lsearch $l b]-1 } a test lindex-1.16 "int+int, int-int" { lindex {a b c} 0+1 } b test lindex-1.17 "int+int - errors" { catch {lindex {a b c} 5-blah} } 1 test lindex-1.18 "int+int - errors" { catch {lindex {a b c} blah-2} } 1 test lindex-1.19 "int+int - errors" { catch {lindex {a b c} 5+blah} } 1 test lindex-1.20 "unary plus" { lindex {a b c} +2 } c test incr-1.1 "incr unset" { unset -nocomplain a incr a set a } 1 test incr-1.2 "incr, incr unset" { incr a } 2 test incr-1.3 "incr unset array element" { unset -nocomplain a incr a(2) set a(2) } 1 test incr-1.4 "incr array element - shimmering" { set b "$a(2)-test" incr a(2) } 2 test catch-1.1 "catch ok" { list [catch {set abc 2} result] $result } {0 2} test catch-1.2 "catch error" { list [catch {error 3} result] $result } {1 3} test catch-1.3 "catch break" { list [catch {break} result] $result } {3 {}} test catch-1.4 "catch -nobreak" { set result {} foreach x {a b c} { lappend result $x # This acts just like break since it won't be caught by catch catch -nobreak {break} tmp } set result } {a} test catch-1.5 "catch -no3" { set result {} foreach x {a b c} { lappend result $x # Same as above, but specify as an integer catch -no3 {break} tmp } set result } {a} test catch-1.6 "catch break" { set result {} foreach x {a b c} { lappend result $x # This does nothing since the break is caught catch {break} tmp } set result } {a b c} test catch-1.7 "catch exit" { # Normally exit would not be caught dict get [info returncodes] [catch -exit {exit 5} result] } {exit} test catch-1.8 "catch error has -errorinfo" { set rc [catch {set undefined} msg opts] list $rc [info exists opts(-errorinfo)] } {1 1} test catch-1.9 "catch no error has no -errorinfo" { set rc [catch {set x 1} msg opts] list $rc [info exists opts(-errorinfo)] } {0 0} test return-1.1 "return can rethrow an error" { proc a {} { error "from a" } proc b {} { catch {a} msg opts; return {*}$opts $msg } set rc [catch {b} msg opts] list $rc $msg [llength $opts(-errorinfo)] } {1 {from a} 6} test return-1.2 "error can rethrow an error" { proc a {} { error "from a" } proc b {} { catch {a} msg; error $msg [info stacktrace] } set rc [catch {b} msg opts] list $rc $msg [llength $opts(-errorinfo)] } {1 {from a} 9} test return-1.3 "return can rethrow no error" { proc a {} { return "from a" } proc b {} { catch {a} msg opts; return {*}$opts $msg } set rc [catch {b} msg opts] #list $rc $msg [llength $opts(-errorinfo)] list $rc $msg [info exists opts(-errorinfo)] } {0 {from a} 0} test stringreverse-1.1 "Containing nulls" { string reverse abc\0def } "fed\0cba" test split-1.1 "Split with leading null" { split "\0abc\0def\0" \0 } {{} abc def {}} test parsevar-1.1 "Variables should include double colons" { set ::a::b 2 set x $::a::b unset ::a::b set x } 2 test sharing-1.1 "Problems with ref sharing in arrays: lappend" { set a {a 1 c 2} set b $a lappend b(c) 3 set a(c) } 2 test sharing-1.2 "Problems with ref sharing in arrays: append" { set a {a 1 c 2} set b $a append b(c) 3 set a(c) } 2 test sharing-1.3 "Problems with ref sharing in arrays: incr" { set a {a 1 c 2} set b $a incr b(c) set a(c) } 2 test sharing-1.4 "Problems with ref sharing in arrays: lset" { set a {a 1 c {2 3}} set b $a lset b(c) 1 x set a(c) } {2 3} test jimexpr-1.1 "integer ** operator" { expr {2 ** 3} } 8 test jimexpr-1.2 "integer ** operator" { expr {0 ** 3} } 0 test jimexpr-1.3 "integer ** operator" { expr {2 ** 0} } 1 test jimexpr-1.4 "integer ** operator" { expr {-2 ** 1} } -2 test jimexpr-1.5 "integer ** operator" { expr {3 ** -2} } 0 test jimexpr-1.6 "+ command" { + 1 } 1 test jimexpr-1.7 "+ command" { + 2 3.5 } 5.5 test jimexpr-1.8 "+ command" { + 2 3 4 -6 } 3 test jimexpr-1.9 "* command" { * 4 } 4 test jimexpr-1.10 "* command" { * 4 2 } 8 test jimexpr-1.11 "* command" { * 4 2 -0.5 } -4.0 test jimexpr-1.12 "/ command" { / 2 } 0.5 test jimexpr-1.12 "/ command" { / 0.5 } 2.0 test jimexpr-1.13 "/ command" { / 12 3 } 4 test jimexpr-1.14 "/ command" { / 12 3 2.0 } 2.0 test jimexpr-1.15 "- command" { - 6 } -6 test jimexpr-1.15 "- command" { - 6.5 } -6.5 test jimexpr-1.16 "- command" { - 6 3 } 3 test jimexpr-1.17 "- command" { - 6 3 1.5 } 1.5 test jimexpr-1.17 "- command" { - 6.5 3 } 3.5 test jimexpr-2.1 "errors in math commands" { list [catch /] [catch {/ x}] [catch -] [catch {- blah blah}] [catch {- 2.0 blah}] [catch {+ x y}] [catch {* x}] } {1 1 1 1 1 1 1} test jimexpr-2.2 "not var optimisation" { set x [expr 1] set y [expr 0] set z [expr 2.0] list [expr {!$x}] [expr {!$y}] [expr {!$z}] } {0 1 0} test jimexpr-2.3 "expr access unset var" { unset -nocomplain a catch {expr {3 * $a}} } 1 test jimexpr-2.4 "expr double as bool" { set x 2 if {1.0} { set x 3 } } 3 # May be supported if support compiled in test jimexpr-2.5 "double ** operator" { catch {expr {2.0 ** 3}} result expr {$result in {unsupported 8.0}} } 1 # This one is for test coverage of an unusual case test jimobj-1.1 "duplicate obj with no dupIntRepProc" { proc "x x" {} { return 2 } set a "x x" # force it to be a command object set b [$a] # A second reference set c $a # Now force it to be duplicated lset a 1 x # force the duplicate object it to be a command object again set b [$a] # And get the string rep set x "y $a" } "y x x" test jimobj-1.2 "cooerced double to int" { set x 3 # cooerce to a double expr {4.5 + $x} # Now get the int rep incr x } 4 test jimobj-1.3 "cooerced double to double" { set x 3 # cooerce to a double expr {4.5 + $x} # Now use as a double expr {1.5 + $x} } 4.5 test jimobj-1.4 "incr dict sugar" { unset -nocomplain a set a(3) 3 incr a(3) list $a(3) $a } {4 {3 4}} test jim-badvar-1.1 "invalid variable name" { set x b\0c catch {set $x 5} } 1 test jim-badvar-1.2 "incr invalid variable name" { set x b\0c catch {incr $x} } 1 test lset-1.1 "lset with bad var" { catch {lset badvar 1 x} } 1 test dict-1.1 "dict to string" { set a [dict create abc \\ def \"] set x x$a } "xabc \\\\ def {\"}" test channels-1.1 {info channels} { lsort [info channels] } {stderr stdin stdout} test lmap-1.1 {lmap} { lmap p {1 2 3} {incr p} } {2 3 4} test exprerr-1.1 {Error message with bad expr} { catch {expr {5 ||}} msg set msg } {Expression has bad operands to ||} test eval-list-1.1 {Lost string rep with list} { set x {set y 1; incr y} # Convert to list rep internally lindex $x 4 # But make sure we don't lost the original string rep list [catch $x] $y } {0 2} test info-statics-1.1 {info statics commands} { set x 1 proc a {} {x {y 2}} {} info statics a } {x 1 y 2} testreport openocd-0.7.0/jimtcl/tests/expr-base.test0000644000175000001440000000110312134336723015274 00000000000000source [file dirname [info script]]/testing.tcl # Test number detection set good_testcases { 0 0 1 1 8 8 00 0 07 7 08 8 0x5 5 0x0 0 0x00 0 -0x5 -5 0b111 7 -0b111 -7 -0B101 -5 0o7 7 } set i 0 foreach {str exp} $good_testcases { test expr-base-1.[incr i] "expr conversion" [list expr [list $str]] $exp } set bad_testcases { {0x + 1} x 0xx5 0x-5 {0x 5} {0o8 + 1} } set i 0 foreach str $bad_testcases { test expr-base-2.[incr i] "expr conversion failure" -returnCodes error -body [list expr $str] -match glob -result "*" } testreport openocd-0.7.0/jimtcl/tests/tailcall.test0000644000175000001440000000216212134336723015201 00000000000000source [file dirname [info script]]/testing.tcl needs cmd tailcall needs cmd try tclcompat test tailcall-1.1 {Basic tailcall} { # Demo -- a tail-recursive factorial function proc fac {x {val 1}} { if {$x <= 2} { expr {$x * $val} } else { tailcall fac [expr {$x -1}] [expr {$x * $val}] } } fac 10 } {3628800} test tailcall-1.2 {Tailcall in try} { set x 0 proc a {} { upvar x x; incr x } proc b {} { upvar x x; incr x 4; try { tailcall a } finally { incr x 8 }} b set x } {13} test tailcall-1.3 {Tailcall does return} { set x 0 proc a {} { upvar x x; incr x } proc b {} { upvar x x; incr x 4; tailcall a; incr x 8} b set x } {5} test tailcall-1.5 {interaction of uplevel and tailcall} { proc a {cmd} { tailcall $cmd } proc b {} { lappend result [uplevel 1 a c] lappend result [uplevel 1 a c] } proc c {} { return c } a b } {c c} test tailcall-1.6 {tailcall pass through return} { proc a {script} { # return from $script should pass through back to the caller tailcall foreach i {1 2 3} $script } proc b {} { a {return ok} # Should not get here return bad } b } {ok} testreport openocd-0.7.0/jimtcl/tests/list.test0000644000175000001440000000765012134336723014376 00000000000000# Commands covered: list # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # RCS: @(#) $Id: list.test,v 1.5 2000/04/10 17:19:01 ericm Exp $ source [file dirname [info script]]/testing.tcl # First, a bunch of individual tests test list-1.1 {basic tests} {list a b c} {a b c} test list-1.2 {basic tests} {list {a b} c} {{a b} c} test list-1.3 {basic tests} {list \{a b c} {\{a b c} test list-1.4 {basic tests} "list a{}} b{} c}" "a\\{\\}\\} b{} c\\}" test list-1.5 {basic tests} {list a\[ b\] } "{a\[} b\\]" test list-1.6 {basic tests} {list c\ d\t } "{c } {d\t}" test list-1.7 {basic tests} {list e\n f\$ } "{e\n} {f\$}" test list-1.8 {basic tests} {list g\; h\\} {{g;} h\\} test list-1.9 {basic tests} "list a\\\[} b\\\]} " "a\\\[\\\} b\\\]\\\}" test list-1.10 {basic tests} "list c\\\} d\\t} " "c\\} d\\t\\}" test list-1.11 {basic tests} "list e\\n} f\\$} " "e\\n\\} f\\$\\}" test list-1.12 {basic tests} "list g\\;} h\\\\} " "g\\;\\} {h\\}}" test list-1.13 {basic tests} {list a {{}} b} {a {{}} b} test list-1.14 {basic tests} {list a b xy\\} "a b xy\\\\" test list-1.15 {basic tests} "list a b\} e\\" "a b\\} e\\\\" test list-1.16 {basic tests} "list a b\}\\\$ e\\\$\\" "a b\\}\\\$ e\\\$\\\\" test list-1.17 {basic tests} {list a\f \{\f} "{a\f} \\\{\\f" test list-1.18 {basic tests} {list a\r \{\r} "{a\r} \\\{\\r" test list-1.19 {basic tests} {list a\v \{\v} "{a\v} \\\{\\v" test list-1.20 {basic tests} {list \"\}\{} "\\\"\\}\\{" test list-1.21 {basic tests} {list a b c\\\nd} "a b c\\\\\\nd" test list-1.22 {basic tests} {list "{ab}\\"} \\{ab\\}\\\\ test list-1.23 {basic tests} {list \{} "\\{" test list-1.24 {basic tests} {list} {} test list-1.25 {basic tests} {list #} {{#}} test list-1.26 {basic tests} {list #abc} {{#abc}} test list-1.27 {basic tests} {list def #abc} {def #abc} # For the next round of tests create a list and then pick it apart # with "index" to make sure that we get back exactly what went in. test list-2.1 {placeholder} { } {} set num 1 proc lcheck {a b c} { global num d set d [list $a $b $c] ; test list-2.$num {what goes in must come out} {lindex $d 0} $a set num [expr $num+1] ; test list-2.$num {what goes in must come out} {lindex $d 1} $b set num [expr $num+1] ; test list-2.$num {what goes in must come out} {lindex $d 2} $c set num [expr $num+1] } lcheck a b c lcheck "a b" c\td e\nf lcheck {{a b}} {} { } lcheck \$ \$ab ab\$ lcheck \; \;ab ab\; lcheck \[ \[ab ab\[ lcheck \\ \\ab ab\\ lcheck {"} {"ab} {ab"} lcheck {a b} { ab} {ab } lcheck a{ a{b \{ab lcheck a} a}b }ab lcheck a\\} {a \}b} {a \{c} lcheck xyz \\ 1\\\n2 lcheck "{ab}\\" "{ab}xy" abc concat {} # Check that tclListObj.c's SetListFromAny handles possible overlarge # string rep lengths in the source object. proc slowsort list { set result {} set last [expr [llength $list] - 1] while {$last > 0} { set minIndex [expr [llength $list] - 1] set min [lindex $list $last] set i [expr $minIndex-1] while {$i >= 0} { if {[string compare [lindex $list $i] $min] < 0} { set minIndex $i set min [lindex $list $i] } set i [expr $i-1] } set result [concat $result [list $min]] if {$minIndex == 0} { set list [lrange $list 1 end] } else { set list [concat [lrange $list 0 [expr $minIndex-1]] \ [lrange $list [expr $minIndex+1] end]] } set last [expr $last-1] } return [concat $result $list] } test list-3.1 {SetListFromAny and lrange/concat results} { slowsort {fred julie alex carol bill annie} } {alex annie bill carol fred julie} testreport openocd-0.7.0/jimtcl/tests/tree.test0000644000175000001440000000454112134336723014356 00000000000000source [file dirname [info script]]/testing.tcl needs cmd tree needs cmd ref proc dputs {msg} { #puts $msg } test tree-1.1 "Create tree" { set pt [tree] return 1 } {1} test tree-1.2 "Root node depth" { $pt depth root } {0} test tree-1.3 "Access invalid node" { list [catch { $pt depth bogus } msg] $msg } {1 {key "bogus" not known in dictionary}} test tree-1.4 "Set key/value" { $pt set root key value $pt set root type root $pt set root name rootnode $pt set root values {} $pt get root key } {value} test tree-1.5 "Add child node" { set n [$pt insert root] $pt set $n childkey childvalue $pt set $n type level1type $pt set $n name childnode1 $pt set $n values {label testlabel} $pt get $n childkey } {childvalue} test tree-1.6 "Add child, child node" { set nn [$pt insert $n] $pt set $nn childkey2 childvalue2 $pt set $nn type level2type $pt set $nn name childnode2 $pt set $nn values {label testlabel storage none} $pt get $nn childkey2 } {childvalue2} test tree-1.7 "Key exists true" { $pt keyexists $nn childkey2 } {1} test tree-1.7 "Key exists false" { $pt keyexists $n boguskey } {0} test tree-1.8 "lappend" { $pt lappend $n newkey first $pt lappend $n newkey second $pt lappend $n newkey third $pt lappend $n newkey last } {first second third last} test tree-2.0 "Add more nodes" { set c [$pt insert root] $pt set $c name root.c2 set c [$pt insert root] $pt set $c name root.c3 set c [$pt insert $n] $pt set $c name n.c4 set c [$pt insert $n] $pt set $c name n.c5 set c [$pt insert $c] $pt set $c name n.c5.c6 return 1 } {1} test tree-2.1 "walk dfs" { set result {} dputs "" $pt walk root dfs {action n} { set indent [string repeat " " [$pt depth $n]] if {$action == "enter"} { lappend result [$pt get $n name] dputs "$indent[$pt get $n name]" } } dputs "" set result } {rootnode childnode1 childnode2 n.c4 n.c5 n.c5.c6 root.c2 root.c3} test tree-2.2 "walk dfs exit" { set result {} $pt walk root dfs {action n} { if {$action == "exit"} { lappend result [$pt get $n name] } } set result } {childnode2 n.c4 n.c5.c6 n.c5 childnode1 root.c2 root.c3 rootnode} test tree-2.3 "walk bfs" { set result {} $pt walk root bfs {action n} { if {$action == "enter"} { lappend result [$pt get $n name] } } set result } {rootnode childnode1 root.c2 root.c3 childnode2 n.c4 n.c5 n.c5.c6} $pt destroy testreport openocd-0.7.0/jimtcl/tests/lsort.test0000644000175000001440000001730412134336723014563 00000000000000# This file contains a collection of tests for the procedures in the # file tclCmdIL.c. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1997 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # RCS: @(#) $Id: lsort.test,v 1.12.2.2 2001/10/08 15:50:24 dkf Exp $ source [file dirname [info script]]/testing.tcl test lsort-1.1 {Tcl_LsortObjCmd procedure} jim { list [catch {lsort} msg] $msg } {1 {wrong # args: should be "lsort ?options? list"}} test lsort-1.2 {Tcl_LsortObjCmd procedure} jim { list [catch {lsort -foo {1 3 2 5}} msg] $msg } {1 {bad option "-foo": must be -ascii, -command, -decreasing, -increasing, -index, -integer, or -nocase}} test lsort-1.3 {Tcl_LsortObjCmd procedure, default options} { lsort {d e c b a \{ d35 d300} } {a b c d d300 d35 e \{} test lsort-1.4 {Tcl_LsortObjCmd procedure, -ascii option} { lsort -integer -ascii {d e c b a d35 d300} } {a b c d d300 d35 e} test lsort-1.5 {Tcl_LsortObjCmd procedure, -command option} { list [catch {lsort -command {1 3 2 5}} msg] $msg } {1 {"-command" option must be followed by comparison command}} test lsort-1.6 {Tcl_LsortObjCmd procedure, -command option} { proc cmp {a b} { set rc [expr {[string match x* $b] - [string match x* $a]}] if {$rc == 0} { set rc [string compare $a $b] } return $rc } lsort -command cmp {x1 abc x2 def x3 x4} } {x1 x2 x3 x4 abc def} test lsort-1.7 {Tcl_LsortObjCmd procedure, -decreasing option} { lsort -decreasing {d e c b a d35 d300} } {e d35 d300 d c b a} test lsort-1.10 {Tcl_LsortObjCmd procedure, -increasing option} { lsort -decreasing -increasing {d e c b a d35 d300} } {a b c d d300 d35 e} test lsort-1.11 {Tcl_LsortObjCmd procedure, -index option} { list [catch {lsort -index {1 3 2 5}} msg] $msg } {1 {"-index" option must be followed by list index}} test lsort-1.12 {Tcl_LsortObjCmd procedure, -index option} { list [catch {lsort -index foo {1 3 2 5}} msg] $msg } {1 {bad index "foo": must be integer?[+-]integer? or end?[+-]integer?}} test lsort-1.13 {Tcl_LsortObjCmd procedure, -index option} { lsort -index end -integer {{2 25} {10 20 50 100} {3 16 42} 1} } {1 {2 25} {3 16 42} {10 20 50 100}} test lsort-1.14 {Tcl_LsortObjCmd procedure, -index option} { lsort -index 1 -integer {{1 25 100} {3 16 42} {10 20 50}} } {{3 16 42} {10 20 50} {1 25 100}} test lsort-1.15 {Tcl_LsortObjCmd procedure, -integer option} { lsort -integer {24 6 300 18} } {6 18 24 300} test lsort-1.16 {Tcl_LsortObjCmd procedure, -integer option} { list [catch {lsort -integer {1 3 2.4}} msg] $msg } {1 {expected integer but got "2.4"}} test lsort-1.19 {Tcl_LsortObjCmd procedure, empty list} { lsort {} } {} test lsort-1.24 {Tcl_LsortObjCmd procedure, order of -index and -command} { catch {rename 1 ""} proc testcmp {a b} {return [string compare $a $b]} set l [list [list a b] [list c d]] set result [list [catch {lsort -command testcmp -index 1 $l} msg] $msg] rename testcmp "" set result } [list 0 [list [list a b] [list c d]]] test lsort-1.25 {Tcl_LsortObjCmd procedure, order of -index and -command} { catch {rename 1 ""} proc testcmp {a b} {return [string compare $a $b]} set l [list [list a b] [list c d]] set result [list [catch {lsort -index 1 -command testcmp $l} msg] $msg] rename testcmp "" set result } [list 0 [list [list a b] [list c d]]] # Note that the required order only exists in the end-1'th element; # indexing using the end element or any fixed offset from the start # will not work... test lsort-1.26 {Tcl_LsortObjCmd procedure, offset indexing from end} { lsort -index end-1 {{a 1 e i} {b 2 3 f g} {c 4 5 6 d h}} } {{c 4 5 6 d h} {a 1 e i} {b 2 3 f g}} # Can't think of any good tests for the MergeSort and MergeLists # procedures, except a bunch of random lists to sort. test lsort-2.1 {MergeSort and MergeLists procedures} { set result {} set r 1435753299 proc rand {} { global r set r [expr {(16807 * $r) % (0x7fffffff)}] } for {set i 0} {$i < 150} {incr i} { set x {} for {set j 0} {$j < $i} {incr j} { lappend x [expr {[rand] & 0xfff}] } set y [lsort -integer $x] set old -1 foreach el $y { if {$el < $old} { append result "list {$x} sorted to {$y}, element $el out of order\n" break } set old $el } } set result } {} test lsort-3.1 {SortCompare procedure, skip comparisons after error} { set x 0 proc cmp {a b} { global x incr x error "error #$x" } list [catch {lsort -integer -command cmp {48 6 28 190 16 2 3 6 1}} msg] \ $msg $x } {1 {error #1} 1} test lsort-3.3 {SortCompare procedure, -index option} jim { list [catch {lsort -integer -index 2 {{20 10} {15 30 40}}} msg] $msg } {1 {list index out of range}} test lsort-3.5 {SortCompare procedure, -index option} jim { list [catch {lsort -integer -index 2 {{20 10 13} {15}}} msg] $msg } {1 {list index out of range}} test lsort-3.6 {SortCompare procedure, -index option} { lsort -integer -index 2 {{1 15 30} {2 5 25} {3 25 20}} } {{3 25 20} {2 5 25} {1 15 30}} test lsort-3.7 {SortCompare procedure, -ascii option} { lsort -ascii {d e c b a d35 d300 100 20} } {100 20 a b c d d300 d35 e} test lsort-3.9 {SortCompare procedure, -integer option} { list [catch {lsort -integer {x 3}} msg] $msg } {1 {expected integer but got "x"}} test lsort-3.10 {SortCompare procedure, -integer option} { list [catch {lsort -integer {3 q}} msg] $msg } {1 {expected integer but got "q"}} test lsort-3.11 {SortCompare procedure, -integer option} { lsort -integer {35 21 0x20 30 023 100 8} } {8 21 023 30 0x20 35 100} test lsort-3.15 {SortCompare procedure, -command option} { proc cmp {a b} { error "comparison error" } list [catch {lsort -command cmp {48 6}} msg] $msg } {1 {comparison error}} test lsort-3.16 {SortCompare procedure, -command option, long command} { proc cmp {dummy a b} { string compare $a $b } lsort -command {cmp {this argument is very very long in order to make the dstring overflow its statically allocated space}} {{this first element is also long in order to help expand the dstring} {the second element, last but not least, is quite long also, in order to make absolutely sure that space is allocated dynamically for the dstring}} } {{the second element, last but not least, is quite long also, in order to make absolutely sure that space is allocated dynamically for the dstring} {this first element is also long in order to help expand the dstring}} test lsort-3.17 {SortCompare procedure, -command option, non-integer result} jim { proc cmp {a b} { return foow } list [catch {lsort -command cmp {48 6}} msg] $msg } {1 {expected integer but got "foow"}} test lsort-3.18 {SortCompare procedure, -command option} { proc cmp {a b} { expr {$b - $a} } lsort -command cmp {48 6 18 22 21 35 36} } {48 36 35 22 21 18 6} test lsort-3.19 {SortCompare procedure, -decreasing option} { lsort -decreasing -integer {35 21 0x20 30 023 100 8} } {100 35 0x20 30 023 21 8} test lsort-4.26 {DefaultCompare procedure, signed characters} utf8 { set l [lsort [list "abc\u80" "abc"]] set viewlist {} foreach s $l { set viewelem "" set len [string length $s] for {set i 0} {$i < $len} {incr i} { set c [string index $s $i] scan $c %c d if {$d > 0 && $d < 128} { append viewelem $c } else { append viewelem "\\[format %03o [expr {$d & 0xff}]]" } } lappend viewlist $viewelem } set viewlist } [list "abc" "abc\\200"] test lsort-5.1 "Sort case insensitive" { lsort -nocase {ba aB aa ce} } {aa aB ba ce} testreport openocd-0.7.0/jimtcl/tests/event.test0000644000175000001440000001166712134336723014547 00000000000000# This file contains a collection of tests for the procedures in the file # tclEvent.c, which includes the "update", and "vwait" Tcl # commands. Sourcing this file into Tcl runs the tests and generates # output for errors. No output means no errors were found. # # Copyright (c) 1995-1997 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. source [file dirname [info script]]/testing.tcl needs cmd after eventloop testConstraint socket [expr {[info commands socket] ne ""}] testConstraint exec [expr {[info commands exec] ne ""}] test event-5.1 {Tcl_BackgroundError, HandleBgErrors procedures} jim { catch {rename bgerror {}} proc bgerror msg { lappend ::x $msg } after idle {error "a simple error"} after idle {open non_existent} after idle {set errorInfo foobar; set errorCode xyzzy} set x {} update idletasks rename bgerror {} set x } {{a simple error} {non_existent: No such file or directory}} test event-7.1 {bgerror / regular} { set errRes {} proc bgerror {err} { global errRes; set errRes $err; } after 0 {error err1} vwait errRes; set errRes; } err1 test event-7.2 {bgerror / accumulation} { set errRes {} proc bgerror {err} { global errRes; lappend errRes $err; } after 0 {error err1} after 0 {error err2} after 0 {error err3} update set errRes; } {err1 err2 err3} test event-7.3 {bgerror / accumulation / break} { set errRes {} proc bgerror {err} { global errRes; lappend errRes $err; return -code break "skip!"; } after 0 {error err1} after 0 {error err2} after 0 {error err3} update set errRes; } err1 # end of bgerror tests catch {rename bgerror {}} test event-10.1 {Tcl_Exit procedure} exec { set cmd [list exec [info nameofexecutable] "< external conversion did not # occur before writing out the temp file. exec cat << "\uE9\uE0\uFC\uF1" } "\uE9\uE0\uFC\uF1" # I/O redirection: output to file. file delete gorp.file test exec-3.1 {redirecting output to file} { exec echo "Some simple words" > gorp.file exec cat gorp.file } "Some simple words" test exec-3.2 {redirecting output to file} { exec echo "More simple words" | >gorp.file cat | cat exec cat gorp.file } "More simple words" test exec-3.3 {redirecting output to file} { exec > gorp.file echo "Different simple words" | cat | cat exec cat gorp.file } "Different simple words" test exec-3.4 {redirecting output to file} { exec echo "Some simple words" >gorp.file exec cat gorp.file } "Some simple words" test exec-3.5 {redirecting output to file} { exec echo "First line" >gorp.file exec echo "Second line" >> gorp.file exec cat gorp.file } "First line\nSecond line" test exec-3.6 {redirecting output to file} { exec echo "First line" >gorp.file exec echo "Second line" >>gorp.file exec cat gorp.file } "First line\nSecond line" test exec-3.7 {redirecting output to file} { set f [open gorp.file w] puts $f "Line 1" flush $f exec echo "More text" >@ $f exec echo >@$f "Even more" puts $f "Line 3" close $f exec cat gorp.file } "Line 1\nMore text\nEven more\nLine 3" # I/O redirection: output and stderr to file. file delete gorp.file test exec-4.1 {redirecting output and stderr to file} { exec echo "test output" >& gorp.file exec cat gorp.file } "test output" test exec-4.2 {redirecting output and stderr to file} { list [exec sh -c "echo foo bar 1>&2" >&gorp.file] \ [exec cat gorp.file] } {{} {foo bar}} test exec-4.3 {redirecting output and stderr to file} { exec echo "first line" > gorp.file list [exec sh -c "echo foo bar 1>&2" >>&gorp.file] \ [exec cat gorp.file] } "{} {first line\nfoo bar}" test exec-4.4 {redirecting output and stderr to file} { set f [open gorp.file w] puts $f "Line 1" flush $f exec echo "More text" >&@ $f exec echo >&@$f "Even more" puts $f "Line 3" close $f exec cat gorp.file } "Line 1\nMore text\nEven more\nLine 3" test exec-4.5 {redirecting output and stderr to file} { set f [open gorp.file w] puts $f "Line 1" flush $f exec >&@ $f sh -c "echo foo bar 1>&2" exec >&@$f sh -c "echo xyzzy 1>&2" puts $f "Line 3" close $f exec cat gorp.file } "Line 1\nfoo bar\nxyzzy\nLine 3" # I/O redirection: input from file. exec echo "Just a few thoughts" > gorp.file test exec-5.1 {redirecting input from file} { exec cat < gorp.file } {Just a few thoughts} test exec-5.2 {redirecting input from file} { exec cat | cat < gorp.file } {Just a few thoughts} test exec-5.3 {redirecting input from file} { exec cat < gorp.file | cat } {Just a few thoughts} test exec-5.4 {redirecting input from file} { exec < gorp.file cat | cat } {Just a few thoughts} test exec-5.5 {redirecting input from file} { exec cat &2" |& cat } "foo bar" test exec-6.3 {redirecting stderr through a pipeline} { exec sh -c "echo foo bar 1>&2" \ |& cat |& cat } "foo bar" # I/O redirection: combinations. file delete gorp.file2 test exec-7.1 {multiple I/O redirections} { exec << "command input" > gorp.file2 cat < gorp.file exec cat gorp.file2 } {Just a few thoughts} test exec-7.2 {multiple I/O redirections} { exec < gorp.file << "command input" cat } {command input} # Long input to command and output from command. set a "0123456789 xxxxxxxxx abcdefghi ABCDEFGHIJK\n" set a [concat $a $a $a $a] set a [concat $a $a $a $a] set a [concat $a $a $a $a] set a [concat $a $a $a $a] test exec-8.1 {long input and output} { exec cat << $a } $a # More than 20 arguments to exec. test exec-8.1 {long input and output} { exec echo 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 } {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23} # Commands that return errors. test exec-9.1 {commands returning errors} { catch {exec gorp456} } {1} test exec-9.2 {commands returning errors} { catch {exec echo foo | foo123} msg } {1} test exec-9.3 {commands returning errors} { list [catch {exec {*}$sleepx 0.1 | false | {*}$sleepx 0.1} msg] } {1} test exec-9.4 {commands returning errors} jim { list [catch {exec false | echo "foo bar"} msg] $msg } {1 {foo bar}} test exec-9.5 {commands returning errors} { list [catch {exec gorp456 | echo a b c} msg] } {1} test exec-9.6 {commands returning errors} jim { list [catch {exec sh -c "echo error msg 1>&2"} msg] $msg } {0 {error msg}} test exec-9.7 {commands returning errors} jim { # Note: Use sleep here to ensure the order list [catch {exec sh -c "echo error msg 1 1>&2" \ | sh -c "sleep 0.1; echo error msg 2 1>&2"} msg] $msg } {0 {error msg 1 error msg 2}} # Errors in executing the Tcl command, as opposed to errors in the # processes that are invoked. test exec-10.1 {errors in exec invocation} { list [catch {exec} msg] } {1} test exec-10.2 {errors in exec invocation} { list [catch {exec | cat} msg] $msg } {1 {illegal use of | or |& in command}} test exec-10.3 {errors in exec invocation} { list [catch {exec cat |} msg] $msg } {1 {illegal use of | or |& in command}} test exec-10.4 {errors in exec invocation} { list [catch {exec cat | | cat} msg] $msg } {1 {illegal use of | or |& in command}} test exec-10.5 {errors in exec invocation} { list [catch {exec cat | |& cat} msg] $msg } {1 {illegal use of | or |& in command}} test exec-10.6 {errors in exec invocation} { list [catch {exec cat |&} msg] $msg } {1 {illegal use of | or |& in command}} test exec-10.7 {errors in exec invocation} { list [catch {exec cat <} msg] $msg } {1 {can't specify "<" as last word in command}} test exec-10.8 {errors in exec invocation} { list [catch {exec cat >} msg] $msg } {1 {can't specify ">" as last word in command}} test exec-10.9 {errors in exec invocation} { list [catch {exec cat <<} msg] $msg } {1 {can't specify "<<" as last word in command}} test exec-10.10 {errors in exec invocation} { list [catch {exec cat >>} msg] $msg } {1 {can't specify ">>" as last word in command}} test exec-10.11 {errors in exec invocation} { list [catch {exec cat >&} msg] $msg } {1 {can't specify ">&" as last word in command}} test exec-10.12 {errors in exec invocation} { list [catch {exec cat >>&} msg] $msg } {1 {can't specify ">>&" as last word in command}} test exec-10.13 {errors in exec invocation} { list [catch {exec cat >@} msg] $msg } {1 {can't specify ">@" as last word in command}} test exec-10.14 {errors in exec invocation} { list [catch {exec cat <@} msg] $msg } {1 {can't specify "<@" as last word in command}} test exec-10.15 {errors in exec invocation} { list [catch {exec cat < a/b/c} msg] [string tolower $msg] } {1 {couldn't read file "a/b/c": no such file or directory}} test exec-10.16 {errors in exec invocation} { list [catch {exec cat << foo > a/b/c} msg] [string tolower $msg] } {1 {couldn't write file "a/b/c": no such file or directory}} test exec-10.17 {errors in exec invocation} { list [catch {exec cat << foo > a/b/c} msg] [string tolower $msg] } {1 {couldn't write file "a/b/c": no such file or directory}} set f [open gorp.file w] test exec-10.18 {errors in exec invocation} { list [catch {exec cat <@ $f} msg] } 1 close $f # Commands in background. test exec-11.1 {commands in background} { set x [lindex [time {exec {*}$sleepx 0.2 &}] 0] expr $x<1000000 } 1 test exec-11.2 {commands in background} { list [catch {exec echo a &b} msg] $msg } {0 {a &b}} test exec-11.3 {commands in background} { llength [exec {*}$sleepx 0.1 &] } 1 test exec-11.4 {commands in background} { llength [exec {*}$sleepx 0.1 | {*}$sleepx 0.1 | {*}$sleepx 0.1 &] } 3 # Make sure that background commands are properly reaped when # they eventually die. exec {*}$sleepx 0.3 test exec-12.1 {reaping background processes} -body { for {set i 0} {$i < 20} {incr i} { exec echo foo > exec.tmp1 & } exec {*}$sleepx 0.1 catch {exec ps | fgrep "echo foo" | fgrep -v fgrep | wc} msg lindex $msg 0 } -cleanup { file delete exec.tmp1 } -result 0 # Redirecting standard error separately from standard output test exec-15.1 {standard error redirection} { exec echo "First line" > gorp.file list [exec sh -c "echo foo bar 1>&2" 2> gorp.file] \ [exec cat gorp.file] } {{} {foo bar}} test exec-15.2 {standard error redirection} { list [exec sh -c "echo foo bar 1>&2" \ | echo biz baz >gorp.file 2> gorp.file2] \ [exec cat gorp.file] \ [exec cat gorp.file2] } {{} {biz baz} {foo bar}} test exec-15.3 {standard error redirection} { list [exec sh -c "echo foo bar 1>&2" \ | echo biz baz 2>gorp.file > gorp.file2] \ [exec cat gorp.file] \ [exec cat gorp.file2] } {{} {foo bar} {biz baz}} test exec-15.4 {standard error redirection} { set f [open gorp.file w] puts $f "Line 1" flush $f exec sh -c "echo foo bar 1>&2" 2>@ $f puts $f "Line 3" close $f exec cat gorp.file } {Line 1 foo bar Line 3} test exec-15.5 {standard error redirection} { exec echo "First line" > gorp.file exec sh -c "echo foo bar 1>&2" 2>> gorp.file exec cat gorp.file } {First line foo bar} test exec-15.6 {standard error redirection} { exec sh -c "echo foo bar 1>&2" > gorp.file2 2> gorp.file \ >& gorp.file 2> gorp.file2 | echo biz baz list [exec cat gorp.file] [exec cat gorp.file2] } {{biz baz} {foo bar}} test exec-15.7 {combine standard output/standard error} -body { exec sh -c "echo foo bar 1>&2" > gorp.file 2>@1 exec cat gorp.file } -cleanup { file delete gorp.file gorp.file2 } -result {foo bar} test exec-16.1 {flush output before exec} -body { set f [open gorp.file w] puts $f "First line" exec echo "Second line" >@ $f puts $f "Third line" close $f exec cat gorp.file } -cleanup { file delete gorp.file } -result {First line Second line Third line} file delete sleepx testreport openocd-0.7.0/jimtcl/tests/binary-fmt.test0000644000175000001440000005161512134336723015473 00000000000000# This file tests the tclBinary.c file and the "binary" Tcl command. # # This file contains a collection of tests for one or more of the Tcl built-in # commands. Sourcing this file into Tcl runs the tests and generates output # for errors. No output means no errors were found. # # Copyright (c) 1997 by Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution of # this file, and for a DISCLAIMER OF ALL WARRANTIES. # # RCS: @(#) $Id: binary.test,v 1.38 2008/12/15 17:11:34 ferrieux Exp $ source [file dirname [info script]]/testing.tcl needs cmd binary testConstraint bigEndian [expr {$tcl_platform(byteOrder) eq "bigEndian"}] testConstraint littleEndian [expr {$tcl_platform(byteOrder) eq "littleEndian"}] # ---------------------------------------------------------------------- test binary-0.1 {DupByteArrayInternalRep} { set hdr [binary format cc 0 0316] set buf hellomatt set data $hdr append data $buf string length $data } 11 test binary-1.1 {Tcl_BinaryObjCmd: bad args} -body { binary } -returnCodes error -match glob -result {wrong # args: *} test binary-1.2 {Tcl_BinaryObjCmd: bad args} -returnCodes error -body { binary foo } -match glob -result {*} test binary-1.3 {Tcl_BinaryObjCmd: format error} -returnCodes error -body { binary f } -match glob -result {*} test binary-1.4 {Tcl_BinaryObjCmd: format} -body { binary format "" } -result {} test binary-2.1 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format a } -result {not enough arguments for all format specifiers} test binary-2.2 {Tcl_BinaryObjCmd: format} { binary format a0 foo } {} test binary-2.3 {Tcl_BinaryObjCmd: format} { binary format a f } {f} test binary-2.4 {Tcl_BinaryObjCmd: format} { binary format a foo } {f} test binary-2.5 {Tcl_BinaryObjCmd: format} { binary format a3 foo } {foo} test binary-2.6 {Tcl_BinaryObjCmd: format} { binary format a5 foo } foo\x00\x00 test binary-2.7 {Tcl_BinaryObjCmd: format} { binary format a*a3 foobarbaz blat } foobarbazbla test binary-2.8 {Tcl_BinaryObjCmd: format} { binary format a*X3a2 foobar x } foox\x00r test binary-3.1 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format A } -result {not enough arguments for all format specifiers} test binary-3.2 {Tcl_BinaryObjCmd: format} { binary format A0 f } {} test binary-3.3 {Tcl_BinaryObjCmd: format} { binary format A f } {f} test binary-3.4 {Tcl_BinaryObjCmd: format} { binary format A foo } {f} test binary-3.5 {Tcl_BinaryObjCmd: format} { binary format A3 foo } {foo} test binary-3.6 {Tcl_BinaryObjCmd: format} { binary format A5 foo } {foo } test binary-3.7 {Tcl_BinaryObjCmd: format} { binary format A*A3 foobarbaz blat } foobarbazbla test binary-3.8 {Tcl_BinaryObjCmd: format} { binary format A*X3A2 foobar x } {foox r} test binary-4.1 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format B } -result {not enough arguments for all format specifiers} test binary-4.2 {Tcl_BinaryObjCmd: format} { binary format B0 1 } {} test binary-4.3 {Tcl_BinaryObjCmd: format} { binary format B 1 } \x80 test binary-4.4 {Tcl_BinaryObjCmd: format} { binary format B* 010011 } \x4c test binary-4.5 {Tcl_BinaryObjCmd: format} { binary format B8 01001101 } \x4d test binary-4.6 {Tcl_BinaryObjCmd: format} { binary format A2X2B9 oo 01001101 } \x4d\x00 test binary-4.7 {Tcl_BinaryObjCmd: format} { binary format B9 010011011010 } \x4d\x80 test binary-4.8 {Tcl_BinaryObjCmd: format} { binary format B2B3 10 010 } \x80\x40 test binary-4.9 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format B1B5 1 foo } -match glob -result {expected *} test binary-5.1 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format b } -result {not enough arguments for all format specifiers} test binary-5.2 {Tcl_BinaryObjCmd: format} { binary format b0 1 } {} test binary-5.3 {Tcl_BinaryObjCmd: format} { binary format b 1 } \x01 test binary-5.4 {Tcl_BinaryObjCmd: format} { binary format b* 010011 } 2 test binary-5.5 {Tcl_BinaryObjCmd: format} { binary format b8 01001101 } \xb2 test binary-5.6 {Tcl_BinaryObjCmd: format} { binary format A2X2b9 oo 01001101 } \xb2\x00 test binary-5.7 {Tcl_BinaryObjCmd: format} { binary format b9 010011011010 } \xb2\x01 test binary-5.8 {Tcl_BinaryObjCmd: format} { binary format b17 1 } \x01\00\00 test binary-5.9 {Tcl_BinaryObjCmd: format} { binary format b2b3 10 010 } \x01\x02 test binary-5.10 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format b1b5 1 foo } -match glob -result {expected *} test binary-6.1 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format h } -result {not enough arguments for all format specifiers} test binary-6.2 {Tcl_BinaryObjCmd: format} { binary format h0 1 } {} test binary-6.3 {Tcl_BinaryObjCmd: format} { binary format h 1 } \x01 test binary-6.4 {Tcl_BinaryObjCmd: format} { binary format h c } \x0c test binary-6.5 {Tcl_BinaryObjCmd: format} { binary format h* baadf00d } \xab\xda\x0f\xd0 test binary-6.6 {Tcl_BinaryObjCmd: format} { binary format h4 c410 } \x4c\x01 test binary-6.7 {Tcl_BinaryObjCmd: format} { binary format h6 c4102 } \x4c\x01\x02 test binary-6.8 {Tcl_BinaryObjCmd: format} { binary format h5 c41020304 } \x4c\x01\x02 test binary-6.9 {Tcl_BinaryObjCmd: format} { binary format a3X3h5 foo 2 } \x02\x00\x00 test binary-6.10 {Tcl_BinaryObjCmd: format} { binary format h2h3 23 456 } \x32\x54\x06 test binary-6.11 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format h2 foo } -match glob -result {expected *} test binary-7.1 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format H } -result {not enough arguments for all format specifiers} test binary-7.2 {Tcl_BinaryObjCmd: format} { binary format H0 1 } {} test binary-7.3 {Tcl_BinaryObjCmd: format} { binary format H 1 } \x10 test binary-7.4 {Tcl_BinaryObjCmd: format} { binary format H c } \xc0 test binary-7.5 {Tcl_BinaryObjCmd: format} { binary format H* baadf00d } \xba\xad\xf0\x0d test binary-7.6 {Tcl_BinaryObjCmd: format} { binary format H4 c410 } \xc4\x10 test binary-7.7 {Tcl_BinaryObjCmd: format} { binary format H6 c4102 } \xc4\x10\x20 test binary-7.8 {Tcl_BinaryObjCmd: format} { binary format H5 c41023304 } \xc4\x10\x20 test binary-7.9 {Tcl_BinaryObjCmd: format} { binary format a3X3H5 foo 2 } \x20\x00\x00 test binary-7.10 {Tcl_BinaryObjCmd: format} { binary format H2H3 23 456 } \x23\x45\x60 test binary-7.11 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format H2 foo } -match glob -result {expected *} test binary-8.1 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format c } -result {not enough arguments for all format specifiers} test binary-8.2 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format c blat } -match glob -result {expected *} test binary-8.3 {Tcl_BinaryObjCmd: format} { binary format c0 0x50 } {} test binary-8.4 {Tcl_BinaryObjCmd: format} { binary format c 0x50 } P test binary-8.5 {Tcl_BinaryObjCmd: format} { binary format c 0x5052 } R test binary-8.6 {Tcl_BinaryObjCmd: format} { binary format c2 {0x50 0x52} } PR test binary-8.7 {Tcl_BinaryObjCmd: format} { binary format c2 {0x50 0x52 0x53} } PR test binary-8.8 {Tcl_BinaryObjCmd: format} { binary format c* {0x50 0x52} } PR test binary-8.9 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format c2 {0x50} } -result {number of elements in list does not match count} test binary-8.10 {Tcl_BinaryObjCmd: format} -returnCodes error -body { set a {0x50 0x51} binary format c $a } -result "expected integer but got \"0x50 0x51\"" test binary-8.11 {Tcl_BinaryObjCmd: format} { set a {0x50 0x51} binary format c1 $a } P test binary-9.1 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format s } -result {not enough arguments for all format specifiers} test binary-9.2 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format s blat } -result {expected integer but got "blat"} test binary-9.3 {Tcl_BinaryObjCmd: format} { binary format s0 0x50 } {} test binary-9.4 {Tcl_BinaryObjCmd: format} { binary format s 0x50 } P\x00 test binary-9.5 {Tcl_BinaryObjCmd: format} { binary format s 0x5052 } RP test binary-9.6 {Tcl_BinaryObjCmd: format} { binary format s 0x505251 0x53 } QR test binary-9.7 {Tcl_BinaryObjCmd: format} { binary format s2 {0x50 0x52} } P\x00R\x00 test binary-9.8 {Tcl_BinaryObjCmd: format} { binary format s* {0x5051 0x52} } QPR\x00 test binary-9.9 {Tcl_BinaryObjCmd: format} { binary format s2 {0x50 0x52 0x53} 0x54 } P\x00R\x00 test binary-9.10 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format s2 {0x50} } -result {number of elements in list does not match count} test binary-9.11 {Tcl_BinaryObjCmd: format} -returnCodes error -body { set a {0x50 0x51} binary format s $a } -result "expected integer but got \"0x50 0x51\"" test binary-9.12 {Tcl_BinaryObjCmd: format} { set a {0x50 0x51} binary format s1 $a } P\x00 test binary-10.1 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format S } -result {not enough arguments for all format specifiers} test binary-10.2 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format S blat } -result {expected integer but got "blat"} test binary-10.3 {Tcl_BinaryObjCmd: format} { binary format S0 0x50 } {} test binary-10.4 {Tcl_BinaryObjCmd: format} { binary format S 0x50 } \x00P test binary-10.5 {Tcl_BinaryObjCmd: format} { binary format S 0x5052 } PR test binary-10.6 {Tcl_BinaryObjCmd: format} { binary format S 0x505251 0x53 } RQ test binary-10.7 {Tcl_BinaryObjCmd: format} { binary format S2 {0x50 0x52} } \x00P\x00R test binary-10.8 {Tcl_BinaryObjCmd: format} { binary format S* {0x5051 0x52} } PQ\x00R test binary-10.9 {Tcl_BinaryObjCmd: format} { binary format S2 {0x50 0x52 0x53} 0x54 } \x00P\x00R test binary-10.10 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format S2 {0x50} } -result {number of elements in list does not match count} test binary-10.11 {Tcl_BinaryObjCmd: format} -returnCodes error -body { set a {0x50 0x51} binary format S $a } -result "expected integer but got \"0x50 0x51\"" test binary-10.12 {Tcl_BinaryObjCmd: format} { set a {0x50 0x51} binary format S1 $a } \x00P test binary-11.1 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format i } -result {not enough arguments for all format specifiers} test binary-11.2 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format i blat } -result {expected integer but got "blat"} test binary-11.3 {Tcl_BinaryObjCmd: format} { binary format i0 0x50 } {} test binary-11.4 {Tcl_BinaryObjCmd: format} { binary format i 0x50 } P\x00\x00\x00 test binary-11.5 {Tcl_BinaryObjCmd: format} { binary format i 0x5052 } RP\x00\x00 test binary-11.6 {Tcl_BinaryObjCmd: format} { binary format i 0x505251 0x53 } QRP\x00 test binary-11.7 {Tcl_BinaryObjCmd: format} { binary format i1 {0x505251 0x53} } QRP\x00 test binary-11.8 {Tcl_BinaryObjCmd: format} { binary format i 0x53525150 } PQRS test binary-11.9 {Tcl_BinaryObjCmd: format} { binary format i2 {0x50 0x52} } P\x00\x00\x00R\x00\x00\x00 test binary-11.10 {Tcl_BinaryObjCmd: format} { binary format i* {0x50515253 0x52} } SRQPR\x00\x00\x00 test binary-11.11 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format i2 {0x50} } -result {number of elements in list does not match count} test binary-11.12 {Tcl_BinaryObjCmd: format} -returnCodes error -body { set a {0x50 0x51} binary format i $a } -result "expected integer but got \"0x50 0x51\"" test binary-11.13 {Tcl_BinaryObjCmd: format} { set a {0x50 0x51} binary format i1 $a } P\x00\x00\x00 test binary-12.1 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format I } -result {not enough arguments for all format specifiers} test binary-12.2 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format I blat } -result {expected integer but got "blat"} test binary-12.3 {Tcl_BinaryObjCmd: format} { binary format I0 0x50 } {} test binary-12.4 {Tcl_BinaryObjCmd: format} { binary format I 0x50 } \x00\x00\x00P test binary-12.5 {Tcl_BinaryObjCmd: format} { binary format I 0x5052 } \x00\x00PR test binary-12.6 {Tcl_BinaryObjCmd: format} { binary format I 0x505251 0x53 } \x00PRQ test binary-12.7 {Tcl_BinaryObjCmd: format} { binary format I1 {0x505251 0x53} } \x00PRQ test binary-12.8 {Tcl_BinaryObjCmd: format} { binary format I 0x53525150 } SRQP test binary-12.9 {Tcl_BinaryObjCmd: format} { binary format I2 {0x50 0x52} } \x00\x00\x00P\x00\x00\x00R test binary-12.10 {Tcl_BinaryObjCmd: format} { binary format I* {0x50515253 0x52} } PQRS\x00\x00\x00R test binary-12.11 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format i2 {0x50} } -result {number of elements in list does not match count} test binary-12.12 {Tcl_BinaryObjCmd: format} -returnCodes error -body { set a {0x50 0x51} binary format I $a } -result "expected integer but got \"0x50 0x51\"" test binary-12.13 {Tcl_BinaryObjCmd: format} { set a {0x50 0x51} binary format I1 $a } \x00\x00\x00P test binary-15.1 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format ax*a "y" "z" } -result {cannot use "*" in format string with "x"} test binary-15.2 {Tcl_BinaryObjCmd: format} { binary format axa "y" "z" } y\x00z test binary-15.3 {Tcl_BinaryObjCmd: format} { binary format ax3a "y" "z" } y\x00\x00\x00z test binary-15.4 {Tcl_BinaryObjCmd: format} { binary format a*X3x3a* "foo" "z" } \x00\x00\x00z test binary-15.5 {Tcl_BinaryObjCmd: format - bug #1923966} { binary format x0s 1 } \x01\x00 test binary-15.6 {Tcl_BinaryObjCmd: format - bug #1923966} { binary format x0ss 1 1 } \x01\x00\x01\x00 test binary-15.7 {Tcl_BinaryObjCmd: format - bug #1923966} { binary format x1s 1 } \x00\x01\x00 test binary-15.8 {Tcl_BinaryObjCmd: format - bug #1923966} { binary format x1ss 1 1 } \x00\x01\x00\x01\x00 test binary-16.1 {Tcl_BinaryObjCmd: format} { binary format a*X*a "foo" "z" } zoo test binary-16.2 {Tcl_BinaryObjCmd: format} { binary format aX3a "y" "z" } z test binary-16.3 {Tcl_BinaryObjCmd: format} { binary format a*Xa* "foo" "zy" } fozy test binary-16.4 {Tcl_BinaryObjCmd: format} { binary format a*X3a "foobar" "z" } foozar test binary-16.5 {Tcl_BinaryObjCmd: format} { binary format a*X3aX2a "foobar" "z" "b" } fobzar test binary-17.1 {Tcl_BinaryObjCmd: format} { binary format @1 } \x00 test binary-17.2 {Tcl_BinaryObjCmd: format} { binary format @5a2 "ab" } \x00\x00\x00\x00\x00\x61\x62 test binary-17.3 {Tcl_BinaryObjCmd: format} { binary format {a* @0 a2 @* a*} "foobar" "ab" "blat" } abobarblat test binary-18.1 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format u0a3 abc abd } -result {bad field specifier "u"} # GetFormatSpec is pretty thoroughly tested above, but there are a few cases # we should text explicitly test binary-37.1 {GetFormatSpec: whitespace} { binary format "a3 a5 a3" foo barblat baz } foobarblbaz test binary-37.2 {GetFormatSpec: whitespace} { binary format " " foo } {} test binary-37.3 {GetFormatSpec: whitespace} { binary format " a3" foo } foo test binary-37.4 {GetFormatSpec: whitespace} { binary format "" foo } {} test binary-37.5 {GetFormatSpec: whitespace} { binary format "" foo } {} test binary-37.6 {GetFormatSpec: whitespace} { binary format " a3 " foo } foo test binary-38.1 {FormatNumber: word alignment} { set x [binary format c1s1 1 1] } \x01\x01\x00 test binary-38.2 {FormatNumber: word alignment} { set x [binary format c1S1 1 1] } \x01\x00\x01 test binary-38.3 {FormatNumber: word alignment} { set x [binary format c1i1 1 1] } \x01\x01\x00\x00\x00 test binary-38.4 {FormatNumber: word alignment} { set x [binary format c1I1 1 1] } \x01\x00\x00\x00\x01 # Wide int (guaranteed at least 64-bit) handling test binary-43.1 {Tcl_BinaryObjCmd: format wide int} {} { binary format w 7810179016327718216 } HelloTcl test binary-43.2 {Tcl_BinaryObjCmd: format wide int} {} { binary format W 7810179016327718216 } lcTolleH ### TIP#129: endian specifiers ---- # format t test binary-48.1 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format t } -result {not enough arguments for all format specifiers} test binary-48.2 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format t blat } -result {expected integer but got "blat"} test binary-48.3 {Tcl_BinaryObjCmd: format} { binary format S0 0x50 } {} test binary-48.4 {Tcl_BinaryObjCmd: format} bigEndian { binary format t 0x50 } \x00P test binary-48.5 {Tcl_BinaryObjCmd: format} littleEndian { binary format t 0x50 } P\x00 test binary-48.6 {Tcl_BinaryObjCmd: format} bigEndian { binary format t 0x5052 } PR test binary-48.7 {Tcl_BinaryObjCmd: format} littleEndian { binary format t 0x5052 } RP test binary-48.8 {Tcl_BinaryObjCmd: format} bigEndian { binary format t 0x505251 0x53 } RQ test binary-48.9 {Tcl_BinaryObjCmd: format} littleEndian { binary format t 0x505251 0x53 } QR test binary-48.10 {Tcl_BinaryObjCmd: format} bigEndian { binary format t2 {0x50 0x52} } \x00P\x00R test binary-48.11 {Tcl_BinaryObjCmd: format} littleEndian { binary format t2 {0x50 0x52} } P\x00R\x00 test binary-48.12 {Tcl_BinaryObjCmd: format} bigEndian { binary format t* {0x5051 0x52} } PQ\x00R test binary-48.13 {Tcl_BinaryObjCmd: format} littleEndian { binary format t* {0x5051 0x52} } QPR\x00 test binary-48.14 {Tcl_BinaryObjCmd: format} bigEndian { binary format t2 {0x50 0x52 0x53} 0x54 } \x00P\x00R test binary-48.15 {Tcl_BinaryObjCmd: format} littleEndian { binary format t2 {0x50 0x52 0x53} 0x54 } P\x00R\x00 test binary-48.16 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format t2 {0x50} } -result {number of elements in list does not match count} test binary-48.17 {Tcl_BinaryObjCmd: format} -returnCodes error -body { set a {0x50 0x51} binary format t $a } -result "expected integer but got \"0x50 0x51\"" test binary-48.18 {Tcl_BinaryObjCmd: format} bigEndian { set a {0x50 0x51} binary format t1 $a } \x00P test binary-48.19 {Tcl_BinaryObjCmd: format} littleEndian { set a {0x50 0x51} binary format t1 $a } P\x00 # format n test binary-49.1 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format n } -result {not enough arguments for all format specifiers} test binary-49.2 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format n blat } -result {expected integer but got "blat"} test binary-49.3 {Tcl_BinaryObjCmd: format} { binary format n0 0x50 } {} test binary-49.4 {Tcl_BinaryObjCmd: format} littleEndian { binary format n 0x50 } P\x00\x00\x00 test binary-49.5 {Tcl_BinaryObjCmd: format} littleEndian { binary format n 0x5052 } RP\x00\x00 test binary-49.6 {Tcl_BinaryObjCmd: format} littleEndian { binary format n 0x505251 0x53 } QRP\x00 test binary-49.7 {Tcl_BinaryObjCmd: format} littleEndian { binary format i1 {0x505251 0x53} } QRP\x00 test binary-49.8 {Tcl_BinaryObjCmd: format} littleEndian { binary format n 0x53525150 } PQRS test binary-49.9 {Tcl_BinaryObjCmd: format} littleEndian { binary format n2 {0x50 0x52} } P\x00\x00\x00R\x00\x00\x00 test binary-49.10 {Tcl_BinaryObjCmd: format} littleEndian { binary format n* {0x50515253 0x52} } SRQPR\x00\x00\x00 test binary-49.11 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format n2 {0x50} } -result {number of elements in list does not match count} test binary-49.12 {Tcl_BinaryObjCmd: format} -returnCodes error -body { set a {0x50 0x51} binary format n $a } -result "expected integer but got \"0x50 0x51\"" test binary-49.13 {Tcl_BinaryObjCmd: format} littleEndian { set a {0x50 0x51} binary format n1 $a } P\x00\x00\x00 test binary-49.14 {Tcl_BinaryObjCmd: format} bigEndian { binary format n 0x50 } \x00\x00\x00P test binary-49.15 {Tcl_BinaryObjCmd: format} bigEndian { binary format n 0x5052 } \x00\x00PR test binary-49.16 {Tcl_BinaryObjCmd: format} bigEndian { binary format n 0x505251 0x53 } \x00PRQ test binary-49.17 {Tcl_BinaryObjCmd: format} bigEndian { binary format i1 {0x505251 0x53} } QRP\x00 test binary-49.18 {Tcl_BinaryObjCmd: format} bigEndian { binary format n 0x53525150 } SRQP test binary-49.19 {Tcl_BinaryObjCmd: format} bigEndian { binary format n2 {0x50 0x52} } \x00\x00\x00P\x00\x00\x00R test binary-49.20 {Tcl_BinaryObjCmd: format} bigEndian { binary format n* {0x50515253 0x52} } PQRS\x00\x00\x00R # format m test binary-50.1 {Tcl_BinaryObjCmd: format wide int} littleEndian { binary format m 7810179016327718216 } HelloTcl test binary-50.2 {Tcl_BinaryObjCmd: format wide int} bigEndian { binary format m 7810179016327718216 } lcTolleH # cleanup ::tcltest::cleanupTests return # Local Variables: # mode: tcl # End: openocd-0.7.0/jimtcl/tests/exprsugar.test0000644000175000001440000000177312134336723015443 00000000000000source [file dirname [info script]]/testing.tcl needs constraint jim # Test the expr-sugar syntax: $(...) test exprsugar-1.1 {Simple operations} { set x $(2) } 2 test exprsugar-1.2 {Simple operations} { set x $(-3) } -3 test exprsugar-1.3 {Simple operations} { set x $(!0) } 1 test exprsugar-1.4 {Simple operations} { set a 3 set x $($a) } 3 test exprsugar-1.5 {Simple operations} { set x $($a + 4) } 7 test exprsugar-1.6 {Simple operations} { set x $(6 * 7 + 2) } 44 test exprsugar-1.7 {Simple operations} { set a bb set x $($a in {aa bb cc}) } 1 test exprsugar-1.8 {Simple operations} { set a 1 set x $($a ? "yes" : "no") } yes test exprsugar-1.9 {Simple operations} { set a 1 set x $([incr a]) list $a $x } {2 2} # expr sugar inside an expression is an error test exprsugar-1.10 {Simple operations} { catch {set x $(1 + $(5 * 7))} } 1 test exprsugar-1.11 {Simple operations} { unset a set a(b) 3 set x $(2 + $a(b)) } 5 test exprsugar-1.12 {Simple operations} { set x $((2 + 4)) } 6 testreport openocd-0.7.0/jimtcl/tests/signal.test0000644000175000001440000000336012134336723014672 00000000000000source [file dirname [info script]]/testing.tcl needs cmd signal needs cmd pid test signal-1.1 "catch/throw" { signal handle TERM set x 1 set rc [catch -signal { signal throw -TERM incr x } result] signal default TERM list [info returncode $rc] $result $x } {signal SIGTERM 1} test signal-1.2 "catch/kill" { signal handle TERM set x 1 set rc [catch -signal { kill -TERM [pid] incr x } result] signal default TERM list [info returncode $rc] $result $x } {signal SIGTERM 1} test signal-1.3 "catch/alarm" { signal handle ALRM set x 1 set rc [catch -signal { alarm .2 sleep 1 incr x } result] signal default ALRM list [info returncode $rc] $result $x } {signal SIGALRM 1} test signal-1.4 "multiple signals before catch" { signal handle ALRM INT kill -INT [pid] alarm .2 sleep 1 set x 1 set rc [catch -signal { # Doesn't not execute because signals already active incr x } result] signal default ALRM INT list [info returncode $rc] [lsort $result] $x } {signal {SIGALRM SIGINT} 1} test signal-1.5 "ignored signals" { signal handle INT signal ignore HUP set x 1 catch -signal { # Send an ignored signal kill -HUP [pid] incr x # Now a caught signal kill -INT [pid] incr x } result signal default INT TERM list [lsort $result] $x } {SIGINT 2} test signal-1.6 "check ignored signals" { list [signal check SIGINT] [signal check] } {{} SIGHUP} test signal-1.7 "clearing ignored signals" { signal check -clear signal check } {} test signal-1.8 "try/signal" { signal handle ALRM try -signal { alarm 0.4 foreach i [range 10] { sleep 0.1 } set msg "" } on signal {msg} { # Just set msg here } finally { alarm 0 } signal default ALRM list [expr {$i in {3 4 5}}] $msg } {1 SIGALRM} testreport openocd-0.7.0/jimtcl/tests/error.test0000644000175000001440000000216412134336723014547 00000000000000source [file dirname [info script]]/testing.tcl needs constraint jim; needs cmd package proc a {} { error "error thrown from a" } proc b {} { set rc [catch {a} msg] if {$rc} { error $msg [info stacktrace] } } test error-1.1 "Rethrow caught error" { set rc [catch {b} msg] #puts stderr "error-1.1\n[errorInfo $msg]\n" list $rc $msg [info stacktrace] } {1 {error thrown from a} {{} error.test 4 a error.test 8 b error.test 15}} proc c {} { a } proc d {} { c } proc e {} { d } test error-1.2 "Modify stacktrace" { set rc [catch {e} msg] set st [info stacktrace] # Now elide one entry from the stacktrace #puts [errorInfo $msg] set newst {} foreach {p f l} $st { if {$p ne "d"} { lappend newst $p $f $l } } # Now rethrow with the new stack set rc [catch {error $msg $newst} msg] #puts [errorInfo $msg] info stacktrace } {{} error.test 4 a error.test 22 c error.test 26 e error.test 34} # Package should be able to invoke exit, which should exit if not caught test error-2.1 "Exit from package" { list [catch -exit {package require exitpackage} msg] $msg } {6 {Can't load package exitpackage}} testreport openocd-0.7.0/jimtcl/tests/jim.test0000644000175000001440000027226212134336723014205 00000000000000# $Id: test.tcl,v 1.31 2008/11/06 13:31:22 oharboe Exp $ # # These are Tcl tests imported into Jim. Tests that will probably not be passed # in the long term are usually removed (for example all the tests about # unicode things, about errors in list parsing that are always valid in Jim # and so on). # # Sometimes tests are modified to reflect different error messages. source [file dirname [info script]]/testing.tcl needs constraint jim catch {package require regexp} testConstraint regexp [expr {[info commands regexp] ne {}}] testConstraint lambda [expr {[info commands ref] ne {}}] ################################################################################ # SET ################################################################################ test set-1.2 {TclCompileSetCmd: simple variable name} { set i 10 list [set i] $i } {10 10} test set-1.4 {TclCompileSetCmd: simple variable name in quotes} { set i 17 list [set "i"] $i } {17 17} test set-1.7 {TclCompileSetCmd: non-simple (computed) variable name} { set x "i" set i 77 list [set $x] $i } {77 77} test set-1.8 {TclCompileSetCmd: non-simple (computed) variable name} { set x "i" set i 77 list [set [set x] 2] $i } {2 2} test set-1.9 {TclCompileSetCmd: 3rd arg => assignment} { set i "abcdef" list [set i] $i } {abcdef abcdef} test set-1.10 {TclCompileSetCmd: only two args => just getting value} { set i {one two} set i } {one two} test set-1.11 {TclCompileSetCmd: simple global name} { proc p {} { global i set i 54 set i } p } {54} test set-1.12 {TclCompileSetCmd: simple local name} { proc p {bar} { set foo $bar set foo } p 999 } {999} test set-1.14 {TclCompileSetCmd: simple local name, >255 locals} { proc 260locals {} { # create 260 locals (the last ones with index > 255) set a0 0; set a1 0; set a2 0; set a3 0; set a4 0 set a5 0; set a6 0; set a7 0; set a8 0; set a9 0 set b0 0; set b1 0; set b2 0; set b3 0; set b4 0 set b5 0; set b6 0; set b7 0; set b8 0; set b9 0 set c0 0; set c1 0; set c2 0; set c3 0; set c4 0 set c5 0; set c6 0; set c7 0; set c8 0; set c9 0 set d0 0; set d1 0; set d2 0; set d3 0; set d4 0 set d5 0; set d6 0; set d7 0; set d8 0; set d9 0 set e0 0; set e1 0; set e2 0; set e3 0; set e4 0 set e5 0; set e6 0; set e7 0; set e8 0; set e9 0 set f0 0; set f1 0; set f2 0; set f3 0; set f4 0 set f5 0; set f6 0; set f7 0; set f8 0; set f9 0 set g0 0; set g1 0; set g2 0; set g3 0; set g4 0 set g5 0; set g6 0; set g7 0; set g8 0; set g9 0 set h0 0; set h1 0; set h2 0; set h3 0; set h4 0 set h5 0; set h6 0; set h7 0; set h8 0; set h9 0 set i0 0; set i1 0; set i2 0; set i3 0; set i4 0 set i5 0; set i6 0; set i7 0; set i8 0; set i9 0 set j0 0; set j1 0; set j2 0; set j3 0; set j4 0 set j5 0; set j6 0; set j7 0; set j8 0; set j9 0 set k0 0; set k1 0; set k2 0; set k3 0; set k4 0 set k5 0; set k6 0; set k7 0; set k8 0; set k9 0 set l0 0; set l1 0; set l2 0; set l3 0; set l4 0 set l5 0; set l6 0; set l7 0; set l8 0; set l9 0 set m0 0; set m1 0; set m2 0; set m3 0; set m4 0 set m5 0; set m6 0; set m7 0; set m8 0; set m9 0 set n0 0; set n1 0; set n2 0; set n3 0; set n4 0 set n5 0; set n6 0; set n7 0; set n8 0; set n9 0 set o0 0; set o1 0; set o2 0; set o3 0; set o4 0 set o5 0; set o6 0; set o7 0; set o8 0; set o9 0 set p0 0; set p1 0; set p2 0; set p3 0; set p4 0 set p5 0; set p6 0; set p7 0; set p8 0; set p9 0 set q0 0; set q1 0; set q2 0; set q3 0; set q4 0 set q5 0; set q6 0; set q7 0; set q8 0; set q9 0 set r0 0; set r1 0; set r2 0; set r3 0; set r4 0 set r5 0; set r6 0; set r7 0; set r8 0; set r9 0 set s0 0; set s1 0; set s2 0; set s3 0; set s4 0 set s5 0; set s6 0; set s7 0; set s8 0; set s9 0 set t0 0; set t1 0; set t2 0; set t3 0; set t4 0 set t5 0; set t6 0; set t7 0; set t8 0; set t9 0 set u0 0; set u1 0; set u2 0; set u3 0; set u4 0 set u5 0; set u6 0; set u7 0; set u8 0; set u9 0 set v0 0; set v1 0; set v2 0; set v3 0; set v4 0 set v5 0; set v6 0; set v7 0; set v8 0; set v9 0 set w0 0; set w1 0; set w2 0; set w3 0; set w4 0 set w5 0; set w6 0; set w7 0; set w8 0; set w9 0 set x0 0; set x1 0; set x2 0; set x3 0; set x4 0 set x5 0; set x6 0; set x7 0; set x8 0; set x9 0 set y0 0; set y1 0; set y2 0; set y3 0; set y4 0 set y5 0; set y6 0; set y7 0; set y8 0; set y9 0 set z0 0; set z1 0; set z2 0; set z3 0; set z4 0 set z5 0; set z6 0; set z7 0; set z8 0; set z9 1234 } 260locals } {1234} test set-1.17 {TclCompileSetCmd: doing assignment, simple int} { set i 5 set i 123 } 123 test set-1.18 {TclCompileSetCmd: doing assignment, simple int} { set i 5 set i -100 } -100 test set-1.19 {TclCompileSetCmd: doing assignment, simple but not int} { set i 5 set i 0x12MNOP set i } {0x12MNOP} test set-1.20 {TclCompileSetCmd: doing assignment, in quotes} { set i 25 set i "-100" } -100 test set-1.21 {TclCompileSetCmd: doing assignment, in braces} { set i 24 set i {126} } 126 test set-1.22 {TclCompileSetCmd: doing assignment, large int} { set i 5 set i 200000 } 200000 test set-1.23 {TclCompileSetCmd: doing assignment, formatted int != int} { set i 25 set i 000012345 ;# a decimal literal == 5349 decimal list $i [incr i] } {000012345 12346} ################################################################################ # LIST ################################################################################ test list-1.1 {basic tests} {list a b c} {a b c} test list-1.2 {basic tests} {list {a b} c} {{a b} c} test list-1.3 {basic tests} {list \{a b c} {\{a b c} test list-1.4 {basic tests} "list a{}} b{} c}" "a\\{\\}\\} b{} c\\}" test list-1.5 {basic tests} {list a\[ b\] } "{a\[} b\\]" test list-1.6 {basic tests} {list c\ d\t } "{c } {d\t}" test list-1.7 {basic tests} {list e\n f\$ } "{e\n} {f\$}" test list-1.8 {basic tests} {list g\; h\\} {{g;} h\\} test list-1.9 {basic tests} "list a\\\[} b\\\]} " "a\\\[\\\} b\\\]\\\}" test list-1.10 {basic tests} "list c\\\} d\\t} " "c\\} d\\t\\}" test list-1.11 {basic tests} "list e\\n} f\\$} " "e\\n\\} f\\$\\}" test list-1.12 {basic tests} "list g\\;} h\\\\} " "g\\;\\} {h\\}}" test list-1.13 {basic tests} {list a {{}} b} {a {{}} b} test list-1.14 {basic tests} {list a b xy\\} "a b xy\\\\" test list-1.15 {basic tests} "list a b\} e\\" "a b\\} e\\\\" test list-1.16 {basic tests} "list a b\}\\\$ e\\\$\\" "a b\\}\\\$ e\\\$\\\\" test list-1.17 {basic tests} {list a\f \{\f} "{a\f} \\\{\\f" test list-1.18 {basic tests} {list a\r \{\r} "{a\r} \\\{\\r" test list-1.19 {basic tests} {list a\v \{\v} "{a\v} \\\{\\v" test list-1.20 {basic tests} {list \"\}\{} "\\\"\\}\\{" test list-1.21 {basic tests} {list a b c\\\nd} "a b c\\\\\\nd" test list-1.22 {basic tests} {list "{ab}\\"} \\{ab\\}\\\\ test list-1.23 {basic tests} {list \{} "\\{" test list-1.24 {basic tests} {list} {} set num 0 proc lcheck {testid a b c} { global num d set d [list $a $b $c] test ${testid}-0 {what goes in must come out} {lindex $d 0} $a test ${testid}-1 {what goes in must come out} {lindex $d 1} $b test ${testid}-2 {what goes in must come out} {lindex $d 2} $c } lcheck list-2.1 a b c lcheck list-2.2 "a b" c\td e\nf lcheck list-2.3 {{a b}} {} { } lcheck list-2.4 \$ \$ab ab\$ lcheck list-2.5 \; \;ab ab\; lcheck list-2.6 \[ \[ab ab\[ lcheck list-2.7 \\ \\ab ab\\ lcheck list-2.8 {"} {"ab} {ab"} ;#" Stupid emacs highlighting! lcheck list-2.9 {a b} { ab} {ab } lcheck list-2.10 a{ a{b \{ab lcheck list-2.11 a} a}b }ab lcheck list-2.12 a\\} {a \}b} {a \{c} lcheck list-2.13 xyz \\ 1\\\n2 lcheck list-2.14 "{ab}\\" "{ab}xy" abc concat {} ################################################################################ # WHILE ################################################################################ test while-1.9 {TclCompileWhileCmd: simple command body} { set a {} set i 1 while {$i<6} { if $i==4 break set a [concat $a $i] incr i } set a } {1 2 3} test while-1.10 {TclCompileWhileCmd: command body in quotes} { set a {} set i 1 while {$i<6} "append a x; incr i" set a } {xxxxx} test while-1.13 {TclCompileWhileCmd: while command result} { set i 0 set a [while {$i < 5} {incr i}] set a } {} test while-1.14 {TclCompileWhileCmd: while command result} { set i 0 set a [while {$i < 5} {if $i==3 break; incr i}] set a } {} test while-2.1 {continue tests} { set a {} set i 1 while {$i <= 4} { incr i if {$i == 3} continue set a [concat $a $i] } set a } {2 4 5} test while-2.2 {continue tests} { set a {} set i 1 while {$i <= 4} { incr i if {$i != 2} continue set a [concat $a $i] } set a } {2} test while-2.3 {continue tests, nested loops} { set msg {} set i 1 while {$i <= 4} { incr i set a 1 while {$a <= 2} { incr a if {$i>=3 && $a>=3} continue set msg [concat $msg "$i.$a"] } } set msg } {2.2 2.3 3.2 4.2 5.2} test while-4.1 {while and computed command names} { set i 0 set z while $z {$i < 10} { incr i } set i } 10 test while-5.2 {break tests with computed command names} { set a {} set i 1 set z break while {$i <= 4} { if {$i == 3} $z set a [concat $a $i] incr i } set a } {1 2} test while-7.1 {delayed substitution of body} { set i 0 while {[incr i] < 10} " set result $i " proc p {} { set i 0 while {[incr i] < 10} " set result $i " set result } append result [p] } {00} ################################################################################ # LSET ################################################################################ set lset lset test lset-2.1 {lset, not compiled, 3 args, second arg a plain index} { set x {0 1 2} list [eval [list $lset x 0 3]] $x } {{3 1 2} {3 1 2}} test lset-3.1 {lset, not compiled, 3 args, data duplicated} { set x {0 1 2} list [eval [list $lset x 0 $x]] $x } {{{0 1 2} 1 2} {{0 1 2} 1 2}} test lset-3.2 {lset, not compiled, 3 args, data duplicated} { set x {0 1} set y $x list [eval [list $lset x 0 2]] $x $y } {{2 1} {2 1} {0 1}} test lset-3.3 {lset, not compiled, 3 args, data duplicated} { set x {0 1} set y $x list [eval [list $lset x 0 $x]] $x $y } {{{0 1} 1} {{0 1} 1} {0 1}} test lset-3.4 {lset, not compiled, 3 args, data duplicated} { set x {0 1 2} list [eval [list $lset x [list 0] $x]] $x } {{{0 1 2} 1 2} {{0 1 2} 1 2}} test lset-3.5 {lset, not compiled, 3 args, data duplicated} { set x {0 1} set y $x list [eval [list $lset x [list 0] 2]] $x $y } {{2 1} {2 1} {0 1}} test lset-3.6 {lset, not compiled, 3 args, data duplicated} { set x {0 1} set y $x list [eval [list $lset x [list 0] $x]] $x $y } {{{0 1} 1} {{0 1} 1} {0 1}} test lset-4.2 {lset, not compiled, 3 args, bad index} { set a {x y z} list [catch { eval [list $lset a [list 2a2] w] } msg] $msg } {1 {bad index "2a2": must be integer?[+-]integer? or end?[+-]integer?}} test lset-4.3 {lset, not compiled, 3 args, index out of range} { set a {x y z} list [catch { eval [list $lset a [list -1] w] } msg] $msg } {1 {list index out of range}} test lset-4.4 {lset, not compiled, 3 args, index out of range} { set a {x y z} list [catch { eval [list $lset a [list 3] w] } msg] $msg } {1 {list index out of range}} test lset-4.5 {lset, not compiled, 3 args, index out of range} { set a {x y z} list [catch { eval [list $lset a [list end--1] w] } msg] $msg } {1 {list index out of range}} test lset-4.6 {lset, not compiled, 3 args, index out of range} { set a {x y z} list [catch { eval [list $lset a [list end-3] w] } msg] $msg } {1 {list index out of range}} test lset-4.8 {lset, not compiled, 3 args, bad index} { set a {x y z} list [catch { eval [list $lset a 2a2 w] } msg] $msg } {1 {bad index "2a2": must be integer?[+-]integer? or end?[+-]integer?}} test lset-4.9 {lset, not compiled, 3 args, index out of range} { set a {x y z} list [catch { eval [list $lset a -1 w] } msg] $msg } {1 {list index out of range}} test lset-4.10 {lset, not compiled, 3 args, index out of range} { set a {x y z} list [catch { eval [list $lset a 3 w] } msg] $msg } {1 {list index out of range}} test lset-4.11 {lset, not compiled, 3 args, index out of range} { set a {x y z} list [catch { eval [list $lset a end--1 w] } msg] $msg } {1 {list index out of range}} test lset-4.12 {lset, not compiled, 3 args, index out of range} { set a {x y z} list [catch { eval [list $lset a end-3 w] } msg] $msg } {1 {list index out of range}} test lset-6.1 {lset, not compiled, 3 args, 1-d list basics} { set a {x y z} list [eval [list $lset a 0 a]] $a } {{a y z} {a y z}} test lset-6.2 {lset, not compiled, 3 args, 1-d list basics} { set a {x y z} list [eval [list $lset a [list 0] a]] $a } {{a y z} {a y z}} test lset-6.3 {lset, not compiled, 1-d list basics} { set a {x y z} list [eval [list $lset a 2 a]] $a } {{x y a} {x y a}} test lset-6.4 {lset, not compiled, 1-d list basics} { set a {x y z} list [eval [list $lset a [list 2] a]] $a } {{x y a} {x y a}} test lset-6.5 {lset, not compiled, 1-d list basics} { set a {x y z} list [eval [list $lset a end a]] $a } {{x y a} {x y a}} test lset-6.6 {lset, not compiled, 1-d list basics} { set a {x y z} list [eval [list $lset a [list end] a]] $a } {{x y a} {x y a}} test lset-6.7 {lset, not compiled, 1-d list basics} { set a {x y z} list [eval [list $lset a end-0 a]] $a } {{x y a} {x y a}} test lset-6.8 {lset, not compiled, 1-d list basics} { set a {x y z} list [eval [list $lset a [list end-0] a]] $a } {{x y a} {x y a}} test lset-6.9 {lset, not compiled, 1-d list basics} { set a {x y z} list [eval [list $lset a end-2 a]] $a } {{a y z} {a y z}} test lset-6.10 {lset, not compiled, 1-d list basics} { set a {x y z} list [eval [list $lset a [list end-2] a]] $a } {{a y z} {a y z}} test lset-7.1 {lset, not compiled, data sharing} { set a 0 list [eval [list $lset a $a {gag me}]] $a } {{{gag me}} {{gag me}}} test lset-7.2 {lset, not compiled, data sharing} { set a [list 0] list [eval [list $lset a $a {gag me}]] $a } {{{gag me}} {{gag me}}} test lset-7.3 {lset, not compiled, data sharing} { set a {x y} list [eval [list $lset a 0 $a]] $a } {{{x y} y} {{x y} y}} test lset-7.4 {lset, not compiled, data sharing} { set a {x y} list [eval [list $lset a [list 0] $a]] $a } {{{x y} y} {{x y} y}} test lset-7.5 {lset, not compiled, data sharing} { set n 0 set a {x y} list [eval [list $lset a $n $n]] $a $n } {{0 y} {0 y} 0} test lset-7.6 {lset, not compiled, data sharing} { set n [list 0] set a {x y} list [eval [list $lset a $n $n]] $a $n } {{0 y} {0 y} 0} test lset-7.7 {lset, not compiled, data sharing} { set n 0 set a [list $n $n] list [eval [list $lset a $n 1]] $a $n } {{1 0} {1 0} 0} test lset-7.8 {lset, not compiled, data sharing} { set n [list 0] set a [list $n $n] list [eval [list $lset a $n 1]] $a $n } {{1 0} {1 0} 0} test lset-7.9 {lset, not compiled, data sharing} { set a 0 list [eval [list $lset a $a $a]] $a } {0 0} test lset-7.10 {lset, not compiled, data sharing} { set a [list 0] list [eval [list $lset a $a $a]] $a } {0 0} test lset-8.3 {lset, not compiled, bad second index} { set a {{b c} {d e}} list [catch {eval [list $lset a 0 2a2 f]} msg] $msg } {1 {bad index "2a2": must be integer?[+-]integer? or end?[+-]integer?}} test lset-8.5 {lset, not compiled, second index out of range} { set a {{b c} {d e} {f g}} list [catch {eval [list $lset a 2 -1 h]} msg] $msg } {1 {list index out of range}} test lset-8.7 {lset, not compiled, second index out of range} { set a {{b c} {d e} {f g}} list [catch {eval [list $lset a 2 2 h]} msg] $msg } {1 {list index out of range}} test lset-8.9 {lset, not compiled, second index out of range} { set a {{b c} {d e} {f g}} list [catch {eval [list $lset a 2 end--1 h]} msg] $msg } {1 {list index out of range}} test lset-8.11 {lset, not compiled, second index out of range} { set a {{b c} {d e} {f g}} list [catch {eval [list $lset a 2 end-2 h]} msg] $msg } {1 {list index out of range}} test lset-9.1 {lset, not compiled, entire variable} { set a x list [eval [list $lset a y]] $a } {y y} test lset-10.1 {lset, not compiled, shared data} { set row {p q} set a [list $row $row] list [eval [list $lset a 0 0 x]] $a } {{{x q} {p q}} {{x q} {p q}}} test lset-11.1 {lset, not compiled, 2-d basics} { set a {{b c} {d e}} list [eval [list $lset a 0 0 f]] $a } {{{f c} {d e}} {{f c} {d e}}} test lset-11.3 {lset, not compiled, 2-d basics} { set a {{b c} {d e}} list [eval [list $lset a 0 1 f]] $a } {{{b f} {d e}} {{b f} {d e}}} test lset-11.5 {lset, not compiled, 2-d basics} { set a {{b c} {d e}} list [eval [list $lset a 1 0 f]] $a } {{{b c} {f e}} {{b c} {f e}}} test lset-11.7 {lset, not compiled, 2-d basics} { set a {{b c} {d e}} list [eval [list $lset a 1 1 f]] $a } {{{b c} {d f}} {{b c} {d f}}} test lset-12.0 {lset, not compiled, typical sharing pattern} { set zero 0 set row [list $zero $zero $zero $zero] set ident [list $row $row $row $row] for { set i 0 } { $i < 4 } { incr i } { eval [list $lset ident $i $i 1] } set ident } {{1 0 0 0} {0 1 0 0} {0 0 1 0} {0 0 0 1}} test lset-13.0 {lset, not compiled, shimmering hell} { set a 0 list [eval [list $lset a $a $a $a $a {gag me}]] $a } {{{{{{gag me}}}}} {{{{{gag me}}}}}} test lset-13.1 {lset, not compiled, shimmering hell} { set a [list 0] list [eval [list $lset a $a $a $a $a {gag me}]] $a } {{{{{{gag me}}}}} {{{{{gag me}}}}}} test lset-14.1 {lset, not compiled, list args, is string rep preserved?} { set a { { 1 2 } { 3 4 } } catch { eval [list $lset a {1 5} 5] } list $a [lindex $a 1] } "{ { 1 2 } { 3 4 } } { 3 4 }" catch {unset noRead} catch {unset noWrite} catch {rename failTrace {}} catch {unset ::x} catch {unset ::y} ################################################################################ # IF ################################################################################ test if-1.1 {bad syntax: lacking all} { catch {if} } 1 test if-1.2 {bad syntax: lacking then-clause} { catch {if 1==1} } 1 test if-1.3 {bad syntax: lacking then-clause 2} { catch {if 1==1 then} } 1 test if-1.4 {bad syntax: lacking else-clause after keyword 'else'} { catch {if 1==0 then {list 1} else} } 1 test if-1.5 {bad syntax: lacking expr after 'elseif'} { catch {if 1==0 then {list 1} elseif} } 1 test if-1.6 {bad syntax: lacking then-clause after 'elseif'} { catch {if 1==0 then {list 1} elseif 1==1} } 1 test if-1.7 {bad syntax: lacking else-clause after 'elseif' after keyword 'else'} { catch {if 1==0 then {list 1} elseif 1==0 {list 2} else} } 1 test if-1.8 {bad syntax: extra arg after implicit else-clause} { catch {if 1==0 {list 1} elseif 1==0 then {list 2} {list 3} else} } 1 test if-1.9 {bad syntax: elsif-clause after else-clause} { catch {if 1==0 {list 1} else {list 2} elseif 1==1 {list 3}} } 1 test if-2.1 {taking proper branch} { set a {} if 0 {set a 1} else {set a 2} set a } 2 test if-2.2 {taking proper branch} { set a {} if 1 {set a 1} else {set a 2} set a } 1 test if-2.3 {taking proper branch} { set a {} if 1<2 {set a 1} set a } 1 test if-2.4 {taking proper branch} { set a {} if 1>2 {set a 1} set a } {} test if-2.5 {taking proper branch} { set a {} if 0 {set a 1} else {} set a } {} test if-2.6 {taking proper branch} { set a {} if 0 {set a 1} elseif 1 {set a 2} elseif 1 {set a 3} else {set a 4} set a } 2 test if-2.7 {taking proper branch} { set a {} if 0 {set a 1} elseif 0 {set a 2} elseif 1 {set a 3} else {set a 4} set a } 3 test if-2.8 {taking proper branch} { set a {} if 0 {set a 1} elseif 0 {set a 2} elseif 0 {set a 3} else {set a 4} set a } 4 test if-2.9 {taking proper branch, multiline test expr} { set a {} if {1 != \ 3} {set a 3} else {set a 4} set a } 3 test if-3.1 {optional then-else args} { set a 44 if 0 then {set a 1} elseif 0 then {set a 3} else {set a 2} set a } 2 test if-3.2 {optional then-else args} { set a 44 if 1 then {set a 1} else {set a 2} set a } 1 test if-3.3 {optional then-else args} { set a 44 if 0 {set a 1} else {set a 2} set a } 2 test if-3.4 {optional then-else args} { set a 44 if 1 {set a 1} else {set a 2} set a } 1 test if-3.5 {optional then-else args} { set a 44 if 0 then {set a 1} {set a 2} set a } 2 test if-3.6 {optional then-else args} { set a 44 if 1 then {set a 1} {set a 2} set a } 1 test if-3.7 {optional then-else args} { set a 44 if 0 then {set a 1} else {set a 2} set a } 2 test if-3.8 {optional then-else args} { set a 44 if 0 then {set a 1} elseif 0 {set a 2} elseif 0 {set a 3} {set a 4} set a } 4 test if-4.1 {return value} { if 1 then {set a 22; concat abc} } abc test if-4.2 {return value} { if 0 then {set a 22; concat abc} elseif 1 {concat def} {concat ghi} } def test if-4.3 {return value} { if 0 then {set a 22; concat abc} else {concat def} } def test if-4.4 {return value} { if 0 then {set a 22; concat abc} } {} test if-4.5 {return value} { if 0 then {set a 22; concat abc} elseif 0 {concat def} } {} test if-5.1 {error conditions} { list [catch {if {[error "error in condition"]} foo} msg] $msg } {1 {error in condition}} test if-5.2 {error conditions} { list [catch {if 2 the} msg] $msg } {1 {invalid command name "the"}} test if-5.3 {error conditions} { list [catch {if 2 then {[error "error in then clause"]}} msg] $msg } {1 {error in then clause}} test if-5.4 {error conditions} { list [catch {if 0 then foo elsei} msg] $msg } {1 {invalid command name "elsei"}} test if-5.5 {error conditions} { list [catch {if 0 then foo elseif 0 bar els} msg] $msg } {1 {invalid command name "els"}} test if-5.6 {error conditions} { list [catch {if 0 then foo elseif 0 bar else {[error "error in else clause"]}} msg] $msg } {1 {error in else clause}} ################################################################################ # APPEND ################################################################################ catch {unset x} test append-1.1 {append command} { catch {unset x} list [append x 1 2 abc "long string"] $x } {{12abclong string} {12abclong string}} test append-1.2 {append command} { set x "" list [append x first] [append x second] [append x third] $x } {first firstsecond firstsecondthird firstsecondthird} test append-1.3 {append command} { set x "abcd" append x } abcd test append-2.1 {long appends} { set x "" for {set i 0} {$i < 1000} {set i [expr $i+1]} { append x "foobar " } set y "foobar" set y "$y $y $y $y $y $y $y $y $y $y" set y "$y $y $y $y $y $y $y $y $y $y" set y "$y $y $y $y $y $y $y $y $y $y " expr {$x eq $y} } 1 test append-3.1 {append errors} { list [catch {append} msg] $msg } {1 {wrong # args: should be "append varName ?value value ...?"}} test append-3.2 {append errors} { set x 1 list [catch {append x(0) 44} msg] $msg } {1 {can't set "x(0)": variable isn't array}} test append-3.3 {append errors} { catch {unset x} list [catch {append x} msg] $msg } {1 {can't read "x": no such variable}} test append-4.1 {lappend command} { catch {unset x} list [lappend x 1 2 abc "long string"] $x } {{1 2 abc {long string}} {1 2 abc {long string}}} test append-4.2 {lappend command} { set x "" list [lappend x first] [lappend x second] [lappend x third] $x } {first {first second} {first second third} {first second third}} test append-4.3 {lappend command} { proc foo {} { global x set x old unset x lappend x new } set result [foo] rename foo {} set result } {new} test append-4.4 {lappend command} { set x {} lappend x \{\ abc } {\{\ abc} test append-4.5 {lappend command} { set x {} lappend x \{ abc } {\{ abc} test append-4.6 {lappend command} { set x {1 2 3} lappend x } {1 2 3} test append-4.7 {lappend command} { set x "a\{" lappend x abc } "a\\\{ abc" test append-4.8 {lappend command} { set x "\\\{" lappend x abc } "\\{ abc" #test append-4.9 {lappend command} { # set x " \{" # list [catch {lappend x abc} msg] $msg #} {1 {unmatched open brace in list}} #test append-4.10 {lappend command} { # set x " \{" # list [catch {lappend x abc} msg] $msg #} {1 {unmatched open brace in list}} #test append-4.11 {lappend command} { # set x "\{\{\{" # list [catch {lappend x abc} msg] $msg #} {1 {unmatched open brace in list}} #test append-4.12 {lappend command} { # set x "x \{\{\{" # list [catch {lappend x abc} msg] $msg #} {1 {unmatched open brace in list}} test append-4.13 {lappend command} { set x "x\{\{\{" lappend x abc } "x\\\{\\\{\\\{ abc" test append-4.14 {lappend command} { set x " " lappend x abc } "abc" test append-4.15 {lappend command} { set x "\\ " lappend x abc } "{ } abc" test append-4.16 {lappend command} { set x "x " lappend x abc } "x abc" test append-4.17 {lappend command} { catch {unset x} lappend x } {} test append-4.18 {lappend command} { catch {unset x} lappend x {} } {{}} test append-4.19 {lappend command} { catch {unset x} lappend x(0) } {} test append-4.20 {lappend command} { catch {unset x} lappend x(0) abc } {abc} proc check {var size} { set l [llength $var] if {$l != $size} { return "length mismatch: should have been $size, was $l" } for {set i 0} {$i < $size} {set i [expr $i+1]} { set j [lindex $var $i] if {$j ne "item $i"} { return "element $i should have been \"item $i\", was \"$j\"" } } return ok } test append-5.1 {long lappends} { catch {unset x} set x "" for {set i 0} {$i < 300} {set i [expr $i+1]} { lappend x "item $i" } check $x 300 } ok test append-6.1 {lappend errors} { list [catch {lappend} msg] $msg } {1 {wrong # args: should be "lappend varName ?value value ...?"}} test append-6.2 {lappend errors} { set x 1 list [catch {lappend x(0) 44} msg] $msg } {1 {can't set "x(0)": variable isn't array}} ################################################################################ # UPLEVEL ################################################################################ proc a {x y} { newset z [expr $x+$y] return $z } proc newset {name value} { uplevel set $name $value uplevel 1 {uplevel 1 {set xyz 22}} } test uplevel-1.1 {simple operation} { set xyz 0 a 22 33 } 55 test uplevel-1.2 {command is another uplevel command} { set xyz 0 a 22 33 set xyz } 22 proc a1 {} { b1 global a a1 set a $x set a1 $y } proc b1 {} { c1 global b b1 set b $x set b1 $y } proc c1 {} { uplevel 1 set x 111 uplevel #2 set y 222 uplevel 2 set x 333 uplevel #1 set y 444 uplevel 3 set x 555 uplevel #0 set y 666 } a1 test uplevel-2.1 {relative and absolute uplevel} {set a} 333 test uplevel-2.2 {relative and absolute uplevel} {set a1} 444 test uplevel-2.3 {relative and absolute uplevel} {set b} 111 test uplevel-2.4 {relative and absolute uplevel} {set b1} 222 test uplevel-2.5 {relative and absolute uplevel} {set x} 555 test uplevel-2.6 {relative and absolute uplevel} {set y} 666 test uplevel-3.1 {uplevel to same level} { set x 33 uplevel #0 set x 44 set x } 44 test uplevel-3.2 {uplevel to same level} { set x 33 uplevel 0 set x } 33 test uplevel-3.3 {uplevel to same level} { set y xxx proc a1 {} {set y 55; uplevel 0 set y 66; return $y} a1 } 66 test uplevel-3.4 {uplevel to same level} { set y zzz proc a1 {} {set y 55; uplevel #1 set y} a1 } 55 test uplevel-4.1 {error: non-existent level} { list [catch c1 msg] $msg } {1 {bad level "#2"}} test uplevel-4.2 {error: non-existent level} { proc c2 {} {uplevel 3 {set a b}} list [catch c2 msg] $msg } {1 {bad level "3"}} test uplevel-4.3 {error: not enough args} { list [catch uplevel msg] $msg } {1 {wrong # args: should be "uplevel ?level? command ?arg ...?"}} test uplevel-4.4 {error: not enough args} { proc upBug {} {uplevel 1} list [catch upBug msg] $msg } {1 {wrong # args: should be "uplevel ?level? command ?arg ...?"}} proc a2 {} { uplevel a3 } proc a3 {} { global x y set x [info level] set y [info level 1] } a2 test uplevel-5.1 {info level} {set x} 1 test uplevel-5.2 {info level} {set y} a3 ################################################################################ # UNKNOWN ################################################################################ catch {unset x} catch {rename unknown unknown.old} test unknown-1.1 {non-existent "unknown" command} { list [catch {_non-existent_ foo bar} msg] $msg } {1 {invalid command name "_non-existent_"}} proc unknown {args} { global x set x $args } test unknown-2.1 {calling "unknown" command} { foobar x y z set x } {foobar x y z} test unknown-2.2 {calling "unknown" command with lots of args} { foobar 1 2 3 4 5 6 7 set x } {foobar 1 2 3 4 5 6 7} test unknown-2.3 {calling "unknown" command with lots of args} { foobar 1 2 3 4 5 6 7 8 set x } {foobar 1 2 3 4 5 6 7 8} test unknown-2.4 {calling "unknown" command with lots of args} { foobar 1 2 3 4 5 6 7 8 9 set x } {foobar 1 2 3 4 5 6 7 8 9} test unknown-3.1 {argument quoting in calls to "unknown"} { foobar \{ \} a\{b \; "\\" \$a a\[b \] set x } "foobar \\{ \\} a\\{b {;} \\\\ {\$a} {a\[b} \\]" proc unknown args { error "unknown failed" } test unknown-4.1 {errors in "unknown" procedure} { list [catch {non-existent a b} msg] $msg } {1 {unknown failed}} rename unknown {} ################################################################################ # INCR ################################################################################ catch {unset x} catch {unset i} test incr-1.1 {TclCompileIncrCmd: missing variable name} { list [catch {incr} msg] $msg } {1 {wrong # args: should be "incr varName ?increment?"}} test incr-1.2 {TclCompileIncrCmd: simple variable name} { set i 10 list [incr i] $i } {11 11} #test incr-1.3 {TclCompileIncrCmd: error compiling variable name} { # set i 10 # catch {incr "i"xxx} msg # set msg #} {extra characters after close-quote} test incr-1.4 {TclCompileIncrCmd: simple variable name in quotes} { set i 17 list [incr "i"] $i } {18 18} test incr-1.5 {TclCompileIncrCmd: simple variable name in braces} { catch {unset {a simple var}} set {a simple var} 27 list [incr {a simple var}] ${a simple var} } {28 28} test incr-1.6 {TclCompileIncrCmd: simple array variable name} { catch {unset a} set a(foo) 37 list [incr a(foo)] $a(foo) } {38 38} test incr-1.7 {TclCompileIncrCmd: non-simple (computed) variable name} { set x "i" set i 77 list [incr $x 2] $i } {79 79} test incr-1.8 {TclCompileIncrCmd: non-simple (computed) variable name} { set x "i" set i 77 list [incr [set x] +2] $i } {79 79} test incr-1.9 {TclCompileIncrCmd: increment given} { set i 10 list [incr i +07] $i } {17 17} test incr-1.10 {TclCompileIncrCmd: no increment given} { set i 10 list [incr i] $i } {11 11} test incr-1.11 {TclCompileIncrCmd: simple global name} { proc p {} { global i set i 54 incr i } p } {55} test incr-1.12 {TclCompileIncrCmd: simple local name} { proc p {} { set foo 100 incr foo } p } {101} test incr-1.13 {TclCompileIncrCmd: simple but new (unknown) local name} { proc p {} { incr bar } catch {p} msg set msg } {1} test incr-1.14 {TclCompileIncrCmd: simple local name, >255 locals} { proc 260locals {} { # create 260 locals set a0 0; set a1 0; set a2 0; set a3 0; set a4 0 set a5 0; set a6 0; set a7 0; set a8 0; set a9 0 set b0 0; set b1 0; set b2 0; set b3 0; set b4 0 set b5 0; set b6 0; set b7 0; set b8 0; set b9 0 set c0 0; set c1 0; set c2 0; set c3 0; set c4 0 set c5 0; set c6 0; set c7 0; set c8 0; set c9 0 set d0 0; set d1 0; set d2 0; set d3 0; set d4 0 set d5 0; set d6 0; set d7 0; set d8 0; set d9 0 set e0 0; set e1 0; set e2 0; set e3 0; set e4 0 set e5 0; set e6 0; set e7 0; set e8 0; set e9 0 set f0 0; set f1 0; set f2 0; set f3 0; set f4 0 set f5 0; set f6 0; set f7 0; set f8 0; set f9 0 set g0 0; set g1 0; set g2 0; set g3 0; set g4 0 set g5 0; set g6 0; set g7 0; set g8 0; set g9 0 set h0 0; set h1 0; set h2 0; set h3 0; set h4 0 set h5 0; set h6 0; set h7 0; set h8 0; set h9 0 set i0 0; set i1 0; set i2 0; set i3 0; set i4 0 set i5 0; set i6 0; set i7 0; set i8 0; set i9 0 set j0 0; set j1 0; set j2 0; set j3 0; set j4 0 set j5 0; set j6 0; set j7 0; set j8 0; set j9 0 set k0 0; set k1 0; set k2 0; set k3 0; set k4 0 set k5 0; set k6 0; set k7 0; set k8 0; set k9 0 set l0 0; set l1 0; set l2 0; set l3 0; set l4 0 set l5 0; set l6 0; set l7 0; set l8 0; set l9 0 set m0 0; set m1 0; set m2 0; set m3 0; set m4 0 set m5 0; set m6 0; set m7 0; set m8 0; set m9 0 set n0 0; set n1 0; set n2 0; set n3 0; set n4 0 set n5 0; set n6 0; set n7 0; set n8 0; set n9 0 set o0 0; set o1 0; set o2 0; set o3 0; set o4 0 set o5 0; set o6 0; set o7 0; set o8 0; set o9 0 set p0 0; set p1 0; set p2 0; set p3 0; set p4 0 set p5 0; set p6 0; set p7 0; set p8 0; set p9 0 set q0 0; set q1 0; set q2 0; set q3 0; set q4 0 set q5 0; set q6 0; set q7 0; set q8 0; set q9 0 set r0 0; set r1 0; set r2 0; set r3 0; set r4 0 set r5 0; set r6 0; set r7 0; set r8 0; set r9 0 set s0 0; set s1 0; set s2 0; set s3 0; set s4 0 set s5 0; set s6 0; set s7 0; set s8 0; set s9 0 set t0 0; set t1 0; set t2 0; set t3 0; set t4 0 set t5 0; set t6 0; set t7 0; set t8 0; set t9 0 set u0 0; set u1 0; set u2 0; set u3 0; set u4 0 set u5 0; set u6 0; set u7 0; set u8 0; set u9 0 set v0 0; set v1 0; set v2 0; set v3 0; set v4 0 set v5 0; set v6 0; set v7 0; set v8 0; set v9 0 set w0 0; set w1 0; set w2 0; set w3 0; set w4 0 set w5 0; set w6 0; set w7 0; set w8 0; set w9 0 set x0 0; set x1 0; set x2 0; set x3 0; set x4 0 set x5 0; set x6 0; set x7 0; set x8 0; set x9 0 set y0 0; set y1 0; set y2 0; set y3 0; set y4 0 set y5 0; set y6 0; set y7 0; set y8 0; set y9 0 set z0 0; set z1 0; set z2 0; set z3 0; set z4 0 set z5 0; set z6 0; set z7 0; set z8 0; set z9 0 # now increment the last one (local var index > 255) incr z9 } 260locals } {1} test incr-1.15 {TclCompileIncrCmd: variable is array} { catch {unset a} set a(foo) 27 set x [incr a(foo) 11] catch {unset a} set x } 38 test incr-1.16 {TclCompileIncrCmd: variable is array, elem substitutions} { catch {unset a} set i 5 set a(foo5) 27 set x [incr a(foo$i) 11] catch {unset a} set x } 38 test incr-1.17 {TclCompileIncrCmd: increment given, simple int} { set i 5 incr i 123 } 128 test incr-1.18 {TclCompileIncrCmd: increment given, simple int} { set i 5 incr i -100 } -95 #test incr-1.19 {TclCompileIncrCmd: increment given, but erroneous} { # set i 5 # catch {incr i [set]} msg # set errorInfo #} {wrong # args: should be "set varName ?newValue?" # while compiling #"set" # while compiling #"incr i [set]"} test incr-1.20 {TclCompileIncrCmd: increment given, in quotes} { set i 25 incr i "-100" } -75 test incr-1.21 {TclCompileIncrCmd: increment given, in braces} { set i 24 incr i {126} } 150 test incr-1.22 {TclCompileIncrCmd: increment given, large int} { set i 5 incr i 200000 } 200005 test incr-1.23 {TclCompileIncrCmd: increment given, formatted int != int} { set i 25 incr i 000012345 ;# a decimal literal } 12370 test incr-1.24 {TclCompileIncrCmd: increment given, formatted int != int} { set i 25 catch {incr i 1a} msg set msg } {expected integer but got "1a"} test incr-1.25 {TclCompileIncrCmd: too many arguments} { set i 10 catch {incr i 10 20} msg set msg } {wrong # args: should be "incr varName ?increment?"} test incr-1.29 {TclCompileIncrCmd: runtime error, bad variable value} { set x " - " list [catch {incr x 1} msg] $msg } {1 {expected integer but got " - "}} test incr-1.30 {TclCompileIncrCmd: array var, braced (no subs)} { catch {unset array} set array(\$foo) 4 incr {array($foo)} } 5 # Check "incr" and computed command names. test incr-2.0 {incr and computed command names} { set i 5 set z incr $z i -1 set i } 4 catch {unset x} catch {unset i} test incr-2.1 {incr command (not compiled): missing variable name} { set z incr list [catch {$z} msg] $msg } {1 {wrong # args: should be "incr varName ?increment?"}} test incr-2.2 {incr command (not compiled): simple variable name} { set z incr set i 10 list [$z i] $i } {11 11} test incr-2.4 {incr command (not compiled): simple variable name in quotes} { set z incr set i 17 list [$z "i"] $i } {18 18} test incr-2.5 {incr command (not compiled): simple variable name in braces} { set z incr catch {unset {a simple var}} set {a simple var} 27 list [$z {a simple var}] ${a simple var} } {28 28} test incr-2.6 {incr command (not compiled): simple array variable name} { set z incr catch {unset a} set a(foo) 37 list [$z a(foo)] $a(foo) } {38 38} test incr-2.7 {incr command (not compiled): non-simple (computed) variable name} { set z incr set x "i" set i 77 list [$z $x 2] $i } {79 79} test incr-2.8 {incr command (not compiled): non-simple (computed) variable name} { set z incr set x "i" set i 77 list [$z [set x] +2] $i } {79 79} test incr-2.9 {incr command (not compiled): increment given} { set z incr set i 10 list [$z i +07] $i } {17 17} test incr-2.10 {incr command (not compiled): no increment given} { set z incr set i 10 list [$z i] $i } {11 11} test incr-2.11 {incr command (not compiled): simple global name} { proc p {} { set z incr global i set i 54 $z i } p } {55} test incr-2.12 {incr command (not compiled): simple local name} { proc p {} { set z incr set foo 100 $z foo } p } {101} test incr-2.13 {incr command (not compiled): simple but new (unknown) local name} { proc p {} { set z incr $z bar } catch {p} msg set msg } {1} test incr-2.14 {incr command (not compiled): simple local name, >255 locals} { proc 260locals {} { set z incr # create 260 locals set a0 0; set a1 0; set a2 0; set a3 0; set a4 0 set a5 0; set a6 0; set a7 0; set a8 0; set a9 0 set b0 0; set b1 0; set b2 0; set b3 0; set b4 0 set b5 0; set b6 0; set b7 0; set b8 0; set b9 0 set c0 0; set c1 0; set c2 0; set c3 0; set c4 0 set c5 0; set c6 0; set c7 0; set c8 0; set c9 0 set d0 0; set d1 0; set d2 0; set d3 0; set d4 0 set d5 0; set d6 0; set d7 0; set d8 0; set d9 0 set e0 0; set e1 0; set e2 0; set e3 0; set e4 0 set e5 0; set e6 0; set e7 0; set e8 0; set e9 0 set f0 0; set f1 0; set f2 0; set f3 0; set f4 0 set f5 0; set f6 0; set f7 0; set f8 0; set f9 0 set g0 0; set g1 0; set g2 0; set g3 0; set g4 0 set g5 0; set g6 0; set g7 0; set g8 0; set g9 0 set h0 0; set h1 0; set h2 0; set h3 0; set h4 0 set h5 0; set h6 0; set h7 0; set h8 0; set h9 0 set i0 0; set i1 0; set i2 0; set i3 0; set i4 0 set i5 0; set i6 0; set i7 0; set i8 0; set i9 0 set j0 0; set j1 0; set j2 0; set j3 0; set j4 0 set j5 0; set j6 0; set j7 0; set j8 0; set j9 0 set k0 0; set k1 0; set k2 0; set k3 0; set k4 0 set k5 0; set k6 0; set k7 0; set k8 0; set k9 0 set l0 0; set l1 0; set l2 0; set l3 0; set l4 0 set l5 0; set l6 0; set l7 0; set l8 0; set l9 0 set m0 0; set m1 0; set m2 0; set m3 0; set m4 0 set m5 0; set m6 0; set m7 0; set m8 0; set m9 0 set n0 0; set n1 0; set n2 0; set n3 0; set n4 0 set n5 0; set n6 0; set n7 0; set n8 0; set n9 0 set o0 0; set o1 0; set o2 0; set o3 0; set o4 0 set o5 0; set o6 0; set o7 0; set o8 0; set o9 0 set p0 0; set p1 0; set p2 0; set p3 0; set p4 0 set p5 0; set p6 0; set p7 0; set p8 0; set p9 0 set q0 0; set q1 0; set q2 0; set q3 0; set q4 0 set q5 0; set q6 0; set q7 0; set q8 0; set q9 0 set r0 0; set r1 0; set r2 0; set r3 0; set r4 0 set r5 0; set r6 0; set r7 0; set r8 0; set r9 0 set s0 0; set s1 0; set s2 0; set s3 0; set s4 0 set s5 0; set s6 0; set s7 0; set s8 0; set s9 0 set t0 0; set t1 0; set t2 0; set t3 0; set t4 0 set t5 0; set t6 0; set t7 0; set t8 0; set t9 0 set u0 0; set u1 0; set u2 0; set u3 0; set u4 0 set u5 0; set u6 0; set u7 0; set u8 0; set u9 0 set v0 0; set v1 0; set v2 0; set v3 0; set v4 0 set v5 0; set v6 0; set v7 0; set v8 0; set v9 0 set w0 0; set w1 0; set w2 0; set w3 0; set w4 0 set w5 0; set w6 0; set w7 0; set w8 0; set w9 0 set x0 0; set x1 0; set x2 0; set x3 0; set x4 0 set x5 0; set x6 0; set x7 0; set x8 0; set x9 0 set y0 0; set y1 0; set y2 0; set y3 0; set y4 0 set y5 0; set y6 0; set y7 0; set y8 0; set y9 0 set z0 0; set z1 0; set z2 0; set z3 0; set z4 0 set z5 0; set z6 0; set z7 0; set z8 0; set z9 0 # now increment the last one (local var index > 255) $z z9 } 260locals } {1} test incr-2.15 {incr command (not compiled): variable is array} { set z incr catch {unset a} set a(foo) 27 set x [$z a(foo) 11] catch {unset a} set x } 38 test incr-2.16 {incr command (not compiled): variable is array, elem substitutions} { set z incr catch {unset a} set i 5 set a(foo5) 27 set x [$z a(foo$i) 11] catch {unset a} set x } 38 test incr-2.17 {incr command (not compiled): increment given, simple int} { set z incr set i 5 $z i 123 } 128 test incr-2.18 {incr command (not compiled): increment given, simple int} { set z incr set i 5 $z i -100 } -95 test incr-2.20 {incr command (not compiled): increment given, in quotes} { set z incr set i 25 $z i "-100" } -75 test incr-2.21 {incr command (not compiled): increment given, in braces} { set z incr set i 24 $z i {126} } 150 test incr-2.22 {incr command (not compiled): increment given, large int} { set z incr set i 5 $z i 200000 } 200005 test incr-2.23 {incr command (not compiled): increment given, formatted int != int} { set z incr set i 25 $z i 000012345 ;# an octal literal } 12370 test incr-2.24 {incr command (not compiled): increment given, formatted int != int} { set z incr set i 25 catch {$z i 1a} msg set msg } {expected integer but got "1a"} test incr-2.25 {incr command (not compiled): too many arguments} { set z incr set i 10 catch {$z i 10 20} msg set msg } {wrong # args: should be "incr varName ?increment?"} test incr-2.29 {incr command (not compiled): runtime error, bad variable value} { set z incr set x " - " list [catch {$z x 1} msg] $msg } {1 {expected integer but got " - "}} ################################################################################ # LLENGTH ################################################################################ test llength-1.1 {length of list} { llength {a b c d} } 4 test llength-1.2 {length of list} { llength {a b c {a b {c d}} d} } 5 test llength-1.3 {length of list} { llength {} } 0 test llength-2.1 {error conditions} { list [catch {llength} msg] $msg } {1 {wrong # args: should be "llength list"}} test llength-2.2 {error conditions} { list [catch {llength 123 2} msg] $msg } {1 {wrong # args: should be "llength list"}} ################################################################################ # LINDEX ################################################################################ set lindex lindex set minus - # Tests of Tcl_LindexObjCmd, NOT COMPILED #test lindex-1.1 {wrong # args} { # list [catch {eval $lindex} result] $result #} "1 {wrong # args: should be \"lindex list ?index...?\"}" # Indices that are lists or convertible to lists #test lindex-2.1 {empty index list} { # set x {} # list [eval [list $lindex {a b c} $x]] [eval [list $lindex {a b c} $x]] #} {{a b c} {a b c}} test lindex-2.2 {singleton index list} { set x { 1 } list [eval [list $lindex {a b c} $x]] [eval [list $lindex {a b c} $x]] } {b b} test lindex-2.4 {malformed index list} { set x \{ list [catch { eval [list $lindex {a b c} $x] } result] $result } {1 bad\ index\ \"\{\":\ must\ be\ integer?\[+-\]integer?\ or\ end?\[+-\]integer?} # Indices that are integers or convertible to integers test lindex-3.1 {integer -1} { set x ${minus}1 list [eval [list $lindex {a b c} $x]] [eval [list $lindex {a b c} $x]] } {{} {}} test lindex-3.2 {integer 0} { set x [string range 00 0 0] list [eval [list $lindex {a b c} $x]] [eval [list $lindex {a b c} $x]] } {a a} test lindex-3.3 {integer 2} { set x [string range 22 0 0] list [eval [list $lindex {a b c} $x]] [eval [list $lindex {a b c} $x]] } {c c} test lindex-3.4 {integer 3} { set x [string range 33 0 0] list [eval [list $lindex {a b c} $x]] [eval [list $lindex {a b c} $x]] } {{} {}} test lindex-3.7 {indexes don't shimmer wide ints} { set x [expr {(1<<31) - 2}] list $x [lindex {1 2 3} $x] [incr x] [incr x] } {2147483646 {} 2147483647 2147483648} # Indices relative to end test lindex-4.1 {index = end} { set x end list [eval [list $lindex {a b c} $x]] [eval [list $lindex {a b c} $x]] } {c c} test lindex-4.2 {index = end--1} { set x end--1 list [eval [list $lindex {a b c} $x]] [eval [list $lindex {a b c} $x]] } {{} {}} test lindex-4.3 {index = end-0} { set x end-0 list [eval [list $lindex {a b c} $x]] [eval [list $lindex {a b c} $x]] } {c c} test lindex-4.4 {index = end-2} { set x end-2 list [eval [list $lindex {a b c} $x]] [eval [list $lindex {a b c} $x]] } {a a} test lindex-4.5 {index = end-3} { set x end-3 list [eval [list $lindex {a b c} $x]] [eval [list $lindex {a b c} $x]] } {{} {}} test lindex-4.8 {bad integer, not octal} { set x end-0a2 list [catch { eval [list $lindex {a b c} $x] } result] $result } {1 {bad index "end-0a2": must be integer?[+-]integer? or end?[+-]integer?}} #test lindex-4.9 {incomplete end} { # set x en # list [eval [list $lindex {a b c} $x]] [eval [list $lindex {a b c} $x]] #} {c c} test lindex-4.10 {incomplete end-} { set x end- list [catch { eval [list $lindex {a b c} $x] } result] $result } {1 {bad index "end-": must be integer?[+-]integer? or end?[+-]integer?}} test lindex-5.1 {bad second index} { list [catch { eval [list $lindex {a b c} 0 0a2] } result] $result } {1 {bad index "0a2": must be integer?[+-]integer? or end?[+-]integer?}} test lindex-5.2 {good second index} { eval [list $lindex {{a b c} {d e f} {g h i}} 1 2] } f test lindex-5.3 {three indices} { eval [list $lindex {{{a b} {c d}} {{e f} {g h}}} 1 0 1] } f test lindex-7.1 {quoted elements} { eval [list $lindex {a "b c" d} 1] } {b c} test lindex-7.2 {quoted elements} { eval [list $lindex {"{}" b c} 0] } {{}} test lindex-7.3 {quoted elements} { eval [list $lindex {ab "c d \" x" y} 1] } {c d " x} test lindex-7.4 {quoted elements} { lindex {a b {c d "e} {f g"}} 2 } {c d "e} test lindex-8.1 {data reuse} { set x 0 eval [list $lindex $x $x] } {0} test lindex-8.2 {data reuse} { set a 0 eval [list $lindex $a $a $a] } 0 test lindex-8.3 {data reuse} { set a 1 eval [list $lindex $a $a $a] } {} #---------------------------------------------------------------------- test lindex-10.2 {singleton index list} { set x { 1 } catch { list [lindex {a b c} $x] [lindex {a b c} $x] } result set result } {b b} test lindex-10.4 {malformed index list} { set x \{ list [catch { lindex {a b c} $x } result] $result } {1 bad\ index\ \"\{\":\ must\ be\ integer?\[+-\]integer?\ or\ end?\[+-\]integer?} # Indices that are integers or convertible to integers test lindex-11.1 {integer -1} { set x ${minus}1 catch { list [lindex {a b c} $x] [lindex {a b c} $x] } result set result } {{} {}} test lindex-11.2 {integer 0} { set x [string range 00 0 0] catch { list [lindex {a b c} $x] [lindex {a b c} $x] } result set result } {a a} test lindex-11.3 {integer 2} { set x [string range 22 0 0] catch { list [lindex {a b c} $x] [lindex {a b c} $x] } result set result } {c c} test lindex-11.4 {integer 3} { set x [string range 33 0 0] catch { list [lindex {a b c} $x] [lindex {a b c} $x] } result set result } {{} {}} # Indices relative to end test lindex-12.1 {index = end} { set x end catch { list [lindex {a b c} $x] [lindex {a b c} $x] } result set result } {c c} test lindex-12.2 {index = end--1} { set x end--1 catch { list [lindex {a b c} $x] [lindex {a b c} $x] } result set result } {{} {}} test lindex-12.3 {index = end-0} { set x end-0 catch { list [lindex {a b c} $x] [lindex {a b c} $x] } result set result } {c c} test lindex-12.4 {index = end-2} { set x end-2 catch { list [lindex {a b c} $x] [lindex {a b c} $x] } result set result } {a a} test lindex-12.5 {index = end-3} { set x end-3 catch { list [lindex {a b c} $x] [lindex {a b c} $x] } result set result } {{} {}} test lindex-12.8 {bad integer, not octal} { set x end-0a2 list [catch { lindex {a b c} $x } result] $result } {1 {bad index "end-0a2": must be integer?[+-]integer? or end?[+-]integer?}} test lindex-12.10 {incomplete end-} { set x end- list [catch { lindex {a b c} $x } result] $result } {1 {bad index "end-": must be integer?[+-]integer? or end?[+-]integer?}} test lindex-13.1 {bad second index} { list [catch { lindex {a b c} 0 0a2 } result] $result } {1 {bad index "0a2": must be integer?[+-]integer? or end?[+-]integer?}} test lindex-13.2 {good second index} { catch { lindex {{a b c} {d e f} {g h i}} 1 2 } result set result } f test lindex-13.3 {three indices} { catch { lindex {{{a b} {c d}} {{e f} {g h}}} 1 0 1 } result set result } f test lindex-15.1 {quoted elements} { catch { lindex {a "b c" d} 1 } result set result } {b c} test lindex-15.2 {quoted elements} { catch { lindex {"{}" b c} 0 } result set result } {{}} test lindex-15.3 {quoted elements} { catch { lindex {ab "c d \" x" y} 1 } result set result } {c d " x} test lindex-15.4 {quoted elements} { catch { lindex {a b {c d "e} {f g"}} 2 } result set result } {c d "e} test lindex-16.1 {data reuse} { set x 0 catch { lindex $x $x } result set result } {0} test lindex-16.2 {data reuse} { set a 0 catch { lindex $a $a $a } result set result } 0 test lindex-16.3 {data reuse} { set a 1 catch { lindex $a $a $a } result set result } {} catch { unset lindex} catch { unset minus } ################################################################################ # LINDEX ################################################################################ catch {unset a} catch {unset x} # Basic "foreach" operation. test foreach-1.1 {basic foreach tests} { set a {} foreach i {a b c d} { set a [concat $a $i] } set a } {a b c d} test foreach-1.2 {basic foreach tests} { set a {} foreach i {a b {{c d} e} {123 {{x}}}} { set a [concat $a $i] } set a } {a b {c d} e 123 {{x}}} test foreach-1.3 {basic foreach tests} {catch {foreach} msg} 1 test foreach-1.4 {basic foreach tests} {catch {foreach i} msg} 1 test foreach-1.5 {basic foreach tests} {catch {foreach i j} msg} 1 test foreach-1.6 {basic foreach tests} {catch {foreach i j k l} msg} 1 test foreach-1.7 {basic foreach tests} { set a {} foreach i {} { set a [concat $a $i] } set a } {} catch {unset a} test foreach-2.1 {foreach errors} { list [catch {foreach {} {} {}} msg] $msg } {1 {foreach varlist is empty}} catch {unset a} test foreach-3.1 {parallel foreach tests} { set x {} foreach {a b} {1 2 3 4} { append x $b $a } set x } {2143} test foreach-3.2 {parallel foreach tests} { set x {} foreach {a b} {1 2 3 4 5} { append x $b $a } set x } {21435} test foreach-3.3 {parallel foreach tests} { set x {} foreach a {1 2 3} b {4 5 6} { append x $b $a } set x } {415263} test foreach-3.4 {parallel foreach tests} { set x {} foreach a {1 2 3} b {4 5 6 7 8} { append x $b $a } set x } {41526378} test foreach-3.5 {parallel foreach tests} { set x {} foreach {a b} {a b A B aa bb} c {c C cc CC} { append x $a $b $c } set x } {abcABCaabbccCC} test foreach-3.6 {parallel foreach tests} { set x {} foreach a {1 2 3} b {1 2 3} c {1 2 3} d {1 2 3} e {1 2 3} { append x $a $b $c $d $e } set x } {111112222233333} test foreach-3.7 {parallel foreach tests} { set x {} foreach a {} b {1 2 3} c {1 2} d {1 2 3 4} e {{1 2}} { append x $a $b $c $d $e } set x } {1111 2222334} test foreach-4.1 {foreach only sets vars if repeating loop} { proc foo {} { set rgb {65535 0 0} foreach {r g b} [set rgb] {} return "r=$r, g=$g, b=$b" } foo } {r=65535, g=0, b=0} test foreach-5.1 {foreach supports dict syntactic sugar} { proc foo {} { set x {} foreach {a(3)} {1 2 3 4} {lappend x [set {a(3)}]} list $a $x } foo } {{3 4} {1 2 3 4}} test foreach-6.1 {noncompiled foreach and shared variable or value list objects that are converted to another type} { catch {unset x} foreach {12.0} {a b c} { set x 12.0 set x [expr $x + 1] } set x } 13.0 # Check "continue". test foreach-7.1 {continue tests} {catch continue} 4 test foreach-7.2 {continue tests} { set a {} foreach i {a b c d} { if {[string compare $i "b"] == 0} continue set a [concat $a $i] } set a } {a c d} test foreach-7.3 {continue tests} { set a {} foreach i {a b c d} { if {[string compare $i "b"] != 0} continue set a [concat $a $i] } set a } {b} test foreach-7.4 {continue tests} {catch {continue foo} msg} 1 test foreach-7.5 {continue tests} { catch {continue foo} msg set msg } {wrong # args: should be "continue"} # Check "break". test foreach-8.1 {break tests} {catch break} 3 test foreach-8.2 {break tests} { set a {} foreach i {a b c d} { if {[string compare $i "c"] == 0} break set a [concat $a $i] } set a } {a b} test foreach-8.3 {break tests} {catch {break foo} msg} 1 test foreach-8.4 {break tests} { catch {break foo} msg set msg } {wrong # args: should be "break"} # Test for incorrect "double evaluation" semantics test foreach-9.1 {delayed substitution of body - knownbugs} { proc foo {} { set a 0 foreach a [list 1 2 3] " set x $a " set x } foo } {0} # cleanup catch {unset a} catch {unset x} ################################################################################ # STRING ################################################################################ # string last test string-7.1 {string last, too few args} { list [catch {string last a} msg] $msg } {1 {wrong # args: should be "string last subString string ?index?"}} test string-7.2 {string last, bad args} { list [catch {string last a b c} msg] $msg } {1 {bad index "c": must be integer?[+-]integer? or end?[+-]integer?}} test string-7.3 {string last, too many args} { list [catch {string last a b c d} msg] $msg } {1 {wrong # args: should be "string last subString string ?index?"}} test string-7.5 {string last} { string last xx xxxx123xx345x678 } 7 test string-7.13 {string last, start index} { ## Constrain to last 'a' should work string last ba badbad end-1 } 3 test string-7.14 {string last, start index} { ## Constrain to last 'b' should skip last 'ba' string last ba badbad end-2 } 0 ## string match ## test string-11.1 {string match, too few args} { proc foo {} {string match a} list [catch {foo} msg] $msg } {1 {wrong # args: should be "string match ?-nocase? pattern string"}} test string-11.2 {string match, too many args} { proc foo {} {string match a b c d} list [catch {foo} msg] $msg } {1 {wrong # args: should be "string match ?-nocase? pattern string"}} test string-11.3 {string match} { proc foo {} {string match abc abc} foo } 1 #test string-11.4 {string match} { # proc foo {} {string mat abc abd} # foo #} 0 test string-11.5 {string match} { proc foo {} {string match ab*c abc} foo } 1 test string-11.6 {string match} { proc foo {} {string match ab**c abc} foo } 1 test string-11.7 {string match} { proc foo {} {string match ab* abcdef} foo } 1 test string-11.8 {string match} { proc foo {} {string match *c abc} foo } 1 test string-11.9 {string match} { proc foo {} {string match *3*6*9 0123456789} foo } 1 test string-11.10 {string match} { proc foo {} {string match *3*6*9 01234567890} foo } 0 test string-11.11 {string match} { proc foo {} {string match a?c abc} foo } 1 test string-11.12 {string match} { proc foo {} {string match a??c abc} foo } 0 test string-11.13 {string match} { proc foo {} {string match ?1??4???8? 0123456789} foo } 1 test string-11.14 {string match} { proc foo {} {string match {[abc]bc} abc} foo } 1 test string-11.15 {string match} { proc foo {} {string match {a[abc]c} abc} foo } 1 test string-11.16 {string match} { proc foo {} {string match {a[xyz]c} abc} foo } 0 test string-11.17 {string match} { proc foo {} {string match {12[2-7]45} 12345} foo } 1 test string-11.18 {string match} { proc foo {} {string match {12[ab2-4cd]45} 12345} foo } 1 test string-11.19 {string match} { proc foo {} {string match {12[ab2-4cd]45} 12b45} foo } 1 test string-11.20 {string match} { proc foo {} {string match {12[ab2-4cd]45} 12d45} foo } 1 test string-11.21 {string match} { proc foo {} {string match {12[ab2-4cd]45} 12145} foo } 0 test string-11.22 {string match} { proc foo {} {string match {12[ab2-4cd]45} 12545} foo } 0 test string-11.23 {string match} { proc foo {} {string match {a\*b} a*b} foo } 1 test string-11.24 {string match} { proc foo {} {string match {a\*b} ab} foo } 0 test string-11.25 {string match} { proc foo {} {string match {a\*\?\[\]\\\x} "a*?\[\]\\x"} foo } 1 test string-11.26 {string match} { proc foo {} {string match ** ""} foo } 1 test string-11.27 {string match} { proc foo {} {string match *. ""} foo } 0 test string-11.28 {string match} { proc foo {} {string match "" ""} foo } 1 test string-11.29 {string match} { proc foo {} {string match \[a a} foo } 1 test string-11.31 {string match case} { proc foo {} {string match a A} foo } 0 test string-11.32 {string match nocase} { proc foo {} {string match -n a A} foo } 1 #test string-11.33 {string match nocase} { # proc foo {} {string match -nocase a\334 A\374} # foo #} 1 test string-11.34 {string match nocase} { proc foo {} {string match -nocase a*f ABCDEf} foo } 1 test string-11.35 {string match case, false hope} { # This is true because '_' lies between the A-Z and a-z ranges proc foo {} {string match {[A-z]} _} foo } 1 test string-11.36 {string match nocase range} { # This is false because although '_' lies between the A-Z and a-z ranges, # we lower case the end points before checking the ranges. proc foo {} {string match -nocase {[A-z]} _} foo } 0 test string-11.37 {string match nocase} { proc foo {} {string match -nocase {[A-fh-Z]} g} foo } 0 test string-11.38 {string match case, reverse range} { proc foo {} {string match {[A-fh-Z]} g} foo } 1 test string-11.39 {string match, *\ case} { proc foo {} {string match {*\abc} abc} foo } 1 test string-11.40 {string match, *special case} { proc foo {} {string match {*[ab]} abc} foo } 0 test string-11.41 {string match, *special case} { proc foo {} {string match {*[ab]*} abc} foo } 1 #test string-11.42 {string match, *special case} { # proc foo {} {string match "*\\" "\\"} # foo #} 0 test string-11.43 {string match, *special case} { proc foo {} {string match "*\\\\" "\\"} foo } 1 test string-11.44 {string match, *special case} { proc foo {} {string match "*???" "12345"} foo } 1 test string-11.45 {string match, *special case} { proc foo {} {string match "*???" "12"} foo } 0 test string-11.46 {string match, *special case} { proc foo {} {string match "*\\*" "abc*"} foo } 1 test string-11.47 {string match, *special case} { proc foo {} {string match "*\\*" "*"} foo } 1 test string-11.48 {string match, *special case} { proc foo {} {string match "*\\*" "*abc"} foo } 0 test string-11.49 {string match, *special case} { proc foo {} {string match "?\\*" "a*"} foo } 1 #test string-11.50 {string match, *special case} { # proc foo {} {string match "\\" "\\"} # foo #} 0 ## string length ## test string-9.1 {string length} { proc foo {} {string length} list [catch {foo} msg] $msg } {1 {wrong # args: should be "string length string"}} test string-9.2 {string length} { proc foo {} {string length a b} list [catch {foo} msg] $msg } {1 {wrong # args: should be "string length string"}} test string-9.3 {string length} { proc foo {} {string length "a little string"} foo } 15 # string map test string-10.4 {string map} { string map {a b} abba } {bbbb} test string-10.5 {string map} { string map {a b} a } {b} test string-10.6 {string map -nocase} { string map -nocase {a b} Abba } {bbbb} test string-10.7 {string map} { string map {abc 321 ab * a A} aabcabaababcab } {A321*A*321*} test string-10.8 {string map -nocase} { string map -nocase {aBc 321 Ab * a A} aabcabaababcab } {A321*A*321*} test string-10.10 {string map} { list [catch {string map {a b c} abba} msg] $msg } {1 {list must contain an even number of elements}} test string-10.11 {string map, nulls} { string map {\x00 NULL blah \x00nix} {qwerty} } {qwerty} test string-10.12 {string map, unicode} { string map [list \u00fc ue UE \u00dc] "a\u00fcueUE\000EU" } aueue\u00dc\0EU test string-10.13 {string map, -nocase unicode} { string map -nocase [list \u00fc ue UE \u00dc] "a\u00fcueUE\000EU" } aue\u00dc\u00dc\0EU test string-10.14 {string map, -nocase null arguments} { string map -nocase {{} abc} foo } foo test string-10.15 {string map, one pair case} { string map -nocase {abc 32} aAbCaBaAbAbcAb } {a32aBaAb32Ab} test string-10.16 {string map, one pair case} { string map -nocase {ab 4321} aAbCaBaAbAbcAb } {a4321C4321a43214321c4321} test string-10.17 {string map, one pair case} { string map {Ab 4321} aAbCaBaAbAbcAb } {a4321CaBa43214321c4321} test string-10.18 {string map, empty argument} { string map -nocase {{} abc} foo } foo test string-10.19 {string map, empty arguments} { string map -nocase {{} abc f bar {} def} foo } baroo ################################################################################ # SPLIT ################################################################################ test split-1.1 {basic split commands} { split "a\n b\t\r c\n " } {a {} b {} {} c {} {}} test split-1.2 {basic split commands} { split "word 1xyzword 2zword 3" xyz } {{word 1} {} {} {word 2} {word 3}} test split-1.3 {basic split commands} { split "12345" {} } {1 2 3 4 5} test split-1.4 {basic split commands} { split "a\}b\[c\{\]\$" } "a\\}b\\\[c\\{\\\]\\\$" test split-1.5 {basic split commands} { split {} {} } {} test split-1.6 {basic split commands} { split {} } {} test split-1.7 {basic split commands} { split { } } {{} {} {} {}} test split-1.8 {basic split commands} { proc foo {} { set x {} foreach f [split {]\n} {}] { append x $f } return $x } foo } {]\n} test split-1.9 {basic split commands} { proc foo {} { set x ab\000c set y [split $x {}] return $y } foo } "a b \000 c" test split-1.10 {basic split commands} { split "a0ab1b2bbb3\000c4" ab\000c } {{} 0 {} 1 2 {} {} 3 {} 4} test split-1.11 {basic split commands} { split "12,3,45" {,} } {12 3 45} test split-1.12 {basic split commands} { split "\u0001ab\u0001cd\u0001\u0001ef\u0001" \1 } {{} ab cd {} ef {}} test split-1.13 {basic split commands} { split "12,34,56," {,} } {12 34 56 {}} test split-1.14 {basic split commands} { split ",12,,,34,56," {,} } {{} 12 {} {} 34 56 {}} test split-2.1 {split errors} { list [catch split msg] $msg } {1 {wrong # args: should be "split string ?splitChars?"}} test split-2.2 {split errors} { list [catch {split a b c} msg] $msg } {1 {wrong # args: should be "split string ?splitChars?"}} # cleanup catch {rename foo {}} ################################################################################ # JOIN ################################################################################ test join-1.1 {basic join commands} { join {a b c} xyz } axyzbxyzc test join-1.2 {basic join commands} { join {a b c} {} } abc test join-1.3 {basic join commands} { join {} xyz } {} test join-1.4 {basic join commands} { join {12 34 56} } {12 34 56} test join-2.1 {join errors} { list [catch join msg] $msg } {1 {wrong # args: should be "join list ?joinString?"}} test join-2.2 {join errors} { list [catch {join a b c} msg] $msg } {1 {wrong # args: should be "join list ?joinString?"}} #test join-2.3 {join errors} { # list [catch {join "a \{ c" 111} msg] $msg #} {1 {unmatched open brace in list}} test join-3.1 {joinString is binary ok} { string length [join {a b c} a\0b] } 9 test join-3.2 {join is binary ok} { string length [join "a\0b a\0b a\0b"] } 11 ################################################################################ # SWITCH ################################################################################ test switch-1.1 {simple patterns} { switch a a {expr 1} b {expr 2} c {expr 3} default {expr 4} } 1 test switch-1.2 {simple patterns} { switch b a {expr 1} b {expr 2} c {expr 3} default {expr 4} } 2 test switch-1.3 {simple patterns} { switch x a {expr 1} b {expr 2} c {expr 3} default {expr 4} } 4 test switch-1.4 {simple patterns} { switch x a {expr 1} b {expr 2} c {expr 3} } {} test switch-1.5 {simple pattern matches many times} { switch b a {expr 1} b {expr 2} b {expr 3} b {expr 4} } 2 test switch-1.6 {simple patterns} { switch default a {expr 1} default {expr 2} c {expr 3} default {expr 4} } 2 test switch-1.7 {simple patterns} { switch x a {expr 1} default {expr 2} c {expr 3} default {expr 4} } 4 test switch-2.1 {single-argument form for pattern/command pairs} { switch b { a {expr 1} b {expr 2} default {expr 6} } } {2} test switch-2.2 {single-argument form for pattern/command pairs} { list [catch {switch z {a 2 b}}] } 1 test switch-3.1 {-exact vs. -glob vs. -regexp} { switch -exact aaaab { ^a*b$ {concat regexp} *b {concat glob} aaaab {concat exact} default {concat none} } } exact test switch-3.2 {-exact vs. -glob vs. -regexp (no [regexp] cmd)} regexp { rename regexp regexp.none set rc [catch { switch -regexp aaaab { ^a*b$ {concat regexp} *b {concat glob} aaaab {concat exact} default {concat none} } }] rename regexp.none regexp set rc } 1 test switch-3.3 {-exact vs. -glob vs. -regexp (with [regexp] cmd)} regexp { switch -regexp aaaab { ^a*b$ {concat regexp} *b {concat glob} aaaab {concat exact} default {concat none} } } regexp test switch-3.4 {-exact vs. -glob vs. -regexp} { switch -glob aaaab { ^a*b$ {concat regexp} *b {concat glob} aaaab {concat exact} default {concat none} } } glob test switch-3.5 {-exact vs. -glob vs. -regexp} { switch aaaab {^a*b$} {concat regexp} *b {concat glob} \ aaaab {concat exact} default {concat none} } exact test switch-3.6 {-exact vs. -glob vs. -regexp} { switch -- -glob { ^g.*b$ {concat regexp} -* {concat glob} -glob {concat exact} default {concat none} } } exact test switch-3.7 {-exact vs. -glob vs. -regexp} { list [catch {switch -foo a b c} msg] $msg } {1 {bad option "-foo": must be -exact, -glob, -regexp, -command procname or --}} test switch-4.1 {error in executed command} { list [catch {switch a a {error "Just a test"} default {expr 1}} msg] \ $msg } {1 {Just a test}} test switch-4.2 {error: not enough args} { catch {switch} } 1 test switch-4.3 {error: pattern with no body} { catch {switch a b} } 1 test switch-4.4 {error: pattern with no body} { catch {switch a b {expr 1} c} } 1 test switch-4.5 {error in default command} { list [catch {switch foo a {error switch1} b {error switch 3} \ default {error switch2}} msg] $msg } {1 switch2} test switch-5.1 {errors in -regexp matching} regexp { catch {switch -regexp aaaab { *b {concat glob} aaaab {concat exact} default {concat none} }} msg } 1 test switch-6.1 {backslashes in patterns} { switch -exact {\a\$\.\[} { \a\$\.\[ {concat first} \a\\$\.\\[ {concat second} \\a\\$\\.\\[ {concat third} {\a\\$\.\\[} {concat fourth} {\\a\\$\\.\\[} {concat fifth} default {concat none} } } third test switch-6.2 {backslashes in patterns} { switch -exact {\a\$\.\[} { \a\$\.\[ {concat first} {\a\$\.\[} {concat second} {{\a\$\.\[}} {concat third} default {concat none} } } second test switch-7.1 {"-" bodies} { switch a { a - b - c {concat 1} default {concat 2} } } 1 test switch-7.2 {"-" bodies} { list [catch { switch a { a - b - c - } } msg] $msg } {1 {no body specified for pattern "c"}} # Following original Tcl test makes no sense, I feel! Please review ... #~ test switch-7.3 {"-" bodies} { #~ list [catch { #~ switch a { #~ a - #~ b -foo #~ c - #~ } #~ } msg] $msg #~ } {1 {no body specified for pattern "c"}} test switch-7.3 {"-" bodies} { list [catch { switch a { a - b -foo c - } } msg] $msg } {1 {invalid command name "-foo"}} test switch-8.1 {empty body} { set msg {} switch {2} { 1 {set msg 1} 2 {} default {set msg 2} } } {} test switch-9.1 {empty pattern/body list} { catch {switch x} } 1 test switch-9.2 {empty pattern/body list} { catch {switch -- x} } 1 test switch-9.3 {empty pattern/body list} { catch {switch x {}} } 1 test switch-9.4 {empty pattern/body list} { catch {switch -- x {}} } 1 test switch-9.5 {unpaired pattern} { catch {switch x a {} b} } 1 test switch-9.6 {unpaired pattern} { catch {switch x {a {} b}} } 1 test switch-9.7 {unpaired pattern} { catch {switch x a {} # comment b} } 1 test switch-9.8 {unpaired pattern} { catch {switch x {a {} # comment b}} } 1 test switch-9.9 {unpaired pattern} { catch {switch x a {} x {} # comment b} } 1 test switch-9.10 {unpaired pattern} { catch {switch x {a {} x {} # comment b}} } 1 test switch-10.1 {no callback given to -command} { catch {switch -command a { a {expr 1} b {expr 2} }} } 1 test switch-10.2 {callback expect wrong # args for -command} lambda { catch {switch -command [lambda {p1} {expr 1}] a { a {expr 1} b {expr 2} }} } 1 test switch-10.3 {callback to -command returns ever 0: no match} lambda { switch -command [lambda {p1 p2} {expr 0}] a a {expr 1} b {expr 2} } {} test switch-10.4 {callback to -command returns 3 at first match} lambda { switch -command [lambda {p1 p2} {expr 3}] a a {expr 1} b {expr 2} } 1 test switch-10.5 {[error] in callback to -command} lambda { list [catch { switch -command [lambda {p1 p2} {error "foo"}] a a {expr 1} b {expr 2} } msg] $msg } {1 foo} test switch-10.6 {[continue] in callback to -command} lambda { list [catch { switch -command [lambda {p1 p2} {continue}] a a {expr 1} b {expr 2} } msg] $msg } {4 {}} test switch-10.7 {callback matches first if pat < str} lambda { switch -command [lambda {pat str} {expr {$pat < $str}}] 3 \ 5 {expr 1} 3 {expr 2} } {} test switch-10.8 {callback matches first if pat < str} lambda { switch -command [lambda {pat str} {expr {$pat < $str}}] 7 \ 5 {expr 1} 3 {expr 2} } 1 test switch-10.9 {callback matches first if pat < str} lambda { switch -command [lambda {pat str} {expr {$pat < $str}}] 4 \ 5 {expr 1} 3 {expr 2} } 2 ################################################################################ # FOR ################################################################################ # Basic "for" operation. test for-1.1 {TclCompileForCmd: missing initial command} { list [catch {for} msg] $msg } {1 {wrong # args: should be "for start test next body"}} test for-1.2 {TclCompileForCmd: error in initial command} { list [catch {for {set}} msg] $msg } {1 {wrong # args: should be "for start test next body"}} catch {unset i} test for-1.3 {TclCompileForCmd: missing test expression} { catch {for {set i 0}} msg set msg } {wrong # args: should be "for start test next body"} test for-1.5 {TclCompileForCmd: test expression is enclosed in quotes} { set i 0 for {} "$i > 5" {incr i} {} } {} test for-1.6 {TclCompileForCmd: missing "next" command} { catch {for {set i 0} {$i < 5}} msg set msg } {wrong # args: should be "for start test next body"} test for-1.7 {TclCompileForCmd: missing command body} { catch {for {set i 0} {$i < 5} {incr i}} msg set msg } {wrong # args: should be "for start test next body"} catch {unset a} test for-1.9 {TclCompileForCmd: simple command body} { set a {} for {set i 1} {$i<6} {set i [expr $i+1]} { if $i==4 break set a [concat $a $i] } set a } {1 2 3} test for-1.10 {TclCompileForCmd: command body in quotes} { set a {} for {set i 1} {$i<6} {set i [expr $i+1]} "append a x" set a } {xxxxx} test for-1.11 {TclCompileForCmd: computed command body} { catch {unset x1} catch {unset bb} catch {unset x2} set x1 {append a x1; } set bb {break} set x2 {; append a x2} set a {} for {set i 1} {$i<6} {set i [expr $i+1]} $x1$bb$x2 set a } {x1} test for-1.13 {TclCompileForCmd: long command body} { set a {} for {set i 1} {$i<6} {set i [expr $i+1]} { if $i==4 break if $i>5 continue set tcl_platform(machine) i686 if {$i>6 && $tcl_platform(machine) eq "xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine) eq "xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine) eq "xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine) eq "xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine) eq "xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } set a [concat $a $i] } set a } {1 2 3} test for-1.14 {TclCompileForCmd: for command result} { set a [for {set i 0} {$i < 5} {incr i} {}] set a } {} test for-1.15 {TclCompileForCmd: for command result} { set a [for {set i 0} {$i < 5} {incr i} {if $i==3 break}] set a } {} # Check "for" and "continue". test for-2.1 {TclCompileContinueCmd: arguments after "continue"} { catch {continue foo} msg set msg } {wrong # args: should be "continue"} test for-2.2 {TclCompileContinueCmd: continue result} { catch continue } 4 test for-2.3 {continue tests} { set a {} for {set i 1} {$i <= 4} {set i [expr $i+1]} { if {$i == 2} continue set a [concat $a $i] } set a } {1 3 4} test for-2.4 {continue tests} { set a {} for {set i 1} {$i <= 4} {set i [expr $i+1]} { if {$i != 2} continue set a [concat $a $i] } set a } {2} test for-2.5 {continue tests, nested loops} { set msg {} for {set i 1} {$i <= 4} {incr i} { for {set a 1} {$a <= 2} {incr a} { if {$i>=2 && $a>=2} continue set msg [concat $msg "$i.$a"] } } set msg } {1.1 1.2 2.1 3.1 4.1} test for-2.6 {continue tests, long command body} { set a {} for {set i 1} {$i<6} {set i [expr $i+1]} { if $i==2 continue if $i==4 break if $i>5 continue if {$i>6 && $tcl_platform(machine) eq "xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine) eq "xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine) eq "xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine) eq "xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine) eq "xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } set a [concat $a $i] } set a } {1 3} # Check "for" and "break". test for-3.1 {TclCompileBreakCmd: arguments after "break"} { catch {break foo} msg set msg } {wrong # args: should be "break"} test for-3.2 {TclCompileBreakCmd: break result} { catch break } 3 test for-3.3 {break tests} { set a {} for {set i 1} {$i <= 4} {incr i} { if {$i == 3} break set a [concat $a $i] } set a } {1 2} test for-3.4 {break tests, nested loops} { set msg {} for {set i 1} {$i <= 4} {incr i} { for {set a 1} {$a <= 2} {incr a} { if {$i>=2 && $a>=2} break set msg [concat $msg "$i.$a"] } } set msg } {1.1 1.2 2.1 3.1 4.1} test for-3.5 {break tests, long command body} { set a {} for {set i 1} {$i<6} {set i [expr $i+1]} { if $i==2 continue if $i==5 break if $i>5 continue if {$i>6 && $tcl_platform(machine) eq "xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine) eq "xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine) eq "xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i == 4} break if {$i>6 && $tcl_platform(machine) eq "xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine) eq "xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } set a [concat $a $i] } set a } {1 3} test for-4.1 {break must reset the interp result} { catch { set z GLOBTESTDIR/dir2/file2.c if [string match GLOBTESTDIR/dir2/* $z] { break } } j set j } {} # Test for incorrect "double evaluation" semantics test for-5.1 {possible delayed substitution of increment command} { # Increment should be 5, and lappend should always append $a catch {unset a} catch {unset i} set a 5 set i {} for {set a 1} {$a < 12} "incr a $a" {lappend i $a} set i } {1 6 11} test for-5.2 {possible delayed substitution of increment command} { # Increment should be 5, and lappend should always append $a catch {rename p ""} proc p {} { set a 5 set i {} for {set a 1} {$a < 12} "incr a $a" {lappend i $a} set i } p } {1 6 11} test for-5.3 {possible delayed substitution of body command} { # Increment should be $a, and lappend should always append 5 set a 5 set i {} for {set a 1} {$a < 12} {incr a $a} "lappend i $a" set i } {5 5 5 5} test for-5.4 {possible delayed substitution of body command} { # Increment should be $a, and lappend should always append 5 catch {rename p ""} proc p {} { set a 5 set i {} for {set a 1} {$a < 12} {incr a $a} "lappend i $a" set i } p } {5 5 5 5} # In the following tests we need to bypass the bytecode compiler by # substituting the command from a variable. This ensures that command # procedure is invoked directly. test for-6.1 {Tcl_ForObjCmd: number of args} { set z for catch {$z} msg set msg } {wrong # args: should be "for start test next body"} test for-6.2 {Tcl_ForObjCmd: number of args} { set z for catch {$z {set i 0}} msg set msg } {wrong # args: should be "for start test next body"} test for-6.3 {Tcl_ForObjCmd: number of args} { set z for catch {$z {set i 0} {$i < 5}} msg set msg } {wrong # args: should be "for start test next body"} test for-6.4 {Tcl_ForObjCmd: number of args} { set z for catch {$z {set i 0} {$i < 5} {incr i}} msg set msg } {wrong # args: should be "for start test next body"} test for-6.5 {Tcl_ForObjCmd: number of args} { set z for catch {$z {set i 0} {$i < 5} {incr i} {body} extra} msg set msg } {wrong # args: should be "for start test next body"} test for-6.6 {Tcl_ForObjCmd: error in initial command} { set z for list [catch {$z {set} {$i < 5} {incr i} {body}} msg] $msg } {1 {wrong # args: should be "set varName ?newValue?"}} test for-6.8 {Tcl_ForObjCmd: test expression is enclosed in quotes} { set z for set i 0 $z {set i 6} "$i > 5" {incr i} {set y $i} set i } 6 test for-6.10 {Tcl_ForObjCmd: simple command body} { set z for set a {} $z {set i 1} {$i<6} {set i [expr $i+1]} { if $i==4 break set a [concat $a $i] } set a } {1 2 3} test for-6.11 {Tcl_ForObjCmd: command body in quotes} { set z for set a {} $z {set i 1} {$i<6} {set i [expr $i+1]} "append a x" set a } {xxxxx} test for-6.12 {Tcl_ForObjCmd: computed command body} { set z for catch {unset x1} catch {unset bb} catch {unset x2} set x1 {append a x1; } set bb {break} set x2 {; append a x2} set a {} $z {set i 1} {$i<6} {set i [expr $i+1]} $x1$bb$x2 set a } {x1} test for-6.14 {Tcl_ForObjCmd: long command body} { set z for set a {} $z {set i 1} {$i<6} {set i [expr $i+1]} { if $i==4 break if $i>5 continue if {$i>6 && $tcl_platform(machine) eq "xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine) eq "xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine) eq "xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine) eq "xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } if {$i>6 && $tcl_platform(machine) eq "xxx"} { catch {set a $a} msg catch {incr i 5} msg catch {incr i -5} msg } set a [concat $a $i] } set a } {1 2 3} test for-6.15 {Tcl_ForObjCmd: for command result} { set z for set a [$z {set i 0} {$i < 5} {incr i} {}] set a } {} test for-6.16 {Tcl_ForObjCmd: for command result} { set z for set a [$z {set i 0} {$i < 5} {incr i} {if $i==3 break}] set a } {} ################################################################################ # INFO ################################################################################ test info-1.1 {info body option} { proc t1 {} {body of t1} info body t1 } {body of t1} test info-1.2 {info body option} { list [catch {info body set} msg] $msg } {1 {command "set" is not a procedure}} test info-1.3 {info body option} { list [catch {info args set 1} msg] $msg } {1 {wrong # args: should be "info args procname"}} test info-1.5 {info body option, returning bytecompiled bodies} { catch {unset args} proc foo {args} { foreach v $args { upvar $v var return "variable $v existence: [info exists var]" } } foo a list [catch [info body foo] msg] $msg } {1 {can't read "args": no such variable}} test info-1.6 {info body option, returning list bodies} { proc foo args [list subst bar] list [string length [info body foo]] \ [foo; string length [info body foo]] } {9 9} test info-2.1 {info commands option} { proc t1 {} {} proc t2 {} {} set x " [info commands] " list [string match {* t1 *} $x] [string match {* t2 *} $x] \ [string match {* set *} $x] [string match {* list *} $x] } {1 1 1 1} test info-2.2 {info commands option} { proc t1 {} {} rename t1 {} set x [info commands] string match {* t1 *} $x } 0 test info-2.3 {info commands option} { proc _test1_ {} {} proc _test2_ {} {} info commands _test1_ } _test1_ test info-2.4 {info commands option} { proc _test1_ {} {} proc _test2_ {} {} lsort [info commands _test*] } {_test1_ _test2_} catch {rename _test1_ {}} catch {rename _test2_ {}} test info-2.5 {info commands option} { list [catch {info commands a b} msg] $msg } {1 {wrong # args: should be "info commands ?pattern?"}} test info-3.1 {info exists option} { set value foo info exists value } 1 catch {unset _nonexistent_} test info-3.2 {info exists option} { info exists _nonexistent_ } 0 test info-3.3 {info exists option} { proc t1 {x} {return [info exists x]} t1 2 } 1 test info-3.4 {info exists option} { proc t1 {x} { global _nonexistent_ return [info exists _nonexistent_] } t1 2 } 0 test info-3.5 {info exists option} { proc t1 {x} { set y 47 return [info exists y] } t1 2 } 1 test info-3.6 {info exists option} { proc t1 {x} {return [info exists value]} t1 2 } 0 test info-3.7 {info exists option} { catch {unset x} set x(2) 44 list [info exists x] [info exists x(1)] [info exists x(2)] } {1 0 1} catch {unset x} test info-3.8 {info exists option} { list [catch {info exists} msg] $msg } {1 {wrong # args: should be "info exists varName"}} test info-3.9 {info exists option} { list [catch {info exists 1 2} msg] $msg } {1 {wrong # args: should be "info exists varName"}} test info-4.1 {info globals option} { set x 1 set y 2 set value 23 set a " [info globals] " list [string match {* x *} $a] [string match {* y *} $a] \ [string match {* value *} $a] [string match {* _foobar_ *} $a] } {1 1 1 0} test info-4.2 {info globals option} { set _xxx1 1 set _xxx2 2 lsort [info globals _xxx*] } {_xxx1 _xxx2} test info-4.3 {info globals option} { list [catch {info globals 1 2} msg] $msg } {1 {wrong # args: should be "info globals ?pattern?"}} test info-5.1 {info level option} { info level } 0 test info-5.2 {info level option} { proc t1 {a b} { set x [info level] set y [info level 1] list $x $y } t1 146 testString } {1 {t1 146 testString}} test info-5.3 {info level option} { proc t1 {a b} { t2 [expr $a*2] $b } proc t2 {x y} { list [info level] [info level 1] [info level 2] [info level -1] \ [info level 0] } t1 146 {a {b c} {{{c}}}} } {2 {t1 146 {a {b c} {{{c}}}}} {t2 292 {a {b c} {{{c}}}}} {t1 146 {a {b c} {{{c}}}}} {t2 292 {a {b c} {{{c}}}}}} test info-5.4 {info level option} { proc t1 {} { set x [info level] set y [info level 1] list $x $y } t1 } {1 t1} test info-5.5 {info level option} { list [catch {info level 1 2} msg] $msg } {1 {wrong # args: should be "info level ?levelNum?"}} test info-5.6 {info level option} { list [catch {info level 123a} msg] $msg } {1 {bad level "123a"}} test info-5.7 {info level option} { list [catch {info level 0} msg] $msg } {1 {bad level "0"}} test info-5.8 {info level option} { proc t1 {} {info level -1} list [catch {t1} msg] $msg } {1 {bad level "-1"}} test info-5.9 {info level option} { proc t1 {x} {info level $x} list [catch {t1 -3} msg] $msg } {1 {bad level "-3"}} test info-6.1 {info locals option} { set a 22 proc t1 {x y} { set b 13 set c testing global a global aa set aa 23 return [info locals] } lsort [t1 23 24] } {b c x y} test info-6.2 {info locals option} { proc t1 {x y} { set xx1 2 set xx2 3 set y 4 return [info locals x*] } lsort [t1 2 3] } {x xx1 xx2} test info-6.3 {info locals option} { list [catch {info locals 1 2} msg] $msg } {1 {wrong # args: should be "info locals ?pattern?"}} test info-6.4 {info locals option} { info locals } {} test info-6.5 {info locals option} { proc t1 {} {return [info locals]} t1 } {} test info-6.6 {info locals vs unset compiled locals} { proc t1 {lst} { foreach $lst $lst {} unset lst return [info locals] } lsort [t1 {a b c c d e f}] } {a b c d e f} test info-6.7 {info locals with temporary variables} { proc t1 {} { foreach a {b c} {} info locals } t1 } {a} test info-7.1 {info vars option} { set a 1 set b 2 proc t1 {x y} { global a b set c 33 return [info vars] } lsort [t1 18 19] } {a b c x y} test info-7.2 {info vars option} { set xxx1 1 set xxx2 2 proc t1 {xxa y} { global xxx1 xxx2 set c 33 return [info vars x*] } lsort [t1 18 19] } {xxa xxx1 xxx2} test info-7.3 {info vars option} { lsort [info vars] } [lsort [info globals]] test info-7.4 {info vars option} { list [catch {info vars a b} msg] $msg } {1 {wrong # args: should be "info vars ?pattern?"}} test info-7.5 {info vars with temporary variables} { proc t1 {} { foreach a {b c} {} info vars } t1 } {a} ################################################################################ # RANGE ################################################################################ test range-1.1 {basic range tests} { range 0 10 } {0 1 2 3 4 5 6 7 8 9} test range-1.2 {basic range tests} { range 10 0 -1 } {10 9 8 7 6 5 4 3 2 1} test range-1.3 {basic range tests} { range 1 10 11 } {1} test range-1.4 {basic range tests} { range 1 10 11 } {1} test range-1.5 {basic range tests} { range 10 10 } {} test range-1.6 {basic range tests} { range 10 10 2 } {} test range-1.7 {basic range test} { range 5 } {0 1 2 3 4} test range-1.8 {basic range test} { range -10 -20 -2 } {-10 -12 -14 -16 -18} test range-1.9 {basic range test} { range -20 -10 3 } {-20 -17 -14 -11} test range-2.0 {foreach range test} { set k 0 foreach {x y} [range 100] { incr k [expr {$x*$y}] } set k } {164150} test range-2.1 {foreach range test without obj reuse} { set k 0 set trash {} foreach {x y} [range 100] { incr k [expr {$x*$y}] lappend trash $x $y } set trash {} set k } {164150} test range-2.2 {range element shimmering test} { set k {} foreach x [range 0 10] { append k [llength $x] } set k } {1111111111} test range-3.0 {llength range test} { llength [range 5000] } {5000} test range-3.1 {llength range test} { llength [range 5000 5000] } {0} test range-4.0 {lindex range test} { lindex [range 1000] 500 } {500} test range-4.1 {lindex range test} { lindex [range 1000] end-2 } {997} test range-5.0 {lindex llength range test} { set k 0 set trash {} set r [range 100] for {set i 0} {$i < [llength $r]} {incr i 2} { incr k [expr {[lindex $r $i]*[lindex $r [expr {$i+1}]]}] } set trash {} set k } {164150} ################################################################################ # SCOPE ################################################################################ if 0 { test scope-1.0 {Non existing var} { catch {unset x} scope x { set x 10 set y [+ $x 1] } list [info exists x] $y } {0 11} test scope-1.1 {Existing var restore} { set x 100 scope x { for {set x 0} {$x < 10} {incr x} {} } set x } {100} test scope-1.2 {Mix of 1.0 and 1.1 tests} { catch {unset x} set y 10 scope {x y} { set y 100 set x 200 } list [info exists x] $y } {0 10} test scope-1.3 {Array element} { set x "a 1 b 2" scope x(a) { set x(a) Hello! } set x(a) } {1} test scope-1.4 {Non existing array element} { catch {unset x} scope x(a) { set x(a) Hello! } info exists x(a) } {0} test scope-1.5 {Info exists} { set x foo scope x { info exists x } } {0} catch {unset x} catch {unset y} } ################################################################################ # RAND ################################################################################ test rand-1.0 {Only one output is valid} { list [rand 100 100] [rand 101 101] } {100 101} test rand-1.1 {invalid arguments} { catch {rand 100 50} err set err } {Invalid arguments (max < min)} test rand-1.2 {Check limits} { set sum 0 for {set i 0} {$i < 100} {incr i} { incr sum [expr {([rand $i] >= 0)+([rand $i] < 100)}] } set sum } {200} catch {unset sum; unset err; unset i} ################################################################################ # JIM REGRESSION TESTS ################################################################################ test regression-1.0 {Rename against procedures with static vars} { proc foobar {x} {{y 10}} { incr y $x } foobar 30 foobar 20 rename foobar barfoo list [barfoo 1] [barfoo 2] [barfoo 3] } {61 63 66} catch {rename barfoo {}} test regression-1.1 {lrange bug with negative indexes of type int} { lrange {a b c} 0 [- 0 1] } {} testreport openocd-0.7.0/jimtcl/tests/expr.test0000644000175000001440000000457412134336723014403 00000000000000source [file dirname [info script]]/testing.tcl test expr-1.1 "Compare strings lt" { expr {"V000500" < "V000405"} } {0} test expr-1.2 "Compare strings with embedded nulls" { set s1 [format abc%cdef 0] set s2 [format abc%cghi 0] expr {$s1 < $s2} } {1} test expr-1.3 "Hex values" { set mask1 [expr 0x4050 & 0x0CCC] } {64} test expr-1.4 "Ternary operator - true" { expr {1 ? 2 : 3} } {2} test expr-1.5 "Ternary operator - false" { expr {0 ? 2 : 3} } {3} test expr-1.6 "Ternary operator - double check" { expr {1.0 ? 2 : 3} } {2} test expr-1.7 "Ternary operator - string result" { expr {1 ? "two" : 3} } {two} test expr-1.8 "Ternary operator - don't eval false path" { set a 100 set b 200 set c [expr {20 ? [incr a] : [incr b]}] list $a $b $c } {101 200 101} test expr-1.9 "Unary minus" { set a 1 expr {-$a} } {-1} test expr-1.10 "Subtraction" { set a 1 set b 10 expr {$b-$a} } {9} test expr-1.11 "Short circuit evaluation" { set a 100 set c [expr {0 || [incr a]}] list $a $c } {101 1} test expr-1.12 "Short circuit evaluation" { set a 100 set c [expr {1 || [incr a]}] list $a $c } {100 1} test expr-1.13 "Short circuit evaluation" { set a 100 set c [expr {1 || [incr a] && [incr a]}] list $a $c } {100 1} test expr-1.14 "Rotate left" jim { expr {1 <<< 5} } {32} test expr-1.15 "Rotate left" jim { expr {1 <<< 65} } {2} test expr-1.16 "Rotate right" jim { expr {1 >>> 48} } {65536} test expr-1.17 "Rotate left" jim { expr {1 >>> 63} } {2} # This crashes older jim test expr-2.1 "bogus unarymin" { catch {expr {unarymin 1}} return 1 } {1} test expr-2.2 "Ternary operator - missing colon" { list [catch {expr {1 ? 2 3}} msg] } {1} test expr-2.3 "Ternary operator - missing third term" { list [catch {expr {1 ? 2}} msg] } {1} test expr-2.4 "Ternary operator - missing question" { list [catch {expr {1 : 2}} msg] } {1} test expr-3.1 "in, ni operators" { set l {a b c d} set c C list [expr {"a" in $l}] [expr {$c in $l}] [expr {"b" ni $l}] [expr {$c ni $l}] } {1 0 0 1} test expr-3.2 "if: in, ni operators" { set l {a b c d} set a a set c C set result {} if {$a in $l} { lappend result 1 } if {$c in $l} { lappend result 2 } if {$a ni $l} { lappend result 3 } if {$c ni $l} { lappend result 4 } if {"d" in $l} { lappend result 5 } } {1 4 5} # Don't want a to become 2.0 test expr-4.1 "Shimmering" { set a 2 expr {$a < 3.0} set a } {2} testreport openocd-0.7.0/jimtcl/tests/regexp2.test0000644000175000001440000006127612134336723015003 00000000000000# Commands covered: regexp, regsub # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1998 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # RCS: @(#) $Id$ source [file dirname [info script]]/testing.tcl needs cmd regexp testConstraint regexp_are [regexp {\d} 1] needs constraint regexp_are # Procedure to evaluate a script within a proc, to test compilation # functionality proc evalInProc { script } { proc testProc {} $script set status [catch { testProc } result] rename testProc {} return $result #return [list $status $result] } catch {unset foo} test regexpComp-1.1 {basic regexp operation} { evalInProc { regexp ab*c abbbc } } 1 test regexpComp-1.2 {basic regexp operation} { evalInProc { regexp ab*c ac } } 1 test regexpComp-1.3 {basic regexp operation} { evalInProc { regexp ab*c ab } } 0 test regexpComp-1.4 {basic regexp operation} { evalInProc { regexp -- -gorp abc-gorpxxx } } 1 test regexpComp-1.5 {basic regexp operation} { evalInProc { regexp {^([^ ]*)[ ]*([^ ]*)} "" a } } 1 test regexpComp-1.6 {basic regexp operation} { list [catch {regexp {} abc} msg] $msg } {0 1} test regexpComp-1.7 {regexp utf compliance} { # if not UTF-8 aware, result is "0 1" evalInProc { set foo "\u4e4eb q" regexp "\u4e4eb q" "a\u4e4eb qw\u5e4e\x4e wq" bar list [string compare $foo $bar] [regexp 4 $bar] } } {0 0} test regexpComp-2.1 {getting substrings back from regexp} { evalInProc { set foo {} list [regexp ab*c abbbbc foo] $foo } } {1 abbbbc} test regexpComp-2.2 {getting substrings back from regexp} { evalInProc { set foo {} set f2 {} list [regexp a(b*)c abbbbc foo f2] $foo $f2 } } {1 abbbbc bbbb} test regexpComp-2.3 {getting substrings back from regexp} { evalInProc { set foo {} set f2 {} list [regexp a(b*)(c) abbbbc foo f2] $foo $f2 } } {1 abbbbc bbbb} test regexpComp-2.4 {getting substrings back from regexp} { evalInProc { set foo {} set f2 {} set f3 {} list [regexp a(b*)(c) abbbbc foo f2 f3] $foo $f2 $f3 } } {1 abbbbc bbbb c} test regexpComp-2.5 {getting substrings back from regexp} { evalInProc { set foo {}; set f1 {}; set f2 {}; set f3 {}; set f4 {}; set f5 {}; set f6 {}; set f7 {}; set f8 {}; set f9 {}; set fa {}; set fb {}; list [regexp (1*)(2*)(3*)(4*)(5*)(6*)(7*)(8*)(9*)(a*)(b*) \ 12223345556789999aabbb \ foo f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb] $foo $f1 $f2 $f3 $f4 $f5 \ $f6 $f7 $f8 $f9 $fa $fb } } {1 12223345556789999aabbb 1 222 33 4 555 6 7 8 9999 aa bbb} test regexpComp-2.6 {getting substrings back from regexp} { evalInProc { set foo 2; set f2 2; set f3 2; set f4 2 list [regexp (a)(b)? xay foo f2 f3 f4] $foo $f2 $f3 $f4 } } {1 a a {} {}} test regexpComp-2.7 {getting substrings back from regexp} { evalInProc { set foo 1; set f2 1; set f3 1; set f4 1 list [regexp (a)(b)?(c) xacy foo f2 f3 f4] $foo $f2 $f3 $f4 } } {1 ac a {} c} test regexpComp-2.8 {getting substrings back from regexp} { evalInProc { set match {} list [regexp {^a*b} aaaab match] $match } } {1 aaaab} test regexpComp-3.1 {-indices option to regexp} { evalInProc { set foo {} list [regexp -indices ab*c abbbbc foo] $foo } } {1 {0 5}} test regexpComp-3.2 {-indices option to regexp} { evalInProc { set foo {} set f2 {} list [regexp -indices a(b*)c abbbbc foo f2] $foo $f2 } } {1 {0 5} {1 4}} test regexpComp-3.3 {-indices option to regexp} { evalInProc { set foo {} set f2 {} list [regexp -indices a(b*)(c) abbbbc foo f2] $foo $f2 } } {1 {0 5} {1 4}} test regexpComp-3.4 {-indices option to regexp} { evalInProc { set foo {} set f2 {} set f3 {} list [regexp -indices a(b*)(c) abbbbc foo f2 f3] $foo $f2 $f3 } } {1 {0 5} {1 4} {5 5}} test regexpComp-3.5 {-indices option to regexp} { evalInProc { set foo {}; set f1 {}; set f2 {}; set f3 {}; set f4 {}; set f5 {}; set f6 {}; set f7 {}; set f8 {}; set f9 {} list [regexp -indices (1*)(2*)(3*)(4*)(5*)(6*)(7*)(8*)(9*) \ 12223345556789999 \ foo f1 f2 f3 f4 f5 f6 f7 f8 f9] $foo $f1 $f2 $f3 $f4 $f5 \ $f6 $f7 $f8 $f9 } } {1 {0 16} {0 0} {1 3} {4 5} {6 6} {7 9} {10 10} {11 11} {12 12} {13 16}} test regexpComp-3.6 {getting substrings back from regexp} { evalInProc { set foo 2; set f2 2; set f3 2; set f4 2 list [regexp -indices (a)(b)? xay foo f2 f3 f4] $foo $f2 $f3 $f4 } } {1 {1 1} {1 1} {-1 -1} {-1 -1}} test regexpComp-3.7 {getting substrings back from regexp} { evalInProc { set foo 1; set f2 1; set f3 1; set f4 1 list [regexp -indices (a)(b)?(c) xacy foo f2 f3 f4] $foo $f2 $f3 $f4 } } {1 {1 2} {1 1} {-1 -1} {2 2}} test regexpComp-4.1 {-nocase option to regexp} { evalInProc { regexp -nocase foo abcFOo } } 1 test regexpComp-4.2 {-nocase option to regexp} { evalInProc { set f1 22 set f2 33 set f3 44 list [regexp -nocase {a(b*)([xy]*)z} aBbbxYXxxZ22 f1 f2 f3] $f1 $f2 $f3 } } {1 aBbbxYXxxZ Bbb xYXxx} test regexpComp-4.3 {-nocase option to regexp} { evalInProc { regexp -nocase FOo abcFOo } } 1 set ::x abcdefghijklmnopqrstuvwxyz1234567890 set ::x $x$x$x$x$x$x$x$x$x$x$x$x test regexpComp-4.4 {case conversion in regexp} { evalInProc { list [regexp -nocase $::x $::x foo] $foo } } "1 $x" catch {unset ::x} test regexpComp-5.1 {exercise cache of compiled expressions} { evalInProc { regexp .*a b regexp .*b c regexp .*c d regexp .*d e regexp .*e f regexp .*a bbba } } 1 test regexpComp-5.2 {exercise cache of compiled expressions} { evalInProc { regexp .*a b regexp .*b c regexp .*c d regexp .*d e regexp .*e f regexp .*b xxxb } } 1 test regexpComp-5.3 {exercise cache of compiled expressions} { evalInProc { regexp .*a b regexp .*b c regexp .*c d regexp .*d e regexp .*e f regexp .*c yyyc } } 1 test regexpComp-5.4 {exercise cache of compiled expressions} { evalInProc { regexp .*a b regexp .*b c regexp .*c d regexp .*d e regexp .*e f regexp .*d 1d } } 1 test regexpComp-5.5 {exercise cache of compiled expressions} { evalInProc { regexp .*a b regexp .*b c regexp .*c d regexp .*d e regexp .*e f regexp .*e xe } } 1 test regexpComp-6.4 {regexp errors} { evalInProc { list [catch {regexp a( b} msg] $msg } } {1 {couldn't compile regular expression pattern: parentheses () not balanced}} test regexpComp-6.5 {regexp errors} { evalInProc { list [catch {regexp a( b} msg] $msg } } {1 {couldn't compile regular expression pattern: parentheses () not balanced}} test regexpComp-6.6 {regexp errors} { evalInProc { list [catch {regexp a a f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1} msg] $msg } } {0 1} test regexpComp-6.7 {regexp errors} { evalInProc { list [catch {regexp (x)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.) xyzzy} msg] $msg } } {0 0} test regexpComp-6.8 {regexp errors} { evalInProc { catch {unset f1} set f1 44 catch {regexp abc abc f1(f2)} msg } } {1} test regexpComp-6.9 {regexp errors, -start bad int check} { evalInProc { list [catch {regexp -start bogus {^$} {}} msg] $msg } } {1 {bad index "bogus": must be integer?[+-]integer? or end?[+-]integer?}} test regexpComp-7.1 {basic regsub operation} { evalInProc { list [regsub aa+ xaxaaaxaa 111&222 foo] $foo } } {1 xax111aaa222xaa} test regexpComp-7.2 {basic regsub operation} { evalInProc { list [regsub aa+ aaaxaa &111 foo] $foo } } {1 aaa111xaa} test regexpComp-7.3 {basic regsub operation} { evalInProc { list [regsub aa+ xaxaaa 111& foo] $foo } } {1 xax111aaa} test regexpComp-7.4 {basic regsub operation} { evalInProc { list [regsub aa+ aaa 11&2&333 foo] $foo } } {1 11aaa2aaa333} test regexpComp-7.5 {basic regsub operation} { evalInProc { list [regsub aa+ xaxaaaxaa &2&333 foo] $foo } } {1 xaxaaa2aaa333xaa} test regexpComp-7.6 {basic regsub operation} { evalInProc { list [regsub aa+ xaxaaaxaa 1&22& foo] $foo } } {1 xax1aaa22aaaxaa} test regexpComp-7.7 {basic regsub operation} { evalInProc { list [regsub a(a+) xaxaaaxaa {1\122\1} foo] $foo } } {1 xax1aa22aaxaa} test regexpComp-7.8 {basic regsub operation} { evalInProc { list [regsub a(a+) xaxaaaxaa {1\\\122\1} foo] $foo } } "1 {xax1\\aa22aaxaa}" test regexpComp-7.9 {basic regsub operation} { evalInProc { list [regsub a(a+) xaxaaaxaa {1\\122\1} foo] $foo } } "1 {xax1\\122aaxaa}" test regexpComp-7.10 {basic regsub operation} { evalInProc { list [regsub a(a+) xaxaaaxaa {1\\&\1} foo] $foo } } "1 {xax1\\aaaaaxaa}" test regexpComp-7.11 {basic regsub operation} { evalInProc { list [regsub a(a+) xaxaaaxaa {1\&\1} foo] $foo } } {1 xax1&aaxaa} test regexpComp-7.12 {basic regsub operation} { evalInProc { list [regsub a(a+) xaxaaaxaa {\1\1\1\1&&} foo] $foo } } {1 xaxaaaaaaaaaaaaaaxaa} test regexpComp-7.13 {basic regsub operation} { evalInProc { set foo xxx list [regsub abc xyz 111 foo] $foo } } {0 xyz} test regexpComp-7.14 {basic regsub operation} { evalInProc { set foo xxx list [regsub ^ xyz "111 " foo] $foo } } {1 {111 xyz}} test regexpComp-7.15 {basic regsub operation} { evalInProc { set foo xxx list [regsub -- -foo abc-foodef "111 " foo] $foo } } {1 {abc111 def}} test regexpComp-7.16 {basic regsub operation} { evalInProc { set foo xxx list [regsub x "" y foo] $foo } } {0 {}} test regexpComp-7.17 {regsub utf compliance} { evalInProc { # if not UTF-8 aware, result is "0 1" set foo "xyz555ijka\u4e4ebpqr" regsub a\u4e4eb xyza\u4e4ebijka\u4e4ebpqr 555 bar list [string compare $foo $bar] [regexp 4 $bar] } } {0 0} test regexpComp-7.18 {regsub utf8 in char range} utf8 { regsub {[\u4e4ex]b} xyza\u4e4ebijka\u4e4ebpqr 555 } xyza555ijka\u4e4ebpqr test regexpComp-7.19 {regsub utf8 in complemented char range} utf8 { regsub -all {[^x\u4e4e]b} xyza\u4e4ebizbjxbka\u4e4fbpqr 555 } xyza\u4e4ebi555jxbka555pqr test regexpComp-8.1 {case conversion in regsub} { evalInProc { list [regsub -nocase a(a+) xaAAaAAay & foo] $foo } } {1 xaAAaAAay} test regexpComp-8.2 {case conversion in regsub} { evalInProc { list [regsub -nocase a(a+) xaAAaAAay & foo] $foo } } {1 xaAAaAAay} test regexpComp-8.3 {case conversion in regsub} { evalInProc { set foo 123 list [regsub a(a+) xaAAaAAay & foo] $foo } } {0 xaAAaAAay} test regexpComp-8.4 {case conversion in regsub} { evalInProc { set foo 123 list [regsub -nocase a CaDE b foo] $foo } } {1 CbDE} test regexpComp-8.5 {case conversion in regsub} { evalInProc { set foo 123 list [regsub -nocase XYZ CxYzD b foo] $foo } } {1 CbD} test regexpComp-8.6 {case conversion in regsub} { evalInProc { set x abcdefghijklmnopqrstuvwxyz1234567890 set x $x$x$x$x$x$x$x$x$x$x$x$x set foo 123 list [regsub -nocase $x $x b foo] $foo } } {1 b} test regexpComp-9.1 {-all option to regsub} { evalInProc { set foo 86 list [regsub -all x+ axxxbxxcxdx |&| foo] $foo } } {4 a|xxx|b|xx|c|x|d|x|} test regexpComp-9.2 {-all option to regsub} { evalInProc { set foo 86 list [regsub -nocase -all x+ aXxXbxxcXdx |&| foo] $foo } } {4 a|XxX|b|xx|c|X|d|x|} test regexpComp-9.3 {-all option to regsub} { evalInProc { set foo 86 list [regsub x+ axxxbxxcxdx |&| foo] $foo } } {1 a|xxx|bxxcxdx} test regexpComp-9.4 {-all option to regsub} { evalInProc { set foo 86 list [regsub -all bc axxxbxxcxdx |&| foo] $foo } } {0 axxxbxxcxdx} test regexpComp-9.5 {-all option to regsub} { evalInProc { set foo xxx list [regsub -all node "node node more" yy foo] $foo } } {2 {yy yy more}} test regexpComp-9.6 {-all option to regsub} { evalInProc { set foo xxx list [regsub -all ^ xxx 123 foo] $foo } } {1 123xxx} #test regexpComp-10.1 {expanded syntax in regsub} { # evalInProc { # set foo xxx # list [regsub -expanded ". \#comment\n . \#comment2" abc def foo] $foo # } #} {1 defc} test regexpComp-10.2 {newline sensitivity in regsub} { evalInProc { set foo xxx list [regsub -line {^a.*b$} "dabc\naxyb\n" 123 foo] $foo } } "1 {dabc\n123\n}" test regexpComp-10.3 {newline sensitivity in regsub} { evalInProc { set foo xxx list [regsub -line {^a.*b$} "dabc\naxyb\nxb" 123 foo] $foo } } "1 {dabc\n123\nxb}" #test regexpComp-10.4 {partial newline sensitivity in regsub} { # evalInProc { # set foo xxx # list [regsub -lineanchor {^a.*b$} "da\naxyb\nxb" 123 foo] $foo # } #} "1 {da\n123}" #test regexpComp-10.5 {inverse partial newline sensitivity in regsub} { # evalInProc { # set foo xxx # list [regsub -linestop {a.*b} "da\nbaxyb\nxb" 123 foo] $foo # } #} "1 {da\nb123\nxb}" #test regexpComp-11.1 {regsub errors} { # evalInProc { # list [catch {regsub a b} msg] $msg # } #} {1 {wrong # args: should be "regsub ?-switch ...? exp string subSpec ?varName?"}} #test regexpComp-11.2 {regsub errors} { # evalInProc { # list [catch {regsub -nocase a b} msg] $msg # } #} {1 {wrong # args: should be "regsub ?-switch ...? exp string subSpec ?varName?"}} #test regexpComp-11.3 {regsub errors} { # evalInProc { # list [catch {regsub -nocase -all a b} msg] $msg # } #} {1 {wrong # args: should be "regsub ?-switch ...? exp string subSpec ?varName?"}} #test regexpComp-11.4 {regsub errors} { # evalInProc { # list [catch {regsub a b c d e f} msg] $msg # } #} {1 {wrong # args: should be "regsub ?-switch ...? exp string subSpec ?varName?"}} #test regexpComp-11.5 {regsub errors} { # evalInProc { # list [catch {regsub -gorp a b c} msg] $msg # } #} {1 {bad switch "-gorp": must be -all, -nocase, -expanded, -line, -linestop, -lineanchor, -start, or --}} #test regexpComp-11.6 {regsub errors} { # evalInProc { # list [catch {regsub -nocase a( b c d} msg] $msg # } #} {1 {couldn't compile regular expression pattern: parentheses () not balanced}} test regexpComp-11.7 {regsub errors} { evalInProc { catch {unset f1} set f1 44 catch {regsub -nocase aaa aaa xxx f1(f2)} msg } } {1} test regexpComp-11.8 {regsub errors, -start bad int check} { evalInProc { list [catch {regsub -start bogus pattern string rep var} msg] $msg } } {1 {bad index "bogus": must be integer?[+-]integer? or end?[+-]integer?}} # This test crashes on the Mac unless you increase the Stack Space to about 1 # Meg. This is probably bigger than most users want... # 8.2.3 regexp reduced stack space requirements, but this should be # tested again test regexpComp-12.1 {Tcl_RegExpExec: large number of subexpressions} { evalInProc { list [regexp (.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.) abcdefghijklmnopqrstuvwxyz all a b c d e f g h i j k l m n o p q r s t u v w x y z] $all $a $b $c $d $e $f $g $h $i $j $k $l $m $n $o $p $q $r $s $t $u $v $w $x $y $z } } {1 abcdefghijklmnopqrstuvwxyz a b c d e f g h i j k l m n o p q r s t u v w x y z} test regexpComp-13.1 {regsub of a very large string} { # This test is designed to stress the memory subsystem in order # to catch Bug #933. It only fails if the Tcl memory allocator # is in use. set line {BEGIN_TABLE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; END_TABLE} set filedata [string repeat $line 200] for {set i 1} {$i<10} {incr i} { regsub -all "BEGIN_TABLE " $filedata "" newfiledata } set x done } {done} test regexpComp-14.1 {CompileRegexp: regexp cache} { evalInProc { regexp .*a b regexp .*b c regexp .*c d regexp .*d e regexp .*e f set x . append x *a regexp $x bbba } } 1 test regexpComp-14.2 {CompileRegexp: regexp cache, different flags} { evalInProc { regexp .*a b regexp .*b c regexp .*c d regexp .*d e regexp .*e f set x . append x *a regexp -nocase $x bbba } } 1 test regexpComp-15.1 {regexp -start} { catch {unset x} list [regexp -start -10 {\d} 1abc2de3 x] $x } {1 1} test regexpComp-15.2 {regexp -start} { catch {unset x} list [regexp -start 2 {\d} 1abc2de3 x] $x } {1 2} test regexpComp-15.3 {regexp -start} { catch {unset x} list [regexp -start 4 {\d} 1abc2de3 x] $x } {1 2} test regexpComp-15.4 {regexp -start} { catch {unset x} list [regexp -start 5 {\d} 1abc2de3 x] $x } {1 3} test regexpComp-15.5 {regexp -start, over end of string} { catch {unset x} list [regexp -start [string length 1abc2de3] {\d} 1abc2de3 x] [info exists x] } {0 0} test regexpComp-15.6 {regexp -start, loss of ^$ behavior} { list [regexp -start 2 {^$} {}] } {0} test regexpComp-16.1 {regsub -start} { catch {unset x} list [regsub -all -start 2 {\d} a1b2c3d4e5 {/&} x] $x } {4 a1b/2c/3d/4e/5} test regexpComp-16.2 {regsub -start} { catch {unset x} list [regsub -all -start -25 {z} hello {/&} x] $x } {0 hello} test regexpComp-16.3 {regsub -start} { catch {unset x} list [regsub -all -start 3 {z} hello {/&} x] $x } {0 hello} #test regexpComp-16.4 {regsub -start, \A behavior} { # set out {} # lappend out [regsub -start 0 -all {\A(\w)} {abcde} {/\1} x] $x # lappend out [regsub -start 2 -all {\A(\w)} {abcde} {/\1} x] $x #} {5 /a/b/c/d/e 3 ab/c/d/e} test regexpComp-17.1 {regexp -inline} { regexp -inline b ababa } {b} test regexpComp-17.2 {regexp -inline} { regexp -inline (b) ababa } {b b} test regexpComp-17.3 {regexp -inline -indices} { regexp -inline -indices (b) ababa } {{1 1} {1 1}} test regexpComp-17.4 {regexp -inline} { regexp -inline {\w(\d+)\w} " hello 23 there456def " } {e456d 456} test regexpComp-17.5 {regexp -inline no matches} { regexp -inline {\w(\d+)\w} "" } {} test regexpComp-17.6 {regexp -inline no matches} { regexp -inline hello goodbye } {} test regexpComp-17.7 {regexp -inline, no matchvars allowed} { list [catch {regexp -inline b abc match} msg] $msg } {1 {regexp match variables not allowed when using -inline}} test regexpComp-18.1 {regexp -all} { regexp -all b bbbbb } {5} test regexpComp-18.2 {regexp -all} { regexp -all b abababbabaaaaaaaaaab } {6} test regexpComp-18.3 {regexp -all -inline} { regexp -all -inline b abababbabaaaaaaaaaab } {b b b b b b} test regexpComp-18.4 {regexp -all -inline} { regexp -all -inline {\w(\w)} abcdefg } {ab b cd d ef f} test regexpComp-18.5 {regexp -all -inline} { regexp -all -inline {\w(\w)$} abcdefg } {fg g} test regexpComp-18.6 {regexp -all -inline} { regexp -all -inline {\d+} 10:20:30:40 } {10 20 30 40} test regexpComp-18.7 {regexp -all -inline} { list [catch {regexp -all -inline b abc match} msg] $msg } {1 {regexp match variables not allowed when using -inline}} test regexpComp-18.8 {regexp -all} { # This should not cause an infinite loop regexp -all -inline {a*} a } {a} test regexpComp-18.9 {regexp -all} { # Yes, the expected result is {a {}}. Here's why: # Start at index 0; a* matches the "a" there then stops. # Go to index 1; a* matches the lambda (or {}) there then stops. Recall # that a* matches zero or more "a"'s; thus it matches the string "b", as # there are zero or more "a"'s there. # Go to index 2; this is past the end of the string, so stop. regexp -all -inline {a*} ab } {a {}} test regexpComp-18.10 {regexp -all} { # Yes, the expected result is {a {} a}. Here's why: # Start at index 0; a* matches the "a" there then stops. # Go to index 1; a* matches the lambda (or {}) there then stops. Recall # that a* matches zero or more "a"'s; thus it matches the string "b", as # there are zero or more "a"'s there. # Go to index 2; a* matches the "a" there then stops. # Go to index 3; this is past the end of the string, so stop. regexp -all -inline {a*} aba } {a {} a} test regexpComp-18.11 {regexp -all} { evalInProc { regexp -all -inline {^a} aaaa } } {a} test regexpComp-18.12 {regexp -all -inline -indices} { evalInProc { regexp -all -inline -indices a(b(c)d|e(f)g)h abcdhaefgh } } {{0 4} {1 3} {2 2} {-1 -1} {5 9} {6 8} {-1 -1} {7 7}} test regexpComp-19.1 {regsub null replacement} { evalInProc { regsub -all {@} {@hel@lo@} "\0a\0" result list $result [string length $result] } } "\0a\0hel\0a\0lo\0a\0 14" test regexpComp-20.1 {regsub shared object shimmering} { evalInProc { # Bug #461322 set a abcdefghijklmnopqurstuvwxyz set b $a set c abcdefghijklmnopqurstuvwxyz0123456789 regsub $a $c $b d list $d [string length $d] [string bytelength $d] } } [list abcdefghijklmnopqurstuvwxyz0123456789 37 37] #test regexpComp-20.2 {regsub shared object shimmering with -about} { # evalInProc { # eval regexp -about abc # } #} {0 {}} test regexpComp-21.1 {regexp command compiling tests} { evalInProc { regexp foo bar } } 0 test regexpComp-21.2 {regexp command compiling tests} { evalInProc { regexp {^foo$} dogfood } } 0 test regexpComp-21.3 {regexp command compiling tests} { evalInProc { set a foo regexp {^foo$} $a } } 1 test regexpComp-21.4 {regexp command compiling tests} { evalInProc { regexp foo dogfood } } 1 test regexpComp-21.5 {regexp command compiling tests} { evalInProc { regexp -nocase FOO dogfod } } 0 test regexpComp-21.6 {regexp command compiling tests} { evalInProc { regexp -n foo dogfoOd } } 1 test regexpComp-21.7 {regexp command compiling tests} { evalInProc { regexp -no -- FoO dogfood } } 1 test regexpComp-21.8 {regexp command compiling tests} { evalInProc { regexp -- foo dogfod } } 0 test regexpComp-21.9 {regexp command compiling tests} { evalInProc { list [catch {regexp -- -nocase foo dogfod} msg] $msg } } {0 0} test regexpComp-21.10 {regexp command compiling tests} { evalInProc { list [regsub -all "" foo bar str] $str } } {3 barfbarobaro} # This useless expression fails. Jim returns "bar" #test regexpComp-21.11 {regexp command compiling tests} { # evalInProc { # list [regsub -all "" "" bar str] $str # } #} {0 {}} # We can forgive the underlying regexp engine for not supporting this. # Why not use this instead? "((^X)*|\$)" #test regexpComp-22.0.1 {Bug 1810038} { # evalInProc { # regexp ($|^X)* {} # } #} 1 set i 0 foreach {str exp result} { foo ^foo 1 foobar ^foobar$ 1 foobar bar$ 1 foobar ^$ 0 "" ^$ 1 anything $ 1 anything ^.*$ 1 anything ^.*a$ 0 anything ^.*a.*$ 1 anything ^.*.*$ 1 anything ^.*..*$ 1 anything ^.*b$ 0 anything ^a.*$ 1 } { test regexpComp-22.[incr i] {regexp command compiling tests} \ [subst {evalInProc {set a "$str"; regexp {$exp} \$a}}] $result } set i 0 foreach {str exp result} { foo ^foo 1 foobar ^foobar$ 1 foobar bar$ 1 foobar ^$ 0 "" ^$ 1 anything $ 1 anything ^.*$ 1 anything ^.*a$ 0 anything ^.*a.*$ 1 anything ^.*.*$ 1 anything ^.*..*$ 1 anything ^.*b$ 0 anything ^a.*$ 1 } { test regexpComp-23.[incr i] {regexp command compiling tests INST_REGEXP} \ [list regexp $exp $str] $result } test regexpComp-24.1 {regexp command compiling tests} { evalInProc { set re foo regexp -nocase $re bar } } 0 test regexpComp-24.2 {regexp command compiling tests} { evalInProc { set re {^foo$} regexp $re dogfood } } 0 test regexpComp-24.3 {regexp command compiling tests} { evalInProc { set a foo set re {^foo$} regexp $re $a } } 1 test regexpComp-24.4 {regexp command compiling tests} { evalInProc { set re foo regexp $re dogfood } } 1 test regexpComp-24.5 {regexp command compiling tests} { evalInProc { set re FOO regexp -nocase $re dogfod } } 0 test regexpComp-24.6 {regexp command compiling tests} { evalInProc { set re foo regexp -n $re dogfoOd } } 1 test regexpComp-24.7 {regexp command compiling tests} { evalInProc { set re FoO regexp -no -- $re dogfood } } 1 test regexpComp-24.8 {regexp command compiling tests} { evalInProc { set re foo regexp -- $re dogfod } } 0 test regexpComp-24.9 {regexp command compiling tests} { evalInProc { set re "(" list [catch {regexp -- $re dogfod} msg] $msg } } {1 {couldn't compile regular expression pattern: parentheses () not balanced}} test regexpComp-24.10 {regexp command compiling tests} { # Bug 1902436 - last * escaped evalInProc { set text {this is *bold* !} set re {\*bold\*} regexp -- $re $text } } 1 test regexpComp-24.11 {regexp command compiling tests} { # Bug 1902436 - last * escaped evalInProc { set text {this is *bold* !} set re {\*bold\*.*!} regexp -- $re $text } } 1 test regexp-25.1 {Repeat on escaped char} { regexp {\x41\x42*} bc } 0 test regexp-25.2 {Single braced count} { regexp "a{4}" baaaad } 1 testreport openocd-0.7.0/jimtcl/tests/loop.test0000644000175000001440000000465312134336723014374 00000000000000source [file dirname [info script]]/testing.tcl # Check "loop" and its use of continue and break. needs cmd loop catch {unset a i} test loop-1.1 {loop tests} { set a {} loop i 1 6 { set a [concat $a $i] } set a } {1 2 3 4 5} test loop-1.2 {loop tests} { set a {} loop i 1 6 { if $i==4 continue set a [concat $a $i] } set a } {1 2 3 5} test loop-1.3 {loop tests} { set a {} loop i 1 6 { if $i==4 break set a [concat $a $i] } set a } {1 2 3} test loop-1.5 {loop errors} { catch {loop 1 2 3} msg } {1} test loop-1.6 {loop errors} { catch {loop 1 2 3 4 5} msg } {1} test loop-1.7 {loop tests} { set a {xyz} loop i 1 6 { } set a } xyz test loop-1.8 {error in loop} { set rc [catch { set a {} loop i 1 6 { lappend a $i if {$i == 3} { error "stop" } } }] list $a $rc } {{1 2 3} 1} test loop-1.9 {loop incr} { set a {} loop i 0 6 2 { lappend a $i } set a } {0 2 4} test loop-1.10 {no exec infinite loop} { set a {} loop i 0 6 -1 { lappend a $i break } set a } {} test loop-2.1 {loop shimmering tests} { loop i 1 6 { } set i } 6 test loop-2.2 {loop shimmering tests} { # Setting the variable inside the loop doesn't # affect the loop or the final variable value loop i 1 6 { set i blah } set i } 6 test loop-2.3 {loop shimmering tests} { set a {} loop i 1 6 { lappend a $i set i blah lappend a $i } set a } {1 blah 2 blah 3 blah 4 blah 5 blah} test loop-2.4 {loop shimmering tests} { set i xyz loop i 1 6 { } set i } 6 test loop-2.5 {loop shimmering tests} { # Ensure that the string rep of $i is updated set i {1 3} loop i(1) 1 6 { } set i } {1 6} test loop-2.6 {modify loop var} { unset -nocomplain i catch { loop i(1) 1 6 { # this makes it impossible to set the loop var set i blah } } } 1 test loop-2.7 {unset loop var} { unset -nocomplain i loop i 1 6 { # var will simply get recreated on each loop unset i } set i } 6 test loop-2.8 {modify loop var} { unset -nocomplain i set a {} loop i 1 6 { lappend a $i incr i } set a } {1 2 3 4 5} testreport break testreport openocd-0.7.0/jimtcl/tests/regexp.test0000644000175000001440000005513612134336723014717 00000000000000# Commands covered: regexp, regsub # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1998 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # RCS: @(#) $Id: regexp.test,v 1.30.2.1 2008/08/21 23:19:06 hobbs Exp $ source [file dirname [info script]]/testing.tcl needs cmd regexp catch {unset foo} test regexp-1.1 {basic regexp operation} { regexp ab*c abbbc } 1 test regexp-1.2 {basic regexp operation} { regexp ab*c ac } 1 test regexp-1.3 {basic regexp operation} { regexp ab*c ab } 0 test regexp-1.4 {basic regexp operation} { regexp -- -gorp abc-gorpxxx } 1 test regexp-1.5 {basic regexp operation} { regexp {^([^ ]*)[ ]*([^ ]*)} "" a } 1 #test regexp-1.6 {basic regexp operation} { # list [catch {regexp {} abc} msg] $msg #} {0 1} #test regexp-1.7 {regexp utf compliance} { # # if not UTF-8 aware, result is "0 1" # set foo "\u4e4eb q" # regexp "\u4e4eb q" "a\u4e4eb qw\u5e4e\x4e wq" bar # list [string compare $foo $bar] [regexp 4 $bar] #} {0 0} test regexp-2.1 {getting substrings back from regexp} { set foo {} list [regexp ab*c abbbbc foo] $foo } {1 abbbbc} test regexp-2.2 {getting substrings back from regexp} { set foo {} set f2 {} list [regexp a(b*)c abbbbc foo f2] $foo $f2 } {1 abbbbc bbbb} test regexp-2.3 {getting substrings back from regexp} { set foo {} set f2 {} list [regexp a(b*)(c) abbbbc foo f2] $foo $f2 } {1 abbbbc bbbb} test regexp-2.4 {getting substrings back from regexp} { set foo {} set f2 {} set f3 {} list [regexp a(b*)(c) abbbbc foo f2 f3] $foo $f2 $f3 } {1 abbbbc bbbb c} test regexp-2.5 {getting substrings back from regexp} { set foo {}; set f1 {}; set f2 {}; set f3 {}; set f4 {}; set f5 {}; set f6 {}; set f7 {}; set f8 {}; set f9 {}; set fa {}; set fb {}; list [regexp (1*)(2*)(3*)(4*)(5*)(6*)(7*)(8*)(9*)(a*)(b*) \ 12223345556789999aabbb \ foo f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb] $foo $f1 $f2 $f3 $f4 $f5 \ $f6 $f7 $f8 $f9 $fa $fb } {1 12223345556789999aabbb 1 222 33 4 555 6 7 8 9999 aa bbb} test regexp-2.6 {getting substrings back from regexp} { set foo 2; set f2 2; set f3 2; set f4 2 list [regexp (a)(b)? xay foo f2 f3 f4] $foo $f2 $f3 $f4 } {1 a a {} {}} test regexp-2.7 {getting substrings back from regexp} { set foo 1; set f2 1; set f3 1; set f4 1 list [regexp (a)(b)?(c) xacy foo f2 f3 f4] $foo $f2 $f3 $f4 } {1 ac a {} c} test regexp-2.8 {getting substrings back from regexp} { set match {} list [regexp {^a*b} aaaab match] $match } {1 aaaab} test regexp-2.9 {getting substrings back from regexp} { set foo {} set f2 {} list [regexp f\352te(b*)c f\352tebbbbc foo f2] $foo $f2 } [list 1 f\352tebbbbc bbbb] test regexp-2.10 {getting substrings back from regexp} { set foo {} set f2 {} list [regexp f\352te(b*)c eff\352tebbbbc foo f2] $foo $f2 } [list 1 f\352tebbbbc bbbb] test regexp-3.1 {-indices option to regexp} { set foo {} list [regexp -indices ab*c abbbbc foo] $foo } {1 {0 5}} test regexp-3.2 {-indices option to regexp} { set foo {} set f2 {} list [regexp -indices a(b*)c abbbbc foo f2] $foo $f2 } {1 {0 5} {1 4}} test regexp-3.3 {-indices option to regexp} { set foo {} set f2 {} list [regexp -indices a(b*)(c) abbbbc foo f2] $foo $f2 } {1 {0 5} {1 4}} test regexp-3.4 {-indices option to regexp} { set foo {} set f2 {} set f3 {} list [regexp -indices a(b*)(c) abbbbc foo f2 f3] $foo $f2 $f3 } {1 {0 5} {1 4} {5 5}} test regexp-3.5 {-indices option to regexp} { set foo {}; set f1 {}; set f2 {}; set f3 {}; set f4 {}; set f5 {}; set f6 {}; set f7 {}; set f8 {}; set f9 {} list [regexp -indices (1*)(2*)(3*)(4*)(5*)(6*)(7*)(8*)(9*) \ 12223345556789999 \ foo f1 f2 f3 f4 f5 f6 f7 f8 f9] $foo $f1 $f2 $f3 $f4 $f5 \ $f6 $f7 $f8 $f9 } {1 {0 16} {0 0} {1 3} {4 5} {6 6} {7 9} {10 10} {11 11} {12 12} {13 16}} test regexp-3.6 {getting substrings back from regexp} { set foo 2; set f2 2; set f3 2; set f4 2 list [regexp -indices (a)(b)? xay foo f2 f3 f4] $foo $f2 $f3 $f4 } {1 {1 1} {1 1} {-1 -1} {-1 -1}} test regexp-3.7 {getting substrings back from regexp} { set foo 1; set f2 1; set f3 1; set f4 1 list [regexp -indices (a)(b)?(c) xacy foo f2 f3 f4] $foo $f2 $f3 $f4 } {1 {1 2} {1 1} {-1 -1} {2 2}} test regexp-4.1 {-nocase option to regexp} { regexp -nocase foo abcFOo } 1 test regexp-4.2 {-nocase option to regexp} { set f1 22 set f2 33 set f3 44 list [regexp -nocase {a(b*)([xy]*)z} aBbbxYXxxZ22 f1 f2 f3] $f1 $f2 $f3 } {1 aBbbxYXxxZ Bbb xYXxx} test regexp-4.3 {-nocase option to regexp} { regexp -nocase FOo abcFOo } 1 set x abcdefghijklmnopqrstuvwxyz1234567890 set x $x$x$x$x$x$x$x$x$x$x$x$x test regexp-4.4 {case conversion in regexp} { list [regexp -nocase $x $x foo] $foo } "1 $x" catch {unset x} test regexp-5.1 {exercise cache of compiled expressions} { regexp .*a b regexp .*b c regexp .*c d regexp .*d e regexp .*e f regexp .*a bbba } 1 test regexp-5.2 {exercise cache of compiled expressions} { regexp .*a b regexp .*b c regexp .*c d regexp .*d e regexp .*e f regexp .*b xxxb } 1 test regexp-5.3 {exercise cache of compiled expressions} { regexp .*a b regexp .*b c regexp .*c d regexp .*d e regexp .*e f regexp .*c yyyc } 1 test regexp-5.4 {exercise cache of compiled expressions} { regexp .*a b regexp .*b c regexp .*c d regexp .*d e regexp .*e f regexp .*d 1d } 1 test regexp-5.5 {exercise cache of compiled expressions} { regexp .*a b regexp .*b c regexp .*c d regexp .*d e regexp .*e f regexp .*e xe } 1 test regexp-6.1 {regexp errors} jim { list [catch {regexp a} msg] $msg } {1 {wrong # args: should be "regexp ?switches? exp string ?matchVar? ?subMatchVar subMatchVar ...?"}} test regexp-6.2 {regexp errors} jim { list [catch {regexp -nocase a} msg] $msg } {1 {wrong # args: should be "regexp ?switches? exp string ?matchVar? ?subMatchVar subMatchVar ...?"}} test regexp-6.3 {regexp errors} jim { list [catch {regexp -gorp a} msg] $msg } {1 {bad switch "-gorp": must be --, -all, -indices, -inline, -line, -nocase, or -start}} test regexp-6.4 {regexp errors} { catch {regexp a( b} msg } 1 #test regexp-6.5 {regexp errors} { # list [catch {regexp a) b} msg] [string match *parentheses* $msg] #} {1 1} test regexp-6.6 {regexp errors} { list [catch {regexp a a f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1 f1} msg] $msg } {0 1} test regexp-6.7 {regexp errors} { list [catch {regexp (x)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.) xyzzy} msg] $msg } {0 0} test regexp-6.8 {regexp errors} jim { catch {unset f1} set f1 44 list [catch {regexp abc abc f1(f2)} msg] $msg } {1 {can't set "f1(f2)": variable isn't array}} test regexp-6.9 {regexp errors, -start bad int check} { list [catch {regexp -start bogus {^$} {}} msg] $msg } {1 {bad index "bogus": must be integer?[+-]integer? or end?[+-]integer?}} test regexp-7.1 {basic regsub operation} { list [regsub aa+ xaxaaaxaa 111&222 foo] $foo } {1 xax111aaa222xaa} test regexp-7.2 {basic regsub operation} { list [regsub aa+ aaaxaa &111 foo] $foo } {1 aaa111xaa} test regexp-7.3 {basic regsub operation} { list [regsub aa+ xaxaaa 111& foo] $foo } {1 xax111aaa} test regexp-7.4 {basic regsub operation} { list [regsub aa+ aaa 11&2&333 foo] $foo } {1 11aaa2aaa333} test regexp-7.5 {basic regsub operation} { list [regsub aa+ xaxaaaxaa &2&333 foo] $foo } {1 xaxaaa2aaa333xaa} test regexp-7.6 {basic regsub operation} { list [regsub aa+ xaxaaaxaa 1&22& foo] $foo } {1 xax1aaa22aaaxaa} test regexp-7.7 {basic regsub operation} { list [regsub a(a+) xaxaaaxaa {1\122\1} foo] $foo } {1 xax1aa22aaxaa} test regexp-7.8 {basic regsub operation} { list [regsub a(a+) xaxaaaxaa {1\\\122\1} foo] $foo } "1 {xax1\\aa22aaxaa}" test regexp-7.9 {basic regsub operation} { list [regsub a(a+) xaxaaaxaa {1\\122\1} foo] $foo } "1 {xax1\\122aaxaa}" test regexp-7.10 {basic regsub operation} { list [regsub a(a+) xaxaaaxaa {1\\&\1} foo] $foo } "1 {xax1\\aaaaaxaa}" test regexp-7.11 {basic regsub operation} { list [regsub a(a+) xaxaaaxaa {1\&\1} foo] $foo } {1 xax1&aaxaa} test regexp-7.12 {basic regsub operation} { list [regsub a(a+) xaxaaaxaa {\1\1\1\1&&} foo] $foo } {1 xaxaaaaaaaaaaaaaaxaa} test regexp-7.13 {basic regsub operation} { set foo xxx list [regsub abc xyz 111 foo] $foo } {0 xyz} test regexp-7.14 {basic regsub operation} { set foo xxx list [regsub ^ xyz "111 " foo] $foo } {1 {111 xyz}} test regexp-7.15 {basic regsub operation} { set foo xxx list [regsub -- -foo abc-foodef "111 " foo] $foo } {1 {abc111 def}} test regexp-7.16 {basic regsub operation} { set foo xxx list [regsub x "" y foo] $foo } {0 {}} #test regexp-7.17 {regsub utf compliance} { # # if not UTF-8 aware, result is "0 1" # set foo "xyz555ijka\u4e4ebpqr" # regsub a\u4e4eb xyza\u4e4ebijka\u4e4ebpqr 555 bar # list [string compare $foo $bar] [regexp 4 $bar] #} {0 0} test regexp-8.1 {case conversion in regsub} { list [regsub -nocase a(a+) xaAAaAAay & foo] $foo } {1 xaAAaAAay} test regexp-8.2 {case conversion in regsub} { list [regsub -nocase a(a+) xaAAaAAay & foo] $foo } {1 xaAAaAAay} test regexp-8.3 {case conversion in regsub} { set foo 123 list [regsub a(a+) xaAAaAAay & foo] $foo } {0 xaAAaAAay} test regexp-8.4 {case conversion in regsub} { set foo 123 list [regsub -nocase a CaDE b foo] $foo } {1 CbDE} test regexp-8.5 {case conversion in regsub} { set foo 123 list [regsub -nocase XYZ CxYzD b foo] $foo } {1 CbD} test regexp-8.6 {case conversion in regsub} { set x abcdefghijklmnopqrstuvwxyz1234567890 set x $x$x$x$x$x$x$x$x$x$x$x$x set foo 123 list [regsub -nocase $x $x b foo] $foo } {1 b} test regexp-9.1 {-all option to regsub} { set foo 86 list [regsub -all x+ axxxbxxcxdx |&| foo] $foo } {4 a|xxx|b|xx|c|x|d|x|} test regexp-9.2 {-all option to regsub} { set foo 86 list [regsub -nocase -all x+ aXxXbxxcXdx |&| foo] $foo } {4 a|XxX|b|xx|c|X|d|x|} test regexp-9.3 {-all option to regsub} { set foo 86 list [regsub x+ axxxbxxcxdx |&| foo] $foo } {1 a|xxx|bxxcxdx} test regexp-9.4 {-all option to regsub} { set foo 86 list [regsub -all bc axxxbxxcxdx |&| foo] $foo } {0 axxxbxxcxdx} test regexp-9.5 {-all option to regsub} { set foo xxx list [regsub -all node "node node more" yy foo] $foo } {2 {yy yy more}} test regexp-9.6 {-all option to regsub} { set foo xxx list [regsub -all ^ xxx 123 foo] $foo } {1 123xxx} test regexp-10.2 {newline sensitivity in regsub} { set foo xxx list [regsub -line {^a.*b$} "dabc\naxyb\n" 123 foo] $foo } "1 {dabc\n123\n}" test regexp-10.3 {newline sensitivity in regsub} { set foo xxx list [regsub -line {^a.*b$} "dabc\naxyb\nxb" 123 foo] $foo } "1 {dabc\n123\nxb}" #test regexp-10.4 {partial newline sensitivity in regsub} { # set foo xxx # list [regsub -lineanchor {^a.*b$} "da\naxyb\nxb" 123 foo] $foo #} "1 {da\n123}" #test regexp-10.5 {inverse partial newline sensitivity in regsub} { # set foo xxx # list [regsub -linestop {a.*b} "da\nbaxyb\nxb" 123 foo] $foo #} "1 {da\nb123\nxb}" test regexp-11.1 {regsub errors} jim { list [catch {regsub a b} msg] $msg } {1 {wrong # args: should be "regsub ?switches? exp string subSpec ?varName?"}} test regexp-11.2 {regsub errors} jim { list [catch {regsub -nocase a b} msg] $msg } {1 {wrong # args: should be "regsub ?switches? exp string subSpec ?varName?"}} test regexp-11.3 {regsub errors} jim { list [catch {regsub -nocase -all a b} msg] $msg } {1 {wrong # args: should be "regsub ?switches? exp string subSpec ?varName?"}} test regexp-11.4 {regsub errors} jim { list [catch {regsub a b c d e f} msg] $msg } {1 {wrong # args: should be "regsub ?switches? exp string subSpec ?varName?"}} test regexp-11.5 {regsub errors} jim { list [catch {regsub -gorp a b c} msg] $msg } {1 {bad switch "-gorp": must be --, -all, -line, -nocase, or -start}} test regexp-11.6 {regsub errors} { catch {regsub -nocase a( b c d} msg } 1 test regexp-11.7 {regsub errors} jim { catch {unset f1} set f1 44 list [catch {regsub -nocase aaa aaa xxx f1(f2)} msg] $msg } {1 {can't set "f1(f2)": variable isn't array}} test regexp-11.8 {regsub errors, -start bad int check} { list [catch {regsub -start bogus pattern string rep var} msg] $msg } {1 {bad index "bogus": must be integer?[+-]integer? or end?[+-]integer?}} test regexp-11.9 {regsub without final variable name returns value} { regsub b abaca X } {aXaca} test regexp-11.10 {regsub without final variable name returns value} { regsub -all a abaca X } {XbXcX} test regexp-11.11 {regsub without final variable name returns value} { regsub b(\[^d\]*)d abcdeabcfde {,&,\1,} } {a,bcd,c,eabcfde} test regexp-11.12 {regsub without final variable name returns value} { regsub -all b(\[^d\]*)d abcdeabcfde {,&,\1,} } {a,bcd,c,ea,bcfd,cf,e} # This test crashes on the Mac unless you increase the Stack Space to about 1 # Meg. This is probably bigger than most users want... # 8.2.3 regexp reduced stack space requirements, but this should be # tested again test regexp-12.1 {Tcl_RegExpExec: large number of subexpressions} { list [regexp (.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.) abcdefghijklmnopqrstuvwxyz all a b c d e f g h i j k l m n o p q r s t u v w x y z] $all $a $b $c $d $e $f $g $h $i $j $k $l $m $n $o $p $q $r $s $t $u $v $w $x $y $z } {1 abcdefghijklmnopqrstuvwxyz a b c d e f g h i j k l m n o p q r s t u v w x y z} test regexp-13.1 {regsub of a very large string} { # This test is designed to stress the memory subsystem in order # to catch Bug #933. It only fails if the Tcl memory allocator # is in use. set line {BEGIN_TABLE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; END_TABLE} set filedata [string repeat $line 200] for {set i 1} {$i<10} {incr i} { regsub -all "BEGIN_TABLE " $filedata "" newfiledata } set x done } {done} test regexp-14.1 {CompileRegexp: regexp cache} { regexp .*a b regexp .*b c regexp .*c d regexp .*d e regexp .*e f set x . append x *a regexp $x bbba } 1 test regexp-14.2 {CompileRegexp: regexp cache, different flags} { regexp .*a b regexp .*b c regexp .*c d regexp .*d e regexp .*e f set x . append x *a regexp -nocase $x bbba } 1 #test regexp-15.1 {regexp -start} { # catch {unset x} # list [regexp -start -10 {\d} 1abc2de3 x] $x #} {1 1} #test regexp-15.2 {regexp -start} { # catch {unset x} # list [regexp -start 2 {\d} 1abc2de3 x] $x #} {1 2} #test regexp-15.3 {regexp -start} { # catch {unset x} # list [regexp -start 4 {\d} 1abc2de3 x] $x #} {1 2} #test regexp-15.4 {regexp -start} { # catch {unset x} # list [regexp -start 5 {\d} 1abc2de3 x] $x #} {1 3} test regexp-15.5 {regexp -start, over end of string} { catch {unset x} list [regexp -start [string length 1abc2de3] {\d} 1abc2de3 x] [info exists x] } {0 0} test regexp-15.6 {regexp -start, loss of ^$ behavior} { list [regexp -start 2 {^$} {}] } {0} test regexp-15.7 {regexp -start, double option} { regexp -start 2 -start 0 a abc } 1 test regexp-15.8 {regexp -start, double option} { regexp -start 0 -start 2 a abc } 0 #test regexp-15.9 {regexp -start, end relative index} { # catch {unset x} # list [regexp -start end {\d} 1abc2de3 x] [info exists x] #} {0 0} #test regexp-15.10 {regexp -start, end relative index} { # catch {unset x} # list [regexp -start end-1 {\d} 1abc2de3 x] [info exists x] $x #} {1 1 3} # #test regexp-16.1 {regsub -start} { # catch {unset x} # list [regsub -all -start 2 {\d} a1b2c3d4e5 {/&} x] $x #} {4 a1b/2c/3d/4e/5} test regexp-16.2 {regsub -start} { catch {unset x} list [regsub -all -start -25 {z} hello {/&} x] $x } {0 hello} test regexp-16.3 {regsub -start} { catch {unset x} list [regsub -all -start 3 {z} hello {/&} x] $x } {0 hello} #test regexp-16.4 {regsub -start, \A behavior} { # set out {} # lappend out [regsub -start 0 -all {\A(\w)} {abcde} {/\1} x] $x # lappend out [regsub -start 2 -all {\A(\w)} {abcde} {/\1} x] $x #} {5 /a/b/c/d/e 3 ab/c/d/e} test regexp-16.5 {regsub -start, double option} { list [regsub -start 2 -start 0 a abc c x] $x } {1 cbc} test regexp-16.6 {regsub -start, double option} { list [regsub -start 0 -start 2 a abc c x] $x } {0 abc} test regexp-16.7 {regexp -start, end relative index} { list [regsub -start end a aaa b x] $x } {0 aaa} test regexp-16.8 {regexp -start, end relative index} { list [regsub -start end-1 a aaa b x] $x } {1 aab} test regexp-17.1 {regexp -inline} { regexp -inline b ababa } {b} test regexp-17.2 {regexp -inline} { regexp -inline (b) ababa } {b b} test regexp-17.3 {regexp -inline -indices} { regexp -inline -indices (b) ababa } {{1 1} {1 1}} #test regexp-17.4 {regexp -inline} { # regexp -inline {\w(\d+)\w} " hello 23 there456def " #} {e456d 456} #test regexp-17.5 {regexp -inline no matches} { # regexp -inline {\w(\d+)\w} "" #} {} test regexp-17.6 {regexp -inline no matches} { regexp -inline hello goodbye } {} test regexp-17.7 {regexp -inline, no matchvars allowed} { list [catch {regexp -inline b abc match} msg] $msg } {1 {regexp match variables not allowed when using -inline}} test regexp-18.1 {regexp -all} { regexp -all b bbbbb } {5} test regexp-18.2 {regexp -all} { regexp -all b abababbabaaaaaaaaaab } {6} test regexp-18.3 {regexp -all -inline} { regexp -all -inline b abababbabaaaaaaaaaab } {b b b b b b} #test regexp-18.4 {regexp -all -inline} { # regexp -all -inline {\w(\w)} abcdefg #} {ab b cd d ef f} #test regexp-18.5 {regexp -all -inline} { # regexp -all -inline {\w(\w)$} abcdefg #} {fg g} #test regexp-18.6 {regexp -all -inline} { # regexp -all -inline {\d+} 10:20:30:40 #} {10 20 30 40} test regexp-18.7 {regexp -all -inline} { list [catch {regexp -all -inline b abc match} msg] $msg } {1 {regexp match variables not allowed when using -inline}} test regexp-18.8 {regexp -all} { # This should not cause an infinite loop regexp -all -inline {a*} a } {a} test regexp-18.9 {regexp -all} { # Yes, the expected result is {a {}}. Here's why: # Start at index 0; a* matches the "a" there then stops. # Go to index 1; a* matches the lambda (or {}) there then stops. Recall # that a* matches zero or more "a"'s; thus it matches the string "b", as # there are zero or more "a"'s there. # Go to index 2; this is past the end of the string, so stop. regexp -all -inline {a*} ab } {a {}} test regexp-18.10 {regexp -all} { # Yes, the expected result is {a {} a}. Here's why: # Start at index 0; a* matches the "a" there then stops. # Go to index 1; a* matches the lambda (or {}) there then stops. Recall # that a* matches zero or more "a"'s; thus it matches the string "b", as # there are zero or more "a"'s there. # Go to index 2; a* matches the "a" there then stops. # Go to index 3; this is past the end of the string, so stop. regexp -all -inline {a*} aba } {a {} a} test regexp-18.11 {regexp -all} { regexp -all -inline {^a} aaaa } {a} test regexp-18.12 {regexp -all -inline -indices} { regexp -all -inline -indices a(b(c)d|e(f)g)h abcdhaefgh } {{0 4} {1 3} {2 2} {-1 -1} {5 9} {6 8} {-1 -1} {7 7}} test regexp-19.1 {regsub null replacement} { regsub -all {@} {@hel@lo@} "\0a\0" result list $result [string length $result] } "\0a\0hel\0a\0lo\0a\0 14" #test regexp-20.1 {regsub shared object shimmering} { # # Bug #461322 # set a abcdefghijklmnopqurstuvwxyz # set b $a # set c abcdefghijklmnopqurstuvwxyz0123456789 # regsub $a $c $b d # list $d [string length $d] [string bytelength $d] #} [list abcdefghijklmnopqurstuvwxyz0123456789 37 37] #test regexp-20.2 {regsub shared object shimmering with -about} { # eval regexp -about abc #} {0 {}} test regexp-21.1 {regsub works with empty string} { regsub -- ^ {} foo } {foo} test regexp-21.2 {regsub works with empty string} { regsub -- \$ {} foo } {foo} test regexp-21.3 {regsub works with empty string offset} { regsub -start 0 -- ^ {} foo } {foo} test regexp-21.4 {regsub works with empty string offset} { regsub -start 0 -- \$ {} foo } {foo} test regexp-21.5 {regsub works with empty string offset} { regsub -start 3 -- \$ {123} foo } {123foo} test regexp-21.6 {regexp works with empty string} { regexp -- ^ {} } {1} test regexp-21.7 {regexp works with empty string} { regexp -start 0 -- ^ {} } {1} test regexp-21.8 {regexp works with empty string offset} { regexp -start 3 -- ^ {123} } {0} test regexp-21.9 {regexp works with empty string offset} { regexp -start 3 -- \$ {123} } {1} #test regexp-21.10 {multiple matches handle newlines} { # regsub -all -lineanchor -- {^#[^\n]*\n} "#one\n#two\n#three\n" foo\n #} "foo\nfoo\nfoo\n" test regexp-21.11 {multiple matches handle newlines} { regsub -all -line -- ^ "a\nb\nc" \# } "\#a\n\#b\n\#c" test regexp-21.12 {multiple matches handle newlines} { regsub -all -line -- ^ "\n\n" \# } "\#\n\#\n\#" test regexp-21.13 {multiple matches handle newlines} { regexp -all -inline -indices -line -- ^ "a\nb\nc" } {{0 -1} {2 1} {4 3}} test regexp-21.14 {Literal newline in pattern} { regexp -all -inline "\n(\[ \t\]+)" "\n\t\t# This is a test" } "{\n\t\t} {\t\t}" test regexp-22.1 {effect of caching} jim { set filedata {BEGIN_TABLE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; END_TABLE} # Note: use 2 REs because often libc will cache a single regcomp() result # t1 should be faster because the compiled re can be cached. set re1 "END_TABLE" set re2 "BEGIN_TABLE" set t1 [time { regexp -inline -all $re1 $filedata regexp -inline -all $re2 $filedata } 10000] # t2 should be slower since the re's need to be recompiled every time set t2 [time { set re1 END append re1 _TABLE regexp -inline -all $re1 $filedata set re2 BEGIN append re2 _TABLE regexp -inline -all $re2 $filedata } 10000] set t1 [lindex $t1 0] set t2 [lindex $t2 0] # If these two times are within 20% of each other, caching isn't working expr {$t2 * 1.0 / $t1 < 1.2 && $t1 * 1.0 / $t2 < 1.2} } {0} testreport openocd-0.7.0/jimtcl/tests/filejoin.test0000644000175000001440000000311112134336723015206 00000000000000source [file dirname [info script]]/testing.tcl needs cmd file test join-1.1 "One name" { file join abc } {abc} test join-1.2 "One name with trailing slash" { file join abc/ } {abc} test join-1.3 "One name with leading slash" { file join /abc } {/abc} test join-1.4 "One name with leading and trailing slash" { file join /abc/ } {/abc} test join-1.5 "Two names" { file join abc def } {abc/def} test join-1.6 "Two names with dir trailing slash" { file join abc/ def } {abc/def} test join-1.7 "Two names with dir leading slash" { file join /abc def } {/abc/def} test join-1.8 "Two names with dir leading and trailing slash" { file join /abc/ def } {/abc/def} test join-1.9 "Two names with file trailing slash" { file join abc def/ } {abc/def} test join-1.10 "Two names with file leading slash" { file join abc /def } {/def} test join-1.11 "Two names with file leading and trailing slash" { file join abc /def/ } {/def} test join-1.12 "Two names with double slashes" { file join abc/ /def } {/def} test join-1.13 "Join to root" { file join / abc } {/abc} test join-1.14 "Join to root" { set dir [file join / .] # Either / or /. is OK here expr {$dir in {/ /.}} } 1 test join-1.15 "Join to root" { file join / / } {/} test join-1.16 "Join to root" { file join /abc / } {/} test join-2.1 "Dir is empty string" { file join "" def } {def} test join-2.2 "File is empty string" { file join abc "" } {abc} test join-2.3 "Path too long" jim { set components [string repeat {abcdefghi } 500] list [catch [concat file join $components] msg] $msg } {1 {Path too long}} testreport openocd-0.7.0/jimtcl/tests/Makefile0000644000175000001440000000024312134336723014151 00000000000000jimsh ?= ../jimsh test: @for i in *.test; do LD_LIBRARY_PATH=..:$(LD_LIBRARY_PATH) $(jimsh) $$i; done clean: rm -f gorp.file2 gorp.file sleepx test1 exec.tmp1 openocd-0.7.0/jimtcl/tests/lrange.test0000644000175000001440000000550312134336723014666 00000000000000# Commands covered: lrange # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. source [file dirname [info script]]/testing.tcl test lrange-1.1 {range of list elements} { lrange {a b c d} 1 2 } {b c} test lrange-1.2 {range of list elements} { lrange {a {bcd e {f g {}}} l14 l15 d} 1 1 } {{bcd e {f g {}}}} test lrange-1.3 {range of list elements} { lrange {a {bcd e {f g {}}} l14 l15 d} 3 end } {l15 d} test lrange-1.4 {range of list elements} { lrange {a {bcd e {f g {}}} l14 l15 d} 4 10000 } {d} test lrange-1.5 {range of list elements} { lrange {a {bcd e {f g {}}} l14 l15 d} 4 3 } {} test lrange-1.6 {range of list elements} { lrange {a {bcd e {f g {}}} l14 l15 d} 10 11 } {} test lrange-1.7 {range of list elements} { lrange {a b c d e} -1 2 } {a b c} test lrange-1.8 {range of list elements} { lrange {a b c d e} -2 -1 } {} test lrange-1.9 {range of list elements} { lrange {a b c d e} -2 end } {a b c d e} test lrange-1.10 {range of list elements} { lrange "a b\{c d" 1 2 } "b\\{c d" test lrange-1.11 {range of list elements} { lrange "a b c d" end end } d test lrange-1.12 {range of list elements} { lrange "a b c d" end 100000 } d test lrange-1.13 {range of list elements} { lrange "a b c d" end 3 } d test lrange-1.14 {range of list elements} { lrange "a b c d" end 2 } {} test lrange-1.15 {range of list elements} { concat \"[lrange {a b \{\ } 0 2]" } {"a b \{\ "} test lrange-1.16 {list element quoting} { lrange {[append a .b]} 0 end } {{[append} a .b\]} test lrange-2.1 {error conditions} { list [catch {lrange a b} msg] $msg } {1 {wrong # args: should be "lrange list first last"}} test lrange-2.2 {error conditions} { list [catch {lrange a b 6 7} msg] $msg } {1 {wrong # args: should be "lrange list first last"}} test lrange-2.3 {error conditions} { list [catch {lrange a b 6} msg] $msg } {1 {bad index "b": must be integer?[+-]integer? or end?[+-]integer?}} test lrange-2.4 {error conditions} { list [catch {lrange a 0 enigma} msg] $msg } {1 {bad index "enigma": must be integer?[+-]integer? or end?[+-]integer?}} test lrange-2.5 {error conditions} tcl { list [catch {lrange "a \{b c" 3 4} msg] $msg } {1 {unmatched open brace in list}} test lrange-2.6 {error conditions} tcl { list [catch {lrange "a b c \{ d e" 1 4} msg] $msg } {1 {unmatched open brace in list}} # cleanup ::tcltest::cleanupTests return openocd-0.7.0/jimtcl/tests/upvar.test0000644000175000001440000002027012134336723014551 00000000000000# Commands covered: upvar # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # RCS: @(#) $Id: upvar.test,v 1.7 2000/04/10 17:19:05 ericm Exp $ source [file dirname [info script]]/testing.tcl needs cmd array test upvar-1.1 {reading variables with upvar} { proc p1 {a b} {set c 22; set d 33; p2} proc p2 {} {upvar a x1 b x2 c x3 d x4; set a abc; list $x1 $x2 $x3 $x4 $a} p1 foo bar } {foo bar 22 33 abc} test upvar-1.2 {reading variables with upvar} { proc p1 {a b} {set c 22; set d 33; p2} proc p2 {} {p3} proc p3 {} {upvar 2 a x1 b x2 c x3 d x4; set a abc; list $x1 $x2 $x3 $x4 $a} p1 foo bar } {foo bar 22 33 abc} test upvar-1.3 {reading variables with upvar} { proc p1 {a b} {set c 22; set d 33; p2} proc p2 {} {p3} proc p3 {} { upvar #1 a x1 b x2 c x3 d x4 set a abc list $x1 $x2 $x3 $x4 $a } p1 foo bar } {foo bar 22 33 abc} test upvar-1.4 {reading variables with upvar} { set x1 44 set x2 55 proc p1 {} {p2} proc p2 {} { upvar 2 x1 x1 x2 a upvar #0 x1 b set c $b incr b 3 list $x1 $a $b } p1 } {47 55 47} test upvar-1.5 {reading array elements with upvar} { proc p1 {} {set a(0) zeroth; set a(1) first; p2} proc p2 {} {upvar a(0) x; set x} p1 } {zeroth} test upvar-2.1 {writing variables with upvar} { proc p1 {a b} {set c 22; set d 33; p2; list $a $b $c $d} proc p2 {} { upvar a x1 b x2 c x3 d x4 set x1 14 set x4 88 } p1 foo bar } {14 bar 22 88} test upvar-2.2 {writing variables with upvar} { set x1 44 set x2 55 proc p1 {x1 x2} { upvar #0 x1 a upvar x2 b set a $x1 set b $x2 } p1 newbits morebits list $x1 $x2 } {newbits morebits} test upvar-2.3 {writing variables with upvar} { catch {unset x1} catch {unset x2} proc p1 {x1 x2} { upvar #0 x1 a upvar x2 b set a $x1 set b $x2 } p1 newbits morebits list [catch {set x1} msg] $msg [catch {set x2} msg] $msg } {0 newbits 0 morebits} test upvar-2.4 {writing array elements with upvar} { proc p1 {} {set a(0) zeroth; set a(1) first; list [p2] $a(0)} proc p2 {} {upvar a(0) x; set x xyzzy} p1 } {xyzzy xyzzy} test upvar-3.1 {unsetting variables with upvar} { proc p1 {a b} {set c 22; set d 33; p2; lsort [info vars]} proc p2 {} { upvar 1 a x1 d x2 unset x1 x2 } p1 foo bar } {b c} test upvar-3.2 {unsetting variables with upvar} { proc p1 {a b} {set c 22; set d 33; p2; lsort [info vars]} proc p2 {} { upvar 1 a x1 d x2 unset x1 x2 set x2 28 } p1 foo bar } {b c d} test upvar-3.3 {unsetting variables with upvar} { set x1 44 set x2 55 proc p1 {} {p2} proc p2 {} { upvar 2 x1 a upvar #0 x2 b unset a b } p1 list [info exists x1] [info exists x2] } {0 0} test upvar-3.4 {unsetting variables with upvar} { set x1 44 set x2 55 proc p1 {} { upvar x1 a x2 b unset a b set b 118 } p1 list [info exists x1] [catch {set x2} msg] $msg } {0 0 118} test upvar-3.5 {unsetting array elements with upvar} { proc p1 {} { set a(0) zeroth set a(1) first set a(2) second p2 array names a } proc p2 {} {upvar a(0) x; unset x} p1 } {1 2} test upvar-3.6 {unsetting then resetting array elements with upvar} { proc p1 {} { set a(0) zeroth set a(1) first set a(2) second p2 list [array names a] [catch {set a(0)} msg] $msg } proc p2 {} {upvar a(0) x; unset x; set x 12345} p1 } {{0 1 2} 0 12345} test upvar-4.1 {nested upvars} { set x1 88 proc p1 {a b} {set c 22; set d 33; p2} proc p2 {} {global x1; upvar c x2; p3} proc p3 {} { upvar x1 a x2 b list $a $b } p1 14 15 } {88 22} test upvar-4.2 {nested upvars} { set x1 88 proc p1 {a b} {set c 22; set d 33; p2; list $a $b $c $d} proc p2 {} {global x1; upvar c x2; p3} proc p3 {} { upvar x1 a x2 b set a foo set b bar } list [p1 14 15] $x1 } {{14 15 bar 33} foo} proc tproc {args} {global x; set x [list $args [uplevel info vars]]} test upvar-6.1 {retargeting an upvar} { proc p1 {} { set a(0) zeroth set a(1) first set a(2) second p2 } proc p2 {} { upvar a x set result {} foreach i [array names x] { upvar a($i) x lappend result $x } lsort $result } p1 } {first second zeroth} test upvar-6.2 {retargeting an upvar} { set x 44 set y abcde proc p1 {} { global x set result $x upvar y x lappend result $x } p1 } {44 abcde} test upvar-6.3 {retargeting an upvar} { set x 44 set y abcde proc p1 {} { upvar y x lappend result $x global x lappend result $x } p1 } {abcde 44} test upvar-7.1 {upvar to same level} { set x 44 set y 55 catch {unset uv} upvar #0 x uv set uv abc upvar 0 y uv set uv xyzzy list $x $y } {abc xyzzy} test upvar-7.2 {upvar to same level} { set x 1234 set y 4567 proc p1 {x y} { upvar 0 x uv set uv $y return "$x $y" } p1 44 89 } {89 89} test upvar-7.3 {upvar to same level} { set x 1234 set y 4567 proc p1 {x y} { upvar #1 x uv set uv $y return "$x $y" } p1 xyz abc } {abc abc} test upvar-7.4 {upvar to same level: tricky problems when deleting variable table} { proc tt {} {upvar #1 toto loc; return $loc} list [catch tt msg] $msg } {1 {can't read "loc": no such variable}} test upvar-7.5 {potential memory leak when deleting variable table} { proc leak {} { array set foo {1 2 3 4} upvar 0 foo(1) bar } leak } {} test upvar-8.1 {errors in upvar command} { catch upvar msg } 1 test upvar-8.2 {errors in upvar command} { catch {upvar 1} } 1 test upvar-8.3 {errors in upvar command} { proc p1 {} {upvar a b c} catch p1 } 1 test upvar-8.4 {errors in upvar command} { proc p1 {} {upvar 0 b b} list [catch p1 msg] $msg } {1 {can't upvar from variable to itself}} test upvar-8.5 {errors in upvar command} { proc p1 {} {upvar 0 a b; upvar 0 b a} list [catch p1 msg] $msg } {1 {can't upvar from variable to itself}} test upvar-8.6 {errors in upvar command} { proc p1 {} {set a 33; upvar b a} list [catch p1 msg] $msg } {1 {variable "a" already exists}} # Jim allows dicts within dicts. Tcl can't do this. test upvar-8.8 {create nested array with upvar} jim { proc p1 {} {upvar x(a) b; set b(2) 44} catch {unset x} p1 set x } {a {2 44}} test upvar-8.10 {upvar will create element alias for new array element} { catch {unset upvarArray} array set upvarArray {} catch {upvar 0 upvarArray(elem) upvarArrayElemAlias} } {0} test upvar-8.11 {error upvar array element} { proc a {} { upvar a b(1) } list [catch {a} msg] $msg } {1 {bad variable name "b(1)": upvar won't create a scalar variable that looks like an array element}} test upvar-9.1 {global redefine} { proc p1 {} { global x; global x } p1 } {} test upvar-9.2 {upvar redefine} { set a 1 set b 2 proc p1 {} { upvar a x; upvar b x; return $x } p1 } 2 test upvar-9.3 {upvar redefine static} jim { proc p1 {} {{a 3}} { upvar b a; return $b } list [catch p1 msg] $msg } {1 {variable "a" already exists}} test upvar-9.4 {upvar links to static} jim { proc p1 {} {} { upvar a x; incr x; return $x } proc p2 {} {{a 3}} { list [p1] $a } p2 } {4 4} test upvar-9.5 {upvar via global namespace} { set x 2 unset -nocomplain y # Links ::y to ::x proc p1 {} { upvar x ::y; incr ::y -1 } p1 list $x $y } {1 1} test upvar-9.6 {upvar via global namespace} { set x 2 unset -nocomplain x # Links ::x to ::x proc p1 {} { upvar x ::x; incr ::x } list [catch p1 msg] $msg } {1 {can't upvar from variable to itself}} test upvar-9.7 {upvar to higher level} { proc p1 {} { upvar 0 x ::globx } list [catch p1 msg] $msg } {1 {bad variable name "::globx": upvar won't create namespace variable that refers to procedure variable}} catch {unset a} testreport openocd-0.7.0/jimtcl/tests/filecopy.test0000644000175000001440000000375312134336723015235 00000000000000source [file dirname [info script]]/testing.tcl needs constraint jim needs cmd file needs cmd exec needs cmd parray tclcompat cd $testdir file mkdir tempdir test filecopy-1.1 "Simple case" { file copy testio.in tempfile } {} test filecopy-1.2 "Target exists" { list [catch {file copy testio.in tempfile} msg] $msg } {1 {error copying "testio.in" to "tempfile": file already exists}} test filecopy-1.3 "Source doesn't exist" { list [catch {file copy missing tempfile} msg] $msg } {1 {missing: No such file or directory}} test filecopy-1.4 "Can't write to target" { list [catch {file copy testio.in tempdir} msg] $msg } {1 {error copying "testio.in" to "tempdir": file already exists}} test filecopy-1.5 "Source doesn't exist and can't write to target" { list [catch {file copy missing tempdir} msg] $msg } {1 {missing: No such file or directory}} test filecopy-1.6 "Wrong args" { list [catch {file copy onearg} msg] $msg } {1 {wrong # args: should be "file copy ?-force? source dest"}} test filecopy-1.7 "Wrong args" { list [catch {file copy too many args here} msg] $msg } {1 {wrong # args: should be "file copy ?-force? source dest"}} test filecopy-1.8 "Wrong args" { list [catch {file copy -blah testio.in tempfile} msg] $msg } {1 {bad option "-blah": should be -force}} file delete tempfile test filecopy-2.1 "Simple case (-force)" { file copy -force testio.in tempfile } {} test filecopy-2.2 "Target exists (-force)" { file copy -force testio.in tempfile } {} test filecopy-2.3 "Source doesn't exist (-force)" { list [catch {file copy -force missing tempfile} msg] $msg } {1 {missing: No such file or directory}} test filecopy-2.4 "Can't write to target (-force)" -body { file copy -force testio.in tempdir } -returnCodes error -match glob -result {tempdir: *} test filecopy-2.5 "Source doesn't exist and can't write to target (-force)" { list [catch {file copy -force missing tempdir} msg] $msg } {1 {missing: No such file or directory}} file delete tempfile exec rm -rf tempdir testreport openocd-0.7.0/jimtcl/tests/return-break.tcl0000644000175000001440000000003212134336723015612 00000000000000return -code break result openocd-0.7.0/jimtcl/tests/stacktrace.test0000644000175000001440000001461712134336723015550 00000000000000source [file dirname [info script]]/testing.tcl needs constraint jim; needs cmd package package require errors # Make this a proc so that the line numbers don't have to change proc main {} { set id1 0 foreach type {badcmd badvar error interpbadvar interpbadcmd package source badpackage returncode} { set id2 0 incr id1 foreach method {call uplevel eval evalstr} { incr id2 set exp "" if {[info exists ::expected(err-$id1.$id2)]} { set exp $::expected(err-$id1.$id2) } test err-$id1.$id2 "Stacktrace on error type $type, method $method" { set rc [catch {error_caller $type $method} msg] #puts "\n-----------------\n$type, $method\n[errorInfo $msg]\n\n" if {$::SHOW_EXPECTED} { puts stderr "\terr-$id1.$id2 {[list $rc $msg [info stacktrace]]}" } list $rc $msg [info stacktrace] } $exp } } proc unknown {args} { error "from unknown" } test err-10.1 "Stacktrace on error from unknown (badcmd, call)" { set rc [catch {error_caller badcmd call} msg] #puts stderr "err-10.1\n[errorInfo $msg]\n" #puts stderr "\terr-10.1 {[list $rc $msg [info stacktrace]]}" list $rc $msg [info stacktrace] } {1 {from unknown} {{} stacktrace.test 26 {} errors.tcl 6 error_generator errors.tcl 44 error_caller stacktrace.test 30}} rename unknown "" set a {one} set b [list 1 \ 2 \ 3] set c {two} set d "list 1 2 3" set e {three} set f "list 1 \ 2 \ 3" set g {four} test source-1.1 "Basic line numbers" { info source $a } {stacktrace.test 39} test source-1.2 "Line numbers after command with escaped newlines" { info source $c } {stacktrace.test 43} test source-1.3 "Line numbers after string with newlines" { info source $e } {stacktrace.test 47} test source-1.4 "Line numbers after string with escaped newlines" { info source $g } {stacktrace.test 51} } set expected { err-1.1 {1 {invalid command name "bogus"} {{} errors.tcl 6 error_generator errors.tcl 44 error_caller stacktrace.test 17}} err-1.2 {1 {invalid command name "bogus"} {{} errors.tcl 6 error_generator errors.tcl 47 error_caller stacktrace.test 17}} err-1.3 {1 {invalid command name "bogus"} {{} errors.tcl 6 error_generator errors.tcl 50 error_caller stacktrace.test 17}} err-1.4 {1 {invalid command name "bogus"} {{} errors.tcl 6 error_generator errors.tcl 53 error_caller stacktrace.test 17}} err-2.1 {1 {can't read "bogus": no such variable} {{} errors.tcl 9 error_generator errors.tcl 44 error_caller stacktrace.test 17}} err-2.2 {1 {can't read "bogus": no such variable} {{} errors.tcl 9 error_generator errors.tcl 47 error_caller stacktrace.test 17}} err-2.3 {1 {can't read "bogus": no such variable} {{} errors.tcl 9 error_generator errors.tcl 50 error_caller stacktrace.test 17}} err-2.4 {1 {can't read "bogus": no such variable} {{} errors.tcl 9 error_generator errors.tcl 53 error_caller stacktrace.test 17}} err-3.1 {1 bogus {{} errors.tcl 12 error_generator errors.tcl 44 error_caller stacktrace.test 17}} err-3.2 {1 bogus {{} errors.tcl 12 error_generator errors.tcl 47 error_caller stacktrace.test 17}} err-3.3 {1 bogus {{} errors.tcl 12 error_generator errors.tcl 50 error_caller stacktrace.test 17}} err-3.4 {1 bogus {{} errors.tcl 12 error_generator errors.tcl 53 error_caller stacktrace.test 17}} err-4.1 {1 {can't read "bogus": no such variable} {{} errors.tcl 15 error_generator errors.tcl 44 error_caller stacktrace.test 17}} err-4.2 {1 {can't read "bogus": no such variable} {{} errors.tcl 15 error_generator errors.tcl 47 error_caller stacktrace.test 17}} err-4.3 {1 {can't read "bogus": no such variable} {{} errors.tcl 15 error_generator errors.tcl 50 error_caller stacktrace.test 17}} err-4.4 {1 {can't read "bogus": no such variable} {{} errors.tcl 15 error_generator errors.tcl 53 error_caller stacktrace.test 17}} err-5.1 {1 {can't read "bogus": no such variable} {{} errors.tcl 18 error_generator errors.tcl 44 error_caller stacktrace.test 17}} err-5.2 {1 {can't read "bogus": no such variable} {{} errors.tcl 18 error_generator errors.tcl 47 error_caller stacktrace.test 17}} err-5.3 {1 {can't read "bogus": no such variable} {{} errors.tcl 18 error_generator errors.tcl 50 error_caller stacktrace.test 17}} err-5.4 {1 {can't read "bogus": no such variable} {{} errors.tcl 18 error_generator errors.tcl 53 error_caller stacktrace.test 17}} err-6.1 {1 {from dummyproc Can't load package dummy} {{} dummy.tcl 3 dummyproc dummy.tcl 6 {} errors.tcl 21 error_generator errors.tcl 44 error_caller stacktrace.test 17}} err-6.2 {1 {from dummyproc Can't load package dummy} {{} dummy.tcl 3 dummyproc dummy.tcl 6 {} errors.tcl 21 error_generator errors.tcl 47 error_caller stacktrace.test 17}} err-6.3 {1 {from dummyproc Can't load package dummy} {{} dummy.tcl 3 dummyproc dummy.tcl 6 {} errors.tcl 21 error_generator errors.tcl 50 error_caller stacktrace.test 17}} err-6.4 {1 {from dummyproc Can't load package dummy} {{} dummy.tcl 3 dummyproc dummy.tcl 6 {} errors.tcl 21 error_generator errors.tcl 53 error_caller stacktrace.test 17}} err-7.1 {1 {from dummyproc} {{} dummy.tcl 3 dummyproc dummy.tcl 6 {} errors.tcl 24 error_generator errors.tcl 44 error_caller stacktrace.test 17}} err-7.2 {1 {from dummyproc} {{} dummy.tcl 3 dummyproc dummy.tcl 6 {} errors.tcl 24 error_generator errors.tcl 47 error_caller stacktrace.test 17}} err-7.3 {1 {from dummyproc} {{} dummy.tcl 3 dummyproc dummy.tcl 6 {} errors.tcl 24 error_generator errors.tcl 50 error_caller stacktrace.test 17}} err-7.4 {1 {from dummyproc} {{} dummy.tcl 3 dummyproc dummy.tcl 6 {} errors.tcl 24 error_generator errors.tcl 53 error_caller stacktrace.test 17}} err-8.1 {1 {Can't load package bogus} {{} errors.tcl 27 error_generator errors.tcl 44 error_caller stacktrace.test 17}} err-8.2 {1 {Can't load package bogus} {{} errors.tcl 27 error_generator errors.tcl 47 error_caller stacktrace.test 17}} err-8.3 {1 {Can't load package bogus} {{} errors.tcl 27 error_generator errors.tcl 50 error_caller stacktrace.test 17}} err-8.4 {1 {Can't load package bogus} {{} errors.tcl 27 error_generator errors.tcl 53 error_caller stacktrace.test 17}} err-9.1 {1 failure {{} errors.tcl 44 error_caller stacktrace.test 17}} err-9.2 {1 failure {{} errors.tcl 47 error_caller stacktrace.test 17}} err-9.3 {1 failure {{} errors.tcl 50 error_caller stacktrace.test 17}} err-9.4 {1 failure {{} errors.tcl 53 error_caller stacktrace.test 17}} } # Set this to output expected results to stderr # in a form which can be pasted into 'expected' below set SHOW_EXPECTED 0 main testreport openocd-0.7.0/jimtcl/tests/apply.test0000644000175000001440000001023312134336723014537 00000000000000# Commands covered: apply # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994-1996 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # Copyright (c) 2005-2006 Miguel Sofer # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. source [file dirname [info script]]/testing.tcl needs cmd apply # Tests for wrong number of arguments test apply-1.1 {too few arguments} -returnCodes error -body { apply } -result {wrong # args: should be "apply lambdaExpr ?arg ...?"} # Tests for malformed lambda test apply-2.0 {malformed lambda} -returnCodes error -body { set lambda a apply $lambda } -result {can't interpret "a" as a lambda expression} test apply-2.1 {malformed lambda} -returnCodes error -body { set lambda [list a b c d] apply $lambda } -result {can't interpret "a b c d" as a lambda expression} test apply-2.2 {malformed lambda} -body { set lambda [list {{}} boo] apply $lambda } -returnCodes error -match glob -result {*argument with no name} test apply-2.3 {malformed lambda} { set lambda [list {{a b c}} boo] list [catch {apply $lambda} msg] $msg } {1 {too many fields in argument specifier "a b c"}} # Note that Jim allow both of these test apply-2.4 {malformed lambda} tcl { set lambda [list a(1) {return $a(1)}] list [catch {apply $lambda x} msg] $msg } {1 {formal parameter "a(1)" is an array element}} test apply-2.5 {malformed lambda} tcl { set lambda [list a::b {return $a::b}] list [catch {apply $lambda x} msg] $msg } {1 {formal parameter "a::b" is not a simple name}} # Tests for runtime errors in the lambda expression test apply-4.1 {error in arguments to lambda expression} -body { set lambda [list x {set x 1}] apply $lambda } -returnCodes error -result {wrong # args: should be "apply lambdaExpr x"} test apply-4.2 {error in arguments to lambda expression} -body { set lambda [list x {set x 1}] apply $lambda a b } -returnCodes error -result {wrong # args: should be "apply lambdaExpr x"} test apply-5.1 {runtime error in lambda expression} { set lambda [list {} {error foo}] list [catch {apply $lambda} msg] $msg } {1 foo} # Tests for correct execution; as the implementation is the same as that for # procs, the general functionality is mostly tested elsewhere test apply-6.1 {info level} { set lev [info level] set lambda [list {} {info level}] expr {[apply $lambda] - $lev} } 1 test apply-6.2 {info level} tcl { set lambda [list {} {info level 0}] apply $lambda } {apply {{} {info level 0}}} test apply-6.3 {info level} tcl { set lambda [list args {info level 0}] apply $lambda x y } {apply {args {info level 0}} x y} # Tests for correct argument treatment set applyBody { set res {} foreach v [info locals] { if {$v eq "res"} continue lappend res [list $v [set $v]] } set res } test apply-8.1 {args treatment} { apply [list args $applyBody] 1 2 3 } {{args {1 2 3}}} test apply-8.2 {args treatment} { apply [list {x args} $applyBody] 1 2 } {{x 1} {args 2}} test apply-8.3 {args treatment} { apply [list {x args} $applyBody] 1 2 3 } {{x 1} {args {2 3}}} test apply-8.4 {default values} { apply [list {{x 1} {y 2}} $applyBody] } {{x 1} {y 2}} test apply-8.5 {default values} { apply [list {{x 1} {y 2}} $applyBody] 3 4 } {{x 3} {y 4}} test apply-8.6 {default values} { apply [list {{x 1} {y 2}} $applyBody] 3 } {{x 3} {y 2}} test apply-8.7 {default values} { apply [list {x {y 2}} $applyBody] 1 } {{x 1} {y 2}} test apply-8.8 {default values} { apply [list {x {y 2}} $applyBody] 1 3 } {{x 1} {y 3}} test apply-8.9 {default values} { apply [list {x {y 2} args} $applyBody] 1 } {{x 1} {y 2} {args {}}} test apply-8.10 {default values} { apply [list {x {y 2} args} $applyBody] 1 3 } {{x 1} {y 3} {args {}}} ::tcltest::cleanupTests return # Local Variables: # mode: tcl # fill-column: 78 # End: openocd-0.7.0/jimtcl/tests/util.test0000644000175000001440000003503712134336723014400 00000000000000# This file is a Tcl script to test the code in the file tclUtil.c. # This file is organized in the standard fashion for Tcl tests. # # Copyright (c) 1995-1998 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. source [file dirname [info script]]/testing.tcl needs cmd binary testConstraint controversialNaN 1 testConstraint testdstring [llength [info commands testdstring]] testConstraint testconcatobj [llength [info commands testconcatobj]] # Big test for correct ordering of data in [expr] proc convertDouble { x } { variable ieeeValues if { $ieeeValues(littleEndian) } { binary scan [binary format w $x] d result } else { binary scan [binary format W $x] d result } return $result } test util-1.1 {TclFindElement procedure - binary element in middle of list} { lindex {0 foo\x00help 1} 1 } "foo\x00help" test util-1.2 {TclFindElement procedure - binary element at end of list} { lindex {0 foo\x00help} 1 } "foo\x00help" test util-2.1 {TclCopyAndCollapse procedure - normal string} { lindex {0 foo} 1 } {foo} test util-2.2 {TclCopyAndCollapse procedure - string with backslashes} { lindex {0 foo\n\x00help 1} 1 } "foo\n\x00help" test util-3.1 {Tcl_ScanCountedElement procedure - don't leave unmatched braces} { # This test checks for a very tricky feature. Any list element # generated with Tcl_ScanCountedElement and Tcl_ConvertElement must # have the property that it can be enclosing in curly braces to make # an embedded sub-list. If this property doesn't hold, then # Tcl_DStringStartSublist doesn't work. set x {} lappend x "# \\\{ \\" concat $x [llength "{$x}"] } {\#\ \\\{\ \\ 1} test util-3.2 {Tcl_ConverCountedElement procedure - quote leading '#'} { list # # a } {{#} # a} test util-3.3 {Tcl_ConverCountedElement procedure - quote leading '#'} { list #\{ # a } {\#\{ # a} test util-3.4 {Tcl_ConverCountedElement procedure - quote leading '#'} { proc # {} {return #} set result [eval [list #]] rename # {} set result } {#} test util-3.4.1 {Tcl_ConverCountedElement procedure - quote leading '#'} { proc # {} {return #} set cmd [list #] append cmd "" ;# force string rep generation set result [eval $cmd] rename # {} set result } {#} test util-3.5 {Tcl_ConverCountedElement procedure - quote leading '#'} { proc #\{ {} {return #} set result [eval [list #\{]] rename #\{ {} set result } {#} test util-3.5.1 {Tcl_ConverCountedElement procedure - quote leading '#'} { proc #\{ {} {return #} set cmd [list #\{] append cmd "" ;# force string rep generation set result [eval $cmd] rename #\{ {} set result } {#} test util-3.6 {Tcl_ConvertElement, Bug 3371644} tcl { interp create #\\ interp alias {} x #\\ concat interp target {} x ;# Crash if bug not fixed interp delete #\\ } {} test util-4.1 {Tcl_ConcatObj - backslash-space at end of argument} { concat a {b\ } c } {a b\ c} test util-4.2 {Tcl_ConcatObj - backslash-space at end of argument} { concat a {b\ } c } {a b\ c} test util-4.3 {Tcl_ConcatObj - backslash-space at end of argument} { concat a {b\\ } c } {a b\\ c} test util-4.4 {Tcl_ConcatObj - backslash-space at end of argument} { concat a {b } c } {a b c} test util-4.5 {Tcl_ConcatObj - backslash-space at end of argument} { concat a { } c } {a c} test util-4.6 {Tcl_ConcatObj - utf-8 sequence with "whitespace" char} { # Check for Bug #227512. If this violates C isspace, then it returns \xc3. concat \xe0 } \xe0 test util-4.7 {Tcl_ConcatObj - refCount safety} testconcatobj { # Check for Bug #1447328 (actually, bugs in its original "fix"). One of the # symptoms was Bug #2055782. testconcatobj } {} proc Wrapper_Tcl_StringMatch {pattern string} { # Forces use of Tcl_StringMatch, not Tcl_UniCharCaseMatch switch -glob -- $string $pattern {return 1} default {return 0} } test util-5.1 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch ab*c abc } 1 test util-5.2 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch ab**c abc } 1 test util-5.3 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch ab* abcdef } 1 test util-5.4 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch *c abc } 1 test util-5.5 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch *3*6*9 0123456789 } 1 test util-5.6 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch *3*6*9 01234567890 } 0 test util-5.7 {Tcl_StringMatch: UTF-8} { Wrapper_Tcl_StringMatch *u \u4e4fu } 1 test util-5.8 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch a?c abc } 1 test util-5.9 {Tcl_StringMatch: UTF-8} utf8 { # skip one character in string Wrapper_Tcl_StringMatch a?c a\u4e4fc } 1 test util-5.10 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch a??c abc } 0 test util-5.11 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch ?1??4???8? 0123456789 } 1 test util-5.12 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch {[abc]bc} abc } 1 test util-5.13 {Tcl_StringMatch: UTF-8} utf8 { # string += Tcl_UtfToUniChar(string, &ch); Wrapper_Tcl_StringMatch "\[\u4e4fxy\]bc" "\u4e4fbc" } 1 test util-5.14 {Tcl_StringMatch} { # if ((*pattern == ']') || (*pattern == '\0')) # badly formed pattern Wrapper_Tcl_StringMatch {[]} {[]} } 0 test util-5.15 {Tcl_StringMatch} { # if ((*pattern == ']') || (*pattern == '\0')) # badly formed pattern Wrapper_Tcl_StringMatch {[} {[} } 0 test util-5.16 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch {a[abc]c} abc } 1 test util-5.17 {Tcl_StringMatch: UTF-8} utf8 { # pattern += Tcl_UtfToUniChar(pattern, &endChar); # get 1 UTF-8 character Wrapper_Tcl_StringMatch "a\[a\u4e4fc]c" "a\u4e4fc" } 1 test util-5.18 {Tcl_StringMatch: UTF-8} { # pattern += Tcl_UtfToUniChar(pattern, &endChar); # proper advance: wrong answer would match on UTF trail byte of \u4e4f Wrapper_Tcl_StringMatch {a[a\u4e4fc]c} [bytestring a\u008fc] } 0 test util-5.19 {Tcl_StringMatch: UTF-8} { # pattern += Tcl_UtfToUniChar(pattern, &endChar); # proper advance. Wrapper_Tcl_StringMatch {a[a\u4e4fc]c} "acc" } 1 test util-5.20 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch {a[xyz]c} abc } 0 test util-5.21 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch {12[2-7]45} 12345 } 1 test util-5.22 {Tcl_StringMatch: UTF-8 range} { Wrapper_Tcl_StringMatch "\[\u4e00-\u4e4f]" "0" } 0 test util-5.23 {Tcl_StringMatch: UTF-8 range} utf8 { Wrapper_Tcl_StringMatch "\[\u4e00-\u4e4f]" "\u4e33" } 1 test util-5.24 {Tcl_StringMatch: UTF-8 range} utf8 { Wrapper_Tcl_StringMatch "\[\u4e00-\u4e4f]" "\uff08" } 0 test util-5.25 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch {12[ab2-4cd]45} 12345 } 1 test util-5.26 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch {12[ab2-4cd]45} 12b45 } 1 test util-5.27 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch {12[ab2-4cd]45} 12d45 } 1 test util-5.28 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch {12[ab2-4cd]45} 12145 } 0 test util-5.29 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch {12[ab2-4cd]45} 12545 } 0 test util-5.30 {Tcl_StringMatch: forwards range} { Wrapper_Tcl_StringMatch {[k-w]} "z" } 0 test util-5.31 {Tcl_StringMatch: forwards range} { Wrapper_Tcl_StringMatch {[k-w]} "w" } 1 test util-5.32 {Tcl_StringMatch: forwards range} { Wrapper_Tcl_StringMatch {[k-w]} "r" } 1 test util-5.33 {Tcl_StringMatch: forwards range} { Wrapper_Tcl_StringMatch {[k-w]} "k" } 1 test util-5.34 {Tcl_StringMatch: forwards range} { Wrapper_Tcl_StringMatch {[k-w]} "a" } 0 test util-5.35 {Tcl_StringMatch: reverse range} { Wrapper_Tcl_StringMatch {[w-k]} "z" } 0 test util-5.36 {Tcl_StringMatch: reverse range} { Wrapper_Tcl_StringMatch {[w-k]} "w" } 1 test util-5.37 {Tcl_StringMatch: reverse range} { Wrapper_Tcl_StringMatch {[w-k]} "r" } 1 test util-5.38 {Tcl_StringMatch: reverse range} { Wrapper_Tcl_StringMatch {[w-k]} "k" } 1 test util-5.39 {Tcl_StringMatch: reverse range} { Wrapper_Tcl_StringMatch {[w-k]} "a" } 0 test util-5.40 {Tcl_StringMatch: skip correct number of ']'} { Wrapper_Tcl_StringMatch {[A-]x} Ax } 0 test util-5.41 {Tcl_StringMatch: skip correct number of ']'} { Wrapper_Tcl_StringMatch {[A-]]x} Ax } 1 test util-5.42 {Tcl_StringMatch: skip correct number of ']'} { Wrapper_Tcl_StringMatch {[A-]]x} \ue1x } 0 test util-5.43 {Tcl_StringMatch: skip correct number of ']'} utf8 { Wrapper_Tcl_StringMatch \[A-]\ue1]x \ue1x } 1 test util-5.44 {Tcl_StringMatch: skip correct number of ']'} { Wrapper_Tcl_StringMatch {[A-]h]x} hx } 1 test util-5.45 {Tcl_StringMatch} { # if (*pattern == '\0') # badly formed pattern, still treats as a set Wrapper_Tcl_StringMatch {[a} a } 1 test util-5.46 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch {a\*b} a*b } 1 test util-5.47 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch {a\*b} ab } 0 test util-5.48 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch {a\*\?\[\]\\\x} "a*?\[\]\\x" } 1 test util-5.49 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch ** "" } 1 test util-5.50 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch *. "" } 0 test util-5.51 {Tcl_StringMatch} { Wrapper_Tcl_StringMatch "" "" } 1 test util-9.0.0 {TclGetIntForIndex} { string index abcd 0 } a test util-9.0.1 {TclGetIntForIndex} { string index abcd 0x0 } a test util-9.0.2 {TclGetIntForIndex} { string index abcd -0x0 } a test util-9.0.3 {TclGetIntForIndex} { string index abcd { 0 } } a test util-9.0.4 {TclGetIntForIndex} { string index abcd { 0x0 } } a test util-9.0.5 {TclGetIntForIndex} { string index abcd { -0x0 } } a test util-9.0.6 {TclGetIntForIndex} { string index abcd 01 } b test util-9.0.7 {TclGetIntForIndex} { string index abcd { 01 } } b test util-9.1.0 {TclGetIntForIndex} { string index abcd 3 } d test util-9.1.1 {TclGetIntForIndex} { string index abcd { 3 } } d test util-9.1.2 {TclGetIntForIndex} { string index abcdefghijk 0xa } k test util-9.1.3 {TclGetIntForIndex} { string index abcdefghijk { 0xa } } k test util-9.2.0 {TclGetIntForIndex} { string index abcd end } d test util-9.2.1 {TclGetIntForIndex} -body { string index abcd { end} } -returnCodes error -match glob -result * test util-9.2.2 {TclGetIntForIndex} -constraints tcl -body { string index abcd {end } } -returnCodes error -match glob -result * test util-9.3 {TclGetIntForIndex} tcl { # Deprecated string index abcd en } d test util-9.4 {TclGetIntForIndex} tcl { # Deprecated string index abcd e } d test util-9.5.0 {TclGetIntForIndex} { string index abcd end-1 } c test util-9.5.1 {TclGetIntForIndex} tcl { string index abcd {end-1 } } c test util-9.5.2 {TclGetIntForIndex} -body { string index abcd { end-1} } -returnCodes error -match glob -result * test util-9.6 {TclGetIntForIndex} { string index abcd end+-1 } c test util-9.7 {TclGetIntForIndex} { string index abcd end+1 } {} test util-9.8 {TclGetIntForIndex} { string index abcd end--1 } {} test util-9.9.0 {TclGetIntForIndex} { string index abcd 0+0 } a test util-9.9.1 {TclGetIntForIndex} tcl { string index abcd { 0+0 } } a test util-9.10 {TclGetIntForIndex} { string index abcd 0-0 } a test util-9.11 {TclGetIntForIndex} { string index abcd 1+0 } b test util-9.12 {TclGetIntForIndex} { string index abcd 1-0 } b test util-9.13 {TclGetIntForIndex} { string index abcd 1+1 } c test util-9.14 {TclGetIntForIndex} { string index abcd 1-1 } a test util-9.15 {TclGetIntForIndex} { string index abcd -1+2 } b test util-9.16 {TclGetIntForIndex} { string index abcd -1--2 } b test util-9.17 {TclGetIntForIndex} tcl { string index abcd { -1+2 } } b test util-9.18 {TclGetIntForIndex} tcl { string index abcd { -1--2 } } b test util-9.19 {TclGetIntForIndex} -body { string index a {} } -returnCodes error -match glob -result * test util-9.20 {TclGetIntForIndex} -body { string index a { } } -returnCodes error -match glob -result * test util-9.21 {TclGetIntForIndex} -body { string index a " \r\t\n" } -returnCodes error -match glob -result * test util-9.22 {TclGetIntForIndex} -body { string index a + } -returnCodes error -match glob -result * test util-9.23 {TclGetIntForIndex} -body { string index a - } -returnCodes error -match glob -result * test util-9.24 {TclGetIntForIndex} -body { string index a x } -returnCodes error -match glob -result * test util-9.25 {TclGetIntForIndex} -body { string index a +x } -returnCodes error -match glob -result * test util-9.26 {TclGetIntForIndex} -body { string index a -x } -returnCodes error -match glob -result * test util-9.27 {TclGetIntForIndex} -body { string index a 0y } -returnCodes error -match glob -result * test util-9.28 {TclGetIntForIndex} -body { string index a 1* } -returnCodes error -match glob -result * test util-9.29 {TclGetIntForIndex} -body { string index a 0+ } -returnCodes error -match glob -result * test util-9.30 {TclGetIntForIndex} -body { string index a {0+ } } -returnCodes error -match glob -result * test util-9.31 {TclGetIntForIndex} -body { string index a 0x } -returnCodes error -match glob -result * test util-9.32 {TclGetIntForIndex} -constraints tcl -body { string index a 0x1FFFFFFFF+0 } -returnCodes error -match glob -result * test util-9.33 {TclGetIntForIndex} -constraints tcl -body { string index a 100000000000+0 } -returnCodes error -match glob -result * test util-9.34 {TclGetIntForIndex} -body { string index a 1.0 } -returnCodes error -match glob -result * test util-9.35 {TclGetIntForIndex} -body { string index a 1e23 } -returnCodes error -match glob -result * test util-9.36 {TclGetIntForIndex} -body { string index a 1.5e2 } -returnCodes error -match glob -result * test util-9.37 {TclGetIntForIndex} -body { string index a 0+x } -returnCodes error -match glob -result * test util-9.38 {TclGetIntForIndex} -body { string index a 0+0x } -returnCodes error -match glob -result * test util-9.39 {TclGetIntForIndex} -body { string index a 0+0xg } -returnCodes error -match glob -result * test util-9.40 {TclGetIntForIndex} -body { string index a 0+0xg } -returnCodes error -match glob -result * test util-9.41 {TclGetIntForIndex} -body { string index a 0+1.0 } -returnCodes error -match glob -result * test util-9.42 {TclGetIntForIndex} -body { string index a 0+1e2 } -returnCodes error -match glob -result * test util-9.43 {TclGetIntForIndex} -body { string index a 0+1.5e1 } -returnCodes error -match glob -result * test util-9.44 {TclGetIntForIndex} -constraints tcl -body { string index a 0+1000000000000 } -returnCodes error -match glob -result * # cleanup ::tcltest::cleanupTests return # Local Variables: # mode: tcl # End: openocd-0.7.0/jimtcl/tests/while.test0000644000175000001440000000567712134336723014542 00000000000000# Commands covered: while # # This file contains the original set of tests for Tcl's while command. # Since the while command is now compiled, a new set of tests covering # the new implementation is in the file "while.test". Sourcing this file # into Tcl runs the tests and generates output for errors. # No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994-1996 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # RCS: @(#) $Id: while-old.test,v 1.6 2000/04/10 17:19:06 ericm Exp $ source [file dirname [info script]]/testing.tcl test while-old-1.1 {basic while loops} { set count 0 while {$count < 10} {set count [expr $count+1]} set count } 10 test while-old-1.2 {basic while loops} { set value xxx while {2 > 3} {set value yyy} set value } xxx test while-old-1.3 {basic while loops} { set value 1 while {1} { incr value; if {$value > 5} { break; } } set value } 6 test while-old-1.4 {basic while loops, multiline test expr} { set value 1 while {($tcl_platform(platform) != "foobar1") && \ ($tcl_platform(platform) != "foobar2")} { incr value break } set value } {2} test while-old-1.5 {basic while loops, test expr in quotes} { set value 1 while "0 < 3" {set value 2; break} set value } {2} test while-old-2.1 {continue in while loop} { set list {1 2 3 4 5} set index 0 set result {} while {$index < 5} { if {$index == 2} {set index [expr $index+1]; continue} set result [concat $result [lindex $list $index]] set index [expr $index+1] } set result } {1 2 4 5} test while-old-3.1 {break in while loop} { set list {1 2 3 4 5} set index 0 set result {} while {$index < 5} { if {$index == 3} break set result [concat $result [lindex $list $index]] set index [expr $index+1] } set result } {1 2 3} test while-old-4.1 {errors in while loops} { set err [catch {while} msg] list $err } {1} test while-old-4.2 {errors in while loops} { set err [catch {while 1} msg] list $err } {1} test while-old-4.3 {errors in while loops} { set err [catch {while 1 2 3} msg] list $err } {1} test while-old-4.4 {errors in while loops} { set err [catch {while {"a"+"b"} {error "loop aborted"}} msg] list $err } {1} test while-old-4.5 {errors in while loops} { catch {unset x} set x 1 set err [catch {while {$x} {set x foo}} msg] list $err } {1} test while-old-4.6 {errors in while loops} { set err [catch {while {1} {error "loop aborted"}} msg] list $err $msg } {1 {loop aborted}} test while-old-5.1 {while return result} { while {0} {set a 400} } {} test while-old-5.2 {while return result} { set x 1 while {$x} {set x 0} } {} # cleanup testreport openocd-0.7.0/jimtcl/tests/filedir.test0000644000175000001440000000242612134336723015035 00000000000000source [file dirname [info script]]/testing.tcl needs cmd file needs cmd exec catch { exec rm -rf tmp exec mkdir tmp exec touch tmp/file exec mkdir tmp/dir } test mkdir-1.1 "Simple dir" { file mkdir tmp/abc file isdir tmp/abc } {1} test mkdir-1.2 "Create missing parents" { file mkdir tmp/def/ghi/jkl file isdir tmp/def/ghi/jkl } {1} test mkdir-1.3 "Existing dir" { file mkdir tmp/dir file isdir tmp/dir } {1} test mkdir-1.4 "Child of existing dir" { file mkdir tmp/dir/child file isdir tmp/dir/child } {1} test mkdir-1.5 "Create dir over existing file" { list [catch {file mkdir tmp/file} msg] [file isdir tmp/file] } {1 0} test mkdir-1.6 "Create dir below existing file" { list [catch {file mkdir tmp/file/dir} msg] [file isdir tmp/file/dir] } {1 0} test mkdir-1.8 "Multiple dirs" { file mkdir tmp/1 tmp/2 tmp/3 list [file isdir tmp/1] [file isdir tmp/2] [file isdir tmp/3] } {1 1 1} test mkdir-1.7 "Stop on failure" { catch {file mkdir tmp/4 tmp/file tmp/5} list [file isdir tmp/4] [file isdir tmp/5] } {1 0} test rmdir-2.0 "Remove existing dir" { file delete tmp/1 file isdir tmp/1 } {0} test rmdir-2.1 "Remove missing dir" { file delete tmp/1 } {} test rmdir-2.2 "Remove non-empty dir" { catch {file delete tmp/def} } {1} catch { exec rm -rf tmp } testreport openocd-0.7.0/jimtcl/tests/stringmatch.test0000644000175000001440000001405012134336723015736 00000000000000# This file is a Tcl script to test the code in the file tclUtil.c. # This file is organized in the standard fashion for Tcl tests. # # Copyright (c) 1995-1998 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # RCS: @(#) $Id: util.test,v 1.7.2.1 2001/07/16 23:14:13 hobbs Exp $ source [file dirname [info script]]/testing.tcl test stringmatch-5.1 {Tcl_StringMatch} { string match ab*c abc } 1 test stringmatch-5.2 {Tcl_StringMatch} { string match ab**c abc } 1 test stringmatch-5.3 {Tcl_StringMatch} { string match ab* abcdef } 1 test stringmatch-5.4 {Tcl_StringMatch} { string match *c abc } 1 test stringmatch-5.5 {Tcl_StringMatch} { string match *3*6*9 0123456789 } 1 test stringmatch-5.6 {Tcl_StringMatch} { string match *3*6*9 01234567890 } 0 test stringmatch-5.7 {Tcl_StringMatch: UTF-8} { string match *u \u4e4fu } 1 test stringmatch-5.8 {Tcl_StringMatch} { string match a?c abc } 1 test stringmatch-5.9 {Tcl_StringMatch: UTF-8} utf8 { # skip one character in string string match a?c a\u4e4fc } 1 test stringmatch-5.10 {Tcl_StringMatch} { string match a??c abc } 0 test stringmatch-5.11 {Tcl_StringMatch} { string match ?1??4???8? 0123456789 } 1 test stringmatch-5.12 {Tcl_StringMatch} { string match {[abc]bc} abc } 1 test stringmatch-5.13 {Tcl_StringMatch: UTF-8} utf8 { # string += Tcl_UtfToUniChar(string, &ch); string match "\[\u4e4fxy\]bc" "\u4e4fbc" } 1 test stringmatch-5.14 {Tcl_StringMatch} { # if ((*pattern == ']') || (*pattern == '\0')) # badly formed pattern string match {[]} {[]} } 0 test stringmatch-5.15 {Tcl_StringMatch} { # if ((*pattern == ']') || (*pattern == '\0')) # badly formed pattern string match {[} {[} } 0 test stringmatch-5.16 {Tcl_StringMatch} { string match {a[abc]c} abc } 1 test stringmatch-5.17 {Tcl_StringMatch: UTF-8} utf8 { # pattern += Tcl_UtfToUniChar(pattern, &endChar); # get 1 UTF-8 character string match "a\[a\u4e4fc]c" "a\u4e4fc" } 1 test stringmatch-5.18 {Tcl_StringMatch: UTF-8} { # pattern += Tcl_UtfToUniChar(pattern, &endChar); # proper advance: wrong answer would match on UTF trail byte of \u4e4f string match {a[a\u4e4fc]c} a\u008fc } 0 test stringmatch-5.19 {Tcl_StringMatch: UTF-8} { # pattern += Tcl_UtfToUniChar(pattern, &endChar); # proper advance. string match {a[a\u4e4fc]c} "acc" } 1 test stringmatch-5.20 {Tcl_StringMatch} { string match {a[xyz]c} abc } 0 test stringmatch-5.21 {Tcl_StringMatch} { string match {12[2-7]45} 12345 } 1 test stringmatch-5.22 {Tcl_StringMatch: UTF-8 range} { string match "\[\u4e00-\u4e4f]" "0" } 0 test stringmatch-5.23 {Tcl_StringMatch: UTF-8 range} utf8 { string match "\[\u4e00-\u4e4f]" "\u4e33" } 1 test stringmatch-5.24 {Tcl_StringMatch: UTF-8 range} utf8 { string match "\[\u4e00-\u4e4f]" "\uff08" } 0 test stringmatch-5.25 {Tcl_StringMatch} { string match {12[ab2-4cd]45} 12345 } 1 test stringmatch-5.26 {Tcl_StringMatch} { string match {12[ab2-4cd]45} 12b45 } 1 test stringmatch-5.27 {Tcl_StringMatch} { string match {12[ab2-4cd]45} 12d45 } 1 test stringmatch-5.28 {Tcl_StringMatch} { string match {12[ab2-4cd]45} 12145 } 0 test stringmatch-5.29 {Tcl_StringMatch} { string match {12[ab2-4cd]45} 12545 } 0 test stringmatch-5.30 {Tcl_StringMatch: forwards range} { string match {[k-w]} "z" } 0 test stringmatch-5.31 {Tcl_StringMatch: forwards range} { string match {[k-w]} "w" } 1 test stringmatch-5.32 {Tcl_StringMatch: forwards range} { string match {[k-w]} "r" } 1 test stringmatch-5.33 {Tcl_StringMatch: forwards range} { string match {[k-w]} "k" } 1 test stringmatch-5.34 {Tcl_StringMatch: forwards range} { string match {[k-w]} "a" } 0 test stringmatch-5.35 {Tcl_StringMatch: reverse range} { string match {[w-k]} "z" } 0 test stringmatch-5.36 {Tcl_StringMatch: reverse range} { string match {[w-k]} "w" } 1 test stringmatch-5.37 {Tcl_StringMatch: reverse range} { string match {[w-k]} "r" } 1 test stringmatch-5.38 {Tcl_StringMatch: reverse range} { string match {[w-k]} "k" } 1 test stringmatch-5.39 {Tcl_StringMatch: reverse range} { string match {[w-k]} "a" } 0 test stringmatch-5.40 {Tcl_StringMatch: skip correct number of ']'} { string match {[A-]x} Ax } 0 test stringmatch-5.41 {Tcl_StringMatch: skip correct number of ']'} { string match {[A-]]x} Ax } 1 test stringmatch-5.42 {Tcl_StringMatch: skip correct number of ']'} { string match {[A-]]x} \ue1x } 0 test stringmatch-5.43 {Tcl_StringMatch: skip correct number of ']'} utf8 { string match \[A-]\ue1]x \ue1x } 1 test stringmatch-5.44 {Tcl_StringMatch: skip correct number of ']'} { string match {[A-]h]x} hx } 1 test stringmatch-5.45 {Tcl_StringMatch} { # if (*pattern == '\0') # badly formed pattern, still treats as a set string match {[a} a } 1 test stringmatch-5.46 {Tcl_StringMatch} { string match {a\*b} a*b } 1 test stringmatch-5.47 {Tcl_StringMatch} { string match {a\*b} ab } 0 test stringmatch-5.48 {Tcl_StringMatch} { string match {a\*\?\[\]\\\x} "a*?\[\]\\x" } 1 test stringmatch-5.49 {Tcl_StringMatch} { string match ** "" } 1 test stringmatch-5.50 {Tcl_StringMatch} { string match *. "" } 0 test stringmatch-5.51 {Tcl_StringMatch} { string match "" "" } 1 # 'string match' doesn't support ^, which is different # from 'scan' test stringmatch-6.1 {bracket in charset} { string match {a[]b]c} {a]c} } 0 test stringmatch-6.2 {bracket in charset} { string match {a[]b]c} {abc} } 0 test stringmatch-6.3 {charset with ^} { string match {a[^]b]c} {axc} } 0 test stringmatch-6.4 {charset with ^} { string match {a[^]b]c} {a]c} } 0 test stringmatch-6.5 {charset with ^} { string match {a[^bc]d} {axd} } 0 test stringmatch-6.6 {charset with ^} { string match {a[\]]c} {a]c} } 0 test stringmatch=7.1 {short string with ?} { string match {ab?} ab } 0 test stringmatch=7.1 {multiple * to end} { string match {ab**} ab } 1 testreport openocd-0.7.0/jimtcl/tests/scan.test0000644000175000001440000005563112134336723014351 00000000000000# Commands covered: scan # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1994 The Regents of the University of California. # Copyright (c) 1994-1997 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # RCS: @(#) $Id: scan.test,v 1.10.2.2 2002/02/07 01:54:04 hobbs Exp $ source [file dirname [info script]]/testing.tcl needs cmd scan test scan-1.1 {BuildCharSet, CharInSet} { list [scan foo {%[^o]} x] $x } {1 f} test scan-1.2 {BuildCharSet, CharInSet} { list [scan \]foo {%[]f]} x] $x } {1 \]f} test scan-1.3 {BuildCharSet, CharInSet} { list [scan abc-def {%[a-c]} x] $x } {1 abc} test scan-1.4 {BuildCharSet, CharInSet} { list [scan abc-def {%[a-c]} x] $x } {1 abc} test scan-1.5 {BuildCharSet, CharInSet} { list [scan -abc-def {%[-ac]} x] $x } {1 -a} test scan-1.6 {BuildCharSet, CharInSet} { list [scan -abc-def {%[ac-]} x] $x } {1 -a} test scan-1.7 {BuildCharSet, CharInSet} { list [scan abc-def {%[c-a]} x] $x } {1 abc} test scan-1.8 {BuildCharSet, CharInSet} { list [scan def-abc {%[^c-a]} x] $x } {1 def-} test scan-1.9 {BuildCharSet, CharInSet no match} { catch {unset x} list [scan {= f} {= %[TF]} x] [info exists x] } {0 0} test scan-2.1 {ReleaseCharSet} { list [scan abcde {%[abc]} x] $x } {1 abc} test scan-2.2 {ReleaseCharSet} { list [scan abcde {%[a-c]} x] $x } {1 abc} test scan-3.1 {ValidateFormat} { list [catch {scan {} {%d%1$d} x} msg] $msg } {1 {cannot mix "%" and "%n$" conversion specifiers}} test scan-3.2 {ValidateFormat} { list [catch {scan {} {%d%1$d} x} msg] $msg } {1 {cannot mix "%" and "%n$" conversion specifiers}} test scan-3.3 {ValidateFormat} { list [catch {scan {} {%2$d%d} x} msg] $msg } {1 {"%n$" argument index out of range}} test scan-3.4 {ValidateFormat} { # degenerate case, before changed from 8.2 to 8.3 list [catch {scan {} %d} msg] $msg } {0 {}} test scan-3.5 {ValidateFormat} { list [catch {scan {} {%10c} a} msg] $msg } {1 {field width may not be specified in %c conversion}} test scan-3.6 {ValidateFormat} jim { list [catch {scan {} {%*1$d} a} msg] $msg } {1 {bad scan conversion character}} test scan-3.7 {ValidateFormat} { list [catch {scan {} {%1$d%1$d} a} msg] $msg } {1 {variable is assigned by multiple "%n$" conversion specifiers}} test scan-3.8 {ValidateFormat} { list [catch {scan {} a x} msg] $msg } {1 {variable is not assigned by any conversion specifiers}} test scan-3.9 {ValidateFormat} { list [catch {scan {} {%2$s} x y} msg] $msg } {1 {variable is not assigned by any conversion specifiers}} test scan-3.10 {ValidateFormat} { list [catch {scan {} {%[a} x} msg] $msg } {1 {unmatched [ in format string}} test scan-3.11 {ValidateFormat} { list [catch {scan {} {%[^a} x} msg] $msg } {1 {unmatched [ in format string}} test scan-3.12 {ValidateFormat} { list [catch {scan {} {%[]a} x} msg] $msg } {1 {unmatched [ in format string}} test scan-3.13 {ValidateFormat} { list [catch {scan {} {%[^]a} x} msg] $msg } {1 {unmatched [ in format string}} test scan-4.1 {Tcl_ScanObjCmd, argument checks} jim { list [catch {scan} msg] $msg } {1 {wrong # args: should be "scan string format ?varName varName ...?"}} test scan-4.2 {Tcl_ScanObjCmd, argument checks} jim { list [catch {scan string} msg] $msg } {1 {wrong # args: should be "scan string format ?varName varName ...?"}} test scan-4.3 {Tcl_ScanObjCmd, argument checks} { # degenerate case, before changed from 8.2 to 8.3 list [catch {scan string format} msg] $msg } {0 {}} test scan-4.4 {Tcl_ScanObjCmd, whitespace} { list [scan { abc def } {%s%s} x y] $x $y } {2 abc def} test scan-4.5 {Tcl_ScanObjCmd, whitespace} { list [scan { abc def } { %s %s } x y] $x $y } {2 abc def} test scan-4.6 {Tcl_ScanObjCmd, whitespace} { list [scan { abc def } { %s %s } x y] $x $y } {2 abc def} test scan-4.7 {Tcl_ScanObjCmd, literals} { # degenerate case, before changed from 8.2 to 8.3 scan { abc def } { abc def } } {} test scan-4.8 {Tcl_ScanObjCmd, literals} { set x {} list [scan { abcg} { abc def %1s} x] $x } {0 {}} test scan-4.9 {Tcl_ScanObjCmd, literals} { list [scan { abc%defghi} { abc %% def%n } x] $x } {1 10} test scan-4.10 {Tcl_ScanObjCmd, assignment suppression} { list [scan { abc def } { %*c%s def } x] $x } {1 bc} test scan-4.11 {Tcl_ScanObjCmd, XPG3-style} { list [scan { abc def } {%2$s %1$s} x y] $x $y } {2 def abc} test scan-4.12 {Tcl_ScanObjCmd, width specifiers} { list [scan {abc123456789012} {%3s%3d%3f%3[0-9]%s} a b c d e] $a $b $c $d $e } {5 abc 123 456.0 789 012} test scan-4.13 {Tcl_ScanObjCmd, width specifiers} { list [scan {abc123456789012} {%3s%3d%3f%3[0-9]%s} a b c d e] $a $b $c $d $e } {5 abc 123 456.0 789 012} test scan-4.14 {Tcl_ScanObjCmd, underflow} { set x {} list [scan {a} {a%d} x] $x } {-1 {}} test scan-4.15 {Tcl_ScanObjCmd, underflow} { set x {} list [scan {} {a%d} x] $x } {-1 {}} test scan-4.16 {Tcl_ScanObjCmd, underflow} { set x {} list [scan {ab} {a%d} x] $x } {0 {}} test scan-4.17 {Tcl_ScanObjCmd, underflow} { set x {} list [scan {a } {a%d} x] $x } {-1 {}} test scan-4.18 {Tcl_ScanObjCmd, skipping whitespace} { list [scan { b} {%c%s} x y] $x $y } {2 32 b} test scan-4.19 {Tcl_ScanObjCmd, skipping whitespace} { list [scan { b} {%[^b]%s} x y] $x $y } {2 { } b} test scan-4.20 {Tcl_ScanObjCmd, string scanning} { list [scan {abc def} {%s} x] $x } {1 abc} test scan-4.21 {Tcl_ScanObjCmd, string scanning} { list [scan {abc def} {%0s} x] $x } {1 abc} test scan-4.22 {Tcl_ScanObjCmd, string scanning} { list [scan {abc def} {%2s} x] $x } {1 ab} test scan-4.23 {Tcl_ScanObjCmd, string scanning} { list [scan {abc def} {%*s%n} x] $x } {1 3} test scan-4.24 {Tcl_ScanObjCmd, charset scanning} { list [scan {abcdef} {%[a-c]} x] $x } {1 abc} test scan-4.25 {Tcl_ScanObjCmd, charset scanning} { list [scan {abcdef} {%0[a-c]} x] $x } {1 abc} test scan-4.26 {Tcl_ScanObjCmd, charset scanning} { list [scan {abcdef} {%2[a-c]} x] $x } {1 ab} test scan-4.27 {Tcl_ScanObjCmd, charset scanning} { list [scan {abcdef} {%*[a-c]%n} x] $x } {1 3} test scan-4.28 {Tcl_ScanObjCmd, character scanning} { list [scan {abcdef} {%c} x] $x } {1 97} test scan-4.29 {Tcl_ScanObjCmd, character scanning} { list [scan {abcdef} {%*c%n} x] $x } {1 1} test scan-4.30 {Tcl_ScanObjCmd, base-10 integer scanning} { set x {} list [scan {1234567890a} {%3d} x] $x } {1 123} test scan-4.31 {Tcl_ScanObjCmd, base-10 integer scanning} { set x {} list [scan {1234567890a} {%d} x] $x } {1 1234567890} test scan-4.32 {Tcl_ScanObjCmd, base-10 integer scanning} { set x {} list [scan {01234567890a} {%d} x] $x } {1 1234567890} test scan-4.33 {Tcl_ScanObjCmd, base-10 integer scanning} { set x {} list [scan {+01234} {%d} x] $x } {1 1234} test scan-4.34 {Tcl_ScanObjCmd, base-10 integer scanning} { set x {} list [scan {-01234} {%d} x] $x } {1 -1234} test scan-4.35 {Tcl_ScanObjCmd, base-10 integer scanning} { set x {} list [scan {a01234} {%d} x] $x } {0 {}} test scan-4.36 {Tcl_ScanObjCmd, base-10 integer scanning} { set x {} list [scan {0x10} {%d} x] $x } {1 0} test scan-4.37 {Tcl_ScanObjCmd, base-8 integer scanning} { set x {} list [scan {012345678} {%o} x] $x } {1 342391} test scan-4.38 {Tcl_ScanObjCmd, base-8 integer scanning} { set x {} list [scan {+1238 -1239 123a} {%o%*s%o%*s%o} x y z] $x $y $z } {3 83 -83 83} test scan-4.39 {Tcl_ScanObjCmd, base-16 integer scanning} { set x {} list [scan {+1238 -123a 0123} {%x%x%x} x y z] $x $y $z } {3 4664 -4666 291} test scan-4.40 {Tcl_ScanObjCmd, base-16 integer scanning} { # The behavior changed in 8.4a4/8.3.4cvs (6 Feb) to correctly # return '1' for 0x1 scanned via %x, to comply with 8.0 and C scanf. # Bug #495213 set x {} list [scan {aBcDeF AbCdEf 0x1} {%x%x%x} x y z] $x $y $z } {3 11259375 11259375 1} test scan-4.40.1 {Tcl_ScanObjCmd, base-16 integer scanning} { set x {} list [scan {0xF 0x00A0B 0X0XF} {%x %x %x} x y z] $x $y $z } {3 15 2571 0} test scan-4.40.2 {Tcl_ScanObjCmd, base-16 integer scanning} { catch {unset x} list [scan {xF} {%x} x] [info exists x] } {0 0} test scan-4.41 {Tcl_ScanObjCmd, base-unknown integer scanning} { set x {} list [scan {10 010 0x10} {%i%i%i} x y z] $x $y $z } {3 10 10 16} test scan-4.42 {Tcl_ScanObjCmd, base-unknown integer scanning} { set x {} list [scan {10 010 0X10} {%i%i%i} x y z] $x $y $z } {3 10 10 16} test scan-4.43 {Tcl_ScanObjCmd, integer scanning, odd cases} { set x {} list [scan {+ } {%i} x] $x } {0 {}} #test scan-4.44 {Tcl_ScanObjCmd, integer scanning, odd cases} { # set x {} # list [scan {+} {%i} x] $x #} {-1 {}} test scan-4.45 {Tcl_ScanObjCmd, integer scanning, odd cases} { set x {} list [scan {0x} {%i%s} x y] $x $y } {2 0 x} test scan-4.46 {Tcl_ScanObjCmd, integer scanning, odd cases} { set x {} list [scan {0X} {%i%s} x y] $x $y } {2 0 X} test scan-4.47 {Tcl_ScanObjCmd, integer scanning, suppressed} { set x {} list [scan {123def} {%*i%s} x] $x } {1 def} test scan-4.48 {Tcl_ScanObjCmd, float scanning} { list [scan {1 2 3} {%e %f %g} x y z] $x $y $z } {3 1.0 2.0 3.0} test scan-4.49 {Tcl_ScanObjCmd, float scanning} { list [scan {.1 0.2 3.} {%e %f %g} x y z] $x $y $z } {3 0.1 0.2 3.0} test scan-4.50 {Tcl_ScanObjCmd, float scanning} { list [scan {1234567890a} %f x] $x } {1 1234567890.0} test scan-4.51 {Tcl_ScanObjCmd, float scanning} { list [scan {+123+45} %f x] $x } {1 123.0} test scan-4.52 {Tcl_ScanObjCmd, float scanning} { list [scan {-123+45} %f x] $x } {1 -123.0} test scan-4.53 {Tcl_ScanObjCmd, float scanning} { list [scan {1.0e1} %f x] $x } {1 10.0} test scan-4.54 {Tcl_ScanObjCmd, float scanning} { list [scan {1.0e-1} %f x] $x } {1 0.1} #test scan-4.55 {Tcl_ScanObjCmd, odd cases} { # set x {} # list [scan {+} %f x] $x #} {-1 {}} test scan-4.56 {Tcl_ScanObjCmd, odd cases} { set x {} list [scan {1.0e} %f%s x y] $x $y } {2 1.0 e} test scan-4.57 {Tcl_ScanObjCmd, odd cases} { set x {} list [scan {1.0e+} %f%s x y] $x $y } {2 1.0 e+} test scan-4.58 {Tcl_ScanObjCmd, odd cases} { set x {} set y {} list [scan {e1} %f%s x y] $x $y } {0 {} {}} test scan-4.59 {Tcl_ScanObjCmd, float scanning} { list [scan {1.0e-1x} %*f%n x] $x } {1 6} test scan-4.60 {Tcl_ScanObjCmd, set errors} { set x {} set y {} set z 1 set result [list [catch {scan {abc def ghi} {%s%s%s} x z(z) y} msg] \ $x $y] set result } {1 abc ghi} test scan-4.61 {Tcl_ScanObjCmd, set errors} { set x {} set y 1 set z 1 set result [list [catch {scan {abc def ghi} {%s%s%s} x y(y) z(z)} msg] \ $x] set result } {1 abc} # procedure that returns the range of integers # On Tcl with bignum, these won't produce a result! proc int_range {} { for { set MIN_INT 1 } { $MIN_INT > 0 } {} { set MIN_INT [expr { $MIN_INT << 1 }] } set MAX_INT [expr { ~ $MIN_INT }] return [list $MIN_INT $MAX_INT] } test scan-4.62 {scanning of large and negative octal integers} jim { foreach { MIN_INT MAX_INT } [int_range] {} set scanstring [format {%o %o %o} -1 $MIN_INT $MAX_INT] list [scan $scanstring {%o %o %o} a b c] \ [expr { $a == -1 }] [expr { $b == $MIN_INT }] [expr { $c == $MAX_INT }] } {3 1 1 1} test scan-4.63 {scanning of large and negative hex integers} jim { foreach { MIN_INT MAX_INT } [int_range] {} set scanstring [format {%x %x %x} -1 $MIN_INT $MAX_INT] list [scan $scanstring {%x %x %x} a b c] \ [expr { $a == -1 }] [expr { $b == $MIN_INT }] [expr { $c == $MAX_INT }] } {3 1 1 1} # clean up from last two tests catch { rename int_range {} } test scan-5.1 {integer scanning} { set a {}; set b {}; set c {}; set d {} list [scan "-20 1476 \n33 0" "%d %d %d %d" a b c d] $a $b $c $d } {4 -20 1476 33 0} test scan-5.2 {integer scanning} { set a {}; set b {}; set c {} list [scan "-45 16 7890 +10" "%2d %*d %10d %d" a b c] $a $b $c } {3 -4 16 7890} test scan-5.3 {integer scanning} { set a {}; set b {}; set c {}; set d {} list [scan "-45 16 +10 987" "%ld %d %ld %d" a b c d] $a $b $c $d } {4 -45 16 10 987} test scan-5.4 {integer scanning} { set a {}; set b {}; set c {}; set d {} list [scan "14 1ab 62 10" "%d %x %lo %x" a b c d] $a $b $c $d } {4 14 427 50 16} test scan-5.5 {integer scanning} { set a {}; set b {}; set c {}; set d {} list [scan "12345670 1234567890ab cdefg" "%o %o %x %lx" a b c d] \ $a $b $c $d } {4 2739128 342391 561323 52719} test scan-5.6 {integer scanning} { set a {}; set b {}; set c {}; set d {} list [scan "ab123-24642" "%2x %3x %3o %2o" a b c d] $a $b $c $d } {4 171 291 -20 52} test scan-5.7 {integer scanning} { set a {}; set b {} list [scan "1234567 234 567 " "%*3x %x %*o %4o" a b] $a $b } {2 17767 375} test scan-5.8 {integer scanning} { set a {}; set b {} list [scan "a 1234" "%d %d" a b] $a $b } {0 {} {}} test scan-5.9 {integer scanning} { set a {}; set b {}; set c {}; set d {}; list [scan "12345678" "%2d %2d %2ld %2d" a b c d] $a $b $c $d } {4 12 34 56 78} test scan-5.10 {integer scanning} { set a {}; set b {}; set c {}; set d {} list [scan "1 2 " "%hd %d %d %d" a b c d] $a $b $c $d } {2 1 2 {} {}} # # The behavior for scaning intergers larger than MAX_INT is # not defined by the ANSI spec. Some implementations wrap the # input (-16) some return MAX_INT. # test scan-5.11 {integer scanning} { set a {}; set b {}; list [scan "4294967280 4294967280" "%u %d" a b] $a \ [expr {$b == -16 || $b == 0x7fffffff || $b == $a}] } {2 4294967280 1} test scan-6.1 {floating-point scanning} { set a {}; set b {}; set c {}; set d {} list [scan "2.1 -3.0e8 .99962 a" "%f%g%e%f" a b c d] $a $b $c $d } {3 2.1 -300000000.0 0.99962 {}} test scan-6.2 {floating-point scanning} { set a {}; set b {}; set c {}; set d {} list [scan "-1.2345 +8.2 9" "%3e %3lf %f %f" a b c d] $a $b $c $d } {4 -1.0 234.0 5.0 8.2} test scan-6.3 {floating-point scanning} { set a {}; set b {}; set c {} list [scan "1e00004 332E-4 3e+4" "%Lf %*2e %f %f" a b c] $a $c } {3 10000.0 30000.0} # # Some libc implementations consider 3.e- bad input. The ANSI # spec states that digits must follow the - sign. # test scan-6.4 {floating-point scanning} { set a {}; set b {}; set c {} list [scan "1. 47.6 2.e2 3.e-" "%f %*f %f %f" a b c] $a $b $c } {3 1.0 200.0 3.0} test scan-6.5 {floating-point scanning} { set a {}; set b {}; set c {}; set d {} list [scan "4.6 99999.7 876.43e-1 118" "%f %f %f %e" a b c d] $a $b $c $d } {4 4.6 99999.7 87.643 118.0} test scan-6.6 {floating-point scanning} jim { set a {}; set b {}; set c {}; set d {} list [scan "1.2345 697.0e-3 124 .00005" "%f %e %f %e" a b c d] $a $b $c $d } {4 1.2345 0.697 124.0 5e-05} test scan-6.7 {floating-point scanning} { set a {}; set b {}; set c {}; set d {} list [scan "4.6abc" "%f %f %f %f" a b c d] $a $b $c $d } {1 4.6 {} {} {}} test scan-6.8 {floating-point scanning} { set a {}; set b {}; set c {}; set d {} list [scan "4.6 5.2" "%f %f %f %f" a b c d] $a $b $c $d } {2 4.6 5.2 {} {}} test scan-7.1 {string and character scanning} { set a {}; set b {}; set c {}; set d {} list [scan "abc defghijk dum " "%s %3s %20s %s" a b c d] $a $b $c $d } {4 abc def ghijk dum} test scan-7.2 {string and character scanning} { set a {}; set b {}; set c {}; set d {} list [scan "a bcdef" "%c%c%1s %s" a b c d] $a $b $c $d } {4 97 32 b cdef} test scan-7.3 {string and character scanning} { set a {}; set b {}; set c {} list [scan "123456 test " "%*c%*s %s %s %s" a b c] $a $b $c } {1 test {} {}} test scan-7.4 {string and character scanning} { set a {}; set b {}; set c {}; set d list [scan "ababcd01234 f 123450" {%4[abcd] %4[abcd] %[^abcdef] %[^0]} a b c d] $a $b $c $d } {4 abab cd {01234 } {f 12345}} test scan-7.5 {string and character scanning} { set a {}; set b {}; set c {} list [scan "aaaaaabc aaabcdefg + + XYZQR" {%*4[a] %s %*4[a]%s%*4[ +]%c} a b c] $a $b $c } {3 aabc bcdefg 43} test scan-7.6 {string and character scanning, unicode} utf8 { set a {}; set b {}; set c {}; set d {} list [scan "abc d\u00c7fghijk dum " "%s %3s %20s %s" a b c d] $a $b $c $d } "4 abc d\u00c7f ghijk dum" test scan-7.7 {string and character scanning, unicode} utf8 { set a {}; set b {} list [scan "ab\u00c7cdef" "ab%c%c" a b] $a $b } "2 199 99" test scan-7.8 {string and character scanning, unicode} utf8 { set a {}; set b {} list [scan "ab\ufeffdef" "%\[ab\ufeff\]" a] $a } "1 ab\ufeff" test scan-8.1 {error conditions} { catch {scan a} } 1 test scan-8.2 {error conditions} jim { catch {scan a} msg set msg } {wrong # args: should be "scan string format ?varName varName ...?"} test scan-8.3 {error conditions} jim { list [catch {scan a %D x} msg] $msg } {1 {bad scan conversion character}} test scan-8.4 {error conditions} jim { list [catch {scan a %O x} msg] $msg } {1 {bad scan conversion character}} test scan-8.5 {error conditions} jim { list [catch {scan a %X x} msg] $msg } {1 {bad scan conversion character}} test scan-8.6 {error conditions} jim { list [catch {scan a %F x} msg] $msg } {1 {bad scan conversion character}} test scan-8.7 {error conditions} jim { list [catch {scan a %E x} msg] $msg } {1 {bad scan conversion character}} test scan-8.8 {error conditions} { list [catch {scan a "%d %d" a} msg] $msg } {1 {different numbers of variable names and field specifiers}} test scan-8.9 {error conditions} { list [catch {scan a "%d %d" a b c} msg] $msg } {1 {variable is not assigned by any conversion specifiers}} test scan-8.10 {error conditions} { set a {}; set b {}; set c {}; set d {} list [expr {[scan " a" " a %d %d %d %d" a b c d] <= 0}] $a $b $c $d } {1 {} {} {} {}} test scan-8.11 {error conditions} { set a {}; set b {}; set c {}; set d {} list [scan "1 2" "%d %d %d %d" a b c d] $a $b $c $d } {2 1 2 {} {}} test scan-8.12 {error conditions} { set a 44 list [catch {scan 44 %d a(0)} msg] } {1} test scan-8.13 {error conditions} { set a 44 list [catch {scan 44 %c a(0)} msg] } {1} test scan-8.14 {error conditions} { set a 44 list [catch {scan 44 %s a(0)} msg] } {1} test scan-8.15 {error conditions} { set a 44 list [catch {scan 44 %f a(0)} msg] } {1} catch {unset a} test scan-8.17 {error conditions} { list [catch {scan 44 %2c a} msg] $msg } {1 {field width may not be specified in %c conversion}} test scan-8.18 {error conditions} { list [catch {scan abc {%[} x} msg] $msg } {1 {unmatched [ in format string}} test scan-8.19 {error conditions} { list [catch {scan abc {%[^a} x} msg] $msg } {1 {unmatched [ in format string}} test scan-8.20 {error conditions} { list [catch {scan abc {%[^]a} x} msg] $msg } {1 {unmatched [ in format string}} test scan-8.21 {error conditions} { list [catch {scan abc {%[]a} x} msg] $msg } {1 {unmatched [ in format string}} test scan-9.1 {lots of arguments} { scan "10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 190 200" "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d" a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18 a19 a20 } 20 test scan-9.2 {lots of arguments} { scan "10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 190 200" "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d" a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18 a19 a20 set a20 } 200 test scan-10.1 {miscellaneous tests} { set a {} list [scan ab16c ab%dc a] $a } {1 16} test scan-10.2 {miscellaneous tests} { set a {} list [scan ax16c ab%dc a] $a } {0 {}} test scan-10.3 {miscellaneous tests} { set a {} list [catch {scan ab%c114 ab%%c%d a} msg] $msg $a } {0 1 114} test scan-10.4 {miscellaneous tests} { set a {} list [catch {scan ab%c14 ab%%c%d a} msg] $msg $a } {0 1 14} test scan-10.5 {miscellaneous tests} { catch {unset arr} set arr(2) {} list [catch {scan ab%c14 ab%%c%d arr(2)} msg] $msg $arr(2) } {0 1 14} test scan-11.1 {alignment in results array (TCL_ALIGN)} { scan "123 13.6" "%s %f" a b set b } 13.6 test scan-11.2 {alignment in results array (TCL_ALIGN)} { scan "1234567 13.6" "%s %f" a b set b } 13.6 test scan-11.3 {alignment in results array (TCL_ALIGN)} { scan "12345678901 13.6" "%s %f" a b set b } 13.6 test scan-11.4 {alignment in results array (TCL_ALIGN)} { scan "123456789012345 13.6" "%s %f" a b set b } 13.6 test scan-11.5 {alignment in results array (TCL_ALIGN)} { scan "1234567890123456789 13.6" "%s %f" a b set b } 13.6 test scan-12.1 {Tcl_ScanObjCmd, inline case} { scan a %c } 97 test scan-12.2 {Tcl_ScanObjCmd, inline case} { scan abc %c%c%c%c } {97 98 99 {}} test scan-12.3 {Tcl_ScanObjCmd, inline case} { scan abc %s%c } {abc {}} test scan-12.4 {Tcl_ScanObjCmd, inline case, underflow} { scan abc abc%c } {} test scan-12.5 {Tcl_ScanObjCmd, inline case} { scan abc bogus%c%c%c } {{} {} {}} test scan-12.6 {Tcl_ScanObjCmd, inline case} { # degenerate case, behavior changed from 8.2 to 8.3 list [catch {scan foo foobar} msg] $msg } {0 {}} test scan-12.7 {Tcl_ScanObjCmd, inline case lots of arguments} { scan "10 20 30 40 50 60 70 80 90 100 110 120 130 140\ 150 160 170 180 190 200" \ "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d" } {10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 190 200 {}} test scan-13.1 {Tcl_ScanObjCmd, inline XPG case} { scan a {%1$c} } 97 test scan-13.2 {Tcl_ScanObjCmd, inline XPG case} { scan abc {%1$c%2$c%3$c%4$c} } {97 98 99 {}} test scan-13.3 {Tcl_ScanObjCmd, inline XPG case} { list [catch {scan abc {%1$c%1$c}} msg] $msg } {1 {variable is assigned by multiple "%n$" conversion specifiers}} test scan-13.4 {Tcl_ScanObjCmd, inline XPG case} { scan abc {%2$s%1$c} } {{} abc} test scan-13.5 {Tcl_ScanObjCmd, inline XPG case, underflow} { scan abc {abc%5$c} } {} test scan-13.6 {Tcl_ScanObjCmd, inline XPG case} { catch {scan abc {bogus%1$c%5$c%10$c}} msg list [llength $msg] $msg } {10 {{} {} {} {} {} {} {} {} {} {}}} test scan-13.7 {Tcl_ScanObjCmd, inline XPG case lots of arguments} { scan "10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 190 200" {%20$d %18$d %17$d %16$d %15$d %14$d %13$d %12$d %11$d %10$d %9$d %8$d %7$d %6$d %5$d %4$d %3$d %2$d %1$d} } {190 180 170 160 150 140 130 120 110 100 90 80 70 60 50 40 30 20 {} 10} test scan-13.8 {Tcl_ScanObjCmd, inline XPG case lots of arguments} { set msg [scan "10 20 30" {%100$d %5$d %200$d}] list [llength $msg] [lindex $msg 99] [lindex $msg 4] [lindex $msg 199] } {200 10 20 30} test scan-14.1 {scan with null chars} { scan a\0c %c%c%c } {97 0 99} test scan-14.2 {scan with null chars} { scan \0\0c %c%c%c } {0 0 99} test scan-14.3 {scan with null chars} { scan ab12x\0 %cb%dx%c } {97 12 0} testreport openocd-0.7.0/jimtcl/tests/perf.test0000644000175000001440000000655412134336723014361 00000000000000source [file dirname [info script]]/testing.tcl needs constraint manual set iterations 10000 set version [info patchlevel] proc bench {name cmd} { if {[catch { set t [time $cmd 2] set ms [format %.0f [expr {[lindex $t 0] / 1000}]] }]} { set ms ? } puts "$::version: $name ${ms}ms" } proc set_dict_sugar {} { for {set i 0} {$i < $::iterations} {incr i} { set a(b) $i } } # Note that this case does not benefit from the dict sugar # speedup since a($b) needs to be interpolated and reparsed every time proc set_var_dict_sugar {} { set b b for {set i 0} {$i < $::iterations} {incr i} { set a($b) $i } } proc set_var_dict {} { set b b for {set i 0} {$i < $::iterations} {incr i} { dict set a $b $i } } proc read_file {file} { set f [open $file] while {[gets $f buf] >= 0} { } close $f } proc read_file_split {file} { set f [open $file] while {[gets $f buf] >= 0} { split $buf \t } close $f } proc read_file_split_assign_foreach {file} { set f [open $file] while {[gets $f buf] >= 0} { foreach {info(chan) info(datetime) info(duration) info(title) subtitle_genre info(desc) info(rating) dummy} [split $buf \t] {break} } close $f } proc read_file_split_assign_foreach_dict {file} { set f [open $file] while {[gets $f buf] >= 0} { foreach {chan datetime duration title subtitle_genre desc rating dummy} [split $buf \t] {break} dict set info chan $chan dict set info duration $duration dict set info title $title dict set info subtitle_genre $subtitle_genre dict set info desc $desc dict set info rating $rating } close $f } proc read_file_split_assign_foreach_dictsugar {file} { set f [open $file] while {[gets $f buf] >= 0} { foreach {chan datetime duration title subtitle_genre desc rating dummy} [split $buf \t] {break} set info(chan) $chan set info(duration) $duration set info(title) $title set info(subtitle_genre) $subtitle_genre set info(desc) $desc set info(rating) $rating } close $f } proc read_file_split_assign_foreach_simple {file} { set f [open $file] while {[gets $f buf] >= 0} { foreach {chan datetime duration title subtitle_genre desc rating dummy} [split $buf \t] {break} } close $f } proc read_file_split_assign_lindex {file} { set f [open $file] while {[gets $f buf] >= 0} { set split [split $buf \t] set info(chan) [lindex $split 0] set info(datetime) [lindex $split 1] set info(duration) [lindex $split 2] set info(title) [lindex $split 3] set info(subtitle_genre) [lindex $split 4] set info(desc) [lindex $split 5] set info(rating) [lindex $split 6] } close $f } # Create a really big file set f [open test.in w] for {set i 0} {$i < $::iterations} {incr i} { puts $f "a\tb\tc\te\tf\tg\th\ti\tj\tk" } close $f bench "set dictsugar" {set_dict_sugar} bench "set var dictsugar" {set_var_dict_sugar} bench "set var dict" {set_var_dict} # Read once before testing perf read_file test.in bench "read file" {read_file test.in} bench "read file split" {read_file_split test.in} bench "foreach: simple" {read_file_split_assign_foreach_simple test.in} bench "foreach: direct dictsugar" {read_file_split_assign_foreach test.in} bench "foreach: dict cmd" {read_file_split_assign_foreach_dict test.in} bench "foreach: assign to dictsugar" {read_file_split_assign_foreach_dictsugar test.in} bench "foreach: assign to dictsugar via lindex" {read_file_split_assign_lindex test.in} file delete test.in # testreport openocd-0.7.0/jimtcl/tests/utf8.test0000644000175000001440000000643612134336723014312 00000000000000source [file dirname [info script]]/testing.tcl needs constraint utf8 test utf8-1.1 "Pattern matching - ?" { string match "abc?def" "abc\u00b5def" } 1 test utf8-1.2 "Pattern matching - ?" { string match "abc?def" "abc\u2704def" } 1 test utf8-1.3 "Pattern utf-8 literal" { string match "ab\u00b5\u2704?" "ab\u00b5\u2704x" } 1 test utf8-1.4 "Pattern utf-8 char sets" { string match "a\[b\u00b5\]\u2704?" "a\u00b5\u2704x" } 1 test utf8-1.5 "Pattern utf-8 char sets" { string match "a\[b\u00b5\]\u2704?" "a\u00b6\u2704x" } 0 test utf8-1.6 "Pattern utf-8 char sets" { string match "a\[b\u00b5\]\u2704?" "ab\u2704x" } 1 test utf8-1.7 "Pattern utf-8 char sets" { string match "a\[b\u00b5\]?" "a\u2704x" } 0 test utf8-1.8 "Pattern utf-8 char sets" { string match "a\[\u00b5-\u00c3\]" "a\ubd" } 1 test utf8-1.9 "Pattern utf-8 char sets" { string match "a\[\u00b5-\u00c3\]" "a\uc4" } 0 test utf8-2.1 "Pattern utf-8 nocase" { string match -nocase "a\u1edc\u1ef4*" "A\u1edd\u1ef5XX" } 1 test utf8-2.2 "Pattern utf-8 case difference" { string match "a\u1edc\u1ef4*" "A\u1edd\u1ef5XX" } 0 test utf8-3.1 "lsearch -glob" { lsearch -glob {1 d a\u00b5xyb c} a\ub5*b } 2 test utf8-3.2 "switch -glob" { switch -glob -- a\ub5xyb a\ub5*b { set x 1 } default { set x 0 } set x } 1 set x "\ub5test" test utf8-3.3 "info procs" { proc $x {} { info procs \[\ub5X]???? } $x } $x test utf8-3.3 "info commands" { info commands \[\ub5X]???? } $x test utf8-3.4 "proc name with invalid utf-8" { catch { proc ab\xc2 {} {} } msg } 0 test utf8-3.5 "rename to invalid name" { catch { rename ab\xc2 ab\xc3 } msg } 0 catch {rename ab\xc3 ""} test utf8-4.1 "split with utf-8" { split "zy\u2702xw" x } "zy\u2702 w" test utf8-4.2 "split with utf-8" { split "zy\u2702xw" \u2702 } "zy xw" test utf8-4.2 "split with utf-8" { split "zy\u2702xw" {} } "z y \u2702 x w" test utf8-5.1 "string first with utf-8" { string first w "zy\u2702xw" } 4 test utf8-5.2 "string first with utf-8" { string first \u2702 "\ub5zy\u2702xw" } 3 test utf8-5.3 "string first with utf-8" { string first \u2704 "\ub5zy\u2702xw" } -1 test utf8-5.4 "string first with utf-8" { string first \u2702 "\ub5zy\u2702xw\u2702BB" } 3 test utf8-6.1 "string last with utf-8" { string last w "zy\u2702xw" } 4 test utf8-6.2 "string last with utf-8" { string last \u2702 "\ub5zy\u2702xw" } 3 test utf8-6.3 "string last with utf-8" { string last \u2704 "\ub5zy\u2702xw" } -1 test utf8-6.4 "string last with utf-8" { string last \u2702 "\ub5zy\u2702xw\u2702BB" } 6 test utf8-7.1 "string reverse" { string reverse \ub5Test\u2702 } \u2702tseT\ub5 test utf8-7.2 {append counts correctly} { set x \u2702XYZ append x \u2702XYZ list [string length $x] [string bytelength $x] } {8 12} test utf8-7.3 {Upper, lower for titlecase utf-8} { list [string toupper \u01c5] [string tolower \u01c5] } "\u01c4 \u01c6" test utf8-7.4 {Case folding may change encoded length} { list [string bytelength \u0131] [string bytelength [string toupper \u0131]] } {2 1} test utf8-8.1 {Chars outside the BMP} jim { string length \u{12000}\u{13000} } 2 test utf8-8.2 {Chars outside the BMP} jim { string match "ab\[\u{12000}c\]d" ab\u{12000}d } 1 test utf8-8.3 {Chars outside the BMP} jim { string last d "ab\u{101fff}cd" } 4 test utf8-8.4 {Longer sequences} { string length \u12000 } 2 testreport openocd-0.7.0/jimtcl/tests/try.test0000644000175000001440000000304412134336723014232 00000000000000source [file dirname [info script]]/testing.tcl needs cmd try tclcompat test try-1.1 "Simple case" { try { set x 0 } finally { incr x } } 0 test try-1.2 "Error in body" { list [catch { try { set x 0 error message } finally { incr x } } msg] $msg $x } {1 message 1} test try-1.3 "Error in finally" { list [catch { try { set x 0 } finally { incr x error finally } } msg] $msg $x } {1 finally 1} test try-1.4 "Error in both" { list [catch { try { set x 0 error message } finally { incr x error finally } } msg] $msg $x } {1 finally 1} test try-1.5 "break in body" { list [catch { try { set x 0 break } finally { incr x } } msg] $msg $x } {3 {} 1} test try-1.6 "break in finally" { list [catch { try { set x 0 } finally { incr x break } } msg] $msg $x } {3 {} 1} test try-1.7 "return value from try, not finally" { list [catch { try { set x 0 } finally { incr x } } msg] $msg $x } {0 0 1} test try-1.8 "return from within try" { proc a {} { try { return 1 } # notreached return 2 } a } {1} test try-1.9 "return -code from within try" { proc a {} { try { return -code break text } # notreached return 2 } list [catch a msg] $msg } {3 text} proc c {} { try { error here } on error {msg opts} { # jim can do simply: if {[catch {incr opts(-level)}]} { # Must be Tcl dict incr opts -level } return {*}$opts $msg } } test try-3.1 "rethrow error in try/on handler" { list [catch c msg] $msg } {1 here} testreport openocd-0.7.0/jimtcl/tests/string.test0000644000175000001440000006462512134336723014736 00000000000000# Commands covered: string # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # RCS: @(#) $Id: string.test,v 1.23.2.1 2001/04/03 22:54:38 hobbs Exp $ source [file dirname [info script]]/testing.tcl # Some tests require the testobj command test string-1.1 {error conditions} { list [catch {string gorp a b} msg] } {1} test string-1.2 {error conditions} { list [catch {string} msg] } {1} test string-2.1 {string compare, too few args} { list [catch {string compare a} msg] } {1} test string-2.2 {string compare, bad args} { list [catch {string compare a b c} msg] } {1} test string-2.3 {string compare, bad args} { list [catch {string compare -length -nocase str1 str2} msg] } {1} test string-2.4 {string compare, too many args} { list [catch {string compare -length 10 -nocase str1 str2 str3} msg] } {1} test string-2.5 {string compare with length unspecified} { list [catch {string compare -length 10 10} msg] } {1} test string-2.6 {string compare} { string compare abcde abdef } -1 test string-2.7 {string compare, shortest method name} { string c abcde ABCDE } 1 test string-2.8 {string compare} { string compare abcde abcde } 0 test string-2.9 {string compare with length} { string compare -length 2 abcde abxyz } 0 test string-2.10 {string compare with special index} { list [catch {string compare -length end-3 abcde abxyz} msg] } {1} test string-2.12 {string compare, high bit} { # This test will fail if the underlying comparaison # is using signed chars instead of unsigned chars. # (like SunOS's default memcmp thus the compat/memcmp.c) string compare "\x80" "@" # Nb this tests works also in utf8 space because \x80 is # translated into a 2 or more bytelength but whose first byte has # the high bit set. } 1 test string-2.13 {string compare -nocase} { string compare -nocase abcde abdef } -1 test string-2.14 {string compare -nocase} { string c -nocase abcde ABCDE } 0 test string-2.15 {string compare -nocase} { string compare -nocase abcde abcde } 0 test string-2.16 {string compare -nocase with length} { string compare -length 2 -nocase abcde Abxyz } 0 test string-2.17 {string compare -nocase with length} { string compare -nocase -length 3 abcde Abxyz } -1 test string-2.18 {string compare -nocase with length <= 0} { string compare -nocase -length -1 abcde AbCdEf } -1 test string-2.19 {string compare -nocase with excessive length} { string compare -nocase -length 50 AbCdEf abcde } 1 test string-2.20 {string compare -len unicode} { # These are strings that are 6 BYTELENGTH long, but the length # shouldn't make a different because there are actually 3 CHARS long string compare -len 5 \334\334\334 \334\334\374 } -1 test string-2.21 {string compare -nocase with special index} { list [catch {string compare -nocase -length end-3 Abcde abxyz} msg] } {1} test string-2.22 {string compare, null strings} { string compare "" "" } 0 test string-2.23 {string compare, null strings} { string compare "" foo } -1 test string-2.24 {string compare, null strings} { string compare foo "" } 1 test string-2.25 {string compare -nocase, null strings} { string compare -nocase "" "" } 0 test string-2.26 {string compare -nocase, null strings} { string compare -nocase "" foo } -1 test string-2.27 {string compare -nocase, null strings} { string compare -nocase foo "" } 1 test string-2.28 {string equal with length, unequal strings} { string compare -length 2 abc abde } 0 test string-2.29 {string equal with length, unequal strings} { string compare -length 2 ab abde } 0 # only need a few tests on equal, since it uses the same code as # string compare, but just modifies the return output test string-3.1 {string equal} { string equal abcde abdef } 0 test string-3.2 {string equal} { string eq abcde ABCDE } 0 test string-3.3 {string equal} { string equal abcde abcde } 1 test string-3.4 {string equal -nocase} utf8 { string equal -nocase \u00dc\u00dc\u00dc\u00dc\u00fc\u00fc\u00fc\u00fc \u00dc\u00dc\u00dc\u00dc\u00dc\u00dc\u00dc\u00dc } 1 test string-3.5 {string equal -nocase} { string equal -nocase abcde abdef } 0 test string-3.6 {string equal -nocase} { string eq -nocase abcde ABCDE } 1 test string-3.7 {string equal -nocase} { string equal -nocase abcde abcde } 1 test string-3.8 {string equal with length, unequal strings} { string equal -length 2 abc abde } 1 test string-4.1 {string first, too few args} { list [catch {string first a} msg] } {1} test string-4.2 {string first, bad args} { list [catch {string first a b c} msg] } {1} test string-4.3 {string first, too many args} { list [catch {string first a b 5 d} msg] } {1} test string-4.4 {string first} { string first bq abcdefgbcefgbqrs } 12 test string-4.5 {string first} { string fir bcd abcdefgbcefgbqrs } 1 test string-4.6 {string first} { string f b abcdefgbcefgbqrs } 1 test string-4.7 {string first} { string first xxx x123xx345xxx789xxx012 } 9 test string-4.8 {string first} { string first "" x123xx345xxx789xxx012 } -1 test string-4.14 {string first, start index} { string first a abcabc end-4 } 3 test string-4.15 {string first, empty needle} { string first "" b } -1 test string-4.16 {string first, empty haystack} { string first a "" } -1 test string-4.17 {string first, needle bigger than haystack} { string first aaa b } -1 test string-4.18 {string first, negative index} { string first a aaa -4 } 0 test string-4.19 {string first, not found} { string first a bcd } -1 test string-5.1 {string index} { list [catch {string index} msg] } {1} test string-5.2 {string index} { list [catch {string index a b c} msg] } {1} test string-5.3 {string index} { string index abcde 0 } a test string-5.4 {string index} { string in abcde 4 } e test string-5.5 {string index} { string index abcde 5 } {} test string-5.6 {string index} { list [catch {string index abcde -10} msg] } {0} test string-5.7 {string index} { list [catch {string index a xyz} msg] } {1} test string-5.8 {string index} { string index abc end } c test string-5.9 {string index} { string index abc end-1 } b test string-5.17 {string index, bad integer} tcl { list [catch {string index "abc" 08} msg] } {1} test string-5.18 {string index, bad integer} tcl { list [catch {string index "abc" end-00289} msg] } {1} test string-6.1 {string is, too few args} jim { list [catch {string is} msg] $msg } {1 {wrong # args: should be "string is class ?-strict? str"}} test string-6.2 {string is, too few args} jim { list [catch {string is alpha} msg] $msg } {1 {wrong # args: should be "string is class ?-strict? str"}} test string-6.3 {string is, bad args} jim { list [catch {string is alpha -failin str} msg] $msg } {1 {wrong # args: should be "string is class ?-strict? str"}} test string-6.4 {string is, too many args} jim { list [catch {string is alpha -failin var -strict str more} msg] $msg } {1 {wrong # args: should be "string is class ?-strict? str"}} test string-6.5 {string is, class check} jim { list [catch {string is bogus str} msg] $msg } {1 {bad class "bogus": must be alnum, alpha, ascii, control, digit, double, graph, integer, lower, print, punct, space, upper, or xdigit}} test string-6.6 {string is, ambiguous class} jim { list [catch {string is al str} msg] $msg } {1 {ambiguous class "al": must be alnum, alpha, ascii, control, digit, double, graph, integer, lower, print, punct, space, upper, or xdigit}} test string-6.10 {string is, ok on empty} { string is alpha {} } 1 test string-6.11 {string is, -strict check against empty} { string is alpha -strict {} } 0 test string-6.12 {string is alnum, true} { string is alnum abc123 } 1 test string-6.15 {string is alpha, true} { string is alpha abc } 1 test string-6.24 {string is digit, true} { string is digit 0123456789 } 1 test string-6.25 {string is digit, false} { list [string is digit 0123Ü567] } {0} test string-6.26 {string is digit, false} { list [string is digit +123567] } {0} test string-6.27 {string is double, true} { string is double 1 } 1 test string-6.28 {string is double, true} { string is double [expr double(1)] } 1 test string-6.29 {string is double, true} { string is double 1.0 } 1 test string-6.30 {string is double, true} { string is double [string compare a a] } 1 test string-6.31 {string is double, true} { string is double " +1.0e-1 " } 1 test string-6.32 {string is double, true} { string is double "\n1.0\v" } 1 test string-6.33 {string is double, false} { list [string is double 1abc] } {0} test string-6.34 {string is double, false} { list [string is double abc] } {0} test string-6.35 {string is double, false} { list [string is double " 1.0e4e4 "] } {0} test string-6.36 {string is double, false} { list [string is double "\n"] } {0} test string-6.38 {string is double, false on underflow} jim { list [string is double 123e-9999] } {0} test string-6.39 {string is double, false} { # This test is non-portable because IRIX thinks # that .e1 is a valid double - this is really a bug # on IRIX as .e1 should NOT be a valid double list [string is double .e1] } {0} test string-6.48 {string is integer, true} { string is integer +1234567890 } 1 test string-6.49 {string is integer, true on type} { string is integer [expr int(50.0)] } 1 test string-6.50 {string is integer, true} { string is integer [list -10] } 1 test string-6.51 {string is integer, true as hex} { string is integer 0xabcdef } 1 test string-6.52 {string is integer, true as octal} { string is integer 012345 } 1 test string-6.53 {string is integer, true with whitespace} { string is integer " \n1234\v" } 1 test string-6.54 {string is integer, false} { list [string is integer 123abc] } 0 test string-6.56 {string is integer, false} { list [string is integer [expr double(1)]] } 0 test string-6.57 {string is integer, false} { list [string is integer " "] } 0 test string-6.58 {string is integer, false on bad octal} jim { list [string is integer 036963] } 1 test string-6.59 {string is integer, false on bad octal} tcl { list [string is integer 036963] } 0 test string-6.60 {string is integer, false on bad hex} { list [string is integer 0X345XYZ] } 0 test string-6.61 {string is lower, true} { string is lower abc } 1 test string-6.62 {string is lower, false} { list [string is lower aBc] } 0 test string-6.63 {string is lower, false} { list [string is lower abc1] } 0 test string-6.64 {string is lower, unicode false} { list [string is lower abÜUE] } 0 test string-6.65 {string is space, true} { string is space " \t\n\v\f" } 1 test string-6.66 {string is space, false} { list [string is space " \t\n\v1\f"] } 0 test string-6.75 {string is upper, true} { string is upper ABC } 1 test string-6.77 {string is upper, false} { list [string is upper AbC] } 0 test string-6.78 {string is upper, false} { list [string is upper AB2C] } 0 test string-6.84 {string is control} { ## Control chars are in the ranges ## 00..1F && 7F..9F list [string is control \x00\x01\x10\x1F\x7F\x80\x9F\x60] } 0 test string-6.85 {string is control} tcl { string is control \u0100 } 0 test string-6.86 {string is graph} { ## graph is any print char, except space list [string is gra "0123abc!@#\$ "] } 0 test string-6.87 {string is print} { ## basically any printable char list [string is print "0123abc!@#\$ \010"] } 0 test string-6.88 {string is punct} { ## any graph char that isn't alnum list [string is punct "_!@#\000beq0"] } 0 test string-6.89 {string is xdigit} { list [string is xdigit 0123456789\u0061bcdefABCDEFg] } 0 test string-7.1 {string last, too few args} { list [catch {string last a} msg] } {1} test string-7.2 {string last, bad args} { list [catch {string last a b c} msg] } {1} test string-7.3 {string last, too many args} { list [catch {string last a b c d} msg] } {1} test string-7.4 {string last} { string la xxx xxxx123xx345x678 } 1 test string-7.5 {string last} { string last xx xxxx123xx345x678 } 7 test string-7.6 {string last} { string las x xxxx123xx345x678 } 12 test string-7.13 {string last, start index} { ## Constrain to last 'a' should work string last ba badbad end-1 } 3 test string-7.14 {string last, start index} { ## Constrain to last 'b' should skip last 'ba' string last ba badbad end-2 } 0 test string-7.15 {string last, start index} { string last \u00dca \u00dcad\u00dcad 0 } -1 test string-7.16 {string last, start index} utf8 { string last \u00dca \u00dcad\u00dcad end-1 } 3 test string-7.17 {string last, too few args} { string last abc def } -1 test string-9.1 {string length} { list [catch {string length} msg] } {1} test string-9.2 {string length} { list [catch {string length a b} msg] } {1} test string-9.3 {string length} { string length "a little string" } 15 test string-9.4 {string length} { string le "" } 0 test string-10.1 {string map, too few args} { list [catch {string map} msg] } {1} test string-10.2 {string map, bad args} { list [catch {string map {a b} abba oops} msg] } {1} test string-10.3 {string map, too many args} { list [catch {string map -nocase {a b} str1 str2} msg] } {1} test string-10.4 {string map} { string map {a b} abba } {bbbb} test string-10.5 {string map} { string map {a b} a } {b} test string-10.6 {string map -nocase} { string map -nocase {a b} Abba } {bbbb} test string-10.7 {string map} { string map {abc 321 ab * a A} aabcabaababcab } {A321*A*321*} test string-10.8 {string map -nocase} { string map -nocase {aBc 321 Ab * a A} aabcabaababcab } {A321*A*321*} test string-10.9 {string map -nocase} { string map -no {abc 321 Ab * a A} aAbCaBaAbAbcAb } {A321*A*321*} test string-10.10 {string map} { list [catch {string map {a b c} abba} msg] } {1} test string-10.11 {string map, nulls} { string map {\x00 NULL blah \x00nix} {qwerty} } {qwerty} test string-10.12 {string map, unicode} { string map [list \u00fc ue UE \u00dc] "a\u00fcueUE\000EU" } aueue\u00dc\0EU test string-10.13 {string map, -nocase unicode} { string map -nocase [list \u00fc ue UE \u00dc] "a\u00fcueUE\000EU" } aue\u00dc\u00dc\0EU test string-10.14 {string map, -nocase null arguments} { string map -nocase {{} abc} foo } foo test string-10.15 {string map, one pair case} { string map -nocase {abc 32} aAbCaBaAbAbcAb } {a32aBaAb32Ab} test string-10.16 {string map, one pair case} { string map -nocase {ab 4321} aAbCaBaAbAbcAb } {a4321C4321a43214321c4321} test string-10.17 {string map, one pair case} { string map {Ab 4321} aAbCaBaAbAbcAb } {a4321CaBa43214321c4321} test string-11.1 {string match, too few args} { list [catch {string match a} msg] } {1} test string-11.2 {string match, too many args} { list [catch {string match a b c d} msg] } {1} test string-11.3 {string match} { string match abc abc } 1 test string-11.4 {string match} { string mat abc abd } 0 test string-11.5 {string match} { string match ab*c abc } 1 test string-11.6 {string match} { string match ab**c abc } 1 test string-11.7 {string match} { string match ab* abcdef } 1 test string-11.8 {string match} { string match *c abc } 1 test string-11.9 {string match} { string match *3*6*9 0123456789 } 1 test string-11.10 {string match} { string match *3*6*9 01234567890 } 0 test string-11.11 {string match} { string match a?c abc } 1 test string-11.12 {string match} { string match a??c abc } 0 test string-11.13 {string match} { string match ?1??4???8? 0123456789 } 1 test string-11.14 {string match} { string match {[abc]bc} abc } 1 test string-11.15 {string match} { string match {a[abc]c} abc } 1 test string-11.16 {string match} { string match {a[xyz]c} abc } 0 test string-11.17 {string match} { string match {12[2-7]45} 12345 } 1 test string-11.18 {string match} { string match {12[ab2-4cd]45} 12345 } 1 test string-11.19 {string match} { string match {12[ab2-4cd]45} 12b45 } 1 test string-11.20 {string match} { string match {12[ab2-4cd]45} 12d45 } 1 test string-11.21 {string match} { string match {12[ab2-4cd]45} 12145 } 0 test string-11.22 {string match} { string match {12[ab2-4cd]45} 12545 } 0 test string-11.23 {string match} { string match {a\*b} a*b } 1 test string-11.24 {string match} { string match {a\*b} ab } 0 test string-11.25 {string match} { string match {a\*\?\[\]\\\x} "a*?\[\]\\x" } 1 test string-11.26 {string match} { string match ** "" } 1 test string-11.27 {string match} { string match *. "" } 0 test string-11.28 {string match} { string match "" "" } 1 test string-11.29 {string match} { string match \[a a } 1 test string-11.30 {string match, bad args} { list [catch {string match - b c} msg] } {1} test string-11.31 {string match case} { string match a A } 0 test string-11.32 {string match nocase} { string match -nocase a A } 1 test string-11.34 {string match nocase} { string match -nocase a*f ABCDEf } 1 test string-11.35 {string match case, false hope} { # This is true because '_' lies between the A-Z and a-z ranges string match {[A-z]} _ } 1 test string-11.36 {string match nocase range} { # This is false because although '_' lies between the A-Z and a-z ranges, # we lower case the end points before checking the ranges. string match -nocase {[A-z]} _ } 0 test string-11.37 {string match nocase} { string match -nocase {[A-fh-Z]} g } 0 test string-11.38 {string match case, reverse range} { string match {[A-fh-Z]} g } 1 test string-11.39 {string match, *\ case} { string match {*\abc} abc } 1 test string-11.40 {string match, *special case} { string match {*[ab]} abc } 0 test string-11.41 {string match, *special case} { string match {*[ab]*} abc } 1 # I don't see why this shouldn't match. Ignored for jim test string-11.42 {string match, *special case} tcl { string match "*\\" "\\" } 0 test string-11.43 {string match, *special case} { string match "*\\\\" "\\" } 1 test string-11.44 {string match, *special case} { string match "*???" "12345" } 1 test string-11.45 {string match, *special case} { string match "*???" "12" } 0 test string-11.46 {string match, *special case} { string match "*\\*" "abc*" } 1 test string-11.47 {string match, *special case} { string match "*\\*" "*" } 1 test string-11.48 {string match, *special case} { string match "*\\*" "*abc" } 0 test string-11.49 {string match, *special case} { string match "?\\*" "a*" } 1 # I don't see why this shouldn't match. Ignored for jim test string-11.50 {string match, *special case} tcl { string match "\\" "\\" } 0 test string-12.1 {string range} { list [catch {string range} msg] } {1} test string-12.2 {string range} { list [catch {string range a 1} msg] } {1} test string-12.3 {string range} { list [catch {string range a 1 2 3} msg] } {1} test string-12.4 {string range} { string range abcdefghijklmnop 2 14 } {cdefghijklmno} test string-12.5 {string range, last > length} { string range abcdefghijklmnop 7 1000 } {hijklmnop} test string-12.6 {string range} { string range abcdefghijklmnop 10 end } {klmnop} test string-12.7 {string range, last < first} { string range abcdefghijklmnop 10 9 } {} test string-12.8 {string range, first < 0} { string range abcdefghijklmnop -3 2 } {abc} test string-12.9 {string range} { string range abcdefghijklmnop -3 -2 } {} test string-12.10 {string range} { string range abcdefghijklmnop 1000 1010 } {} test string-12.11 {string range} { string range abcdefghijklmnop -100 end } {abcdefghijklmnop} test string-12.12 {string range} { list [catch {string range abc abc 1} msg] } {1} test string-12.13 {string range} { list [catch {string range abc 1 eof} msg] } {1} test string-12.14 {string range} { string range abcdefghijklmnop end-1 end } {op} test string-12.15 {string range} { string range abcdefghijklmnop end 1000 } {p} test string-12.16 {string range} { string range abcdefghijklmnop end end-1 } {} test string-13.1 {string repeat} { list [catch {string repeat} msg] } {1} test string-13.2 {string repeat} { list [catch {string repeat abc 10 oops} msg] } {1} test string-13.3 {string repeat} { string repeat {} 100 } {} test string-13.4 {string repeat} { string repeat { } 5 } { } test string-13.5 {string repeat} { string repeat abc 3 } {abcabcabc} test string-13.6 {string repeat} { string repeat abc -1 } {} test string-13.7 {string repeat} { list [catch {string repeat abc end} msg] } {1} test string-13.8 {string repeat} { string repeat {} -1000 } {} test string-13.9 {string repeat} { string repeat {} 0 } {} test string-13.10 {string repeat} { string repeat def 0 } {} test string-13.11 {string repeat} { string repeat def 1 } def test string-13.12 {string repeat} { string repeat ab\u7266cd 3 } ab\u7266cdab\u7266cdab\u7266cd test string-13.13 {string repeat} { string repeat \x00 3 } \x00\x00\x00 test string-14.1 {string replace} { list [catch {string replace} msg] $msg } {1 {wrong # args: should be "string replace string first last ?string?"}} test string-14.2 {string replace} { list [catch {string replace a 1} msg] $msg } {1 {wrong # args: should be "string replace string first last ?string?"}} test string-14.3 {string replace} { list [catch {string replace a 1 2 3 4} msg] $msg } {1 {wrong # args: should be "string replace string first last ?string?"}} test string-14.4 {string replace} { } {} test string-14.5 {string replace} { string replace abcdefghijklmnop 2 14 } {abp} test string-14.6 {string replace} { string replace abcdefghijklmnop 7 1000 } {abcdefg} test string-14.7 {string replace} { string replace abcdefghijklmnop 10 end } {abcdefghij} test string-14.8 {string replace} { string replace abcdefghijklmnop 10 9 } {abcdefghijklmnop} test string-14.9 {string replace} { string replace abcdefghijklmnop -3 2 } {defghijklmnop} test string-14.10 {string replace} { string replace abcdefghijklmnop -3 -2 } {abcdefghijklmnop} test string-14.11 {string replace} { string replace abcdefghijklmnop 1000 1010 } {abcdefghijklmnop} test string-14.12 {string replace} { string replace abcdefghijklmnop -100 end } {} test string-14.13 {string replace} { list [catch {string replace abc abc 1} msg] $msg } {1 {bad index "abc": must be integer?[+-]integer? or end?[+-]integer?}} test string-14.14 {string replace} { list [catch {string replace abc 1 eof} msg] $msg } {1 {bad index "eof": must be integer?[+-]integer? or end?[+-]integer?}} test string-14.15 {string replace} { string replace abcdefghijklmnop end-10 end-2 NEW } {abcdeNEWop} test string-14.16 {string replace} { string replace abcdefghijklmnop 0 end foo } {foo} test string-14.17 {string replace} { string replace abcdefghijklmnop end end-1 } {abcdefghijklmnop} test string-15.1 {string tolower too few args} { list [catch {string tolower} msg] } {1} test string-15.2 {string tolower bad args} { list [catch {string tolower a b} msg] } {1} test string-15.3 {string tolower too many args} { list [catch {string tolower ABC 1 end oops} msg] } {1} test string-15.4 {string tolower} { string tolower ABCDeF } {abcdef} test string-15.5 {string tolower} { string tolower "ABC XyZ" } {abc xyz} test string-15.6 {string tolower} { string tolower {123#$&*()} } {123#$&*()} test string-16.1 {string toupper} { list [catch {string toupper} msg] } {1} test string-16.2 {string toupper} { list [catch {string toupper a b} msg] } {1} test string-16.4 {string toupper} { string toupper abCDEf } {ABCDEF} test string-16.5 {string toupper} { string toupper "abc xYz" } {ABC XYZ} test string-16.6 {string toupper} { string toupper {123#$&*()} } {123#$&*()} test string-17.1 {string totitle} -body { string totitle } -returnCodes error -match glob -result {wrong # args: should be "string totitle string*} test string-17.3 {string totitle} { string totitle abCDEf } {Abcdef} test string-17.4 {string totitle} { string totitle "abc xYz" } {Abc xyz} test string-17.5 {string totitle} { string totitle {123#$&*()} } {123#$&*()} test string-18.1 {string trim} { list [catch {string trim} msg] } {1} test string-18.2 {string trim} { list [catch {string trim a b c} msg] } {1} test string-18.3 {string trim} { string trim " XYZ " } {XYZ} test string-18.4 {string trim} { string trim "\t\nXYZ\t\n\r\n" } {XYZ} test string-18.5 {string trim} { string trim " A XYZ A " } {A XYZ A} test string-18.6 {string trim} { string trim "XXYYZZABC XXYYZZ" ZYX } {ABC } test string-18.7 {string trim} { string trim " \t\r " } {} test string-18.8 {string trim} { string trim {abcdefg} {} } {abcdefg} test string-18.9 {string trim} { string trim {} } {} test string-18.10 {string trim} { string trim ABC DEF } {ABC} test string-18.11 {string trim, unicode} { string trim "\xe7\xe8 AB\xe7C \xe8\xe7" \xe7\xe8 } " AB\xe7C " test string-19.1 {string trimleft} { list [catch {string trimleft} msg] } {1} test string-19.2 {string trimleft} { string trimleft " XYZ " } {XYZ } test string-20.1 {string trimright errors} { list [catch {string trimright} msg] } {1} test string-20.2 {string trimright errors} { list [catch {string trimg a} msg] } {1} test string-20.3 {string trimright} { string trimright " XYZ " } { XYZ} test string-20.4 {string trimright} { string trimright " " } {} test string-20.5 {string trimright} { string trimright "" } {} # Test for 8-bit clean and utf-8 trim chars test string-21.1 {string trim embedded nulls} { string trim " abc\x00def " } "abc\x00def" test string-21.2 {string trimleft embedded nulls} { string trimleft " abc\x00def " } "abc\x00def " test string-21.3 {string trimright embedded nulls} { string trimright " abc\x00def " } " abc\x00def" test string-21.4 {string trim utf-8} { string trim "\u00b5\u00b6abc\x00def\u00b5\u00b5" "\u00b5\u00b6" } "abc\x00def" test string-22.1 {string replace} { string replace //test.net/path/path2?query=url?otherquery 21 end } {//test.net/path/path2} testreport openocd-0.7.0/jimtcl/tests/regcount.test0000644000175000001440000000514512134336723015246 00000000000000source [file dirname [info script]]/testing.tcl needs cmd regexp testConstraint regexp_are [expr {[regexp {\d} 1]}] needs constraint regexp_are # Test regexp counted repetitions set n 0 foreach {pat str exp} { a+ bac a a{1,} bac a a* bac {{}} a{0,} bac {{}} aa+ bac {} a{2,} bac {} a{2,} bacaad aa a{3,} bacaad {} {a{2,}$} bacaad {} {a{2,}$} bacaa aa {a{2,}$} ba {} {a{2,}$} aa aa {a{0,0}b$} b b {a{1,1}b$} b {} {a{1,1}b$} cab ab {a{2,2}b$} cab {} {a{2,2}b$} cabaabx {} {a{2,2}b$} cacaab aab ca{2,4}b cacaab caab ca{2,3}b cacaab caab ca{2,3}b cacaaab caaab c(a|b){2,3}d xcbad {cbad a} c(a|b){2,3}d xcabbd {cabbd b} c(a|b){2,3}d xcbaaad {} a{4} baaaad aaaa a{2,5} baaaad aaaa a{1,3} baaaad aaa a{1,2} baaaad aa a{3,4} baaaad aaaa a{5,6} baaaad {} a{4}? baaaad aaaa a{2,5}? baaaad aa a{1,3}? baaaad a a{1,2}? baaaad a a{3,4}? baaaad aaa a{5,6}? baaaad {} {\d{1,3}} 239 239 (aa|bb)?c xabbaac {aac aa} (a|y)+ bac {a a} (a|y){1,} bac {a a} (a|y)* bac {{} {}} (a|y){0,} bac {{} {}} (a|y)a+ bac {} (a|y){2,} bac {} (a|y){2,} bacaad {aa a} (a|y){3,} bacaad {} {(a|y){2,}$} bacaad {} {(a|y){2,}$} bacaa {aa a} {(a|y){2,}$} ba {} {(a|y){2,}$} aa {aa a} {(a|y){0,0}b$} b {b {}} {(a|y){1,1}b$} b {} {(a|y){1,1}b$} cab {ab a} {(a|y){2,2}b$} cab {} {(a|y){2,2}b$} cabaabx {} {(a|y){2,2}b$} cacaab {aab a} c(a|y){2,4}b cacaab {caab a} c(a|y){2,3}b cacaab {caab a} c(a|y){2,3}b cacaaab {caaab a} c((a|y)|b){2,3}d xcbad {cbad a a} ####c((a|y)|b){2,3}d xcabbd {cabbd b {}} c((a|y)|b){2,3}d xcbaaad {} (a|y){4} baaaad {aaaa a} (a|y){2,5} baaaad {aaaa a} (a|y){1,3} baaaad {aaa a} (a|y){1,2} baaaad {aa a} (a|y){3,4} baaaad {aaaa a} (a|y){5,6} baaaad {} (a|y){4}? baaaad {aaaa a} (a|y){2,5}? baaaad {aa a} (a|y){1,3}? baaaad {a a} (a|y){1,2}? baaaad {a a} (a|y){3,4}? baaaad {aaa a} (a|y){5,6}? baaaad {} {[[:alpha:]]+} _bcd56_ef bcd {[[:alnum:]]+} _bcd56_ef bcd56 {[[:space:]]+} "_bc \t\r\n\f\v_" "{ \t\r\n\f\v}" {[\x41-\x43]+} "_ABCD_" ABC {\m.+\M} "#A test#" "{A test}" {\m.+?\M} "#A test#" "A" {\m\M} "a" "" {ab*c} xnbbmbbbc {} {.^xxx} yyy {} {\mb} " abc " "" ####((a*)*b)*b aaaaaaaaaaaaaaaaaaaaaaaaab {b {} {}} ####(a*)* aab {aa {}} {^([^:=]*)(:)?(=)?$} version {version version {} {}} } { if {[string match #* $pat]} { continue } #puts \t[list $pat $str [regexp -inline -- $pat $str]] test regcount-1.[incr n] "Test: regexp $pat $str" [list regexp -inline -- $pat $str] $exp } test regcount-2.1 "regexp counts cleared" { set re "((a|b){1,2}(c{2,3}))" regexp -inline $re xabcccce regexp -inline $re xabcccce } {abccc abccc b ccc} testreport openocd-0.7.0/jimtcl/tests/timer.test0000644000175000001440000002565412134336723014547 00000000000000# This file contains a collection of tests for the procedures in the # file tclTimer.c, which includes the "after" Tcl command. Sourcing # this file into Tcl runs the tests and generates output for errors. # No output means no errors were found. # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1997 by Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # RCS: @(#) $Id: timer.test,v 1.7.2.1 2001/10/13 01:14:19 hobbs Exp $ source [file dirname [info script]]/testing.tcl needs cmd after eventloop test timer-1.1 {Tcl_CreateTimerHandler procedure} { foreach i [after info] { after cancel $i } set x "" foreach i {20 40 200 10 30} { after $i lappend x $i } after 50 update set x } {10 20 30 40} test timer-2.1 {Tcl_DeleteTimerHandler procedure} { foreach i [after info] { after cancel $i } set x "" foreach i {20 40 60 10 30} { after $i lappend x $i } after cancel lappend x 60 after cancel lappend x 10 after 50 update set x } {20 30 40} # No tests for Tcl_ServiceTimer or ResetTimer, since it is already tested # above. test timer-3.1 {TimerHandlerEventProc procedure: event masks} { set x start after 20 { set x fired } update idletasks set result $x after 40 update lappend result $x } {start fired} test timer-3.2 {TimerHandlerEventProc procedure: multiple timers} { foreach i [after info] { after cancel $i } foreach i {40 120 200} { after $i lappend x $i } after 50 set result "" set x "" update lappend result $x after 80 update lappend result $x after 80 update lappend result $x } {40 {40 120} {40 120 200}} test timer-3.3 {TimerHandlerEventProc procedure: reentrant timer deletion} { foreach i [after info] { after cancel $i } set x {} after 20 lappend x 20 set i [after 60 lappend x 60] after 40 after cancel $i after 80 update set x } 20 test timer-3.4 {TimerHandlerEventProc procedure: all expired timers fire} { foreach i [after info] { after cancel $i } set x {} after 20 lappend x a after 40 lappend x b after 60 lappend x c after 70 vwait x set x } {a b c} test timer-3.5 {TimerHandlerEventProc procedure: reentrantly added timers don't fire} { foreach i [after info] { after cancel $i } set x {} after 20 {lappend x a; after 0 lappend x b} after 20 vwait x set x } a test timer-3.6 {TimerHandlerEventProc procedure: reentrantly added timers don't fire} { foreach i [after info] { after cancel $i } set x {} after 20 {lappend x a; after 20 lappend x b; after 20} after 20 vwait x set result $x vwait x lappend result $x } {a {a b}} # No tests for Tcl_DoWhenIdle: it's already tested by other tests # below. test timer-4.1 {Tcl_CancelIdleCall procedure} { foreach i [after info] { after cancel $i } set x before set y before set z before after idle set x after1 after idle set y after2 after idle set z after3 after cancel set y after2 update idletasks concat $x $y $z } {after1 before after3} test timer-4.2 {Tcl_CancelIdleCall procedure} { foreach i [after info] { after cancel $i } set x before set y before set z before after idle set x after1 after idle set y after2 after idle set z after3 after cancel set x after1 update idletasks concat $x $y $z } {before after2 after3} test timer-5.1 {Tcl_ServiceIdle, self-rescheduling handlers} { foreach i [after info] { after cancel $i } set x 1 set y 23 after idle {incr x; after idle {incr x; after idle {incr x}}} after idle {incr y} vwait x set result "$x $y" update idletasks lappend result $x } {2 24 4} test timer-6.1 {Tcl_AfterCmd procedure, basics} { list [catch {after} msg] $msg } {1 {wrong # args: should be "after option ?arg ...?"}} test timer-6.2 {Tcl_AfterCmd procedure, basics} jim { list [catch {after 2x} msg] $msg } {1 {bad argument "2x": must be cancel, idle, or info}} test timer-6.3 {Tcl_AfterCmd procedure, basics} jim { list [catch {after gorp} msg] $msg } {1 {bad argument "gorp": must be cancel, idle, or info}} test timer-6.4 {Tcl_AfterCmd procedure, ms argument} { set x before after 80 {set x after} after 40 update set y $x after 80 update list $y $x } {before after} test timer-6.5 {Tcl_AfterCmd procedure, ms argument} { set x before after 60 {set x after} after 40 update set y $x after 40 update list $y $x } {before after} test timer-6.6 {Tcl_AfterCmd procedure, cancel option} { list [catch {after cancel} msg] $msg } {1 {wrong # args: should be "after cancel id|command"}} test timer-6.7 {Tcl_AfterCmd procedure, cancel option} { after cancel after#1 } {} test timer-6.8 {Tcl_AfterCmd procedure, cancel option} { after cancel {foo bar} } {} test timer-6.9 {Tcl_AfterCmd procedure, cancel option} { foreach i [after info] { after cancel $i } set x before set y [after 20 set x after] after cancel $y after 40 update set x } {before} test timer-6.10 {Tcl_AfterCmd procedure, cancel option} { foreach i [after info] { after cancel $i } set x before after 20 set x after after cancel set x after after 40 update set x } {before} test timer-6.11 {Tcl_AfterCmd procedure, cancel option} { foreach i [after info] { after cancel $i } set x before after 20 set x after set id [after 60 set x after] after cancel $id after 40 update set y $x set x cleared after 40 update list $y $x } {after cleared} test timer-6.12 {Tcl_AfterCmd procedure, cancel option} { foreach i [after info] { after cancel $i } set x first after idle lappend x second after idle lappend x third set i [after idle lappend x fourth] after cancel {lappend x second} after cancel $i update idletasks set x } {first third} test timer-6.13 {Tcl_AfterCmd procedure, cancel option, multiple arguments for command} { foreach i [after info] { after cancel $i } set x first after idle lappend x second after idle lappend x third set i [after idle lappend x fourth] after cancel lappend x second after cancel $i update idletasks set x } {first third} test timer-6.14 {Tcl_AfterCmd procedure, cancel option, cancel during handler, used to dump core} { foreach i [after info] { after cancel $i } set id [ after 20 { set x done after cancel $id } ] vwait x } {} test timer-6.16 {Tcl_AfterCmd procedure, idle option} { list [catch {after idle} msg] $msg } {1 {wrong # args: should be "after idle script ?script ...?"}} test timer-6.17 {Tcl_AfterCmd procedure, idle option} { set x before after idle {set x after} set y $x update idletasks list $y $x } {before after} test timer-6.18 {Tcl_AfterCmd procedure, idle option} { set x before after idle set x after set y $x update idletasks list $y $x } {before after} test timer-6.23 {Tcl_AfterCmd procedure, no option, script with NULL} { foreach i [after info] { after cancel $i } set x "hello world" after 1 "set x ab\0cd" after 10 update string length $x } {5} test timer-6.24 {Tcl_AfterCmd procedure, no option, script with NULL} { foreach i [after info] { after cancel $i } set x "hello world" after 1 set x ab\0cd after 10 update string length $x } {5} test timer-6.25 {Tcl_AfterCmd procedure, cancel option, script with NULL} { foreach i [after info] { after cancel $i } set x "hello world" after 1 set x ab\0cd after cancel "set x ab\0ef" set x [llength [after info]] foreach i [after info] { after cancel $i } set x } {1} test timer-6.26 {Tcl_AfterCmd procedure, cancel option, script with NULL} { foreach i [after info] { after cancel $i } set x "hello world" after 1 set x ab\0cd after cancel set x ab\0ef set y [llength [after info]] foreach i [after info] { after cancel $i } set y } {1} test timer-6.27 {Tcl_AfterCmd procedure, idle option, script with NULL} { foreach i [after info] { after cancel $i } set x "hello world" after idle "set x ab\0cd" update string length $x } {5} test timer-6.28 {Tcl_AfterCmd procedure, idle option, script with NULL} { foreach i [after info] { after cancel $i } set x "hello world" after idle set x ab\0cd update string length $x } {5} test timer-6.29 {Tcl_AfterCmd procedure, info option, script with NULL} { foreach i [after info] { after cancel $i } set x "hello world" set id junk set id [after 10 set x ab\0cd] update set y [string length [lindex [lindex [after info $id] 0] 2]] foreach i [after info] { after cancel $i } set y } {5} set event [after idle foo bar] scan $event after#%d id test timer-7.1 {GetAfterEvent procedure} { list [catch {after info xfter#$id} msg] $msg } "1 {event \"xfter#$id\" doesn't exist}" test timer-7.2 {GetAfterEvent procedure} { list [catch {after info afterx$id} msg] $msg } "1 {event \"afterx$id\" doesn't exist}" test timer-7.3 {GetAfterEvent procedure} { list [catch {after info after#ab} msg] $msg } {1 {event "after#ab" doesn't exist}} test timer-7.4 {GetAfterEvent procedure} { list [catch {after info after#} msg] $msg } {1 {event "after#" doesn't exist}} test timer-7.5 {GetAfterEvent procedure} { list [catch {after info after#${id}x} msg] $msg } "1 {event \"after#${id}x\" doesn't exist}" test timer-7.6 {GetAfterEvent procedure} { list [catch {after info afterx[expr $id+1]} msg] $msg } "1 {event \"afterx[expr $id+1]\" doesn't exist}" after cancel $event test timer-8.1 {AfterProc procedure} { set x before proc foo {} { set x untouched after 20 {set x after} after 200 update return $x } list [foo] $x } {untouched after} test timer-8.2 {AfterProc procedure} { catch {rename bgerror {}} proc bgerror msg { set ::x $msg } set x empty after 20 {error "After error"} after 200 set y $x update catch {rename bgerror {}} list $y $x } {empty {After error}} test timer-8.4 {AfterProc procedure, deleting handler from itself} { foreach i [after info] { after cancel $i } proc foo {} { global x set x {} foreach i [after info] { lappend x [after info $i] } after cancel foo } after 1000 {error "I shouldn't ever have executed"} after idle foo update idletasks set x } {{{error "I shouldn't ever have executed"} timer}} foreach i [after info] { after cancel $i } testreport openocd-0.7.0/jimtcl/tests/parse.test0000644000175000001440000001267312134336723014536 00000000000000source [file dirname [info script]]/testing.tcl test parse-1.1 "Quoted closing bracket" { set x [string length "]"] } {1} test parse-1.2 "Quoted opening bracket" { set x [string length "\["] } {1} test parse-1.3 "Quoted open brace" { set x [string length "\{"] } {1} test parse-1.4 "Quoted open brace via var" { set lb \{ set x [string length "$lb"] } {1} test parse-1.5 "Braced bracket" { set x [string length {]}] } {1} test parse-1.6 "Dict sugar" -body { unset -nocomplain a array set a {a 1 b 2 c 3} set x $a( } -returnCodes error -match glob -result "*" test parse-1.8 "Dict sugar" { unset -nocomplain a array set a {a 1 b 2 c 3} set x $a([set y b]) } 2 test parse-1.9 "Backslash newline" { set x 123;\ set y 456 list $x $y } {123 456} test parse-1.10 "Backslash newline in quotes" { set x "abc\ def" } "abc def" test parse-1.11 "Backslash newline in quotes after var" { set y 1 set x "abc$y\ def" } "abc1 def" test parse-1.12 "Backslash newline in quotes after var" { set y 1 set x "abc$y\ def" } "abc1 def" test parse-1.13 "Newline in quotes" { set y 1 set x "abc def" } "abc\ndef" test parse-1.14 "Newline in quotes after var" { set y 1 set x "abc$y def" } "abc1\ndef" test parse-1.15 "Space in quotes" { set y 1 set x "abc def" } "abc def" test parse-1.16 "Space in quotes after var" { set y 1 set x "abc${y} def" } "abc1 def" test parse-1.17 "Command and var in quotes" { set y 1 set x "[set z 2][set y]" } 21 test parse-1.18 "Command and var in bare context" { set y 1 set x [set z 2][set y] } 21 test parse-1.19 "Lone dollar sign in quotes" { set y 1 set x "6$[set y]" } 6\$1 test parse-1.20 "Command and var in bare context" { set y 1 set x 6$[set y] } 6\$1 test parse-1.21 "Comment" { set y 1 # A comment one a line set x [set y] ;# comment after semicolon } 1 test parse-1.22 "# char" { set y 1 append y # set x "[set y]#" } {1##} test parse-1.23 "newline in command" { set y 1 set z 2 set x [incr y incr z] list $x $y $z } {3 2 3} test parse-1.24 "semicolon in command" { set x [list a; list b c; list d e f] } {d e f} # Note that Tcl complains about the missing brace here # while Jim ignores it test parse-1.25 "missing brace in var" jim { unset -nocomplain a set a 3 set brace \{ set x [subst \$${brace}a] } 3 test parse-1.26 "newline in braced var" { set "a\nb" var1 set x ${a b} } var1 test parse-1.27 "backslash escape in dict sugar" { unset -nocomplain a set a(b\x55d) 5 set x $a(b\x55d) } 5 test parse-1.28 "nested dict sugar" { unset -nocomplain a b set a(V) 5 set b(5) five set x $b($a(V)) } five set dq {"} set script "set x ${dq}hello" test parse-1.29 "missing quote" jim { eval $script } hello test parse-1.30 "missing quote" { info complete $script } 0 test parse-1.31 "backslash newline in bare context" { list abc\ 123 } {abc 123} test parse-1.32 "comment as last line of script" { set script {set x 3; # this is a comment} eval $script } 3 test parse-1.33 "upper case hex escapes" { list \x4A \x4F \x3C } {J O <} test parse-1.34 "octal escapes" { list \112 \117 \074 } {J O <} test parse-1.35 "invalid hex escape" { list \xZZ } xZZ test parse-1.36 "unicode escape" jim { list \u00b5 } \xc2\xb5 test parse-1.37 "invalid unicode escape after unicode" jim { list \ub5x } \xc2\xb5x test parse-1.38 "invalid unicode escape" { list \ux } ux test parse-1.39 "octal escape followed by invalid" { list \76x } >x test parse-1.40 "list containing quoted trailing backslash" jim { set x "abc \"def\\" lindex $x 1 } def\\ test parse-1.41 "list containing quoted newline" { set x {abc "def ghi"} lindex $x 1 } def\nghi test parse-1.42 "list containing missing quote" jim { set x {abc "def} lindex $x 1 } def test parse-1.43 "list containing trailing backslash" { set x "abc def\\" lindex $x 1 } def\\ test parse-1.44 "list creation" { list "a{ }d" } {{a{ }d}} test parse-1.45 "spaces before expr function args" { expr {round (3.2)} } 3 test parse-1.46 "expr function missing paren" { catch {expr {round 3.2}} } 1 test parse-1.47 "backslash newline in quotes" { # spaces set x "abc\ def" } "abc def" test parse-1.48 "backslash newline in quotes" { # tabs set x "abc\ def" } "abc def" test parse-1.49 "backslash newline in quotes" { # tabs plus newline set x "abc\ def" } "abc \ndef" test parse-1.50 "backslash newline in quotes" { # tabs plus newline set x "abc\ def" } "abc def" test parse-1.51 "special chars in dict sugar" { unset -nocomplain a set a(x$) 5 array names a } {{x$}} test parse-1.52 "special chars in dict sugar" { set x $a(x$) } 5 test parse-1.53 "special chars in dict sugar" { unset -nocomplain a set a(x\[) 5 array names a } {{x[}} test parse-1.54 "special chars in dict sugar" { set x $a(x\[) } 5 test parse-1.55 "special chars in dict sugar" { unset -nocomplain a set a(x\() 5 array names a } {x(} test parse-1.56 "special chars in dict sugar" { set x $a(x\() } 5 test parse-1.57 "special chars in dict sugar" { unset -nocomplain a set a(x() 5 array names a } {x(} test parse-1.58 "special chars in dict sugar" { set x $a(x() } 5 test parse-1.59 "special chars in dict sugar" { unset -nocomplain a set a(x") 5 lindex [array names a] 0 } {x"} test parse-1.60 "special chars in dict sugar" { set x $a(x") } 5 test parse-1.61 "quote in command" { set x [list \\" x] lindex $x end } x test parse-1.62 "quoted orphan dollar sign" { set x "x$" } {x$} test parse-1.63 "unquoted dollar sign" { set x x$ } {x$} testreport openocd-0.7.0/jimtcl/tests/applyns.test0000644000175000001440000000627512134336723015113 00000000000000# Commands covered: apply # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994-1996 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # Copyright (c) 2005-2006 Miguel Sofer # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. source [file dirname [info script]]/testing.tcl needs cmd apply needs cmd namespace # Tests for runtime errors in the lambda expression # Note: Jim doesn't have the concept of non-existent namespaces test apply-3.1 {non-existing namespace} -constraints tcl -body { apply [list x {set x 1} ::NONEXIST::FOR::SURE] x } -returnCodes error -result {namespace "::NONEXIST::FOR::SURE" not found} test apply-3.2 {non-existing namespace} -constraints tcl -body { namespace eval ::NONEXIST::FOR::SURE {} set lambda [list x {set x 1} ::NONEXIST::FOR::SURE] apply $lambda x namespace delete ::NONEXIST apply $lambda x } -returnCodes error -result {namespace "::NONEXIST::FOR::SURE" not found} test apply-3.3 {non-existing namespace} -constraints tcl -body { apply [list x {set x 1} NONEXIST::FOR::SURE] x } -returnCodes error -result {namespace "::NONEXIST::FOR::SURE" not found} test apply-3.4 {non-existing namespace} -constraints tcl -body { namespace eval ::NONEXIST::FOR::SURE {} set lambda [list x {set x 1} NONEXIST::FOR::SURE] apply $lambda x namespace delete ::NONEXIST apply $lambda x } -returnCodes error -result {namespace "::NONEXIST::FOR::SURE" not found} # Tests for correct namespace scope namespace eval ::testApply { proc testApply args {return testApply} } test apply-7.1 {namespace access} { set ::testApply::x 0 set body {set x 1; set x} list [apply [list args $body ::testApply]] $::testApply::x } {1 0} test apply-7.2 {namespace access} { set ::testApply::x 0 set body {variable x; set x} list [apply [list args $body ::testApply]] $::testApply::x } {0 0} test apply-7.3 {namespace access} { set ::testApply::x 0 set body {variable x; set x 1} list [apply [list args $body ::testApply]] $::testApply::x } {1 1} test apply-7.4 {namespace access} { set ::testApply::x 0 set body {testApply} apply [list args $body ::testApply] } testApply test apply-7.5 {namespace access} { set ::testApply::x 0 set body {set x 1; set x} list [apply [list args $body testApply]] $::testApply::x } {1 0} test apply-7.6 {namespace access} { set ::testApply::x 0 set body {variable x; set x} list [apply [list args $body testApply]] $::testApply::x } {0 0} test apply-7.7 {namespace access} { set ::testApply::x 0 set body {variable x; set x 1} list [apply [list args $body testApply]] $::testApply::x } {1 1} test apply-7.8 {namespace access} { set ::testApply::x 0 set body {testApply} apply [list args $body testApply] } testApply namespace delete testApply testreport # Local Variables: # mode: tcl # fill-column: 78 # End: openocd-0.7.0/jimtcl/tests/exitpackage.tcl0000644000175000001440000000004212134336723015477 00000000000000# This package just exits exit 1 openocd-0.7.0/jimtcl/tests/uplevel.test0000644000175000001440000000573012134336723015074 00000000000000# Commands covered: uplevel # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # RCS: @(#) $Id: uplevel.test,v 1.6 2000/04/10 17:19:05 ericm Exp $ source [file dirname [info script]]/testing.tcl proc a {x y} { newset z [expr $x+$y] return $z } proc newset {name value} { uplevel set $name $value uplevel 1 {uplevel 1 {set xyz 22}} } proc b {x y} { uplevel #0 set $x $y } test uplevel-1.1 {simple operation} { set xyz 0 a 22 33 } 55 test uplevel-1.2 {command is another uplevel command} { set xyz 0 a 22 33 set xyz } 22 proc a1 {} { b1 global a a1 set a $x set a1 $y } proc b1 {} { c1 global b b1 set b $x set b1 $y } proc c1 {} { uplevel 1 set x 111 uplevel #2 set y 222 uplevel 2 set x 333 uplevel #1 set y 444 uplevel 3 set x 555 uplevel #0 set y 666 } a1 test uplevel-2.1 {relative and absolute uplevel} {set a} 333 test uplevel-2.2 {relative and absolute uplevel} {set a1} 444 test uplevel-2.3 {relative and absolute uplevel} {set b} 111 test uplevel-2.4 {relative and absolute uplevel} {set b1} 222 test uplevel-2.5 {relative and absolute uplevel} {set x} 555 test uplevel-2.6 {relative and absolute uplevel} {set y} 666 test uplevel-3.1 {uplevel to same level} { set x 33 uplevel #0 set x 44 set x } 44 test uplevel-3.2 {uplevel to same level} { set x 33 uplevel 0 set x } 33 test uplevel-3.3 {uplevel to same level} { set y xxx proc a1 {} {set y 55; uplevel 0 set y 66; return $y} a1 } 66 test uplevel-3.4 {uplevel to same level} { set y zzz proc a1 {} {set y 55; uplevel #1 set y} a1 } 55 test uplevel-4.1 {error check: non-existent level} { list [catch c1 msg] $msg } {1 {bad level "#2"}} test uplevel-4.2 {error check: non-existent level} { proc c2 {} {uplevel 3 {set a b}} list [catch c2 msg] $msg } {1 {bad level "3"}} test uplevel-4.3 {error check: not enough args} { list [catch uplevel msg] $msg } {1 {wrong # args: should be "uplevel ?level? command ?arg ...?"}} test uplevel-4.4 {error check: not enough args} { proc upBug {} {uplevel 1} list [catch upBug msg] $msg } {1 {wrong # args: should be "uplevel ?level? command ?arg ...?"}} proc a2 {} { uplevel a3 } proc a3 {} { global x y set x [info level] set y [info level 1] } a2 test uplevel-5.1 {info level} {set x} 1 test uplevel-5.2 {info level} {set y} a3 test uplevel-6.1 {uplevel #0} { b g1 g1val set ::g1 } g1val test uplevel-6.2 {uplevel #bad} { catch {uplevel #bad set x 1} } 1 testreport openocd-0.7.0/jimtcl/tests/return.test0000644000175000001440000000200712134336723014731 00000000000000source [file dirname [info script]]/testing.tcl # return -code test return-1.1 {return -code} { set script "return -code 4 result" list [catch {eval $script} msg] $msg } {2 result} test return-1.2 {source file with break} { list [catch {source break.tcl} msg] $msg } {3 {}} test return-1.3 {source file with break} { list [catch {source return-break.tcl} msg] $msg } {3 result} proc a {level code msg} { return -level $level -code $code $msg } proc b {level code msg} { a $level $code $msg } test return-2.1 {return -level 0} { list [catch {a 0 20 text} msg] $msg } {20 text} test return-2.2 {return -level 1} { list [catch {a 1 20 text} msg] $msg } {20 text} test return-2.3 {return -level 2} { list [catch {a 2 20 text} msg] $msg } {2 text} test return-2.4 {return -level 0} { list [catch {b 0 20 text} msg] $msg } {20 text} test return-2.5 {return -level 1} { list [catch {b 1 20 text} msg] $msg } {20 text} test return-2.6 {return -level 2} { list [catch {b 2 20 text} msg] $msg } {20 text} testreport openocd-0.7.0/jimtcl/tests/proc.test0000644000175000001440000002327712134336723014371 00000000000000# Commands covered: proc, return, global # # This file, proc-old.test, includes the original set of tests for Tcl's # proc, return, and global commands. There is now a new file proc.test # that contains tests for the tclProc.c source file. # # Sourcing this file into Tcl runs the tests and generates output for # errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994-1997 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # RCS: @(#) $Id: proc-old.test,v 1.6 2000/04/10 17:19:03 ericm Exp $ source [file dirname [info script]]/testing.tcl needs constraint jim needs cmd array catch {rename t1 ""} catch {rename foo ""} proc tproc {} {return a; return b} test proc-old-1.1 {simple procedure call and return} {tproc} a proc tproc x { set x [expr $x+1] return $x } test proc-old-1.2 {simple procedure call and return} {tproc 2} 3 test proc-old-1.3 {simple procedure call and return} { proc tproc {} {return foo} } {tproc} test proc-old-1.4 {simple procedure call and return} { proc tproc {} {return} tproc } {} proc tproc1 {a} {incr a; return $a} proc tproc2 {a b} {incr a; return $a} test proc-old-1.5 {simple procedure call and return (2 procs with same body but different parameters)} { list [tproc1 123] [tproc2 456 789] } {124 457} test proc-old-1.6 {simple procedure call and return (shared proc body string)} { set x {} proc tproc {} {} ;# body is shared with x list [tproc] [append x foo] } {{} foo} test proc-old-2.1 {local and global variables} { proc tproc x { set x [expr $x+1] return $x } set x 42 list [tproc 6] $x } {7 42} test proc-old-2.2 {local and global variables} { proc tproc x { set y [expr $x+1] return $y } set y 18 list [tproc 6] $y } {7 18} test proc-old-2.3 {local and global variables} { proc tproc x { global y set y [expr $x+1] return $y } set y 189 list [tproc 6] $y } {7 7} test proc-old-2.4 {local and global variables} { proc tproc x { global y return [expr $x+$y] } set y 189 list [tproc 6] $y } {195 189} catch {unset _undefined_} test proc-old-2.5 {local and global variables} { proc tproc x { global _undefined_ return $_undefined_ } list [catch {tproc xxx} msg] $msg } {1 {can't read "_undefined_": no such variable}} test proc-old-2.6 {local and global variables} { set a 114 set b 115 global a b list $a $b } {114 115} proc do {cmd} {eval $cmd} test proc-old-3.1 {local and global arrays} { catch {unset a} set a(0) 22 list [catch {do {global a; set a(0)}} msg] $msg } {0 22} test proc-old-3.2 {local and global arrays} { catch {unset a} set a(x) 22 list [catch {do {global a; set a(x) newValue}} msg] $msg $a(x) } {0 newValue newValue} test proc-old-3.3 {local and global arrays} { catch {unset a} set a(x) 22 set a(y) 33 list [catch {do {global a; unset a(y)}; array names a} msg] $msg } {0 x} test proc-old-3.4 {local and global arrays} { catch {unset a} set a(x) 22 set a(y) 33 list [catch {do {global a; unset a; info exists a}} msg] $msg \ [info exists a] } {0 0 0} test proc-old-3.5 {local and global arrays} { catch {unset a} set a(x) 22 set a(y) 33 list [catch {do {global a; unset a(y); array names a}} msg] $msg } {0 x} catch {unset a} test proc-old-3.6 {local and global arrays} { catch {unset a} set a(x) 22 set a(y) 33 do {global a; do {global a; unset a}; set a(z) 22} list [catch {array names a} msg] $msg } {0 z} test proc-old-3.1 {arguments and defaults} { proc tproc {x y z} { return [list $x $y $z] } tproc 11 12 13 } {11 12 13} test proc-old-3.2 {arguments and defaults} { proc tproc {x y z} { return [list $x $y $z] } list [catch {tproc 11 12} msg] } {1} test proc-old-3.3 {arguments and defaults} { proc tproc {x y z} { return [list $x $y $z] } list [catch {tproc 11 12 13 14} msg] } {1} test proc-old-3.4 {arguments and defaults} { proc tproc {x {y y-default} {z z-default}} { return [list $x $y $z] } tproc 11 12 13 } {11 12 13} test proc-old-3.5 {arguments and defaults} { proc tproc {x {y y-default} {z z-default}} { return [list $x $y $z] } tproc 11 12 } {11 12 z-default} test proc-old-3.6 {arguments and defaults} { proc tproc {x {y y-default} {z z-default}} { return [list $x $y $z] } tproc 11 } {11 y-default z-default} test proc-old-3.7 {arguments and defaults} { proc tproc {x {y y-default} {z z-default}} { return [list $x $y $z] } list [catch {tproc} msg] } {1} # Note: This requires new TIP #288 support test proc-old-3.8 {arguments and defaults} { list [catch { proc tproc {x {y y-default} z} { return [list $x $y $z] } tproc 2 3 } msg] $msg } {0 {2 y-default 3}} test proc-old-3.9 {arguments and defaults} { proc tproc {x {y y-default} args} { return [list $x $y $args] } tproc 2 3 4 5 } {2 3 {4 5}} test proc-old-3.10 {arguments and defaults} { proc tproc {x {y y-default} args} { return [list $x $y $args] } tproc 2 3 } {2 3 {}} test proc-old-3.11 {arguments and defaults} { proc tproc {x {y y-default} args} { return [list $x $y $args] } tproc 2 } {2 y-default {}} test proc-old-3.12 {arguments and defaults} { proc tproc {x {y y-default} args} { return [list $x $y $args] } list [catch {tproc} msg] } {1} test proc-old-4.1 {variable numbers of arguments} { proc tproc args {return $args} tproc } {} test proc-old-4.2 {variable numbers of arguments} { proc tproc args {return $args} tproc 1 2 3 4 5 6 7 8 } {1 2 3 4 5 6 7 8} test proc-old-4.3 {variable numbers of arguments} { proc tproc args {return $args} tproc 1 {2 3} {4 {5 6} {{{7}}}} 8 } {1 {2 3} {4 {5 6} {{{7}}}} 8} test proc-old-4.4 {variable numbers of arguments} { proc tproc {x y args} {return $args} tproc 1 2 3 4 5 6 7 } {3 4 5 6 7} test proc-old-4.5 {variable numbers of arguments} { proc tproc {x y args} {return $args} tproc 1 2 } {} test proc-old-4.6 {variable numbers of arguments} { proc tproc {x missing args} {return $args} list [catch {tproc 1} msg] } {1} test proc-old-5.1 {error conditions} { list [catch {proc} msg] } {1} test proc-old-5.2 {error conditions} { list [catch {proc tproc b} msg] } {1} test proc-old-5.3 {error conditions} { list [catch {proc tproc b c d e} msg] } {1} test proc-old-5.6 {error conditions} { list [catch {proc tproc {{} y} {return foo}} msg] $msg } {1 {argument with no name}} test proc-old-5.7 {error conditions} { list [catch {proc tproc {{x 1 2} y} {return foo}} msg] $msg } {1 {too many fields in argument specifier "x 1 2"}} test proc-old-5.8 {error conditions} { catch {return} } 2 test proc-old-5.9 {error conditions} { list [catch {global} msg] $msg } {1 {wrong # args: should be "global varName ?varName ...?"}} proc tproc {} { set a 22 global a } test proc-old-5.10 {error conditions} { list [catch {tproc} msg] $msg } {1 {variable "a" already exists}} test proc-old-5.11 {error conditions} { catch {rename tproc {}} catch { proc tproc {x {} z} {return foo} } list [catch {tproc 1} msg] $msg } {1 {invalid command name "tproc"}} test proc-old-5.12 {error conditions} { proc tproc {} { set a 22 error "error in procedure" return } list [catch tproc msg] $msg } {1 {error in procedure}} # The tests below will really only be useful when run under Purify or # some other system that can detect accesses to freed memory... test proc-old-6.1 {procedure that redefines itself} { proc tproc {} { proc tproc {} { return 44 } return 45 } tproc } 45 test proc-old-6.2 {procedure that deletes itself} { proc tproc {} { rename tproc {} return 45 } tproc } 45 proc tproc code { return -code $code abc } test proc-old-7.1 {return with special completion code} { list [catch {tproc ok} msg] $msg } {0 abc} test proc-old-7.2 {return with special completion code} { list [catch {tproc error} msg] $msg } {1 abc} test proc-old-7.3 {return with special completion code} { list [catch {tproc return} msg] $msg } {2 abc} test proc-old-7.4 {return with special completion code} { list [catch {tproc break} msg] $msg } {3 abc} test proc-old-7.5 {return with special completion code} { list [catch {tproc continue} msg] $msg } {4 abc} test proc-old-7.6 {return with special completion code} { list [catch {tproc -14} msg] $msg } {-14 abc} test proc-old-7.7 {return with special completion code} { list [catch {tproc gorp} msg] } {1} test proc-old-7.8 {return with special completion code} { list [catch {tproc 10b} msg] } {1} test proc-old-7.9 {return with special completion code} { proc tproc2 {} { tproc return } list [catch tproc2 msg] $msg } {0 abc} test proc-old-7.10 {return with special completion code} { proc tproc2 {} { return -code error } list [catch tproc2 msg] $msg } {1 {}} test proc-old-8.1 {unset and undefined local arrays} { proc t1 {} { foreach v {xxx, yyy} { catch {unset $v} } set yyy(foo) bar } t1 } bar test proc-old-9.1 {empty command name} { catch {rename {} ""} proc t1 {args} { return } set v [t1] catch {$v} } 1 test proc-old-10.1 {ByteCode epoch change during recursive proc execution} { proc t1 x { set y 20 rename expr expr.old rename expr.old expr if $x then {t1 0} ;# recursive call after foo's code is invalidated return 20 } t1 1 } 20 # cleanup catch {rename t1 ""} catch {rename foo ""} testreport openocd-0.7.0/jimtcl/tests/concat.test0000644000175000001440000000405212134336723014663 00000000000000source [file dirname [info script]]/testing.tcl test concat-1.1 {simple concatenation} { concat a b c d e f g } {a b c d e f g} test concat-1.2 {merging lists together} { concat a {b c d} {e f g h} } {a b c d e f g h} test concat-1.3 {merge lists, retain sub-lists} { concat a {b {c d}} {{e f}} g h } {a b {c d} {e f} g h} test concat-1.4 {special characters} { concat a\{ {b \{c d} \{d } "a{ b \\{c d {d" test concat-2.1 {error check: one empty argument} { concat {} } {} test concat-3.1 {error check: no arguments} { list [catch concat msg] $msg } {0 {}} test concat-4.1 {pruning off extra white space} { concat {} {a b c} } {a b c} test concat-4.2 {pruning off extra white space} { concat x y " a b c \n\t " " " " def " } {x y a b c def} test concat-4.3 {pruning off extra white space sets length correctly} { llength [concat { {{a}} }] } 1 test concat-5.1 {Tcl_ScanCountedElement procedure - don't leave unmatched braces} { # This test checks for a very tricky feature. Any list element # generated with Tcl_ScanCountedElement and Tcl_ConvertElement must # have the property that it can be enclosing in curly braces to make # an embedded sub-list. If this property doesn't hold, then # Tcl_DStringStartSublist doesn't work. set x {} lappend x " \\\{ \\" concat $x [llength "{$x}"] } {\ \\\{\ \\ 1} test concat-6.1 {Tcl_ConcatObj - backslash-space at end of argument} { concat a {b\ } c } {a b\ c} test concat-6.2 {Tcl_ConcatObj - backslash-space at end of argument} { concat a {b\ } c } {a b\ c} test concat-6.3 {Tcl_ConcatObj - backslash-space at end of argument} { concat a {b\\ } c } {a b\\ c} test concat-6.4 {Tcl_ConcatObj - backslash-space at end of argument} { concat a {b } c } {a b c} test concat-6.5 {Tcl_ConcatObj - backslash-space at end of argument} { concat a { } c } {a c} test concat-6.6 {Tcl_ConcatObj - utf-8 sequence with "whitespace" char} { # Check for Bug #227512. If this violates C isspace, then it returns \xc3. concat \xe0 } \xe0 testreport openocd-0.7.0/jimtcl/tests/dict.test0000644000175000001440000001172012134336723014337 00000000000000source [file dirname [info script]]/testing.tcl test dict-1.1 "Basic dict" { set d [dict create] dict set d fruit apple dict set d car holden #puts "d=$d" #puts "d(fruit)=$d(fruit)" dict get $d car } {holden} catch {unset d} test dict-2.1 "Dict via reference" references { set d [dict create] dict set d fruit apple dict set d car holden # now create a dictionary reference set dref [ref $d dict] dict get [getref $dref] car } {holden} test dict-2.2 "Modify dict via reference" references { # Get the value out of the refernence set d [getref $dref] # Modify it dict set d car toyota # And put the new value back setref $dref $d # Finally check it dict get [getref $dref] car } {toyota} test dict-2.3 "Modify dict via reference - one line" references { # Get the value out of the refernence set d [getref $dref] setref $dref [dict set d car toyota] # Finally check it dict get [getref $dref] car } {toyota} # Sort a dictionary in key order - return a list proc dictsort {dict} { set result {} foreach k [lsort [dict keys $dict]] { lappend result $k [dict get $dict $k] } return $result } set a [dict create a 1 b 2] set b [dict create b 3 c 4] test dict-3.1 {Merge} { dict merge } {} test dict-3.2 {Merge} { dictsort [dict merge $a] } {a 1 b 2} test dict-3.3 {Merge} { dictsort [dict merge $b] } {b 3 c 4} test dict-3.4 {Merge} { dictsort [dict merge $a $b] } {a 1 b 3 c 4} test dict-3.5 {Merge} { dictsort [dict merge $b $a] } {a 1 b 2 c 4} test dict-3.6 {Merge} { dictsort [dict merge $b $a {a 5}] } {a 5 b 2 c 4} test dict-3.7 {Merge} { dictsort [dict merge {a 5} $b $a] } {a 1 b 2 c 4} test dict-3.8 {Merge} { catch {dict merge 1 $b $a} } 1 test dict-3.9 {Merge} { catch {dict merge $b 1 $a} } 1 test dict-3.10 {Merge} { catch {dict merge $b $a 1} } 1 test dict-3.11 {Merge} { catch {dict merge 1} } 1 test dict-4.1 {Dict size} { dict size {a b} } 1 test dict-4.2 {Dict size} { dict size {a b c d} } 2 test dict-5.1 {Dict with} { proc a {} { set x [dict create a b c d] dict with x { set a B unset c } set x } dictsort [a] } {a B} test dict-5.2 {Dict with} { proc a {} { set x [dict create a b c d] dict with x { set a B unset c } set x } dictsort [a] } {a B} test dict-22.1 {dict with command} { list [catch {dict with} msg] $msg } {1 {wrong # args: should be "dict with dictVar ?key ...? script"}} test dict-22.2 {dict with command} { list [catch {dict with v} msg] $msg } {1 {wrong # args: should be "dict with dictVar ?key ...? script"}} test dict-22.3 {dict with command} { unset -nocomplain v list [catch {dict with v {error "in body"}} msg] $msg } {1 {can't read "v": no such variable}} test dict-22.4 {dict with command} { set a {b c d e} unset -nocomplain b d set result [list [info exist b] [info exist d]] dict with a { lappend result [info exist b] [info exist d] $b $d } set result } {0 0 1 1 c e} test dict-22.5 {dict with command} { set a {b c d e} dict with a { lassign "$b $d" d b } dictsort $a } {b e d c} test dict-22.6 {dict with command} { set a {b c d e} dict with a { unset b # This *won't* go into the dict... set f g } set a } {d e} test dict-22.7 {dict with command} { set a {b c d e} dict with a { dict unset a b } dictsort $a } {b c d e} test dict-22.8 {dict with command} { set a [dict create b c] dict with a { set b $a } set a } {b {b c}} test dict-22.9 {dict with command} { set a {b {c d}} dict with a b { set c $c$c } set a } {b {c dd}} test dict-22.10 {dict with command: result handling tricky case} { set a {b {c d}} foreach i {0 1} { if {$i} break dict with a b { set a {} # We're checking to see if we lose this break break } } list $i $a } {0 {}} test dict-22.11 {dict with command: no recursive structures [Bug 1786481]} { set foo {t {t {t {inner 1}}}} dict with foo { dict with t { dict with t { dict with t { incr inner } } } } string range [append foo OK] end-1 end } OK test dict-23.1 {dict unset missing last level} { set a {b c d e} dict unset a xyz dict size $a } 2 test dict-23.2 {dict unset command} -returnCodes error -body { set dictVar a dict unset dictVar a } -cleanup { unset dictVar } -result {missing value to go with key} test dict-23.3 {dict unset command} -setup { unset -nocomplain dictVar } -body { list [info exists dictVar] [dict unset dictVar a] [info exists dictVar] } -cleanup { unset dictVar } -result {0 {} 1} test dict-23.4 {dict unset command: write failure} -setup { unset -nocomplain dictVar } -body { set dictVar 1 dict unset dictVar a } -returnCodes error -cleanup { unset dictVar } -result {missing value to go with key} test dict-24.1 {dict/list shimmering - Bug 3004007} {set l [list p 1 p 2 q 3];dict get $l q;set l} {p 1 p 2 q 3} test dict-24.2 {dict/list shimmering - Bug 3004007} {set l [list p 1 p 2 q 3];dict get $l q;llength $l} 6 testreport openocd-0.7.0/jimtcl/tests/proc-new.test0000644000175000001440000000523512134336723015152 00000000000000source [file dirname [info script]]/testing.tcl needs constraint jim needs cmd array proc aproc {} { list } proc bproc {b} { list b $b } proc cproc {b c} { list b $b c $c } proc dproc {b c {d dd}} { list b $b c $c d $d } proc eproc {b c {d dd} e} { list b $b c $c d $d e $e } proc fproc {b c {d dd} args} { list b $b c $c d $d args $args } proc gproc {b c {d dd} args e} { list b $b c $c d $d args $args e $e } proc hproc {{a aa} args} { list a $a args $args } proc iproc {{a aa} b {c cc}} { list a $a b $b c $c } proc jproc {args {a aa} b {c cc} d} { list a $a b $b c $c d $d args $args } set n 1 foreach {proc params result} { aproc {} {} bproc B {b B} cproc {B C} {b B c C} dproc {B C} {b B c C d dd} dproc {B C D} {b B c C d D} eproc {B C D E} {b B c C d D e E} eproc {B C E} {b B c C d dd e E} fproc {B C} {b B c C d dd args {}} fproc {B C D} {b B c C d D args {}} fproc {B C D E} {b B c C d D args E} fproc {B C D E F} {b B c C d D args {E F}} gproc {B C E} {b B c C d dd args {} e E} gproc {B C D E} {b B c C d D args {} e E} gproc {B C D X E} {b B c C d D args X e E} gproc {B C D X Y Z E} {b B c C d D args {X Y Z} e E} hproc {} {a aa args {}} hproc {A} {a A args {}} hproc {A X Y Z} {a A args {X Y Z}} iproc {B} {a aa b B c cc} iproc {A B} {a A b B c cc} iproc {A B C} {a A b B c C} jproc {B D} {a aa b B c cc d D args {}} jproc {A B D} {a A b B c cc d D args {}} jproc {A B C D} {a A b B c C d D args {}} jproc {E F A B C D} {a A b B c C d D args {E F}} } { test proc-1.$n "Proc args combos" [list $proc {*}$params] $result incr n } proc onearg_search {{nocase ""} value list} { lsearch {*}$nocase $list $value } proc multiarg_search {args value list} { lsearch {*}$args $list $value } test proc-2.1 "Real test of optional switches" { onearg_search c {A a B b C c D d} } 5 test proc-2.2 "Real test of optional switches" { onearg_search -nocase c {A a B b C c D d} } 4 test proc-2.3 "Real test of optional switches" { multiarg_search -glob c* {A a B b C c D d} } 5 test proc-2.4 "Real test of optional switches" { multiarg_search -nocase -glob c* {A a B b C c D d} } 4 test proc-3.1 "Rename optional args" { proc a {b {args vars}} { } catch {a} msg set msg } {wrong # args: should be "a b ?vars ...?"} test proc-3.2 "Rename optional args" { proc a {b {args vars} c} { } catch {a} msg set msg } {wrong # args: should be "a b ?vars ...? c"} test proc-3.2 "Rename optional args" { proc a {b {args vars}} { return $vars } a B C D } {C D} test proc-3.3 "dict sugar arg" { proc a {b(c)} { return $b} a 4 } {c 4} test proc-3.4 "invalid upref in rightargs" { proc a {{x 2} &b} { return $b} unset -nocomplain B catch {a B} } 1 testreport openocd-0.7.0/jimtcl/tests/rename.test0000644000175000001440000001130412134336723014661 00000000000000# Commands covered: rename # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # RCS: @(#) $Id: rename.test,v 1.8.2.1 2001/09/12 20:34:59 dgp Exp $ source [file dirname [info script]]/testing.tcl # Must eliminate the "unknown" command while the test is running, # especially if the test is being run in a program with its # own special-purpose unknown command. catch {rename unknown unknown.old} catch {rename r2 {}} proc r1 {} {return "procedure r1"} rename r1 r2 test rename-1.1 {simple renaming} { r2 } {procedure r1} test rename-1.2 {simple renaming} { list [catch r1 msg] $msg } {1 {invalid command name "r1"}} rename r2 {} test rename-1.3 {simple renaming} { list [catch r2 msg] $msg } {1 {invalid command name "r2"}} # The test below is tricky because it renames a built-in command. # It's possible that the test procedure uses this command, so must # restore the command before calling test again. rename list l.new set a [catch list msg1] set b [l.new a b c] rename l.new list set c [catch l.new msg2] set d [list 111 222] test rename-2.1 {renaming built-in command} { list $a $msg1 $b $c $msg2 $d } {1 {invalid command name "list"} {a b c} 1 {invalid command name "l.new"} {111 222}} test rename-3.1 {error conditions} { list [catch {rename r1} msg] $msg } {1 {wrong # args: should be "rename oldName newName"}} test rename-3.2 {error conditions} { list [catch {rename r1 r2 r3} msg] $msg } {1 {wrong # args: should be "rename oldName newName"}} test rename-3.3 {error conditions} { proc r1 {} {} proc r2 {} {} list [catch {rename r1 r2} msg] $msg } {1 {can't rename to "r2": command already exists}} test rename-3.4 {error conditions} { catch {rename r1 {}} catch {rename r2 {}} list [catch {rename r1 r2} msg] $msg } {1 {can't rename "r1": command doesn't exist}} test rename-3.5 {error conditions} { catch {rename _non_existent_command {}} list [catch {rename _non_existent_command {}} msg] $msg } {1 {can't delete "_non_existent_command": command doesn't exist}} catch {rename unknown {}} catch {rename unknown.old unknown} if {[info command testdel] == "testdel"} { test rename-4.1 {reentrancy issues with command deletion and renaming} { set x {} testdel {} foo {lappend x deleted; rename bar {}; lappend x [info command bar]} rename foo bar lappend x | rename bar {} set x } {| deleted {}} test rename-4.2 {reentrancy issues with command deletion and renaming} { set x {} testdel {} foo {lappend x deleted; rename foo bar} rename foo {} set x } {deleted} test rename-4.3 {reentrancy issues with command deletion and renaming} { set x {} testdel {} foo {lappend x deleted; testdel {} foo {lappend x deleted2}} rename foo {} lappend x | rename foo {} set x } {deleted | deleted2} test rename-4.4 {reentrancy issues with command deletion and renaming} { set x {} testdel {} foo {lappend x deleted; rename foo bar} rename foo {} lappend x | [info command bar] } {deleted | {}} test rename-4.5 {reentrancy issues with command deletion and renaming} { set env(value) before interp create foo testdel foo cmd {set env(value) deleted} interp delete foo set env(value) } {deleted} test rename-4.6 {reentrancy issues with command deletion and renaming} { proc killx args { interp delete foo } set env(value) before interp create foo foo alias killx killx testdel foo cmd {set env(value) deleted; killx} list [catch {foo eval {rename cmd {}}} msg] $msg $env(value) } {0 {} deleted} test rename-4.7 {reentrancy issues with command deletion and renaming} { proc killx args { interp delete foo } set env(value) before interp create foo foo alias killx killx testdel foo cmd {set env(value) deleted; killx} list [catch {interp delete foo} msg] $msg $env(value) } {0 {} deleted} if {[info exists env(value)]} { unset env(value) } } test rename-6.1 {old code invalidated (epoch incremented) when cmd with compile proc is renamed } { proc x {} { set a 123 set b [split a 2] } x rename split split.old proc split {} {puts "new split called!"} catch {x} msg } 1 if {[info commands split.old] != {}} { catch {rename split {}} catch {rename split.old split} } catch {rename x {}} catch {rename killx {}} testreport openocd-0.7.0/jimtcl/tests/pid.test0000644000175000001440000000326512134336723014175 00000000000000# Commands covered: pid # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994-1995 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # RCS: @(#) $Id: pid.test,v 1.6 2000/04/10 17:19:03 ericm Exp $ source [file dirname [info script]]/testing.tcl needs cmd pid posix needs cmd exec catch {package require regexp} testConstraint regexp [expr {[info commands regexp] ne {}}] testConstraint socket [expr {[info commands socket] ne {}}] testConstraint getpid [expr {[catch pid] == 0}] file delete test1 test pid-1.1 {pid command} {regexp getpid} { regexp {(^[0-9]+$)|(^0x[0-9a-fA-F]+$)} [pid] } 1 test pid-1.2 {pid command} {regexp socket} { set f [open {| echo foo | cat >test1} w] set pids [pid $f] close $f catch {removeFile test1} list [llength $pids] [regexp {^[0-9]+$} [lindex $pids 0]] \ [regexp {^[0-9]+$} [lindex $pids 1]] \ [expr {[lindex $pids 0] == [lindex $pids 1]}] } {2 1 1 0} test pid-1.3 {pid command} socket { set f [open test1 w] set pids [pid $f] close $f set pids } {} test pid-1.4 {pid command} jim { list [catch {pid a b} msg] $msg } {1 {wrong # args: should be "pid ?chan?"}} test pid-1.5 {pid command} { list [catch {pid gorp} msg] $msg } {1 {can not find channel named "gorp"}} # cleanup file delete test1 testreport openocd-0.7.0/jimtcl/tests/infoframe.test0000644000175000001440000000105712134336723015364 00000000000000source [file dirname [info script]]/testing.tcl needs constraint jim proc a {n} { if {$n eq "trace"} { stacktrace } else { info frame $n } } proc b {n} { a $n } proc c {n} { b $n } # --- Don't change line numbers above test info-frame-1.1 "Current proc" { c 0 } {a infoframe.test 12} test info-frame-1.2 "Caller" { c -1 } {b infoframe.test 16} test info-frame-1.3 "Caller of Caller" { c -2 } {c infoframe.test 30} test stacktrace-1.1 "Full stack trace" { c trace } {a infoframe.test 12 b infoframe.test 16 c infoframe.test 34} testreport openocd-0.7.0/jimtcl/tests/alias.test0000644000175000001440000001064212134336723014507 00000000000000source [file dirname [info script]]/testing.tcl needs constraint jim needs cmd array needs cmd ref test alias-1.1 "One word alias" { set x 2 alias newincr incr newincr x } {3} test alias-1.4 "Two word alias" { alias infoexists info exists infoexists x } {1} test alias-1.5 "Replace alias" { alias newincr infoexists newincr x } {1} test alias-1.6 "Delete alias" { rename newincr "" catch {newincr x} } {1} test alias-1.7 "Replace alias with proc" { proc infoexists {n} { return yes } infoexists any } {yes} test alias-1.8 "Replace proc with alias" { alias infoexists info exists infoexists any } {0} test alias-1.9 "error message from alias" -body { alias newstring string newstring match } -returnCodes error -result {wrong # args: should be "string match ?-nocase? pattern string"} test alias-1.10 "info alias" { alias x info exists info alias x } {info exists} test alias-1.10 "info alias on non-alias" -body { info alias format } -returnCodes error -result {command "format" is not an alias} test curry-1.1 "One word curry" { set x 2 set one [curry incr] $one x } {3} test curry-1.4 "Two word curry" { set two [curry info exists] list [$two x] [$two y] } {1 0} test curry-1.5 "Delete curry" { unset one two collect } {2} test local-1.2 "local curry in proc" { proc a {} { local set p [curry info exists] set x 1 list $p [$p x] [$p y] } lassign [a] p exists_x exists_y list [info procs $p] $exists_x $exists_y } {{} 1 0} test local-1.2 "set local curry in proc" { proc a {} { set p [local curry info exists] set x 1 list $p [$p x] [$p y] } lassign [a] p exists_x exists_y list [info procs $p] $exists_x $exists_y } {{} 1 0} test local-1.3 "local alias in proc" { proc a {} { local alias p info exists set x 1 list [p x] [p y] } lassign [a] exists_x exists_y list [info commands p] $exists_x $exists_y } {{} 1 0} test local-1.5 "local proc in proc" { set ::x 1 proc a {} { local proc b {} { incr ::x } b set ::x } a list [info procs b] $::x } {{} 2} test local-1.6 "local lambda in lsort" { proc a {} { lsort -command [local lambda {a b} {string compare $a $b}] {d a f g} } a } {a d f g} test local-1.7 "check no reference procs" { info procs ">2} 63 test expr-old-1.14 {integer operators} {expr -1>>2} -1 test expr-old-1.15 {integer operators} {expr 3>2} 1 test expr-old-1.16 {integer operators} {expr 2>2} 0 test expr-old-1.17 {integer operators} {expr 1>2} 0 test expr-old-1.18 {integer operators} {expr 3<2} 0 test expr-old-1.19 {integer operators} {expr 2<2} 0 test expr-old-1.20 {integer operators} {expr 1<2} 1 test expr-old-1.21 {integer operators} {expr 3>=2} 1 test expr-old-1.22 {integer operators} {expr 2>=2} 1 test expr-old-1.23 {integer operators} {expr 1>=2} 0 test expr-old-1.24 {integer operators} {expr 3<=2} 0 test expr-old-1.25 {integer operators} {expr 2<=2} 1 test expr-old-1.26 {integer operators} {expr 1<=2} 1 test expr-old-1.27 {integer operators} {expr 3==2} 0 test expr-old-1.28 {integer operators} {expr 2==2} 1 test expr-old-1.29 {integer operators} {expr 3!=2} 1 test expr-old-1.30 {integer operators} {expr 2!=2} 0 test expr-old-1.31 {integer operators} {expr 7&0x13} 3 test expr-old-1.32 {integer operators} {expr 7^0x13} 20 test expr-old-1.33 {integer operators} {expr 7|0x13} 23 test expr-old-1.34 {integer operators} {expr 0&&1} 0 test expr-old-1.35 {integer operators} {expr 0&&0} 0 test expr-old-1.36 {integer operators} {expr 1&&3} 1 test expr-old-1.37 {integer operators} {expr 0||1} 1 test expr-old-1.38 {integer operators} {expr 3||0} 1 test expr-old-1.39 {integer operators} {expr 0||0} 0 test expr-old-1.40 {integer operators} {expr 3>2?44:66} 44 test expr-old-1.41 {integer operators} {expr 2>3?44:66} 66 test expr-old-1.42 {integer operators} {expr 36/5} 7 test expr-old-1.43 {integer operators} {expr 36%5} 1 test expr-old-1.44 {integer operators} {expr -36/5} -8 test expr-old-1.45 {integer operators} {expr -36%5} 4 test expr-old-1.46 {integer operators} {expr 36/-5} -8 test expr-old-1.47 {integer operators} {expr 36%-5} -4 test expr-old-1.48 {integer operators} {expr -36/-5} 7 test expr-old-1.49 {integer operators} {expr -36%-5} -1 test expr-old-1.50 {integer operators} {expr +36} 36 test expr-old-1.51 {integer operators} {expr +--++36} 36 test expr-old-1.52 {integer operators} {expr +36%+5} 1 test expr-old-1.53 {integer operators} { catch {unset x} set x 1 list [expr {1 && $x}] [expr {$x && 1}] \ [expr {0 || $x}] [expr {$x || 0}] } {1 1 1 1} # Check the floating-point operators individually, along with # automatic conversion to integers where needed. test expr-old-2.1 {floating-point operators} {expr -4.2} -4.2 test expr-old-2.2 {floating-point operators} jim {expr -(1.1+4.2)} -5.3 test expr-old-2.3 {floating-point operators} {expr +5.7} 5.7 test expr-old-2.4 {floating-point operators} {expr +--+-62.0} -62.0 test expr-old-2.5 {floating-point operators} {expr !2.1} 0 test expr-old-2.6 {floating-point operators} {expr !0.0} 1 test expr-old-2.7 {floating-point operators} {expr 4.2*6.3} 26.46 test expr-old-2.8 {floating-point operators} {expr 36.0/12.0} 3.0 test expr-old-2.9 {floating-point operators} {expr 27/4.0} 6.75 test expr-old-2.10 {floating-point operators} {expr 2.3+2.1} 4.4 test expr-old-2.11 {floating-point operators} {expr 2.3-6.5} -4.2 test expr-old-2.12 {floating-point operators} {expr 3.1>2.1} 1 test expr-old-2.13 {floating-point operators} {expr {2.1 > 2.1}} 0 test expr-old-2.14 {floating-point operators} {expr 1.23>2.34e+1} 0 test expr-old-2.15 {floating-point operators} {expr 3.45<2.34} 0 test expr-old-2.16 {floating-point operators} {expr 0.002e3<--200e-2} 0 test expr-old-2.17 {floating-point operators} {expr 1.1<2.1} 1 test expr-old-2.18 {floating-point operators} {expr 3.1>=2.2} 1 test expr-old-2.19 {floating-point operators} {expr 2.345>=2.345} 1 test expr-old-2.20 {floating-point operators} {expr 1.1>=2.2} 0 test expr-old-2.21 {floating-point operators} {expr 3.0<=2.0} 0 test expr-old-2.22 {floating-point operators} {expr 2.2<=2.2} 1 test expr-old-2.23 {floating-point operators} {expr 2.2<=2.2001} 1 test expr-old-2.24 {floating-point operators} {expr 3.2==2.2} 0 test expr-old-2.25 {floating-point operators} {expr 2.2==2.2} 1 test expr-old-2.26 {floating-point operators} {expr 3.2!=2.2} 1 test expr-old-2.27 {floating-point operators} {expr 2.2!=2.2} 0 test expr-old-2.28 {floating-point operators} {expr 0.0&&0.0} 0 test expr-old-2.29 {floating-point operators} {expr 0.0&&1.3} 0 test expr-old-2.30 {floating-point operators} {expr 1.3&&0.0} 0 test expr-old-2.31 {floating-point operators} {expr 1.3&&3.3} 1 test expr-old-2.32 {floating-point operators} {expr 0.0||0.0} 0 test expr-old-2.33 {floating-point operators} {expr 0.0||1.3} 1 test expr-old-2.34 {floating-point operators} {expr 1.3||0.0} 1 test expr-old-2.35 {floating-point operators} {expr 3.3||0.0} 1 test expr-old-2.36 {floating-point operators} {expr 3.3>2.3?44.3:66.3} 44.3 test expr-old-2.37 {floating-point operators} {expr 2.3>3.3?44.3:66.3} 66.3 test expr-old-2.38 {floating-point operators} { list [catch {expr 028.1 + 09.2} msg] $msg } {0 37.3} # Operators that aren't legal on floating-point numbers test expr-old-3.1 {illegal floating-point operations} { list [catch {expr ~4.0} msg] } {1} test expr-old-3.2 {illegal floating-point operations} { list [catch {expr 27%4.0} msg] } {1} test expr-old-3.3 {illegal floating-point operations} { list [catch {expr 27.0%4} msg] } {1} test expr-old-3.4 {illegal floating-point operations} { list [catch {expr 1.0<<3} msg] } {1} test expr-old-3.5 {illegal floating-point operations} { list [catch {expr 3<<1.0} msg] } {1} test expr-old-3.6 {illegal floating-point operations} { list [catch {expr 24.0>>3} msg] } {1} test expr-old-3.7 {illegal floating-point operations} { list [catch {expr 24>>3.0} msg] } {1} test expr-old-3.8 {illegal floating-point operations} { list [catch {expr 24&3.0} msg] } {1} test expr-old-3.9 {illegal floating-point operations} { list [catch {expr 24.0|3} msg] } {1} test expr-old-3.10 {illegal floating-point operations} { list [catch {expr 24.0^3} msg] } {1} # Check the string operators individually. test expr-old-4.1 {string operators} {expr {"abc" > "def"}} 0 test expr-old-4.2 {string operators} {expr {"def" > "def"}} 0 test expr-old-4.3 {string operators} {expr {"g" > "def"}} 1 test expr-old-4.4 {string operators} {expr {"abc" < "abd"}} 1 test expr-old-4.5 {string operators} {expr {"abd" < "abd"}} 0 test expr-old-4.6 {string operators} {expr {"abe" < "abd"}} 0 test expr-old-4.7 {string operators} {expr {"abc" >= "def"}} 0 test expr-old-4.8 {string operators} {expr {"def" >= "def"}} 1 test expr-old-4.9 {string operators} {expr {"g" >= "def"}} 1 test expr-old-4.10 {string operators} {expr {"abc" <= "abd"}} 1 test expr-old-4.11 {string operators} {expr {"abd" <= "abd"}} 1 test expr-old-4.12 {string operators} {expr {"abe" <= "abd"}} 0 test expr-old-4.13 {string operators} {expr {"abc" == "abd"}} 0 test expr-old-4.14 {string operators} {expr {"abd" == "abd"}} 1 test expr-old-4.15 {string operators} {expr {"abc" != "abd"}} 1 test expr-old-4.16 {string operators} {expr {"abd" != "abd"}} 0 test expr-old-4.17 {string operators} {expr {"0y" < "0x12"}} 0 test expr-old-4.18 {string operators} {expr {"." < " "}} 0 # The following tests are non-portable because on some systems "+" # and "-" can be parsed as numbers. test expr-old-4.19 {string operators} {expr {"0" == "+"}} 0 test expr-old-4.20 {string operators} {expr {"0" == "-"}} 0 test expr-old-4.21 {string operators} {expr {1?"foo":"bar"}} foo test expr-old-4.22 {string operators} {expr {0?"foo":"bar"}} bar # Operators that aren't legal on string operands. test expr-old-5.1 {illegal string operations} { list [catch {expr {-"a"}} msg] } {1} test expr-old-5.2 {illegal string operations} { list [catch {expr {+"a"}} msg] } {1} test expr-old-5.3 {illegal string operations} { list [catch {expr {~"a"}} msg] } {1} test expr-old-5.4 {illegal string operations} { list [catch {expr {!"a"}} msg] } {1} test expr-old-5.5 {illegal string operations} { list [catch {expr {"a"*"b"}} msg] } {1} test expr-old-5.6 {illegal string operations} { list [catch {expr {"a"/"b"}} msg] } {1} test expr-old-5.7 {illegal string operations} { list [catch {expr {"a"%"b"}} msg] } {1} test expr-old-5.8 {illegal string operations} { list [catch {expr {"a"+"b"}} msg] } {1} test expr-old-5.9 {illegal string operations} { list [catch {expr {"a"-"b"}} msg] } {1} test expr-old-5.10 {illegal string operations} { list [catch {expr {"a"<<"b"}} msg] } {1} test expr-old-5.11 {illegal string operations} { list [catch {expr {"a">>"b"}} msg] } {1} test expr-old-5.12 {illegal string operations} { list [catch {expr {"a"&"b"}} msg] } {1} test expr-old-5.13 {illegal string operations} { list [catch {expr {"a"^"b"}} msg] } {1} test expr-old-5.14 {illegal string operations} { list [catch {expr {"a"|"b"}} msg] } {1} test expr-old-5.15 {illegal string operations} { list [catch {expr {"a"&&"b"}} msg] } {1} test expr-old-5.16 {illegal string operations} { list [catch {expr {"a"||"b"}} msg] } {1} test expr-old-5.17 {illegal string operations} { list [catch {expr {"a"?4:2}} msg] } {1} # Check precedence pairwise. test expr-old-6.1 {precedence checks} {expr -~3} 4 test expr-old-6.2 {precedence checks} {expr -!3} 0 test expr-old-6.3 {precedence checks} {expr -~0} 1 test expr-old-7.1 {precedence checks} {expr 2*4/6} 1 test expr-old-7.2 {precedence checks} {expr 24/6*3} 12 test expr-old-7.3 {precedence checks} {expr 24/6/2} 2 test expr-old-8.1 {precedence checks} {expr -2+4} 2 test expr-old-8.2 {precedence checks} {expr -2-4} -6 test expr-old-8.3 {precedence checks} {expr +2-4} -2 test expr-old-9.1 {precedence checks} {expr 2*3+4} 10 test expr-old-9.2 {precedence checks} {expr 8/2+4} 8 test expr-old-9.3 {precedence checks} {expr 8%3+4} 6 test expr-old-9.4 {precedence checks} {expr 2*3-1} 5 test expr-old-9.5 {precedence checks} {expr 8/2-1} 3 test expr-old-9.6 {precedence checks} {expr 8%3-1} 1 test expr-old-10.1 {precedence checks} {expr 6-3-2} 1 test expr-old-11.1 {precedence checks} {expr 7+1>>2} 2 test expr-old-11.2 {precedence checks} {expr 7+1<<2} 32 test expr-old-11.3 {precedence checks} {expr 7>>3-2} 3 test expr-old-11.4 {precedence checks} {expr 7<<3-2} 14 test expr-old-12.1 {precedence checks} {expr 6>>1>4} 0 test expr-old-12.2 {precedence checks} {expr 6>>1<2} 0 test expr-old-12.3 {precedence checks} {expr 6>>1>=3} 1 test expr-old-12.4 {precedence checks} {expr 6>>1<=2} 0 test expr-old-12.5 {precedence checks} {expr 6<<1>5} 1 test expr-old-12.6 {precedence checks} {expr 6<<1<5} 0 test expr-old-12.7 {precedence checks} {expr 5<=6<<1} 1 test expr-old-12.8 {precedence checks} {expr 5>=6<<1} 0 test expr-old-13.1 {precedence checks} {expr 2<3<4} 1 test expr-old-13.2 {precedence checks} {expr 0<4>2} 0 test expr-old-13.3 {precedence checks} {expr 4>2<1} 0 test expr-old-13.4 {precedence checks} {expr 4>3>2} 0 test expr-old-13.5 {precedence checks} {expr 4>3>=2} 0 test expr-old-13.6 {precedence checks} {expr 4>=3>2} 0 test expr-old-13.7 {precedence checks} {expr 4>=3>=2} 0 test expr-old-13.8 {precedence checks} {expr 0<=4>=2} 0 test expr-old-13.9 {precedence checks} {expr 4>=2<=0} 0 test expr-old-13.10 {precedence checks} {expr 2<=3<=4} 1 test expr-old-14.1 {precedence checks} {expr 1==4>3} 1 test expr-old-14.2 {precedence checks} {expr 0!=4>3} 1 test expr-old-14.3 {precedence checks} {expr 1==3<4} 1 test expr-old-14.4 {precedence checks} {expr 0!=3<4} 1 test expr-old-14.5 {precedence checks} {expr 1==4>=3} 1 test expr-old-14.6 {precedence checks} {expr 0!=4>=3} 1 test expr-old-14.7 {precedence checks} {expr 1==3<=4} 1 test expr-old-14.8 {precedence checks} {expr 0!=3<=4} 1 test expr-old-15.1 {precedence checks} {expr 1==3==3} 0 test expr-old-15.2 {precedence checks} {expr 3==3!=2} 1 test expr-old-15.3 {precedence checks} {expr 2!=3==3} 0 test expr-old-15.4 {precedence checks} {expr 2!=1!=1} 0 test expr-old-16.1 {precedence checks} {expr 2&3==2} 0 test expr-old-16.2 {precedence checks} {expr 1&3!=3} 0 test expr-old-17.1 {precedence checks} {expr 7&3^0x10} 19 test expr-old-17.2 {precedence checks} {expr 7^0x10&3} 7 test expr-old-18.1 {precedence checks} {expr 7^0x10|3} 23 test expr-old-18.2 {precedence checks} {expr 7|0x10^3} 23 test expr-old-19.1 {precedence checks} {expr 7|3&&1} 1 test expr-old-19.2 {precedence checks} {expr 1&&3|7} 1 test expr-old-19.3 {precedence checks} {expr 0&&1||1} 1 test expr-old-19.4 {precedence checks} {expr 1||1&&0} 1 test expr-old-20.1 {precedence checks} {expr 1||0?3:4} 3 test expr-old-20.2 {precedence checks} {expr 1?0:4||1} 0 test expr-old-20.3 {precedence checks} {expr 1?2:0?3:4} 2 test expr-old-20.4 {precedence checks} {expr 0?2:0?3:4} 4 test expr-old-20.5 {precedence checks} {expr 1?2?3:4:0} 3 test expr-old-20.6 {precedence checks} {expr 0?2?3:4:0} 0 test expr-old-20.7 {precedence checks} {expr 0?1?1?2:3:0?4:5:1?0?6:7:0?8:9} 7 # Parentheses. test expr-old-21.1 {parenthesization} {expr (2+4)*6} 36 test expr-old-21.2 {parenthesization} {expr (1?0:4)||1} 1 test expr-old-21.3 {parenthesization} {expr +(3-4)} -1 # Embedded commands and variable names. set a 16 test expr-old-22.1 {embedded variables} {expr {2*$a}} 32 test expr-old-22.2 {embedded variables} { set x -5 set y 10 expr {$x + $y} } {5} test expr-old-22.3 {embedded variables} { set x " -5" set y " +10" expr {$x + $y} } {5} test expr-old-22.4 {embedded commands and variables} {expr {[set a] - 14}} 2 test expr-old-22.5 {embedded commands and variables} { list [catch {expr {12 - [bad_command_name]}} msg] $msg } {1 {invalid command name "bad_command_name"}} # Double-quotes and things inside them. test expr-old-23.1 {double quotes} {expr {"abc"}} abc test expr-old-23.2 {double quotes} { set a 189 expr {"$a.bc"} } 189.bc test expr-old-23.3 {double quotes} { set b2 xyx expr {"$b2$b2$b2.[set b2].[set b2]"} } xyxxyxxyx.xyx.xyx test expr-old-23.4 {double quotes} {expr {"11\}\}22"}} 11}}22 test expr-old-23.5 {double quotes} {expr {"\*bc"}} {*bc} test expr-old-23.6 {double quotes} { catch {unset bogus__} list [catch {expr {"$bogus__"}} msg] $msg } {1 {can't read "bogus__": no such variable}} test expr-old-23.7 {double quotes} { list [catch {expr {"a[error Testing]bc"}} msg] $msg } {1 Testing} test expr-old-23.8 {double quotes} { list [catch {expr {"12398712938788234-1298379" != ""}} msg] $msg } {0 1} # Numbers in various bases. test expr-old-24.1 {numbers in different bases} {expr 0x20} 32 test expr-old-24.2 {numbers in different bases} {expr 015} 15 # Conversions between various data types. test expr-old-25.1 {type conversions} {expr 2+2.5} 4.5 test expr-old-25.2 {type conversions} {expr 2.5+2} 4.5 test expr-old-25.3 {type conversions} {expr 2-2.5} -0.5 test expr-old-25.4 {type conversions} {expr 2/2.5} 0.8 test expr-old-25.5 {type conversions} {expr 2>2.5} 0 test expr-old-25.6 {type conversions} {expr 2.5>2} 1 test expr-old-25.7 {type conversions} {expr 2<2.5} 1 test expr-old-25.8 {type conversions} {expr 2>=2.5} 0 test expr-old-25.9 {type conversions} {expr 2<=2.5} 1 test expr-old-25.10 {type conversions} {expr 2==2.5} 0 test expr-old-25.11 {type conversions} {expr 2!=2.5} 1 test expr-old-25.12 {type conversions} {expr 2>"ab"} 0 test expr-old-25.13 {type conversions} {expr {2>" "}} 1 test expr-old-25.14 {type conversions} {expr {"24.1a" > 24.1}} 1 test expr-old-25.15 {type conversions} {expr {24.1 > "24.1a"}} 0 test expr-old-25.16 {type conversions} {expr 2+2.5} 4.5 test expr-old-25.17 {type conversions} {expr 2+2.5} 4.5 test expr-old-25.18 {type conversions} {expr 2.0e2} 200.0 test expr-old-25.19 {type conversions} {expr 2.0e30} 2e+30 test expr-old-25.20 {type conversions} {expr 10.0} 10.0 # Various error conditions. test expr-old-26.1 {error conditions} { list [catch {expr 2+"a"} msg] } {1} test expr-old-26.2 {error conditions} { list [catch {expr 2+4*} msg] } {1} test expr-old-26.3 {error conditions} { list [catch {expr 2+4*(} msg] } {1} catch {unset _non_existent_} test expr-old-26.4 {error conditions} { list [catch {expr 2+$_non_existent_} msg] } {1} set a xx test expr-old-26.5 {error conditions} { list [catch {expr {2+$a}} msg] } {1} test expr-old-26.6 {error conditions} { list [catch {expr {2+[set a]}} msg] } {1} test expr-old-26.7 {error conditions} { list [catch {expr {2+(4}} msg] } {1} test expr-old-26.8 {error conditions} { list [catch {expr 2/0} msg] } {1} test expr-old-26.9 {error conditions} { list [catch {expr 2%0} msg] } {1} test expr-old-26.10 {error conditions} { expr 2.0/0.0 } {Inf} test expr-old-26.11 {error conditions} { list [catch {expr 2#} msg] } {1} test expr-old-26.12 {error conditions} { list [catch {expr a.b} msg] } {1} test expr-old-26.13 {error conditions} { list [catch {expr {"a"/"b"}} msg] } {1} test expr-old-26.14 {error conditions} { list [catch {expr 2:3} msg] } {1} test expr-old-26.15 {error conditions} { list [catch {expr a@b} msg] } {1} test expr-old-26.16 {error conditions} { list [catch {expr a[b} msg] } {1} test expr-old-26.17 {error conditions} { list [catch {expr a`b} msg] } {1} test expr-old-26.18 {error conditions} { list [catch {expr \"a\"\{b} msg] } {1} test expr-old-26.19 {error conditions} { list [catch {expr a} msg] } {1} test expr-old-26.20 {error conditions} { list [catch expr msg] } {1} # Cancelled evaluation. test expr-old-27.1 {cancelled evaluation} { set a 1 expr {0&&[set a 2]} set a } 1 test expr-old-27.2 {cancelled evaluation} { set a 1 expr {1||[set a 2]} set a } 1 test expr-old-27.3 {cancelled evaluation} { set a 1 expr {0?[set a 2]:1} set a } 1 test expr-old-27.4 {cancelled evaluation} { set a 1 expr {1?2:[set a 2]} set a } 1 catch {unset x} test expr-old-27.5 {cancelled evaluation} { list [catch {expr {[info exists x] && $x}} msg] $msg } {0 0} test expr-old-27.6 {cancelled evaluation} { list [catch {expr {0 && [concat $x]}} msg] $msg } {0 0} test expr-old-27.7 {cancelled evaluation} { set one 1 list [catch {expr {1 || 1/$one}} msg] $msg } {0 1} test expr-old-27.8 {cancelled evaluation} { list [catch {expr {1 || -"string"}} msg] $msg } {0 1} test expr-old-27.9 {cancelled evaluation} { list [catch {expr {1 || ("string" * ("x" && "y"))}} msg] $msg } {0 1} test expr-old-27.10 {cancelled evaluation} { set x -1.3 list [catch {expr {($x > 0) ? round($x) : 0}} msg] $msg } {0 0} test expr-old-27.11 {cancelled evaluation} { list [catch {expr {0 && foo}} msg] } {1} test expr-old-27.12 {cancelled evaluation} { list [catch {expr {0 ? 1 : foo}} msg] } {1} # Operands enclosed in braces #test expr-old-29.1 {braces} {expr {{abc}}} abc #test expr-old-29.2 {braces} {expr {{00010}}} 8 #test expr-old-29.3 {braces} {expr {{3.1200000}}} 3.12 #test expr-old-29.4 {braces} {expr {{a{b}{1 {2 3}}c}}} "a{b}{1 {2 3}}c" #test expr-old-29.5 {braces} { # list [catch {expr "\{abc"} msg] $msg #} {1 {missing close-brace}} # Very long values test expr-old-30.1 {long values} { set a "0000 1111 2222 3333 4444" set a "$a | $a | $a | $a | $a" set a "$a || $a || $a || $a || $a" expr {$a} } {0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 || 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 || 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 || 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 || 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444 | 0000 1111 2222 3333 4444} test expr-old-30.2 {long values} { set a "000000000000000000000000000000" set a "$a$a$a$a$a$a$a$a$a$a$a$a$a$a$a$a${a}5" expr $a } 5 # Expressions spanning multiple arguments test expr-old-31.1 {multiple arguments to expr command} { expr 4 + ( 6 *12) -3 } 73 test expr-old-31.2 {multiple arguments to expr command} { list [catch {expr 2 + (3 + 4} msg] } {1} test expr-old-31.3 {multiple arguments to expr command} { list [catch {expr 2 + 3 +} msg] } {1} test expr-old-31.4 {multiple arguments to expr command} { list [catch {expr 2 + 3 )} msg] } {1} # Math functions if {0} { test expr-old-32.1 {math functions in expressions} { format %.6g [expr acos(0.5)] } {1.0472} test expr-old-32.2 {math functions in expressions} { format %.6g [expr asin(0.5)] } {0.523599} test expr-old-32.3 {math functions in expressions} { format %.6g [expr atan(1.0)] } {0.785398} test expr-old-32.4 {math functions in expressions} { format %.6g [expr atan2(2.0, 2.0)] } {0.785398} test expr-old-32.5 {math functions in expressions} { format %.6g [expr ceil(1.999)] } {2} test expr-old-32.6 {math functions in expressions} { format %.6g [expr cos(.1)] } {0.995004} test expr-old-32.7 {math functions in expressions} { format %.6g [expr cosh(.1)] } {1.005} test expr-old-32.8 {math functions in expressions} { format %.6g [expr exp(1.0)] } {2.71828} test expr-old-32.9 {math functions in expressions} { format %.6g [expr floor(2.000)] } {2} test expr-old-32.10 {math functions in expressions} { format %.6g [expr floor(2.001)] } {2} test expr-old-32.11 {math functions in expressions} { format %.6g [expr fmod(7.3, 3.2)] } {0.9} test expr-old-32.12 {math functions in expressions} { format %.6g [expr hypot(3.0, 4.0)] } {5} test expr-old-32.13 {math functions in expressions} { format %.6g [expr log(2.8)] } {1.02962} test expr-old-32.14 {math functions in expressions} { format %.6g [expr log10(2.8)] } {0.447158} test expr-old-32.15 {math functions in expressions} { format %.6g [expr pow(2.1, 3.1)] } {9.97424} test expr-old-32.16 {math functions in expressions} { format %.6g [expr sin(.1)] } {0.0998334} test expr-old-32.17 {math functions in expressions} { format %.6g [expr sinh(.1)] } {0.100167} test expr-old-32.18 {math functions in expressions} { format %.6g [expr sqrt(2.0)] } {1.41421} test expr-old-32.19 {math functions in expressions} { format %.6g [expr tan(0.8)] } {1.02964} test expr-old-32.20 {math functions in expressions} { format %.6g [expr tanh(0.8)] } {0.664037} } test expr-old-32.21 {math functions in expressions} { format %.6g [expr abs(-1.8)] } {1.8} test expr-old-32.22 {math functions in expressions} { expr abs(10.0) } {10.0} test expr-old-32.23 {math functions in expressions} { format %.6g [expr abs(-4)] } {4} test expr-old-32.24 {math functions in expressions} { format %.6g [expr abs(66)] } {66} # The following test is different for 32-bit versus 64-bit architectures. #test expr-old-32.25 {math functions in expressions} { # list [catch {expr abs(0x8000000000000000)} msg] $msg #} {1 {integer value too large to represent}} test expr-old-32.26 {math functions in expressions} { expr double(1) } {1.0} test expr-old-32.27 {math functions in expressions} { expr double(1.1) } {1.1} test expr-old-32.28 {math functions in expressions} { expr int(1) } {1} test expr-old-32.29 {math functions in expressions} { expr int(1.4) } {1} test expr-old-32.30 {math functions in expressions} { expr int(1.6) } {1} test expr-old-32.31 {math functions in expressions} { expr int(-1.4) } {-1} test expr-old-32.32 {math functions in expressions} { expr int(-1.6) } {-1} #test expr-old-32.33 {math functions in expressions} { # list [catch {expr int(1e60)} msg] $msg #} {1 {integer value too large to represent}} #test expr-old-32.34 {math functions in expressions} { # list [catch {expr int(-1e60)} msg] $msg #} {1 {integer value too large to represent}} test expr-old-32.35 {math functions in expressions} { expr round(1.49) } {1} test expr-old-32.36 {math functions in expressions} { expr round(1.51) } {2} test expr-old-32.37 {math functions in expressions} { expr round(-1.49) } {-1} test expr-old-32.38 {math functions in expressions} { expr round(-1.51) } {-2} #test expr-old-32.39 {math functions in expressions} { # list [catch {expr round(1e60)} msg] $msg #} {1 {integer value too large to represent}} #test expr-old-32.40 {math functions in expressions} { # list [catch {expr round(-1e60)} msg] $msg #} {1 {integer value too large to represent}} if {0} { test expr-old-32.41 {math functions in expressions} { list [catch {expr pow(1.0 + 3.0 - 2, .8 * 5)} msg] $msg } {0 16.0} test expr-old-32.42 {math functions in expressions} { list [catch {expr hypot(5*.8,3)} msg] $msg } {0 5.0} test expr-old-32.45 {math functions in expressions} { expr (0 <= rand()) && (rand() < 1) } {1} test expr-old-32.46 {math functions in expressions} { list [catch {expr rand(24)} msg] $msg } {1 {too many arguments for math function}} test expr-old-32.47 {math functions in expressions} { list [catch {expr srand()} msg] $msg } {1 {too few arguments for math function}} test expr-old-32.48 {math functions in expressions} { list [catch {expr srand(3.79)} msg] $msg } {1 {can't use floating-point value as argument to srand}} test expr-old-32.49 {math functions in expressions} { list [catch {expr srand("")} msg] $msg } {1 {argument to math function didn't have numeric value}} test expr-old-32.50 {math functions in expressions} { set result [expr round(srand(12345) * 1000)] for {set i 0} {$i < 10} {incr i} { lappend result [expr round(rand() * 1000)] } set result } {97 834 948 36 12 51 766 585 914 784 333} test expr-old-32.51 {math functions in expressions} { list [catch {expr {srand([lindex "6ty" 0])}} msg] $msg } {1 {argument to math function didn't have numeric value}} test expr-old-33.1 {conversions and fancy args to math functions} { expr hypot ( 3 , 4 ) } 5.0 test expr-old-33.2 {conversions and fancy args to math functions} { expr hypot ( (2.0+1.0) , 4 ) } 5.0 test expr-old-33.3 {conversions and fancy args to math functions} { expr hypot ( 3 , (3.0 + 1.0) ) } 5.0 test expr-old-33.4 {conversions and fancy args to math functions} { format %.6g [expr cos(acos(0.1))] } 0.1 test expr-old-34.1 {errors in math functions} { list [catch {expr func_2(1.0)} msg] $msg } {1 {unknown math function "func_2"}} test expr-old-34.2 {errors in math functions} { list [catch {expr func|(1.0)} msg] $msg } {1 {syntax error in expression "func|(1.0)"}} test expr-old-34.3 {errors in math functions} { list [catch {expr {hypot("a b", 2.0)}} msg] $msg } {1 {argument to math function didn't have numeric value}} test expr-old-34.4 {errors in math functions} { list [catch {expr hypot(1.0 2.0)} msg] $msg } {1 {syntax error in expression "hypot(1.0 2.0)"}} test expr-old-34.5 {errors in math functions} { list [catch {expr hypot(1.0, 2.0} msg] $msg } {1 {syntax error in expression "hypot(1.0, 2.0"}} test expr-old-34.6 {errors in math functions} { list [catch {expr hypot(1.0 ,} msg] $msg } {1 {syntax error in expression "hypot(1.0 ,"}} test expr-old-34.7 {errors in math functions} { list [catch {expr hypot(1.0)} msg] $msg } {1 {too few arguments for math function}} test expr-old-34.8 {errors in math functions} { list [catch {expr hypot(1.0, 2.0, 3.0)} msg] $msg } {1 {too many arguments for math function}} test expr-old-34.9 {errors in math functions} { list [catch {expr acos(-2.0)} msg] $msg $errorCode } {1 {domain error: argument not in valid range} {ARITH DOMAIN {domain error: argument not in valid range}}} test expr-old-34.10 {errors in math functions} { list [catch {expr pow(-3, 1000001)} msg] $msg $errorCode } {1 {floating-point value too large to represent} {ARITH OVERFLOW {floating-point value too large to represent}}} test expr-old-34.11 {errors in math functions} { list [catch {expr pow(3, 1000001)} msg] $msg $errorCode } {1 {floating-point value too large to represent} {ARITH OVERFLOW {floating-point value too large to represent}}} test expr-old-34.12 {errors in math functions} { list [catch {expr -14.0*exp(100000)} msg] $msg $errorCode } {1 {floating-point value too large to represent} {ARITH OVERFLOW {floating-point value too large to represent}}} test expr-old-34.13 {errors in math functions} { list [catch {expr int(1.0e30)} msg] $msg $errorCode } {1 {integer value too large to represent} {ARITH IOVERFLOW {integer value too large to represent}}} test expr-old-34.14 {errors in math functions} { list [catch {expr int(-1.0e30)} msg] $msg $errorCode } {1 {integer value too large to represent} {ARITH IOVERFLOW {integer value too large to represent}}} test expr-old-34.15 {errors in math functions} { list [catch {expr round(1.0e30)} msg] $msg $errorCode } {1 {integer value too large to represent} {ARITH IOVERFLOW {integer value too large to represent}}} test expr-old-34.16 {errors in math functions} { list [catch {expr round(-1.0e30)} msg] $msg $errorCode } {1 {integer value too large to represent} {ARITH IOVERFLOW {integer value too large to represent}}} test expr-old-36.1 {ExprLooksLikeInt procedure} { list [catch {expr 0289} msg] $msg } {1 {"0289" is an invalid octal number}} test expr-old-36.2 {ExprLooksLikeInt procedure} { set x 0289 list [catch {expr {$x+1}} msg] $msg } {1 {can't use invalid octal number as operand of "+"}} test expr-old-36.3 {ExprLooksLikeInt procedure} { list [catch {expr 0289.1} msg] $msg } {0 289.1} test expr-old-36.4 {ExprLooksLikeInt procedure} { set x 0289.1 list [catch {expr {$x+1}} msg] $msg } {0 290.1} test expr-old-36.5 {ExprLooksLikeInt procedure} { set x { +22} list [catch {expr {$x+1}} msg] $msg } {0 23} test expr-old-36.6 {ExprLooksLikeInt procedure} { set x { -22} list [catch {expr {$x+1}} msg] $msg } {0 -21} test expr-old-36.7 {ExprLooksLikeInt procedure} { list [catch {expr nan} msg] $msg } {1 {domain error: argument not in valid range}} test expr-old-36.8 {ExprLooksLikeInt procedure} { list [catch {expr 78e1} msg] $msg } {0 780.0} test expr-old-36.9 {ExprLooksLikeInt procedure} { list [catch {expr 24E1} msg] $msg } {0 240.0} test expr-old-36.10 {ExprLooksLikeInt procedure} { list [catch {expr 78e} msg] $msg } {1 {syntax error in expression "78e"}} } # test for [Bug #542588] # XXX: Can't rely on overflow checking #test expr-old-36.11 {ExprLooksLikeInt procedure} { # # define a "too large integer"; this one works also for 64bit arith # set x 665802003400000000000000 # list [catch {expr {$x+1}} msg] $msg #} {1 {can't use integer value too large to represent as operand of "+"}} # Special test for Pentium arithmetic bug of 1994: if {(4195835.0 - (4195835.0/3145727.0)*3145727.0) == 256.0} { puts "Warning: this machine contains a defective Pentium processor" puts "that performs arithmetic incorrectly. I recommend that you" puts "call Intel customer service immediately at 1-800-628-8686" puts "to request a replacement processor." puts [expr {(4195835.0 - (4195835.0/3145727.0)*3145727.0)}] } if {0.0 == 256.0} { puts error } testreport openocd-0.7.0/jimtcl/tests/namespace.test0000644000175000001440000003555012134336723015357 00000000000000source [file dirname [info script]]/testing.tcl needs cmd namespace test namespace-1.1 {usage for "namespace" command} -body { namespace } -returnCodes error -match glob -result {wrong # args: should be *} test namespace-1.2 {global namespace's name is "::" or {}} { list [namespace current] [namespace eval {} {namespace current}] [namespace eval :: {namespace current}] } {:: :: ::} test namespace-1.3 {usage for "namespace eval"} -body { namespace eval } -returnCodes error -match glob -result {wrong # args: should be "namespace eval *"} test namespace-1.5 {access a new namespace} { namespace eval ns1 { namespace current } } {::ns1} test namespace-1.7 {usage for "namespace eval"} -body { namespace eval ns1 } -returnCodes error -match glob -result {wrong # args: should be "namespace eval *"} test namespace-1.8 {command "namespace eval" concatenates args} { namespace eval ns1 namespace current } {::ns1} test namespace-1.9 {simple namespace elements} { namespace eval ns1 { variable v1 1 proc p1 {a} {variable v1; list $a $v1} p1 3 } } {3 1} test namespace-1.10 {commands in a namespace} { namespace eval ns1 { info commands [namespace current]::* } } {::ns1::p1} test namespace-1.11 {variables in a namespace} { namespace eval ns1 { info vars [namespace current]::* } } {::ns1::v1} test namespace-1.12 {global vars are separate from locals vars} { set v1 2 list [ns1::p1 123] [set ns1::v1] [set ::v1] } {{123 1} 1 2} test namespace-1.13 {add to an existing namespace} { namespace eval ns1 { variable v2 22 proc p2 {script} {variable v2; eval $script} p2 {return $v2} } } 22 test namespace-1.14 {commands in a namespace} { lsort [namespace eval ns1 {info commands [namespace current]::*}] } {::ns1::p1 ::ns1::p2} test namespace-1.15 {variables in a namespace} { lsort [namespace eval ns1 {info vars [namespace current]::*}] } {::ns1::v1 ::ns1::v2} # Tcl produces fully scoped names here test namespace-1.16 {variables in a namespace} jim { lsort [info vars ns1::*] } {ns1::v1 ns1::v2} test namespace-1.17 {commands in a namespace are hidden} -body { v2 {return 3} } -returnCodes error -result {invalid command name "v2"} test namespace-1.18 {using namespace qualifiers} { ns1::p2 {return 44} } 44 test namespace-1.19 {using absolute namespace qualifiers} { ::ns1::p2 {return 55} } 55 test namespace-1.20 {variables in a namespace are hidden} -body { set v2 } -returnCodes error -result {can't read "v2": no such variable} test namespace-1.21 {using namespace qualifiers} { list $ns1::v1 $ns1::v2 } {1 22} test namespace-1.22 {using absolute namespace qualifiers} { list $::ns1::v1 $::ns1::v2 } {1 22} test namespace-1.23 {variables can be accessed within a namespace} { ns1::p2 { variable v1 variable v2 list $v1 $v2 } } {1 22} test namespace-1.24 {setting global variables} { ns1::p2 { variable v1 set v1 new } namespace eval ns1 { variable v1 variable v2 list $v1 $v2 } } {new 22} test namespace-1.25 {qualified variables don't need a global declaration} { namespace eval ns2 { variable x 456 } set cmd {set ::ns2::x} ns1::p2 "$cmd some-value" set ::ns2::x } {some-value} test namespace-1.26 {namespace qualifiers are okay after $'s} { namespace eval ns1 { variable x; variable y; set x 12; set y 34 } set cmd {list $::ns1::x $::ns1::y} list [ns1::p2 $cmd] [eval $cmd] } {{12 34} {12 34}} test namespace-1.27 {can create commands with null names} { proc ns1:: {args} {return $args} ns1:: x } {x} unset -nocomplain ns1::x ns1::y # ----------------------------------------------------------------------- # TEST: using "info" in namespace contexts # ----------------------------------------------------------------------- test namespace-2.1 {querying: info commands} { lsort [ns1::p2 {info commands [namespace current]::*}] } {::ns1:: ::ns1::p1 ::ns1::p2} test namespace-2.2 {querying: info procs} { lsort [ns1::p2 {info procs}] } {{} p1 p2} # Tcl produces fully scoped names here test namespace-2.3 {querying: info vars} jim { lsort [info vars ns1::*] } {ns1::v1 ns1::v2} test namespace-2.4 {querying: info vars} { lsort [ns1::p2 {info vars [namespace current]::*}] } {::ns1::v1 ::ns1::v2} test namespace-2.5 {querying: info locals} { lsort [ns1::p2 {info locals}] } {script} test namespace-2.6 {querying: info exists} { ns1::p2 {info exists v1} } {0} test namespace-2.7 {querying: info exists} { ns1::p2 {info exists v2} } {1} test namespace-2.8 {querying: info args} { info args ns1::p2 } {script} test namespace-2.9 {querying: info body} { string trim [info body ns1::p1] } {variable v1; list $a $v1} # ----------------------------------------------------------------------- # TEST: namespace qualifiers, namespace tail # ----------------------------------------------------------------------- test namespace-3.1 {usage for "namespace qualifiers"} { list [catch "namespace qualifiers" msg] $msg } {1 {wrong # args: should be "namespace qualifiers string"}} test namespace-3.2 {querying: namespace qualifiers} { list [namespace qualifiers ""] \ [namespace qualifiers ::] \ [namespace qualifiers x] \ [namespace qualifiers ::x] \ [namespace qualifiers foo::x] \ [namespace qualifiers ::foo::bar::xyz] } {{} {} {} {} foo ::foo::bar} test namespace-3.3 {usage for "namespace tail"} { list [catch "namespace tail" msg] $msg } {1 {wrong # args: should be "namespace tail string"}} test namespace-3.4 {querying: namespace tail} { list [namespace tail ""] \ [namespace tail ::] \ [namespace tail x] \ [namespace tail ::x] \ [namespace tail foo::x] \ [namespace tail ::foo::bar::xyz] } {{} {} x x x xyz} # ----------------------------------------------------------------------- # TEST: namespace hierarchy # ----------------------------------------------------------------------- test namespace-5.1 {define nested namespaces} { set test_ns_var_global "var in ::" proc test_ns_cmd_global {} {return "cmd in ::"} namespace eval nsh1 { set test_ns_var_hier1 "particular to hier1" proc test_ns_cmd_hier1 {} {return "particular to hier1"} proc test_ns_show {} {return "[namespace current]: 1"} namespace eval nsh2 { set test_ns_var_hier2 "particular to hier2" proc test_ns_cmd_hier2 {} {return "particular to hier2"} proc test_ns_show {} {return "[namespace current]: 2"} namespace eval nsh3a {} namespace eval nsh3b {} } namespace eval nsh2a {} namespace eval nsh2b {} } } {} test namespace-5.2 {namespaces can be nested} { list [namespace eval nsh1 {namespace current}] \ [namespace eval nsh1 { namespace eval nsh2 {namespace current} }] } {::nsh1 ::nsh1::nsh2} test namespace-5.3 {namespace qualifiers work in namespace command} { list [namespace eval ::nsh1 {namespace current}] \ [namespace eval nsh1::nsh2 {namespace current}] \ [namespace eval ::nsh1::nsh2 {namespace current}] } {::nsh1 ::nsh1::nsh2 ::nsh1::nsh2} test namespace-5.4 {nested namespaces can access global namespace} { list [namespace eval nsh1 {set ::test_ns_var_global}] \ [namespace eval nsh1 {test_ns_cmd_global}] \ [namespace eval nsh1::nsh2 {set ::test_ns_var_global}] \ [namespace eval nsh1::nsh2 {test_ns_cmd_global}] } {{var in ::} {cmd in ::} {var in ::} {cmd in ::}} test namespace-5.6 {commands in different namespaces don't conflict} { list [nsh1::test_ns_show] \ [nsh1::nsh2::test_ns_show] } {{::nsh1: 1} {::nsh1::nsh2: 2}} test namespace-5.7 {nested namespaces don't see variables in parent} { set cmd { namespace eval nsh1::nsh2 {set test_ns_var_hier1} } list [catch $cmd msg] $msg } {1 {can't read "test_ns_var_hier1": no such variable}} test namespace-5.8 {nested namespaces don't see commands in parent} { set cmd { namespace eval nsh1::nsh2 {test_ns_cmd_hier1} } list [catch $cmd msg] $msg } {1 {invalid command name "test_ns_cmd_hier1"}} test namespace-5.18 {usage for "namespace parent"} { list [catch {namespace parent x y} msg] $msg } {1 {wrong # args: should be "namespace parent ?name?"}} test namespace-5.20 {querying namespace parent} { list [namespace eval :: {namespace parent}] \ [namespace eval nsh1 {namespace parent}] \ [namespace eval nsh1::nsh2 {namespace parent}] \ [namespace eval nsh1::nsh2::nsh3a {namespace parent}] \ } {{} :: ::nsh1 ::nsh1::nsh2} test namespace-5.21 {querying namespace parent for explicit namespace} { list [namespace parent ::] \ [namespace parent nsh1] \ [namespace parent nsh1::nsh2] \ [namespace parent nsh1::nsh2::nsh3a] } {{} :: ::nsh1 ::nsh1::nsh2} # ----------------------------------------------------------------------- # TEST: name resolution and caching # ----------------------------------------------------------------------- test namespace-6.1 {relative ns names only looked up in current ns} { namespace eval tns1 {} namespace eval tns2 {} namespace eval tns2::test_ns_cache3 {} set trigger { namespace eval tns2 {namespace current} } set trigger2 { namespace eval tns2::test_ns_cache3 {namespace current} } list [namespace eval tns1 $trigger] \ [namespace eval tns1 $trigger2] } {::tns1::tns2 ::tns1::tns2::test_ns_cache3} test namespace-6.2 {relative ns names only looked up in current ns} { namespace eval tns1::tns2 {} list [namespace eval tns1 $trigger] \ [namespace eval tns1 $trigger2] } {::tns1::tns2 ::tns1::tns2::test_ns_cache3} test namespace-6.3 {relative ns names only looked up in current ns} { namespace eval tns1::tns2::test_ns_cache3 {} list [namespace eval tns1 $trigger] \ [namespace eval tns1 $trigger2] } {::tns1::tns2 ::tns1::tns2::test_ns_cache3} test namespace-6.4 {relative ns names only looked up in current ns} { namespace delete tns1::tns2 list [namespace eval tns1 $trigger] \ [namespace eval tns1 $trigger2] } {::tns1::tns2 ::tns1::tns2::test_ns_cache3} test namespace-6.5 {define test commands} { proc testcmd {} { return "global version" } namespace eval tns1 { proc trigger {} { testcmd } } tns1::trigger } {global version} test namespace-6.6 {one-level check for command shadowing} { proc tns1::testcmd {} { return "cache1 version" } tns1::trigger } {cache1 version} test namespace-6.7 {renaming commands changes command epoch} { namespace eval tns1 { rename testcmd testcmd_new } tns1::trigger } {global version} test namespace-6.8 {renaming back handles shadowing} { namespace eval tns1 { rename testcmd_new testcmd } tns1::trigger } {cache1 version} test namespace-6.9 {deleting commands changes command epoch} { namespace eval tns1 { rename testcmd "" } tns1::trigger } {global version} test namespace-6.10 {define test namespaces} { namespace eval tns2 { proc testcmd {} { return "global cache2 version" } } namespace eval tns1 { proc trigger {} { tns2::testcmd } } namespace eval tns1::tns2 { proc trigger {} { testcmd } } list [tns1::trigger] [tns1::tns2::trigger] } {{global cache2 version} {global version}} test namespace-6.11 {commands affect all parent namespaces} { proc tns1::tns2::testcmd {} { return "cache2 version" } list [tns1::trigger] [tns1::tns2::trigger] } {{cache2 version} {cache2 version}} # ----------------------------------------------------------------------- # TEST: uplevel/upvar across namespace boundaries # ----------------------------------------------------------------------- # Note that Tcl behaves a little differently for uplevel and upvar test namespace-7.1 {uplevel in namespace eval} jim { set x 66 namespace eval uns1 { variable y 55 set x 33 uplevel 1 set x } } {66} test namespace-7.2 {upvar in ns proc} jim { proc uns1::getvar {v} { variable y upvar $v var list $var $y } uns1::getvar x } {66 55} # ----------------------------------------------------------------------- # TEST: scoped values # ----------------------------------------------------------------------- test namespace-10.1 {define namespace for scope test} { namespace eval ins1 { variable x "x-value" proc show {args} { return "show: $args" } proc do {args} { return [eval $args] } list [set x] [show test] } } {x-value {show: test}} test namespace-10.2 {command "namespace code" requires one argument} { list [catch {namespace code} msg] $msg } {1 {wrong # args: should be "namespace code arg"}} test namespace-10.3 {command "namespace code" requires one argument} { list [catch {namespace code first "second arg" third} msg] $msg } {1 {wrong # args: should be "namespace code arg"}} test namespace-10.4 {command "namespace code" gets current namesp context} { namespace eval ins1 { namespace code {"1 2 3" "4 5" 6} } } {::namespace inscope ::ins1 {"1 2 3" "4 5" 6}} test namespace-10.5 {with one arg, first "scope" sticks} { set sval [namespace eval ins1 {namespace code {one two}}] namespace code $sval } {::namespace inscope ::ins1 {one two}} test namespace-10.6 {with many args, each "scope" adds new args} { set sval [namespace eval ins1 {namespace code {one two}}] namespace code "$sval three" } {::namespace inscope ::ins1 {one two} three} test namespace-10.7 {scoped commands work with eval} { set cref [namespace eval ins1 {namespace code show}] list [eval $cref "a" "b c" "d e f"] } {{show: a b c d e f}} test namespace-10.8 {scoped commands execute in namespace context} { set cref [namespace eval ins1 { namespace code {variable x; set x "some new value"} }] list [set ins1::x] [eval $cref] [set ins1::x] } {x-value {some new value} {some new value}} test namespace-11.1 {command caching} { proc cmd1 {} { return global } set result {} namespace eval ns1 { proc cmd1 {} { return ns1 } proc cmd2 {} { uplevel 1 cmd1 } lappend ::result [cmd2] } lappend result [ns1::cmd2] } {ns1 global} foreach cmd [info commands test_ns_*] { rename $cmd "" } catch {rename cmd {}} catch {rename cmd1 {}} catch {rename cmd2 {}} catch {rename ncmd {}} catch {rename ncmd1 {}} catch {rename ncmd2 {}} catch {unset cref} catch {unset trigger} catch {unset trigger2} catch {unset sval} catch {unset msg} catch {unset x} catch {unset test_ns_var_global} catch {unset cmd} catch {eval namespace delete [namespace children :: test_ns_*]} # cleanup ::tcltest::cleanupTests return # Local Variables: # mode: tcl # End: openocd-0.7.0/jimtcl/tests/linsert.test0000644000175000001440000000675112134336723015104 00000000000000# Commands covered: linsert # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. source [file dirname [info script]]/testing.tcl catch {unset lis} catch {rename p ""} test linsert-1.1 {linsert command} { linsert {1 2 3 4 5} 0 a } {a 1 2 3 4 5} test linsert-1.2 {linsert command} { linsert {1 2 3 4 5} 1 a } {1 a 2 3 4 5} test linsert-1.3 {linsert command} { linsert {1 2 3 4 5} 2 a } {1 2 a 3 4 5} test linsert-1.4 {linsert command} { linsert {1 2 3 4 5} 3 a } {1 2 3 a 4 5} test linsert-1.5 {linsert command} { linsert {1 2 3 4 5} 4 a } {1 2 3 4 a 5} test linsert-1.6 {linsert command} { linsert {1 2 3 4 5} 5 a } {1 2 3 4 5 a} test linsert-1.7 {linsert command} { linsert {1 2 3 4 5} 2 one two \{three \$four } {1 2 one two \{three {$four} 3 4 5} test linsert-1.8 {linsert command} { linsert {\{one \$two \{three \ four \ five} 2 a b c } {\{one {$two} a b c \{three { four} { five}} test linsert-1.9 {linsert command} { linsert {{1 2} {3 4} {5 6} {7 8}} 2 {x y} {a b} } {{1 2} {3 4} {x y} {a b} {5 6} {7 8}} test linsert-1.10 {linsert command} { linsert {} 2 a b c } {a b c} test linsert-1.11 {linsert command} { linsert {} 2 {} } {{}} test linsert-1.12 {linsert command} { linsert {a b "c c" d e} 3 1 } {a b {c c} 1 d e} test linsert-1.13 {linsert command} { linsert { a b c d} 0 1 2 } {1 2 a b c d} test linsert-1.14 {linsert command} { linsert {a b c {d e f}} 4 1 2 } {a b c {d e f} 1 2} test linsert-1.15 {linsert command} { linsert {a b c \{\ abc} 4 q r } {a b c \{\ q r abc} test linsert-1.16 {linsert command} { linsert {a b c \{ abc} 4 q r } {a b c \{ q r abc} test linsert-1.17 {linsert command} { linsert {a b c} end q r } {a b c q r} test linsert-1.18 {linsert command} { linsert {a} end q r } {a q r} test linsert-1.19 {linsert command} { linsert {} end q r } {q r} test linsert-1.20 {linsert command, use of end-int index} { linsert {a b c d} end-2 e f } {a b e f c d} test linsert-2.1 {linsert errors} { list [catch linsert msg] $msg } {1 {wrong # args: should be "linsert list index ?element ...?"}} test linsert-2.2 {linsert errors} { list [catch {linsert a b} msg] $msg } {1 {bad index "b": must be integer?[+-]integer? or end?[+-]integer?}} test linsert-2.3 {linsert errors} { list [catch {linsert a 12x 2} msg] $msg } {1 {bad index "12x": must be integer?[+-]integer? or end?[+-]integer?}} test linsert-2.4 {linsert errors} tcl { list [catch {linsert \{ 12 2} msg] $msg } {1 {unmatched open brace in list}} test linsert-2.5 {syntax (TIP 323)} { linsert {a b c} 0 } [list a b c] test linsert-2.6 {syntax (TIP 323)} { linsert "a\nb\nc" 0 } [list a b c] test linsert-3.1 {linsert won't modify shared argument objects} { proc p {} { linsert "a b c" 1 "x y" return "a b c" } p } "a b c" test linsert-3.2 {linsert won't modify shared argument objects} { catch {unset lis} set lis [format "a \"%s\" c" "b"] linsert $lis 0 [string length $lis] } "7 a b c" # cleanup catch {unset lis} catch {rename p ""} ::tcltest::cleanupTests return openocd-0.7.0/jimtcl/tests/binary-scan.test0000644000175000001440000011354212134336723015627 00000000000000# This file tests the tclBinary.c file and the "binary" Tcl command. # # This file contains a collection of tests for one or more of the Tcl built-in # commands. Sourcing this file into Tcl runs the tests and generates output # for errors. No output means no errors were found. # # Copyright (c) 1997 by Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution of # this file, and for a DISCLAIMER OF ALL WARRANTIES. # # RCS: @(#) $Id: binary.test,v 1.38 2008/12/15 17:11:34 ferrieux Exp $ source [file dirname [info script]]/testing.tcl needs cmd binary testConstraint bigEndian [expr {$tcl_platform(byteOrder) eq "bigEndian"}] testConstraint littleEndian [expr {$tcl_platform(byteOrder) eq "littleEndian"}] test binary-19.1 {Tcl_BinaryObjCmd: errors} -returnCodes error -body { binary s } -match glob -result {*} test binary-19.2 {Tcl_BinaryObjCmd: errors} -returnCodes error -body { binary scan foo } -result {wrong # args: should be "binary scan value formatString ?varName ...?"} test binary-19.3 {Tcl_BinaryObjCmd: scan} { binary scan {} {} } 0 test binary-20.1 {Tcl_BinaryObjCmd: scan} -returnCodes error -body { binary scan abc a } -result {not enough arguments for all format specifiers} test binary-20.2 {Tcl_BinaryObjCmd: scan} -setup { unset -nocomplain arg1 } -returnCodes error -body { set arg1 1 binary scan abc a arg1(a) } -result {can't set "arg1(a)": variable isn't array} test binary-20.3 {Tcl_BinaryObjCmd: scan} -setup { unset -nocomplain arg1 } -body { set arg1 abc list [binary scan abc a0 arg1] $arg1 } -result {1 {}} test binary-20.4 {Tcl_BinaryObjCmd: scan} -setup { unset -nocomplain arg1 } -body { list [binary scan abc a* arg1] $arg1 } -result {1 abc} test binary-20.5 {Tcl_BinaryObjCmd: scan} -setup { unset -nocomplain arg1 } -body { list [binary scan abc a5 arg1] [info exists arg1] } -result {0 0} test binary-20.6 {Tcl_BinaryObjCmd: scan} { set arg1 foo list [binary scan abc a2 arg1] $arg1 } {1 ab} test binary-20.7 {Tcl_BinaryObjCmd: scan} -setup { unset -nocomplain arg1 unset -nocomplain arg2 } -body { list [binary scan abcdef a2a2 arg1 arg2] $arg1 $arg2 } -result {2 ab cd} test binary-20.8 {Tcl_BinaryObjCmd: scan} -setup { unset -nocomplain arg1 } -body { list [binary scan abc a2 arg1(a)] $arg1(a) } -result {1 ab} test binary-20.9 {Tcl_BinaryObjCmd: scan} -setup { unset -nocomplain arg1 } -body { list [binary scan abc a arg1(a)] $arg1(a) } -result {1 a} # As soon as a conversion runs out of bytes, scan should stop test binary-20.10 {Tcl_BinaryObjCmd: scan, too few bytes} -setup { unset -nocomplain arg1 arg2 } -body { list [binary scan abc a5a2 arg1 arg2] [info exists arg1] [info exists arg2] } -result {0 0 0} test binary-21.1 {Tcl_BinaryObjCmd: scan} -returnCodes error -body { binary scan abc A } -result {not enough arguments for all format specifiers} test binary-21.2 {Tcl_BinaryObjCmd: scan} -setup { unset -nocomplain arg1 } -returnCodes error -body { set arg1 1 binary scan abc A arg1(a) } -result {can't set "arg1(a)": variable isn't array} test binary-21.3 {Tcl_BinaryObjCmd: scan} -setup { unset -nocomplain arg1 } -body { set arg1 abc list [binary scan abc A0 arg1] $arg1 } -result {1 {}} test binary-21.4 {Tcl_BinaryObjCmd: scan} -setup { unset -nocomplain arg1 } -body { list [binary scan abc A* arg1] $arg1 } -result {1 abc} test binary-21.5 {Tcl_BinaryObjCmd: scan} -setup { unset -nocomplain arg1 } -body { list [binary scan abc A5 arg1] [info exists arg1] } -result {0 0} test binary-21.6 {Tcl_BinaryObjCmd: scan} { set arg1 foo list [binary scan abc A2 arg1] $arg1 } {1 ab} test binary-21.7 {Tcl_BinaryObjCmd: scan} -setup { unset -nocomplain arg1 unset -nocomplain arg2 } -body { list [binary scan abcdef A2A2 arg1 arg2] $arg1 $arg2 } -result {2 ab cd} test binary-21.8 {Tcl_BinaryObjCmd: scan} -setup { unset -nocomplain arg1 } -body { list [binary scan abc A2 arg1(a)] $arg1(a) } -result {1 ab} test binary-21.9 {Tcl_BinaryObjCmd: scan} -setup { unset -nocomplain arg1 } -body { list [binary scan abc A2 arg1(a)] $arg1(a) } -result {1 ab} test binary-21.10 {Tcl_BinaryObjCmd: scan} -setup { unset -nocomplain arg1 } -body { list [binary scan abc A arg1(a)] $arg1(a) } -result {1 a} test binary-21.11 {Tcl_BinaryObjCmd: scan} -setup { unset -nocomplain arg1 } -body { list [binary scan "abc def \x00 " A* arg1] $arg1 } -result {1 {abc def}} test binary-21.12 {Tcl_BinaryObjCmd: scan} -setup { unset -nocomplain arg1 } -body { list [binary scan "abc def \x00ghi " A* arg1] $arg1 } -result [list 1 "abc def \x00ghi"] test binary-22.1 {Tcl_BinaryObjCmd: scan} -returnCodes error -body { binary scan abc b } -result {not enough arguments for all format specifiers} test binary-22.2 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\x53 b* arg1] $arg1 } {1 0100101011001010} test binary-22.3 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x82\x53 b arg1] $arg1 } {1 0} test binary-22.4 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x82\x53 b1 arg1] $arg1 } {1 0} test binary-22.5 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x82\x53 b0 arg1] $arg1 } {1 {}} test binary-22.6 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\x53 b5 arg1] $arg1 } {1 01001} test binary-22.7 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\x53 b8 arg1] $arg1 } {1 01001010} test binary-22.8 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\x53 b14 arg1] $arg1 } {1 01001010110010} test binary-22.9 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 set arg1 foo list [binary scan \x52 b14 arg1] $arg1 } {0 foo} test binary-22.10 {Tcl_BinaryObjCmd: scan} -setup { unset -nocomplain arg1 } -returnCodes error -body { set arg1 1 binary scan \x52\x53 b1 arg1(a) } -result {can't set "arg1(a)": variable isn't array} test binary-22.11 {Tcl_BinaryObjCmd: scan} -setup { unset -nocomplain arg1 arg2 } -body { set arg1 foo set arg2 bar list [binary scan \x07\x87\x05 b5b* arg1 arg2] $arg1 $arg2 } -result {2 11100 1110000110100000} # As soon as a conversion runs out of bytes, scan should stop test binary-20.12 {Tcl_BinaryObjCmd: scan, too few bytes} { unset -nocomplain arg1 arg2 set arg1 foo set arg2 bar list [binary scan \x52 b14b8 arg1 arg2] $arg1 $arg2 } {0 foo bar} test binary-23.1 {Tcl_BinaryObjCmd: scan} -returnCodes error -body { binary scan abc B } -result {not enough arguments for all format specifiers} test binary-23.2 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\x53 B* arg1] $arg1 } {1 0101001001010011} test binary-23.3 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x82\x53 B arg1] $arg1 } {1 1} test binary-23.4 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x82\x53 B1 arg1] $arg1 } {1 1} test binary-23.5 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\x53 B0 arg1] $arg1 } {1 {}} test binary-23.6 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\x53 B5 arg1] $arg1 } {1 01010} test binary-23.7 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\x53 B8 arg1] $arg1 } {1 01010010} test binary-23.8 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\x53 B14 arg1] $arg1 } {1 01010010010100} test binary-23.9 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 set arg1 foo list [binary scan \x52 B14 arg1] $arg1 } {0 foo} test binary-23.10 {Tcl_BinaryObjCmd: scan} -setup { unset -nocomplain arg1 } -returnCodes error -body { set arg1 1 binary scan \x52\x53 B1 arg1(a) } -result {can't set "arg1(a)": variable isn't array} test binary-23.11 {Tcl_BinaryObjCmd: scan} -setup { unset -nocomplain arg1 arg2 } -body { set arg1 foo set arg2 bar list [binary scan \x70\x87\x05 B5B* arg1 arg2] $arg1 $arg2 } -result {2 01110 1000011100000101} test binary-24.1 {Tcl_BinaryObjCmd: scan} -returnCodes error -body { binary scan abc h } -result {not enough arguments for all format specifiers} test binary-24.2 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\xa3 h* arg1] $arg1 } {1 253a} test binary-24.3 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \xc2\xa3 h arg1] $arg1 } {1 2} test binary-24.4 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x82\x53 h1 arg1] $arg1 } {1 2} test binary-24.5 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\x53 h0 arg1] $arg1 } {1 {}} test binary-24.6 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \xf2\x53 h2 arg1] $arg1 } {1 2f} test binary-24.7 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\x53 h3 arg1] $arg1 } {1 253} test binary-24.8 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 set arg1 foo list [binary scan \x52 h3 arg1] $arg1 } {0 foo} test binary-24.9 {Tcl_BinaryObjCmd: scan} -setup { unset -nocomplain arg1 } -returnCodes error -body { set arg1 1 binary scan \x52\x53 h1 arg1(a) } -result {can't set "arg1(a)": variable isn't array} test binary-24.10 {Tcl_BinaryObjCmd: scan} -setup { unset -nocomplain arg1 arg2 } -body { set arg1 foo set arg2 bar list [binary scan \x70\x87\x05 h2h* arg1 arg2] $arg1 $arg2 } -result {2 07 7850} test binary-25.1 {Tcl_BinaryObjCmd: scan} -returnCodes error -body { binary scan abc H } -result {not enough arguments for all format specifiers} test binary-25.2 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\xa3 H* arg1] $arg1 } {1 52a3} test binary-25.3 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \xc2\xa3 H arg1] $arg1 } {1 c} test binary-25.4 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x82\x53 H1 arg1] $arg1 } {1 8} test binary-25.5 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\x53 H0 arg1] $arg1 } {1 {}} test binary-25.6 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \xf2\x53 H2 arg1] $arg1 } {1 f2} test binary-25.7 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\x53 H3 arg1] $arg1 } {1 525} test binary-25.8 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 set arg1 foo list [binary scan \x52 H3 arg1] $arg1 } {0 foo} test binary-25.9 {Tcl_BinaryObjCmd: scan} -setup { unset -nocomplain arg1 } -returnCodes error -body { set arg1 1 binary scan \x52\x53 H1 arg1(a) } -result {can't set "arg1(a)": variable isn't array} test binary-25.10 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 arg2 set arg1 foo set arg2 bar list [binary scan \x70\x87\x05 H2H* arg1 arg2] $arg1 $arg2 } {2 70 8705} test binary-26.1 {Tcl_BinaryObjCmd: scan} -returnCodes error -body { binary scan abc c } -result {not enough arguments for all format specifiers} test binary-26.2 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\xa3 c* arg1] $arg1 } {1 {82 -93}} test binary-26.3 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\xa3 c arg1] $arg1 } {1 82} test binary-26.4 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\xa3 c1 arg1] $arg1 } {1 82} test binary-26.5 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\xa3 c0 arg1] $arg1 } {1 {}} test binary-26.6 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\xa3 c2 arg1] $arg1 } {1 {82 -93}} test binary-26.7 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \xff c arg1] $arg1 } {1 -1} test binary-26.8 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 set arg1 foo list [binary scan \x52 c3 arg1] $arg1 } {0 foo} test binary-26.9 {Tcl_BinaryObjCmd: scan} -setup { unset -nocomplain arg1 } -returnCodes error -body { set arg1 1 binary scan \x52\x53 c1 arg1(a) } -result {can't set "arg1(a)": variable isn't array} test binary-26.10 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 arg2 set arg1 foo set arg2 bar list [binary scan \x70\x87\x05 c2c* arg1 arg2] $arg1 $arg2 } {2 {112 -121} 5} test binary-26.11 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\xa3 cu* arg1] $arg1 } {1 {82 163}} test binary-26.12 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\xa3 cu arg1] $arg1 } {1 82} test binary-26.13 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \xff cu arg1] $arg1 } {1 255} test binary-26.14 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 arg2 set arg1 foo set arg2 bar list [binary scan \x80\x80 cuc arg1 arg2] $arg1 $arg2 } {2 128 -128} test binary-26.15 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 arg2 set arg1 foo set arg2 bar list [binary scan \x80\x80 ccu arg1 arg2] $arg1 $arg2 } {2 -128 128} test binary-27.1 {Tcl_BinaryObjCmd: scan} -returnCodes error -body { binary scan abc s } -result {not enough arguments for all format specifiers} test binary-27.2 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\xa3\x53\x54 s* arg1] $arg1 } {1 {-23726 21587}} test binary-27.3 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\xa3\x53\x54 s arg1] $arg1 } {1 -23726} test binary-27.4 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\xa3 s1 arg1] $arg1 } {1 -23726} test binary-27.5 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\xa3 s0 arg1] $arg1 } {1 {}} test binary-27.6 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\xa3\x53\x54 s2 arg1] $arg1 } {1 {-23726 21587}} test binary-27.7 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 set arg1 foo list [binary scan \x52 s1 arg1] $arg1 } {0 foo} test binary-27.8 {Tcl_BinaryObjCmd: scan} -setup { unset -nocomplain arg1 } -returnCodes error -body { set arg1 1 binary scan \x52\x53 s1 arg1(a) } -result {can't set "arg1(a)": variable isn't array} test binary-27.9 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 arg2 set arg1 foo set arg2 bar list [binary scan \x52\xa3\x53\x54\x05 s2c* arg1 arg2] $arg1 $arg2 } {2 {-23726 21587} 5} test binary-27.10 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\xa3\x53\x54 su* arg1] $arg1 } {1 {41810 21587}} test binary-27.11 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 arg2 set arg1 foo set arg2 bar list [binary scan \xff\xff\xff\xff sus arg1 arg2] $arg1 $arg2 } {2 65535 -1} test binary-27.12 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 arg2 set arg1 foo set arg2 bar list [binary scan \xff\xff\xff\xff ssu arg1 arg2] $arg1 $arg2 } {2 -1 65535} test binary-28.1 {Tcl_BinaryObjCmd: scan} -returnCodes error -body { binary scan abc S } -result {not enough arguments for all format specifiers} test binary-28.2 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\xa3\x53\x54 S* arg1] $arg1 } {1 {21155 21332}} test binary-28.3 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\xa3\x53\x54 S arg1] $arg1 } {1 21155} test binary-28.4 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\xa3 S1 arg1] $arg1 } {1 21155} test binary-28.5 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\xa3 S0 arg1] $arg1 } {1 {}} test binary-28.6 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\xa3\x53\x54 S2 arg1] $arg1 } {1 {21155 21332}} test binary-28.7 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 set arg1 foo list [binary scan \x52 S1 arg1] $arg1 } {0 foo} test binary-28.8 {Tcl_BinaryObjCmd: scan} -setup { unset -nocomplain arg1 } -returnCodes error -body { set arg1 1 binary scan \x52\x53 S1 arg1(a) } -result {can't set "arg1(a)": variable isn't array} test binary-28.9 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 arg2 set arg1 foo set arg2 bar list [binary scan \x52\xa3\x53\x54\x05 S2c* arg1 arg2] $arg1 $arg2 } {2 {21155 21332} 5} test binary-28.10 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\xa3\x53\x54 Su* arg1] $arg1 } {1 {21155 21332}} test binary-28.11 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \xa3\x52\x54\x53 Su* arg1] $arg1 } {1 {41810 21587}} test binary-29.1 {Tcl_BinaryObjCmd: scan} -returnCodes error -body { binary scan abc i } -result {not enough arguments for all format specifiers} test binary-29.2 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\xa3\x53\x54\x01\x02\x03\x04 i* arg1] $arg1 } {1 {1414767442 67305985}} test binary-29.3 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\xa3\x53\x54\x01\x02\x03\x04 i arg1] $arg1 } {1 1414767442} test binary-29.4 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\xa3\x53\x54 i1 arg1] $arg1 } {1 1414767442} test binary-29.5 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\xa3\x53 i0 arg1] $arg1 } {1 {}} test binary-29.6 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\xa3\x53\x54\x01\x02\x03\x04 i2 arg1] $arg1 } {1 {1414767442 67305985}} test binary-29.7 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 set arg1 foo list [binary scan \x52 i1 arg1] $arg1 } {0 foo} test binary-29.8 {Tcl_BinaryObjCmd: scan} -setup { unset -nocomplain arg1 } -returnCodes error -body { set arg1 1 binary scan \x52\x53\x53\x54 i1 arg1(a) } -result {can't set "arg1(a)": variable isn't array} test binary-29.9 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 arg2 set arg1 foo set arg2 bar list [binary scan \x52\xa3\x53\x54\x01\x02\x03\x04\x05 i2c* arg1 arg2] $arg1 $arg2 } {2 {1414767442 67305985} 5} test binary-29.10 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 arg2 list [binary scan \xff\xff\xff\xff\xff\xff\xff\xff iui arg1 arg2] $arg1 $arg2 } {2 4294967295 -1} test binary-29.11 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 arg2 list [binary scan \xff\xff\xff\xff\xff\xff\xff\xff iiu arg1 arg2] $arg1 $arg2 } {2 -1 4294967295} test binary-29.12 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 arg2 list [binary scan \x80\x00\x00\x00\x00\x00\x00\x80 iuiu arg1 arg2] $arg1 $arg2 } {2 128 2147483648} test binary-30.1 {Tcl_BinaryObjCmd: scan} -returnCodes error -body { binary scan abc I } -result {not enough arguments for all format specifiers} test binary-30.2 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\xa3\x53\x54\x01\x02\x03\x04 I* arg1] $arg1 } {1 {1386435412 16909060}} test binary-30.3 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\xa3\x53\x54\x01\x02\x03\x04 I arg1] $arg1 } {1 1386435412} test binary-30.4 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\xa3\x53\x54 I1 arg1] $arg1 } {1 1386435412} test binary-30.5 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\xa3\x53 I0 arg1] $arg1 } {1 {}} test binary-30.6 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan \x52\xa3\x53\x54\x01\x02\x03\x04 I2 arg1] $arg1 } {1 {1386435412 16909060}} test binary-30.7 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 set arg1 foo list [binary scan \x52 I1 arg1] $arg1 } {0 foo} test binary-30.8 {Tcl_BinaryObjCmd: scan} -setup { unset -nocomplain arg1 } -returnCodes error -body { set arg1 1 binary scan \x52\x53\x53\x54 I1 arg1(a) } -result {can't set "arg1(a)": variable isn't array} test binary-30.9 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 arg2 set arg1 foo set arg2 bar list [binary scan \x52\xa3\x53\x54\x01\x02\x03\x04\x05 I2c* arg1 arg2] $arg1 $arg2 } {2 {1386435412 16909060} 5} test binary-30.10 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 arg2 list [binary scan \xff\xff\xff\xff\xff\xff\xff\xff IuI arg1 arg2] $arg1 $arg2 } {2 4294967295 -1} test binary-30.11 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 arg2 list [binary scan \xff\xff\xff\xff\xff\xff\xff\xff IIu arg1 arg2] $arg1 $arg2 } {2 -1 4294967295} test binary-30.12 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 arg2 list [binary scan \x80\x00\x00\x00\x00\x00\x00\x80 IuIu arg1 arg2] $arg1 $arg2 } {2 2147483648 128} test binary-33.1 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 unset -nocomplain arg2 list [binary scan abcdefg a2xa3 arg1 arg2] $arg1 $arg2 } {2 ab def} test binary-33.2 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 unset -nocomplain arg2 set arg2 foo list [binary scan abcdefg a3x*a3 arg1 arg2] $arg1 $arg2 } {1 abc foo} test binary-33.3 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 unset -nocomplain arg2 set arg2 foo list [binary scan abcdefg a3x20a3 arg1 arg2] $arg1 $arg2 } {1 abc foo} test binary-33.4 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 unset -nocomplain arg2 set arg2 foo list [binary scan abc a3x20a3 arg1 arg2] $arg1 $arg2 } {1 abc foo} test binary-33.5 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan abcdef x1a1 arg1] $arg1 } {1 b} test binary-33.6 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan abcdef x5a1 arg1] $arg1 } {1 f} test binary-33.7 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan abcdef x0a1 arg1] $arg1 } {1 a} test binary-34.1 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 unset -nocomplain arg2 list [binary scan abcdefg a2Xa3 arg1 arg2] $arg1 $arg2 } {2 ab bcd} test binary-34.2 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 unset -nocomplain arg2 set arg2 foo list [binary scan abcdefg a3X*a3 arg1 arg2] $arg1 $arg2 } {2 abc abc} test binary-34.3 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 unset -nocomplain arg2 set arg2 foo list [binary scan abcdefg a3X20a3 arg1 arg2] $arg1 $arg2 } {2 abc abc} test binary-34.4 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan abc X20a3 arg1] $arg1 } {1 abc} test binary-34.5 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan abcdef x*X1a1 arg1] $arg1 } {1 f} test binary-34.6 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan abcdef x*X5a1 arg1] $arg1 } {1 b} test binary-34.7 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan abcdef x3X0a1 arg1] $arg1 } {1 d} test binary-35.1 {Tcl_BinaryObjCmd: scan} -setup { unset -nocomplain arg1 unset -nocomplain arg2 } -returnCodes error -body { binary scan abcdefg a2@a3 arg1 arg2 } -result {missing count for "@" field specifier} test binary-35.2 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 unset -nocomplain arg2 set arg2 foo list [binary scan abcdefg a3@*a3 arg1 arg2] $arg1 $arg2 } {1 abc foo} test binary-35.3 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 unset -nocomplain arg2 set arg2 foo list [binary scan abcdefg a3@20a3 arg1 arg2] $arg1 $arg2 } {1 abc foo} test binary-35.4 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan abcdef @2a3 arg1] $arg1 } {1 cde} test binary-35.5 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan abcdef x*@1a1 arg1] $arg1 } {1 b} test binary-35.6 {Tcl_BinaryObjCmd: scan} { unset -nocomplain arg1 list [binary scan abcdef x*@0a1 arg1] $arg1 } {1 a} test binary-36.1 {Tcl_BinaryObjCmd: scan} -returnCodes error -body { binary scan abcdef u0a3 } -result {bad field specifier "u"} # Jim doesn't bother to throw errors on extra chars in the format spec test binary-37.7 {GetFormatSpec: numbers} -returnCodes error -constraints tcl -body { binary scan abcdef "x-1" foo } -result {bad field specifier "-"} test binary-37.8 {GetFormatSpec: numbers} { unset -nocomplain arg1 set arg1 foo list [binary scan abcdef "a0x3" arg1] $arg1 } {1 {}} test binary-39.1 {ScanNumber: sign extension} { unset -nocomplain arg1 list [binary scan \x52\xa3 c2 arg1] $arg1 } {1 {82 -93}} test binary-39.2 {ScanNumber: sign extension} { unset -nocomplain arg1 list [binary scan \x01\x02\x01\x81\x82\x01\x81\x82 s4 arg1] $arg1 } {1 {513 -32511 386 -32127}} test binary-39.3 {ScanNumber: sign extension} { unset -nocomplain arg1 list [binary scan \x01\x02\x01\x81\x82\x01\x81\x82 S4 arg1] $arg1 } {1 {258 385 -32255 -32382}} test binary-39.4 {ScanNumber: sign extension} { unset -nocomplain arg1 list [binary scan \x01\x01\x01\x02\x81\x01\x01\x01\x01\x82\x01\x01\x01\x01\x82\x01\x01\x01\x01\x81 i5 arg1] $arg1 } {1 {33620225 16843137 16876033 25297153 -2130640639}} test binary-39.5 {ScanNumber: sign extension} { unset -nocomplain arg1 list [binary scan \x01\x01\x01\x02\x81\x01\x01\x01\x01\x82\x01\x01\x01\x01\x82\x01\x01\x01\x01\x81 I5 arg1] $arg1 } {1 {16843010 -2130640639 25297153 16876033 16843137}} test binary-39.6 {ScanNumber: no sign extension} { unset -nocomplain arg1 list [binary scan \x52\xa3 cu2 arg1] $arg1 } {1 {82 163}} test binary-39.7 {ScanNumber: no sign extension} { unset -nocomplain arg1 list [binary scan \x01\x02\x01\x81\x82\x01\x81\x82 su4 arg1] $arg1 } {1 {513 33025 386 33409}} test binary-39.8 {ScanNumber: no sign extension} { unset -nocomplain arg1 list [binary scan \x01\x02\x01\x81\x82\x01\x81\x82 Su4 arg1] $arg1 } {1 {258 385 33281 33154}} test binary-39.9 {ScanNumber: no sign extension} { unset -nocomplain arg1 list [binary scan \x01\x01\x01\x02\x81\x01\x01\x01\x01\x82\x01\x01\x01\x01\x82\x01\x01\x01\x01\x81 iu5 arg1] $arg1 } {1 {33620225 16843137 16876033 25297153 2164326657}} test binary-39.10 {ScanNumber: no sign extension} { unset -nocomplain arg1 list [binary scan \x01\x01\x01\x02\x81\x01\x01\x01\x01\x82\x01\x01\x01\x01\x82\x01\x01\x01\x01\x81 Iu5 arg1] $arg1 } {1 {16843010 2164326657 25297153 16876033 16843137}} test binary-41.1 {ScanNumber: word alignment} { unset -nocomplain arg1; unset arg2 list [binary scan \x01\x01\x00 c1s1 arg1 arg2] $arg1 $arg2 } {2 1 1} test binary-41.2 {ScanNumber: word alignment} { unset -nocomplain arg1; unset arg2 list [binary scan \x01\x00\x01 c1S1 arg1 arg2] $arg1 $arg2 } {2 1 1} test binary-41.3 {ScanNumber: word alignment} { unset -nocomplain arg1; unset arg2 list [binary scan \x01\x01\x00\x00\x00 c1i1 arg1 arg2] $arg1 $arg2 } {2 1 1} test binary-41.4 {ScanNumber: word alignment} { unset -nocomplain arg1; unset arg2 list [binary scan \x01\x00\x00\x00\x01 c1I1 arg1 arg2] $arg1 $arg2 } {2 1 1} test binary-42.1 {Tcl_BinaryObjCmd: bad arguments} -constraints {} -body { binary ? } -returnCodes error -match glob -result {*} test binary-44.1 {Tcl_BinaryObjCmd: scan wide int} {} { binary scan HelloTcl W x set x } 5216694956358656876 test binary-44.2 {Tcl_BinaryObjCmd: scan wide int} {} { binary scan lcTolleH w x set x } 5216694956358656876 test binary-44.3 {Tcl_BinaryObjCmd: scan wide int with bit 31 set} {} { binary scan [binary format w [expr {3 << 31}]] w x set x } 6442450944 test binary-44.4 {Tcl_BinaryObjCmd: scan wide int with bit 31 set} {} { binary scan [binary format W [expr {3 << 31}]] W x set x } 6442450944 test binary-43.5 {Tcl_BinaryObjCmd: scan wide int} {} { unset -nocomplain arg1 list [binary scan \x80[string repeat \x00 7] W arg1] $arg1 } {1 -9223372036854775808} # Note that Jim doesn't have unsigned 64 bit ints test binary-43.6 {Tcl_BinaryObjCmd: scan unsigned wide int} {tcl} { unset -nocomplain arg1 list [binary scan \x80[string repeat \x00 7] Wu arg1] $arg1 } {1 9223372036854775808} test binary-43.7 {Tcl_BinaryObjCmd: scan unsigned wide int} {tcl} { unset -nocomplain arg1 list [binary scan [string repeat \x00 7]\x80 wu arg1] $arg1 } {1 9223372036854775808} test binary-43.8 {Tcl_BinaryObjCmd: scan unsigned wide int} {tcl} { unset -nocomplain arg1 arg2 list [binary scan \x80[string repeat \x00 7]\x80[string repeat \x00 7] WuW arg1 arg2] $arg1 $arg2 } {2 9223372036854775808 -9223372036854775808} test binary-43.9 {Tcl_BinaryObjCmd: scan unsigned wide int} {tcl} { unset -nocomplain arg1 arg2 list [binary scan [string repeat \x00 7]\x80[string repeat \x00 7]\x80 wuw arg1 arg2] $arg1 $arg2 } {2 9223372036854775808 -9223372036854775808} test binary-45.1 {Tcl_BinaryObjCmd: combined wide int handling} { binary scan [binary format sws 16450 -1 19521] c* x set x } {66 64 -1 -1 -1 -1 -1 -1 -1 -1 65 76} test binary-45.2 {Tcl_BinaryObjCmd: combined wide int handling} { binary scan [binary format sWs 16450 0x7fffffff 19521] c* x set x } {66 64 0 0 0 0 127 -1 -1 -1 65 76} test binary-47.1 {Tcl_BinaryObjCmd: number cache reference count handling} { # This test is only reliable when memory debugging is turned on, but # without even memory debugging it should still generate the expected # answers and might therefore still pick up memory corruption caused by # [Bug 851747]. list [binary scan aba ccc x x x] $x } {3 97} test binary-50.3 {Tcl_BinaryObjCmd: scan wide int with bit 31 set} littleEndian { binary scan [binary format m [expr {3 << 31}]] w x set x } 6442450944 test binary-50.4 {Tcl_BinaryObjCmd: scan wide int with bit 31 set} bigEndian { binary scan [binary format m [expr {3 << 31}]] W x set x } 6442450944 # scan t (s) test binary-54.1 {Tcl_BinaryObjCmd: scan} -returnCodes error -body { binary scan abc t } -result {not enough arguments for all format specifiers} test binary-54.2 {Tcl_BinaryObjCmd: scan} littleEndian { unset -nocomplain arg1 list [binary scan \x52\xa3\x53\x54 t* arg1] $arg1 } {1 {-23726 21587}} test binary-54.3 {Tcl_BinaryObjCmd: scan} littleEndian { unset -nocomplain arg1 list [binary scan \x52\xa3\x53\x54 t arg1] $arg1 } {1 -23726} test binary-54.4 {Tcl_BinaryObjCmd: scan} littleEndian { unset -nocomplain arg1 list [binary scan \x52\xa3 t1 arg1] $arg1 } {1 -23726} test binary-54.5 {Tcl_BinaryObjCmd: scan} littleEndian { unset -nocomplain arg1 list [binary scan \x52\xa3 t0 arg1] $arg1 } {1 {}} test binary-54.6 {Tcl_BinaryObjCmd: scan} littleEndian { unset -nocomplain arg1 list [binary scan \x52\xa3\x53\x54 t2 arg1] $arg1 } {1 {-23726 21587}} test binary-54.7 {Tcl_BinaryObjCmd: scan} littleEndian { unset -nocomplain arg1 set arg1 foo list [binary scan \x52 t1 arg1] $arg1 } {0 foo} test binary-54.8 {Tcl_BinaryObjCmd: scan} -setup { unset -nocomplain arg1 } -returnCodes error -body { set arg1 1 binary scan \x52\x53 t1 arg1(a) } -result {can't set "arg1(a)": variable isn't array} test binary-54.9 {Tcl_BinaryObjCmd: scan} littleEndian { unset -nocomplain arg1 arg2 set arg1 foo set arg2 bar list [binary scan \x52\xa3\x53\x54\x05 t2c* arg1 arg2] $arg1 $arg2 } {2 {-23726 21587} 5} test binary-54.10 {Tcl_BinaryObjCmd: scan} littleEndian { unset -nocomplain arg1 arg2 set arg1 foo set arg2 bar list [binary scan \x00\x80\x00\x80 tut arg1 arg2] $arg1 $arg2 } {2 32768 -32768} test binary-54.11 {Tcl_BinaryObjCmd: scan} littleEndian { unset -nocomplain arg1 arg2 set arg1 foo set arg2 bar list [binary scan \x00\x80\x00\x80 ttu arg1 arg2] $arg1 $arg2 } {2 -32768 32768} # scan t (b) test binary-55.1 {Tcl_BinaryObjCmd: scan} -returnCodes error -body { binary scan abc t } -result {not enough arguments for all format specifiers} test binary-55.2 {Tcl_BinaryObjCmd: scan} bigEndian { unset -nocomplain arg1 list [binary scan \x52\xa3\x53\x54 t* arg1] $arg1 } {1 {21155 21332}} test binary-55.3 {Tcl_BinaryObjCmd: scan} bigEndian { unset -nocomplain arg1 list [binary scan \x52\xa3\x53\x54 t arg1] $arg1 } {1 21155} test binary-55.4 {Tcl_BinaryObjCmd: scan} bigEndian { unset -nocomplain arg1 list [binary scan \x52\xa3 t1 arg1] $arg1 } {1 21155} test binary-55.5 {Tcl_BinaryObjCmd: scan} bigEndian { unset -nocomplain arg1 list [binary scan \x52\xa3 t0 arg1] $arg1 } {1 {}} test binary-55.6 {Tcl_BinaryObjCmd: scan} bigEndian { unset -nocomplain arg1 list [binary scan \x52\xa3\x53\x54 t2 arg1] $arg1 } {1 {21155 21332}} test binary-55.7 {Tcl_BinaryObjCmd: scan} bigEndian { unset -nocomplain arg1 set arg1 foo list [binary scan \x52 t1 arg1] $arg1 } {0 foo} test binary-55.8 {Tcl_BinaryObjCmd: scan} -setup { unset -nocomplain arg1 } -returnCodes error -body { set arg1 1 binary scan \x52\x53 t1 arg1(a) } -result {can't set "arg1(a)": variable isn't array} test binary-55.9 {Tcl_BinaryObjCmd: scan} bigEndian { unset -nocomplain arg1 arg2 set arg1 foo set arg2 bar list [binary scan \x52\xa3\x53\x54\x05 t2c* arg1 arg2] $arg1 $arg2 } {2 {21155 21332} 5} test binary-55.10 {Tcl_BinaryObjCmd: scan} bigEndian { unset -nocomplain arg1 arg2 set arg1 foo set arg2 bar list [binary scan \x80\x00\x80\x00 tut arg1 arg2] $arg1 $arg2 } {2 32768 -32768} test binary-55.11 {Tcl_BinaryObjCmd: scan} bigEndian { unset -nocomplain arg1 arg2 set arg1 foo set arg2 bar list [binary scan \x80\x00\x80\x00 ttu arg1 arg2] $arg1 $arg2 } {2 -32768 32768} # scan n (s) test binary-56.1 {Tcl_BinaryObjCmd: scan} -returnCodes error -body { binary scan abc n } -result {not enough arguments for all format specifiers} test binary-56.2 {Tcl_BinaryObjCmd: scan} littleEndian { unset -nocomplain arg1 list [binary scan \x52\xa3\x53\x54\x01\x02\x03\x04 n* arg1] $arg1 } {1 {1414767442 67305985}} test binary-56.3 {Tcl_BinaryObjCmd: scan} littleEndian { unset -nocomplain arg1 list [binary scan \x52\xa3\x53\x54\x01\x02\x03\x04 n arg1] $arg1 } {1 1414767442} test binary-56.4 {Tcl_BinaryObjCmd: scan} littleEndian { unset -nocomplain arg1 list [binary scan \x52\xa3\x53\x54 n1 arg1] $arg1 } {1 1414767442} test binary-56.5 {Tcl_BinaryObjCmd: scan} littleEndian { unset -nocomplain arg1 list [binary scan \x52\xa3\x53 n0 arg1] $arg1 } {1 {}} test binary-56.6 {Tcl_BinaryObjCmd: scan} littleEndian { unset -nocomplain arg1 list [binary scan \x52\xa3\x53\x54\x01\x02\x03\x04 n2 arg1] $arg1 } {1 {1414767442 67305985}} test binary-56.7 {Tcl_BinaryObjCmd: scan} littleEndian { unset -nocomplain arg1 set arg1 foo list [binary scan \x52 n1 arg1] $arg1 } {0 foo} test binary-56.8 {Tcl_BinaryObjCmd: scan} -setup { unset -nocomplain arg1 } -returnCodes error -body { set arg1 1 binary scan \x52\x53\x53\x54 n1 arg1(a) } -result {can't set "arg1(a)": variable isn't array} test binary-56.9 {Tcl_BinaryObjCmd: scan} littleEndian { unset -nocomplain arg1 arg2 set arg1 foo set arg2 bar list [binary scan \x52\xa3\x53\x54\x01\x02\x03\x04\x05 n2c* arg1 arg2] $arg1 $arg2 } {2 {1414767442 67305985} 5} test binary-56.10 {Tcl_BinaryObjCmd: scan} littleEndian { unset -nocomplain arg1 arg2 set arg1 foo set arg2 bar list [binary scan \x80\x00\x00\x00\x80\x00\x00\x00 nun arg1 arg2] $arg1 $arg2 } {2 128 128} test binary-56.11 {Tcl_BinaryObjCmd: scan} littleEndian { unset -nocomplain arg1 arg2 set arg1 foo set arg2 bar list [binary scan \x00\x00\x00\x80\x00\x00\x00\x80 nun arg1 arg2] $arg1 $arg2 } {2 2147483648 -2147483648} # scan n (b) test binary-57.1 {Tcl_BinaryObjCmd: scan} -returnCodes error -body { binary scan abc n } -result {not enough arguments for all format specifiers} test binary-57.2 {Tcl_BinaryObjCmd: scan} bigEndian { unset -nocomplain arg1 list [binary scan \x52\xa3\x53\x54\x01\x02\x03\x04 n* arg1] $arg1 } {1 {1386435412 16909060}} test binary-57.3 {Tcl_BinaryObjCmd: scan} bigEndian { unset -nocomplain arg1 list [binary scan \x52\xa3\x53\x54\x01\x02\x03\x04 n arg1] $arg1 } {1 1386435412} test binary-57.4 {Tcl_BinaryObjCmd: scan} bigEndian { unset -nocomplain arg1 list [binary scan \x52\xa3\x53\x54 n1 arg1] $arg1 } {1 1386435412} test binary-57.5 {Tcl_BinaryObjCmd: scan} bigEndian { unset -nocomplain arg1 list [binary scan \x52\xa3\x53 n0 arg1] $arg1 } {1 {}} test binary-57.6 {Tcl_BinaryObjCmd: scan} bigEndian { unset -nocomplain arg1 list [binary scan \x52\xa3\x53\x54\x01\x02\x03\x04 n2 arg1] $arg1 } {1 {1386435412 16909060}} test binary-57.7 {Tcl_BinaryObjCmd: scan} bigEndian { unset -nocomplain arg1 set arg1 foo list [binary scan \x52 n1 arg1] $arg1 } {0 foo} test binary-57.8 {Tcl_BinaryObjCmd: scan} -setup { unset -nocomplain arg1 } -returnCodes error -body { set arg1 1 binary scan \x52\x53\x53\x54 n1 arg1(a) } -result {can't set "arg1(a)": variable isn't array} test binary-57.9 {Tcl_BinaryObjCmd: scan} bigEndian { unset -nocomplain arg1 arg2 set arg1 foo set arg2 bar list [binary scan \x52\xa3\x53\x54\x01\x02\x03\x04\x05 n2c* arg1 arg2] $arg1 $arg2 } {2 {1386435412 16909060} 5} test binary-57.10 {Tcl_BinaryObjCmd: scan} bigEndian { unset -nocomplain arg1 arg2 set arg1 foo set arg2 bar list [binary scan \x80\x00\x00\x00\x80\x00\x00\x00 nun arg1 arg2] $arg1 $arg2 } {2 2147483648 -2147483648} test binary-57.11 {Tcl_BinaryObjCmd: scan} bigEndian { unset -nocomplain arg1 arg2 set arg1 foo set arg2 bar list [binary scan \x00\x00\x00\x80\x00\x00\x00\x80 nun arg1 arg2] $arg1 $arg2 } {2 128 128} # scan m test binary-61.1 {Tcl_BinaryObjCmd: scan wide int} bigEndian { binary scan HelloTcl m x set x } 5216694956358656876 test binary-61.2 {Tcl_BinaryObjCmd: scan wide int} littleEndian { binary scan lcTolleH m x set x } 5216694956358656876 test binary-61.3 {Tcl_BinaryObjCmd: scan wide int with bit 31 set} littleEndian { binary scan [binary format w [expr {3 << 31}]] m x set x } 6442450944 test binary-61.4 {Tcl_BinaryObjCmd: scan wide int with bit 31 set} bigEndian { binary scan [binary format W [expr {3 << 31}]] m x set x } 6442450944 testreport openocd-0.7.0/jimtcl/tests/testio.in0000644000175000001440000000002012134336723014341 00000000000000One line here ^openocd-0.7.0/jimtcl/tests/case.test0000644000175000001440000000252412134336723014331 00000000000000source [file dirname [info script]]/testing.tcl needs cmd case {tclcompat} catch {unset result} test case-1.1 "Simple case" { foreach c {abc xyz def sdfbc basdf a aba} { case $c in { b* { lappend result 1 } {ab a} { lappend result 2 } {def *bc} { lappend result 3 } default { lappend result 4 } } } set result } {3 4 3 3 1 2 4} # case is a proc, but it should be able # to cause a return in do_case proc do_case {var} { case $var in { 0 { return } 1 { return one } 2 { return -code ok two } 3 { return -code continue three } 4 { return -code break four } 5 { continue } 6 { break } } return zero } test case-2.0 "Plain from case" { do_case 0 } {} test case-2.1 "Return from case with value" { do_case 1 } {one} test case-2.2 "Return -code ok from case" { do_case 2 list [catch {do_case 2} msg] $msg } {0 two} test case-2.3 "Return -code continue from case" { list [catch {do_case 3} msg] $msg } {4 three} test case-2.4 "Return -code break from case" { list [catch {do_case 4} msg] $msg } {3 four} if {0} { test case-2.5 "continue from case" { list [catch {do_case 5} msg] $msg } {1 {invoked "continue" outside of a loop}} test case-2.6 "break from case" { list [catch {do_case 6} msg] $msg } {1 {invoked "break" outside of a loop}} } testreport openocd-0.7.0/jimtcl/tests/errors.tcl0000644000175000001440000000162512134336723014536 00000000000000# Package which can generate a variety of errors at known locations proc error_generator {type} { switch $type { badcmd { bogus command called } badvar { set bogus } error { error bogus } interpbadvar { set x "some $bogus text" } interpbadcmd { set x "some $bogus text" } package { package require dummy } source { source dummy.tcl } badpackage { package require bogus } returncode { return -code error failure } default { puts "Unknown type=$type" } } } # line 40: Some empty lines above so that line numbers don't change proc error_caller {type {method call}} { switch $method { call { error_generator $type } uplevel { uplevel 1 [list error_generator $type] } eval { eval [list error_generator $type] } evalstr { eval error_generator $type } default { puts "Unknown method=$method" } } } openocd-0.7.0/jimtcl/tests/testing.tcl0000644000175000001440000001177012134336723014701 00000000000000# Common code set testinfo(verbose) 0 set testinfo(numpass) 0 set testinfo(numfail) 0 set testinfo(numskip) 0 set testinfo(numtests) 0 set testinfo(failed) {} set testdir [file dirname [info script]] set bindir [file dirname [info nameofexecutable]] if {[lsearch $argv "-verbose"] >= 0 || [info exists env(testverbose)]} { incr testinfo(verbose) } proc needs {type what {packages {}}} { if {$type eq "constraint"} { if {![info exists ::tcltest::testConstraints($what)]} { set ::tcltest::testConstraints($what) 0 } if {![set ::tcltest::testConstraints($what)]} { skiptest " (constraint $what)" } return } if {$type eq "cmd"} { # Does it exist already? if {[info commands $what] ne ""} { return } if {$packages eq ""} { # e.g. exec command is in exec package set packages $what } foreach p $packages { catch {package require $p} } if {[info commands $what] ne ""} { return } skiptest " (command $what)" } error "Unknown needs type: $type" } proc skiptest {{msg {}}} { puts [format "%16s: --- skipped$msg" $::argv0] exit 0 } # If tcl, just use tcltest if {[catch {info version}]} { package require Tcl 8.5 package require tcltest 2.1 namespace import tcltest::* if {$testinfo(verbose)} { configure -verbose bps } testConstraint utf8 1 testConstraint tcl 1 proc testreport {} { ::tcltest::cleanupTests } return } lappend auto_path $testdir $bindir [file dirname [pwd]] # For Jim, this is reasonable compatible tcltest proc makeFile {contents name} { set f [open $name w] puts $f $contents close $f return $name } proc removeFile {name} { file delete $name } proc script_source {script} { lassign [info source $script] f l if {$f ne ""} { puts "At : $f:$l" return \t$f:$l } } proc error_source {} { lassign [info stacktrace] p f l if {$f ne ""} { puts "At : $f:$l" return \t$f:$l } } proc package-or-skip {name} { if {[catch { package require $name }]} { puts [format "%16s: --- skipped" $::argv0] exit 0 } } proc testConstraint {constraint bool} { set ::tcltest::testConstraints($constraint) $bool } testConstraint {utf8} [expr {[string length "\xc2\xb5"] == 1}] testConstraint {references} [expr {[info commands ref] ne ""}] testConstraint {jim} 1 testConstraint {tcl} 0 proc bytestring {x} { return $x } # Note: We don't support -output or -errorOutput yet proc test {id descr args} { set a [dict create -returnCodes {ok return} -match exact -result {} -constraints {} -body {} -setup {} -cleanup {}] if {[lindex $args 0] ni [dict keys $a]} { if {[llength $args] == 2} { lassign $args body result constraints } elseif {[llength $args] == 3} { lassign $args constraints body result } else { return -code error "$id: Wrong syntax for tcltest::test v1" } tailcall test $id $descr -body $body -result $result -constraints $constraints } # tcltest::test v2 syntax array set a $args incr ::testinfo(numtests) if {$::testinfo(verbose)} { puts -nonewline "$id " } foreach c $a(-constraints) { if {[info exists ::tcltest::testConstraints($c)]} { if {$::tcltest::testConstraints($c)} { continue } incr ::testinfo(numskip) if {$::testinfo(verbose)} { puts "SKIP" } return } } catch {uplevel 1 $a(-setup)} set rc [catch {uplevel 1 $a(-body)} result opts] catch {uplevel 1 $a(-cleanup)} if {[info return $rc] ni $a(-returnCodes) && $rc ni $a(-returnCodes)} { set ok 0 set expected "rc=$a(-returnCodes) result=$a(-result)" set result "rc=[info return $rc] result=$result" } else { if {$a(-match) eq "exact"} { set ok [string equal $a(-result) $result] } elseif {$a(-match) eq "glob"} { set ok [string match $a(-result) $result] } elseif {$a(-match) eq "regexp"} { set ok [regexp $a(-result) $result] } else { return -code error "$id: unknown match type: $a(-match)" } set expected $a(-result) } if {$ok} { if {$::testinfo(verbose)} { puts "OK $descr" } incr ::testinfo(numpass) return } if {!$::testinfo(verbose)} { puts -nonewline "$id " } puts "ERR $descr" if {$rc in {0 2}} { set source [script_source $a(-body)] } else { set source [error_source] } puts "Expected: '$expected'" puts "Got : '$result'" puts "" incr ::testinfo(numfail) lappend ::testinfo(failed) [list $id $descr $source $expected $result] } proc ::tcltest::cleanupTests {} { tailcall testreport } proc testreport {} { if {$::testinfo(verbose)} { puts -nonewline "\n$::argv0" } else { puts -nonewline [format "%16s" $::argv0] } puts [format ": Total %5d Passed %5d Skipped %5d Failed %5d" \ $::testinfo(numtests) $::testinfo(numpass) $::testinfo(numskip) $::testinfo(numfail)] if {$::testinfo(numfail)} { puts [string repeat - 60] puts "FAILED: $::testinfo(numfail)" foreach failed $::testinfo(failed) { foreach {id descr source expected result} $failed {} puts "$source\t$id" } puts [string repeat - 60] } if {$::testinfo(numfail)} { exit 1 } } proc testerror {} { error "deliberate error" } if {$testinfo(verbose)} { puts "==== $argv0 ====" } openocd-0.7.0/jimtcl/tests/subst.test0000644000175000001440000001160012134336723014551 00000000000000# Commands covered: subst # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1994 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # Copyright (c) 1998-2000 Ajuba Solutions. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # RCS: @(#) $Id: subst.test,v 1.6.2.1 2001/04/03 22:54:38 hobbs Exp $ source [file dirname [info script]]/testing.tcl test subst-1.0 {basics} { subst {\$x} } "\$x" test subst-1.1 {basics} { list [catch {subst} msg] } {1} test subst-1.2 {basics} { list [catch {subst a b c} msg] } {1} test subst-2.1 {simple strings} { subst {} } {} test subst-2.2 {simple strings} { subst a } a test subst-2.3 {simple strings} { subst abcdefg } abcdefg test subst-3.1 {backslash substitutions} { subst {\x\$x\[foo bar]\\} } "x\$x\[foo bar]\\" test subst-4.1 {variable substitutions} { set a 44 subst {$a} } {44} test subst-4.2 {variable substitutions} { set a 44 subst {x$a.y{$a}.z} } {x44.y{44}.z} test subst-4.3 {variable substitutions} { catch {unset a} set a(13) 82 set i 13 subst {x.$a($i)} } {x.82} catch {unset a} set long {This is a very long string, intentionally made so long that it will overflow the static character size for dstrings, so that additional memory will have to be allocated by subst. That way, if the subst procedure forgets to free up memory while returning an error, there will be memory that isn't freed (this will be detected when the tests are run under a checking memory allocator such as Purify).} test subst-4.4 {variable substitutions} { list [catch {subst {$long $a}} msg] $msg } {1 {can't read "a": no such variable}} test subst-5.1 {command substitutions} { subst {[concat {}]} } {} test subst-5.2 {command substitutions} { subst {[concat A test string]} } {A test string} test subst-5.3 {command substitutions} { subst {x.[concat foo].y.[concat bar].z} } {x.foo.y.bar.z} test subst-5.4 {command substitutions} { list [catch {subst {$long [set long] [bogus_command]}} msg] $msg } {1 {invalid command name "bogus_command"}} test subst-6.1 {clear the result after command substitution} { catch {unset a} list [catch {subst {[concat foo] $a}} msg] $msg } {1 {can't read "a": no such variable}} test subst-7.1 {switches} { list [catch {subst foo bar} msg] } {1} test subst-7.2 {switches} { list [catch {subst -no bar} msg] } {1} test subst-7.3 {switches} { list [catch {subst -bogus bar} msg] } {1} test subst-7.4 {switches} { set x 123 subst -nobackslashes {abc $x [expr 1+2] \\\x41} } {abc 123 3 \\\x41} test subst-7.5 {switches} { set x 123 subst -nocommands {abc $x [expr 1+2] \\\x41} } {abc 123 [expr 1+2] \A} test subst-7.6 {switches} { set x 123 subst -novariables {abc $x [expr 1+2] \\\x41} } {abc $x 3 \A} test subst-7.7 {switches} { set x 123 subst -nov -nob -noc {abc $x [expr 1+2] \\\x41} } {abc $x [expr 1+2] \\\x41} test subst-8.1 {return in a subst} { subst {foo [return {x}; bogus code] bar} } {foo x bar} test subst-8.2 {return in a subst} { subst {foo [return x ; bogus code] bar} } {foo x bar} test subst-8.3 {return in a subst} { subst {foo [if 1 { return {x}; bogus code }] bar} } {foo x bar} test subst-8.4 {return in a subst} { subst {[eval {return hi}] there} } {hi there} test subst-8.5 {return in a subst} { subst {foo [return {]}; bogus code] bar} } {foo ] bar} test subst-9.1 {error in a subst} { list [catch {subst {[error foo; bogus code]bar}} msg] $msg } {1 foo} test subst-9.2 {error in a subst} { list [catch {subst {[if 1 { error foo; bogus code}]bar}} msg] $msg } {1 foo} test subst-10.1 {break in a subst} { subst {foo [break; bogus code] bar} } {foo } test subst-10.2 {break in a subst} { subst {foo [break; return x; bogus code] bar} } {foo } test subst-10.3 {break in a subst} { subst {foo [if 1 { break; bogus code}] bar} } {foo } test subst-10.4 {break in a subst, parse error} { subst {foo [break ; set a {}{} ; stuff] bar} } {foo } test subst-10.5 {break in a subst, parse error} { subst {foo [break ;set bar baz ;set a {}{} ; stuff] bar} } {foo } test subst-11.1 {continue in a subst} { subst {foo [continue; bogus code] bar} } {foo bar} test subst-11.2 {continue in a subst} { subst {foo [continue; return x; bogus code] bar} } {foo bar} test subst-11.3 {continue in a subst} { subst {foo [if 1 { continue; bogus code}] bar} } {foo bar} test subst-12.1 {lone $} { subst {$} } {$} test subst-12.2 {lone $} { set a 1 subst -novar {${a}} } {${a}} test subst-12.3 {variable inside [] with -noc} { set a 1 subst -noc {x[join $a]y} } {x[join 1]y} # cleanup testreport openocd-0.7.0/jimtcl/tests/expr-new.test0000644000175000001440000007231012134336723015163 00000000000000# Commands covered: expr # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1996-1997 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # RCS: @(#) $Id: expr.test,v 1.9 2000/04/10 17:18:59 ericm Exp $ source [file dirname [info script]]/testing.tcl # procedures used below proc put_hello_char {c} { global a append a [format %c $c] return $c } proc hello_world {} { global a set a "" set L1 [set l0 [set h_1 [set q 0]]] for {put_hello_char [expr [put_hello_char [expr [set h 7]*10+2]]+29]} {$l0?[put_hello_char $l0] :!$h_1} {put_hello_char $ll;expr {$L1==2?[set ll [expr 32+0-0+[set bar 0]]]:0}} {expr {[incr L1]==[expr 1+([string length "abc"]-[string length "abc"])] ?[set ll [set l0 [expr 54<<1]]]:$ll==108&&$L1<3? [incr ll [expr 1|1<<1]; set ll $ll; set ll $ll; set ll $ll; set ll $ll; set l0 [expr ([string length "abc"]-[string length "abc"])+([string length "abc"]-[string length "abc"])-([string length "abc"]-[string length "abc"])+([string length "abc"]-[string length "abc"])]; set l0; set l0 $l0; set l0; set l0]:$L1==4&&$ll==32?[set ll [expr 19+$h1+([string length "abc"]-[string length "abc"])-([string length "abc"]-[string length "abc"])+([string length "abc"]-[string length "abc"])-([string length "abc"]-[string length "abc"])+[set foo [expr ([string length "abc"]-[string length "abc"])+([string length "abc"]-[string length "abc"])+([string length "abc"]-[string length "abc"])]]]] :[set q [expr $q-$h1+([string length "abc"]-[string length "abc"])-([string length "abc"]-[string length "abc"])]]};expr {$L1==5?[incr ll -8; set ll $ll; set ll]:$q&&$h1&&1};expr {$L1==4+2 ?[incr ll 3]:[expr ([string length "abc"]-[string length "abc"])+1]};expr {$ll==($h<<4)+2+0&&$L1!=6?[incr ll -6]:[set h1 [expr 100+([string length "abc"]-[string length "abc"])-([string length "abc"]-[string length "abc"])]]} expr {$L1!=1<<3?[incr q [expr ([string length "abc"]-[string length "abc"])-1]]:[set h_1 [set ll $h1]]} } set a } proc 12days {a b c} { global xxx expr {1<$a?[expr {$a<3?[12days -79 -13 [string range $c [12days -87 \ [expr 1-$b] [string range $c [12days -86 0 [string range $c 1 end]] \ end]] end]]:1};expr {$a<$b?[12days [expr $a+1] $b $c]:3};expr {[12days \ -94 [expr $a-27] $c]&&$a==2?$b<13?[12days 2 [expr $b+1] "%s %d %d\n"]:9 :16}]:$a<0?$a<-72?[12days $b $a "@n'+,#'/*\{\}w+/w#cdnr/+,\{\}r/*de\}+,/*\{*+,/w\{%+,/w#q#n+,/#\{l+,/n\{n+,/+#n+,/#;#q#n+,/+k#;*+,/'r :'d*'3,\}\{w+K w'K:'+\}e#';dq#'l q#'+d'K#!/+k#;q#'r\}eKK#\}w'r\}eKK\{nl\]'/#;#q#n')\{)#\}w')\{)\{nl\]'/+#n';d\}rw' i;# )\{nl\]!/n\{n#'; r\{#w'r nc\{nl\]'/#\{l,+'K \{rw' iK\{;\[\{nl\]'/w#q#n'wk nw' iwk\{KK\{nl\]!/w\{%'l##w#' i; :\{nl\]'/*\{q#'ld;r'\}\{nlwb!/*de\}'c ;;\{nl'-\{\}rw\]'/+,\}##'*\}#nc,',#nw\]'/+kd'+e\}+;#'rdq#w! nr'/ ') \}+\}\{rl#'\{n' ')# \}'+\}##(!!/"] :$a<-50?[string compare [format %c $b] [string index $c 0]]==0?[append \ xxx [string index $c 31];scan [string index $c 31] %c x;set x] :[12days -65 $b [string range $c 1 end]]:[12days [expr ([string compare \ [string index $c 0] "/"]==0)+$a] $b [string range $c 1 end]]:0<$a ?[12days 2 2 "%s"]:[string compare [string index $c 0] "/"]==0|| [12days 0 [12days -61 [scan [string index $c 0] %c x; set x] \ "!ek;dc i@bK'(q)-\[w\]*%n+r3#l,\{\}:\nuwloca-O;m .vpbks,fxntdCeghiry"] \ [string range $c 1 end]]} } proc do_twelve_days {} { global xxx set xxx "" 12days 1 1 1 string length $xxx } # start of tests catch {unset a b i x} test expr-1.1 {TclCompileExprCmd: no expression} { list [catch {expr } msg] } {1} test expr-1.2 {TclCompileExprCmd: one expression word} { expr -25 } -25 test expr-1.3 {TclCompileExprCmd: two expression words} { expr -8.2 -6 } -14.2 test expr-1.4 {TclCompileExprCmd: five expression words} { expr 20 - 5 +10 -7 } 18 test expr-1.5 {TclCompileExprCmd: quoted expression word} { expr "0005" } 5 test expr-1.6 {TclCompileExprCmd: quoted expression word} { catch {expr "0005"zxy} msg } {1} test expr-1.7 {TclCompileExprCmd: expression word in braces} { expr {-0005} } -5 # XXX: I believe that this ought to return a string, thus -0x1234 #test expr-1.8 {TclCompileExprCmd: expression word in braces} { # expr {{-0x1234}} #} -4660 test expr-1.9 {TclCompileExprCmd: expression word in braces} { catch {expr {-0005}foo} msg } {1} test expr-1.10 {TclCompileExprCmd: other expression word in braces} { expr 4*[llength "6 2"] } 8 test expr-1.11 {TclCompileExprCmd: expression word terminated by ;} { expr 4*[llength "6 2"]; } 8 test expr-1.12 {TclCompileExprCmd: inlined expr (in "catch") inside other catch} { set a xxx catch { # Might not be a number set a [expr 10*$a] } } 1 test expr-1.13 {TclCompileExprCmd: second level of substitutions in expr not in braces with single var reference} { set a xxx set x 27; set bool {$x}; if $bool {set a foo} set a } foo test expr-1.14 {TclCompileExprCmd: second level of substitutions in expr with comparison as top-level operator} { set a xxx set x 2; set b {$x}; set a [expr $b == 2] set a } 1 test expr-2.1 {TclCompileExpr: are builtin functions registered?} { expr double(5*[llength "6 2"]) } 10.0 test expr-2.2 {TclCompileExpr: error in expr} { catch {expr 2//3} msg } {1} test expr-2.3 {TclCompileExpr: junk after legal expr} { catch {expr 7*[llength "a b"]foo} msg } {1} test expr-2.4 {TclCompileExpr: numeric expr string rep == formatted int rep} { expr {0001} } 1 test expr-3.1 {CompileCondExpr: just lor expr} {expr 3||0} 1 test expr-3.2 {CompileCondExpr: error in lor expr} { catch {expr x||3} msg } {1} test expr-3.3 {CompileCondExpr: test true arm} {expr 3>2?44:66} 44 test expr-3.4 {CompileCondExpr: error compiling true arm} { catch {expr 3>2?2//3:66} msg } {1} test expr-3.5 {CompileCondExpr: test false arm} {expr 2>3?44:66} 66 test expr-3.6 {CompileCondExpr: error compiling false arm} { catch {expr 2>3?44:2//3} msg } {1} if {0} { test expr-3.7 {CompileCondExpr: long arms & nested cond exprs} { puts "Note: doing test expr-3.7 which can take several minutes to run" hello_world } {Hello world} catch {unset xxx} test expr-3.8 {CompileCondExpr: long arms & nested cond exprs} { puts "Note: doing test expr-3.8 which can take several minutes to run" do_twelve_days } 2358 catch {unset xxx} } test expr-4.1 {CompileLorExpr: just land expr} {expr 1.3&&3.3} 1 test expr-4.2 {CompileLorExpr: error in land expr} { catch {expr x&&3} msg } {1} test expr-4.3 {CompileLorExpr: simple lor exprs} {expr 0||1.0} 1 test expr-4.4 {CompileLorExpr: simple lor exprs} {expr 3.0||0.0} 1 test expr-4.5 {CompileLorExpr: simple lor exprs} {expr 0||0||1} 1 test expr-4.6 {CompileLorExpr: error compiling lor arm} { catch {expr 2//3||4.0} msg } {1} test expr-4.7 {CompileLorExpr: error compiling lor arm} { catch {expr 1.3||2//3} msg } {1} test expr-4.8 {CompileLorExpr: error compiling lor arms} { list [catch {expr {"a"||"b"}} msg] } {1} test expr-4.9 {CompileLorExpr: long lor arm} { set a "abcdefghijkl" set i 7 expr {[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]] || [string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]] || [string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]] || [string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]&&[string compare [format %c $i] [string index $a $i]]} } 1 test expr-5.1 {CompileLandExpr: just bitor expr} {expr 7|0x13} 23 test expr-5.2 {CompileLandExpr: error in bitor expr} { catch {expr x|3} msg } {1} test expr-5.3 {CompileLandExpr: simple land exprs} {expr 0&&1.0} 0 test expr-5.4 {CompileLandExpr: simple land exprs} {expr 0&&0} 0 test expr-5.5 {CompileLandExpr: simple land exprs} {expr 3.0&&1.2} 1 test expr-5.6 {CompileLandExpr: simple land exprs} {expr 1&&1&&2} 1 test expr-5.7 {CompileLandExpr: error compiling land arm} { catch {expr 2//3&&4.0} msg } {1} test expr-5.8 {CompileLandExpr: error compiling land arm} { catch {expr 1.3&&2//3} msg } {1} test expr-5.9 {CompileLandExpr: error compiling land arm} { list [catch {expr {"a"&&"b"}} msg] } {1} test expr-5.10 {CompileLandExpr: long land arms} { set a "abcdefghijkl" set i 7 expr {[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]] && [string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]] && [string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]] && [string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]^[string compare [format %c 103] [string index $a $i]]^[string compare [format %c 105] [string index $a $i]]} } 1 test expr-6.1 {CompileBitXorExpr: just bitand expr} {expr 7&0x13} 3 test expr-6.2 {CompileBitXorExpr: error in bitand expr} { catch {expr x|3} msg } {1} test expr-6.3 {CompileBitXorExpr: simple bitxor exprs} {expr 7^0x13} 20 test expr-6.4 {CompileBitXorExpr: simple bitxor exprs} {expr 3^0x10} 19 test expr-6.5 {CompileBitXorExpr: simple bitxor exprs} {expr 0^7} 7 test expr-6.6 {CompileBitXorExpr: simple bitxor exprs} {expr -1^7} -8 test expr-6.7 {CompileBitXorExpr: error compiling bitxor arm} { catch {expr 2//3|6} msg } {1} test expr-6.8 {CompileBitXorExpr: error compiling bitxor arm} { catch {expr 2^x} msg } {1} test expr-6.9 {CompileBitXorExpr: runtime error in bitxor arm} { list [catch {expr {24.0^3}} msg] } {1} test expr-6.10 {CompileBitXorExpr: runtime error in bitxor arm} { list [catch {expr {"a"^"b"}} msg] } {1} test expr-7.1 {CompileBitAndExpr: just equality expr} {expr 3==2} 0 test expr-7.2 {CompileBitAndExpr: just equality expr} {expr 2.0==2} 1 test expr-7.3 {CompileBitAndExpr: just equality expr} {expr 3.2!=2.2} 1 test expr-7.4 {CompileBitAndExpr: just equality expr} {expr {"abc" == "abd"}} 0 test expr-7.5 {CompileBitAndExpr: error in equality expr} { catch {expr x==3} msg } {1} test expr-7.6 {CompileBitAndExpr: simple bitand exprs} {expr 7&0x13} 3 test expr-7.7 {CompileBitAndExpr: simple bitand exprs} {expr 0xf2&0x53} 82 test expr-7.8 {CompileBitAndExpr: simple bitand exprs} {expr 3&6} 2 test expr-7.9 {CompileBitAndExpr: simple bitand exprs} {expr -1&-7} -7 test expr-7.10 {CompileBitAndExpr: error compiling bitand arm} { catch {expr 2//3&6} msg } {1} test expr-7.11 {CompileBitAndExpr: error compiling bitand arm} { catch {expr 2&x} msg } {1} test expr-7.12 {CompileBitAndExpr: runtime error in bitand arm} { list [catch {expr {24.0&3}} msg] } {1} test expr-7.13 {CompileBitAndExpr: runtime error in bitand arm} { list [catch {expr {"a"&"b"}} msg] } {1} test expr-8.1 {CompileEqualityExpr: just relational expr} {expr 3>=2} 1 test expr-8.2 {CompileEqualityExpr: just relational expr} {expr 2<=2.1} 1 test expr-8.3 {CompileEqualityExpr: just relational expr} {expr 3.2>"2.2"} 1 test expr-8.4 {CompileEqualityExpr: just relational expr} {expr {"0y"<"0x12"}} 0 test expr-8.5 {CompileEqualityExpr: error in relational expr} { catch {expr x>3} msg } {1} test expr-8.6 {CompileEqualityExpr: simple equality exprs} {expr 7==0x13} 0 test expr-8.7 {CompileEqualityExpr: simple equality exprs} {expr -0xf2!=0x53} 1 test expr-8.8 {CompileEqualityExpr: simple equality exprs} {expr {"12398712938788234-1298379" != ""}} 1 test expr-8.9 {CompileEqualityExpr: simple equality exprs} {expr -1!="abc"} 1 test expr-8.10 {CompileEqualityExpr: error compiling equality arm} { catch {expr 2//3==6} msg } {1} test expr-8.11 {CompileEqualityExpr: error compiling equality arm} { catch {expr 2!=x} msg } {1} test expr-9.1 {CompileRelationalExpr: just shift expr} {expr 3<<2} 12 test expr-9.2 {CompileRelationalExpr: just shift expr} {expr 0xff>>2} 63 test expr-9.3 {CompileRelationalExpr: just shift expr} {expr -1>>2} -1 test expr-9.4 {CompileRelationalExpr: just shift expr} {expr {1<<3}} 8 # The following test is different for 32-bit versus 64-bit # architectures because LONG_MIN is different if {0x80000000 > 0} { test expr-9.5 {CompileRelationalExpr: shift expr producing LONG_MIN (64bit)} jim { expr {1<<63} } -9223372036854775808 } else { test expr-9.5 {CompileRelationalExpr: shift expr producing LONG_MIN (32bit)} jim { expr {1<<31} } -2147483648 } test expr-9.6 {CompileRelationalExpr: error in shift expr} { catch {expr x>>3} msg } {1} test expr-9.7 {CompileRelationalExpr: simple relational exprs} {expr 0xff>=+0x3} 1 test expr-9.8 {CompileRelationalExpr: simple relational exprs} {expr -0xf2<0x3} 1 test expr-9.9 {CompileRelationalExpr: error compiling relational arm} { catch {expr 2//3>6} msg } {1} test expr-9.10 {CompileRelationalExpr: error compiling relational arm} { catch {expr 2>0x3} 31 test expr-10.7 {CompileShiftExpr: simple shift exprs} {expr -0xf2<<0x3} -1936 test expr-10.8 {CompileShiftExpr: error compiling shift arm} { catch {expr 2//3>>6} msg } {1} test expr-10.9 {CompileShiftExpr: error compiling shift arm} { catch {expr 2<>43}} msg] } {1} test expr-10.11 {CompileShiftExpr: runtime error} { list [catch {expr {"a"<<"b"}} msg] } {1} test expr-11.1 {CompileAddExpr: just multiply expr} {expr 4*-2} -8 test expr-11.2 {CompileAddExpr: just multiply expr} {expr 0xff%2} 1 test expr-11.3 {CompileAddExpr: just multiply expr} {expr -1/2} -1 test expr-11.4 {CompileAddExpr: just multiply expr} {expr 7891%0123} 19 test expr-11.5 {CompileAddExpr: error in multiply expr} { catch {expr x*3} msg } {1} test expr-11.6 {CompileAddExpr: simple add exprs} {expr 0xff++0x3} 258 test expr-11.7 {CompileAddExpr: simple add exprs} {expr -0xf2--0x3} -239 test expr-11.8 {CompileAddExpr: error compiling add arm} { catch {expr 2//3+6} msg } {1} test expr-11.9 {CompileAddExpr: error compiling add arm} { catch {expr 2-x} msg } {1} test expr-11.10 {CompileAddExpr: runtime error} { list [catch {expr {24.0+"xx"}} msg] } {1} test expr-11.11 {CompileAddExpr: runtime error} { list [catch {expr {"a"-"b"}} msg] } {1} test expr-11.12 {CompileAddExpr: runtime error} { list [catch {expr {3/0}} msg] } {1} test expr-11.13 {CompileAddExpr: divide by zero} { expr {2.3/0.0} } {Inf} test expr-11.14 {CompileAddExpr: divide by zero} { expr {-2.3/0.0} } {-Inf} test expr-12.1 {CompileMultiplyExpr: just unary expr} {expr ~4} -5 test expr-12.2 {CompileMultiplyExpr: just unary expr} {expr --5} 5 test expr-12.3 {CompileMultiplyExpr: just unary expr} {expr !27} 0 test expr-12.4 {CompileMultiplyExpr: just unary expr} {expr ~0xff00ff} -16711936 test expr-12.5 {CompileMultiplyExpr: error in unary expr} { catch {expr ~x} msg } {1} test expr-12.6 {CompileMultiplyExpr: simple multiply exprs} {expr 0xff*0x3} 765 test expr-12.7 {CompileMultiplyExpr: simple multiply exprs} {expr -0xf2%-0x3} -2 test expr-12.8 {CompileMultiplyExpr: error compiling multiply arm} { catch {expr 2*3%%6} msg } {1} test expr-12.9 {CompileMultiplyExpr: error compiling multiply arm} { catch {expr 2*x} msg } {1} test expr-12.10 {CompileMultiplyExpr: runtime error} { list [catch {expr {24.0*"xx"}} msg] } {1} test expr-12.11 {CompileMultiplyExpr: runtime error} { list [catch {expr {"a"/"b"}} msg] } {1} test expr-13.1 {CompileUnaryExpr: unary exprs} {expr -0xff} -255 test expr-13.2 {CompileUnaryExpr: unary exprs} {expr +000123} 123 test expr-13.3 {CompileUnaryExpr: unary exprs} {expr +--++36} 36 test expr-13.4 {CompileUnaryExpr: unary exprs} {expr !2} 0 test expr-13.5 {CompileUnaryExpr: unary exprs} {expr +--+-62.0} -62.0 test expr-13.6 {CompileUnaryExpr: unary exprs} {expr !0.0} 1 test expr-13.7 {CompileUnaryExpr: unary exprs} {expr !0xef} 0 test expr-13.8 {CompileUnaryExpr: error compiling unary expr} { catch {expr ~x} msg } {1} test expr-13.9 {CompileUnaryExpr: error compiling unary expr} { catch {expr !1.x} msg } {1} test expr-13.10 {CompileUnaryExpr: runtime error} { list [catch {expr {~"xx"}} msg] } {1} test expr-13.11 {CompileUnaryExpr: runtime error} { list [catch {expr ~4.0} msg] } {1} test expr-13.12 {CompileUnaryExpr: just primary expr} {expr 0x123} 291 test expr-13.13 {CompileUnaryExpr: just primary expr} { set a 27 expr $a } 27 test expr-13.14 {CompileUnaryExpr: just primary expr} { expr double(27) } 27.0 test expr-13.15 {CompileUnaryExpr: just primary expr} {expr "123"} 123 test expr-13.16 {CompileUnaryExpr: error in primary expr} { catch {expr [set]} msg } {1} test expr-14.1 {CompilePrimaryExpr: literal primary} {expr 1} 1 test expr-14.2 {CompilePrimaryExpr: literal primary} {expr 123} 123 test expr-14.3 {CompilePrimaryExpr: literal primary} {expr 0xff} 255 test expr-14.4 {CompilePrimaryExpr: literal primary} {expr 00010} 10 test expr-14.5 {CompilePrimaryExpr: literal primary} {expr 62.0} 62.0 test expr-14.6 {CompilePrimaryExpr: literal primary} { expr 3.1400000 } 3.14 test expr-14.7 {CompilePrimaryExpr: literal primary} {expr {{abcde}<{abcdef}}} 1 test expr-14.8 {CompilePrimaryExpr: literal primary} {expr {{abc\ def} < {abcdef}}} 1 test expr-14.9 {CompilePrimaryExpr: literal primary} {expr {{abc\tde} > {abc\tdef}}} 0 test expr-14.10 {CompilePrimaryExpr: literal primary} {expr {{123}}} 123 test expr-14.11 {CompilePrimaryExpr: var reference primary} { set i 789 list [expr {$i}] [expr $i] } {789 789} test expr-14.12 {CompilePrimaryExpr: var reference primary} { set i {789} ;# test expr's aggressive conversion to numeric semantics list [expr {$i}] [expr $i] } {789 789} test expr-14.13 {CompilePrimaryExpr: var reference primary} { catch {unset a} set a(foo) foo set a(bar) bar set a(123) 123 set result "" lappend result [expr $a(123)] [expr {$a(bar)<$a(foo)}] catch {unset a} set result } {123 1} test expr-14.14 {CompilePrimaryExpr: var reference primary} { set i 123 ;# test "$var.0" floating point conversion hack list [expr $i] [expr $i.0] [expr $i.0/12.0] } {123 123.0 10.25} test expr-14.15 {CompilePrimaryExpr: var reference primary} { set i 123 catch {expr $i.2} msg set msg } 123.2 test expr-14.16 {CompilePrimaryExpr: error compiling var reference primary} { catch {expr {$a(foo}} msg } {1} test expr-14.18 {CompilePrimaryExpr: quoted string primary} { expr "21" } 21 test expr-14.19 {CompilePrimaryExpr: quoted string primary} { set i 123 set x 456 expr "$i+$x" } 579 test expr-14.20 {CompilePrimaryExpr: quoted string primary} { set i 3 set x 6 expr 2+"$i.$x" } 5.6 test expr-14.21 {CompilePrimaryExpr: error in quoted string primary} { catch {expr "[set]"} msg } {1} test expr-14.22 {CompilePrimaryExpr: subcommand primary} { expr {[set i 123; set i]} } 123 test expr-14.23 {CompilePrimaryExpr: error in subcommand primary} { catch {expr {[set]}} msg } {1} test expr-14.24 {CompilePrimaryExpr: error in subcommand primary} { catch {expr {[set blah}} msg } {1} test expr-14.28 {CompilePrimaryExpr: subexpression primary} { expr 2+(3*4) } 14 test expr-14.29 {CompilePrimaryExpr: error in subexpression primary} { catch {expr 2+(3*[set])} msg } {1} test expr-14.30 {CompilePrimaryExpr: missing paren in subexpression primary} { catch {expr 2+(3*(4+5)} msg } {1} test expr-14.31 {CompilePrimaryExpr: just var ref in subexpression primary} { set i "5+10" list "[expr $i] == 15" "[expr ($i)] == 15" "[eval expr ($i)] == 15" } {{15 == 15} {15 == 15} {15 == 15}} test expr-14.32 {CompilePrimaryExpr: unexpected token} { catch {expr @} msg } {1} test expr-15.2 {CompileMathFuncCall: unknown math function} { catch {expr whazzathuh(1)} msg } {1} test expr-16.1 {GetToken: checks whether integer token starting with "0x" (e.g., "0x$") is invalid} { catch {unset a} set a(VALUE) ff15 set i 123 if {[expr 0x$a(VALUE)] & 16} { set i {} } set i } {} test expr-16.2 {GetToken: check for string literal in braces} { expr {{1}} } {1} # Check "expr" and computed command names. test expr-17.1 {expr and computed command names} { set i 0 set z expr $z 1+2 } 3 # Check correct conversion of operands to numbers: If the string looks like # an integer, convert to integer. Otherwise, if the string looks like a # double, convert to double. test expr-18.1 {expr and conversion of operands to numbers} { set x [lindex 11 0] catch {expr int($x)} expr {$x} } 11 test expr-18.2 {whitespace strings should not be == 0 (buggy strtod)} { expr {" "} } { } # Check "expr" and interpreter result object resetting before appending # an error msg during evaluation of exprs not in {}s test expr-19.1 {expr and interpreter result object resetting} { proc p {} { set t 10.0 set x 2.0 set dx 0.2 set f {$dx-$x/10} set g {-$x/5} set center 1.0 set x [expr $x-$center] set dx [expr $dx+$g] set x [expr $x+$f+$center] set x [expr $x+$f+$center] set y [expr round($x)] } p } 3 catch {unset a} # Test for incorrect "double evaluation" semantics #XXX: Jim doesn't care about missing braces #test expr-20.1 {wrong brace matching} { # catch {unset l} # catch {unset r} # catch {unset q} # catch {unset cmd} # catch {unset a} # set l "\{"; set r "\}"; set q "\"" # set cmd "expr $l$q|$q == $q$r$q$r" # catch $cmd a #} {1} test expr-20.3 {broken substitution of integer digits} { # fails with 8.0.x, but not 8.1b2 list [set a 000; expr 0x1$a] [set a 1; expr ${a}000] } {4096 1000} test expr-20.4 {proper double evaluation compilation, error case} { catch {unset a}; # make sure $a doesn't exist list [catch {expr 1?{$a}:0} msg] } {1} test expr-20.5 {proper double evaluation compilation, working case} { set a yellow expr 1?{$a}:0 } yellow test expr-20.6 {handling of compile error in trial compile} { list [catch {expr + {[incr]}} msg] } {1} test expr-20.7 {handling of compile error in runtime case} { list [catch {expr + {[error foo]}} msg] } {1} # cleanup if {[info exists a]} { unset a } testreport openocd-0.7.0/jimtcl/tests/break.tcl0000644000175000001440000000000612134336723014276 00000000000000break openocd-0.7.0/jimtcl/tests/dummy.tcl0000644000175000001440000000011612134336723014347 00000000000000# generates an error proc dummyproc {} { error "from dummyproc" } dummyproc openocd-0.7.0/jimtcl/tests/glob.test0000644000175000001440000000603512134336723014342 00000000000000# Test the glob command source [file dirname [info script]]/testing.tcl needs constraint jim needs cmd glob # Fake the bare minimum that glob.tcl needs: # [readdir], [file isdir] and [file exists] local proc file {cmd args} { if {$cmd in {isdir exists}} { lassign [fslookup [lindex $args 0]] type contents if {$cmd eq "isdir" && $type eq "dir"} { return 1 } elseif {$type ne "none"} { return 1 } return 0 } tailcall upcall file $cmd {*}$args } local proc readdir {{-nocomplain {}} dir} { lassign [fslookup $dir] type contents if {$type ne "dir"} { if {${-nocomplain} eq ""} { return {} } return -code error "No such file or directory" } dict keys $contents } local proc fslookup {path} { set type dir set dict $::FAKEFS foreach p [split $path /] { if {$p in {. {}}} { continue } if {![dict exists $dict $p] || $type ne "dir"} { return none } lassign [dict get $dict $p] type dict } list $type $dict } # Creates the representation of a filesystem in a dictionary - for testing local proc makefakefs {fs} { set fakefs {} foreach {type name contents} $fs { switch -glob -- $type { f* { set fakefs($name) [list file $contents] } d* { set fakefs($name) [list dir [makefakefs $contents]] } default { error "Unknown fs type: $type" } } } return $fakefs } # Create a fake filesystem for testing the glob command set ::FAKEFS [makefakefs { file abc {This is the contents of abc} dir def { file ghi {This file is inside def} dir jkl } dir tmp { file "open{brace" {} file "close}brace" {} file "open\[bracket" {} file "close\]bracket" {} } }] test glob-1.1 {Simple} { lsort [glob *] } {abc def tmp} test glob-1.2 {Simple} { lsort [glob a*] } {abc} test glob-1.3 {Simple} -returnCodes error -body { lsort [glob x*] } -result {no files matched glob patterns} test glob-1.4 {Simple} -returnCodes error -body { lsort [glob] } -result {wrong # args: should be "glob ?options? pattern ?pattern ...?"} test glob-1.5 {Simple} -returnCodes ok -body { lsort [glob -nocomplain x*] } -result {} test glob-2.1 {Braces} -returnCodes ok -body { lsort [glob "{a,d}*"] } -result {abc def} test glob-2.2 {Files containing braces and brackets} -returnCodes ok -body { lsort [glob tmp/*] } -result {tmp/close\]bracket tmp/close\}brace {tmp/open[bracket} tmp/open\{brace} test glob-2.3 {Glob match files open bracket} -returnCodes ok -body { lsort [glob {tmp/*\[*}] } -result [list tmp/open\[bracket] test glob-2.4 {Glob match files close bracket} -returnCodes ok -body { lsort [glob {tmp/*\]*}] } -result [list tmp/close\]bracket] test glob-2.5 {Glob match files containing braced brackets} -returnCodes ok -body { lsort [glob {tmp/*{\[,]}*}] } -result [list tmp/close\]bracket tmp/open\[bracket] test glob-3.1 {Directory option} -returnCodes ok -body { lsort [glob -dir tmp *] } -result [list close\]bracket close\}brace open\[bracket open\{brace] test glob-3.2 {Directory option} -returnCodes ok -body { lsort [glob -dir tmp *close*] } -result [list close\]bracket close\}brace] testreport openocd-0.7.0/jimtcl/tests/lsortcmd.test0000644000175000001440000000126112134336723015242 00000000000000source [file dirname [info script]]/testing.tcl set list {b d a c z} proc sorter {a v1 v2} { set ::arg $a return [string compare $v1 $v2] } proc test_lsort_cmd {test cmd list exp} { lsort -command $cmd $list if {$::arg != $exp} { error "$test: Failed" } } test lsortcmd-1.1 "Sort with one arg" { lsort -command "sorter arg1" $list set arg } {arg1} test lsortcmd-1.2 "Sort with one arg containg spaces" { lsort -command {sorter "arg with space"} $list set arg } {arg with space} test lsortcmd-1.3 "Sort with arg as list containg spaces" { lsort -command [list sorter [list arg with list "last with spaces"]] $list set arg } {arg with list {last with spaces}} testreport openocd-0.7.0/jimtcl/tests/array.test0000644000175000001440000000277212134336723014541 00000000000000source [file dirname [info script]]/testing.tcl needs cmd array unset -nocomplain a array set a { 1 one 2 two 22 "twenty two" 3 three } test array-1.1 "array exists - true" { array exists a } {1} test array-1.2 "array exists - false" { array exists b } {0} test array-1.3 "array size" { array size a } {4} test array-1.4 "array size - nonexistant" { array size b } {0} test array-1.5 "array get" { set result {} foreach {name value} [array get a] { lappend result $name $value } lsort $result } {1 2 22 3 one three {twenty two} two} test array-1.6 "array get - pattern" { set result {} foreach {name value} [array get a 2*] { lappend result $name $value } lsort $result } {2 22 {twenty two} two} test array-1.7 "array names" { lsort [array names a] } {1 2 22 3} test array-1.8 "array get - pattern" { lsort [array names a 2*] } {2 22} #set b $a array set b [array get a] test array-1.9 "array set - replace" { array set b {22 twenty-two} set b(22) } {twenty-two} test array-1.10 "array unset - pattern" { array unset b 2* lsort [array names b] } {1 3} test array-1.11 "array unset - all" { array unset b list [array size b] [array exists b] } {0 0} test array-1.12 "array set to invalid variable" { unset -nocomplain a b set a 1 catch {array set a(1) {b c}} } {1} test array-1.13 "unset missing array element" { unset -nocomplain a set a(1) one catch {unset a(2)} } 1 test array-1.14 "access array via unset var" { unset -nocomplain b catch {expr {$a($b) + 4}} } 1 testreport openocd-0.7.0/jimtcl/tests/exists.test0000644000175000001440000000223112134336723014730 00000000000000source [file dirname [info script]]/testing.tcl needs cmd exists testConstraint lambda [expr {[info commands lambda] ne {}}] test exists-1.1 "Exists var" { set a 1 exists a } 1 test exists-1.1 "Exists var" { unset -nocomplain b exists b } 0 test exists-1.1 "Exists -var" { exists -var a } 1 test exists-1.1 "Exists -var" { exists -var b } 0 test exists-1.1 "Exists in proc" { proc a {name} { exists $name } a ::a } 1 test exists-1.1 "Exists in proc" { a ::b } 0 test exists-1.1 "Exists in proc" { a name } 1 test exists-1.1 "Exists in proc" { a none } 0 test exists-1.1 "Exists -proc" { exists -proc a } 1 test exists-1.1 "Exists -proc" { exists -proc bogus } 0 test exists-1.1 "Exists -proc" { exists -proc info } 0 test exists-1.1 "Exists -command" { exists -command a } 1 test exists-1.1 "Exists -command" { exists -command info } 1 test exists-1.1 "Exists -command" { exists -command bogus } 0 test exists-1.1 "Exists local lambda after exit" lambda { proc a {} { local lambda {} {dummy} } exists -proc [a] } 0 test exists-1.1 "Exists local lambda" lambda { proc a {} { exists -proc [local lambda {} {dummy}] } a } 1 testreport openocd-0.7.0/jimtcl/tests/lsearch.test0000644000175000001440000001165412134336723015043 00000000000000# Commands covered: lsearch # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # RCS: @(#) $Id: lsearch.test,v 1.5 2000/04/10 17:19:01 ericm Exp $ source [file dirname [info script]]/testing.tcl catch {package require regexp} testConstraint regexp [expr {[info commands regexp] ne {}}] set x {abcd bbcd 123 234 345} test lsearch-1.1 {lsearch command} { lsearch $x 123 } 2 test lsearch-1.2 {lsearch command} { lsearch $x 3456 } -1 test lsearch-1.3 {lsearch command} { lsearch -glob $x *5 } 4 test lsearch-1.4 {lsearch command} { lsearch -glob $x *bc* } 0 test lsearch-2.1 {search modes} { lsearch -exact {xyz bbcc *bc*} *bc* } 2 test lsearch-2.2 {search modes} { lsearch -exact {b.x ^bc xy bcx} ^bc } 1 test lsearch-2.3 {search modes} { lsearch -exact {foo bar cat} ba } -1 test lsearch-2.4 {search modes} { lsearch -exact {foo bar cat} bart } -1 test lsearch-2.5 {search modes} { lsearch -exact {foo bar cat} bar } 1 test lsearch-2.6 {search modes} regexp { list [catch {lsearch -regexp {xyz bbcc *bc*} *bc*} msg] } {1} test lsearch-2.7 {search modes} regexp { lsearch -regexp {b.x ^bc xy bcx} ^bc } 3 test lsearch-2.8 {search modes} { lsearch -glob {xyz bbcc *bc*} *bc* } 1 test lsearch-2.9 {search modes} { lsearch -glob {b.x ^bc xy bcx} ^bc } 1 test lsearch-2.10 {search modes} { list [catch {lsearch -glib {b.x bx xy bcx} b.x} msg] } {1} test lsearch-2.7 {search modes, -nocase} regexp { lsearch -nocase -regexp {b.x ^bc xy bcx} ^BC } 3 test lsearch-2.8 {search modes, -nocase} { lsearch -nocase -exact {b.x ^bc xy bcx} ^BC } 1 test lsearch-2.9 {search modes, -nocase} { lsearch -nocase -glob {b.x ^bc xy bcx} B* } 0 test lsearch-3.1 {lsearch errors} { list [catch lsearch msg] } {1} test lsearch-3.2 {lsearch errors} { list [catch {lsearch a} msg] } {1} test lsearch-3.3 {lsearch errors} { list [catch {lsearch a b c} msg] } {1} test lsearch-3.4 {lsearch errors} { list [catch {lsearch a b c d} msg] } {1} test lsearch-4.1 {binary data} { lsearch -exact [list foo one\000two bar] bar } 2 test lsearch-4.2 {binary data} { set x one append x \x00 append x two lsearch -exact [list foo one\000two bar] $x } 1 test lsearch-5.1 {lsearch -all} { lsearch -glob -all {a1 a2 b1 b2 a3 b3} a* } {0 1 4} test lsearch-5.2 {lsearch -all no match} { lsearch -glob -all {a1 a2 b1 b2 a3 b3} B* } {} test lsearch-5.3 {lsearch -all -nocase} { lsearch -glob -all -nocase {a1 a2 b1 b2 a3 b3} B* } {2 3 5} test lsearch-5.4 {lsearch -all -inline} { lsearch -glob -all -inline -nocase {a1 a2 b1 b2 a3 b3} A* } {a1 a2 a3} test lsearch-5.5 {lsearch -inline} { lsearch -glob -inline {a1 a2 b1 b2 a3 b3} b* } {b1} test lsearch-5.6 {lsearch -not -all} { lsearch -not -glob -all {a1 a2 b1 b2 a3 b3} a* } {2 3 5} test lsearch-5.7 {lsearch -not -all no match} { lsearch -not -glob -all {a1 a2 b1 b2 a3 b3} B* } {0 1 2 3 4 5} test lsearch-5.8 {lsearch -not -all -nocase} { lsearch -not -glob -all -nocase {a1 a2 b1 b2 a3 b3} B* } {0 1 4} test lsearch-5.9 {lsearch -not -all -inline} { lsearch -not -glob -all -inline -nocase {a1 a2 b1 b2 a3 b3} A* } {b1 b2 b3} test lsearch-5.10 {lsearch -not -inline} { lsearch -not -glob -inline {a1 a2 b1 b2 a3 b3} b* } {a1} test lsearch-5.11 {lsearch -inline, no match} { lsearch -glob -inline {a1 a2 b1 b2 a3 b3} C* } {} test lsearch-6.1 {lsearch -bool, found} jim { lsearch -bool {a1 a2 b1 b2 a3 b3} b1 } {1} test lsearch-6.2 {lsearch -bool, not found} jim { lsearch -bool {a1 a2 b1 b2 a3 b3} c1 } {0} test lsearch-6.3 {lsearch -not -bool, found} jim { lsearch -not -bool {a1 a2 b1 b2 a3 b3} b1 } {0} test lsearch-6.4 {lsearch -not -bool, not found} jim { lsearch -not -bool {a1 a2 b1 b2 a3 b3} c1 } {1} test lsearch-6.5 {lsearch -bool -all} jim { lsearch -bool -glob -all {a1 a2 b1 b2 a3 b3} a* } {1 1 0 0 1 0} test lsearch-6.6 {lsearch -bool -all no match} jim { lsearch -bool -glob -all {a1 a2 b1 b2 a3 b3} B* } {0 0 0 0 0 0} test lsearch-6.7 {lsearch -bool -all -nocase} jim { lsearch -bool -glob -all -nocase {a1 a2 b1 b2 a3 b3} B* } {0 0 1 1 0 1} test lsearch-6.8 {lsearch -not -bool -all} jim { lsearch -not -bool -glob -all {a1 a2 b1 b2 a3 b3} a* } {0 0 1 1 0 1} test lsearch-6.9 {lsearch -not -bool -all no match} jim { lsearch -not -bool -glob -all {a1 a2 b1 b2 a3 b3} B* } {1 1 1 1 1 1} test lsearch-6.10 {lsearch -not -bool -all -nocase} jim { lsearch -not -bool -glob -all -nocase {a1 a2 b1 b2 a3 b3} B* } {1 1 0 0 1 0} testreport openocd-0.7.0/jimtcl/tests/regmin.test0000644000175000001440000000241112134336723014672 00000000000000source [file dirname [info script]]/testing.tcl needs cmd regexp testConstraint regexp_are [regexp {\d} 1] needs constraint regexp_are test regexpmin-1.1 {Minimal +} { regexp -inline {x(a|b|c)+?c} xabcabc } {xabc b} test regexpmin-1.2 {Maximal +} { regexp -inline {x(a|b|c)+c} xabcabc } {xabcabc b} test regexpmin-1.3 {Minimal *} { regexp -inline {x(a|b)*?} xababcabc } {x {}} test regexpmin-1.4 {Maximal *} { regexp -inline {x(a|b)*} xababcabc } {xabab b} test regexpmin-1.5 {Maximal ?} { regexp -inline {x(a|b)?} xababcabc } {xa a} test regexpmin-1.6 {Minimal ?} { regexp -inline {x(a|b)??} xababcabc } {x {}} test regexpmin-1.7 {Maximal html} { regexp -inline {<(.+)>} } { foo>} } { foo} test regexpmin-2.1 {utf8 repeat} utf8 { regexp -inline {a\u00df+} a\udf\udf\udf\udf\ub5z } "a\udf\udf\udf\udf" test regexpmin-2.2 {utf8 min repeat} utf8 { regexp -inline {a\u00df+?} a\udf\udf\udf\udf\ub5z } "a\udf" test regexpmin-3.1 {non-capturing paren} { regexp -inline {x(?:a|b)?} xababcabc } {xa} test regexpmin-3.2 {non-capturing paren} { regexp -inline {x(?:a|b)?.*(b|c)} xababcabc } {xababcabc c} testreport openocd-0.7.0/jimtcl/tests/for.test0000644000175000001440000000336012134336723014203 00000000000000# Commands covered: for, continue, break # # This file contains the original set of tests for Tcl's for command. # Since the for command is now compiled, a new set of tests covering # the new implementation is in the file "for.test". Sourcing this file # into Tcl runs the tests and generates output for errors. # No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994-1996 Sun Microsystems, Inc. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # RCS: @(#) $Id: for-old.test,v 1.5 2000/04/10 17:18:59 ericm Exp $ source [file dirname [info script]]/testing.tcl # Check "for" and its use of continue and break. catch {unset a i} test for-old-1.1 {for tests} { set a {} for {set i 1} {$i<6} {set i [expr $i+1]} { set a [concat $a $i] } set a } {1 2 3 4 5} test for-old-1.2 {for tests} { set a {} for {set i 1} {$i<6} {set i [expr $i+1]} { if $i==4 continue set a [concat $a $i] } set a } {1 2 3 5} test for-old-1.3 {for tests} { set a {} for {set i 1} {$i<6} {set i [expr $i+1]} { if $i==4 break set a [concat $a $i] } set a } {1 2 3} test for-old-1.4 {for tests} {catch {for 1 2 3} msg} 1 test for-old-1.5 {for tests} { catch {for 1 2 3} msg } {1} test for-old-1.6 {for tests} {catch {for 1 2 3 4 5} msg} 1 test for-old-1.7 {for tests} { catch {for 1 2 3 4 5} msg } {1} test for-old-1.8 {for tests} { set a {xyz} for {set i 1} {$i<6} {set i [expr $i+1]} {} set a } xyz test for-old-1.9 {for tests} { set a {} for {set i 1} {$i<6} {set i [expr $i+1]; if $i==4 break} { set a [concat $a $i] } set a } {1 2 3} testreport openocd-0.7.0/jimtcl/tests/expand.test0000644000175000001440000000072112134336723014672 00000000000000source [file dirname [info script]]/testing.tcl test expand-1.1 "Basic tests" { set a {1 2 3} set b {4 5 6} lappend a {*}$b } {1 2 3 4 5 6} test expand-1.2 "Basic tests" jim { set a {1 2 3} set b {4 5 6} lappend a {expand}$b } {1 2 3 4 5 6} test expand-1.3 "Basic tests" { set a {1 2 3} set b {4 5 6} lappend a *$b } {1 2 3 {*4 5 6}} test expand-1.4 "Basic tests" { set a {1 2 3} set b {4 5 6} lappend a expand$b } {1 2 3 {expand4 5 6}} testreport openocd-0.7.0/jimtcl/tests/lreplace.test0000644000175000001440000001011412134336723015177 00000000000000# Commands covered: lreplace # # This file contains a collection of tests for one or more of the Tcl # built-in commands. Sourcing this file into Tcl runs the tests and # generates output for errors. No output means no errors were found. # # Copyright (c) 1991-1993 The Regents of the University of California. # Copyright (c) 1994 Sun Microsystems, Inc. # Copyright (c) 1998-1999 by Scriptics Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. source [file dirname [info script]]/testing.tcl test lreplace-1.1 {lreplace command} { lreplace {1 2 3 4 5} 0 0 a } {a 2 3 4 5} test lreplace-1.2 {lreplace command} { lreplace {1 2 3 4 5} 1 1 a } {1 a 3 4 5} test lreplace-1.3 {lreplace command} { lreplace {1 2 3 4 5} 2 2 a } {1 2 a 4 5} test lreplace-1.4 {lreplace command} { lreplace {1 2 3 4 5} 3 3 a } {1 2 3 a 5} test lreplace-1.5 {lreplace command} { lreplace {1 2 3 4 5} 4 4 a } {1 2 3 4 a} test lreplace-1.6 {lreplace command} { lreplace {1 2 3 4 5} 4 5 a } {1 2 3 4 a} test lreplace-1.7 {lreplace command} { lreplace {1 2 3 4 5} -1 -1 a } {a 1 2 3 4 5} test lreplace-1.8 {lreplace command} { lreplace {1 2 3 4 5} 2 end a b c d } {1 2 a b c d} test lreplace-1.9 {lreplace command} { lreplace {1 2 3 4 5} 0 3 } {5} test lreplace-1.10 {lreplace command} { lreplace {1 2 3 4 5} 0 4 } {} test lreplace-1.11 {lreplace command} { lreplace {1 2 3 4 5} 0 1 } {3 4 5} test lreplace-1.12 {lreplace command} { lreplace {1 2 3 4 5} 2 3 } {1 2 5} test lreplace-1.13 {lreplace command} { lreplace {1 2 3 4 5} 3 end } {1 2 3} test lreplace-1.14 {lreplace command} { lreplace {1 2 3 4 5} -1 4 a b c } {a b c} test lreplace-1.15 {lreplace command} { lreplace {a b "c c" d e f} 3 3 } {a b {c c} e f} test lreplace-1.16 {lreplace command} { lreplace { 1 2 3 4 5} 0 0 a } {a 2 3 4 5} test lreplace-1.17 {lreplace command} { lreplace {1 2 3 4 "5 6"} 4 4 a } {1 2 3 4 a} test lreplace-1.18 {lreplace command} { lreplace {1 2 3 4 {5 6}} 4 4 a } {1 2 3 4 a} test lreplace-1.19 {lreplace command} { lreplace {1 2 3 4} 2 end x y z } {1 2 x y z} test lreplace-1.20 {lreplace command} { lreplace {1 2 3 4} end end a } {1 2 3 a} test lreplace-1.21 {lreplace command} { lreplace {1 2 3 4} end 3 a } {1 2 3 a} test lreplace-1.22 {lreplace command} { lreplace {1 2 3 4} end end } {1 2 3} test lreplace-1.23 {lreplace command} { lreplace {1 2 3 4} 2 -1 xy } {1 2 xy 3 4} test lreplace-1.24 {lreplace command} { lreplace {1 2 3 4} end -1 z } {1 2 3 z 4} test lreplace-1.25 {lreplace command} { concat \"[lreplace {\}\ hello} end end]\" } {"\}\ "} test lreplace-1.26 {lreplace command} { catch {unset foo} set foo {a b} list [set foo [lreplace $foo end end]] \ [set foo [lreplace $foo end end]] \ [set foo [lreplace $foo end end]] } {a {} {}} test lreplace-2.1 {lreplace errors} { list [catch lreplace msg] $msg } {1 {wrong # args: should be "lreplace list first last ?element ...?"}} test lreplace-2.2 {lreplace errors} { list [catch {lreplace a b} msg] $msg } {1 {wrong # args: should be "lreplace list first last ?element ...?"}} test lreplace-2.3 {lreplace errors} { list [catch {lreplace x a 10} msg] $msg } {1 {bad index "a": must be integer?[+-]integer? or end?[+-]integer?}} test lreplace-2.4 {lreplace errors} { list [catch {lreplace x 10 x} msg] $msg } {1 {bad index "x": must be integer?[+-]integer? or end?[+-]integer?}} test lreplace-2.5 {lreplace errors} { list [catch {lreplace x 10 1x} msg] $msg } {1 {bad index "1x": must be integer?[+-]integer? or end?[+-]integer?}} test lreplace-2.6 {lreplace errors} { list [catch {lreplace x 3 2} msg] $msg } {1 {list doesn't contain element 3}} test lreplace-2.7 {lreplace errors} { list [catch {lreplace x 1 1} msg] $msg } {1 {list doesn't contain element 1}} test lreplace-3.1 {lreplace won't modify shared argument objects} { proc p {} { lreplace "a b c" 1 1 "x y" return "a b c" } p } "a b c" # cleanup catch {unset foo} ::tcltest::cleanupTests return openocd-0.7.0/jimtcl/regtest.tcl0000644000175000001440000001031112134336723013525 00000000000000# REGTEST 1 # 27Jan2005 - SIGSEGV for bug on Jim_DuplicateObj(). for {set i 0} {$i < 100} {incr i} { set a "x" lappend a n } puts "TEST 1 PASSED" # REGTEST 2 # 29Jan2005 - SEGFAULT parsing script composed of just one comment. eval {#foobar} puts "TEST 2 PASSED" # REGTEST 3 # 29Jan2005 - "Error in Expression" with correct expression set x 5 expr {$x-5} puts "TEST 3 PASSED" # REGTEST 4 # 29Jan2005 - SIGSEGV when run this code, due to expr's bug. proc fibonacci {x} { if {$x <= 1} { expr 1 } else { expr {[fibonacci [expr {$x-1}]] + [fibonacci [expr {$x-2}]]} } } fibonacci 6 puts "TEST 4 PASSED" # REGTEST 5 # 06Mar2005 - This looped forever... for {set i 0} {$i < 10} {incr i} {continue} puts "TEST 5 PASSED" # REGTEST 6 # 07Mar2005 - Unset create variable + dict is using dict syntax sugar at # currently non-existing variable catch {unset thisvardoesnotexists(thiskeytoo)} if {[catch {set thisvardoesnotexists}] == 0} { puts "TEST 6 FAILED - unset created dict for non-existing variable" break } puts "TEST 6 PASSED" # REGTEST 7 # 04Nov2008 - variable parsing does not eat last brace set a 1 list ${a} puts "TEST 7 PASSED" # REGTEST 8 # 04Nov2008 - string toupper/tolower do not convert to string rep string tolower [list a] string toupper [list a] puts "TEST 8 PASSED" # REGTEST 9 # 04Nov2008 - crash on exit when replacing Tcl proc with C command. # Requires the clock extension to be built as a loadable module. proc clock {args} {} catch {package require clock} # Note, crash on exit, so don't say we passed! # REGTEST 10 # 05Nov2008 - incorrect lazy expression evaluation with unary not expr {1 || !0} puts "TEST 10 PASSED" # REGTEST 11 # 14 Feb 2010 - access static variable in deleted proc proc a {} {{x 1}} { rename a ""; incr x } a puts "TEST 11 PASSED" # REGTEST 12 # 13 Sep 2010 - reference with invalid tag set a b[ref value "tag name"] getref [string range $a 1 end] puts "TEST 12 PASSED" # REGTEST 13 # 14 Sep 2010 - parse list with trailing backslash set x "switch -0 \$on \\" lindex $x 1 puts "TEST 13 PASSED" # REGTEST 14 # 14 Sep 2010 - command expands to nothing eval "{*}{}" puts "TEST 14 PASSED" # REGTEST 15 # 24 Feb 2010 - bad reference counting of the stack trace in 'error' proc a {msg stack} { tailcall error $msg $stack } catch {fail} msg opts catch {a $msg $opts(-errorinfo)} # REGTEST 16 # 24 Feb 2010 - rename the current proc # Leaves unfreed objects on the stack proc a {} { rename a newa} a # REGTEST 17 # 26 Nov 2010 - crashes on invalid dict sugar catch {eval {$x(}} puts "TEST 17 PASSED" # REGTEST 18 # 12 Apr 2011 - crashes on unset for loop var catch { for {set i 0} {$i < 5} {incr i} {unset i} } puts "TEST 18 PASSED" # REGTEST 19 # 25 May 2011 - crashes with double colon catch { expr {5 ne ::} } puts "TEST 19 PASSED" # REGTEST 20 # 26 May 2011 - infinite recursion proc a {} { global ::blah; set ::blah test } a puts "TEST 20 PASSED" # REGTEST 21 # 26 May 2011 - infinite loop with null byte in subst subst "abc\0def" puts "TEST 21 PASSED" # REGTEST 22 # 21 June 2011 - crashes on lappend to to value with script rep set x rand eval $x lappend x b puts "TEST 22 PASSED" # REGTEST 23 # 27 July 2011 - unfreed objects on exit catch { set x abc subst $x regexp $x $x } # Actually, the test passes if no objects leaked on exit puts "TEST 23 PASSED" # REGTEST 24 # 13 Nov 2011 - invalid cached global var proc a {} { foreach i {1 2} { incr z [set ::t] unset ::t } } set t 6 catch a puts "TEST 24 PASSED" # REGTEST 25 # 14 Nov 2011 - link global var to proc var proc a {} { set x 3 upvar 0 x ::globx } set globx 0 catch { a } incr globx puts "TEST 25 PASSED" # REGTEST 26 # 2 Dec 2011 - infinite eval recursion catch { set x 0 set y {incr x; eval $y} eval $y } msg puts "TEST 26 PASSED" # REGTEST 27 # 2 Dec 2011 - infinite alias recursion catch { proc p {} {} alias p p p } msg puts "TEST 27 PASSED" # REGTEST 28 # 16 Dec 2011 - ref count problem with finalizers catch { ref x x [list dummy] collect } puts "TEST 28 PASSED" # REGTEST 29 # Reference counting problem at exit set x [lindex {} 0] info source $x eval $x # TAKE THE FOLLOWING puts AS LAST LINE puts "--- ALL TESTS PASSED ---" openocd-0.7.0/jimtcl/bench.tcl0000644000175000001440000003472412134336723013145 00000000000000set batchmode 0 set benchmarks {} proc bench {title script} { global benchmarks batchmode set Title [string range "$title " 0 20] set failed [catch {time $script} res] if {$failed} { if {!$batchmode} {puts "$Title - This test can't run on this interpreter"} lappend benchmarks $title F } else { set t [expr [lindex $res 0] / 1000] lappend benchmarks $title $t set ts " $t" set ts [string range $ts [expr {[string length $ts]-10}] end] if {!$batchmode} {puts "$Title -$ts ms per iteration"} } catch { collect } } ### BUSY LOOP ################################################################## proc whilebusyloop {} { set i 0 while {$i < 1850000} { set a 2 incr i } } proc forbusyloop {} { for {set i 0} {$i < 1850000} {incr i} { set a 2 } } ### FIBONACCI ################################################################## proc fibonacci {x} { if {$x <= 1} { expr 1 } else { expr {[fibonacci [expr {$x-1}]] + [fibonacci [expr {$x-2}]]} } } ### HEAPSORT ################################################################### set IM 139968 set IA 3877 set IC 29573 set last 42 proc make_gen_random {} { global IM IA IC set params [list IM $IM IA $IA IC $IC] set body [string map $params { global last expr {($max * [set last [expr {($last * IA + IC) % IM}]]) / IM} }] proc gen_random {max} $body } proc heapsort {ra_name} { upvar 1 $ra_name ra set n [llength $ra] set l [expr {$n / 2}] set ir [expr {$n - 1}] while 1 { if {$l} { set rra [lindex $ra [incr l -1]] } else { set rra [lindex $ra $ir] lset ra $ir [lindex $ra 0] if {[incr ir -1] == 0} { lset ra 0 $rra break } } set i $l set j [expr {(2 * $l) + 1}] while {$j <= $ir} { set tmp [lindex $ra $j] if {$j < $ir} { if {$tmp < [lindex $ra [expr {$j + 1}]]} { set tmp [lindex $ra [incr j]] } } if {$rra >= $tmp} { break } lset ra $i $tmp incr j [set i $j] } lset ra $i $rra } } proc heapsort_main {} { set n 6100 make_gen_random set data {} for {set i 1} {$i <= $n} {incr i} { lappend data [gen_random 1.0] } heapsort data } ### SIEVE ###################################################################### proc sieve {num} { while {$num > 0} { incr num -1 set count 0 for {set i 2} {$i <= 8192} {incr i} { set flags($i) 1 } for {set i 2} {$i <= 8192} {incr i} { if {$flags($i) == 1} { # remove all multiples of prime: i for {set k [expr {$i+$i}]} {$k <= 8192} {incr k $i} { set flags($k) 0 } incr count } } } return $count } proc sieve_dict {num} { while {$num > 0} { incr num -1 set count 0 for {set i 2} {$i <= 8192} {incr i} { dict set flags $i 1 } for {set i 2} {$i <= 8192} {incr i} { if {[dict get $flags $i] == 1} { # remove all multiples of prime: i for {set k [expr {$i+$i}]} {$k <= 8192} {incr k $i} { dict set flags $k 0 } incr count } } } return $count } ### ARY ######################################################################## proc ary n { for {set i 0} {$i < $n} {incr i} { set x($i) $i } set last [expr {$n - 1}] for {set j $last} {$j >= 0} {incr j -1} { set y($j) $x($j) } } proc ary_dict n { for {set i 0} {$i < $n} {incr i} { dict set x $i $i } set last [expr {$n - 1}] for {set j $last} {$j >= 0} {incr j -1} { dict set y $j $x($j) } } ### REPEAT ##################################################################### proc repeat {n body} { for {set i 0} {$i < $n} {incr i} { uplevel 1 $body } } proc use_repeat {} { set x 0 repeat {1000000} {incr x} } ### UPVAR ###################################################################### proc myincr varname { upvar 1 $varname x incr x } proc upvartest {} { set y 0 for {set x 0} {$x < 100000} {myincr x} { myincr y } } ### NESTED LOOPS ############################################################### proc nestedloops {} { set n 10 set x 0 incr n 1 set a $n while {[incr a -1]} { set b $n while {[incr b -1]} { set c $n while {[incr c -1]} { set d $n while {[incr d -1]} { set e $n while {[incr e -1]} { set f $n while {[incr f -1]} { incr x } } } } } } } ### ROTATE ##################################################################### proc rotate {count} { set v 1 for {set n 0} {$n < $count} {incr n} { set v [expr {$v <<< 1}] } } ### DYNAMICALLY GENERATED CODE ################################################# proc dyncode {} { for {set i 0} {$i < 100000} {incr i} { set script "lappend foo $i" eval $script } } proc dyncode_list {} { for {set i 0} {$i < 100000} {incr i} { set script [list lappend foo $i] eval $script } } ### PI DIGITS ################################################################## proc pi_digits {} { set N 300 set LEN [expr {10*$N/3}] set result "" set a [string repeat " 2" $LEN] set nines 0 set predigit 0 set nines {} set i0 [expr {$LEN+1}] set quot0 [expr {2*$LEN+1}] for {set j 0} {$j<$N} {incr j} { set q 0 set i $i0 set quot $quot0 set pos -1 foreach apos $a { set x [expr {10*$apos + $q * [incr i -1]}] lset a [incr pos] [expr {$x % [incr quot -2]}] set q [expr {$x / $quot}] } lset a end [expr {$q % 10}] set q [expr {$q / 10}] if {$q < 8} { append result $predigit $nines set nines {} set predigit $q } elseif {$q == 9} { append nines 9 } else { append result [expr {$predigit+1}][string map {9 0} $nines] set nines {} set predigit 0 } } #puts $result$predigit } ### EXPAND ##################################################################### proc expand {} { for {set i 0} {$i < 100000} {incr i} { set a [list a b c d e f] lappend b {*}$a } } ### MINLOOPS ################################################################### proc miniloops {} { for {set i 0} {$i < 100000} {incr i} { set sum 0 for {set j 0} {$j < 10} {incr j} { # something of more or less real incr sum $j } } } ### wiki.tcl.tk/8566 ########################################################### # Internal procedure that indexes into the 2-dimensional array t, # which corresponds to the sequence y, looking for the (i,j)th element. proc Index { t y i j } { set indx [expr { ([llength $y] + 1) * ($i + 1) + ($j + 1) }] return [lindex $t $indx] } # Internal procedure that implements Levenshtein to derive the longest # common subsequence of two lists x and y. proc ComputeLCS { x y } { set t [list] for { set i -1 } { $i < [llength $y] } { incr i } { lappend t 0 } for { set i 0 } { $i < [llength $x] } { incr i } { lappend t 0 for { set j 0 } { $j < [llength $y] } { incr j } { if { [string equal [lindex $x $i] [lindex $y $j]] } { set lastT [Index $t $y [expr { $i - 1 }] [expr {$j - 1}]] set nextT [expr {$lastT + 1}] } else { set lastT1 [Index $t $y $i [expr { $j - 1 }]] set lastT2 [Index $t $y [expr { $i - 1 }] $j] if { $lastT1 > $lastT2 } { set nextT $lastT1 } else { set nextT $lastT2 } } lappend t $nextT } } return $t } # Internal procedure that traces through the array built by ComputeLCS # and finds a longest common subsequence -- specifically, the one that # is lexicographically first. proc TraceLCS { t x y } { set trace {} set i [expr { [llength $x] - 1 }] set j [expr { [llength $y] - 1 }] set k [expr { [Index $t $y $i $j] - 1 }] while { $i >= 0 && $j >= 0 } { set im1 [expr { $i - 1 }] set jm1 [expr { $j - 1 }] if { [Index $t $y $i $j] == [Index $t $y $im1 $jm1] + 1 && [string equal [lindex $x $i] [lindex $y $j]] } { lappend trace xy [list $i $j] set i $im1 set j $jm1 } elseif { [Index $t $y $im1 $j] > [Index $t $y $i $jm1] } { lappend trace x $i set i $im1 } else { lappend trace y $j set j $jm1 } } while { $i >= 0 } { lappend trace x $i incr i -1 } while { $j >= 0 } { lappend trace y $j incr j -1 } return $trace } # list::longestCommonSubsequence::compare -- # # Compare two lists for the longest common subsequence # # Arguments: # x, y - Two lists of strings to compare # matched - Callback to execute on matched elements, see below # unmatchedX - Callback to execute on unmatched elements from the # first list, see below. # unmatchedY - Callback to execute on unmatched elements from the # second list, see below. # # Results: # None. # # Side effects: # Whatever the callbacks do. # # The 'compare' procedure compares the two lists of strings, x and y. # It finds a longest common subsequence between the two. It then walks # the lists in order and makes the following callbacks: # # For an element that is common to both lists, it appends the index in # the first list, the index in the second list, and the string value of # the element as three parameters to the 'matched' callback, and executes # the result. # # For an element that is in the first list but not the second, it appends # the index in the first list and the string value of the element as two # parameters to the 'unmatchedX' callback and executes the result. # # For an element that is in the second list but not the first, it appends # the index in the second list and the string value of the element as two # parameters to the 'unmatchedY' callback and executes the result. proc compare { x y matched unmatchedX unmatchedY } { set t [ComputeLCS $x $y] set trace [TraceLCS $t $x $y] set i [llength $trace] while { $i > 0 } { set indices [lindex $trace [incr i -1]] set type [lindex $trace [incr i -1]] switch -exact -- $type { xy { set c $matched eval lappend c $indices lappend c [lindex $x [lindex $indices 0]] uplevel 1 $c } x { set c $unmatchedX lappend c $indices lappend c [lindex $x $indices] uplevel 1 $c } y { set c $unmatchedY lappend c $indices lappend c [lindex $y $indices] uplevel 1 $c } } } return } proc umx { index value } { global lastx global xlines append xlines "< " $value \n set lastx $index } proc umy { index value } { global lasty global ylines append ylines "> " $value \n set lasty $index } proc matched { index1 index2 value } { global lastx global lasty global xlines global ylines if { [info exists lastx] && [info exists lasty] } { #puts "[expr { $lastx + 1 }],${index1}c[expr {$lasty + 1 }],${index2}" #puts -nonewline $xlines #puts "----" #puts -nonewline $ylines } elseif { [info exists lastx] } { #puts "[expr { $lastx + 1 }],${index1}d${index2}" #puts -nonewline $xlines } elseif { [info exists lasty] } { #puts "${index1}a[expr {$lasty + 1 }],${index2}" #puts -nonewline $ylines } catch { unset lastx } catch { unset xlines } catch { unset lasty } catch { unset ylines } } # Really, we should read the first file in like this: # set f0 [open [lindex $argv 0] r] # set x [split [read $f0] \n] # close $f0 # But I'll just provide some sample lines: proc commonsub_test {} { set x {} for { set i 0 } { $i < 20 } { incr i } { lappend x a r a d e d a b r a x } # The second file, too, should be read in like this: # set f1 [open [lindex $argv 1] r] # set y [split [read $f1] \n] # close $f1 # Once again, I'll just do some sample lines. set y {} for { set i 0 } { $i < 20 } { incr i } { lappend y a b r a c a d a b r a } compare $x $y matched umx umy matched [llength $x] [llength $y] {} } ### MANDEL ##################################################################### proc mandel {xres yres infx infy supx supy} { set incremx [expr {double($supx-$infx)/$xres}] set incremy [expr {double($supy-$infy)/$yres}] for {set j 0} {$j < $yres} {incr j} { set cim [expr {$infy+$incremy*$j}] set line {} for {set i 0} {$i < $xres} {incr i} { set counter 0 set zim 0 set zre 0 set cre [expr {$infx+$incremx*$i}] while {$counter < 255} { set dam [expr {$zre*$zre-$zim*$zim+$cre}] set zim [expr {2*$zim*$zre+$cim}] set zre $dam if {$zre*$zre+$zim*$zim > 4} break incr counter } # output pixel $i $j } } } ### RUN ALL #################################################################### if {[string compare [lindex $argv 0] "-batch"] == 0} { set batchmode 1 set argv [lrange $argv 1 end] } set ver [lindex $argv 0] bench {[while] busy loop} {whilebusyloop} bench {[for] busy loop} {forbusyloop} bench {mini loops} {miniloops} bench {fibonacci(25)} {fibonacci 25} bench {heapsort} {heapsort_main} bench {sieve} {sieve 10} bench {sieve [dict]} {sieve_dict 10} bench {ary} {ary 100000} bench {ary [dict]} {ary_dict 100000} bench {repeat} {use_repeat} bench {upvar} {upvartest} bench {nested loops} {nestedloops} bench {rotate} {rotate 100000} bench {dynamic code} {dyncode} bench {dynamic code (list)} {dyncode_list} bench {PI digits} {pi_digits} bench {expand} {expand} bench {wiki.tcl.tk/8566} {commonsub_test} bench {mandel} {mandel 60 60 -2 -1.5 1 1.5} if {$batchmode} { if {$ver == ""} { if {[catch {info patchlevel} ver]} { set ver Jim[info version] } } puts [list $ver $benchmarks] } openocd-0.7.0/jimtcl/examples.api/0000755000175000001440000000000012141414413014005 500000000000000openocd-0.7.0/jimtcl/examples.api/print.tcl0000644000175000001440000000024712134336723015601 00000000000000puts "-- List present in an array constructed from C program --" foreach {str} $MYLIST { puts $str } puts "---------------------------------------------------------" openocd-0.7.0/jimtcl/examples.api/jim_obj.c0000644000175000001440000000455712134336723015526 00000000000000/*- * Copyright (c) 2010 Wojciech A. Koszek * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id$ */ #include #include #include #include #define JIM_EMBEDDED #include #define OBJ_DESC "hello world" int main(int argc, char **argv) { Jim_Interp *interp; Jim_Obj *obj; const char *obj_desc; int obj_size; obj = NULL; obj_desc = NULL; obj_size = -1; /* Create an interpreter */ interp = Jim_CreateInterp(); /* We register base commands, so that we actually implement Tcl. */ Jim_RegisterCoreCommands(interp); /* And initialise any static extensions */ Jim_InitStaticExtensions(interp); /* Create some empty object */ obj = Jim_NewObj(interp); /* Name the object */ Jim_InitStringRep(obj, OBJ_DESC, strlen(OBJ_DESC)) ; /* Obtain internal representation of an object */ obj_desc = Jim_GetString(obj, &obj_size); assert(obj_desc != NULL && "Jim should return NULL as a description"); printf("Object described as '%s'; object size is %d\n", obj_desc, obj_size); Jim_FreeObj(interp, obj); Jim_FreeInterp(interp); return (EXIT_SUCCESS); } openocd-0.7.0/jimtcl/examples.api/Makefile0000644000175000001440000000030012134336723015367 00000000000000CFLAGS+= -Wall -g CFLAGS+= -I.. LDLIBS += -L.. -ljim EXAMPLES= \ jim_command \ jim_hello \ jim_list \ jim_obj \ jim_return all: $(EXAMPLES) clean: rm -rf $(EXAMPLES) rm -rf *.core openocd-0.7.0/jimtcl/examples.api/jim_hello.c0000644000175000001440000000373212134336723016051 00000000000000/*- * Copyright (c) 2010 Wojciech A. Koszek * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id$ */ #include #include #include #include int main(int argc, char **argv) { Jim_Interp *interp; interp = NULL; /* Create Jim instance */ interp = Jim_CreateInterp(); assert(interp != NULL && "couldn't create interpreter!"); /* We register base commands, so that we actually implement Tcl. */ Jim_RegisterCoreCommands(interp); /* And initialise any static extensions */ Jim_InitStaticExtensions(interp); /* Print a string to standard output */ Jim_Eval(interp, "puts {Hello world!}"); /* Free the interpreter */ Jim_FreeInterp(interp); return (EXIT_SUCCESS); } openocd-0.7.0/jimtcl/examples.api/jim_list.c0000644000175000001440000000615512134336723015723 00000000000000/*- * Copyright (c) 2010 Wojciech A. Koszek * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id$ */ #include #include #include #include #define JIM_EMBEDDED #include /* * We have a list of sample words in 'C'.. */ const char *strings[] = { "simple", "strings", "which", "should", "get", "interpreted", "by", "Jim", }; /* * We have macros which let us to easily obtain of array presented above */ #define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0])) #define SAMPLE_OBJS ARRAY_SIZE(strings) /* * Now we try to write big enough code to duplication our array in Jim's * list implementation. Later, we try to load a sample script in Tcl that * could print our list. */ int main(int argc, char **argv) { Jim_Interp *interp; Jim_Obj *obj[SAMPLE_OBJS]; Jim_Obj *list; int i; int error; /* Create an interpreter */ interp = Jim_CreateInterp(); /* We register base commands, so that we actually implement Tcl. */ Jim_RegisterCoreCommands(interp); /* And initialise any static extensions */ Jim_InitStaticExtensions(interp); /* Create an empty list */ list = Jim_NewListObj(interp, NULL, 0); assert(list != NULL); /* * For each string.. */ for (i = 0; i < SAMPLE_OBJS; i++) { /* Duplicate it as an array member. */ obj[i] = Jim_NewStringObj(interp, strings[i], -1); assert(obj[i] != NULL); /* We append newly created object to the list */ Jim_ListAppendElement(interp, list, obj[i]); } /* * We bind a Tcl's name with our list, so that Tcl script can * identify the variable. */ Jim_SetVariableStr(interp, "MYLIST", list); /* * Parse a script */ error = Jim_EvalFile(interp, "./print.tcl"); if (error == JIM_ERR) { Jim_MakeErrorMessage(interp); fprintf(stderr, "%s\n", Jim_GetString(Jim_GetResult(interp), NULL)); } Jim_FreeInterp(interp); return (EXIT_SUCCESS); } openocd-0.7.0/jimtcl/examples.api/jim_return.c0000644000175000001440000000554212134336723016266 00000000000000/*- * Copyright (c) 2010 Wojciech A. Koszek * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id$ */ #include #include #include #include #define JIM_EMBEDDED #include /* * Program which we want to get executed. */ #define JIM_PROGRAM "set l [CountChars Sample]; puts $l" /* * Our function. */ static int CountCharsFunc(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { const char *str; int len; if (argc != 2) { Jim_WrongNumArgs(interp, 1, argv, "string"); return (JIM_ERR); } str = Jim_GetString(argv[1], &len); Jim_SetResult(interp, Jim_NewIntObj(interp, (jim_wide)len)); return (JIM_OK); } /* * Now we try to write big enough code to duplication our array in Jim's * list implementation. Later, we try to load a sample script in Tcl that * could print our list. */ int main(int argc, char **argv) { Jim_Interp *interp; int error; /* Create an interpreter. */ interp = Jim_CreateInterp(); assert(interp != NULL && "couldn't create interpreter"); /* We register base commands, so that we actually implement Tcl. */ Jim_RegisterCoreCommands(interp); /* And initialise any static extensions */ Jim_InitStaticExtensions(interp); /* Register our Jim command. */ Jim_CreateCommand(interp, "CountChars", CountCharsFunc, NULL, NULL); /* Run a script. */ error = Jim_Eval(interp, JIM_PROGRAM); if (error == JIM_ERR) { Jim_MakeErrorMessage(interp); fprintf(stderr, "%s\n", Jim_GetString(Jim_GetResult(interp), NULL)); Jim_FreeInterp(interp); exit(EXIT_FAILURE); } Jim_FreeInterp(interp); return (EXIT_SUCCESS); } openocd-0.7.0/jimtcl/examples.api/README0000644000175000001440000000214312134336723014616 00000000000000Jim examples ============ BSD 2-clause license, (c) 2010 Wojciech A. Koszek This directory contains examples of Jim interpreter API. In order to start working with Jim API one may just want to copy existing example .c file into new file, modify Makefile and start working on a new program. Existing examples ================= jim_command Simple command implementation in Jim's API. Command is then executed in a script encoded within a program. jim_hello Standard "Hello world!" program. jim_inline Similar "Hello world!" program, but the result comes from a Tcl script interpreted in Jim. Result is printed back on a terminal. jim_list Will teach you how to create a list in Jim's API. Once created, will show how to name and export it, so that variable is visible in the script's source code. Once done, interpretation of separate print.tcl file is presented. As a result, the script can print a list members created from within ANSI C program. jim_obj Basic object creation in Jim. jim_return Similar to jim_command example, but implemented command actually returns a value. openocd-0.7.0/jimtcl/examples.api/jim_command.c0000644000175000001440000000551412134336723016364 00000000000000/*- * Copyright (c) 2010 Wojciech A. Koszek * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id$ */ #include #include #include #include #define JIM_EMBEDDED #include /* * Program which we want to get executed. */ #define JIM_PROGRAM "if {1 < 2} { MySampleCommand sample }" static int MySampleCommandFunc(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { const char *str; int len; if (argc != 2) { Jim_WrongNumArgs(interp, 1, argv, "string"); return (JIM_ERR); } str = Jim_GetString(argv[1], &len); assert(str != NULL); printf("%s\n", str); return (JIM_OK); } /* * Now we try to write big enough code to duplication our array in Jim's * list implementation. Later, we try to load a sample script in Tcl that * could print our list. */ int main(int argc, char **argv) { Jim_Interp *interp; int error; /* Create an interpreter. */ interp = Jim_CreateInterp(); assert(interp != NULL && "couldn't create interpreter"); /* We register base commands, so that we actually implement Tcl. */ Jim_RegisterCoreCommands(interp); /* And initialise any static extensions */ Jim_InitStaticExtensions(interp); /* Register our Jim commands. */ Jim_CreateCommand(interp, "MySampleCommand", MySampleCommandFunc, NULL, NULL); /* Run a script. */ error = Jim_Eval(interp, JIM_PROGRAM); if (error == JIM_ERR) { Jim_MakeErrorMessage(interp); fprintf(stderr, "%s\n", Jim_GetString(Jim_GetResult(interp), NULL)); Jim_FreeInterp(interp); exit(EXIT_FAILURE); } Jim_FreeInterp(interp); return (EXIT_SUCCESS); } openocd-0.7.0/jimtcl/jim-load.c0000644000175000001440000000663412134336723013221 00000000000000#include #include "jimautoconf.h" #include /* ----------------------------------------------------------------------------- * Dynamic libraries support (WIN32 not supported) * ---------------------------------------------------------------------------*/ #if defined(HAVE_DLOPEN) || defined(HAVE_DLOPEN_COMPAT) #ifdef HAVE_DLFCN_H #include #endif #ifndef RTLD_NOW #define RTLD_NOW 0 #endif #ifndef RTLD_LOCAL #define RTLD_LOCAL 0 #endif /** * Note that Jim_LoadLibrary() requires a path to an existing file. * * If it is necessary to search JIM_LIBPATH, use Jim_PackageRequire() instead. */ int Jim_LoadLibrary(Jim_Interp *interp, const char *pathName) { void *handle = dlopen(pathName, RTLD_NOW | RTLD_LOCAL); if (handle == NULL) { Jim_SetResultFormatted(interp, "error loading extension \"%s\": %s", pathName, dlerror()); } else { /* We use a unique init symbol depending on the extension name. * This is done for compatibility between static and dynamic extensions. * For extension readline.so, the init symbol is "Jim_readlineInit" */ const char *pt; const char *pkgname; int pkgnamelen; char initsym[40]; typedef int jim_module_init_func_type(Jim_Interp *); jim_module_init_func_type *onload; pt = strrchr(pathName, '/'); if (pt) { pkgname = pt + 1; } else { pkgname = pathName; } pt = strchr(pkgname, '.'); if (pt) { pkgnamelen = pt - pkgname; } else { pkgnamelen = strlen(pkgname); } snprintf(initsym, sizeof(initsym), "Jim_%.*sInit", pkgnamelen, pkgname); if ((onload = (jim_module_init_func_type *)dlsym(handle, initsym)) == NULL) { Jim_SetResultFormatted(interp, "No %s symbol found in extension %s", initsym, pathName); } else if (onload(interp) != JIM_ERR) { /* Add this handle to the stack of handles to be freed */ if (!interp->loadHandles) { interp->loadHandles = Jim_Alloc(sizeof(*interp->loadHandles)); Jim_InitStack(interp->loadHandles); } Jim_StackPush(interp->loadHandles, handle); Jim_SetEmptyResult(interp); return JIM_OK; } } if (handle) { dlclose(handle); } return JIM_ERR; } static void JimFreeOneLoadHandle(void *handle) { dlclose(handle); } void Jim_FreeLoadHandles(Jim_Interp *interp) { if (interp->loadHandles) { Jim_FreeStackElements(interp->loadHandles, JimFreeOneLoadHandle); Jim_Free(interp->loadHandles); } } #else /* JIM_DYNLIB */ int Jim_LoadLibrary(Jim_Interp *interp, const char *pathName) { JIM_NOTUSED(interp); JIM_NOTUSED(pathName); Jim_SetResultString(interp, "the Jim binary has no support for [load]", -1); return JIM_ERR; } void Jim_FreeLoadHandles(Jim_Interp *interp) { } #endif /* JIM_DYNLIB */ /* [load] */ static int Jim_LoadCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "libaryFile"); return JIM_ERR; } return Jim_LoadLibrary(interp, Jim_String(argv[1])); } int Jim_loadInit(Jim_Interp *interp) { Jim_CreateCommand(interp, "load", Jim_LoadCoreCommand, NULL, NULL); return JIM_OK; } openocd-0.7.0/jimtcl/examples.ext/0000755000175000001440000000000012141414413014034 500000000000000openocd-0.7.0/jimtcl/examples.ext/helloworld.c0000644000175000001440000000101212134336723016276 00000000000000/* * hello.c -- A minimal Jim C extension. */ #include static int Hello_Cmd(Jim_Interp *interp, int objc, Jim_Obj *const objv[]) { Jim_SetResultString(interp, "Hello, World!", -1); return JIM_OK; } /* * Jim_helloworldInit -- Called when Jim loads your extension. * * Note that the name *must* correspond exactly to the name of the extension: * Jim_Init */ int Jim_helloworldInit(Jim_Interp *interp) { Jim_CreateCommand(interp, "hello", Hello_Cmd, NULL, NULL); return JIM_OK; } openocd-0.7.0/jimtcl/examples.ext/Makefile0000644000175000001440000000122112134336723015421 00000000000000# Note that if cross compiling, build with: # # make NOTEST=1 # # to avoid trying to load the resulting module. # Also note that you will need a build-host version of jimsh in the # PATH in order to build the extension. # Prefer jimsh in the PATH because it is more likely to be built # for the build-host rather than the target. ifdef NOTEST BUILDOPTS := --notest endif export PATH := $(PATH):.. all: helloworld.so helloworld.so: helloworld.c ../build-jim-ext -I.. -L.. $(BUILDOPTS) $^ # Note: Currently we don't attempt to set LD_LIBRARY_PATH or equivalent test: JIMLIB=. ../jimsh -e 'package require helloworld; hello' clean: rm -f *.o *.so openocd-0.7.0/jimtcl/examples.ext/README0000644000175000001440000000017212134336723014645 00000000000000This directory contains examples of C extensions for Jim. In general, do: build-jim-ext extsource.c See the Makefile openocd-0.7.0/jimtcl/jim-win32compat.h0000644000175000001440000000271712134336723014453 00000000000000#ifndef JIM_WIN32COMPAT_H #define JIM_WIN32COMPAT_H /* Compatibility for Windows (mingw and msvc, not cygwin */ /* Note that at this point we don't yet have access to jimautoconf.h */ #if defined(_WIN32) || defined(WIN32) #define HAVE_DLOPEN void *dlopen(const char *path, int mode); int dlclose(void *handle); void *dlsym(void *handle, const char *symbol); char *dlerror(void); /* MS CRT always uses three digits after 'e' */ #define JIM_SPRINTF_DOUBLE_NEEDS_FIX #ifdef _MSC_VER /* These are msvc vs gcc */ #if _MSC_VER >= 1000 #pragma warning(disable:4146) #endif #include #define jim_wide _int64 #ifndef LLONG_MAX #define LLONG_MAX 9223372036854775807I64 #endif #ifndef LLONG_MIN #define LLONG_MIN (-LLONG_MAX - 1I64) #endif #define JIM_WIDE_MIN LLONG_MIN #define JIM_WIDE_MAX LLONG_MAX #define JIM_WIDE_MODIFIER "I64d" #define strcasecmp _stricmp #define strtoull _strtoui64 #define snprintf _snprintf #include struct timeval { long tv_sec; long tv_usec; }; int gettimeofday(struct timeval *tv, void *unused); #define HAVE_OPENDIR struct dirent { char *d_name; }; typedef struct DIR { long handle; /* -1 for failed rewind */ struct _finddata_t info; struct dirent result; /* d_name null iff first time */ char *name; /* null-terminated char string */ } DIR; DIR *opendir(const char *name); int closedir(DIR *dir); struct dirent *readdir(DIR *dir); #endif /* _MSC_VER */ #endif /* WIN32 */ #endif openocd-0.7.0/jimtcl/jim-history.c0000644000175000001440000000563012134336723013776 00000000000000#include #include #include #include "jim.h" #include "jimautoconf.h" #include "jim-subcmd.h" static int history_cmd_getline(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *objPtr; char *line = Jim_HistoryGetline(Jim_String(argv[0])); /* On EOF returns -1 if varName was specified, or the empty string. */ if (line == NULL) { if (argc == 2) { Jim_SetResultInt(interp, -1); } return JIM_OK; } objPtr = Jim_NewStringObjNoAlloc(interp, line, -1); /* Returns the length of the string if varName was specified */ if (argc == 2) { if (Jim_SetVariable(interp, argv[1], objPtr) != JIM_OK) { Jim_FreeNewObj(interp, objPtr); return JIM_ERR; } Jim_SetResultInt(interp, Jim_Length(objPtr)); } else { Jim_SetResult(interp, objPtr); } return JIM_OK; } static int history_cmd_load(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_HistoryLoad(Jim_String(argv[0])); return JIM_OK; } static int history_cmd_save(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_HistorySave(Jim_String(argv[0])); return JIM_OK; } static int history_cmd_add(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_HistoryAdd(Jim_String(argv[0])); return JIM_OK; } static int history_cmd_show(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_HistoryShow(); return JIM_OK; } static const jim_subcmd_type history_command_table[] = { { "getline", "prompt ?varname?", history_cmd_getline, 1, 2, /* Description: Reads one line from the user. Similar to gets. */ }, { "load", "filename", history_cmd_load, 1, 1, /* Description: Loads history from the given file, if possible */ }, { "save", "filename", history_cmd_save, 1, 1, /* Description: Saves history to the given file */ }, { "add", "line", history_cmd_add, 1, 1, /* Description: Adds the line to the history ands saves */ }, { "show", NULL, history_cmd_show, 0, 0, /* Description: Displays the history */ }, { NULL } }; static int JimHistorySubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { return Jim_CallSubCmd(interp, Jim_ParseSubCmd(interp, history_command_table, argc, argv), argc, argv); } static void JimHistoryDelProc(Jim_Interp *interp, void *privData) { Jim_Free(privData); } int Jim_historyInit(Jim_Interp *interp) { void **history; if (Jim_PackageProvide(interp, "history", "1.0", JIM_ERRMSG)) return JIM_ERR; history = Jim_Alloc(sizeof(*history)); *history = NULL; Jim_CreateCommand(interp, "history", JimHistorySubCmdProc, history, JimHistoryDelProc); return JIM_OK; } openocd-0.7.0/jimtcl/make-bootstrap-jim0000755000175000001440000000555612134336723015016 00000000000000#!/bin/sh # This script writes to stdout, a single source file (e.g. jimsh0.c) # which can be compiled to provide a bootstrap version of jimsh. # e.g. cc -o jimsh0 jimsh0.c makeext() { source="$1" basename=`basename "$source" .tcl` cat < * Copyright 2005 Clemens Hintze * Copyright 2005 patthoyts - Pat Thoyts * Copyright 2008 oharboe - Øyvind Harboe - oyvind.harboe@zylin.com * Copyright 2008 Andrew Lunn * Copyright 2008 Duane Ellis * Copyright 2008 Uwe Klein * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation * are those of the authors and should not be interpreted as representing * official policies, either expressed or implied, of the Jim Tcl Project. **/ #include "jimautoconf.h" #include #include /* POSIX includes */ #include #include #include #include #include #if defined(__MINGW32__) #include #include #define msleep Sleep #ifndef HAVE_USLEEP #define usleep(US) msleep((US) / 1000) #endif #else #include #ifndef HAVE_USLEEP /* XXX: Implement this in terms of select() or nanosleep() */ #define usleep(US) #endif #define msleep(MS) sleep((MS) / 1000); usleep(((MS) % 1000) * 1000); #endif /* --- */ /* File event structure */ typedef struct Jim_FileEvent { FILE *handle; int mask; /* one of JIM_EVENT_(READABLE|WRITABLE|EXCEPTION) */ Jim_FileProc *fileProc; Jim_EventFinalizerProc *finalizerProc; void *clientData; struct Jim_FileEvent *next; } Jim_FileEvent; /* Time event structure */ typedef struct Jim_TimeEvent { jim_wide id; /* time event identifier. */ int mode; /* restart, repetitive .. UK */ long initialms; /* initial relativ timer value UK */ long when_sec; /* seconds */ long when_ms; /* milliseconds */ Jim_TimeProc *timeProc; Jim_EventFinalizerProc *finalizerProc; void *clientData; struct Jim_TimeEvent *next; } Jim_TimeEvent; /* Per-interp stucture containing the state of the event loop */ typedef struct Jim_EventLoop { jim_wide timeEventNextId; Jim_FileEvent *fileEventHead; Jim_TimeEvent *timeEventHead; int suppress_bgerror; /* bgerror returned break, so don't call it again */ } Jim_EventLoop; static void JimAfterTimeHandler(Jim_Interp *interp, void *clientData); static void JimAfterTimeEventFinalizer(Jim_Interp *interp, void *clientData); int Jim_EvalObjBackground(Jim_Interp *interp, Jim_Obj *scriptObjPtr) { Jim_EventLoop *eventLoop = Jim_GetAssocData(interp, "eventloop"); Jim_CallFrame *savedFramePtr; int retval; savedFramePtr = interp->framePtr; interp->framePtr = interp->topFramePtr; retval = Jim_EvalObj(interp, scriptObjPtr); interp->framePtr = savedFramePtr; /* Try to report the error (if any) via the bgerror proc */ if (retval != JIM_OK && !eventLoop->suppress_bgerror) { Jim_Obj *objv[2]; int rc = JIM_ERR; objv[0] = Jim_NewStringObj(interp, "bgerror", -1); objv[1] = Jim_GetResult(interp); Jim_IncrRefCount(objv[0]); Jim_IncrRefCount(objv[1]); if (Jim_GetCommand(interp, objv[0], JIM_NONE) == NULL || (rc = Jim_EvalObjVector(interp, 2, objv)) != JIM_OK) { if (rc == JIM_BREAK) { /* No more bgerror calls */ eventLoop->suppress_bgerror++; } else { /* Report the error to stderr. */ Jim_MakeErrorMessage(interp); fprintf(stderr, "%s\n", Jim_String(Jim_GetResult(interp))); /* And reset the result */ Jim_SetResultString(interp, "", -1); } } Jim_DecrRefCount(interp, objv[0]); Jim_DecrRefCount(interp, objv[1]); } return retval; } void Jim_CreateFileHandler(Jim_Interp *interp, FILE * handle, int mask, Jim_FileProc * proc, void *clientData, Jim_EventFinalizerProc * finalizerProc) { Jim_FileEvent *fe; Jim_EventLoop *eventLoop = Jim_GetAssocData(interp, "eventloop"); fe = Jim_Alloc(sizeof(*fe)); fe->handle = handle; fe->mask = mask; fe->fileProc = proc; fe->finalizerProc = finalizerProc; fe->clientData = clientData; fe->next = eventLoop->fileEventHead; eventLoop->fileEventHead = fe; } void Jim_DeleteFileHandler(Jim_Interp *interp, FILE * handle) { Jim_FileEvent *fe, *prev = NULL; Jim_EventLoop *eventLoop = Jim_GetAssocData(interp, "eventloop"); fe = eventLoop->fileEventHead; while (fe) { if (fe->handle == handle) { if (prev == NULL) eventLoop->fileEventHead = fe->next; else prev->next = fe->next; if (fe->finalizerProc) fe->finalizerProc(interp, fe->clientData); Jim_Free(fe); return; } prev = fe; fe = fe->next; } } static void JimGetTime(long *seconds, long *milliseconds) { struct timeval tv; gettimeofday(&tv, NULL); *seconds = tv.tv_sec; *milliseconds = tv.tv_usec / 1000; } jim_wide Jim_CreateTimeHandler(Jim_Interp *interp, jim_wide milliseconds, Jim_TimeProc * proc, void *clientData, Jim_EventFinalizerProc * finalizerProc) { Jim_EventLoop *eventLoop = Jim_GetAssocData(interp, "eventloop"); jim_wide id = eventLoop->timeEventNextId++; Jim_TimeEvent *te, *e, *prev; long cur_sec, cur_ms; JimGetTime(&cur_sec, &cur_ms); te = Jim_Alloc(sizeof(*te)); te->id = id; te->mode = 0; te->initialms = milliseconds; te->when_sec = cur_sec + milliseconds / 1000; te->when_ms = cur_ms + milliseconds % 1000; if (te->when_ms >= 1000) { te->when_sec++; te->when_ms -= 1000; } te->timeProc = proc; te->finalizerProc = finalizerProc; te->clientData = clientData; /* Add to the appropriate place in the list */ if (eventLoop->timeEventHead) { prev = NULL; for (e = eventLoop->timeEventHead; e; e = e->next) { if (te->when_sec < e->when_sec || (te->when_sec == e->when_sec && te->when_ms < e->when_ms)) { break; } prev = e; } if (prev) { te->next = prev->next; prev->next = te; return id; } } te->next = eventLoop->timeEventHead; eventLoop->timeEventHead = te; return id; } static jim_wide JimParseAfterId(Jim_Obj *idObj) { int len; const char *tok = Jim_GetString(idObj, &len); jim_wide id; if (strncmp(tok, "after#", 6) == 0 && Jim_StringToWide(tok + 6, &id, 10) == JIM_OK) { /* Got an event by id */ return id; } return -1; } static jim_wide JimFindAfterByScript(Jim_EventLoop *eventLoop, Jim_Obj *scriptObj) { Jim_TimeEvent *te; for (te = eventLoop->timeEventHead; te; te = te->next) { /* Is this an 'after' event? */ if (te->timeProc == JimAfterTimeHandler) { if (Jim_StringEqObj(scriptObj, te->clientData)) { return te->id; } } } return -1; /* NO event with the specified ID found */ } static Jim_TimeEvent *JimFindTimeHandlerById(Jim_EventLoop *eventLoop, jim_wide id) { Jim_TimeEvent *te; for (te = eventLoop->timeEventHead; te; te = te->next) { if (te->id == id) { return te; } } return NULL; } static Jim_TimeEvent *Jim_RemoveTimeHandler(Jim_EventLoop *eventLoop, jim_wide id) { Jim_TimeEvent *te, *prev = NULL; for (te = eventLoop->timeEventHead; te; te = te->next) { if (te->id == id) { if (prev == NULL) eventLoop->timeEventHead = te->next; else prev->next = te->next; return te; } prev = te; } return NULL; } static void Jim_FreeTimeHandler(Jim_Interp *interp, Jim_TimeEvent *te) { if (te->finalizerProc) te->finalizerProc(interp, te->clientData); Jim_Free(te); } jim_wide Jim_DeleteTimeHandler(Jim_Interp *interp, jim_wide id) { Jim_TimeEvent *te; Jim_EventLoop *eventLoop = Jim_GetAssocData(interp, "eventloop"); if (id >= eventLoop->timeEventNextId) { return -2; /* wrong event ID */ } te = Jim_RemoveTimeHandler(eventLoop, id); if (te) { jim_wide remain; long cur_sec, cur_ms; JimGetTime(&cur_sec, &cur_ms); remain = (te->when_sec - cur_sec) * 1000; remain += (te->when_ms - cur_ms); remain = (remain < 0) ? 0 : remain; Jim_FreeTimeHandler(interp, te); return remain; } return -1; /* NO event with the specified ID found */ } /* --- POSIX version of Jim_ProcessEvents, for now the only available --- */ /* Process every pending time event, then every pending file event * (that may be registered by time event callbacks just processed). * Without special flags the function sleeps until some file event * fires, or when the next time event occurrs (if any). * * If flags is 0, the function does nothing and returns. * if flags has JIM_ALL_EVENTS set, all the kind of events are processed. * if flags has JIM_FILE_EVENTS set, file events are processed. * if flags has JIM_TIME_EVENTS set, time events are processed. * if flags has JIM_DONT_WAIT set the function returns ASAP until all * the events that's possible to process without to wait are processed. * * The function returns the number of events processed or -1 if * there are no matching handlers, or -2 on error. */ int Jim_ProcessEvents(Jim_Interp *interp, int flags) { jim_wide sleep_ms = -1; int processed = 0; Jim_EventLoop *eventLoop = Jim_GetAssocData(interp, "eventloop"); Jim_FileEvent *fe = eventLoop->fileEventHead; Jim_TimeEvent *te; jim_wide maxId; if ((flags & JIM_FILE_EVENTS) == 0 || fe == NULL) { /* No file events */ if ((flags & JIM_TIME_EVENTS) == 0 || eventLoop->timeEventHead == NULL) { /* No time events */ return -1; } } /* Note that we want call select() even if there are no * file events to process as long as we want to process time * events, in order to sleep until the next time event is ready * to fire. */ if (flags & JIM_DONT_WAIT) { /* Wait no time */ sleep_ms = 0; } else if (flags & JIM_TIME_EVENTS) { /* The nearest timer is always at the head of the list */ if (eventLoop->timeEventHead) { Jim_TimeEvent *shortest = eventLoop->timeEventHead; long now_sec, now_ms; /* Calculate the time missing for the nearest * timer to fire. */ JimGetTime(&now_sec, &now_ms); sleep_ms = 1000 * (shortest->when_sec - now_sec) + (shortest->when_ms - now_ms); if (sleep_ms < 0) { sleep_ms = 1; } } else { /* Wait forever */ sleep_ms = -1; } } #ifdef HAVE_SELECT if (flags & JIM_FILE_EVENTS) { int retval; struct timeval tv, *tvp = NULL; fd_set rfds, wfds, efds; int maxfd = -1; FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); /* Check file events */ while (fe != NULL) { int fd = fileno(fe->handle); if (fe->mask & JIM_EVENT_READABLE) FD_SET(fd, &rfds); if (fe->mask & JIM_EVENT_WRITABLE) FD_SET(fd, &wfds); if (fe->mask & JIM_EVENT_EXCEPTION) FD_SET(fd, &efds); if (maxfd < fd) maxfd = fd; fe = fe->next; } if (sleep_ms >= 0) { tvp = &tv; tvp->tv_sec = sleep_ms / 1000; tvp->tv_usec = 1000 * (sleep_ms % 1000); } retval = select(maxfd + 1, &rfds, &wfds, &efds, tvp); if (retval < 0) { if (errno == EINVAL) { /* This can happen on mingw32 if a non-socket filehandle is passed */ Jim_SetResultString(interp, "non-waitable filehandle", -1); return -2; } /* XXX: What about EINTR? */ } else if (retval > 0) { fe = eventLoop->fileEventHead; while (fe != NULL) { int fd = fileno(fe->handle); int mask = 0; if ((fe->mask & JIM_EVENT_READABLE) && FD_ISSET(fd, &rfds)) mask |= JIM_EVENT_READABLE; if (fe->mask & JIM_EVENT_WRITABLE && FD_ISSET(fd, &wfds)) mask |= JIM_EVENT_WRITABLE; if (fe->mask & JIM_EVENT_EXCEPTION && FD_ISSET(fd, &efds)) mask |= JIM_EVENT_EXCEPTION; if (mask) { if (fe->fileProc(interp, fe->clientData, mask) != JIM_OK) { /* Remove the element on handler error */ Jim_DeleteFileHandler(interp, fe->handle); } processed++; /* After an event is processed our file event list * may no longer be the same, so what we do * is to clear the bit for this file descriptor and * restart again from the head. */ fe = eventLoop->fileEventHead; FD_CLR(fd, &rfds); FD_CLR(fd, &wfds); FD_CLR(fd, &efds); } else { fe = fe->next; } } } } #else if (sleep_ms > 0) { msleep(sleep_ms); } #endif /* Check time events */ te = eventLoop->timeEventHead; maxId = eventLoop->timeEventNextId - 1; while (te) { long now_sec, now_ms; jim_wide id; if (te->id > maxId) { te = te->next; continue; } JimGetTime(&now_sec, &now_ms); if (now_sec > te->when_sec || (now_sec == te->when_sec && now_ms >= te->when_ms)) { id = te->id; /* Remove from the list before executing */ Jim_RemoveTimeHandler(eventLoop, id); te->timeProc(interp, te->clientData); /* After an event is processed our time event list may * no longer be the same, so we restart from head. * Still we make sure to don't process events registered * by event handlers itself in order to don't loop forever * even in case an [after 0] that continuously register * itself. To do so we saved the max ID we want to handle. */ Jim_FreeTimeHandler(interp, te); te = eventLoop->timeEventHead; processed++; } else { te = te->next; } } return processed; } /* ---------------------------------------------------------------------- */ static void JimELAssocDataDeleProc(Jim_Interp *interp, void *data) { void *next; Jim_FileEvent *fe; Jim_TimeEvent *te; Jim_EventLoop *eventLoop = data; fe = eventLoop->fileEventHead; while (fe) { next = fe->next; if (fe->finalizerProc) fe->finalizerProc(interp, fe->clientData); Jim_Free(fe); fe = next; } te = eventLoop->timeEventHead; while (te) { next = te->next; if (te->finalizerProc) te->finalizerProc(interp, te->clientData); Jim_Free(te); te = next; } Jim_Free(data); } static int JimELVwaitCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_EventLoop *eventLoop = Jim_CmdPrivData(interp); Jim_Obj *oldValue; int rc; if (argc != 2) { Jim_WrongNumArgs(interp, 1, argv, "name"); return JIM_ERR; } oldValue = Jim_GetGlobalVariable(interp, argv[1], JIM_NONE); if (oldValue) { Jim_IncrRefCount(oldValue); } else { /* If a result was left, it is an error */ int len; Jim_GetString(interp->result, &len); if (len) { return JIM_ERR; } } eventLoop->suppress_bgerror = 0; while ((rc = Jim_ProcessEvents(interp, JIM_ALL_EVENTS)) >= 0) { Jim_Obj *currValue; currValue = Jim_GetGlobalVariable(interp, argv[1], JIM_NONE); /* Stop the loop if the vwait-ed variable changed value, * or if was unset and now is set (or the contrary). */ if ((oldValue && !currValue) || (!oldValue && currValue) || (oldValue && currValue && !Jim_StringEqObj(oldValue, currValue))) break; } if (oldValue) Jim_DecrRefCount(interp, oldValue); if (rc == -2) { return JIM_ERR; } Jim_SetEmptyResult(interp); return JIM_OK; } static int JimELUpdateCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_EventLoop *eventLoop = Jim_CmdPrivData(interp); static const char * const options[] = { "idletasks", NULL }; enum { UPDATE_IDLE, UPDATE_NONE }; int option = UPDATE_NONE; int flags = JIM_TIME_EVENTS; if (argc == 1) { flags = JIM_ALL_EVENTS; } else if (argc > 2 || Jim_GetEnum(interp, argv[1], options, &option, NULL, JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) { Jim_WrongNumArgs(interp, 1, argv, "?idletasks?"); return JIM_ERR; } eventLoop->suppress_bgerror = 0; while (Jim_ProcessEvents(interp, flags | JIM_DONT_WAIT) > 0) { } return JIM_OK; } static void JimAfterTimeHandler(Jim_Interp *interp, void *clientData) { Jim_Obj *objPtr = clientData; Jim_EvalObjBackground(interp, objPtr); } static void JimAfterTimeEventFinalizer(Jim_Interp *interp, void *clientData) { Jim_Obj *objPtr = clientData; Jim_DecrRefCount(interp, objPtr); } static int JimELAfterCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_EventLoop *eventLoop = Jim_CmdPrivData(interp); jim_wide ms = 0, id; Jim_Obj *objPtr, *idObjPtr; static const char * const options[] = { "cancel", "info", "idle", NULL }; enum { AFTER_CANCEL, AFTER_INFO, AFTER_IDLE, AFTER_RESTART, AFTER_EXPIRE, AFTER_CREATE }; int option = AFTER_CREATE; if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "option ?arg ...?"); return JIM_ERR; } if (Jim_GetWide(interp, argv[1], &ms) != JIM_OK) { if (Jim_GetEnum(interp, argv[1], options, &option, "argument", JIM_ERRMSG) != JIM_OK) { return JIM_ERR; } Jim_SetEmptyResult(interp); } else if (argc == 2) { /* Simply a sleep */ msleep(ms); return JIM_OK; } switch (option) { case AFTER_IDLE: if (argc < 3) { Jim_WrongNumArgs(interp, 2, argv, "script ?script ...?"); return JIM_ERR; } /* fall through */ case AFTER_CREATE: { Jim_Obj *scriptObj = Jim_ConcatObj(interp, argc - 2, argv + 2); Jim_IncrRefCount(scriptObj); id = Jim_CreateTimeHandler(interp, ms, JimAfterTimeHandler, scriptObj, JimAfterTimeEventFinalizer); objPtr = Jim_NewStringObj(interp, NULL, 0); Jim_AppendString(interp, objPtr, "after#", -1); idObjPtr = Jim_NewIntObj(interp, id); Jim_IncrRefCount(idObjPtr); Jim_AppendObj(interp, objPtr, idObjPtr); Jim_DecrRefCount(interp, idObjPtr); Jim_SetResult(interp, objPtr); return JIM_OK; } case AFTER_CANCEL: if (argc < 3) { Jim_WrongNumArgs(interp, 2, argv, "id|command"); return JIM_ERR; } else { jim_wide remain = 0; id = JimParseAfterId(argv[2]); if (id < 0) { /* Not an event id, so search by script */ Jim_Obj *scriptObj = Jim_ConcatObj(interp, argc - 2, argv + 2); id = JimFindAfterByScript(eventLoop, scriptObj); Jim_FreeNewObj(interp, scriptObj); if (id < 0) { /* Not found */ break; } } remain = Jim_DeleteTimeHandler(interp, id); if (remain >= 0) { Jim_SetResultInt(interp, remain); } } break; case AFTER_INFO: if (argc == 2) { Jim_TimeEvent *te = eventLoop->timeEventHead; Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0); char buf[30]; const char *fmt = "after#%" JIM_WIDE_MODIFIER; while (te) { snprintf(buf, sizeof(buf), fmt, te->id); Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, buf, -1)); te = te->next; } Jim_SetResult(interp, listObj); } else if (argc == 3) { id = JimParseAfterId(argv[2]); if (id >= 0) { Jim_TimeEvent *e = JimFindTimeHandlerById(eventLoop, id); if (e && e->timeProc == JimAfterTimeHandler) { Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0); Jim_ListAppendElement(interp, listObj, e->clientData); Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, e->initialms ? "timer" : "idle", -1)); Jim_SetResult(interp, listObj); return JIM_OK; } } Jim_SetResultFormatted(interp, "event \"%#s\" doesn't exist", argv[2]); return JIM_ERR; } else { Jim_WrongNumArgs(interp, 2, argv, "?id?"); return JIM_ERR; } break; } return JIM_OK; } int Jim_eventloopInit(Jim_Interp *interp) { Jim_EventLoop *eventLoop; if (Jim_PackageProvide(interp, "eventloop", "1.0", JIM_ERRMSG)) return JIM_ERR; eventLoop = Jim_Alloc(sizeof(*eventLoop)); eventLoop->fileEventHead = NULL; eventLoop->timeEventHead = NULL; eventLoop->timeEventNextId = 1; eventLoop->suppress_bgerror = 0; Jim_SetAssocData(interp, "eventloop", JimELAssocDataDeleProc, eventLoop); Jim_CreateCommand(interp, "vwait", JimELVwaitCommand, eventLoop, NULL); Jim_CreateCommand(interp, "update", JimELUpdateCommand, eventLoop, NULL); Jim_CreateCommand(interp, "after", JimELAfterCommand, eventLoop, NULL); return JIM_OK; } openocd-0.7.0/jimtcl/jim-tclprefix.c0000644000175000001440000001555712134336723014306 00000000000000/* * Implements the tcl::prefix command for Jim Tcl * * (c) 2011 Steve Bennett * * See LICENSE for license details. */ #include #include "utf8.h" /** * Returns the common initial length of the two strings. */ static int JimStringCommonLength(const char *str1, int charlen1, const char *str2, int charlen2) { int maxlen = 0; while (charlen1-- && charlen2--) { int c1; int c2; str1 += utf8_tounicode(str1, &c1); str2 += utf8_tounicode(str2, &c2); if (c1 != c2) { break; } maxlen++; } return maxlen; } /* [tcl::prefix] */ static int Jim_TclPrefixCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *objPtr; Jim_Obj *stringObj; int option; static const char * const options[] = { "match", "all", "longest", NULL }; enum { OPT_MATCH, OPT_ALL, OPT_LONGEST }; if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "subcommand ?arg ...?"); return JIM_ERR; } if (Jim_GetEnum(interp, argv[1], options, &option, NULL, JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) return JIM_ERR; switch (option) { case OPT_MATCH:{ int i; int ret; int tablesize; const char **table; Jim_Obj *tableObj; Jim_Obj *errorObj = NULL; Jim_Obj *messageObj = NULL; static const char * const matchoptions[] = { "-error", "-exact", "-message", NULL }; enum { OPT_MATCH_ERROR, OPT_MATCH_EXACT, OPT_MATCH_MESSAGE }; int flags = JIM_ERRMSG | JIM_ENUM_ABBREV; if (argc < 4) { Jim_WrongNumArgs(interp, 2, argv, "?options? table string"); return JIM_ERR; } tableObj = argv[argc - 2]; stringObj = argv[argc - 1]; argc -= 2; for (i = 2; i < argc; i++) { int matchoption; if (Jim_GetEnum(interp, argv[i], matchoptions, &matchoption, "option", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) return JIM_ERR; switch (matchoption) { case OPT_MATCH_EXACT: flags &= ~JIM_ENUM_ABBREV; break; case OPT_MATCH_ERROR: if (++i == argc) { Jim_SetResultString(interp, "missing error options", -1); return JIM_ERR; } errorObj = argv[i]; if (Jim_Length(errorObj) % 2) { Jim_SetResultString(interp, "error options must have an even number of elements", -1); return JIM_ERR; } break; case OPT_MATCH_MESSAGE: if (++i == argc) { Jim_SetResultString(interp, "missing message", -1); return JIM_ERR; } messageObj = argv[i]; break; } } /* Do the match */ tablesize = Jim_ListLength(interp, tableObj); table = Jim_Alloc((tablesize + 1) * sizeof(*table)); for (i = 0; i < tablesize; i++) { Jim_ListIndex(interp, tableObj, i, &objPtr, JIM_NONE); table[i] = Jim_String(objPtr); } table[i] = NULL; ret = Jim_GetEnum(interp, stringObj, table, &i, messageObj ? Jim_String(messageObj) : NULL, flags); Jim_Free(table); if (ret == JIM_OK) { Jim_ListIndex(interp, tableObj, i, &objPtr, JIM_NONE); Jim_SetResult(interp, objPtr); return JIM_OK; } if (tablesize == 0) { Jim_SetResultFormatted(interp, "bad option \"%#s\": no valid options", stringObj); return JIM_ERR; } if (errorObj) { if (Jim_Length(errorObj) == 0) { Jim_SetEmptyResult(interp); return JIM_OK; } /* Do this the easy way. Build a list to evaluate */ objPtr = Jim_NewStringObj(interp, "return -level 0 -code error", -1); Jim_ListAppendList(interp, objPtr, errorObj); Jim_ListAppendElement(interp, objPtr, Jim_GetResult(interp)); return Jim_EvalObjList(interp, objPtr); } return JIM_ERR; } break; case OPT_ALL: if (argc != 4) { Jim_WrongNumArgs(interp, 2, argv, "table string"); return JIM_ERR; } else { int i; int listlen = Jim_ListLength(interp, argv[2]); objPtr = Jim_NewListObj(interp, NULL, 0); for (i = 0; i < listlen; i++) { Jim_Obj *valObj = Jim_ListGetIndex(interp, argv[2], i); if (Jim_StringCompareLenObj(interp, argv[3], valObj, 0) == 0) { Jim_ListAppendElement(interp, objPtr, valObj); } } Jim_SetResult(interp, objPtr); return JIM_OK; } case OPT_LONGEST: if (argc != 4) { Jim_WrongNumArgs(interp, 2, argv, "table string"); return JIM_ERR; } else if (Jim_ListLength(interp, argv[2])) { const char *longeststr = NULL; int longestlen = 0; stringObj = argv[3]; int i; int listlen = Jim_ListLength(interp, argv[2]); for (i = 0; i < listlen; i++) { Jim_Obj *valObj = Jim_ListGetIndex(interp, argv[2], i); if (Jim_StringCompareLenObj(interp, stringObj, valObj, 0)) { /* Does not begin with 'string' */ continue; } if (longeststr == NULL) { longestlen = Jim_Utf8Length(interp, valObj); longeststr = Jim_String(valObj); } else { longestlen = JimStringCommonLength(longeststr, longestlen, Jim_String(valObj), Jim_Utf8Length(interp, valObj)); } } if (longeststr) { Jim_SetResultString(interp, longeststr, longestlen); } return JIM_OK; } } return JIM_ERR; } int Jim_tclprefixInit(Jim_Interp *interp) { if (Jim_PackageProvide(interp, "tclprefix", "1.0", JIM_ERRMSG)) { return JIM_ERR; } Jim_CreateCommand(interp, "tcl::prefix", Jim_TclPrefixCoreCommand, NULL, NULL); return JIM_OK; } openocd-0.7.0/jimtcl/tree.tcl0000644000175000001440000001126512134336723013020 00000000000000# Conceptually compatible with tcllib ::struct::tree # but uses an object based interface. # To mimic tcllib, do: # rename [tree] mytree package require oo # set pt [tree] # # Create a tree # This automatically creates a node named "root" # # $pt destroy # # Destroy the tree and all it's nodes # # $pt set # # Set the value for the given key # # $pt lappend ... # # Append to the (list) value(s) for the given key, or set if not yet set # # $pt keyexists # # Returns 1 if the given key exists # # $pt get # # Returns the value associated with the given key # # $pt getall # # Returns the entire attribute dictionary associated with the given key # # $pt depth # # Returns the depth of the given node. The depth of "root" is 0. # # $pt parent # # Returns the name of the parent node, or "" for the root node. # # $pt numchildren # # Returns the number of child nodes. # # $pt children # # Returns a list of the child nodes. # # $pt next # # Returns the next sibling node, or "" if none. # # $pt insert ?index? # # Add a new child node to the given node. # THe default index is "end" # Returns the name of the newly added node # # $pt walk dfs|bfs {actionvar nodevar} # # Walks the tree starting from the given node, either breadth first (bfs) # depth first (dfs). # The value "enter" or "exit" is stored in variable $actionvar # The name of each node is stored in $nodevar. # The script $code is evaluated twice for each node, on entry and exit. # # $pt dump # # Dumps the tree contents to stdout #------------------------------------------ # Internal implementation. # The tree class has 4 instance variables. # - tree is a dictionary. key=node, value=node value dictionary # - parent is a dictionary. key=node, value=parent of this node # - children is a dictionary. key=node, value=list of child nodes for this node # - nodeid is an integer which increments to give each node a unique id # Construct a tree with a single root node with no parent and no children class tree { tree {root {}} parents {root {}} children {root {}} nodeid 0 } # Simply walk up the tree to get the depth tree method depth {node} { set depth 0 while {$node ne "root"} { incr depth set node [dict get $parents $node] } return $depth } tree method parent {node} { dict get $parents $node } tree method children {node} { dict get $children $node } tree method numchildren {node} { llength [dict get $children $node] } tree method next {node} { # My siblings are my parents children set siblings [dict get $children [dict get $parents $node]] # Find me set i [lsearch $siblings $node] incr i lindex $siblings $i } tree method set {node key value} { dict set tree $node $key $value return $value } tree method get {node key} { dict get $tree $node $key } tree method keyexists {node key} { dict exists $tree $node $key } tree method getall {node} { dict get $tree $node } tree method insert {node {index end}} { # Make a new node and add it to the tree set childname node[incr nodeid] dict set tree $childname {} # The new node has no children dict set children $childname {} # Set the parent dict set parents $childname $node # And add it as a child set nodes [dict get $children $node] dict set children $node [linsert $nodes $index $childname] return $childname } tree method lappend {node key args} { if {[dict exists $tree $node $key]} { set result [dict get $tree $node $key] } lappend result {*}$args dict set tree $node $key $result return $result } # $tree walk node bfs|dfs {action loopvar} # tree method walk {node type vars code} { # set up vars lassign $vars actionvar namevar set n $node if {$type ne "child"} { upvar 2 $namevar name $actionvar action # Enter this node set name $node set action enter uplevel 2 $code } if {$type eq "dfs"} { # Depth-first so do the children foreach child [$self children $n] { uplevel 2 [list $self walk $child $type $vars $code] } } elseif {$type ne "none"} { # Breadth-first so do the children to one level only foreach child [$self children $n] { uplevel 2 [list $self walk $child none $vars $code] } # Now our grandchildren foreach child [$self children $n] { uplevel 2 [list $self walk $child child $vars $code] } } if {$type ne "child"} { # Exit this node set name $node set action exit uplevel 2 $code } } tree method dump {} { $self walk root dfs {action n} { set indent [string repeat " " [$self depth $n]] if {$action eq "enter"} { puts "$indent$n ([$self getall $n])" } } puts "" } openocd-0.7.0/jimtcl/jim-pack.c0000644000175000001440000002443012134336723013212 00000000000000#include #include /* Provides the [pack] and [unpack] commands to pack and unpack * a binary string to/from arbitrary width integers and strings. * * This may be used to implement the [binary] command. */ /** * Big endian bit test. * * Considers 'bitvect' as a big endian bit stream and returns * bit 'b' as zero or non-zero. */ static int JimTestBitBigEndian(const unsigned char *bitvec, int b) { div_t pos = div(b, 8); return bitvec[pos.quot] & (1 << (7 - pos.rem)); } /** * Little endian bit test. * * Considers 'bitvect' as a little endian bit stream and returns * bit 'b' as zero or non-zero. */ static int JimTestBitLittleEndian(const unsigned char *bitvec, int b) { div_t pos = div(b, 8); return bitvec[pos.quot] & (1 << pos.rem); } /** * Sign extends the given value, 'n' of width 'width' bits. * * For example, sign extending 0x80 with a width of 8, produces -128 */ static jim_wide JimSignExtend(jim_wide n, int width) { if (width == sizeof(jim_wide) * 8) { /* Can't sign extend the maximum size integer */ return n; } if (n & ((jim_wide)1 << (width - 1))) { /* Need to extend */ n -= ((jim_wide)1 << width); } return n; } /** * Big endian integer extraction. * * Considers 'bitvect' as a big endian bit stream. * Returns an integer of the given width (in bits) * starting at the given position (in bits). * * The pos/width must represent bits inside bitvec, * and the width be no more than the width of jim_wide. */ static jim_wide JimBitIntBigEndian(const unsigned char *bitvec, int pos, int width) { jim_wide result = 0; int i; /* Aligned, byte extraction */ if (pos % 8 == 0 && width % 8 == 0) { for (i = 0; i < width; i += 8) { result = (result << 8) + bitvec[(pos + i) / 8]; } return result; } /* Unaligned */ for (i = 0; i < width; i++) { if (JimTestBitBigEndian(bitvec, pos + width - i - 1)) { result |= ((jim_wide)1 << i); } } return result; } /** * Little endian integer extraction. * * Like JimBitIntBigEndian() but considers 'bitvect' as a little endian bit stream. */ static jim_wide JimBitIntLittleEndian(const unsigned char *bitvec, int pos, int width) { jim_wide result = 0; int i; /* Aligned, byte extraction */ if (pos % 8 == 0 && width % 8 == 0) { for (i = 0; i < width; i += 8) { result += (jim_wide)bitvec[(pos + i) / 8] << i; } return result; } /* Unaligned */ for (i = 0; i < width; i++) { if (JimTestBitLittleEndian(bitvec, pos + i)) { result |= ((jim_wide)1 << i); } } return result; } /** * Big endian bit set. * * Considers 'bitvect' as a big endian bit stream and sets * bit 'b' to 'bit' */ static void JimSetBitBigEndian(unsigned char *bitvec, int b, int bit) { div_t pos = div(b, 8); if (bit) { bitvec[pos.quot] |= (1 << (7 - pos.rem)); } else { bitvec[pos.quot] &= ~(1 << (7 - pos.rem)); } } /** * Little endian bit set. * * Considers 'bitvect' as a little endian bit stream and sets * bit 'b' to 'bit' */ static void JimSetBitLittleEndian(unsigned char *bitvec, int b, int bit) { div_t pos = div(b, 8); if (bit) { bitvec[pos.quot] |= (1 << pos.rem); } else { bitvec[pos.quot] &= ~(1 << pos.rem); } } /** * Big endian integer packing. * * Considers 'bitvect' as a big endian bit stream. * Packs integer 'value' of the given width (in bits) * starting at the given position (in bits). * * The pos/width must represent bits inside bitvec, * and the width be no more than the width of jim_wide. */ static void JimSetBitsIntBigEndian(unsigned char *bitvec, jim_wide value, int pos, int width) { int i; /* Common fast option */ if (pos % 8 == 0 && width == 8) { bitvec[pos / 8] = value; return; } for (i = 0; i < width; i++) { int bit = !!(value & ((jim_wide)1 << i)); JimSetBitBigEndian(bitvec, pos + width - i - 1, bit); } } /** * Little endian version of JimSetBitsIntBigEndian() */ static void JimSetBitsIntLittleEndian(unsigned char *bitvec, jim_wide value, int pos, int width) { int i; /* Common fast option */ if (pos % 8 == 0 && width == 8) { bitvec[pos / 8] = value; return; } for (i = 0; i < width; i++) { int bit = !!(value & ((jim_wide)1 << i)); JimSetBitLittleEndian(bitvec, pos + i, bit); } } /** * [unpack] * * Usage: unpack binvalue -intbe|-intle|-uintbe|-uintle|-str bitpos bitwidth * * Unpacks bits from $binvalue at bit position $bitpos and with $bitwidth. * Interprets the value according to the type and returns it. */ static int Jim_UnpackCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int option; static const char * const options[] = { "-intbe", "-intle", "-uintbe", "-uintle", "-str", NULL }; enum { OPT_INTBE, OPT_INTLE, OPT_UINTBE, OPT_UINTLE, OPT_STR, }; jim_wide pos; jim_wide width; if (argc != 5) { Jim_WrongNumArgs(interp, 1, argv, "binvalue -intbe|-intle|-uintbe|-uintle|-str bitpos bitwidth"); return JIM_ERR; } if (Jim_GetEnum(interp, argv[2], options, &option, NULL, JIM_ERRMSG) != JIM_OK) { return JIM_ERR; } if (Jim_GetWide(interp, argv[3], &pos) != JIM_OK) { return JIM_ERR; } if (Jim_GetWide(interp, argv[4], &width) != JIM_OK) { return JIM_ERR; } if (option == OPT_STR) { int len; const char *str = Jim_GetString(argv[1], &len); if (width % 8 || pos % 8) { Jim_SetResultString(interp, "string field is not on a byte boundary", -1); return JIM_ERR; } if (pos >= 0 && width > 0 && pos < len * 8) { if (pos + width > len * 8) { width = len * 8 - pos; } Jim_SetResultString(interp, str + pos / 8, width / 8); } return JIM_OK; } else { int len; const unsigned char *str = (const unsigned char *)Jim_GetString(argv[1], &len); jim_wide result = 0; if (width > sizeof(jim_wide) * 8) { Jim_SetResultFormatted(interp, "int field is too wide: %#s", argv[4]); return JIM_ERR; } if (pos >= 0 && width > 0 && pos < len * 8) { if (pos + width > len * 8) { width = len * 8 - pos; } if (option == OPT_INTBE || option == OPT_UINTBE) { result = JimBitIntBigEndian(str, pos, width); } else { result = JimBitIntLittleEndian(str, pos, width); } if (option == OPT_INTBE || option == OPT_INTLE) { result = JimSignExtend(result, width); } } Jim_SetResultInt(interp, result); return JIM_OK; } } /** * [pack] * * Usage: pack varname value -intle|-intbe|-str width ?bitoffset? * * Packs the binary representation of 'value' into the variable of the given name. * The value is packed according to the given type, width and bitoffset. * The variable is created if necessary (like [append]) * Ihe variable is expanded if necessary */ static int Jim_PackCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int option; static const char * const options[] = { "-intle", "-intbe", "-str", NULL }; enum { OPT_LE, OPT_BE, OPT_STR }; jim_wide pos = 0; jim_wide width; jim_wide value; Jim_Obj *stringObjPtr; int len; int freeobj = 0; if (argc != 5 && argc != 6) { Jim_WrongNumArgs(interp, 1, argv, "varName value -intle|-intbe|-str bitwidth ?bitoffset?"); return JIM_ERR; } if (Jim_GetEnum(interp, argv[3], options, &option, NULL, JIM_ERRMSG) != JIM_OK) { return JIM_ERR; } if (option != OPT_STR && Jim_GetWide(interp, argv[2], &value) != JIM_OK) { return JIM_ERR; } if (Jim_GetWide(interp, argv[4], &width) != JIM_OK) { return JIM_ERR; } if (width <= 0 || (option == OPT_STR && width % 8) || (option != OPT_STR && width > sizeof(jim_wide) * 8)) { Jim_SetResultFormatted(interp, "bad bitwidth: %#s", argv[5]); return JIM_ERR; } if (argc == 6) { if (Jim_GetWide(interp, argv[5], &pos) != JIM_OK) { return JIM_ERR; } if (pos < 0 || (option == OPT_STR && pos % 8)) { Jim_SetResultFormatted(interp, "bad bitoffset: %#s", argv[5]); return JIM_ERR; } } stringObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED); if (!stringObjPtr) { /* Create the string if it doesn't exist */ stringObjPtr = Jim_NewEmptyStringObj(interp); freeobj = 1; } else if (Jim_IsShared(stringObjPtr)) { freeobj = 1; stringObjPtr = Jim_DuplicateObj(interp, stringObjPtr); } len = Jim_Length(stringObjPtr) * 8; /* Extend the string as necessary first */ while (len < pos + width) { Jim_AppendString(interp, stringObjPtr, "", 1); len += 8; } Jim_SetResultInt(interp, pos + width); /* Now set the bits. Note that the the string *must* have no non-string rep * since we are writing the bytes directly. */ Jim_AppendString(interp, stringObjPtr, "", 0); if (option == OPT_BE) { JimSetBitsIntBigEndian((unsigned char *)stringObjPtr->bytes, value, pos, width); } else if (option == OPT_LE) { JimSetBitsIntLittleEndian((unsigned char *)stringObjPtr->bytes, value, pos, width); } else { pos /= 8; width /= 8; if (width > Jim_Length(argv[2])) { width = Jim_Length(argv[2]); } memcpy(stringObjPtr->bytes + pos, Jim_GetString(argv[2], NULL), width); /* No padding is needed since the string is already extended */ } if (Jim_SetVariable(interp, argv[1], stringObjPtr) != JIM_OK) { if (freeobj) { Jim_FreeNewObj(interp, stringObjPtr); return JIM_ERR; } } return JIM_OK; } int Jim_packInit(Jim_Interp *interp) { if (Jim_PackageProvide(interp, "pack", "1.0", JIM_ERRMSG)) { return JIM_ERR; } Jim_CreateCommand(interp, "unpack", Jim_UnpackCmd, NULL, NULL); Jim_CreateCommand(interp, "pack", Jim_PackCmd, NULL, NULL); return JIM_OK; } openocd-0.7.0/jimtcl/jim-readdir.c0000644000175000001440000001016312134336723013704 00000000000000 /* * Tcl readdir command. * * (c) 2008 Steve Bennett * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation * are those of the authors and should not be interpreted as representing * official policies, either expressed or implied, of the Jim Tcl Project. * * Based on original work by: *----------------------------------------------------------------------------- * Copyright 1991-1994 Karl Lehenbauer and Mark Diekhans. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, provided * that the above copyright notice appear in all copies. Karl Lehenbauer and * Mark Diekhans make no representations about the suitability of this * software for any purpose. It is provided "as is" without express or * implied warranty. *----------------------------------------------------------------------------- */ #include #include #include #include #include #ifdef HAVE_DIRENT_H #include #endif /* *----------------------------------------------------------------------------- * * Jim_ReaddirCmd -- * Implements the rename TCL command: * readdir ?-nocomplain? dirPath * * Results: * Standard TCL result. *----------------------------------------------------------------------------- */ int Jim_ReaddirCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { const char *dirPath; DIR *dirPtr; struct dirent *entryPtr; int nocomplain = 0; if (argc == 3 && Jim_CompareStringImmediate(interp, argv[1], "-nocomplain")) { nocomplain = 1; } if (argc != 2 && !nocomplain) { Jim_WrongNumArgs(interp, 1, argv, "?-nocomplain? dirPath"); return JIM_ERR; } dirPath = Jim_String(argv[1 + nocomplain]); dirPtr = opendir(dirPath); if (dirPtr == NULL) { if (nocomplain) { return JIM_OK; } Jim_SetResultString(interp, strerror(errno), -1); return JIM_ERR; } Jim_SetResultString(interp, strerror(errno), -1); Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0)); while ((entryPtr = readdir(dirPtr)) != NULL) { if (entryPtr->d_name[0] == '.') { if (entryPtr->d_name[1] == '\0') { continue; } if ((entryPtr->d_name[1] == '.') && (entryPtr->d_name[2] == '\0')) continue; } Jim_ListAppendElement(interp, Jim_GetResult(interp), Jim_NewStringObj(interp, entryPtr->d_name, -1)); } closedir(dirPtr); return JIM_OK; } int Jim_readdirInit(Jim_Interp *interp) { if (Jim_PackageProvide(interp, "readdir", "1.0", JIM_ERRMSG)) return JIM_ERR; Jim_CreateCommand(interp, "readdir", Jim_ReaddirCmd, NULL, NULL); return JIM_OK; } openocd-0.7.0/jimtcl/parse-unidata.tcl0000644000175000001440000000221312134336723014607 00000000000000#!/usr/bin/env tclsh # Generate UTF-8 case mapping tables # # (c) 2010 Steve Bennett # # See LICENCE for licence details. #/ # Parse the unicode data from: http://unicode.org/Public/UNIDATA/UnicodeData.txt # to generate case mapping tables set map(lower) {} set map(upper) {} set map(title) {} set f [open [lindex $argv 0]] while {[gets $f buf] >= 0} { set title "" set lower "" set upper "" foreach {code name class x x x x x x x x x upper lower title} [split $buf ";"] break set codex [string tolower 0x$code] if {$codex <= 0x7f} { continue } if {$codex > 0xffff} { break } if {![string match L* $class]} { continue } if {$upper ne ""} { lappend map(upper) $codex [string tolower 0x$upper] } if {$lower ne ""} { lappend map(lower) $codex [string tolower 0x$lower] } if {$title ne "" && $title ne $upper} { if {$title eq $code} { set title 0 } lappend map(title) $codex [string tolower 0x$title] } } close $f foreach type {upper lower title} { puts "static const struct casemap unicode_case_mapping_$type\[\] = \{" foreach {code alt} $map($type) { puts "\t{ $code, $alt }," } puts "\};\n" } openocd-0.7.0/jimtcl/utf8.c0000644000175000001440000001072412134336723012406 00000000000000/** * UTF-8 utility functions * * (c) 2010 Steve Bennett * * See LICENCE for licence details. */ #include #include #include #include #include #include "utf8.h" /* This one is always implemented */ int utf8_fromunicode(char *p, unsigned uc) { if (uc <= 0x7f) { *p = uc; return 1; } else if (uc <= 0x7ff) { *p++ = 0xc0 | ((uc & 0x7c0) >> 6); *p = 0x80 | (uc & 0x3f); return 2; } else if (uc <= 0xffff) { *p++ = 0xe0 | ((uc & 0xf000) >> 12); *p++ = 0x80 | ((uc & 0xfc0) >> 6); *p = 0x80 | (uc & 0x3f); return 3; } /* Note: We silently truncate to 21 bits here: 0x1fffff */ else { *p++ = 0xf0 | ((uc & 0x1c0000) >> 18); *p++ = 0x80 | ((uc & 0x3f000) >> 12); *p++ = 0x80 | ((uc & 0xfc0) >> 6); *p = 0x80 | (uc & 0x3f); return 4; } } #if defined(JIM_UTF8) && !defined(JIM_BOOTSTRAP) int utf8_charlen(int c) { if ((c & 0x80) == 0) { return 1; } if ((c & 0xe0) == 0xc0) { return 2; } if ((c & 0xf0) == 0xe0) { return 3; } if ((c & 0xf8) == 0xf0) { return 4; } /* Invalid sequence */ return -1; } int utf8_strlen(const char *str, int bytelen) { int charlen = 0; if (bytelen < 0) { bytelen = strlen(str); } while (bytelen) { int c; int l = utf8_tounicode(str, &c); charlen++; str += l; bytelen -= l; } return charlen; } int utf8_index(const char *str, int index) { const char *s = str; while (index--) { int c; s += utf8_tounicode(s, &c); } return s - str; } int utf8_charequal(const char *s1, const char *s2) { int c1, c2; utf8_tounicode(s1, &c1); utf8_tounicode(s2, &c2); return c1 == c2; } int utf8_prev_len(const char *str, int len) { int n = 1; assert(len > 0); /* Look up to len chars backward for a start-of-char byte */ while (--len) { if ((str[-n] & 0x80) == 0) { /* Start of a 1-byte char */ break; } if ((str[-n] & 0xc0) == 0xc0) { /* Start of a multi-byte char */ break; } n++; } return n; } int utf8_tounicode(const char *str, int *uc) { unsigned const char *s = (unsigned const char *)str; if (s[0] < 0xc0) { *uc = s[0]; return 1; } if (s[0] < 0xe0) { if ((s[1] & 0xc0) == 0x80) { *uc = ((s[0] & ~0xc0) << 6) | (s[1] & ~0x80); return 2; } } else if (s[0] < 0xf0) { if (((str[1] & 0xc0) == 0x80) && ((str[2] & 0xc0) == 0x80)) { *uc = ((s[0] & ~0xe0) << 12) | ((s[1] & ~0x80) << 6) | (s[2] & ~0x80); return 3; } } else if (s[0] < 0xf8) { if (((str[1] & 0xc0) == 0x80) && ((str[2] & 0xc0) == 0x80) && ((str[3] & 0xc0) == 0x80)) { *uc = ((s[0] & ~0xf0) << 18) | ((s[1] & ~0x80) << 12) | ((s[2] & ~0x80) << 6) | (s[3] & ~0x80); return 4; } } /* Invalid sequence, so just return the byte */ *uc = *s; return 1; } struct casemap { unsigned short code; /* code point */ unsigned short altcode; /* alternate case code point */ }; /* Generated mapping tables */ #include "_unicode_mapping.c" #define ARRAYSIZE(A) sizeof(A) / sizeof(*(A)) static int cmp_casemap(const void *key, const void *cm) { return *(int *)key - (int)((const struct casemap *)cm)->code; } static int utf8_map_case(const struct casemap *mapping, int num, int ch) { /* We only support 16 bit case mapping */ if (ch <= 0xffff) { const struct casemap *cm = bsearch(&ch, mapping, num, sizeof(*mapping), cmp_casemap); if (cm) { return cm->altcode; } } return ch; } int utf8_upper(int ch) { if (isascii(ch)) { return toupper(ch); } return utf8_map_case(unicode_case_mapping_upper, ARRAYSIZE(unicode_case_mapping_upper), ch); } int utf8_lower(int ch) { if (isascii(ch)) { return tolower(ch); } return utf8_map_case(unicode_case_mapping_lower, ARRAYSIZE(unicode_case_mapping_lower), ch); } int utf8_title(int ch) { int newch = utf8_map_case(unicode_case_mapping_title, ARRAYSIZE(unicode_case_mapping_title), ch); if (newch != ch) { return newch ? newch : ch; } return utf8_upper(ch); } #endif /* JIM_BOOTSTRAP */ openocd-0.7.0/jimtcl/linenoise.h0000644000175000001440000000470712134336723013516 00000000000000/* linenoise.h -- guerrilla line editing library against the idea that a * line editing lib needs to be 20,000 lines of C code. * * See linenoise.c for more information. * * ------------------------------------------------------------------------ * * Copyright (c) 2010, Salvatore Sanfilippo * Copyright (c) 2010, Pieter Noordhuis * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __LINENOISE_H #define __LINENOISE_H /* Currently never enable completion */ #define NO_COMPLETION #ifndef NO_COMPLETION typedef struct linenoiseCompletions { size_t len; char **cvec; } linenoiseCompletions; typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *); void linenoiseSetCompletionCallback(linenoiseCompletionCallback *); void linenoiseAddCompletion(linenoiseCompletions *, const char *); #endif char *linenoise(const char *prompt); int linenoiseHistoryAdd(const char *line); int linenoiseHistorySetMaxLen(int len); int linenoiseHistorySave(const char *filename); int linenoiseHistoryLoad(const char *filename); void linenoiseHistoryFree(void); char **linenoiseHistory(int *len); #endif /* __LINENOISE_H */ openocd-0.7.0/jimtcl/sqlite3/0000755000175000001440000000000012141414413013003 500000000000000openocd-0.7.0/jimtcl/sqlite3/sqlite3.c0000644000175000001440002157041312134336723014501 00000000000000/****************************************************************************** ** This file is an amalgamation of many separate C source files from SQLite ** version 3.7.9. By combining all the individual C code files into this ** single large file, the entire code can be compiled as a single translation ** unit. This allows many compilers to do optimizations that would not be ** possible if the files were compiled separately. Performance improvements ** of 5% or more are commonly seen when SQLite is compiled as a single ** translation unit. ** ** This file is all you need to compile SQLite. To use SQLite in other ** programs, you need this file and the "sqlite3.h" header file that defines ** the programming interface to the SQLite library. (If you do not have ** the "sqlite3.h" header file at hand, you will find a copy embedded within ** the text of this file. Search for "Begin file sqlite3.h" to find the start ** of the embedded sqlite3.h header file.) Additional code files may be needed ** if you want a wrapper to interface SQLite with your choice of programming ** language. The code for the "sqlite3" command-line shell is also in a ** separate file. This file contains only code for the core SQLite library. */ #define SQLITE_CORE 1 #define SQLITE_AMALGAMATION 1 #ifndef SQLITE_PRIVATE # define SQLITE_PRIVATE static #endif #ifndef SQLITE_API # define SQLITE_API #endif /************** Begin file sqliteInt.h ***************************************/ /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Internal interface definitions for SQLite. ** */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ /* ** These #defines should enable >2GB file support on POSIX if the ** underlying operating system supports it. If the OS lacks ** large file support, or if the OS is windows, these should be no-ops. ** ** Ticket #2739: The _LARGEFILE_SOURCE macro must appear before any ** system #includes. Hence, this block of code must be the very first ** code in all source files. ** ** Large file support can be disabled using the -DSQLITE_DISABLE_LFS switch ** on the compiler command line. This is necessary if you are compiling ** on a recent machine (ex: Red Hat 7.2) but you want your code to work ** on an older machine (ex: Red Hat 6.0). If you compile on Red Hat 7.2 ** without this option, LFS is enable. But LFS does not exist in the kernel ** in Red Hat 6.0, so the code won't work. Hence, for maximum binary ** portability you should omit LFS. ** ** Similar is true for Mac OS X. LFS is only supported on Mac OS X 9 and later. */ #ifndef SQLITE_DISABLE_LFS # define _LARGE_FILE 1 # ifndef _FILE_OFFSET_BITS # define _FILE_OFFSET_BITS 64 # endif # define _LARGEFILE_SOURCE 1 #endif /* ** Include the configuration header output by 'configure' if we're using the ** autoconf-based build */ #ifdef _HAVE_SQLITE_CONFIG_H #include "config.h" #endif /************** Include sqliteLimit.h in the middle of sqliteInt.h ***********/ /************** Begin file sqliteLimit.h *************************************/ /* ** 2007 May 7 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file defines various limits of what SQLite can process. */ /* ** The maximum length of a TEXT or BLOB in bytes. This also ** limits the size of a row in a table or index. ** ** The hard limit is the ability of a 32-bit signed integer ** to count the size: 2^31-1 or 2147483647. */ #ifndef SQLITE_MAX_LENGTH # define SQLITE_MAX_LENGTH 1000000000 #endif /* ** This is the maximum number of ** ** * Columns in a table ** * Columns in an index ** * Columns in a view ** * Terms in the SET clause of an UPDATE statement ** * Terms in the result set of a SELECT statement ** * Terms in the GROUP BY or ORDER BY clauses of a SELECT statement. ** * Terms in the VALUES clause of an INSERT statement ** ** The hard upper limit here is 32676. Most database people will ** tell you that in a well-normalized database, you usually should ** not have more than a dozen or so columns in any table. And if ** that is the case, there is no point in having more than a few ** dozen values in any of the other situations described above. */ #ifndef SQLITE_MAX_COLUMN # define SQLITE_MAX_COLUMN 2000 #endif /* ** The maximum length of a single SQL statement in bytes. ** ** It used to be the case that setting this value to zero would ** turn the limit off. That is no longer true. It is not possible ** to turn this limit off. */ #ifndef SQLITE_MAX_SQL_LENGTH # define SQLITE_MAX_SQL_LENGTH 1000000000 #endif /* ** The maximum depth of an expression tree. This is limited to ** some extent by SQLITE_MAX_SQL_LENGTH. But sometime you might ** want to place more severe limits on the complexity of an ** expression. ** ** A value of 0 used to mean that the limit was not enforced. ** But that is no longer true. The limit is now strictly enforced ** at all times. */ #ifndef SQLITE_MAX_EXPR_DEPTH # define SQLITE_MAX_EXPR_DEPTH 1000 #endif /* ** The maximum number of terms in a compound SELECT statement. ** The code generator for compound SELECT statements does one ** level of recursion for each term. A stack overflow can result ** if the number of terms is too large. In practice, most SQL ** never has more than 3 or 4 terms. Use a value of 0 to disable ** any limit on the number of terms in a compount SELECT. */ #ifndef SQLITE_MAX_COMPOUND_SELECT # define SQLITE_MAX_COMPOUND_SELECT 500 #endif /* ** The maximum number of opcodes in a VDBE program. ** Not currently enforced. */ #ifndef SQLITE_MAX_VDBE_OP # define SQLITE_MAX_VDBE_OP 25000 #endif /* ** The maximum number of arguments to an SQL function. */ #ifndef SQLITE_MAX_FUNCTION_ARG # define SQLITE_MAX_FUNCTION_ARG 127 #endif /* ** The maximum number of in-memory pages to use for the main database ** table and for temporary tables. The SQLITE_DEFAULT_CACHE_SIZE */ #ifndef SQLITE_DEFAULT_CACHE_SIZE # define SQLITE_DEFAULT_CACHE_SIZE 2000 #endif #ifndef SQLITE_DEFAULT_TEMP_CACHE_SIZE # define SQLITE_DEFAULT_TEMP_CACHE_SIZE 500 #endif /* ** The default number of frames to accumulate in the log file before ** checkpointing the database in WAL mode. */ #ifndef SQLITE_DEFAULT_WAL_AUTOCHECKPOINT # define SQLITE_DEFAULT_WAL_AUTOCHECKPOINT 1000 #endif /* ** The maximum number of attached databases. This must be between 0 ** and 62. The upper bound on 62 is because a 64-bit integer bitmap ** is used internally to track attached databases. */ #ifndef SQLITE_MAX_ATTACHED # define SQLITE_MAX_ATTACHED 10 #endif /* ** The maximum value of a ?nnn wildcard that the parser will accept. */ #ifndef SQLITE_MAX_VARIABLE_NUMBER # define SQLITE_MAX_VARIABLE_NUMBER 999 #endif /* Maximum page size. The upper bound on this value is 65536. This a limit ** imposed by the use of 16-bit offsets within each page. ** ** Earlier versions of SQLite allowed the user to change this value at ** compile time. This is no longer permitted, on the grounds that it creates ** a library that is technically incompatible with an SQLite library ** compiled with a different limit. If a process operating on a database ** with a page-size of 65536 bytes crashes, then an instance of SQLite ** compiled with the default page-size limit will not be able to rollback ** the aborted transaction. This could lead to database corruption. */ #ifdef SQLITE_MAX_PAGE_SIZE # undef SQLITE_MAX_PAGE_SIZE #endif #define SQLITE_MAX_PAGE_SIZE 65536 /* ** The default size of a database page. */ #ifndef SQLITE_DEFAULT_PAGE_SIZE # define SQLITE_DEFAULT_PAGE_SIZE 1024 #endif #if SQLITE_DEFAULT_PAGE_SIZE>SQLITE_MAX_PAGE_SIZE # undef SQLITE_DEFAULT_PAGE_SIZE # define SQLITE_DEFAULT_PAGE_SIZE SQLITE_MAX_PAGE_SIZE #endif /* ** Ordinarily, if no value is explicitly provided, SQLite creates databases ** with page size SQLITE_DEFAULT_PAGE_SIZE. However, based on certain ** device characteristics (sector-size and atomic write() support), ** SQLite may choose a larger value. This constant is the maximum value ** SQLite will choose on its own. */ #ifndef SQLITE_MAX_DEFAULT_PAGE_SIZE # define SQLITE_MAX_DEFAULT_PAGE_SIZE 8192 #endif #if SQLITE_MAX_DEFAULT_PAGE_SIZE>SQLITE_MAX_PAGE_SIZE # undef SQLITE_MAX_DEFAULT_PAGE_SIZE # define SQLITE_MAX_DEFAULT_PAGE_SIZE SQLITE_MAX_PAGE_SIZE #endif /* ** Maximum number of pages in one database file. ** ** This is really just the default value for the max_page_count pragma. ** This value can be lowered (or raised) at run-time using that the ** max_page_count macro. */ #ifndef SQLITE_MAX_PAGE_COUNT # define SQLITE_MAX_PAGE_COUNT 1073741823 #endif /* ** Maximum length (in bytes) of the pattern in a LIKE or GLOB ** operator. */ #ifndef SQLITE_MAX_LIKE_PATTERN_LENGTH # define SQLITE_MAX_LIKE_PATTERN_LENGTH 50000 #endif /* ** Maximum depth of recursion for triggers. ** ** A value of 1 means that a trigger program will not be able to itself ** fire any triggers. A value of 0 means that no trigger programs at all ** may be executed. */ #ifndef SQLITE_MAX_TRIGGER_DEPTH # define SQLITE_MAX_TRIGGER_DEPTH 1000 #endif /************** End of sqliteLimit.h *****************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ /* Disable nuisance warnings on Borland compilers */ #if defined(__BORLANDC__) #pragma warn -rch /* unreachable code */ #pragma warn -ccc /* Condition is always true or false */ #pragma warn -aus /* Assigned value is never used */ #pragma warn -csu /* Comparing signed and unsigned */ #pragma warn -spa /* Suspicious pointer arithmetic */ #endif /* Needed for various definitions... */ #ifndef _GNU_SOURCE # define _GNU_SOURCE #endif /* ** Include standard header files as necessary */ #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_INTTYPES_H #include #endif /* ** The following macros are used to cast pointers to integers and ** integers to pointers. The way you do this varies from one compiler ** to the next, so we have developed the following set of #if statements ** to generate appropriate macros for a wide range of compilers. ** ** The correct "ANSI" way to do this is to use the intptr_t type. ** Unfortunately, that typedef is not available on all compilers, or ** if it is available, it requires an #include of specific headers ** that vary from one machine to the next. ** ** Ticket #3860: The llvm-gcc-4.2 compiler from Apple chokes on ** the ((void*)&((char*)0)[X]) construct. But MSVC chokes on ((void*)(X)). ** So we have to define the macros in different ways depending on the ** compiler. */ #if defined(__PTRDIFF_TYPE__) /* This case should work for GCC */ # define SQLITE_INT_TO_PTR(X) ((void*)(__PTRDIFF_TYPE__)(X)) # define SQLITE_PTR_TO_INT(X) ((int)(__PTRDIFF_TYPE__)(X)) #elif !defined(__GNUC__) /* Works for compilers other than LLVM */ # define SQLITE_INT_TO_PTR(X) ((void*)&((char*)0)[X]) # define SQLITE_PTR_TO_INT(X) ((int)(((char*)X)-(char*)0)) #elif defined(HAVE_STDINT_H) /* Use this case if we have ANSI headers */ # define SQLITE_INT_TO_PTR(X) ((void*)(intptr_t)(X)) # define SQLITE_PTR_TO_INT(X) ((int)(intptr_t)(X)) #else /* Generates a warning - but it always works */ # define SQLITE_INT_TO_PTR(X) ((void*)(X)) # define SQLITE_PTR_TO_INT(X) ((int)(X)) #endif /* ** The SQLITE_THREADSAFE macro must be defined as 0, 1, or 2. ** 0 means mutexes are permanently disable and the library is never ** threadsafe. 1 means the library is serialized which is the highest ** level of threadsafety. 2 means the libary is multithreaded - multiple ** threads can use SQLite as long as no two threads try to use the same ** database connection at the same time. ** ** Older versions of SQLite used an optional THREADSAFE macro. ** We support that for legacy. */ #if !defined(SQLITE_THREADSAFE) #if defined(THREADSAFE) # define SQLITE_THREADSAFE THREADSAFE #else # define SQLITE_THREADSAFE 1 /* IMP: R-07272-22309 */ #endif #endif /* ** The SQLITE_DEFAULT_MEMSTATUS macro must be defined as either 0 or 1. ** It determines whether or not the features related to ** SQLITE_CONFIG_MEMSTATUS are available by default or not. This value can ** be overridden at runtime using the sqlite3_config() API. */ #if !defined(SQLITE_DEFAULT_MEMSTATUS) # define SQLITE_DEFAULT_MEMSTATUS 1 #endif /* ** Exactly one of the following macros must be defined in order to ** specify which memory allocation subsystem to use. ** ** SQLITE_SYSTEM_MALLOC // Use normal system malloc() ** SQLITE_WIN32_MALLOC // Use Win32 native heap API ** SQLITE_MEMDEBUG // Debugging version of system malloc() ** ** On Windows, if the SQLITE_WIN32_MALLOC_VALIDATE macro is defined and the ** assert() macro is enabled, each call into the Win32 native heap subsystem ** will cause HeapValidate to be called. If heap validation should fail, an ** assertion will be triggered. ** ** (Historical note: There used to be several other options, but we've ** pared it down to just these three.) ** ** If none of the above are defined, then set SQLITE_SYSTEM_MALLOC as ** the default. */ #if defined(SQLITE_SYSTEM_MALLOC)+defined(SQLITE_WIN32_MALLOC)+defined(SQLITE_MEMDEBUG)>1 # error "At most one of the following compile-time configuration options\ is allows: SQLITE_SYSTEM_MALLOC, SQLITE_WIN32_MALLOC, SQLITE_MEMDEBUG" #endif #if defined(SQLITE_SYSTEM_MALLOC)+defined(SQLITE_WIN32_MALLOC)+defined(SQLITE_MEMDEBUG)==0 # define SQLITE_SYSTEM_MALLOC 1 #endif /* ** If SQLITE_MALLOC_SOFT_LIMIT is not zero, then try to keep the ** sizes of memory allocations below this value where possible. */ #if !defined(SQLITE_MALLOC_SOFT_LIMIT) # define SQLITE_MALLOC_SOFT_LIMIT 1024 #endif /* ** We need to define _XOPEN_SOURCE as follows in order to enable ** recursive mutexes on most Unix systems. But Mac OS X is different. ** The _XOPEN_SOURCE define causes problems for Mac OS X we are told, ** so it is omitted there. See ticket #2673. ** ** Later we learn that _XOPEN_SOURCE is poorly or incorrectly ** implemented on some systems. So we avoid defining it at all ** if it is already defined or if it is unneeded because we are ** not doing a threadsafe build. Ticket #2681. ** ** See also ticket #2741. */ #if !defined(_XOPEN_SOURCE) && !defined(__DARWIN__) && !defined(__APPLE__) && SQLITE_THREADSAFE # define _XOPEN_SOURCE 500 /* Needed to enable pthread recursive mutexes */ #endif /* ** The TCL headers are only needed when compiling the TCL bindings. */ #if defined(SQLITE_TCL) || defined(TCLSH) # include #endif /* ** Many people are failing to set -DNDEBUG=1 when compiling SQLite. ** Setting NDEBUG makes the code smaller and run faster. So the following ** lines are added to automatically set NDEBUG unless the -DSQLITE_DEBUG=1 ** option is set. Thus NDEBUG becomes an opt-in rather than an opt-out ** feature. */ #if !defined(NDEBUG) && !defined(SQLITE_DEBUG) # define NDEBUG 1 #endif /* ** The testcase() macro is used to aid in coverage testing. When ** doing coverage testing, the condition inside the argument to ** testcase() must be evaluated both true and false in order to ** get full branch coverage. The testcase() macro is inserted ** to help ensure adequate test coverage in places where simple ** condition/decision coverage is inadequate. For example, testcase() ** can be used to make sure boundary values are tested. For ** bitmask tests, testcase() can be used to make sure each bit ** is significant and used at least once. On switch statements ** where multiple cases go to the same block of code, testcase() ** can insure that all cases are evaluated. ** */ #ifdef SQLITE_COVERAGE_TEST SQLITE_PRIVATE void sqlite3Coverage(int); # define testcase(X) if( X ){ sqlite3Coverage(__LINE__); } #else # define testcase(X) #endif /* ** The TESTONLY macro is used to enclose variable declarations or ** other bits of code that are needed to support the arguments ** within testcase() and assert() macros. */ #if !defined(NDEBUG) || defined(SQLITE_COVERAGE_TEST) # define TESTONLY(X) X #else # define TESTONLY(X) #endif /* ** Sometimes we need a small amount of code such as a variable initialization ** to setup for a later assert() statement. We do not want this code to ** appear when assert() is disabled. The following macro is therefore ** used to contain that setup code. The "VVA" acronym stands for ** "Verification, Validation, and Accreditation". In other words, the ** code within VVA_ONLY() will only run during verification processes. */ #ifndef NDEBUG # define VVA_ONLY(X) X #else # define VVA_ONLY(X) #endif /* ** The ALWAYS and NEVER macros surround boolean expressions which ** are intended to always be true or false, respectively. Such ** expressions could be omitted from the code completely. But they ** are included in a few cases in order to enhance the resilience ** of SQLite to unexpected behavior - to make the code "self-healing" ** or "ductile" rather than being "brittle" and crashing at the first ** hint of unplanned behavior. ** ** In other words, ALWAYS and NEVER are added for defensive code. ** ** When doing coverage testing ALWAYS and NEVER are hard-coded to ** be true and false so that the unreachable code then specify will ** not be counted as untested code. */ #if defined(SQLITE_COVERAGE_TEST) # define ALWAYS(X) (1) # define NEVER(X) (0) #elif !defined(NDEBUG) # define ALWAYS(X) ((X)?1:(assert(0),0)) # define NEVER(X) ((X)?(assert(0),1):0) #else # define ALWAYS(X) (X) # define NEVER(X) (X) #endif /* ** Return true (non-zero) if the input is a integer that is too large ** to fit in 32-bits. This macro is used inside of various testcase() ** macros to verify that we have tested SQLite for large-file support. */ #define IS_BIG_INT(X) (((X)&~(i64)0xffffffff)!=0) /* ** The macro unlikely() is a hint that surrounds a boolean ** expression that is usually false. Macro likely() surrounds ** a boolean expression that is usually true. GCC is able to ** use these hints to generate better code, sometimes. */ #if defined(__GNUC__) && 0 # define likely(X) __builtin_expect((X),1) # define unlikely(X) __builtin_expect((X),0) #else # define likely(X) !!(X) # define unlikely(X) !!(X) #endif /************** Include sqlite3.h in the middle of sqliteInt.h ***************/ /************** Begin file sqlite3.h *****************************************/ /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the SQLite library ** presents to client programs. If a C-function, structure, datatype, ** or constant definition does not appear in this file, then it is ** not a published API of SQLite, is subject to change without ** notice, and should not be referenced by programs that use SQLite. ** ** Some of the definitions that are in this file are marked as ** "experimental". Experimental interfaces are normally new ** features recently added to SQLite. We do not anticipate changes ** to experimental interfaces but reserve the right to make minor changes ** if experience from use "in the wild" suggest such changes are prudent. ** ** The official C-language API documentation for SQLite is derived ** from comments in this file. This file is the authoritative source ** on how SQLite interfaces are suppose to operate. ** ** The name of this file under configuration management is "sqlite.h.in". ** The makefile makes some minor changes to this file (such as inserting ** the version number) and changes its name to "sqlite3.h" as ** part of the build process. */ #ifndef _SQLITE3_H_ #define _SQLITE3_H_ #include /* Needed for the definition of va_list */ /* ** Make sure we can call this stuff from C++. */ #if 0 extern "C" { #endif /* ** Add the ability to override 'extern' */ #ifndef SQLITE_EXTERN # define SQLITE_EXTERN extern #endif #ifndef SQLITE_API # define SQLITE_API #endif /* ** These no-op macros are used in front of interfaces to mark those ** interfaces as either deprecated or experimental. New applications ** should not use deprecated interfaces - they are support for backwards ** compatibility only. Application writers should be aware that ** experimental interfaces are subject to change in point releases. ** ** These macros used to resolve to various kinds of compiler magic that ** would generate warning messages when they were used. But that ** compiler magic ended up generating such a flurry of bug reports ** that we have taken it all out and gone back to using simple ** noop macros. */ #define SQLITE_DEPRECATED #define SQLITE_EXPERIMENTAL /* ** Ensure these symbols were not defined by some previous header file. */ #ifdef SQLITE_VERSION # undef SQLITE_VERSION #endif #ifdef SQLITE_VERSION_NUMBER # undef SQLITE_VERSION_NUMBER #endif /* ** CAPI3REF: Compile-Time Library Version Numbers ** ** ^(The [SQLITE_VERSION] C preprocessor macro in the sqlite3.h header ** evaluates to a string literal that is the SQLite version in the ** format "X.Y.Z" where X is the major version number (always 3 for ** SQLite3) and Y is the minor version number and Z is the release number.)^ ** ^(The [SQLITE_VERSION_NUMBER] C preprocessor macro resolves to an integer ** with the value (X*1000000 + Y*1000 + Z) where X, Y, and Z are the same ** numbers used in [SQLITE_VERSION].)^ ** The SQLITE_VERSION_NUMBER for any given release of SQLite will also ** be larger than the release from which it is derived. Either Y will ** be held constant and Z will be incremented or else Y will be incremented ** and Z will be reset to zero. ** ** Since version 3.6.18, SQLite source code has been stored in the ** Fossil configuration management ** system. ^The SQLITE_SOURCE_ID macro evaluates to ** a string which identifies a particular check-in of SQLite ** within its configuration management system. ^The SQLITE_SOURCE_ID ** string contains the date and time of the check-in (UTC) and an SHA1 ** hash of the entire source tree. ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.7.9" #define SQLITE_VERSION_NUMBER 3007009 #define SQLITE_SOURCE_ID "2011-10-29 19:25:08 5b82ec6fbbd2f4195ad06dd911de3817373ad5bf" /* ** CAPI3REF: Run-Time Library Version Numbers ** KEYWORDS: sqlite3_version, sqlite3_sourceid ** ** These interfaces provide the same information as the [SQLITE_VERSION], ** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros ** but are associated with the library instead of the header file. ^(Cautious ** programmers might include assert() statements in their application to ** verify that values returned by these interfaces match the macros in ** the header, and thus insure that the application is ** compiled with matching library and header files. ** **
** assert( sqlite3_libversion_number()==SQLITE_VERSION_NUMBER );
** assert( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)==0 );
** assert( strcmp(sqlite3_libversion(),SQLITE_VERSION)==0 );
** 
)^ ** ** ^The sqlite3_version[] string constant contains the text of [SQLITE_VERSION] ** macro. ^The sqlite3_libversion() function returns a pointer to the ** to the sqlite3_version[] string constant. The sqlite3_libversion() ** function is provided for use in DLLs since DLL users usually do not have ** direct access to string constants within the DLL. ^The ** sqlite3_libversion_number() function returns an integer equal to ** [SQLITE_VERSION_NUMBER]. ^The sqlite3_sourceid() function returns ** a pointer to a string constant whose value is the same as the ** [SQLITE_SOURCE_ID] C preprocessor macro. ** ** See also: [sqlite_version()] and [sqlite_source_id()]. */ SQLITE_API const char sqlite3_version[] = SQLITE_VERSION; SQLITE_API const char *sqlite3_libversion(void); SQLITE_API const char *sqlite3_sourceid(void); SQLITE_API int sqlite3_libversion_number(void); /* ** CAPI3REF: Run-Time Library Compilation Options Diagnostics ** ** ^The sqlite3_compileoption_used() function returns 0 or 1 ** indicating whether the specified option was defined at ** compile time. ^The SQLITE_ prefix may be omitted from the ** option name passed to sqlite3_compileoption_used(). ** ** ^The sqlite3_compileoption_get() function allows iterating ** over the list of options that were defined at compile time by ** returning the N-th compile time option string. ^If N is out of range, ** sqlite3_compileoption_get() returns a NULL pointer. ^The SQLITE_ ** prefix is omitted from any strings returned by ** sqlite3_compileoption_get(). ** ** ^Support for the diagnostic functions sqlite3_compileoption_used() ** and sqlite3_compileoption_get() may be omitted by specifying the ** [SQLITE_OMIT_COMPILEOPTION_DIAGS] option at compile time. ** ** See also: SQL functions [sqlite_compileoption_used()] and ** [sqlite_compileoption_get()] and the [compile_options pragma]. */ #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS SQLITE_API int sqlite3_compileoption_used(const char *zOptName); SQLITE_API const char *sqlite3_compileoption_get(int N); #endif /* ** CAPI3REF: Test To See If The Library Is Threadsafe ** ** ^The sqlite3_threadsafe() function returns zero if and only if ** SQLite was compiled mutexing code omitted due to the ** [SQLITE_THREADSAFE] compile-time option being set to 0. ** ** SQLite can be compiled with or without mutexes. When ** the [SQLITE_THREADSAFE] C preprocessor macro is 1 or 2, mutexes ** are enabled and SQLite is threadsafe. When the ** [SQLITE_THREADSAFE] macro is 0, ** the mutexes are omitted. Without the mutexes, it is not safe ** to use SQLite concurrently from more than one thread. ** ** Enabling mutexes incurs a measurable performance penalty. ** So if speed is of utmost importance, it makes sense to disable ** the mutexes. But for maximum safety, mutexes should be enabled. ** ^The default behavior is for mutexes to be enabled. ** ** This interface can be used by an application to make sure that the ** version of SQLite that it is linking against was compiled with ** the desired setting of the [SQLITE_THREADSAFE] macro. ** ** This interface only reports on the compile-time mutex setting ** of the [SQLITE_THREADSAFE] flag. If SQLite is compiled with ** SQLITE_THREADSAFE=1 or =2 then mutexes are enabled by default but ** can be fully or partially disabled using a call to [sqlite3_config()] ** with the verbs [SQLITE_CONFIG_SINGLETHREAD], [SQLITE_CONFIG_MULTITHREAD], ** or [SQLITE_CONFIG_MUTEX]. ^(The return value of the ** sqlite3_threadsafe() function shows only the compile-time setting of ** thread safety, not any run-time changes to that setting made by ** sqlite3_config(). In other words, the return value from sqlite3_threadsafe() ** is unchanged by calls to sqlite3_config().)^ ** ** See the [threading mode] documentation for additional information. */ SQLITE_API int sqlite3_threadsafe(void); /* ** CAPI3REF: Database Connection Handle ** KEYWORDS: {database connection} {database connections} ** ** Each open SQLite database is represented by a pointer to an instance of ** the opaque structure named "sqlite3". It is useful to think of an sqlite3 ** pointer as an object. The [sqlite3_open()], [sqlite3_open16()], and ** [sqlite3_open_v2()] interfaces are its constructors, and [sqlite3_close()] ** is its destructor. There are many other interfaces (such as ** [sqlite3_prepare_v2()], [sqlite3_create_function()], and ** [sqlite3_busy_timeout()] to name but three) that are methods on an ** sqlite3 object. */ typedef struct sqlite3 sqlite3; /* ** CAPI3REF: 64-Bit Integer Types ** KEYWORDS: sqlite_int64 sqlite_uint64 ** ** Because there is no cross-platform way to specify 64-bit integer types ** SQLite includes typedefs for 64-bit signed and unsigned integers. ** ** The sqlite3_int64 and sqlite3_uint64 are the preferred type definitions. ** The sqlite_int64 and sqlite_uint64 types are supported for backwards ** compatibility only. ** ** ^The sqlite3_int64 and sqlite_int64 types can store integer values ** between -9223372036854775808 and +9223372036854775807 inclusive. ^The ** sqlite3_uint64 and sqlite_uint64 types can store integer values ** between 0 and +18446744073709551615 inclusive. */ #ifdef SQLITE_INT64_TYPE typedef SQLITE_INT64_TYPE sqlite_int64; typedef unsigned SQLITE_INT64_TYPE sqlite_uint64; #elif defined(_MSC_VER) || defined(__BORLANDC__) typedef __int64 sqlite_int64; typedef unsigned __int64 sqlite_uint64; #else typedef long long int sqlite_int64; typedef unsigned long long int sqlite_uint64; #endif typedef sqlite_int64 sqlite3_int64; typedef sqlite_uint64 sqlite3_uint64; /* ** If compiling for a processor that lacks floating point support, ** substitute integer for floating-point. */ #ifdef SQLITE_OMIT_FLOATING_POINT # define double sqlite3_int64 #endif /* ** CAPI3REF: Closing A Database Connection ** ** ^The sqlite3_close() routine is the destructor for the [sqlite3] object. ** ^Calls to sqlite3_close() return SQLITE_OK if the [sqlite3] object is ** successfully destroyed and all associated resources are deallocated. ** ** Applications must [sqlite3_finalize | finalize] all [prepared statements] ** and [sqlite3_blob_close | close] all [BLOB handles] associated with ** the [sqlite3] object prior to attempting to close the object. ^If ** sqlite3_close() is called on a [database connection] that still has ** outstanding [prepared statements] or [BLOB handles], then it returns ** SQLITE_BUSY. ** ** ^If [sqlite3_close()] is invoked while a transaction is open, ** the transaction is automatically rolled back. ** ** The C parameter to [sqlite3_close(C)] must be either a NULL ** pointer or an [sqlite3] object pointer obtained ** from [sqlite3_open()], [sqlite3_open16()], or ** [sqlite3_open_v2()], and not previously closed. ** ^Calling sqlite3_close() with a NULL pointer argument is a ** harmless no-op. */ SQLITE_API int sqlite3_close(sqlite3 *); /* ** The type for a callback function. ** This is legacy and deprecated. It is included for historical ** compatibility and is not documented. */ typedef int (*sqlite3_callback)(void*,int,char**, char**); /* ** CAPI3REF: One-Step Query Execution Interface ** ** The sqlite3_exec() interface is a convenience wrapper around ** [sqlite3_prepare_v2()], [sqlite3_step()], and [sqlite3_finalize()], ** that allows an application to run multiple statements of SQL ** without having to use a lot of C code. ** ** ^The sqlite3_exec() interface runs zero or more UTF-8 encoded, ** semicolon-separate SQL statements passed into its 2nd argument, ** in the context of the [database connection] passed in as its 1st ** argument. ^If the callback function of the 3rd argument to ** sqlite3_exec() is not NULL, then it is invoked for each result row ** coming out of the evaluated SQL statements. ^The 4th argument to ** sqlite3_exec() is relayed through to the 1st argument of each ** callback invocation. ^If the callback pointer to sqlite3_exec() ** is NULL, then no callback is ever invoked and result rows are ** ignored. ** ** ^If an error occurs while evaluating the SQL statements passed into ** sqlite3_exec(), then execution of the current statement stops and ** subsequent statements are skipped. ^If the 5th parameter to sqlite3_exec() ** is not NULL then any error message is written into memory obtained ** from [sqlite3_malloc()] and passed back through the 5th parameter. ** To avoid memory leaks, the application should invoke [sqlite3_free()] ** on error message strings returned through the 5th parameter of ** of sqlite3_exec() after the error message string is no longer needed. ** ^If the 5th parameter to sqlite3_exec() is not NULL and no errors ** occur, then sqlite3_exec() sets the pointer in its 5th parameter to ** NULL before returning. ** ** ^If an sqlite3_exec() callback returns non-zero, the sqlite3_exec() ** routine returns SQLITE_ABORT without invoking the callback again and ** without running any subsequent SQL statements. ** ** ^The 2nd argument to the sqlite3_exec() callback function is the ** number of columns in the result. ^The 3rd argument to the sqlite3_exec() ** callback is an array of pointers to strings obtained as if from ** [sqlite3_column_text()], one for each column. ^If an element of a ** result row is NULL then the corresponding string pointer for the ** sqlite3_exec() callback is a NULL pointer. ^The 4th argument to the ** sqlite3_exec() callback is an array of pointers to strings where each ** entry represents the name of corresponding result column as obtained ** from [sqlite3_column_name()]. ** ** ^If the 2nd parameter to sqlite3_exec() is a NULL pointer, a pointer ** to an empty string, or a pointer that contains only whitespace and/or ** SQL comments, then no SQL statements are evaluated and the database ** is not changed. ** ** Restrictions: ** **
    **
  • The application must insure that the 1st parameter to sqlite3_exec() ** is a valid and open [database connection]. **
  • The application must not close [database connection] specified by ** the 1st parameter to sqlite3_exec() while sqlite3_exec() is running. **
  • The application must not modify the SQL statement text passed into ** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running. **
*/ SQLITE_API int sqlite3_exec( sqlite3*, /* An open database */ const char *sql, /* SQL to be evaluated */ int (*callback)(void*,int,char**,char**), /* Callback function */ void *, /* 1st argument to callback */ char **errmsg /* Error msg written here */ ); /* ** CAPI3REF: Result Codes ** KEYWORDS: SQLITE_OK {error code} {error codes} ** KEYWORDS: {result code} {result codes} ** ** Many SQLite functions return an integer result code from the set shown ** here in order to indicates success or failure. ** ** New error codes may be added in future versions of SQLite. ** ** See also: [SQLITE_IOERR_READ | extended result codes], ** [sqlite3_vtab_on_conflict()] [SQLITE_ROLLBACK | result codes]. */ #define SQLITE_OK 0 /* Successful result */ /* beginning-of-error-codes */ #define SQLITE_ERROR 1 /* SQL error or missing database */ #define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */ #define SQLITE_PERM 3 /* Access permission denied */ #define SQLITE_ABORT 4 /* Callback routine requested an abort */ #define SQLITE_BUSY 5 /* The database file is locked */ #define SQLITE_LOCKED 6 /* A table in the database is locked */ #define SQLITE_NOMEM 7 /* A malloc() failed */ #define SQLITE_READONLY 8 /* Attempt to write a readonly database */ #define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite3_interrupt()*/ #define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */ #define SQLITE_CORRUPT 11 /* The database disk image is malformed */ #define SQLITE_NOTFOUND 12 /* Unknown opcode in sqlite3_file_control() */ #define SQLITE_FULL 13 /* Insertion failed because database is full */ #define SQLITE_CANTOPEN 14 /* Unable to open the database file */ #define SQLITE_PROTOCOL 15 /* Database lock protocol error */ #define SQLITE_EMPTY 16 /* Database is empty */ #define SQLITE_SCHEMA 17 /* The database schema changed */ #define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */ #define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */ #define SQLITE_MISMATCH 20 /* Data type mismatch */ #define SQLITE_MISUSE 21 /* Library used incorrectly */ #define SQLITE_NOLFS 22 /* Uses OS features not supported on host */ #define SQLITE_AUTH 23 /* Authorization denied */ #define SQLITE_FORMAT 24 /* Auxiliary database format error */ #define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */ #define SQLITE_NOTADB 26 /* File opened that is not a database file */ #define SQLITE_ROW 100 /* sqlite3_step() has another row ready */ #define SQLITE_DONE 101 /* sqlite3_step() has finished executing */ /* end-of-error-codes */ /* ** CAPI3REF: Extended Result Codes ** KEYWORDS: {extended error code} {extended error codes} ** KEYWORDS: {extended result code} {extended result codes} ** ** In its default configuration, SQLite API routines return one of 26 integer ** [SQLITE_OK | result codes]. However, experience has shown that many of ** these result codes are too coarse-grained. They do not provide as ** much information about problems as programmers might like. In an effort to ** address this, newer versions of SQLite (version 3.3.8 and later) include ** support for additional result codes that provide more detailed information ** about errors. The extended result codes are enabled or disabled ** on a per database connection basis using the ** [sqlite3_extended_result_codes()] API. ** ** Some of the available extended result codes are listed here. ** One may expect the number of extended result codes will be expand ** over time. Software that uses extended result codes should expect ** to see new result codes in future releases of SQLite. ** ** The SQLITE_OK result code will never be extended. It will always ** be exactly zero. */ #define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8)) #define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8)) #define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8)) #define SQLITE_IOERR_FSYNC (SQLITE_IOERR | (4<<8)) #define SQLITE_IOERR_DIR_FSYNC (SQLITE_IOERR | (5<<8)) #define SQLITE_IOERR_TRUNCATE (SQLITE_IOERR | (6<<8)) #define SQLITE_IOERR_FSTAT (SQLITE_IOERR | (7<<8)) #define SQLITE_IOERR_UNLOCK (SQLITE_IOERR | (8<<8)) #define SQLITE_IOERR_RDLOCK (SQLITE_IOERR | (9<<8)) #define SQLITE_IOERR_DELETE (SQLITE_IOERR | (10<<8)) #define SQLITE_IOERR_BLOCKED (SQLITE_IOERR | (11<<8)) #define SQLITE_IOERR_NOMEM (SQLITE_IOERR | (12<<8)) #define SQLITE_IOERR_ACCESS (SQLITE_IOERR | (13<<8)) #define SQLITE_IOERR_CHECKRESERVEDLOCK (SQLITE_IOERR | (14<<8)) #define SQLITE_IOERR_LOCK (SQLITE_IOERR | (15<<8)) #define SQLITE_IOERR_CLOSE (SQLITE_IOERR | (16<<8)) #define SQLITE_IOERR_DIR_CLOSE (SQLITE_IOERR | (17<<8)) #define SQLITE_IOERR_SHMOPEN (SQLITE_IOERR | (18<<8)) #define SQLITE_IOERR_SHMSIZE (SQLITE_IOERR | (19<<8)) #define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20<<8)) #define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21<<8)) #define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) #define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8)) #define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8)) /* ** CAPI3REF: Flags For File Open Operations ** ** These bit values are intended for use in the ** 3rd parameter to the [sqlite3_open_v2()] interface and ** in the 4th parameter to the [sqlite3_vfs.xOpen] method. */ #define SQLITE_OPEN_READONLY 0x00000001 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_READWRITE 0x00000002 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_CREATE 0x00000004 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_DELETEONCLOSE 0x00000008 /* VFS only */ #define SQLITE_OPEN_EXCLUSIVE 0x00000010 /* VFS only */ #define SQLITE_OPEN_AUTOPROXY 0x00000020 /* VFS only */ #define SQLITE_OPEN_URI 0x00000040 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_MAIN_DB 0x00000100 /* VFS only */ #define SQLITE_OPEN_TEMP_DB 0x00000200 /* VFS only */ #define SQLITE_OPEN_TRANSIENT_DB 0x00000400 /* VFS only */ #define SQLITE_OPEN_MAIN_JOURNAL 0x00000800 /* VFS only */ #define SQLITE_OPEN_TEMP_JOURNAL 0x00001000 /* VFS only */ #define SQLITE_OPEN_SUBJOURNAL 0x00002000 /* VFS only */ #define SQLITE_OPEN_MASTER_JOURNAL 0x00004000 /* VFS only */ #define SQLITE_OPEN_NOMUTEX 0x00008000 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_FULLMUTEX 0x00010000 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_SHAREDCACHE 0x00020000 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_PRIVATECACHE 0x00040000 /* Ok for sqlite3_open_v2() */ #define SQLITE_OPEN_WAL 0x00080000 /* VFS only */ /* Reserved: 0x00F00000 */ /* ** CAPI3REF: Device Characteristics ** ** The xDeviceCharacteristics method of the [sqlite3_io_methods] ** object returns an integer which is a vector of the these ** bit values expressing I/O characteristics of the mass storage ** device that holds the file that the [sqlite3_io_methods] ** refers to. ** ** The SQLITE_IOCAP_ATOMIC property means that all writes of ** any size are atomic. The SQLITE_IOCAP_ATOMICnnn values ** mean that writes of blocks that are nnn bytes in size and ** are aligned to an address which is an integer multiple of ** nnn are atomic. The SQLITE_IOCAP_SAFE_APPEND value means ** that when data is appended to a file, the data is appended ** first then the size of the file is extended, never the other ** way around. The SQLITE_IOCAP_SEQUENTIAL property means that ** information is written to disk in the same order as calls ** to xWrite(). */ #define SQLITE_IOCAP_ATOMIC 0x00000001 #define SQLITE_IOCAP_ATOMIC512 0x00000002 #define SQLITE_IOCAP_ATOMIC1K 0x00000004 #define SQLITE_IOCAP_ATOMIC2K 0x00000008 #define SQLITE_IOCAP_ATOMIC4K 0x00000010 #define SQLITE_IOCAP_ATOMIC8K 0x00000020 #define SQLITE_IOCAP_ATOMIC16K 0x00000040 #define SQLITE_IOCAP_ATOMIC32K 0x00000080 #define SQLITE_IOCAP_ATOMIC64K 0x00000100 #define SQLITE_IOCAP_SAFE_APPEND 0x00000200 #define SQLITE_IOCAP_SEQUENTIAL 0x00000400 #define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800 /* ** CAPI3REF: File Locking Levels ** ** SQLite uses one of these integer values as the second ** argument to calls it makes to the xLock() and xUnlock() methods ** of an [sqlite3_io_methods] object. */ #define SQLITE_LOCK_NONE 0 #define SQLITE_LOCK_SHARED 1 #define SQLITE_LOCK_RESERVED 2 #define SQLITE_LOCK_PENDING 3 #define SQLITE_LOCK_EXCLUSIVE 4 /* ** CAPI3REF: Synchronization Type Flags ** ** When SQLite invokes the xSync() method of an ** [sqlite3_io_methods] object it uses a combination of ** these integer values as the second argument. ** ** When the SQLITE_SYNC_DATAONLY flag is used, it means that the ** sync operation only needs to flush data to mass storage. Inode ** information need not be flushed. If the lower four bits of the flag ** equal SQLITE_SYNC_NORMAL, that means to use normal fsync() semantics. ** If the lower four bits equal SQLITE_SYNC_FULL, that means ** to use Mac OS X style fullsync instead of fsync(). ** ** Do not confuse the SQLITE_SYNC_NORMAL and SQLITE_SYNC_FULL flags ** with the [PRAGMA synchronous]=NORMAL and [PRAGMA synchronous]=FULL ** settings. The [synchronous pragma] determines when calls to the ** xSync VFS method occur and applies uniformly across all platforms. ** The SQLITE_SYNC_NORMAL and SQLITE_SYNC_FULL flags determine how ** energetic or rigorous or forceful the sync operations are and ** only make a difference on Mac OSX for the default SQLite code. ** (Third-party VFS implementations might also make the distinction ** between SQLITE_SYNC_NORMAL and SQLITE_SYNC_FULL, but among the ** operating systems natively supported by SQLite, only Mac OSX ** cares about the difference.) */ #define SQLITE_SYNC_NORMAL 0x00002 #define SQLITE_SYNC_FULL 0x00003 #define SQLITE_SYNC_DATAONLY 0x00010 /* ** CAPI3REF: OS Interface Open File Handle ** ** An [sqlite3_file] object represents an open file in the ** [sqlite3_vfs | OS interface layer]. Individual OS interface ** implementations will ** want to subclass this object by appending additional fields ** for their own use. The pMethods entry is a pointer to an ** [sqlite3_io_methods] object that defines methods for performing ** I/O operations on the open file. */ typedef struct sqlite3_file sqlite3_file; struct sqlite3_file { const struct sqlite3_io_methods *pMethods; /* Methods for an open file */ }; /* ** CAPI3REF: OS Interface File Virtual Methods Object ** ** Every file opened by the [sqlite3_vfs.xOpen] method populates an ** [sqlite3_file] object (or, more commonly, a subclass of the ** [sqlite3_file] object) with a pointer to an instance of this object. ** This object defines the methods used to perform various operations ** against the open file represented by the [sqlite3_file] object. ** ** If the [sqlite3_vfs.xOpen] method sets the sqlite3_file.pMethods element ** to a non-NULL pointer, then the sqlite3_io_methods.xClose method ** may be invoked even if the [sqlite3_vfs.xOpen] reported that it failed. The ** only way to prevent a call to xClose following a failed [sqlite3_vfs.xOpen] ** is for the [sqlite3_vfs.xOpen] to set the sqlite3_file.pMethods element ** to NULL. ** ** The flags argument to xSync may be one of [SQLITE_SYNC_NORMAL] or ** [SQLITE_SYNC_FULL]. The first choice is the normal fsync(). ** The second choice is a Mac OS X style fullsync. The [SQLITE_SYNC_DATAONLY] ** flag may be ORed in to indicate that only the data of the file ** and not its inode needs to be synced. ** ** The integer values to xLock() and xUnlock() are one of **
    **
  • [SQLITE_LOCK_NONE], **
  • [SQLITE_LOCK_SHARED], **
  • [SQLITE_LOCK_RESERVED], **
  • [SQLITE_LOCK_PENDING], or **
  • [SQLITE_LOCK_EXCLUSIVE]. **
** xLock() increases the lock. xUnlock() decreases the lock. ** The xCheckReservedLock() method checks whether any database connection, ** either in this process or in some other process, is holding a RESERVED, ** PENDING, or EXCLUSIVE lock on the file. It returns true ** if such a lock exists and false otherwise. ** ** The xFileControl() method is a generic interface that allows custom ** VFS implementations to directly control an open file using the ** [sqlite3_file_control()] interface. The second "op" argument is an ** integer opcode. The third argument is a generic pointer intended to ** point to a structure that may contain arguments or space in which to ** write return values. Potential uses for xFileControl() might be ** functions to enable blocking locks with timeouts, to change the ** locking strategy (for example to use dot-file locks), to inquire ** about the status of a lock, or to break stale locks. The SQLite ** core reserves all opcodes less than 100 for its own use. ** A [SQLITE_FCNTL_LOCKSTATE | list of opcodes] less than 100 is available. ** Applications that define a custom xFileControl method should use opcodes ** greater than 100 to avoid conflicts. VFS implementations should ** return [SQLITE_NOTFOUND] for file control opcodes that they do not ** recognize. ** ** The xSectorSize() method returns the sector size of the ** device that underlies the file. The sector size is the ** minimum write that can be performed without disturbing ** other bytes in the file. The xDeviceCharacteristics() ** method returns a bit vector describing behaviors of the ** underlying device: ** **
    **
  • [SQLITE_IOCAP_ATOMIC] **
  • [SQLITE_IOCAP_ATOMIC512] **
  • [SQLITE_IOCAP_ATOMIC1K] **
  • [SQLITE_IOCAP_ATOMIC2K] **
  • [SQLITE_IOCAP_ATOMIC4K] **
  • [SQLITE_IOCAP_ATOMIC8K] **
  • [SQLITE_IOCAP_ATOMIC16K] **
  • [SQLITE_IOCAP_ATOMIC32K] **
  • [SQLITE_IOCAP_ATOMIC64K] **
  • [SQLITE_IOCAP_SAFE_APPEND] **
  • [SQLITE_IOCAP_SEQUENTIAL] **
** ** The SQLITE_IOCAP_ATOMIC property means that all writes of ** any size are atomic. The SQLITE_IOCAP_ATOMICnnn values ** mean that writes of blocks that are nnn bytes in size and ** are aligned to an address which is an integer multiple of ** nnn are atomic. The SQLITE_IOCAP_SAFE_APPEND value means ** that when data is appended to a file, the data is appended ** first then the size of the file is extended, never the other ** way around. The SQLITE_IOCAP_SEQUENTIAL property means that ** information is written to disk in the same order as calls ** to xWrite(). ** ** If xRead() returns SQLITE_IOERR_SHORT_READ it must also fill ** in the unread portions of the buffer with zeros. A VFS that ** fails to zero-fill short reads might seem to work. However, ** failure to zero-fill short reads will eventually lead to ** database corruption. */ typedef struct sqlite3_io_methods sqlite3_io_methods; struct sqlite3_io_methods { int iVersion; int (*xClose)(sqlite3_file*); int (*xRead)(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); int (*xWrite)(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst); int (*xTruncate)(sqlite3_file*, sqlite3_int64 size); int (*xSync)(sqlite3_file*, int flags); int (*xFileSize)(sqlite3_file*, sqlite3_int64 *pSize); int (*xLock)(sqlite3_file*, int); int (*xUnlock)(sqlite3_file*, int); int (*xCheckReservedLock)(sqlite3_file*, int *pResOut); int (*xFileControl)(sqlite3_file*, int op, void *pArg); int (*xSectorSize)(sqlite3_file*); int (*xDeviceCharacteristics)(sqlite3_file*); /* Methods above are valid for version 1 */ int (*xShmMap)(sqlite3_file*, int iPg, int pgsz, int, void volatile**); int (*xShmLock)(sqlite3_file*, int offset, int n, int flags); void (*xShmBarrier)(sqlite3_file*); int (*xShmUnmap)(sqlite3_file*, int deleteFlag); /* Methods above are valid for version 2 */ /* Additional methods may be added in future releases */ }; /* ** CAPI3REF: Standard File Control Opcodes ** ** These integer constants are opcodes for the xFileControl method ** of the [sqlite3_io_methods] object and for the [sqlite3_file_control()] ** interface. ** ** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This ** opcode causes the xFileControl method to write the current state of ** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED], ** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE]) ** into an integer that the pArg argument points to. This capability ** is used during testing and only needs to be supported when SQLITE_TEST ** is defined. ** ** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS ** layer a hint of how large the database file will grow to be during the ** current transaction. This hint is not guaranteed to be accurate but it ** is often close. The underlying VFS might choose to preallocate database ** file space based on this hint in order to help writes to the database ** file run faster. ** ** The [SQLITE_FCNTL_CHUNK_SIZE] opcode is used to request that the VFS ** extends and truncates the database file in chunks of a size specified ** by the user. The fourth argument to [sqlite3_file_control()] should ** point to an integer (type int) containing the new chunk-size to use ** for the nominated database. Allocating database file space in large ** chunks (say 1MB at a time), may reduce file-system fragmentation and ** improve performance on some systems. ** ** The [SQLITE_FCNTL_FILE_POINTER] opcode is used to obtain a pointer ** to the [sqlite3_file] object associated with a particular database ** connection. See the [sqlite3_file_control()] documentation for ** additional information. ** ** ^(The [SQLITE_FCNTL_SYNC_OMITTED] opcode is generated internally by ** SQLite and sent to all VFSes in place of a call to the xSync method ** when the database connection has [PRAGMA synchronous] set to OFF.)^ ** Some specialized VFSes need this signal in order to operate correctly ** when [PRAGMA synchronous | PRAGMA synchronous=OFF] is set, but most ** VFSes do not need this signal and should silently ignore this opcode. ** Applications should not call [sqlite3_file_control()] with this ** opcode as doing so may disrupt the operation of the specialized VFSes ** that do require it. ** ** ^The [SQLITE_FCNTL_WIN32_AV_RETRY] opcode is used to configure automatic ** retry counts and intervals for certain disk I/O operations for the ** windows [VFS] in order to work to provide robustness against ** anti-virus programs. By default, the windows VFS will retry file read, ** file write, and file delete opertions up to 10 times, with a delay ** of 25 milliseconds before the first retry and with the delay increasing ** by an additional 25 milliseconds with each subsequent retry. This ** opcode allows those to values (10 retries and 25 milliseconds of delay) ** to be adjusted. The values are changed for all database connections ** within the same process. The argument is a pointer to an array of two ** integers where the first integer i the new retry count and the second ** integer is the delay. If either integer is negative, then the setting ** is not changed but instead the prior value of that setting is written ** into the array entry, allowing the current retry settings to be ** interrogated. The zDbName parameter is ignored. ** ** ^The [SQLITE_FCNTL_PERSIST_WAL] opcode is used to set or query the ** persistent [WAL | Write AHead Log] setting. By default, the auxiliary ** write ahead log and shared memory files used for transaction control ** are automatically deleted when the latest connection to the database ** closes. Setting persistent WAL mode causes those files to persist after ** close. Persisting the files is useful when other processes that do not ** have write permission on the directory containing the database file want ** to read the database file, as the WAL and shared memory files must exist ** in order for the database to be readable. The fourth parameter to ** [sqlite3_file_control()] for this opcode should be a pointer to an integer. ** That integer is 0 to disable persistent WAL mode or 1 to enable persistent ** WAL mode. If the integer is -1, then it is overwritten with the current ** WAL persistence setting. ** ** ^The [SQLITE_FCNTL_OVERWRITE] opcode is invoked by SQLite after opening ** a write transaction to indicate that, unless it is rolled back for some ** reason, the entire database file will be overwritten by the current ** transaction. This is used by VACUUM operations. */ #define SQLITE_FCNTL_LOCKSTATE 1 #define SQLITE_GET_LOCKPROXYFILE 2 #define SQLITE_SET_LOCKPROXYFILE 3 #define SQLITE_LAST_ERRNO 4 #define SQLITE_FCNTL_SIZE_HINT 5 #define SQLITE_FCNTL_CHUNK_SIZE 6 #define SQLITE_FCNTL_FILE_POINTER 7 #define SQLITE_FCNTL_SYNC_OMITTED 8 #define SQLITE_FCNTL_WIN32_AV_RETRY 9 #define SQLITE_FCNTL_PERSIST_WAL 10 #define SQLITE_FCNTL_OVERWRITE 11 /* ** CAPI3REF: Mutex Handle ** ** The mutex module within SQLite defines [sqlite3_mutex] to be an ** abstract type for a mutex object. The SQLite core never looks ** at the internal representation of an [sqlite3_mutex]. It only ** deals with pointers to the [sqlite3_mutex] object. ** ** Mutexes are created using [sqlite3_mutex_alloc()]. */ typedef struct sqlite3_mutex sqlite3_mutex; /* ** CAPI3REF: OS Interface Object ** ** An instance of the sqlite3_vfs object defines the interface between ** the SQLite core and the underlying operating system. The "vfs" ** in the name of the object stands for "virtual file system". See ** the [VFS | VFS documentation] for further information. ** ** The value of the iVersion field is initially 1 but may be larger in ** future versions of SQLite. Additional fields may be appended to this ** object when the iVersion value is increased. Note that the structure ** of the sqlite3_vfs object changes in the transaction between ** SQLite version 3.5.9 and 3.6.0 and yet the iVersion field was not ** modified. ** ** The szOsFile field is the size of the subclassed [sqlite3_file] ** structure used by this VFS. mxPathname is the maximum length of ** a pathname in this VFS. ** ** Registered sqlite3_vfs objects are kept on a linked list formed by ** the pNext pointer. The [sqlite3_vfs_register()] ** and [sqlite3_vfs_unregister()] interfaces manage this list ** in a thread-safe way. The [sqlite3_vfs_find()] interface ** searches the list. Neither the application code nor the VFS ** implementation should use the pNext pointer. ** ** The pNext field is the only field in the sqlite3_vfs ** structure that SQLite will ever modify. SQLite will only access ** or modify this field while holding a particular static mutex. ** The application should never modify anything within the sqlite3_vfs ** object once the object has been registered. ** ** The zName field holds the name of the VFS module. The name must ** be unique across all VFS modules. ** ** [[sqlite3_vfs.xOpen]] ** ^SQLite guarantees that the zFilename parameter to xOpen ** is either a NULL pointer or string obtained ** from xFullPathname() with an optional suffix added. ** ^If a suffix is added to the zFilename parameter, it will ** consist of a single "-" character followed by no more than ** 10 alphanumeric and/or "-" characters. ** ^SQLite further guarantees that ** the string will be valid and unchanged until xClose() is ** called. Because of the previous sentence, ** the [sqlite3_file] can safely store a pointer to the ** filename if it needs to remember the filename for some reason. ** If the zFilename parameter to xOpen is a NULL pointer then xOpen ** must invent its own temporary name for the file. ^Whenever the ** xFilename parameter is NULL it will also be the case that the ** flags parameter will include [SQLITE_OPEN_DELETEONCLOSE]. ** ** The flags argument to xOpen() includes all bits set in ** the flags argument to [sqlite3_open_v2()]. Or if [sqlite3_open()] ** or [sqlite3_open16()] is used, then flags includes at least ** [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]. ** If xOpen() opens a file read-only then it sets *pOutFlags to ** include [SQLITE_OPEN_READONLY]. Other bits in *pOutFlags may be set. ** ** ^(SQLite will also add one of the following flags to the xOpen() ** call, depending on the object being opened: ** **
    **
  • [SQLITE_OPEN_MAIN_DB] **
  • [SQLITE_OPEN_MAIN_JOURNAL] **
  • [SQLITE_OPEN_TEMP_DB] **
  • [SQLITE_OPEN_TEMP_JOURNAL] **
  • [SQLITE_OPEN_TRANSIENT_DB] **
  • [SQLITE_OPEN_SUBJOURNAL] **
  • [SQLITE_OPEN_MASTER_JOURNAL] **
  • [SQLITE_OPEN_WAL] **
)^ ** ** The file I/O implementation can use the object type flags to ** change the way it deals with files. For example, an application ** that does not care about crash recovery or rollback might make ** the open of a journal file a no-op. Writes to this journal would ** also be no-ops, and any attempt to read the journal would return ** SQLITE_IOERR. Or the implementation might recognize that a database ** file will be doing page-aligned sector reads and writes in a random ** order and set up its I/O subsystem accordingly. ** ** SQLite might also add one of the following flags to the xOpen method: ** **
    **
  • [SQLITE_OPEN_DELETEONCLOSE] **
  • [SQLITE_OPEN_EXCLUSIVE] **
** ** The [SQLITE_OPEN_DELETEONCLOSE] flag means the file should be ** deleted when it is closed. ^The [SQLITE_OPEN_DELETEONCLOSE] ** will be set for TEMP databases and their journals, transient ** databases, and subjournals. ** ** ^The [SQLITE_OPEN_EXCLUSIVE] flag is always used in conjunction ** with the [SQLITE_OPEN_CREATE] flag, which are both directly ** analogous to the O_EXCL and O_CREAT flags of the POSIX open() ** API. The SQLITE_OPEN_EXCLUSIVE flag, when paired with the ** SQLITE_OPEN_CREATE, is used to indicate that file should always ** be created, and that it is an error if it already exists. ** It is not used to indicate the file should be opened ** for exclusive access. ** ** ^At least szOsFile bytes of memory are allocated by SQLite ** to hold the [sqlite3_file] structure passed as the third ** argument to xOpen. The xOpen method does not have to ** allocate the structure; it should just fill it in. Note that ** the xOpen method must set the sqlite3_file.pMethods to either ** a valid [sqlite3_io_methods] object or to NULL. xOpen must do ** this even if the open fails. SQLite expects that the sqlite3_file.pMethods ** element will be valid after xOpen returns regardless of the success ** or failure of the xOpen call. ** ** [[sqlite3_vfs.xAccess]] ** ^The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS] ** to test for the existence of a file, or [SQLITE_ACCESS_READWRITE] to ** test whether a file is readable and writable, or [SQLITE_ACCESS_READ] ** to test whether a file is at least readable. The file can be a ** directory. ** ** ^SQLite will always allocate at least mxPathname+1 bytes for the ** output buffer xFullPathname. The exact size of the output buffer ** is also passed as a parameter to both methods. If the output buffer ** is not large enough, [SQLITE_CANTOPEN] should be returned. Since this is ** handled as a fatal error by SQLite, vfs implementations should endeavor ** to prevent this by setting mxPathname to a sufficiently large value. ** ** The xRandomness(), xSleep(), xCurrentTime(), and xCurrentTimeInt64() ** interfaces are not strictly a part of the filesystem, but they are ** included in the VFS structure for completeness. ** The xRandomness() function attempts to return nBytes bytes ** of good-quality randomness into zOut. The return value is ** the actual number of bytes of randomness obtained. ** The xSleep() method causes the calling thread to sleep for at ** least the number of microseconds given. ^The xCurrentTime() ** method returns a Julian Day Number for the current date and time as ** a floating point value. ** ^The xCurrentTimeInt64() method returns, as an integer, the Julian ** Day Number multiplied by 86400000 (the number of milliseconds in ** a 24-hour day). ** ^SQLite will use the xCurrentTimeInt64() method to get the current ** date and time if that method is available (if iVersion is 2 or ** greater and the function pointer is not NULL) and will fall back ** to xCurrentTime() if xCurrentTimeInt64() is unavailable. ** ** ^The xSetSystemCall(), xGetSystemCall(), and xNestSystemCall() interfaces ** are not used by the SQLite core. These optional interfaces are provided ** by some VFSes to facilitate testing of the VFS code. By overriding ** system calls with functions under its control, a test program can ** simulate faults and error conditions that would otherwise be difficult ** or impossible to induce. The set of system calls that can be overridden ** varies from one VFS to another, and from one version of the same VFS to the ** next. Applications that use these interfaces must be prepared for any ** or all of these interfaces to be NULL or for their behavior to change ** from one release to the next. Applications must not attempt to access ** any of these methods if the iVersion of the VFS is less than 3. */ typedef struct sqlite3_vfs sqlite3_vfs; typedef void (*sqlite3_syscall_ptr)(void); struct sqlite3_vfs { int iVersion; /* Structure version number (currently 3) */ int szOsFile; /* Size of subclassed sqlite3_file */ int mxPathname; /* Maximum file pathname length */ sqlite3_vfs *pNext; /* Next registered VFS */ const char *zName; /* Name of this virtual file system */ void *pAppData; /* Pointer to application-specific data */ int (*xOpen)(sqlite3_vfs*, const char *zName, sqlite3_file*, int flags, int *pOutFlags); int (*xDelete)(sqlite3_vfs*, const char *zName, int syncDir); int (*xAccess)(sqlite3_vfs*, const char *zName, int flags, int *pResOut); int (*xFullPathname)(sqlite3_vfs*, const char *zName, int nOut, char *zOut); void *(*xDlOpen)(sqlite3_vfs*, const char *zFilename); void (*xDlError)(sqlite3_vfs*, int nByte, char *zErrMsg); void (*(*xDlSym)(sqlite3_vfs*,void*, const char *zSymbol))(void); void (*xDlClose)(sqlite3_vfs*, void*); int (*xRandomness)(sqlite3_vfs*, int nByte, char *zOut); int (*xSleep)(sqlite3_vfs*, int microseconds); int (*xCurrentTime)(sqlite3_vfs*, double*); int (*xGetLastError)(sqlite3_vfs*, int, char *); /* ** The methods above are in version 1 of the sqlite_vfs object ** definition. Those that follow are added in version 2 or later */ int (*xCurrentTimeInt64)(sqlite3_vfs*, sqlite3_int64*); /* ** The methods above are in versions 1 and 2 of the sqlite_vfs object. ** Those below are for version 3 and greater. */ int (*xSetSystemCall)(sqlite3_vfs*, const char *zName, sqlite3_syscall_ptr); sqlite3_syscall_ptr (*xGetSystemCall)(sqlite3_vfs*, const char *zName); const char *(*xNextSystemCall)(sqlite3_vfs*, const char *zName); /* ** The methods above are in versions 1 through 3 of the sqlite_vfs object. ** New fields may be appended in figure versions. The iVersion ** value will increment whenever this happens. */ }; /* ** CAPI3REF: Flags for the xAccess VFS method ** ** These integer constants can be used as the third parameter to ** the xAccess method of an [sqlite3_vfs] object. They determine ** what kind of permissions the xAccess method is looking for. ** With SQLITE_ACCESS_EXISTS, the xAccess method ** simply checks whether the file exists. ** With SQLITE_ACCESS_READWRITE, the xAccess method ** checks whether the named directory is both readable and writable ** (in other words, if files can be added, removed, and renamed within ** the directory). ** The SQLITE_ACCESS_READWRITE constant is currently used only by the ** [temp_store_directory pragma], though this could change in a future ** release of SQLite. ** With SQLITE_ACCESS_READ, the xAccess method ** checks whether the file is readable. The SQLITE_ACCESS_READ constant is ** currently unused, though it might be used in a future release of ** SQLite. */ #define SQLITE_ACCESS_EXISTS 0 #define SQLITE_ACCESS_READWRITE 1 /* Used by PRAGMA temp_store_directory */ #define SQLITE_ACCESS_READ 2 /* Unused */ /* ** CAPI3REF: Flags for the xShmLock VFS method ** ** These integer constants define the various locking operations ** allowed by the xShmLock method of [sqlite3_io_methods]. The ** following are the only legal combinations of flags to the ** xShmLock method: ** **
    **
  • SQLITE_SHM_LOCK | SQLITE_SHM_SHARED **
  • SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE **
  • SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED **
  • SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE **
** ** When unlocking, the same SHARED or EXCLUSIVE flag must be supplied as ** was given no the corresponding lock. ** ** The xShmLock method can transition between unlocked and SHARED or ** between unlocked and EXCLUSIVE. It cannot transition between SHARED ** and EXCLUSIVE. */ #define SQLITE_SHM_UNLOCK 1 #define SQLITE_SHM_LOCK 2 #define SQLITE_SHM_SHARED 4 #define SQLITE_SHM_EXCLUSIVE 8 /* ** CAPI3REF: Maximum xShmLock index ** ** The xShmLock method on [sqlite3_io_methods] may use values ** between 0 and this upper bound as its "offset" argument. ** The SQLite core will never attempt to acquire or release a ** lock outside of this range */ #define SQLITE_SHM_NLOCK 8 /* ** CAPI3REF: Initialize The SQLite Library ** ** ^The sqlite3_initialize() routine initializes the ** SQLite library. ^The sqlite3_shutdown() routine ** deallocates any resources that were allocated by sqlite3_initialize(). ** These routines are designed to aid in process initialization and ** shutdown on embedded systems. Workstation applications using ** SQLite normally do not need to invoke either of these routines. ** ** A call to sqlite3_initialize() is an "effective" call if it is ** the first time sqlite3_initialize() is invoked during the lifetime of ** the process, or if it is the first time sqlite3_initialize() is invoked ** following a call to sqlite3_shutdown(). ^(Only an effective call ** of sqlite3_initialize() does any initialization. All other calls ** are harmless no-ops.)^ ** ** A call to sqlite3_shutdown() is an "effective" call if it is the first ** call to sqlite3_shutdown() since the last sqlite3_initialize(). ^(Only ** an effective call to sqlite3_shutdown() does any deinitialization. ** All other valid calls to sqlite3_shutdown() are harmless no-ops.)^ ** ** The sqlite3_initialize() interface is threadsafe, but sqlite3_shutdown() ** is not. The sqlite3_shutdown() interface must only be called from a ** single thread. All open [database connections] must be closed and all ** other SQLite resources must be deallocated prior to invoking ** sqlite3_shutdown(). ** ** Among other things, ^sqlite3_initialize() will invoke ** sqlite3_os_init(). Similarly, ^sqlite3_shutdown() ** will invoke sqlite3_os_end(). ** ** ^The sqlite3_initialize() routine returns [SQLITE_OK] on success. ** ^If for some reason, sqlite3_initialize() is unable to initialize ** the library (perhaps it is unable to allocate a needed resource such ** as a mutex) it returns an [error code] other than [SQLITE_OK]. ** ** ^The sqlite3_initialize() routine is called internally by many other ** SQLite interfaces so that an application usually does not need to ** invoke sqlite3_initialize() directly. For example, [sqlite3_open()] ** calls sqlite3_initialize() so the SQLite library will be automatically ** initialized when [sqlite3_open()] is called if it has not be initialized ** already. ^However, if SQLite is compiled with the [SQLITE_OMIT_AUTOINIT] ** compile-time option, then the automatic calls to sqlite3_initialize() ** are omitted and the application must call sqlite3_initialize() directly ** prior to using any other SQLite interface. For maximum portability, ** it is recommended that applications always invoke sqlite3_initialize() ** directly prior to using any other SQLite interface. Future releases ** of SQLite may require this. In other words, the behavior exhibited ** when SQLite is compiled with [SQLITE_OMIT_AUTOINIT] might become the ** default behavior in some future release of SQLite. ** ** The sqlite3_os_init() routine does operating-system specific ** initialization of the SQLite library. The sqlite3_os_end() ** routine undoes the effect of sqlite3_os_init(). Typical tasks ** performed by these routines include allocation or deallocation ** of static resources, initialization of global variables, ** setting up a default [sqlite3_vfs] module, or setting up ** a default configuration using [sqlite3_config()]. ** ** The application should never invoke either sqlite3_os_init() ** or sqlite3_os_end() directly. The application should only invoke ** sqlite3_initialize() and sqlite3_shutdown(). The sqlite3_os_init() ** interface is called automatically by sqlite3_initialize() and ** sqlite3_os_end() is called by sqlite3_shutdown(). Appropriate ** implementations for sqlite3_os_init() and sqlite3_os_end() ** are built into SQLite when it is compiled for Unix, Windows, or OS/2. ** When [custom builds | built for other platforms] ** (using the [SQLITE_OS_OTHER=1] compile-time ** option) the application must supply a suitable implementation for ** sqlite3_os_init() and sqlite3_os_end(). An application-supplied ** implementation of sqlite3_os_init() or sqlite3_os_end() ** must return [SQLITE_OK] on success and some other [error code] upon ** failure. */ SQLITE_API int sqlite3_initialize(void); SQLITE_API int sqlite3_shutdown(void); SQLITE_API int sqlite3_os_init(void); SQLITE_API int sqlite3_os_end(void); /* ** CAPI3REF: Configuring The SQLite Library ** ** The sqlite3_config() interface is used to make global configuration ** changes to SQLite in order to tune SQLite to the specific needs of ** the application. The default configuration is recommended for most ** applications and so this routine is usually not necessary. It is ** provided to support rare applications with unusual needs. ** ** The sqlite3_config() interface is not threadsafe. The application ** must insure that no other SQLite interfaces are invoked by other ** threads while sqlite3_config() is running. Furthermore, sqlite3_config() ** may only be invoked prior to library initialization using ** [sqlite3_initialize()] or after shutdown by [sqlite3_shutdown()]. ** ^If sqlite3_config() is called after [sqlite3_initialize()] and before ** [sqlite3_shutdown()] then it will return SQLITE_MISUSE. ** Note, however, that ^sqlite3_config() can be called as part of the ** implementation of an application-defined [sqlite3_os_init()]. ** ** The first argument to sqlite3_config() is an integer ** [configuration option] that determines ** what property of SQLite is to be configured. Subsequent arguments ** vary depending on the [configuration option] ** in the first argument. ** ** ^When a configuration option is set, sqlite3_config() returns [SQLITE_OK]. ** ^If the option is unknown or SQLite is unable to set the option ** then this routine returns a non-zero [error code]. */ SQLITE_API int sqlite3_config(int, ...); /* ** CAPI3REF: Configure database connections ** ** The sqlite3_db_config() interface is used to make configuration ** changes to a [database connection]. The interface is similar to ** [sqlite3_config()] except that the changes apply to a single ** [database connection] (specified in the first argument). ** ** The second argument to sqlite3_db_config(D,V,...) is the ** [SQLITE_DBCONFIG_LOOKASIDE | configuration verb] - an integer code ** that indicates what aspect of the [database connection] is being configured. ** Subsequent arguments vary depending on the configuration verb. ** ** ^Calls to sqlite3_db_config() return SQLITE_OK if and only if ** the call is considered successful. */ SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...); /* ** CAPI3REF: Memory Allocation Routines ** ** An instance of this object defines the interface between SQLite ** and low-level memory allocation routines. ** ** This object is used in only one place in the SQLite interface. ** A pointer to an instance of this object is the argument to ** [sqlite3_config()] when the configuration option is ** [SQLITE_CONFIG_MALLOC] or [SQLITE_CONFIG_GETMALLOC]. ** By creating an instance of this object ** and passing it to [sqlite3_config]([SQLITE_CONFIG_MALLOC]) ** during configuration, an application can specify an alternative ** memory allocation subsystem for SQLite to use for all of its ** dynamic memory needs. ** ** Note that SQLite comes with several [built-in memory allocators] ** that are perfectly adequate for the overwhelming majority of applications ** and that this object is only useful to a tiny minority of applications ** with specialized memory allocation requirements. This object is ** also used during testing of SQLite in order to specify an alternative ** memory allocator that simulates memory out-of-memory conditions in ** order to verify that SQLite recovers gracefully from such ** conditions. ** ** The xMalloc, xRealloc, and xFree methods must work like the ** malloc(), realloc() and free() functions from the standard C library. ** ^SQLite guarantees that the second argument to ** xRealloc is always a value returned by a prior call to xRoundup. ** ** xSize should return the allocated size of a memory allocation ** previously obtained from xMalloc or xRealloc. The allocated size ** is always at least as big as the requested size but may be larger. ** ** The xRoundup method returns what would be the allocated size of ** a memory allocation given a particular requested size. Most memory ** allocators round up memory allocations at least to the next multiple ** of 8. Some allocators round up to a larger multiple or to a power of 2. ** Every memory allocation request coming in through [sqlite3_malloc()] ** or [sqlite3_realloc()] first calls xRoundup. If xRoundup returns 0, ** that causes the corresponding memory allocation to fail. ** ** The xInit method initializes the memory allocator. (For example, ** it might allocate any require mutexes or initialize internal data ** structures. The xShutdown method is invoked (indirectly) by ** [sqlite3_shutdown()] and should deallocate any resources acquired ** by xInit. The pAppData pointer is used as the only parameter to ** xInit and xShutdown. ** ** SQLite holds the [SQLITE_MUTEX_STATIC_MASTER] mutex when it invokes ** the xInit method, so the xInit method need not be threadsafe. The ** xShutdown method is only called from [sqlite3_shutdown()] so it does ** not need to be threadsafe either. For all other methods, SQLite ** holds the [SQLITE_MUTEX_STATIC_MEM] mutex as long as the ** [SQLITE_CONFIG_MEMSTATUS] configuration option is turned on (which ** it is by default) and so the methods are automatically serialized. ** However, if [SQLITE_CONFIG_MEMSTATUS] is disabled, then the other ** methods must be threadsafe or else make their own arrangements for ** serialization. ** ** SQLite will never invoke xInit() more than once without an intervening ** call to xShutdown(). */ typedef struct sqlite3_mem_methods sqlite3_mem_methods; struct sqlite3_mem_methods { void *(*xMalloc)(int); /* Memory allocation function */ void (*xFree)(void*); /* Free a prior allocation */ void *(*xRealloc)(void*,int); /* Resize an allocation */ int (*xSize)(void*); /* Return the size of an allocation */ int (*xRoundup)(int); /* Round up request size to allocation size */ int (*xInit)(void*); /* Initialize the memory allocator */ void (*xShutdown)(void*); /* Deinitialize the memory allocator */ void *pAppData; /* Argument to xInit() and xShutdown() */ }; /* ** CAPI3REF: Configuration Options ** KEYWORDS: {configuration option} ** ** These constants are the available integer configuration options that ** can be passed as the first argument to the [sqlite3_config()] interface. ** ** New configuration options may be added in future releases of SQLite. ** Existing configuration options might be discontinued. Applications ** should check the return code from [sqlite3_config()] to make sure that ** the call worked. The [sqlite3_config()] interface will return a ** non-zero [error code] if a discontinued or unsupported configuration option ** is invoked. ** **
** [[SQLITE_CONFIG_SINGLETHREAD]]
SQLITE_CONFIG_SINGLETHREAD
**
There are no arguments to this option. ^This option sets the ** [threading mode] to Single-thread. In other words, it disables ** all mutexing and puts SQLite into a mode where it can only be used ** by a single thread. ^If SQLite is compiled with ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then ** it is not possible to change the [threading mode] from its default ** value of Single-thread and so [sqlite3_config()] will return ** [SQLITE_ERROR] if called with the SQLITE_CONFIG_SINGLETHREAD ** configuration option.
** ** [[SQLITE_CONFIG_MULTITHREAD]]
SQLITE_CONFIG_MULTITHREAD
**
There are no arguments to this option. ^This option sets the ** [threading mode] to Multi-thread. In other words, it disables ** mutexing on [database connection] and [prepared statement] objects. ** The application is responsible for serializing access to ** [database connections] and [prepared statements]. But other mutexes ** are enabled so that SQLite will be safe to use in a multi-threaded ** environment as long as no two threads attempt to use the same ** [database connection] at the same time. ^If SQLite is compiled with ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then ** it is not possible to set the Multi-thread [threading mode] and ** [sqlite3_config()] will return [SQLITE_ERROR] if called with the ** SQLITE_CONFIG_MULTITHREAD configuration option.
** ** [[SQLITE_CONFIG_SERIALIZED]]
SQLITE_CONFIG_SERIALIZED
**
There are no arguments to this option. ^This option sets the ** [threading mode] to Serialized. In other words, this option enables ** all mutexes including the recursive ** mutexes on [database connection] and [prepared statement] objects. ** In this mode (which is the default when SQLite is compiled with ** [SQLITE_THREADSAFE=1]) the SQLite library will itself serialize access ** to [database connections] and [prepared statements] so that the ** application is free to use the same [database connection] or the ** same [prepared statement] in different threads at the same time. ** ^If SQLite is compiled with ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then ** it is not possible to set the Serialized [threading mode] and ** [sqlite3_config()] will return [SQLITE_ERROR] if called with the ** SQLITE_CONFIG_SERIALIZED configuration option.
** ** [[SQLITE_CONFIG_MALLOC]]
SQLITE_CONFIG_MALLOC
**
^(This option takes a single argument which is a pointer to an ** instance of the [sqlite3_mem_methods] structure. The argument specifies ** alternative low-level memory allocation routines to be used in place of ** the memory allocation routines built into SQLite.)^ ^SQLite makes ** its own private copy of the content of the [sqlite3_mem_methods] structure ** before the [sqlite3_config()] call returns.
** ** [[SQLITE_CONFIG_GETMALLOC]]
SQLITE_CONFIG_GETMALLOC
**
^(This option takes a single argument which is a pointer to an ** instance of the [sqlite3_mem_methods] structure. The [sqlite3_mem_methods] ** structure is filled with the currently defined memory allocation routines.)^ ** This option can be used to overload the default memory allocation ** routines with a wrapper that simulations memory allocation failure or ** tracks memory usage, for example.
** ** [[SQLITE_CONFIG_MEMSTATUS]]
SQLITE_CONFIG_MEMSTATUS
**
^This option takes single argument of type int, interpreted as a ** boolean, which enables or disables the collection of memory allocation ** statistics. ^(When memory allocation statistics are disabled, the ** following SQLite interfaces become non-operational: **
    **
  • [sqlite3_memory_used()] **
  • [sqlite3_memory_highwater()] **
  • [sqlite3_soft_heap_limit64()] **
  • [sqlite3_status()] **
)^ ** ^Memory allocation statistics are enabled by default unless SQLite is ** compiled with [SQLITE_DEFAULT_MEMSTATUS]=0 in which case memory ** allocation statistics are disabled by default. **
** ** [[SQLITE_CONFIG_SCRATCH]]
SQLITE_CONFIG_SCRATCH
**
^This option specifies a static memory buffer that SQLite can use for ** scratch memory. There are three arguments: A pointer an 8-byte ** aligned memory buffer from which the scratch allocations will be ** drawn, the size of each scratch allocation (sz), ** and the maximum number of scratch allocations (N). The sz ** argument must be a multiple of 16. ** The first argument must be a pointer to an 8-byte aligned buffer ** of at least sz*N bytes of memory. ** ^SQLite will use no more than two scratch buffers per thread. So ** N should be set to twice the expected maximum number of threads. ** ^SQLite will never require a scratch buffer that is more than 6 ** times the database page size. ^If SQLite needs needs additional ** scratch memory beyond what is provided by this configuration option, then ** [sqlite3_malloc()] will be used to obtain the memory needed.
** ** [[SQLITE_CONFIG_PAGECACHE]]
SQLITE_CONFIG_PAGECACHE
**
^This option specifies a static memory buffer that SQLite can use for ** the database page cache with the default page cache implementation. ** This configuration should not be used if an application-define page ** cache implementation is loaded using the SQLITE_CONFIG_PCACHE option. ** There are three arguments to this option: A pointer to 8-byte aligned ** memory, the size of each page buffer (sz), and the number of pages (N). ** The sz argument should be the size of the largest database page ** (a power of two between 512 and 32768) plus a little extra for each ** page header. ^The page header size is 20 to 40 bytes depending on ** the host architecture. ^It is harmless, apart from the wasted memory, ** to make sz a little too large. The first ** argument should point to an allocation of at least sz*N bytes of memory. ** ^SQLite will use the memory provided by the first argument to satisfy its ** memory needs for the first N pages that it adds to cache. ^If additional ** page cache memory is needed beyond what is provided by this option, then ** SQLite goes to [sqlite3_malloc()] for the additional storage space. ** The pointer in the first argument must ** be aligned to an 8-byte boundary or subsequent behavior of SQLite ** will be undefined.
** ** [[SQLITE_CONFIG_HEAP]]
SQLITE_CONFIG_HEAP
**
^This option specifies a static memory buffer that SQLite will use ** for all of its dynamic memory allocation needs beyond those provided ** for by [SQLITE_CONFIG_SCRATCH] and [SQLITE_CONFIG_PAGECACHE]. ** There are three arguments: An 8-byte aligned pointer to the memory, ** the number of bytes in the memory buffer, and the minimum allocation size. ** ^If the first pointer (the memory pointer) is NULL, then SQLite reverts ** to using its default memory allocator (the system malloc() implementation), ** undoing any prior invocation of [SQLITE_CONFIG_MALLOC]. ^If the ** memory pointer is not NULL and either [SQLITE_ENABLE_MEMSYS3] or ** [SQLITE_ENABLE_MEMSYS5] are defined, then the alternative memory ** allocator is engaged to handle all of SQLites memory allocation needs. ** The first pointer (the memory pointer) must be aligned to an 8-byte ** boundary or subsequent behavior of SQLite will be undefined. ** The minimum allocation size is capped at 2**12. Reasonable values ** for the minimum allocation size are 2**5 through 2**8.
** ** [[SQLITE_CONFIG_MUTEX]]
SQLITE_CONFIG_MUTEX
**
^(This option takes a single argument which is a pointer to an ** instance of the [sqlite3_mutex_methods] structure. The argument specifies ** alternative low-level mutex routines to be used in place ** the mutex routines built into SQLite.)^ ^SQLite makes a copy of the ** content of the [sqlite3_mutex_methods] structure before the call to ** [sqlite3_config()] returns. ^If SQLite is compiled with ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then ** the entire mutexing subsystem is omitted from the build and hence calls to ** [sqlite3_config()] with the SQLITE_CONFIG_MUTEX configuration option will ** return [SQLITE_ERROR].
** ** [[SQLITE_CONFIG_GETMUTEX]]
SQLITE_CONFIG_GETMUTEX
**
^(This option takes a single argument which is a pointer to an ** instance of the [sqlite3_mutex_methods] structure. The ** [sqlite3_mutex_methods] ** structure is filled with the currently defined mutex routines.)^ ** This option can be used to overload the default mutex allocation ** routines with a wrapper used to track mutex usage for performance ** profiling or testing, for example. ^If SQLite is compiled with ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then ** the entire mutexing subsystem is omitted from the build and hence calls to ** [sqlite3_config()] with the SQLITE_CONFIG_GETMUTEX configuration option will ** return [SQLITE_ERROR].
** ** [[SQLITE_CONFIG_LOOKASIDE]]
SQLITE_CONFIG_LOOKASIDE
**
^(This option takes two arguments that determine the default ** memory allocation for the lookaside memory allocator on each ** [database connection]. The first argument is the ** size of each lookaside buffer slot and the second is the number of ** slots allocated to each database connection.)^ ^(This option sets the ** default lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE] ** verb to [sqlite3_db_config()] can be used to change the lookaside ** configuration on individual connections.)^
** ** [[SQLITE_CONFIG_PCACHE]]
SQLITE_CONFIG_PCACHE
**
^(This option takes a single argument which is a pointer to ** an [sqlite3_pcache_methods] object. This object specifies the interface ** to a custom page cache implementation.)^ ^SQLite makes a copy of the ** object and uses it for page cache memory allocations.
** ** [[SQLITE_CONFIG_GETPCACHE]]
SQLITE_CONFIG_GETPCACHE
**
^(This option takes a single argument which is a pointer to an ** [sqlite3_pcache_methods] object. SQLite copies of the current ** page cache implementation into that object.)^
** ** [[SQLITE_CONFIG_LOG]]
SQLITE_CONFIG_LOG
**
^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a ** function with a call signature of void(*)(void*,int,const char*), ** and a pointer to void. ^If the function pointer is not NULL, it is ** invoked by [sqlite3_log()] to process each logging event. ^If the ** function pointer is NULL, the [sqlite3_log()] interface becomes a no-op. ** ^The void pointer that is the second argument to SQLITE_CONFIG_LOG is ** passed through as the first parameter to the application-defined logger ** function whenever that function is invoked. ^The second parameter to ** the logger function is a copy of the first parameter to the corresponding ** [sqlite3_log()] call and is intended to be a [result code] or an ** [extended result code]. ^The third parameter passed to the logger is ** log message after formatting via [sqlite3_snprintf()]. ** The SQLite logging interface is not reentrant; the logger function ** supplied by the application must not invoke any SQLite interface. ** In a multi-threaded application, the application-defined logger ** function must be threadsafe.
** ** [[SQLITE_CONFIG_URI]]
SQLITE_CONFIG_URI **
This option takes a single argument of type int. If non-zero, then ** URI handling is globally enabled. If the parameter is zero, then URI handling ** is globally disabled. If URI handling is globally enabled, all filenames ** passed to [sqlite3_open()], [sqlite3_open_v2()], [sqlite3_open16()] or ** specified as part of [ATTACH] commands are interpreted as URIs, regardless ** of whether or not the [SQLITE_OPEN_URI] flag is set when the database ** connection is opened. If it is globally disabled, filenames are ** only interpreted as URIs if the SQLITE_OPEN_URI flag is set when the ** database connection is opened. By default, URI handling is globally ** disabled. The default value may be changed by compiling with the ** [SQLITE_USE_URI] symbol defined. **
*/ #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ #define SQLITE_CONFIG_MULTITHREAD 2 /* nil */ #define SQLITE_CONFIG_SERIALIZED 3 /* nil */ #define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */ #define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */ #define SQLITE_CONFIG_SCRATCH 6 /* void*, int sz, int N */ #define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */ #define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */ #define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */ #define SQLITE_CONFIG_MUTEX 10 /* sqlite3_mutex_methods* */ #define SQLITE_CONFIG_GETMUTEX 11 /* sqlite3_mutex_methods* */ /* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */ #define SQLITE_CONFIG_LOOKASIDE 13 /* int int */ #define SQLITE_CONFIG_PCACHE 14 /* sqlite3_pcache_methods* */ #define SQLITE_CONFIG_GETPCACHE 15 /* sqlite3_pcache_methods* */ #define SQLITE_CONFIG_LOG 16 /* xFunc, void* */ #define SQLITE_CONFIG_URI 17 /* int */ /* ** CAPI3REF: Database Connection Configuration Options ** ** These constants are the available integer configuration options that ** can be passed as the second argument to the [sqlite3_db_config()] interface. ** ** New configuration options may be added in future releases of SQLite. ** Existing configuration options might be discontinued. Applications ** should check the return code from [sqlite3_db_config()] to make sure that ** the call worked. ^The [sqlite3_db_config()] interface will return a ** non-zero [error code] if a discontinued or unsupported configuration option ** is invoked. ** **
**
SQLITE_DBCONFIG_LOOKASIDE
**
^This option takes three additional arguments that determine the ** [lookaside memory allocator] configuration for the [database connection]. ** ^The first argument (the third parameter to [sqlite3_db_config()] is a ** pointer to a memory buffer to use for lookaside memory. ** ^The first argument after the SQLITE_DBCONFIG_LOOKASIDE verb ** may be NULL in which case SQLite will allocate the ** lookaside buffer itself using [sqlite3_malloc()]. ^The second argument is the ** size of each lookaside buffer slot. ^The third argument is the number of ** slots. The size of the buffer in the first argument must be greater than ** or equal to the product of the second and third arguments. The buffer ** must be aligned to an 8-byte boundary. ^If the second argument to ** SQLITE_DBCONFIG_LOOKASIDE is not a multiple of 8, it is internally ** rounded down to the next smaller multiple of 8. ^(The lookaside memory ** configuration for a database connection can only be changed when that ** connection is not currently using lookaside memory, or in other words ** when the "current value" returned by ** [sqlite3_db_status](D,[SQLITE_CONFIG_LOOKASIDE],...) is zero. ** Any attempt to change the lookaside memory configuration when lookaside ** memory is in use leaves the configuration unchanged and returns ** [SQLITE_BUSY].)^
** **
SQLITE_DBCONFIG_ENABLE_FKEY
**
^This option is used to enable or disable the enforcement of ** [foreign key constraints]. There should be two additional arguments. ** The first argument is an integer which is 0 to disable FK enforcement, ** positive to enable FK enforcement or negative to leave FK enforcement ** unchanged. The second parameter is a pointer to an integer into which ** is written 0 or 1 to indicate whether FK enforcement is off or on ** following this call. The second parameter may be a NULL pointer, in ** which case the FK enforcement setting is not reported back.
** **
SQLITE_DBCONFIG_ENABLE_TRIGGER
**
^This option is used to enable or disable [CREATE TRIGGER | triggers]. ** There should be two additional arguments. ** The first argument is an integer which is 0 to disable triggers, ** positive to enable triggers or negative to leave the setting unchanged. ** The second parameter is a pointer to an integer into which ** is written 0 or 1 to indicate whether triggers are disabled or enabled ** following this call. The second parameter may be a NULL pointer, in ** which case the trigger setting is not reported back.
** **
*/ #define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */ #define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */ #define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */ /* ** CAPI3REF: Enable Or Disable Extended Result Codes ** ** ^The sqlite3_extended_result_codes() routine enables or disables the ** [extended result codes] feature of SQLite. ^The extended result ** codes are disabled by default for historical compatibility. */ SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff); /* ** CAPI3REF: Last Insert Rowid ** ** ^Each entry in an SQLite table has a unique 64-bit signed ** integer key called the [ROWID | "rowid"]. ^The rowid is always available ** as an undeclared column named ROWID, OID, or _ROWID_ as long as those ** names are not also used by explicitly declared columns. ^If ** the table has a column of type [INTEGER PRIMARY KEY] then that column ** is another alias for the rowid. ** ** ^This routine returns the [rowid] of the most recent ** successful [INSERT] into the database from the [database connection] ** in the first argument. ^As of SQLite version 3.7.7, this routines ** records the last insert rowid of both ordinary tables and [virtual tables]. ** ^If no successful [INSERT]s ** have ever occurred on that database connection, zero is returned. ** ** ^(If an [INSERT] occurs within a trigger or within a [virtual table] ** method, then this routine will return the [rowid] of the inserted ** row as long as the trigger or virtual table method is running. ** But once the trigger or virtual table method ends, the value returned ** by this routine reverts to what it was before the trigger or virtual ** table method began.)^ ** ** ^An [INSERT] that fails due to a constraint violation is not a ** successful [INSERT] and does not change the value returned by this ** routine. ^Thus INSERT OR FAIL, INSERT OR IGNORE, INSERT OR ROLLBACK, ** and INSERT OR ABORT make no changes to the return value of this ** routine when their insertion fails. ^(When INSERT OR REPLACE ** encounters a constraint violation, it does not fail. The ** INSERT continues to completion after deleting rows that caused ** the constraint problem so INSERT OR REPLACE will always change ** the return value of this interface.)^ ** ** ^For the purposes of this routine, an [INSERT] is considered to ** be successful even if it is subsequently rolled back. ** ** This function is accessible to SQL statements via the ** [last_insert_rowid() SQL function]. ** ** If a separate thread performs a new [INSERT] on the same ** database connection while the [sqlite3_last_insert_rowid()] ** function is running and thus changes the last insert [rowid], ** then the value returned by [sqlite3_last_insert_rowid()] is ** unpredictable and might not equal either the old or the new ** last insert [rowid]. */ SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*); /* ** CAPI3REF: Count The Number Of Rows Modified ** ** ^This function returns the number of database rows that were changed ** or inserted or deleted by the most recently completed SQL statement ** on the [database connection] specified by the first parameter. ** ^(Only changes that are directly specified by the [INSERT], [UPDATE], ** or [DELETE] statement are counted. Auxiliary changes caused by ** triggers or [foreign key actions] are not counted.)^ Use the ** [sqlite3_total_changes()] function to find the total number of changes ** including changes caused by triggers and foreign key actions. ** ** ^Changes to a view that are simulated by an [INSTEAD OF trigger] ** are not counted. Only real table changes are counted. ** ** ^(A "row change" is a change to a single row of a single table ** caused by an INSERT, DELETE, or UPDATE statement. Rows that ** are changed as side effects of [REPLACE] constraint resolution, ** rollback, ABORT processing, [DROP TABLE], or by any other ** mechanisms do not count as direct row changes.)^ ** ** A "trigger context" is a scope of execution that begins and ** ends with the script of a [CREATE TRIGGER | trigger]. ** Most SQL statements are ** evaluated outside of any trigger. This is the "top level" ** trigger context. If a trigger fires from the top level, a ** new trigger context is entered for the duration of that one ** trigger. Subtriggers create subcontexts for their duration. ** ** ^Calling [sqlite3_exec()] or [sqlite3_step()] recursively does ** not create a new trigger context. ** ** ^This function returns the number of direct row changes in the ** most recent INSERT, UPDATE, or DELETE statement within the same ** trigger context. ** ** ^Thus, when called from the top level, this function returns the ** number of changes in the most recent INSERT, UPDATE, or DELETE ** that also occurred at the top level. ^(Within the body of a trigger, ** the sqlite3_changes() interface can be called to find the number of ** changes in the most recently completed INSERT, UPDATE, or DELETE ** statement within the body of the same trigger. ** However, the number returned does not include changes ** caused by subtriggers since those have their own context.)^ ** ** See also the [sqlite3_total_changes()] interface, the ** [count_changes pragma], and the [changes() SQL function]. ** ** If a separate thread makes changes on the same database connection ** while [sqlite3_changes()] is running then the value returned ** is unpredictable and not meaningful. */ SQLITE_API int sqlite3_changes(sqlite3*); /* ** CAPI3REF: Total Number Of Rows Modified ** ** ^This function returns the number of row changes caused by [INSERT], ** [UPDATE] or [DELETE] statements since the [database connection] was opened. ** ^(The count returned by sqlite3_total_changes() includes all changes ** from all [CREATE TRIGGER | trigger] contexts and changes made by ** [foreign key actions]. However, ** the count does not include changes used to implement [REPLACE] constraints, ** do rollbacks or ABORT processing, or [DROP TABLE] processing. The ** count does not include rows of views that fire an [INSTEAD OF trigger], ** though if the INSTEAD OF trigger makes changes of its own, those changes ** are counted.)^ ** ^The sqlite3_total_changes() function counts the changes as soon as ** the statement that makes them is completed (when the statement handle ** is passed to [sqlite3_reset()] or [sqlite3_finalize()]). ** ** See also the [sqlite3_changes()] interface, the ** [count_changes pragma], and the [total_changes() SQL function]. ** ** If a separate thread makes changes on the same database connection ** while [sqlite3_total_changes()] is running then the value ** returned is unpredictable and not meaningful. */ SQLITE_API int sqlite3_total_changes(sqlite3*); /* ** CAPI3REF: Interrupt A Long-Running Query ** ** ^This function causes any pending database operation to abort and ** return at its earliest opportunity. This routine is typically ** called in response to a user action such as pressing "Cancel" ** or Ctrl-C where the user wants a long query operation to halt ** immediately. ** ** ^It is safe to call this routine from a thread different from the ** thread that is currently running the database operation. But it ** is not safe to call this routine with a [database connection] that ** is closed or might close before sqlite3_interrupt() returns. ** ** ^If an SQL operation is very nearly finished at the time when ** sqlite3_interrupt() is called, then it might not have an opportunity ** to be interrupted and might continue to completion. ** ** ^An SQL operation that is interrupted will return [SQLITE_INTERRUPT]. ** ^If the interrupted SQL operation is an INSERT, UPDATE, or DELETE ** that is inside an explicit transaction, then the entire transaction ** will be rolled back automatically. ** ** ^The sqlite3_interrupt(D) call is in effect until all currently running ** SQL statements on [database connection] D complete. ^Any new SQL statements ** that are started after the sqlite3_interrupt() call and before the ** running statements reaches zero are interrupted as if they had been ** running prior to the sqlite3_interrupt() call. ^New SQL statements ** that are started after the running statement count reaches zero are ** not effected by the sqlite3_interrupt(). ** ^A call to sqlite3_interrupt(D) that occurs when there are no running ** SQL statements is a no-op and has no effect on SQL statements ** that are started after the sqlite3_interrupt() call returns. ** ** If the database connection closes while [sqlite3_interrupt()] ** is running then bad things will likely happen. */ SQLITE_API void sqlite3_interrupt(sqlite3*); /* ** CAPI3REF: Determine If An SQL Statement Is Complete ** ** These routines are useful during command-line input to determine if the ** currently entered text seems to form a complete SQL statement or ** if additional input is needed before sending the text into ** SQLite for parsing. ^These routines return 1 if the input string ** appears to be a complete SQL statement. ^A statement is judged to be ** complete if it ends with a semicolon token and is not a prefix of a ** well-formed CREATE TRIGGER statement. ^Semicolons that are embedded within ** string literals or quoted identifier names or comments are not ** independent tokens (they are part of the token in which they are ** embedded) and thus do not count as a statement terminator. ^Whitespace ** and comments that follow the final semicolon are ignored. ** ** ^These routines return 0 if the statement is incomplete. ^If a ** memory allocation fails, then SQLITE_NOMEM is returned. ** ** ^These routines do not parse the SQL statements thus ** will not detect syntactically incorrect SQL. ** ** ^(If SQLite has not been initialized using [sqlite3_initialize()] prior ** to invoking sqlite3_complete16() then sqlite3_initialize() is invoked ** automatically by sqlite3_complete16(). If that initialization fails, ** then the return value from sqlite3_complete16() will be non-zero ** regardless of whether or not the input SQL is complete.)^ ** ** The input to [sqlite3_complete()] must be a zero-terminated ** UTF-8 string. ** ** The input to [sqlite3_complete16()] must be a zero-terminated ** UTF-16 string in native byte order. */ SQLITE_API int sqlite3_complete(const char *sql); SQLITE_API int sqlite3_complete16(const void *sql); /* ** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors ** ** ^This routine sets a callback function that might be invoked whenever ** an attempt is made to open a database table that another thread ** or process has locked. ** ** ^If the busy callback is NULL, then [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED] ** is returned immediately upon encountering the lock. ^If the busy callback ** is not NULL, then the callback might be invoked with two arguments. ** ** ^The first argument to the busy handler is a copy of the void* pointer which ** is the third argument to sqlite3_busy_handler(). ^The second argument to ** the busy handler callback is the number of times that the busy handler has ** been invoked for this locking event. ^If the ** busy callback returns 0, then no additional attempts are made to ** access the database and [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED] is returned. ** ^If the callback returns non-zero, then another attempt ** is made to open the database for reading and the cycle repeats. ** ** The presence of a busy handler does not guarantee that it will be invoked ** when there is lock contention. ^If SQLite determines that invoking the busy ** handler could result in a deadlock, it will go ahead and return [SQLITE_BUSY] ** or [SQLITE_IOERR_BLOCKED] instead of invoking the busy handler. ** Consider a scenario where one process is holding a read lock that ** it is trying to promote to a reserved lock and ** a second process is holding a reserved lock that it is trying ** to promote to an exclusive lock. The first process cannot proceed ** because it is blocked by the second and the second process cannot ** proceed because it is blocked by the first. If both processes ** invoke the busy handlers, neither will make any progress. Therefore, ** SQLite returns [SQLITE_BUSY] for the first process, hoping that this ** will induce the first process to release its read lock and allow ** the second process to proceed. ** ** ^The default busy callback is NULL. ** ** ^The [SQLITE_BUSY] error is converted to [SQLITE_IOERR_BLOCKED] ** when SQLite is in the middle of a large transaction where all the ** changes will not fit into the in-memory cache. SQLite will ** already hold a RESERVED lock on the database file, but it needs ** to promote this lock to EXCLUSIVE so that it can spill cache ** pages into the database file without harm to concurrent ** readers. ^If it is unable to promote the lock, then the in-memory ** cache will be left in an inconsistent state and so the error ** code is promoted from the relatively benign [SQLITE_BUSY] to ** the more severe [SQLITE_IOERR_BLOCKED]. ^This error code promotion ** forces an automatic rollback of the changes. See the ** ** CorruptionFollowingBusyError wiki page for a discussion of why ** this is important. ** ** ^(There can only be a single busy handler defined for each ** [database connection]. Setting a new busy handler clears any ** previously set handler.)^ ^Note that calling [sqlite3_busy_timeout()] ** will also set or clear the busy handler. ** ** The busy callback should not take any actions which modify the ** database connection that invoked the busy handler. Any such actions ** result in undefined behavior. ** ** A busy handler must not close the database connection ** or [prepared statement] that invoked the busy handler. */ SQLITE_API int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*); /* ** CAPI3REF: Set A Busy Timeout ** ** ^This routine sets a [sqlite3_busy_handler | busy handler] that sleeps ** for a specified amount of time when a table is locked. ^The handler ** will sleep multiple times until at least "ms" milliseconds of sleeping ** have accumulated. ^After at least "ms" milliseconds of sleeping, ** the handler returns 0 which causes [sqlite3_step()] to return ** [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED]. ** ** ^Calling this routine with an argument less than or equal to zero ** turns off all busy handlers. ** ** ^(There can only be a single busy handler for a particular ** [database connection] any any given moment. If another busy handler ** was defined (using [sqlite3_busy_handler()]) prior to calling ** this routine, that other busy handler is cleared.)^ */ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms); /* ** CAPI3REF: Convenience Routines For Running Queries ** ** This is a legacy interface that is preserved for backwards compatibility. ** Use of this interface is not recommended. ** ** Definition: A result table is memory data structure created by the ** [sqlite3_get_table()] interface. A result table records the ** complete query results from one or more queries. ** ** The table conceptually has a number of rows and columns. But ** these numbers are not part of the result table itself. These ** numbers are obtained separately. Let N be the number of rows ** and M be the number of columns. ** ** A result table is an array of pointers to zero-terminated UTF-8 strings. ** There are (N+1)*M elements in the array. The first M pointers point ** to zero-terminated strings that contain the names of the columns. ** The remaining entries all point to query results. NULL values result ** in NULL pointers. All other values are in their UTF-8 zero-terminated ** string representation as returned by [sqlite3_column_text()]. ** ** A result table might consist of one or more memory allocations. ** It is not safe to pass a result table directly to [sqlite3_free()]. ** A result table should be deallocated using [sqlite3_free_table()]. ** ** ^(As an example of the result table format, suppose a query result ** is as follows: ** **
**        Name        | Age
**        -----------------------
**        Alice       | 43
**        Bob         | 28
**        Cindy       | 21
** 
** ** There are two column (M==2) and three rows (N==3). Thus the ** result table has 8 entries. Suppose the result table is stored ** in an array names azResult. Then azResult holds this content: ** **
**        azResult[0] = "Name";
**        azResult[1] = "Age";
**        azResult[2] = "Alice";
**        azResult[3] = "43";
**        azResult[4] = "Bob";
**        azResult[5] = "28";
**        azResult[6] = "Cindy";
**        azResult[7] = "21";
** 
)^ ** ** ^The sqlite3_get_table() function evaluates one or more ** semicolon-separated SQL statements in the zero-terminated UTF-8 ** string of its 2nd parameter and returns a result table to the ** pointer given in its 3rd parameter. ** ** After the application has finished with the result from sqlite3_get_table(), ** it must pass the result table pointer to sqlite3_free_table() in order to ** release the memory that was malloced. Because of the way the ** [sqlite3_malloc()] happens within sqlite3_get_table(), the calling ** function must not try to call [sqlite3_free()] directly. Only ** [sqlite3_free_table()] is able to release the memory properly and safely. ** ** The sqlite3_get_table() interface is implemented as a wrapper around ** [sqlite3_exec()]. The sqlite3_get_table() routine does not have access ** to any internal data structures of SQLite. It uses only the public ** interface defined here. As a consequence, errors that occur in the ** wrapper layer outside of the internal [sqlite3_exec()] call are not ** reflected in subsequent calls to [sqlite3_errcode()] or ** [sqlite3_errmsg()]. */ SQLITE_API int sqlite3_get_table( sqlite3 *db, /* An open database */ const char *zSql, /* SQL to be evaluated */ char ***pazResult, /* Results of the query */ int *pnRow, /* Number of result rows written here */ int *pnColumn, /* Number of result columns written here */ char **pzErrmsg /* Error msg written here */ ); SQLITE_API void sqlite3_free_table(char **result); /* ** CAPI3REF: Formatted String Printing Functions ** ** These routines are work-alikes of the "printf()" family of functions ** from the standard C library. ** ** ^The sqlite3_mprintf() and sqlite3_vmprintf() routines write their ** results into memory obtained from [sqlite3_malloc()]. ** The strings returned by these two routines should be ** released by [sqlite3_free()]. ^Both routines return a ** NULL pointer if [sqlite3_malloc()] is unable to allocate enough ** memory to hold the resulting string. ** ** ^(The sqlite3_snprintf() routine is similar to "snprintf()" from ** the standard C library. The result is written into the ** buffer supplied as the second parameter whose size is given by ** the first parameter. Note that the order of the ** first two parameters is reversed from snprintf().)^ This is an ** historical accident that cannot be fixed without breaking ** backwards compatibility. ^(Note also that sqlite3_snprintf() ** returns a pointer to its buffer instead of the number of ** characters actually written into the buffer.)^ We admit that ** the number of characters written would be a more useful return ** value but we cannot change the implementation of sqlite3_snprintf() ** now without breaking compatibility. ** ** ^As long as the buffer size is greater than zero, sqlite3_snprintf() ** guarantees that the buffer is always zero-terminated. ^The first ** parameter "n" is the total size of the buffer, including space for ** the zero terminator. So the longest string that can be completely ** written will be n-1 characters. ** ** ^The sqlite3_vsnprintf() routine is a varargs version of sqlite3_snprintf(). ** ** These routines all implement some additional formatting ** options that are useful for constructing SQL statements. ** All of the usual printf() formatting options apply. In addition, there ** is are "%q", "%Q", and "%z" options. ** ** ^(The %q option works like %s in that it substitutes a null-terminated ** string from the argument list. But %q also doubles every '\'' character. ** %q is designed for use inside a string literal.)^ By doubling each '\'' ** character it escapes that character and allows it to be inserted into ** the string. ** ** For example, assume the string variable zText contains text as follows: ** **
**  char *zText = "It's a happy day!";
** 
** ** One can use this text in an SQL statement as follows: ** **
**  char *zSQL = sqlite3_mprintf("INSERT INTO table VALUES('%q')", zText);
**  sqlite3_exec(db, zSQL, 0, 0, 0);
**  sqlite3_free(zSQL);
** 
** ** Because the %q format string is used, the '\'' character in zText ** is escaped and the SQL generated is as follows: ** **
**  INSERT INTO table1 VALUES('It''s a happy day!')
** 
** ** This is correct. Had we used %s instead of %q, the generated SQL ** would have looked like this: ** **
**  INSERT INTO table1 VALUES('It's a happy day!');
** 
** ** This second example is an SQL syntax error. As a general rule you should ** always use %q instead of %s when inserting text into a string literal. ** ** ^(The %Q option works like %q except it also adds single quotes around ** the outside of the total string. Additionally, if the parameter in the ** argument list is a NULL pointer, %Q substitutes the text "NULL" (without ** single quotes).)^ So, for example, one could say: ** **
**  char *zSQL = sqlite3_mprintf("INSERT INTO table VALUES(%Q)", zText);
**  sqlite3_exec(db, zSQL, 0, 0, 0);
**  sqlite3_free(zSQL);
** 
** ** The code above will render a correct SQL statement in the zSQL ** variable even if the zText variable is a NULL pointer. ** ** ^(The "%z" formatting option works like "%s" but with the ** addition that after the string has been read and copied into ** the result, [sqlite3_free()] is called on the input string.)^ */ SQLITE_API char *sqlite3_mprintf(const char*,...); SQLITE_API char *sqlite3_vmprintf(const char*, va_list); SQLITE_API char *sqlite3_snprintf(int,char*,const char*, ...); SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list); /* ** CAPI3REF: Memory Allocation Subsystem ** ** The SQLite core uses these three routines for all of its own ** internal memory allocation needs. "Core" in the previous sentence ** does not include operating-system specific VFS implementation. The ** Windows VFS uses native malloc() and free() for some operations. ** ** ^The sqlite3_malloc() routine returns a pointer to a block ** of memory at least N bytes in length, where N is the parameter. ** ^If sqlite3_malloc() is unable to obtain sufficient free ** memory, it returns a NULL pointer. ^If the parameter N to ** sqlite3_malloc() is zero or negative then sqlite3_malloc() returns ** a NULL pointer. ** ** ^Calling sqlite3_free() with a pointer previously returned ** by sqlite3_malloc() or sqlite3_realloc() releases that memory so ** that it might be reused. ^The sqlite3_free() routine is ** a no-op if is called with a NULL pointer. Passing a NULL pointer ** to sqlite3_free() is harmless. After being freed, memory ** should neither be read nor written. Even reading previously freed ** memory might result in a segmentation fault or other severe error. ** Memory corruption, a segmentation fault, or other severe error ** might result if sqlite3_free() is called with a non-NULL pointer that ** was not obtained from sqlite3_malloc() or sqlite3_realloc(). ** ** ^(The sqlite3_realloc() interface attempts to resize a ** prior memory allocation to be at least N bytes, where N is the ** second parameter. The memory allocation to be resized is the first ** parameter.)^ ^ If the first parameter to sqlite3_realloc() ** is a NULL pointer then its behavior is identical to calling ** sqlite3_malloc(N) where N is the second parameter to sqlite3_realloc(). ** ^If the second parameter to sqlite3_realloc() is zero or ** negative then the behavior is exactly the same as calling ** sqlite3_free(P) where P is the first parameter to sqlite3_realloc(). ** ^sqlite3_realloc() returns a pointer to a memory allocation ** of at least N bytes in size or NULL if sufficient memory is unavailable. ** ^If M is the size of the prior allocation, then min(N,M) bytes ** of the prior allocation are copied into the beginning of buffer returned ** by sqlite3_realloc() and the prior allocation is freed. ** ^If sqlite3_realloc() returns NULL, then the prior allocation ** is not freed. ** ** ^The memory returned by sqlite3_malloc() and sqlite3_realloc() ** is always aligned to at least an 8 byte boundary, or to a ** 4 byte boundary if the [SQLITE_4_BYTE_ALIGNED_MALLOC] compile-time ** option is used. ** ** In SQLite version 3.5.0 and 3.5.1, it was possible to define ** the SQLITE_OMIT_MEMORY_ALLOCATION which would cause the built-in ** implementation of these routines to be omitted. That capability ** is no longer provided. Only built-in memory allocators can be used. ** ** The Windows OS interface layer calls ** the system malloc() and free() directly when converting ** filenames between the UTF-8 encoding used by SQLite ** and whatever filename encoding is used by the particular Windows ** installation. Memory allocation errors are detected, but ** they are reported back as [SQLITE_CANTOPEN] or ** [SQLITE_IOERR] rather than [SQLITE_NOMEM]. ** ** The pointer arguments to [sqlite3_free()] and [sqlite3_realloc()] ** must be either NULL or else pointers obtained from a prior ** invocation of [sqlite3_malloc()] or [sqlite3_realloc()] that have ** not yet been released. ** ** The application must not read or write any part of ** a block of memory after it has been released using ** [sqlite3_free()] or [sqlite3_realloc()]. */ SQLITE_API void *sqlite3_malloc(int); SQLITE_API void *sqlite3_realloc(void*, int); SQLITE_API void sqlite3_free(void*); /* ** CAPI3REF: Memory Allocator Statistics ** ** SQLite provides these two interfaces for reporting on the status ** of the [sqlite3_malloc()], [sqlite3_free()], and [sqlite3_realloc()] ** routines, which form the built-in memory allocation subsystem. ** ** ^The [sqlite3_memory_used()] routine returns the number of bytes ** of memory currently outstanding (malloced but not freed). ** ^The [sqlite3_memory_highwater()] routine returns the maximum ** value of [sqlite3_memory_used()] since the high-water mark ** was last reset. ^The values returned by [sqlite3_memory_used()] and ** [sqlite3_memory_highwater()] include any overhead ** added by SQLite in its implementation of [sqlite3_malloc()], ** but not overhead added by the any underlying system library ** routines that [sqlite3_malloc()] may call. ** ** ^The memory high-water mark is reset to the current value of ** [sqlite3_memory_used()] if and only if the parameter to ** [sqlite3_memory_highwater()] is true. ^The value returned ** by [sqlite3_memory_highwater(1)] is the high-water mark ** prior to the reset. */ SQLITE_API sqlite3_int64 sqlite3_memory_used(void); SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag); /* ** CAPI3REF: Pseudo-Random Number Generator ** ** SQLite contains a high-quality pseudo-random number generator (PRNG) used to ** select random [ROWID | ROWIDs] when inserting new records into a table that ** already uses the largest possible [ROWID]. The PRNG is also used for ** the build-in random() and randomblob() SQL functions. This interface allows ** applications to access the same PRNG for other purposes. ** ** ^A call to this routine stores N bytes of randomness into buffer P. ** ** ^The first time this routine is invoked (either internally or by ** the application) the PRNG is seeded using randomness obtained ** from the xRandomness method of the default [sqlite3_vfs] object. ** ^On all subsequent invocations, the pseudo-randomness is generated ** internally and without recourse to the [sqlite3_vfs] xRandomness ** method. */ SQLITE_API void sqlite3_randomness(int N, void *P); /* ** CAPI3REF: Compile-Time Authorization Callbacks ** ** ^This routine registers an authorizer callback with a particular ** [database connection], supplied in the first argument. ** ^The authorizer callback is invoked as SQL statements are being compiled ** by [sqlite3_prepare()] or its variants [sqlite3_prepare_v2()], ** [sqlite3_prepare16()] and [sqlite3_prepare16_v2()]. ^At various ** points during the compilation process, as logic is being created ** to perform various actions, the authorizer callback is invoked to ** see if those actions are allowed. ^The authorizer callback should ** return [SQLITE_OK] to allow the action, [SQLITE_IGNORE] to disallow the ** specific action but allow the SQL statement to continue to be ** compiled, or [SQLITE_DENY] to cause the entire SQL statement to be ** rejected with an error. ^If the authorizer callback returns ** any value other than [SQLITE_IGNORE], [SQLITE_OK], or [SQLITE_DENY] ** then the [sqlite3_prepare_v2()] or equivalent call that triggered ** the authorizer will fail with an error message. ** ** When the callback returns [SQLITE_OK], that means the operation ** requested is ok. ^When the callback returns [SQLITE_DENY], the ** [sqlite3_prepare_v2()] or equivalent call that triggered the ** authorizer will fail with an error message explaining that ** access is denied. ** ** ^The first parameter to the authorizer callback is a copy of the third ** parameter to the sqlite3_set_authorizer() interface. ^The second parameter ** to the callback is an integer [SQLITE_COPY | action code] that specifies ** the particular action to be authorized. ^The third through sixth parameters ** to the callback are zero-terminated strings that contain additional ** details about the action to be authorized. ** ** ^If the action code is [SQLITE_READ] ** and the callback returns [SQLITE_IGNORE] then the ** [prepared statement] statement is constructed to substitute ** a NULL value in place of the table column that would have ** been read if [SQLITE_OK] had been returned. The [SQLITE_IGNORE] ** return can be used to deny an untrusted user access to individual ** columns of a table. ** ^If the action code is [SQLITE_DELETE] and the callback returns ** [SQLITE_IGNORE] then the [DELETE] operation proceeds but the ** [truncate optimization] is disabled and all rows are deleted individually. ** ** An authorizer is used when [sqlite3_prepare | preparing] ** SQL statements from an untrusted source, to ensure that the SQL statements ** do not try to access data they are not allowed to see, or that they do not ** try to execute malicious statements that damage the database. For ** example, an application may allow a user to enter arbitrary ** SQL queries for evaluation by a database. But the application does ** not want the user to be able to make arbitrary changes to the ** database. An authorizer could then be put in place while the ** user-entered SQL is being [sqlite3_prepare | prepared] that ** disallows everything except [SELECT] statements. ** ** Applications that need to process SQL from untrusted sources ** might also consider lowering resource limits using [sqlite3_limit()] ** and limiting database size using the [max_page_count] [PRAGMA] ** in addition to using an authorizer. ** ** ^(Only a single authorizer can be in place on a database connection ** at a time. Each call to sqlite3_set_authorizer overrides the ** previous call.)^ ^Disable the authorizer by installing a NULL callback. ** The authorizer is disabled by default. ** ** The authorizer callback must not do anything that will modify ** the database connection that invoked the authorizer callback. ** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their ** database connections for the meaning of "modify" in this paragraph. ** ** ^When [sqlite3_prepare_v2()] is used to prepare a statement, the ** statement might be re-prepared during [sqlite3_step()] due to a ** schema change. Hence, the application should ensure that the ** correct authorizer callback remains in place during the [sqlite3_step()]. ** ** ^Note that the authorizer callback is invoked only during ** [sqlite3_prepare()] or its variants. Authorization is not ** performed during statement evaluation in [sqlite3_step()], unless ** as stated in the previous paragraph, sqlite3_step() invokes ** sqlite3_prepare_v2() to reprepare a statement after a schema change. */ SQLITE_API int sqlite3_set_authorizer( sqlite3*, int (*xAuth)(void*,int,const char*,const char*,const char*,const char*), void *pUserData ); /* ** CAPI3REF: Authorizer Return Codes ** ** The [sqlite3_set_authorizer | authorizer callback function] must ** return either [SQLITE_OK] or one of these two constants in order ** to signal SQLite whether or not the action is permitted. See the ** [sqlite3_set_authorizer | authorizer documentation] for additional ** information. ** ** Note that SQLITE_IGNORE is also used as a [SQLITE_ROLLBACK | return code] ** from the [sqlite3_vtab_on_conflict()] interface. */ #define SQLITE_DENY 1 /* Abort the SQL statement with an error */ #define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */ /* ** CAPI3REF: Authorizer Action Codes ** ** The [sqlite3_set_authorizer()] interface registers a callback function ** that is invoked to authorize certain SQL statement actions. The ** second parameter to the callback is an integer code that specifies ** what action is being authorized. These are the integer action codes that ** the authorizer callback may be passed. ** ** These action code values signify what kind of operation is to be ** authorized. The 3rd and 4th parameters to the authorization ** callback function will be parameters or NULL depending on which of these ** codes is used as the second parameter. ^(The 5th parameter to the ** authorizer callback is the name of the database ("main", "temp", ** etc.) if applicable.)^ ^The 6th parameter to the authorizer callback ** is the name of the inner-most trigger or view that is responsible for ** the access attempt or NULL if this access attempt is directly from ** top-level SQL code. */ /******************************************* 3rd ************ 4th ***********/ #define SQLITE_CREATE_INDEX 1 /* Index Name Table Name */ #define SQLITE_CREATE_TABLE 2 /* Table Name NULL */ #define SQLITE_CREATE_TEMP_INDEX 3 /* Index Name Table Name */ #define SQLITE_CREATE_TEMP_TABLE 4 /* Table Name NULL */ #define SQLITE_CREATE_TEMP_TRIGGER 5 /* Trigger Name Table Name */ #define SQLITE_CREATE_TEMP_VIEW 6 /* View Name NULL */ #define SQLITE_CREATE_TRIGGER 7 /* Trigger Name Table Name */ #define SQLITE_CREATE_VIEW 8 /* View Name NULL */ #define SQLITE_DELETE 9 /* Table Name NULL */ #define SQLITE_DROP_INDEX 10 /* Index Name Table Name */ #define SQLITE_DROP_TABLE 11 /* Table Name NULL */ #define SQLITE_DROP_TEMP_INDEX 12 /* Index Name Table Name */ #define SQLITE_DROP_TEMP_TABLE 13 /* Table Name NULL */ #define SQLITE_DROP_TEMP_TRIGGER 14 /* Trigger Name Table Name */ #define SQLITE_DROP_TEMP_VIEW 15 /* View Name NULL */ #define SQLITE_DROP_TRIGGER 16 /* Trigger Name Table Name */ #define SQLITE_DROP_VIEW 17 /* View Name NULL */ #define SQLITE_INSERT 18 /* Table Name NULL */ #define SQLITE_PRAGMA 19 /* Pragma Name 1st arg or NULL */ #define SQLITE_READ 20 /* Table Name Column Name */ #define SQLITE_SELECT 21 /* NULL NULL */ #define SQLITE_TRANSACTION 22 /* Operation NULL */ #define SQLITE_UPDATE 23 /* Table Name Column Name */ #define SQLITE_ATTACH 24 /* Filename NULL */ #define SQLITE_DETACH 25 /* Database Name NULL */ #define SQLITE_ALTER_TABLE 26 /* Database Name Table Name */ #define SQLITE_REINDEX 27 /* Index Name NULL */ #define SQLITE_ANALYZE 28 /* Table Name NULL */ #define SQLITE_CREATE_VTABLE 29 /* Table Name Module Name */ #define SQLITE_DROP_VTABLE 30 /* Table Name Module Name */ #define SQLITE_FUNCTION 31 /* NULL Function Name */ #define SQLITE_SAVEPOINT 32 /* Operation Savepoint Name */ #define SQLITE_COPY 0 /* No longer used */ /* ** CAPI3REF: Tracing And Profiling Functions ** ** These routines register callback functions that can be used for ** tracing and profiling the execution of SQL statements. ** ** ^The callback function registered by sqlite3_trace() is invoked at ** various times when an SQL statement is being run by [sqlite3_step()]. ** ^The sqlite3_trace() callback is invoked with a UTF-8 rendering of the ** SQL statement text as the statement first begins executing. ** ^(Additional sqlite3_trace() callbacks might occur ** as each triggered subprogram is entered. The callbacks for triggers ** contain a UTF-8 SQL comment that identifies the trigger.)^ ** ** ^The callback function registered by sqlite3_profile() is invoked ** as each SQL statement finishes. ^The profile callback contains ** the original statement text and an estimate of wall-clock time ** of how long that statement took to run. ^The profile callback ** time is in units of nanoseconds, however the current implementation ** is only capable of millisecond resolution so the six least significant ** digits in the time are meaningless. Future versions of SQLite ** might provide greater resolution on the profiler callback. The ** sqlite3_profile() function is considered experimental and is ** subject to change in future versions of SQLite. */ SQLITE_API void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*); SQLITE_API SQLITE_EXPERIMENTAL void *sqlite3_profile(sqlite3*, void(*xProfile)(void*,const char*,sqlite3_uint64), void*); /* ** CAPI3REF: Query Progress Callbacks ** ** ^The sqlite3_progress_handler(D,N,X,P) interface causes the callback ** function X to be invoked periodically during long running calls to ** [sqlite3_exec()], [sqlite3_step()] and [sqlite3_get_table()] for ** database connection D. An example use for this ** interface is to keep a GUI updated during a large query. ** ** ^The parameter P is passed through as the only parameter to the ** callback function X. ^The parameter N is the number of ** [virtual machine instructions] that are evaluated between successive ** invocations of the callback X. ** ** ^Only a single progress handler may be defined at one time per ** [database connection]; setting a new progress handler cancels the ** old one. ^Setting parameter X to NULL disables the progress handler. ** ^The progress handler is also disabled by setting N to a value less ** than 1. ** ** ^If the progress callback returns non-zero, the operation is ** interrupted. This feature can be used to implement a ** "Cancel" button on a GUI progress dialog box. ** ** The progress handler callback must not do anything that will modify ** the database connection that invoked the progress handler. ** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their ** database connections for the meaning of "modify" in this paragraph. ** */ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); /* ** CAPI3REF: Opening A New Database Connection ** ** ^These routines open an SQLite database file as specified by the ** filename argument. ^The filename argument is interpreted as UTF-8 for ** sqlite3_open() and sqlite3_open_v2() and as UTF-16 in the native byte ** order for sqlite3_open16(). ^(A [database connection] handle is usually ** returned in *ppDb, even if an error occurs. The only exception is that ** if SQLite is unable to allocate memory to hold the [sqlite3] object, ** a NULL will be written into *ppDb instead of a pointer to the [sqlite3] ** object.)^ ^(If the database is opened (and/or created) successfully, then ** [SQLITE_OK] is returned. Otherwise an [error code] is returned.)^ ^The ** [sqlite3_errmsg()] or [sqlite3_errmsg16()] routines can be used to obtain ** an English language description of the error following a failure of any ** of the sqlite3_open() routines. ** ** ^The default encoding for the database will be UTF-8 if ** sqlite3_open() or sqlite3_open_v2() is called and ** UTF-16 in the native byte order if sqlite3_open16() is used. ** ** Whether or not an error occurs when it is opened, resources ** associated with the [database connection] handle should be released by ** passing it to [sqlite3_close()] when it is no longer required. ** ** The sqlite3_open_v2() interface works like sqlite3_open() ** except that it accepts two additional parameters for additional control ** over the new database connection. ^(The flags parameter to ** sqlite3_open_v2() can take one of ** the following three values, optionally combined with the ** [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX], [SQLITE_OPEN_SHAREDCACHE], ** [SQLITE_OPEN_PRIVATECACHE], and/or [SQLITE_OPEN_URI] flags:)^ ** **
** ^(
[SQLITE_OPEN_READONLY]
**
The database is opened in read-only mode. If the database does not ** already exist, an error is returned.
)^ ** ** ^(
[SQLITE_OPEN_READWRITE]
**
The database is opened for reading and writing if possible, or reading ** only if the file is write protected by the operating system. In either ** case the database must already exist, otherwise an error is returned.
)^ ** ** ^(
[SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]
**
The database is opened for reading and writing, and is created if ** it does not already exist. This is the behavior that is always used for ** sqlite3_open() and sqlite3_open16().
)^ **
** ** If the 3rd parameter to sqlite3_open_v2() is not one of the ** combinations shown above optionally combined with other ** [SQLITE_OPEN_READONLY | SQLITE_OPEN_* bits] ** then the behavior is undefined. ** ** ^If the [SQLITE_OPEN_NOMUTEX] flag is set, then the database connection ** opens in the multi-thread [threading mode] as long as the single-thread ** mode has not been set at compile-time or start-time. ^If the ** [SQLITE_OPEN_FULLMUTEX] flag is set then the database connection opens ** in the serialized [threading mode] unless single-thread was ** previously selected at compile-time or start-time. ** ^The [SQLITE_OPEN_SHAREDCACHE] flag causes the database connection to be ** eligible to use [shared cache mode], regardless of whether or not shared ** cache is enabled using [sqlite3_enable_shared_cache()]. ^The ** [SQLITE_OPEN_PRIVATECACHE] flag causes the database connection to not ** participate in [shared cache mode] even if it is enabled. ** ** ^The fourth parameter to sqlite3_open_v2() is the name of the ** [sqlite3_vfs] object that defines the operating system interface that ** the new database connection should use. ^If the fourth parameter is ** a NULL pointer then the default [sqlite3_vfs] object is used. ** ** ^If the filename is ":memory:", then a private, temporary in-memory database ** is created for the connection. ^This in-memory database will vanish when ** the database connection is closed. Future versions of SQLite might ** make use of additional special filenames that begin with the ":" character. ** It is recommended that when a database filename actually does begin with ** a ":" character you should prefix the filename with a pathname such as ** "./" to avoid ambiguity. ** ** ^If the filename is an empty string, then a private, temporary ** on-disk database will be created. ^This private database will be ** automatically deleted as soon as the database connection is closed. ** ** [[URI filenames in sqlite3_open()]]

URI Filenames

** ** ^If [URI filename] interpretation is enabled, and the filename argument ** begins with "file:", then the filename is interpreted as a URI. ^URI ** filename interpretation is enabled if the [SQLITE_OPEN_URI] flag is ** set in the fourth argument to sqlite3_open_v2(), or if it has ** been enabled globally using the [SQLITE_CONFIG_URI] option with the ** [sqlite3_config()] method or by the [SQLITE_USE_URI] compile-time option. ** As of SQLite version 3.7.7, URI filename interpretation is turned off ** by default, but future releases of SQLite might enable URI filename ** interpretation by default. See "[URI filenames]" for additional ** information. ** ** URI filenames are parsed according to RFC 3986. ^If the URI contains an ** authority, then it must be either an empty string or the string ** "localhost". ^If the authority is not an empty string or "localhost", an ** error is returned to the caller. ^The fragment component of a URI, if ** present, is ignored. ** ** ^SQLite uses the path component of the URI as the name of the disk file ** which contains the database. ^If the path begins with a '/' character, ** then it is interpreted as an absolute path. ^If the path does not begin ** with a '/' (meaning that the authority section is omitted from the URI) ** then the path is interpreted as a relative path. ** ^On windows, the first component of an absolute path ** is a drive specification (e.g. "C:"). ** ** [[core URI query parameters]] ** The query component of a URI may contain parameters that are interpreted ** either by SQLite itself, or by a [VFS | custom VFS implementation]. ** SQLite interprets the following three query parameters: ** **
    **
  • vfs: ^The "vfs" parameter may be used to specify the name of ** a VFS object that provides the operating system interface that should ** be used to access the database file on disk. ^If this option is set to ** an empty string the default VFS object is used. ^Specifying an unknown ** VFS is an error. ^If sqlite3_open_v2() is used and the vfs option is ** present, then the VFS specified by the option takes precedence over ** the value passed as the fourth parameter to sqlite3_open_v2(). ** **
  • mode: ^(The mode parameter may be set to either "ro", "rw" or ** "rwc". Attempting to set it to any other value is an error)^. ** ^If "ro" is specified, then the database is opened for read-only ** access, just as if the [SQLITE_OPEN_READONLY] flag had been set in the ** third argument to sqlite3_prepare_v2(). ^If the mode option is set to ** "rw", then the database is opened for read-write (but not create) ** access, as if SQLITE_OPEN_READWRITE (but not SQLITE_OPEN_CREATE) had ** been set. ^Value "rwc" is equivalent to setting both ** SQLITE_OPEN_READWRITE and SQLITE_OPEN_CREATE. ^If sqlite3_open_v2() is ** used, it is an error to specify a value for the mode parameter that is ** less restrictive than that specified by the flags passed as the third ** parameter. ** **
  • cache: ^The cache parameter may be set to either "shared" or ** "private". ^Setting it to "shared" is equivalent to setting the ** SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed to ** sqlite3_open_v2(). ^Setting the cache parameter to "private" is ** equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit. ** ^If sqlite3_open_v2() is used and the "cache" parameter is present in ** a URI filename, its value overrides any behaviour requested by setting ** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag. **
** ** ^Specifying an unknown parameter in the query component of a URI is not an ** error. Future versions of SQLite might understand additional query ** parameters. See "[query parameters with special meaning to SQLite]" for ** additional information. ** ** [[URI filename examples]]

URI filename examples

** ** **
URI filenames Results **
file:data.db ** Open the file "data.db" in the current directory. **
file:/home/fred/data.db
** file:///home/fred/data.db
** file://localhost/home/fred/data.db
** Open the database file "/home/fred/data.db". **
file://darkstar/home/fred/data.db ** An error. "darkstar" is not a recognized authority. **
** file:///C:/Documents%20and%20Settings/fred/Desktop/data.db ** Windows only: Open the file "data.db" on fred's desktop on drive ** C:. Note that the %20 escaping in this example is not strictly ** necessary - space characters can be used literally ** in URI filenames. **
file:data.db?mode=ro&cache=private ** Open file "data.db" in the current directory for read-only access. ** Regardless of whether or not shared-cache mode is enabled by ** default, use a private cache. **
file:/home/fred/data.db?vfs=unix-nolock ** Open file "/home/fred/data.db". Use the special VFS "unix-nolock". **
file:data.db?mode=readonly ** An error. "readonly" is not a valid option for the "mode" parameter. **
** ** ^URI hexadecimal escape sequences (%HH) are supported within the path and ** query components of a URI. A hexadecimal escape sequence consists of a ** percent sign - "%" - followed by exactly two hexadecimal digits ** specifying an octet value. ^Before the path or query components of a ** URI filename are interpreted, they are encoded using UTF-8 and all ** hexadecimal escape sequences replaced by a single byte containing the ** corresponding octet. If this process generates an invalid UTF-8 encoding, ** the results are undefined. ** ** Note to Windows users: The encoding used for the filename argument ** of sqlite3_open() and sqlite3_open_v2() must be UTF-8, not whatever ** codepage is currently defined. Filenames containing international ** characters must be converted to UTF-8 prior to passing them into ** sqlite3_open() or sqlite3_open_v2(). */ SQLITE_API int sqlite3_open( const char *filename, /* Database filename (UTF-8) */ sqlite3 **ppDb /* OUT: SQLite db handle */ ); SQLITE_API int sqlite3_open16( const void *filename, /* Database filename (UTF-16) */ sqlite3 **ppDb /* OUT: SQLite db handle */ ); SQLITE_API int sqlite3_open_v2( const char *filename, /* Database filename (UTF-8) */ sqlite3 **ppDb, /* OUT: SQLite db handle */ int flags, /* Flags */ const char *zVfs /* Name of VFS module to use */ ); /* ** CAPI3REF: Obtain Values For URI Parameters ** ** This is a utility routine, useful to VFS implementations, that checks ** to see if a database file was a URI that contained a specific query ** parameter, and if so obtains the value of the query parameter. ** ** The zFilename argument is the filename pointer passed into the xOpen() ** method of a VFS implementation. The zParam argument is the name of the ** query parameter we seek. This routine returns the value of the zParam ** parameter if it exists. If the parameter does not exist, this routine ** returns a NULL pointer. ** ** If the zFilename argument to this function is not a pointer that SQLite ** passed into the xOpen VFS method, then the behavior of this routine ** is undefined and probably undesirable. */ SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam); /* ** CAPI3REF: Error Codes And Messages ** ** ^The sqlite3_errcode() interface returns the numeric [result code] or ** [extended result code] for the most recent failed sqlite3_* API call ** associated with a [database connection]. If a prior API call failed ** but the most recent API call succeeded, the return value from ** sqlite3_errcode() is undefined. ^The sqlite3_extended_errcode() ** interface is the same except that it always returns the ** [extended result code] even when extended result codes are ** disabled. ** ** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language ** text that describes the error, as either UTF-8 or UTF-16 respectively. ** ^(Memory to hold the error message string is managed internally. ** The application does not need to worry about freeing the result. ** However, the error string might be overwritten or deallocated by ** subsequent calls to other SQLite interface functions.)^ ** ** When the serialized [threading mode] is in use, it might be the ** case that a second error occurs on a separate thread in between ** the time of the first error and the call to these interfaces. ** When that happens, the second error will be reported since these ** interfaces always report the most recent result. To avoid ** this, each thread can obtain exclusive use of the [database connection] D ** by invoking [sqlite3_mutex_enter]([sqlite3_db_mutex](D)) before beginning ** to use D and invoking [sqlite3_mutex_leave]([sqlite3_db_mutex](D)) after ** all calls to the interfaces listed here are completed. ** ** If an interface fails with SQLITE_MISUSE, that means the interface ** was invoked incorrectly by the application. In that case, the ** error code and message may or may not be set. */ SQLITE_API int sqlite3_errcode(sqlite3 *db); SQLITE_API int sqlite3_extended_errcode(sqlite3 *db); SQLITE_API const char *sqlite3_errmsg(sqlite3*); SQLITE_API const void *sqlite3_errmsg16(sqlite3*); /* ** CAPI3REF: SQL Statement Object ** KEYWORDS: {prepared statement} {prepared statements} ** ** An instance of this object represents a single SQL statement. ** This object is variously known as a "prepared statement" or a ** "compiled SQL statement" or simply as a "statement". ** ** The life of a statement object goes something like this: ** **
    **
  1. Create the object using [sqlite3_prepare_v2()] or a related ** function. **
  2. Bind values to [host parameters] using the sqlite3_bind_*() ** interfaces. **
  3. Run the SQL by calling [sqlite3_step()] one or more times. **
  4. Reset the statement using [sqlite3_reset()] then go back ** to step 2. Do this zero or more times. **
  5. Destroy the object using [sqlite3_finalize()]. **
** ** Refer to documentation on individual methods above for additional ** information. */ typedef struct sqlite3_stmt sqlite3_stmt; /* ** CAPI3REF: Run-time Limits ** ** ^(This interface allows the size of various constructs to be limited ** on a connection by connection basis. The first parameter is the ** [database connection] whose limit is to be set or queried. The ** second parameter is one of the [limit categories] that define a ** class of constructs to be size limited. The third parameter is the ** new limit for that construct.)^ ** ** ^If the new limit is a negative number, the limit is unchanged. ** ^(For each limit category SQLITE_LIMIT_NAME there is a ** [limits | hard upper bound] ** set at compile-time by a C preprocessor macro called ** [limits | SQLITE_MAX_NAME]. ** (The "_LIMIT_" in the name is changed to "_MAX_".))^ ** ^Attempts to increase a limit above its hard upper bound are ** silently truncated to the hard upper bound. ** ** ^Regardless of whether or not the limit was changed, the ** [sqlite3_limit()] interface returns the prior value of the limit. ** ^Hence, to find the current value of a limit without changing it, ** simply invoke this interface with the third parameter set to -1. ** ** Run-time limits are intended for use in applications that manage ** both their own internal database and also databases that are controlled ** by untrusted external sources. An example application might be a ** web browser that has its own databases for storing history and ** separate databases controlled by JavaScript applications downloaded ** off the Internet. The internal databases can be given the ** large, default limits. Databases managed by external sources can ** be given much smaller limits designed to prevent a denial of service ** attack. Developers might also want to use the [sqlite3_set_authorizer()] ** interface to further control untrusted SQL. The size of the database ** created by an untrusted script can be contained using the ** [max_page_count] [PRAGMA]. ** ** New run-time limit categories may be added in future releases. */ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); /* ** CAPI3REF: Run-Time Limit Categories ** KEYWORDS: {limit category} {*limit categories} ** ** These constants define various performance limits ** that can be lowered at run-time using [sqlite3_limit()]. ** The synopsis of the meanings of the various limits is shown below. ** Additional information is available at [limits | Limits in SQLite]. ** **
** [[SQLITE_LIMIT_LENGTH]] ^(
SQLITE_LIMIT_LENGTH
**
The maximum size of any string or BLOB or table row, in bytes.
)^ ** ** [[SQLITE_LIMIT_SQL_LENGTH]] ^(
SQLITE_LIMIT_SQL_LENGTH
**
The maximum length of an SQL statement, in bytes.
)^ ** ** [[SQLITE_LIMIT_COLUMN]] ^(
SQLITE_LIMIT_COLUMN
**
The maximum number of columns in a table definition or in the ** result set of a [SELECT] or the maximum number of columns in an index ** or in an ORDER BY or GROUP BY clause.
)^ ** ** [[SQLITE_LIMIT_EXPR_DEPTH]] ^(
SQLITE_LIMIT_EXPR_DEPTH
**
The maximum depth of the parse tree on any expression.
)^ ** ** [[SQLITE_LIMIT_COMPOUND_SELECT]] ^(
SQLITE_LIMIT_COMPOUND_SELECT
**
The maximum number of terms in a compound SELECT statement.
)^ ** ** [[SQLITE_LIMIT_VDBE_OP]] ^(
SQLITE_LIMIT_VDBE_OP
**
The maximum number of instructions in a virtual machine program ** used to implement an SQL statement. This limit is not currently ** enforced, though that might be added in some future release of ** SQLite.
)^ ** ** [[SQLITE_LIMIT_FUNCTION_ARG]] ^(
SQLITE_LIMIT_FUNCTION_ARG
**
The maximum number of arguments on a function.
)^ ** ** [[SQLITE_LIMIT_ATTACHED]] ^(
SQLITE_LIMIT_ATTACHED
**
The maximum number of [ATTACH | attached databases].)^
** ** [[SQLITE_LIMIT_LIKE_PATTERN_LENGTH]] ** ^(
SQLITE_LIMIT_LIKE_PATTERN_LENGTH
**
The maximum length of the pattern argument to the [LIKE] or ** [GLOB] operators.
)^ ** ** [[SQLITE_LIMIT_VARIABLE_NUMBER]] ** ^(
SQLITE_LIMIT_VARIABLE_NUMBER
**
The maximum index number of any [parameter] in an SQL statement.)^ ** ** [[SQLITE_LIMIT_TRIGGER_DEPTH]] ^(
SQLITE_LIMIT_TRIGGER_DEPTH
**
The maximum depth of recursion for triggers.
)^ **
*/ #define SQLITE_LIMIT_LENGTH 0 #define SQLITE_LIMIT_SQL_LENGTH 1 #define SQLITE_LIMIT_COLUMN 2 #define SQLITE_LIMIT_EXPR_DEPTH 3 #define SQLITE_LIMIT_COMPOUND_SELECT 4 #define SQLITE_LIMIT_VDBE_OP 5 #define SQLITE_LIMIT_FUNCTION_ARG 6 #define SQLITE_LIMIT_ATTACHED 7 #define SQLITE_LIMIT_LIKE_PATTERN_LENGTH 8 #define SQLITE_LIMIT_VARIABLE_NUMBER 9 #define SQLITE_LIMIT_TRIGGER_DEPTH 10 /* ** CAPI3REF: Compiling An SQL Statement ** KEYWORDS: {SQL statement compiler} ** ** To execute an SQL query, it must first be compiled into a byte-code ** program using one of these routines. ** ** The first argument, "db", is a [database connection] obtained from a ** prior successful call to [sqlite3_open()], [sqlite3_open_v2()] or ** [sqlite3_open16()]. The database connection must not have been closed. ** ** The second argument, "zSql", is the statement to be compiled, encoded ** as either UTF-8 or UTF-16. The sqlite3_prepare() and sqlite3_prepare_v2() ** interfaces use UTF-8, and sqlite3_prepare16() and sqlite3_prepare16_v2() ** use UTF-16. ** ** ^If the nByte argument is less than zero, then zSql is read up to the ** first zero terminator. ^If nByte is non-negative, then it is the maximum ** number of bytes read from zSql. ^When nByte is non-negative, the ** zSql string ends at either the first '\000' or '\u0000' character or ** the nByte-th byte, whichever comes first. If the caller knows ** that the supplied string is nul-terminated, then there is a small ** performance advantage to be gained by passing an nByte parameter that ** is equal to the number of bytes in the input string including ** the nul-terminator bytes as this saves SQLite from having to ** make a copy of the input string. ** ** ^If pzTail is not NULL then *pzTail is made to point to the first byte ** past the end of the first SQL statement in zSql. These routines only ** compile the first statement in zSql, so *pzTail is left pointing to ** what remains uncompiled. ** ** ^*ppStmt is left pointing to a compiled [prepared statement] that can be ** executed using [sqlite3_step()]. ^If there is an error, *ppStmt is set ** to NULL. ^If the input text contains no SQL (if the input is an empty ** string or a comment) then *ppStmt is set to NULL. ** The calling procedure is responsible for deleting the compiled ** SQL statement using [sqlite3_finalize()] after it has finished with it. ** ppStmt may not be NULL. ** ** ^On success, the sqlite3_prepare() family of routines return [SQLITE_OK]; ** otherwise an [error code] is returned. ** ** The sqlite3_prepare_v2() and sqlite3_prepare16_v2() interfaces are ** recommended for all new programs. The two older interfaces are retained ** for backwards compatibility, but their use is discouraged. ** ^In the "v2" interfaces, the prepared statement ** that is returned (the [sqlite3_stmt] object) contains a copy of the ** original SQL text. This causes the [sqlite3_step()] interface to ** behave differently in three ways: ** **
    **
  1. ** ^If the database schema changes, instead of returning [SQLITE_SCHEMA] as it ** always used to do, [sqlite3_step()] will automatically recompile the SQL ** statement and try to run it again. **
  2. ** **
  3. ** ^When an error occurs, [sqlite3_step()] will return one of the detailed ** [error codes] or [extended error codes]. ^The legacy behavior was that ** [sqlite3_step()] would only return a generic [SQLITE_ERROR] result code ** and the application would have to make a second call to [sqlite3_reset()] ** in order to find the underlying cause of the problem. With the "v2" prepare ** interfaces, the underlying reason for the error is returned immediately. **
  4. ** **
  5. ** ^If the specific value bound to [parameter | host parameter] in the ** WHERE clause might influence the choice of query plan for a statement, ** then the statement will be automatically recompiled, as if there had been ** a schema change, on the first [sqlite3_step()] call following any change ** to the [sqlite3_bind_text | bindings] of that [parameter]. ** ^The specific value of WHERE-clause [parameter] might influence the ** choice of query plan if the parameter is the left-hand side of a [LIKE] ** or [GLOB] operator or if the parameter is compared to an indexed column ** and the [SQLITE_ENABLE_STAT3] compile-time option is enabled. ** the **
  6. **
*/ SQLITE_API int sqlite3_prepare( sqlite3 *db, /* Database handle */ const char *zSql, /* SQL statement, UTF-8 encoded */ int nByte, /* Maximum length of zSql in bytes. */ sqlite3_stmt **ppStmt, /* OUT: Statement handle */ const char **pzTail /* OUT: Pointer to unused portion of zSql */ ); SQLITE_API int sqlite3_prepare_v2( sqlite3 *db, /* Database handle */ const char *zSql, /* SQL statement, UTF-8 encoded */ int nByte, /* Maximum length of zSql in bytes. */ sqlite3_stmt **ppStmt, /* OUT: Statement handle */ const char **pzTail /* OUT: Pointer to unused portion of zSql */ ); SQLITE_API int sqlite3_prepare16( sqlite3 *db, /* Database handle */ const void *zSql, /* SQL statement, UTF-16 encoded */ int nByte, /* Maximum length of zSql in bytes. */ sqlite3_stmt **ppStmt, /* OUT: Statement handle */ const void **pzTail /* OUT: Pointer to unused portion of zSql */ ); SQLITE_API int sqlite3_prepare16_v2( sqlite3 *db, /* Database handle */ const void *zSql, /* SQL statement, UTF-16 encoded */ int nByte, /* Maximum length of zSql in bytes. */ sqlite3_stmt **ppStmt, /* OUT: Statement handle */ const void **pzTail /* OUT: Pointer to unused portion of zSql */ ); /* ** CAPI3REF: Retrieving Statement SQL ** ** ^This interface can be used to retrieve a saved copy of the original ** SQL text used to create a [prepared statement] if that statement was ** compiled using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()]. */ SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt); /* ** CAPI3REF: Determine If An SQL Statement Writes The Database ** ** ^The sqlite3_stmt_readonly(X) interface returns true (non-zero) if ** and only if the [prepared statement] X makes no direct changes to ** the content of the database file. ** ** Note that [application-defined SQL functions] or ** [virtual tables] might change the database indirectly as a side effect. ** ^(For example, if an application defines a function "eval()" that ** calls [sqlite3_exec()], then the following SQL statement would ** change the database file through side-effects: ** **
**    SELECT eval('DELETE FROM t1') FROM t2;
** 
** ** But because the [SELECT] statement does not change the database file ** directly, sqlite3_stmt_readonly() would still return true.)^ ** ** ^Transaction control statements such as [BEGIN], [COMMIT], [ROLLBACK], ** [SAVEPOINT], and [RELEASE] cause sqlite3_stmt_readonly() to return true, ** since the statements themselves do not actually modify the database but ** rather they control the timing of when other statements modify the ** database. ^The [ATTACH] and [DETACH] statements also cause ** sqlite3_stmt_readonly() to return true since, while those statements ** change the configuration of a database connection, they do not make ** changes to the content of the database files on disk. */ SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt); /* ** CAPI3REF: Dynamically Typed Value Object ** KEYWORDS: {protected sqlite3_value} {unprotected sqlite3_value} ** ** SQLite uses the sqlite3_value object to represent all values ** that can be stored in a database table. SQLite uses dynamic typing ** for the values it stores. ^Values stored in sqlite3_value objects ** can be integers, floating point values, strings, BLOBs, or NULL. ** ** An sqlite3_value object may be either "protected" or "unprotected". ** Some interfaces require a protected sqlite3_value. Other interfaces ** will accept either a protected or an unprotected sqlite3_value. ** Every interface that accepts sqlite3_value arguments specifies ** whether or not it requires a protected sqlite3_value. ** ** The terms "protected" and "unprotected" refer to whether or not ** a mutex is held. An internal mutex is held for a protected ** sqlite3_value object but no mutex is held for an unprotected ** sqlite3_value object. If SQLite is compiled to be single-threaded ** (with [SQLITE_THREADSAFE=0] and with [sqlite3_threadsafe()] returning 0) ** or if SQLite is run in one of reduced mutex modes ** [SQLITE_CONFIG_SINGLETHREAD] or [SQLITE_CONFIG_MULTITHREAD] ** then there is no distinction between protected and unprotected ** sqlite3_value objects and they can be used interchangeably. However, ** for maximum code portability it is recommended that applications ** still make the distinction between protected and unprotected ** sqlite3_value objects even when not strictly required. ** ** ^The sqlite3_value objects that are passed as parameters into the ** implementation of [application-defined SQL functions] are protected. ** ^The sqlite3_value object returned by ** [sqlite3_column_value()] is unprotected. ** Unprotected sqlite3_value objects may only be used with ** [sqlite3_result_value()] and [sqlite3_bind_value()]. ** The [sqlite3_value_blob | sqlite3_value_type()] family of ** interfaces require protected sqlite3_value objects. */ typedef struct Mem sqlite3_value; /* ** CAPI3REF: SQL Function Context Object ** ** The context in which an SQL function executes is stored in an ** sqlite3_context object. ^A pointer to an sqlite3_context object ** is always first parameter to [application-defined SQL functions]. ** The application-defined SQL function implementation will pass this ** pointer through into calls to [sqlite3_result_int | sqlite3_result()], ** [sqlite3_aggregate_context()], [sqlite3_user_data()], ** [sqlite3_context_db_handle()], [sqlite3_get_auxdata()], ** and/or [sqlite3_set_auxdata()]. */ typedef struct sqlite3_context sqlite3_context; /* ** CAPI3REF: Binding Values To Prepared Statements ** KEYWORDS: {host parameter} {host parameters} {host parameter name} ** KEYWORDS: {SQL parameter} {SQL parameters} {parameter binding} ** ** ^(In the SQL statement text input to [sqlite3_prepare_v2()] and its variants, ** literals may be replaced by a [parameter] that matches one of following ** templates: ** **
    **
  • ? **
  • ?NNN **
  • :VVV **
  • @VVV **
  • $VVV **
** ** In the templates above, NNN represents an integer literal, ** and VVV represents an alphanumeric identifier.)^ ^The values of these ** parameters (also called "host parameter names" or "SQL parameters") ** can be set using the sqlite3_bind_*() routines defined here. ** ** ^The first argument to the sqlite3_bind_*() routines is always ** a pointer to the [sqlite3_stmt] object returned from ** [sqlite3_prepare_v2()] or its variants. ** ** ^The second argument is the index of the SQL parameter to be set. ** ^The leftmost SQL parameter has an index of 1. ^When the same named ** SQL parameter is used more than once, second and subsequent ** occurrences have the same index as the first occurrence. ** ^The index for named parameters can be looked up using the ** [sqlite3_bind_parameter_index()] API if desired. ^The index ** for "?NNN" parameters is the value of NNN. ** ^The NNN value must be between 1 and the [sqlite3_limit()] ** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 999). ** ** ^The third argument is the value to bind to the parameter. ** ** ^(In those routines that have a fourth argument, its value is the ** number of bytes in the parameter. To be clear: the value is the ** number of bytes in the value, not the number of characters.)^ ** ^If the fourth parameter is negative, the length of the string is ** the number of bytes up to the first zero terminator. ** If a non-negative fourth parameter is provided to sqlite3_bind_text() ** or sqlite3_bind_text16() then that parameter must be the byte offset ** where the NUL terminator would occur assuming the string were NUL ** terminated. If any NUL characters occur at byte offsets less than ** the value of the fourth parameter then the resulting string value will ** contain embedded NULs. The result of expressions involving strings ** with embedded NULs is undefined. ** ** ^The fifth argument to sqlite3_bind_blob(), sqlite3_bind_text(), and ** sqlite3_bind_text16() is a destructor used to dispose of the BLOB or ** string after SQLite has finished with it. ^The destructor is called ** to dispose of the BLOB or string even if the call to sqlite3_bind_blob(), ** sqlite3_bind_text(), or sqlite3_bind_text16() fails. ** ^If the fifth argument is ** the special value [SQLITE_STATIC], then SQLite assumes that the ** information is in static, unmanaged space and does not need to be freed. ** ^If the fifth argument has the value [SQLITE_TRANSIENT], then ** SQLite makes its own private copy of the data immediately, before ** the sqlite3_bind_*() routine returns. ** ** ^The sqlite3_bind_zeroblob() routine binds a BLOB of length N that ** is filled with zeroes. ^A zeroblob uses a fixed amount of memory ** (just an integer to hold its size) while it is being processed. ** Zeroblobs are intended to serve as placeholders for BLOBs whose ** content is later written using ** [sqlite3_blob_open | incremental BLOB I/O] routines. ** ^A negative value for the zeroblob results in a zero-length BLOB. ** ** ^If any of the sqlite3_bind_*() routines are called with a NULL pointer ** for the [prepared statement] or with a prepared statement for which ** [sqlite3_step()] has been called more recently than [sqlite3_reset()], ** then the call will return [SQLITE_MISUSE]. If any sqlite3_bind_() ** routine is passed a [prepared statement] that has been finalized, the ** result is undefined and probably harmful. ** ** ^Bindings are not cleared by the [sqlite3_reset()] routine. ** ^Unbound parameters are interpreted as NULL. ** ** ^The sqlite3_bind_* routines return [SQLITE_OK] on success or an ** [error code] if anything goes wrong. ** ^[SQLITE_RANGE] is returned if the parameter ** index is out of range. ^[SQLITE_NOMEM] is returned if malloc() fails. ** ** See also: [sqlite3_bind_parameter_count()], ** [sqlite3_bind_parameter_name()], and [sqlite3_bind_parameter_index()]. */ SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*)); SQLITE_API int sqlite3_bind_double(sqlite3_stmt*, int, double); SQLITE_API int sqlite3_bind_int(sqlite3_stmt*, int, int); SQLITE_API int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64); SQLITE_API int sqlite3_bind_null(sqlite3_stmt*, int); SQLITE_API int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*)); SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*)); SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*); SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n); /* ** CAPI3REF: Number Of SQL Parameters ** ** ^This routine can be used to find the number of [SQL parameters] ** in a [prepared statement]. SQL parameters are tokens of the ** form "?", "?NNN", ":AAA", "$AAA", or "@AAA" that serve as ** placeholders for values that are [sqlite3_bind_blob | bound] ** to the parameters at a later time. ** ** ^(This routine actually returns the index of the largest (rightmost) ** parameter. For all forms except ?NNN, this will correspond to the ** number of unique parameters. If parameters of the ?NNN form are used, ** there may be gaps in the list.)^ ** ** See also: [sqlite3_bind_blob|sqlite3_bind()], ** [sqlite3_bind_parameter_name()], and ** [sqlite3_bind_parameter_index()]. */ SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt*); /* ** CAPI3REF: Name Of A Host Parameter ** ** ^The sqlite3_bind_parameter_name(P,N) interface returns ** the name of the N-th [SQL parameter] in the [prepared statement] P. ** ^(SQL parameters of the form "?NNN" or ":AAA" or "@AAA" or "$AAA" ** have a name which is the string "?NNN" or ":AAA" or "@AAA" or "$AAA" ** respectively. ** In other words, the initial ":" or "$" or "@" or "?" ** is included as part of the name.)^ ** ^Parameters of the form "?" without a following integer have no name ** and are referred to as "nameless" or "anonymous parameters". ** ** ^The first host parameter has an index of 1, not 0. ** ** ^If the value N is out of range or if the N-th parameter is ** nameless, then NULL is returned. ^The returned string is ** always in UTF-8 encoding even if the named parameter was ** originally specified as UTF-16 in [sqlite3_prepare16()] or ** [sqlite3_prepare16_v2()]. ** ** See also: [sqlite3_bind_blob|sqlite3_bind()], ** [sqlite3_bind_parameter_count()], and ** [sqlite3_bind_parameter_index()]. */ SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int); /* ** CAPI3REF: Index Of A Parameter With A Given Name ** ** ^Return the index of an SQL parameter given its name. ^The ** index value returned is suitable for use as the second ** parameter to [sqlite3_bind_blob|sqlite3_bind()]. ^A zero ** is returned if no matching parameter is found. ^The parameter ** name must be given in UTF-8 even if the original statement ** was prepared from UTF-16 text using [sqlite3_prepare16_v2()]. ** ** See also: [sqlite3_bind_blob|sqlite3_bind()], ** [sqlite3_bind_parameter_count()], and ** [sqlite3_bind_parameter_index()]. */ SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName); /* ** CAPI3REF: Reset All Bindings On A Prepared Statement ** ** ^Contrary to the intuition of many, [sqlite3_reset()] does not reset ** the [sqlite3_bind_blob | bindings] on a [prepared statement]. ** ^Use this routine to reset all host parameters to NULL. */ SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt*); /* ** CAPI3REF: Number Of Columns In A Result Set ** ** ^Return the number of columns in the result set returned by the ** [prepared statement]. ^This routine returns 0 if pStmt is an SQL ** statement that does not return data (for example an [UPDATE]). ** ** See also: [sqlite3_data_count()] */ SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt); /* ** CAPI3REF: Column Names In A Result Set ** ** ^These routines return the name assigned to a particular column ** in the result set of a [SELECT] statement. ^The sqlite3_column_name() ** interface returns a pointer to a zero-terminated UTF-8 string ** and sqlite3_column_name16() returns a pointer to a zero-terminated ** UTF-16 string. ^The first parameter is the [prepared statement] ** that implements the [SELECT] statement. ^The second parameter is the ** column number. ^The leftmost column is number 0. ** ** ^The returned string pointer is valid until either the [prepared statement] ** is destroyed by [sqlite3_finalize()] or until the statement is automatically ** reprepared by the first call to [sqlite3_step()] for a particular run ** or until the next call to ** sqlite3_column_name() or sqlite3_column_name16() on the same column. ** ** ^If sqlite3_malloc() fails during the processing of either routine ** (for example during a conversion from UTF-8 to UTF-16) then a ** NULL pointer is returned. ** ** ^The name of a result column is the value of the "AS" clause for ** that column, if there is an AS clause. If there is no AS clause ** then the name of the column is unspecified and may change from ** one release of SQLite to the next. */ SQLITE_API const char *sqlite3_column_name(sqlite3_stmt*, int N); SQLITE_API const void *sqlite3_column_name16(sqlite3_stmt*, int N); /* ** CAPI3REF: Source Of Data In A Query Result ** ** ^These routines provide a means to determine the database, table, and ** table column that is the origin of a particular result column in ** [SELECT] statement. ** ^The name of the database or table or column can be returned as ** either a UTF-8 or UTF-16 string. ^The _database_ routines return ** the database name, the _table_ routines return the table name, and ** the origin_ routines return the column name. ** ^The returned string is valid until the [prepared statement] is destroyed ** using [sqlite3_finalize()] or until the statement is automatically ** reprepared by the first call to [sqlite3_step()] for a particular run ** or until the same information is requested ** again in a different encoding. ** ** ^The names returned are the original un-aliased names of the ** database, table, and column. ** ** ^The first argument to these interfaces is a [prepared statement]. ** ^These functions return information about the Nth result column returned by ** the statement, where N is the second function argument. ** ^The left-most column is column 0 for these routines. ** ** ^If the Nth column returned by the statement is an expression or ** subquery and is not a column value, then all of these functions return ** NULL. ^These routine might also return NULL if a memory allocation error ** occurs. ^Otherwise, they return the name of the attached database, table, ** or column that query result column was extracted from. ** ** ^As with all other SQLite APIs, those whose names end with "16" return ** UTF-16 encoded strings and the other functions return UTF-8. ** ** ^These APIs are only available if the library was compiled with the ** [SQLITE_ENABLE_COLUMN_METADATA] C-preprocessor symbol. ** ** If two or more threads call one or more of these routines against the same ** prepared statement and column at the same time then the results are ** undefined. ** ** If two or more threads call one or more ** [sqlite3_column_database_name | column metadata interfaces] ** for the same [prepared statement] and result column ** at the same time then the results are undefined. */ SQLITE_API const char *sqlite3_column_database_name(sqlite3_stmt*,int); SQLITE_API const void *sqlite3_column_database_name16(sqlite3_stmt*,int); SQLITE_API const char *sqlite3_column_table_name(sqlite3_stmt*,int); SQLITE_API const void *sqlite3_column_table_name16(sqlite3_stmt*,int); SQLITE_API const char *sqlite3_column_origin_name(sqlite3_stmt*,int); SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt*,int); /* ** CAPI3REF: Declared Datatype Of A Query Result ** ** ^(The first parameter is a [prepared statement]. ** If this statement is a [SELECT] statement and the Nth column of the ** returned result set of that [SELECT] is a table column (not an ** expression or subquery) then the declared type of the table ** column is returned.)^ ^If the Nth column of the result set is an ** expression or subquery, then a NULL pointer is returned. ** ^The returned string is always UTF-8 encoded. ** ** ^(For example, given the database schema: ** ** CREATE TABLE t1(c1 VARIANT); ** ** and the following statement to be compiled: ** ** SELECT c1 + 1, c1 FROM t1; ** ** this routine would return the string "VARIANT" for the second result ** column (i==1), and a NULL pointer for the first result column (i==0).)^ ** ** ^SQLite uses dynamic run-time typing. ^So just because a column ** is declared to contain a particular type does not mean that the ** data stored in that column is of the declared type. SQLite is ** strongly typed, but the typing is dynamic not static. ^Type ** is associated with individual values, not with the containers ** used to hold those values. */ SQLITE_API const char *sqlite3_column_decltype(sqlite3_stmt*,int); SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int); /* ** CAPI3REF: Evaluate An SQL Statement ** ** After a [prepared statement] has been prepared using either ** [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] or one of the legacy ** interfaces [sqlite3_prepare()] or [sqlite3_prepare16()], this function ** must be called one or more times to evaluate the statement. ** ** The details of the behavior of the sqlite3_step() interface depend ** on whether the statement was prepared using the newer "v2" interface ** [sqlite3_prepare_v2()] and [sqlite3_prepare16_v2()] or the older legacy ** interface [sqlite3_prepare()] and [sqlite3_prepare16()]. The use of the ** new "v2" interface is recommended for new applications but the legacy ** interface will continue to be supported. ** ** ^In the legacy interface, the return value will be either [SQLITE_BUSY], ** [SQLITE_DONE], [SQLITE_ROW], [SQLITE_ERROR], or [SQLITE_MISUSE]. ** ^With the "v2" interface, any of the other [result codes] or ** [extended result codes] might be returned as well. ** ** ^[SQLITE_BUSY] means that the database engine was unable to acquire the ** database locks it needs to do its job. ^If the statement is a [COMMIT] ** or occurs outside of an explicit transaction, then you can retry the ** statement. If the statement is not a [COMMIT] and occurs within an ** explicit transaction then you should rollback the transaction before ** continuing. ** ** ^[SQLITE_DONE] means that the statement has finished executing ** successfully. sqlite3_step() should not be called again on this virtual ** machine without first calling [sqlite3_reset()] to reset the virtual ** machine back to its initial state. ** ** ^If the SQL statement being executed returns any data, then [SQLITE_ROW] ** is returned each time a new row of data is ready for processing by the ** caller. The values may be accessed using the [column access functions]. ** sqlite3_step() is called again to retrieve the next row of data. ** ** ^[SQLITE_ERROR] means that a run-time error (such as a constraint ** violation) has occurred. sqlite3_step() should not be called again on ** the VM. More information may be found by calling [sqlite3_errmsg()]. ** ^With the legacy interface, a more specific error code (for example, ** [SQLITE_INTERRUPT], [SQLITE_SCHEMA], [SQLITE_CORRUPT], and so forth) ** can be obtained by calling [sqlite3_reset()] on the ** [prepared statement]. ^In the "v2" interface, ** the more specific error code is returned directly by sqlite3_step(). ** ** [SQLITE_MISUSE] means that the this routine was called inappropriately. ** Perhaps it was called on a [prepared statement] that has ** already been [sqlite3_finalize | finalized] or on one that had ** previously returned [SQLITE_ERROR] or [SQLITE_DONE]. Or it could ** be the case that the same database connection is being used by two or ** more threads at the same moment in time. ** ** For all versions of SQLite up to and including 3.6.23.1, a call to ** [sqlite3_reset()] was required after sqlite3_step() returned anything ** other than [SQLITE_ROW] before any subsequent invocation of ** sqlite3_step(). Failure to reset the prepared statement using ** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from ** sqlite3_step(). But after version 3.6.23.1, sqlite3_step() began ** calling [sqlite3_reset()] automatically in this circumstance rather ** than returning [SQLITE_MISUSE]. This is not considered a compatibility ** break because any application that ever receives an SQLITE_MISUSE error ** is broken by definition. The [SQLITE_OMIT_AUTORESET] compile-time option ** can be used to restore the legacy behavior. ** ** Goofy Interface Alert: In the legacy interface, the sqlite3_step() ** API always returns a generic error code, [SQLITE_ERROR], following any ** error other than [SQLITE_BUSY] and [SQLITE_MISUSE]. You must call ** [sqlite3_reset()] or [sqlite3_finalize()] in order to find one of the ** specific [error codes] that better describes the error. ** We admit that this is a goofy design. The problem has been fixed ** with the "v2" interface. If you prepare all of your SQL statements ** using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] instead ** of the legacy [sqlite3_prepare()] and [sqlite3_prepare16()] interfaces, ** then the more specific [error codes] are returned directly ** by sqlite3_step(). The use of the "v2" interface is recommended. */ SQLITE_API int sqlite3_step(sqlite3_stmt*); /* ** CAPI3REF: Number of columns in a result set ** ** ^The sqlite3_data_count(P) interface returns the number of columns in the ** current row of the result set of [prepared statement] P. ** ^If prepared statement P does not have results ready to return ** (via calls to the [sqlite3_column_int | sqlite3_column_*()] of ** interfaces) then sqlite3_data_count(P) returns 0. ** ^The sqlite3_data_count(P) routine also returns 0 if P is a NULL pointer. ** ^The sqlite3_data_count(P) routine returns 0 if the previous call to ** [sqlite3_step](P) returned [SQLITE_DONE]. ^The sqlite3_data_count(P) ** will return non-zero if previous call to [sqlite3_step](P) returned ** [SQLITE_ROW], except in the case of the [PRAGMA incremental_vacuum] ** where it always returns zero since each step of that multi-step ** pragma returns 0 columns of data. ** ** See also: [sqlite3_column_count()] */ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt); /* ** CAPI3REF: Fundamental Datatypes ** KEYWORDS: SQLITE_TEXT ** ** ^(Every value in SQLite has one of five fundamental datatypes: ** **
    **
  • 64-bit signed integer **
  • 64-bit IEEE floating point number **
  • string **
  • BLOB **
  • NULL **
)^ ** ** These constants are codes for each of those types. ** ** Note that the SQLITE_TEXT constant was also used in SQLite version 2 ** for a completely different meaning. Software that links against both ** SQLite version 2 and SQLite version 3 should use SQLITE3_TEXT, not ** SQLITE_TEXT. */ #define SQLITE_INTEGER 1 #define SQLITE_FLOAT 2 #define SQLITE_BLOB 4 #define SQLITE_NULL 5 #ifdef SQLITE_TEXT # undef SQLITE_TEXT #else # define SQLITE_TEXT 3 #endif #define SQLITE3_TEXT 3 /* ** CAPI3REF: Result Values From A Query ** KEYWORDS: {column access functions} ** ** These routines form the "result set" interface. ** ** ^These routines return information about a single column of the current ** result row of a query. ^In every case the first argument is a pointer ** to the [prepared statement] that is being evaluated (the [sqlite3_stmt*] ** that was returned from [sqlite3_prepare_v2()] or one of its variants) ** and the second argument is the index of the column for which information ** should be returned. ^The leftmost column of the result set has the index 0. ** ^The number of columns in the result can be determined using ** [sqlite3_column_count()]. ** ** If the SQL statement does not currently point to a valid row, or if the ** column index is out of range, the result is undefined. ** These routines may only be called when the most recent call to ** [sqlite3_step()] has returned [SQLITE_ROW] and neither ** [sqlite3_reset()] nor [sqlite3_finalize()] have been called subsequently. ** If any of these routines are called after [sqlite3_reset()] or ** [sqlite3_finalize()] or after [sqlite3_step()] has returned ** something other than [SQLITE_ROW], the results are undefined. ** If [sqlite3_step()] or [sqlite3_reset()] or [sqlite3_finalize()] ** are called from a different thread while any of these routines ** are pending, then the results are undefined. ** ** ^The sqlite3_column_type() routine returns the ** [SQLITE_INTEGER | datatype code] for the initial data type ** of the result column. ^The returned value is one of [SQLITE_INTEGER], ** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL]. The value ** returned by sqlite3_column_type() is only meaningful if no type ** conversions have occurred as described below. After a type conversion, ** the value returned by sqlite3_column_type() is undefined. Future ** versions of SQLite may change the behavior of sqlite3_column_type() ** following a type conversion. ** ** ^If the result is a BLOB or UTF-8 string then the sqlite3_column_bytes() ** routine returns the number of bytes in that BLOB or string. ** ^If the result is a UTF-16 string, then sqlite3_column_bytes() converts ** the string to UTF-8 and then returns the number of bytes. ** ^If the result is a numeric value then sqlite3_column_bytes() uses ** [sqlite3_snprintf()] to convert that value to a UTF-8 string and returns ** the number of bytes in that string. ** ^If the result is NULL, then sqlite3_column_bytes() returns zero. ** ** ^If the result is a BLOB or UTF-16 string then the sqlite3_column_bytes16() ** routine returns the number of bytes in that BLOB or string. ** ^If the result is a UTF-8 string, then sqlite3_column_bytes16() converts ** the string to UTF-16 and then returns the number of bytes. ** ^If the result is a numeric value then sqlite3_column_bytes16() uses ** [sqlite3_snprintf()] to convert that value to a UTF-16 string and returns ** the number of bytes in that string. ** ^If the result is NULL, then sqlite3_column_bytes16() returns zero. ** ** ^The values returned by [sqlite3_column_bytes()] and ** [sqlite3_column_bytes16()] do not include the zero terminators at the end ** of the string. ^For clarity: the values returned by ** [sqlite3_column_bytes()] and [sqlite3_column_bytes16()] are the number of ** bytes in the string, not the number of characters. ** ** ^Strings returned by sqlite3_column_text() and sqlite3_column_text16(), ** even empty strings, are always zero terminated. ^The return ** value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer. ** ** ^The object returned by [sqlite3_column_value()] is an ** [unprotected sqlite3_value] object. An unprotected sqlite3_value object ** may only be used with [sqlite3_bind_value()] and [sqlite3_result_value()]. ** If the [unprotected sqlite3_value] object returned by ** [sqlite3_column_value()] is used in any other way, including calls ** to routines like [sqlite3_value_int()], [sqlite3_value_text()], ** or [sqlite3_value_bytes()], then the behavior is undefined. ** ** These routines attempt to convert the value where appropriate. ^For ** example, if the internal representation is FLOAT and a text result ** is requested, [sqlite3_snprintf()] is used internally to perform the ** conversion automatically. ^(The following table details the conversions ** that are applied: ** **
** **
Internal
Type
Requested
Type
Conversion ** **
NULL INTEGER Result is 0 **
NULL FLOAT Result is 0.0 **
NULL TEXT Result is NULL pointer **
NULL BLOB Result is NULL pointer **
INTEGER FLOAT Convert from integer to float **
INTEGER TEXT ASCII rendering of the integer **
INTEGER BLOB Same as INTEGER->TEXT **
FLOAT INTEGER Convert from float to integer **
FLOAT TEXT ASCII rendering of the float **
FLOAT BLOB Same as FLOAT->TEXT **
TEXT INTEGER Use atoi() **
TEXT FLOAT Use atof() **
TEXT BLOB No change **
BLOB INTEGER Convert to TEXT then use atoi() **
BLOB FLOAT Convert to TEXT then use atof() **
BLOB TEXT Add a zero terminator if needed **
**
)^ ** ** The table above makes reference to standard C library functions atoi() ** and atof(). SQLite does not really use these functions. It has its ** own equivalent internal routines. The atoi() and atof() names are ** used in the table for brevity and because they are familiar to most ** C programmers. ** ** Note that when type conversions occur, pointers returned by prior ** calls to sqlite3_column_blob(), sqlite3_column_text(), and/or ** sqlite3_column_text16() may be invalidated. ** Type conversions and pointer invalidations might occur ** in the following cases: ** **
    **
  • The initial content is a BLOB and sqlite3_column_text() or ** sqlite3_column_text16() is called. A zero-terminator might ** need to be added to the string.
  • **
  • The initial content is UTF-8 text and sqlite3_column_bytes16() or ** sqlite3_column_text16() is called. The content must be converted ** to UTF-16.
  • **
  • The initial content is UTF-16 text and sqlite3_column_bytes() or ** sqlite3_column_text() is called. The content must be converted ** to UTF-8.
  • **
** ** ^Conversions between UTF-16be and UTF-16le are always done in place and do ** not invalidate a prior pointer, though of course the content of the buffer ** that the prior pointer references will have been modified. Other kinds ** of conversion are done in place when it is possible, but sometimes they ** are not possible and in those cases prior pointers are invalidated. ** ** The safest and easiest to remember policy is to invoke these routines ** in one of the following ways: ** **
    **
  • sqlite3_column_text() followed by sqlite3_column_bytes()
  • **
  • sqlite3_column_blob() followed by sqlite3_column_bytes()
  • **
  • sqlite3_column_text16() followed by sqlite3_column_bytes16()
  • **
** ** In other words, you should call sqlite3_column_text(), ** sqlite3_column_blob(), or sqlite3_column_text16() first to force the result ** into the desired format, then invoke sqlite3_column_bytes() or ** sqlite3_column_bytes16() to find the size of the result. Do not mix calls ** to sqlite3_column_text() or sqlite3_column_blob() with calls to ** sqlite3_column_bytes16(), and do not mix calls to sqlite3_column_text16() ** with calls to sqlite3_column_bytes(). ** ** ^The pointers returned are valid until a type conversion occurs as ** described above, or until [sqlite3_step()] or [sqlite3_reset()] or ** [sqlite3_finalize()] is called. ^The memory space used to hold strings ** and BLOBs is freed automatically. Do not pass the pointers returned ** [sqlite3_column_blob()], [sqlite3_column_text()], etc. into ** [sqlite3_free()]. ** ** ^(If a memory allocation error occurs during the evaluation of any ** of these routines, a default value is returned. The default value ** is either the integer 0, the floating point number 0.0, or a NULL ** pointer. Subsequent calls to [sqlite3_errcode()] will return ** [SQLITE_NOMEM].)^ */ SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol); SQLITE_API int sqlite3_column_bytes(sqlite3_stmt*, int iCol); SQLITE_API int sqlite3_column_bytes16(sqlite3_stmt*, int iCol); SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol); SQLITE_API int sqlite3_column_int(sqlite3_stmt*, int iCol); SQLITE_API sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol); SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol); SQLITE_API const void *sqlite3_column_text16(sqlite3_stmt*, int iCol); SQLITE_API int sqlite3_column_type(sqlite3_stmt*, int iCol); SQLITE_API sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol); /* ** CAPI3REF: Destroy A Prepared Statement Object ** ** ^The sqlite3_finalize() function is called to delete a [prepared statement]. ** ^If the most recent evaluation of the statement encountered no errors ** or if the statement is never been evaluated, then sqlite3_finalize() returns ** SQLITE_OK. ^If the most recent evaluation of statement S failed, then ** sqlite3_finalize(S) returns the appropriate [error code] or ** [extended error code]. ** ** ^The sqlite3_finalize(S) routine can be called at any point during ** the life cycle of [prepared statement] S: ** before statement S is ever evaluated, after ** one or more calls to [sqlite3_reset()], or after any call ** to [sqlite3_step()] regardless of whether or not the statement has ** completed execution. ** ** ^Invoking sqlite3_finalize() on a NULL pointer is a harmless no-op. ** ** The application must finalize every [prepared statement] in order to avoid ** resource leaks. It is a grievous error for the application to try to use ** a prepared statement after it has been finalized. Any use of a prepared ** statement after it has been finalized can result in undefined and ** undesirable behavior such as segfaults and heap corruption. */ SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt); /* ** CAPI3REF: Reset A Prepared Statement Object ** ** The sqlite3_reset() function is called to reset a [prepared statement] ** object back to its initial state, ready to be re-executed. ** ^Any SQL statement variables that had values bound to them using ** the [sqlite3_bind_blob | sqlite3_bind_*() API] retain their values. ** Use [sqlite3_clear_bindings()] to reset the bindings. ** ** ^The [sqlite3_reset(S)] interface resets the [prepared statement] S ** back to the beginning of its program. ** ** ^If the most recent call to [sqlite3_step(S)] for the ** [prepared statement] S returned [SQLITE_ROW] or [SQLITE_DONE], ** or if [sqlite3_step(S)] has never before been called on S, ** then [sqlite3_reset(S)] returns [SQLITE_OK]. ** ** ^If the most recent call to [sqlite3_step(S)] for the ** [prepared statement] S indicated an error, then ** [sqlite3_reset(S)] returns an appropriate [error code]. ** ** ^The [sqlite3_reset(S)] interface does not change the values ** of any [sqlite3_bind_blob|bindings] on the [prepared statement] S. */ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt); /* ** CAPI3REF: Create Or Redefine SQL Functions ** KEYWORDS: {function creation routines} ** KEYWORDS: {application-defined SQL function} ** KEYWORDS: {application-defined SQL functions} ** ** ^These functions (collectively known as "function creation routines") ** are used to add SQL functions or aggregates or to redefine the behavior ** of existing SQL functions or aggregates. The only differences between ** these routines are the text encoding expected for ** the second parameter (the name of the function being created) ** and the presence or absence of a destructor callback for ** the application data pointer. ** ** ^The first parameter is the [database connection] to which the SQL ** function is to be added. ^If an application uses more than one database ** connection then application-defined SQL functions must be added ** to each database connection separately. ** ** ^The second parameter is the name of the SQL function to be created or ** redefined. ^The length of the name is limited to 255 bytes in a UTF-8 ** representation, exclusive of the zero-terminator. ^Note that the name ** length limit is in UTF-8 bytes, not characters nor UTF-16 bytes. ** ^Any attempt to create a function with a longer name ** will result in [SQLITE_MISUSE] being returned. ** ** ^The third parameter (nArg) ** is the number of arguments that the SQL function or ** aggregate takes. ^If this parameter is -1, then the SQL function or ** aggregate may take any number of arguments between 0 and the limit ** set by [sqlite3_limit]([SQLITE_LIMIT_FUNCTION_ARG]). If the third ** parameter is less than -1 or greater than 127 then the behavior is ** undefined. ** ** ^The fourth parameter, eTextRep, specifies what ** [SQLITE_UTF8 | text encoding] this SQL function prefers for ** its parameters. Every SQL function implementation must be able to work ** with UTF-8, UTF-16le, or UTF-16be. But some implementations may be ** more efficient with one encoding than another. ^An application may ** invoke sqlite3_create_function() or sqlite3_create_function16() multiple ** times with the same function but with different values of eTextRep. ** ^When multiple implementations of the same function are available, SQLite ** will pick the one that involves the least amount of data conversion. ** If there is only a single implementation which does not care what text ** encoding is used, then the fourth argument should be [SQLITE_ANY]. ** ** ^(The fifth parameter is an arbitrary pointer. The implementation of the ** function can gain access to this pointer using [sqlite3_user_data()].)^ ** ** ^The sixth, seventh and eighth parameters, xFunc, xStep and xFinal, are ** pointers to C-language functions that implement the SQL function or ** aggregate. ^A scalar SQL function requires an implementation of the xFunc ** callback only; NULL pointers must be passed as the xStep and xFinal ** parameters. ^An aggregate SQL function requires an implementation of xStep ** and xFinal and NULL pointer must be passed for xFunc. ^To delete an existing ** SQL function or aggregate, pass NULL pointers for all three function ** callbacks. ** ** ^(If the ninth parameter to sqlite3_create_function_v2() is not NULL, ** then it is destructor for the application data pointer. ** The destructor is invoked when the function is deleted, either by being ** overloaded or when the database connection closes.)^ ** ^The destructor is also invoked if the call to ** sqlite3_create_function_v2() fails. ** ^When the destructor callback of the tenth parameter is invoked, it ** is passed a single argument which is a copy of the application data ** pointer which was the fifth parameter to sqlite3_create_function_v2(). ** ** ^It is permitted to register multiple implementations of the same ** functions with the same name but with either differing numbers of ** arguments or differing preferred text encodings. ^SQLite will use ** the implementation that most closely matches the way in which the ** SQL function is used. ^A function implementation with a non-negative ** nArg parameter is a better match than a function implementation with ** a negative nArg. ^A function where the preferred text encoding ** matches the database encoding is a better ** match than a function where the encoding is different. ** ^A function where the encoding difference is between UTF16le and UTF16be ** is a closer match than a function where the encoding difference is ** between UTF8 and UTF16. ** ** ^Built-in functions may be overloaded by new application-defined functions. ** ** ^An application-defined function is permitted to call other ** SQLite interfaces. However, such calls must not ** close the database connection nor finalize or reset the prepared ** statement in which the function is running. */ SQLITE_API int sqlite3_create_function( sqlite3 *db, const char *zFunctionName, int nArg, int eTextRep, void *pApp, void (*xFunc)(sqlite3_context*,int,sqlite3_value**), void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*) ); SQLITE_API int sqlite3_create_function16( sqlite3 *db, const void *zFunctionName, int nArg, int eTextRep, void *pApp, void (*xFunc)(sqlite3_context*,int,sqlite3_value**), void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*) ); SQLITE_API int sqlite3_create_function_v2( sqlite3 *db, const char *zFunctionName, int nArg, int eTextRep, void *pApp, void (*xFunc)(sqlite3_context*,int,sqlite3_value**), void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*), void(*xDestroy)(void*) ); /* ** CAPI3REF: Text Encodings ** ** These constant define integer codes that represent the various ** text encodings supported by SQLite. */ #define SQLITE_UTF8 1 #define SQLITE_UTF16LE 2 #define SQLITE_UTF16BE 3 #define SQLITE_UTF16 4 /* Use native byte order */ #define SQLITE_ANY 5 /* sqlite3_create_function only */ #define SQLITE_UTF16_ALIGNED 8 /* sqlite3_create_collation only */ /* ** CAPI3REF: Deprecated Functions ** DEPRECATED ** ** These functions are [deprecated]. In order to maintain ** backwards compatibility with older code, these functions continue ** to be supported. However, new applications should avoid ** the use of these functions. To help encourage people to avoid ** using these functions, we are not going to tell you what they do. */ #ifndef SQLITE_OMIT_DEPRECATED SQLITE_API SQLITE_DEPRECATED int sqlite3_aggregate_count(sqlite3_context*); SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*); SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*); SQLITE_API SQLITE_DEPRECATED int sqlite3_global_recover(void); SQLITE_API SQLITE_DEPRECATED void sqlite3_thread_cleanup(void); SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),void*,sqlite3_int64); #endif /* ** CAPI3REF: Obtaining SQL Function Parameter Values ** ** The C-language implementation of SQL functions and aggregates uses ** this set of interface routines to access the parameter values on ** the function or aggregate. ** ** The xFunc (for scalar functions) or xStep (for aggregates) parameters ** to [sqlite3_create_function()] and [sqlite3_create_function16()] ** define callbacks that implement the SQL functions and aggregates. ** The 3rd parameter to these callbacks is an array of pointers to ** [protected sqlite3_value] objects. There is one [sqlite3_value] object for ** each parameter to the SQL function. These routines are used to ** extract values from the [sqlite3_value] objects. ** ** These routines work only with [protected sqlite3_value] objects. ** Any attempt to use these routines on an [unprotected sqlite3_value] ** object results in undefined behavior. ** ** ^These routines work just like the corresponding [column access functions] ** except that these routines take a single [protected sqlite3_value] object ** pointer instead of a [sqlite3_stmt*] pointer and an integer column number. ** ** ^The sqlite3_value_text16() interface extracts a UTF-16 string ** in the native byte-order of the host machine. ^The ** sqlite3_value_text16be() and sqlite3_value_text16le() interfaces ** extract UTF-16 strings as big-endian and little-endian respectively. ** ** ^(The sqlite3_value_numeric_type() interface attempts to apply ** numeric affinity to the value. This means that an attempt is ** made to convert the value to an integer or floating point. If ** such a conversion is possible without loss of information (in other ** words, if the value is a string that looks like a number) ** then the conversion is performed. Otherwise no conversion occurs. ** The [SQLITE_INTEGER | datatype] after conversion is returned.)^ ** ** Please pay particular attention to the fact that the pointer returned ** from [sqlite3_value_blob()], [sqlite3_value_text()], or ** [sqlite3_value_text16()] can be invalidated by a subsequent call to ** [sqlite3_value_bytes()], [sqlite3_value_bytes16()], [sqlite3_value_text()], ** or [sqlite3_value_text16()]. ** ** These routines must be called from the same thread as ** the SQL function that supplied the [sqlite3_value*] parameters. */ SQLITE_API const void *sqlite3_value_blob(sqlite3_value*); SQLITE_API int sqlite3_value_bytes(sqlite3_value*); SQLITE_API int sqlite3_value_bytes16(sqlite3_value*); SQLITE_API double sqlite3_value_double(sqlite3_value*); SQLITE_API int sqlite3_value_int(sqlite3_value*); SQLITE_API sqlite3_int64 sqlite3_value_int64(sqlite3_value*); SQLITE_API const unsigned char *sqlite3_value_text(sqlite3_value*); SQLITE_API const void *sqlite3_value_text16(sqlite3_value*); SQLITE_API const void *sqlite3_value_text16le(sqlite3_value*); SQLITE_API const void *sqlite3_value_text16be(sqlite3_value*); SQLITE_API int sqlite3_value_type(sqlite3_value*); SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*); /* ** CAPI3REF: Obtain Aggregate Function Context ** ** Implementations of aggregate SQL functions use this ** routine to allocate memory for storing their state. ** ** ^The first time the sqlite3_aggregate_context(C,N) routine is called ** for a particular aggregate function, SQLite ** allocates N of memory, zeroes out that memory, and returns a pointer ** to the new memory. ^On second and subsequent calls to ** sqlite3_aggregate_context() for the same aggregate function instance, ** the same buffer is returned. Sqlite3_aggregate_context() is normally ** called once for each invocation of the xStep callback and then one ** last time when the xFinal callback is invoked. ^(When no rows match ** an aggregate query, the xStep() callback of the aggregate function ** implementation is never called and xFinal() is called exactly once. ** In those cases, sqlite3_aggregate_context() might be called for the ** first time from within xFinal().)^ ** ** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer if N is ** less than or equal to zero or if a memory allocate error occurs. ** ** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is ** determined by the N parameter on first successful call. Changing the ** value of N in subsequent call to sqlite3_aggregate_context() within ** the same aggregate function instance will not resize the memory ** allocation.)^ ** ** ^SQLite automatically frees the memory allocated by ** sqlite3_aggregate_context() when the aggregate query concludes. ** ** The first parameter must be a copy of the ** [sqlite3_context | SQL function context] that is the first parameter ** to the xStep or xFinal callback routine that implements the aggregate ** function. ** ** This routine must be called from the same thread in which ** the aggregate SQL function is running. */ SQLITE_API void *sqlite3_aggregate_context(sqlite3_context*, int nBytes); /* ** CAPI3REF: User Data For Functions ** ** ^The sqlite3_user_data() interface returns a copy of ** the pointer that was the pUserData parameter (the 5th parameter) ** of the [sqlite3_create_function()] ** and [sqlite3_create_function16()] routines that originally ** registered the application defined function. ** ** This routine must be called from the same thread in which ** the application-defined function is running. */ SQLITE_API void *sqlite3_user_data(sqlite3_context*); /* ** CAPI3REF: Database Connection For Functions ** ** ^The sqlite3_context_db_handle() interface returns a copy of ** the pointer to the [database connection] (the 1st parameter) ** of the [sqlite3_create_function()] ** and [sqlite3_create_function16()] routines that originally ** registered the application defined function. */ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*); /* ** CAPI3REF: Function Auxiliary Data ** ** The following two functions may be used by scalar SQL functions to ** associate metadata with argument values. If the same value is passed to ** multiple invocations of the same SQL function during query execution, under ** some circumstances the associated metadata may be preserved. This may ** be used, for example, to add a regular-expression matching scalar ** function. The compiled version of the regular expression is stored as ** metadata associated with the SQL value passed as the regular expression ** pattern. The compiled regular expression can be reused on multiple ** invocations of the same function so that the original pattern string ** does not need to be recompiled on each invocation. ** ** ^The sqlite3_get_auxdata() interface returns a pointer to the metadata ** associated by the sqlite3_set_auxdata() function with the Nth argument ** value to the application-defined function. ^If no metadata has been ever ** been set for the Nth argument of the function, or if the corresponding ** function parameter has changed since the meta-data was set, ** then sqlite3_get_auxdata() returns a NULL pointer. ** ** ^The sqlite3_set_auxdata() interface saves the metadata ** pointed to by its 3rd parameter as the metadata for the N-th ** argument of the application-defined function. Subsequent ** calls to sqlite3_get_auxdata() might return this data, if it has ** not been destroyed. ** ^If it is not NULL, SQLite will invoke the destructor ** function given by the 4th parameter to sqlite3_set_auxdata() on ** the metadata when the corresponding function parameter changes ** or when the SQL statement completes, whichever comes first. ** ** SQLite is free to call the destructor and drop metadata on any ** parameter of any function at any time. ^The only guarantee is that ** the destructor will be called before the metadata is dropped. ** ** ^(In practice, metadata is preserved between function calls for ** expressions that are constant at compile time. This includes literal ** values and [parameters].)^ ** ** These routines must be called from the same thread in which ** the SQL function is running. */ SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N); SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*)); /* ** CAPI3REF: Constants Defining Special Destructor Behavior ** ** These are special values for the destructor that is passed in as the ** final argument to routines like [sqlite3_result_blob()]. ^If the destructor ** argument is SQLITE_STATIC, it means that the content pointer is constant ** and will never change. It does not need to be destroyed. ^The ** SQLITE_TRANSIENT value means that the content will likely change in ** the near future and that SQLite should make its own private copy of ** the content before returning. ** ** The typedef is necessary to work around problems in certain ** C++ compilers. See ticket #2191. */ typedef void (*sqlite3_destructor_type)(void*); #define SQLITE_STATIC ((sqlite3_destructor_type)0) #define SQLITE_TRANSIENT ((sqlite3_destructor_type)-1) /* ** CAPI3REF: Setting The Result Of An SQL Function ** ** These routines are used by the xFunc or xFinal callbacks that ** implement SQL functions and aggregates. See ** [sqlite3_create_function()] and [sqlite3_create_function16()] ** for additional information. ** ** These functions work very much like the [parameter binding] family of ** functions used to bind values to host parameters in prepared statements. ** Refer to the [SQL parameter] documentation for additional information. ** ** ^The sqlite3_result_blob() interface sets the result from ** an application-defined function to be the BLOB whose content is pointed ** to by the second parameter and which is N bytes long where N is the ** third parameter. ** ** ^The sqlite3_result_zeroblob() interfaces set the result of ** the application-defined function to be a BLOB containing all zero ** bytes and N bytes in size, where N is the value of the 2nd parameter. ** ** ^The sqlite3_result_double() interface sets the result from ** an application-defined function to be a floating point value specified ** by its 2nd argument. ** ** ^The sqlite3_result_error() and sqlite3_result_error16() functions ** cause the implemented SQL function to throw an exception. ** ^SQLite uses the string pointed to by the ** 2nd parameter of sqlite3_result_error() or sqlite3_result_error16() ** as the text of an error message. ^SQLite interprets the error ** message string from sqlite3_result_error() as UTF-8. ^SQLite ** interprets the string from sqlite3_result_error16() as UTF-16 in native ** byte order. ^If the third parameter to sqlite3_result_error() ** or sqlite3_result_error16() is negative then SQLite takes as the error ** message all text up through the first zero character. ** ^If the third parameter to sqlite3_result_error() or ** sqlite3_result_error16() is non-negative then SQLite takes that many ** bytes (not characters) from the 2nd parameter as the error message. ** ^The sqlite3_result_error() and sqlite3_result_error16() ** routines make a private copy of the error message text before ** they return. Hence, the calling function can deallocate or ** modify the text after they return without harm. ** ^The sqlite3_result_error_code() function changes the error code ** returned by SQLite as a result of an error in a function. ^By default, ** the error code is SQLITE_ERROR. ^A subsequent call to sqlite3_result_error() ** or sqlite3_result_error16() resets the error code to SQLITE_ERROR. ** ** ^The sqlite3_result_toobig() interface causes SQLite to throw an error ** indicating that a string or BLOB is too long to represent. ** ** ^The sqlite3_result_nomem() interface causes SQLite to throw an error ** indicating that a memory allocation failed. ** ** ^The sqlite3_result_int() interface sets the return value ** of the application-defined function to be the 32-bit signed integer ** value given in the 2nd argument. ** ^The sqlite3_result_int64() interface sets the return value ** of the application-defined function to be the 64-bit signed integer ** value given in the 2nd argument. ** ** ^The sqlite3_result_null() interface sets the return value ** of the application-defined function to be NULL. ** ** ^The sqlite3_result_text(), sqlite3_result_text16(), ** sqlite3_result_text16le(), and sqlite3_result_text16be() interfaces ** set the return value of the application-defined function to be ** a text string which is represented as UTF-8, UTF-16 native byte order, ** UTF-16 little endian, or UTF-16 big endian, respectively. ** ^SQLite takes the text result from the application from ** the 2nd parameter of the sqlite3_result_text* interfaces. ** ^If the 3rd parameter to the sqlite3_result_text* interfaces ** is negative, then SQLite takes result text from the 2nd parameter ** through the first zero character. ** ^If the 3rd parameter to the sqlite3_result_text* interfaces ** is non-negative, then as many bytes (not characters) of the text ** pointed to by the 2nd parameter are taken as the application-defined ** function result. If the 3rd parameter is non-negative, then it ** must be the byte offset into the string where the NUL terminator would ** appear if the string where NUL terminated. If any NUL characters occur ** in the string at a byte offset that is less than the value of the 3rd ** parameter, then the resulting string will contain embedded NULs and the ** result of expressions operating on strings with embedded NULs is undefined. ** ^If the 4th parameter to the sqlite3_result_text* interfaces ** or sqlite3_result_blob is a non-NULL pointer, then SQLite calls that ** function as the destructor on the text or BLOB result when it has ** finished using that result. ** ^If the 4th parameter to the sqlite3_result_text* interfaces or to ** sqlite3_result_blob is the special constant SQLITE_STATIC, then SQLite ** assumes that the text or BLOB result is in constant space and does not ** copy the content of the parameter nor call a destructor on the content ** when it has finished using that result. ** ^If the 4th parameter to the sqlite3_result_text* interfaces ** or sqlite3_result_blob is the special constant SQLITE_TRANSIENT ** then SQLite makes a copy of the result into space obtained from ** from [sqlite3_malloc()] before it returns. ** ** ^The sqlite3_result_value() interface sets the result of ** the application-defined function to be a copy the ** [unprotected sqlite3_value] object specified by the 2nd parameter. ^The ** sqlite3_result_value() interface makes a copy of the [sqlite3_value] ** so that the [sqlite3_value] specified in the parameter may change or ** be deallocated after sqlite3_result_value() returns without harm. ** ^A [protected sqlite3_value] object may always be used where an ** [unprotected sqlite3_value] object is required, so either ** kind of [sqlite3_value] object can be used with this interface. ** ** If these routines are called from within the different thread ** than the one containing the application-defined function that received ** the [sqlite3_context] pointer, the results are undefined. */ SQLITE_API void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*)); SQLITE_API void sqlite3_result_double(sqlite3_context*, double); SQLITE_API void sqlite3_result_error(sqlite3_context*, const char*, int); SQLITE_API void sqlite3_result_error16(sqlite3_context*, const void*, int); SQLITE_API void sqlite3_result_error_toobig(sqlite3_context*); SQLITE_API void sqlite3_result_error_nomem(sqlite3_context*); SQLITE_API void sqlite3_result_error_code(sqlite3_context*, int); SQLITE_API void sqlite3_result_int(sqlite3_context*, int); SQLITE_API void sqlite3_result_int64(sqlite3_context*, sqlite3_int64); SQLITE_API void sqlite3_result_null(sqlite3_context*); SQLITE_API void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*)); SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*)); SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*)); SQLITE_API void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*)); SQLITE_API void sqlite3_result_value(sqlite3_context*, sqlite3_value*); SQLITE_API void sqlite3_result_zeroblob(sqlite3_context*, int n); /* ** CAPI3REF: Define New Collating Sequences ** ** ^These functions add, remove, or modify a [collation] associated ** with the [database connection] specified as the first argument. ** ** ^The name of the collation is a UTF-8 string ** for sqlite3_create_collation() and sqlite3_create_collation_v2() ** and a UTF-16 string in native byte order for sqlite3_create_collation16(). ** ^Collation names that compare equal according to [sqlite3_strnicmp()] are ** considered to be the same name. ** ** ^(The third argument (eTextRep) must be one of the constants: **
    **
  • [SQLITE_UTF8], **
  • [SQLITE_UTF16LE], **
  • [SQLITE_UTF16BE], **
  • [SQLITE_UTF16], or **
  • [SQLITE_UTF16_ALIGNED]. **
)^ ** ^The eTextRep argument determines the encoding of strings passed ** to the collating function callback, xCallback. ** ^The [SQLITE_UTF16] and [SQLITE_UTF16_ALIGNED] values for eTextRep ** force strings to be UTF16 with native byte order. ** ^The [SQLITE_UTF16_ALIGNED] value for eTextRep forces strings to begin ** on an even byte address. ** ** ^The fourth argument, pArg, is an application data pointer that is passed ** through as the first argument to the collating function callback. ** ** ^The fifth argument, xCallback, is a pointer to the collating function. ** ^Multiple collating functions can be registered using the same name but ** with different eTextRep parameters and SQLite will use whichever ** function requires the least amount of data transformation. ** ^If the xCallback argument is NULL then the collating function is ** deleted. ^When all collating functions having the same name are deleted, ** that collation is no longer usable. ** ** ^The collating function callback is invoked with a copy of the pArg ** application data pointer and with two strings in the encoding specified ** by the eTextRep argument. The collating function must return an ** integer that is negative, zero, or positive ** if the first string is less than, equal to, or greater than the second, ** respectively. A collating function must always return the same answer ** given the same inputs. If two or more collating functions are registered ** to the same collation name (using different eTextRep values) then all ** must give an equivalent answer when invoked with equivalent strings. ** The collating function must obey the following properties for all ** strings A, B, and C: ** **
    **
  1. If A==B then B==A. **
  2. If A==B and B==C then A==C. **
  3. If A<B THEN B>A. **
  4. If A<B and B<C then A<C. **
** ** If a collating function fails any of the above constraints and that ** collating function is registered and used, then the behavior of SQLite ** is undefined. ** ** ^The sqlite3_create_collation_v2() works like sqlite3_create_collation() ** with the addition that the xDestroy callback is invoked on pArg when ** the collating function is deleted. ** ^Collating functions are deleted when they are overridden by later ** calls to the collation creation functions or when the ** [database connection] is closed using [sqlite3_close()]. ** ** ^The xDestroy callback is not called if the ** sqlite3_create_collation_v2() function fails. Applications that invoke ** sqlite3_create_collation_v2() with a non-NULL xDestroy argument should ** check the return code and dispose of the application data pointer ** themselves rather than expecting SQLite to deal with it for them. ** This is different from every other SQLite interface. The inconsistency ** is unfortunate but cannot be changed without breaking backwards ** compatibility. ** ** See also: [sqlite3_collation_needed()] and [sqlite3_collation_needed16()]. */ SQLITE_API int sqlite3_create_collation( sqlite3*, const char *zName, int eTextRep, void *pArg, int(*xCompare)(void*,int,const void*,int,const void*) ); SQLITE_API int sqlite3_create_collation_v2( sqlite3*, const char *zName, int eTextRep, void *pArg, int(*xCompare)(void*,int,const void*,int,const void*), void(*xDestroy)(void*) ); SQLITE_API int sqlite3_create_collation16( sqlite3*, const void *zName, int eTextRep, void *pArg, int(*xCompare)(void*,int,const void*,int,const void*) ); /* ** CAPI3REF: Collation Needed Callbacks ** ** ^To avoid having to register all collation sequences before a database ** can be used, a single callback function may be registered with the ** [database connection] to be invoked whenever an undefined collation ** sequence is required. ** ** ^If the function is registered using the sqlite3_collation_needed() API, ** then it is passed the names of undefined collation sequences as strings ** encoded in UTF-8. ^If sqlite3_collation_needed16() is used, ** the names are passed as UTF-16 in machine native byte order. ** ^A call to either function replaces the existing collation-needed callback. ** ** ^(When the callback is invoked, the first argument passed is a copy ** of the second argument to sqlite3_collation_needed() or ** sqlite3_collation_needed16(). The second argument is the database ** connection. The third argument is one of [SQLITE_UTF8], [SQLITE_UTF16BE], ** or [SQLITE_UTF16LE], indicating the most desirable form of the collation ** sequence function required. The fourth parameter is the name of the ** required collation sequence.)^ ** ** The callback function should register the desired collation using ** [sqlite3_create_collation()], [sqlite3_create_collation16()], or ** [sqlite3_create_collation_v2()]. */ SQLITE_API int sqlite3_collation_needed( sqlite3*, void*, void(*)(void*,sqlite3*,int eTextRep,const char*) ); SQLITE_API int sqlite3_collation_needed16( sqlite3*, void*, void(*)(void*,sqlite3*,int eTextRep,const void*) ); #ifdef SQLITE_HAS_CODEC /* ** Specify the key for an encrypted database. This routine should be ** called right after sqlite3_open(). ** ** The code to implement this API is not available in the public release ** of SQLite. */ SQLITE_API int sqlite3_key( sqlite3 *db, /* Database to be rekeyed */ const void *pKey, int nKey /* The key */ ); /* ** Change the key on an open database. If the current database is not ** encrypted, this routine will encrypt it. If pNew==0 or nNew==0, the ** database is decrypted. ** ** The code to implement this API is not available in the public release ** of SQLite. */ SQLITE_API int sqlite3_rekey( sqlite3 *db, /* Database to be rekeyed */ const void *pKey, int nKey /* The new key */ ); /* ** Specify the activation key for a SEE database. Unless ** activated, none of the SEE routines will work. */ SQLITE_API void sqlite3_activate_see( const char *zPassPhrase /* Activation phrase */ ); #endif #ifdef SQLITE_ENABLE_CEROD /* ** Specify the activation key for a CEROD database. Unless ** activated, none of the CEROD routines will work. */ SQLITE_API void sqlite3_activate_cerod( const char *zPassPhrase /* Activation phrase */ ); #endif /* ** CAPI3REF: Suspend Execution For A Short Time ** ** The sqlite3_sleep() function causes the current thread to suspend execution ** for at least a number of milliseconds specified in its parameter. ** ** If the operating system does not support sleep requests with ** millisecond time resolution, then the time will be rounded up to ** the nearest second. The number of milliseconds of sleep actually ** requested from the operating system is returned. ** ** ^SQLite implements this interface by calling the xSleep() ** method of the default [sqlite3_vfs] object. If the xSleep() method ** of the default VFS is not implemented correctly, or not implemented at ** all, then the behavior of sqlite3_sleep() may deviate from the description ** in the previous paragraphs. */ SQLITE_API int sqlite3_sleep(int); /* ** CAPI3REF: Name Of The Folder Holding Temporary Files ** ** ^(If this global variable is made to point to a string which is ** the name of a folder (a.k.a. directory), then all temporary files ** created by SQLite when using a built-in [sqlite3_vfs | VFS] ** will be placed in that directory.)^ ^If this variable ** is a NULL pointer, then SQLite performs a search for an appropriate ** temporary file directory. ** ** It is not safe to read or modify this variable in more than one ** thread at a time. It is not safe to read or modify this variable ** if a [database connection] is being used at the same time in a separate ** thread. ** It is intended that this variable be set once ** as part of process initialization and before any SQLite interface ** routines have been called and that this variable remain unchanged ** thereafter. ** ** ^The [temp_store_directory pragma] may modify this variable and cause ** it to point to memory obtained from [sqlite3_malloc]. ^Furthermore, ** the [temp_store_directory pragma] always assumes that any string ** that this variable points to is held in memory obtained from ** [sqlite3_malloc] and the pragma may attempt to free that memory ** using [sqlite3_free]. ** Hence, if this variable is modified directly, either it should be ** made NULL or made to point to memory obtained from [sqlite3_malloc] ** or else the use of the [temp_store_directory pragma] should be avoided. */ SQLITE_API char *sqlite3_temp_directory; /* ** CAPI3REF: Test For Auto-Commit Mode ** KEYWORDS: {autocommit mode} ** ** ^The sqlite3_get_autocommit() interface returns non-zero or ** zero if the given database connection is or is not in autocommit mode, ** respectively. ^Autocommit mode is on by default. ** ^Autocommit mode is disabled by a [BEGIN] statement. ** ^Autocommit mode is re-enabled by a [COMMIT] or [ROLLBACK]. ** ** If certain kinds of errors occur on a statement within a multi-statement ** transaction (errors including [SQLITE_FULL], [SQLITE_IOERR], ** [SQLITE_NOMEM], [SQLITE_BUSY], and [SQLITE_INTERRUPT]) then the ** transaction might be rolled back automatically. The only way to ** find out whether SQLite automatically rolled back the transaction after ** an error is to use this function. ** ** If another thread changes the autocommit status of the database ** connection while this routine is running, then the return value ** is undefined. */ SQLITE_API int sqlite3_get_autocommit(sqlite3*); /* ** CAPI3REF: Find The Database Handle Of A Prepared Statement ** ** ^The sqlite3_db_handle interface returns the [database connection] handle ** to which a [prepared statement] belongs. ^The [database connection] ** returned by sqlite3_db_handle is the same [database connection] ** that was the first argument ** to the [sqlite3_prepare_v2()] call (or its variants) that was used to ** create the statement in the first place. */ SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*); /* ** CAPI3REF: Find the next prepared statement ** ** ^This interface returns a pointer to the next [prepared statement] after ** pStmt associated with the [database connection] pDb. ^If pStmt is NULL ** then this interface returns a pointer to the first prepared statement ** associated with the database connection pDb. ^If no prepared statement ** satisfies the conditions of this routine, it returns NULL. ** ** The [database connection] pointer D in a call to ** [sqlite3_next_stmt(D,S)] must refer to an open database ** connection and in particular must not be a NULL pointer. */ SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt); /* ** CAPI3REF: Commit And Rollback Notification Callbacks ** ** ^The sqlite3_commit_hook() interface registers a callback ** function to be invoked whenever a transaction is [COMMIT | committed]. ** ^Any callback set by a previous call to sqlite3_commit_hook() ** for the same database connection is overridden. ** ^The sqlite3_rollback_hook() interface registers a callback ** function to be invoked whenever a transaction is [ROLLBACK | rolled back]. ** ^Any callback set by a previous call to sqlite3_rollback_hook() ** for the same database connection is overridden. ** ^The pArg argument is passed through to the callback. ** ^If the callback on a commit hook function returns non-zero, ** then the commit is converted into a rollback. ** ** ^The sqlite3_commit_hook(D,C,P) and sqlite3_rollback_hook(D,C,P) functions ** return the P argument from the previous call of the same function ** on the same [database connection] D, or NULL for ** the first call for each function on D. ** ** The callback implementation must not do anything that will modify ** the database connection that invoked the callback. Any actions ** to modify the database connection must be deferred until after the ** completion of the [sqlite3_step()] call that triggered the commit ** or rollback hook in the first place. ** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their ** database connections for the meaning of "modify" in this paragraph. ** ** ^Registering a NULL function disables the callback. ** ** ^When the commit hook callback routine returns zero, the [COMMIT] ** operation is allowed to continue normally. ^If the commit hook ** returns non-zero, then the [COMMIT] is converted into a [ROLLBACK]. ** ^The rollback hook is invoked on a rollback that results from a commit ** hook returning non-zero, just as it would be with any other rollback. ** ** ^For the purposes of this API, a transaction is said to have been ** rolled back if an explicit "ROLLBACK" statement is executed, or ** an error or constraint causes an implicit rollback to occur. ** ^The rollback callback is not invoked if a transaction is ** automatically rolled back because the database connection is closed. ** ** See also the [sqlite3_update_hook()] interface. */ SQLITE_API void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*); SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); /* ** CAPI3REF: Data Change Notification Callbacks ** ** ^The sqlite3_update_hook() interface registers a callback function ** with the [database connection] identified by the first argument ** to be invoked whenever a row is updated, inserted or deleted. ** ^Any callback set by a previous call to this function ** for the same database connection is overridden. ** ** ^The second argument is a pointer to the function to invoke when a ** row is updated, inserted or deleted. ** ^The first argument to the callback is a copy of the third argument ** to sqlite3_update_hook(). ** ^The second callback argument is one of [SQLITE_INSERT], [SQLITE_DELETE], ** or [SQLITE_UPDATE], depending on the operation that caused the callback ** to be invoked. ** ^The third and fourth arguments to the callback contain pointers to the ** database and table name containing the affected row. ** ^The final callback parameter is the [rowid] of the row. ** ^In the case of an update, this is the [rowid] after the update takes place. ** ** ^(The update hook is not invoked when internal system tables are ** modified (i.e. sqlite_master and sqlite_sequence).)^ ** ** ^In the current implementation, the update hook ** is not invoked when duplication rows are deleted because of an ** [ON CONFLICT | ON CONFLICT REPLACE] clause. ^Nor is the update hook ** invoked when rows are deleted using the [truncate optimization]. ** The exceptions defined in this paragraph might change in a future ** release of SQLite. ** ** The update hook implementation must not do anything that will modify ** the database connection that invoked the update hook. Any actions ** to modify the database connection must be deferred until after the ** completion of the [sqlite3_step()] call that triggered the update hook. ** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their ** database connections for the meaning of "modify" in this paragraph. ** ** ^The sqlite3_update_hook(D,C,P) function ** returns the P argument from the previous call ** on the same [database connection] D, or NULL for ** the first call on D. ** ** See also the [sqlite3_commit_hook()] and [sqlite3_rollback_hook()] ** interfaces. */ SQLITE_API void *sqlite3_update_hook( sqlite3*, void(*)(void *,int ,char const *,char const *,sqlite3_int64), void* ); /* ** CAPI3REF: Enable Or Disable Shared Pager Cache ** KEYWORDS: {shared cache} ** ** ^(This routine enables or disables the sharing of the database cache ** and schema data structures between [database connection | connections] ** to the same database. Sharing is enabled if the argument is true ** and disabled if the argument is false.)^ ** ** ^Cache sharing is enabled and disabled for an entire process. ** This is a change as of SQLite version 3.5.0. In prior versions of SQLite, ** sharing was enabled or disabled for each thread separately. ** ** ^(The cache sharing mode set by this interface effects all subsequent ** calls to [sqlite3_open()], [sqlite3_open_v2()], and [sqlite3_open16()]. ** Existing database connections continue use the sharing mode ** that was in effect at the time they were opened.)^ ** ** ^(This routine returns [SQLITE_OK] if shared cache was enabled or disabled ** successfully. An [error code] is returned otherwise.)^ ** ** ^Shared cache is disabled by default. But this might change in ** future releases of SQLite. Applications that care about shared ** cache setting should set it explicitly. ** ** See Also: [SQLite Shared-Cache Mode] */ SQLITE_API int sqlite3_enable_shared_cache(int); /* ** CAPI3REF: Attempt To Free Heap Memory ** ** ^The sqlite3_release_memory() interface attempts to free N bytes ** of heap memory by deallocating non-essential memory allocations ** held by the database library. Memory used to cache database ** pages to improve performance is an example of non-essential memory. ** ^sqlite3_release_memory() returns the number of bytes actually freed, ** which might be more or less than the amount requested. ** ^The sqlite3_release_memory() routine is a no-op returning zero ** if SQLite is not compiled with [SQLITE_ENABLE_MEMORY_MANAGEMENT]. */ SQLITE_API int sqlite3_release_memory(int); /* ** CAPI3REF: Impose A Limit On Heap Size ** ** ^The sqlite3_soft_heap_limit64() interface sets and/or queries the ** soft limit on the amount of heap memory that may be allocated by SQLite. ** ^SQLite strives to keep heap memory utilization below the soft heap ** limit by reducing the number of pages held in the page cache ** as heap memory usages approaches the limit. ** ^The soft heap limit is "soft" because even though SQLite strives to stay ** below the limit, it will exceed the limit rather than generate ** an [SQLITE_NOMEM] error. In other words, the soft heap limit ** is advisory only. ** ** ^The return value from sqlite3_soft_heap_limit64() is the size of ** the soft heap limit prior to the call. ^If the argument N is negative ** then no change is made to the soft heap limit. Hence, the current ** size of the soft heap limit can be determined by invoking ** sqlite3_soft_heap_limit64() with a negative argument. ** ** ^If the argument N is zero then the soft heap limit is disabled. ** ** ^(The soft heap limit is not enforced in the current implementation ** if one or more of following conditions are true: ** **
    **
  • The soft heap limit is set to zero. **
  • Memory accounting is disabled using a combination of the ** [sqlite3_config]([SQLITE_CONFIG_MEMSTATUS],...) start-time option and ** the [SQLITE_DEFAULT_MEMSTATUS] compile-time option. **
  • An alternative page cache implementation is specified using ** [sqlite3_config]([SQLITE_CONFIG_PCACHE],...). **
  • The page cache allocates from its own memory pool supplied ** by [sqlite3_config]([SQLITE_CONFIG_PAGECACHE],...) rather than ** from the heap. **
)^ ** ** Beginning with SQLite version 3.7.3, the soft heap limit is enforced ** regardless of whether or not the [SQLITE_ENABLE_MEMORY_MANAGEMENT] ** compile-time option is invoked. With [SQLITE_ENABLE_MEMORY_MANAGEMENT], ** the soft heap limit is enforced on every memory allocation. Without ** [SQLITE_ENABLE_MEMORY_MANAGEMENT], the soft heap limit is only enforced ** when memory is allocated by the page cache. Testing suggests that because ** the page cache is the predominate memory user in SQLite, most ** applications will achieve adequate soft heap limit enforcement without ** the use of [SQLITE_ENABLE_MEMORY_MANAGEMENT]. ** ** The circumstances under which SQLite will enforce the soft heap limit may ** changes in future releases of SQLite. */ SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 N); /* ** CAPI3REF: Deprecated Soft Heap Limit Interface ** DEPRECATED ** ** This is a deprecated version of the [sqlite3_soft_heap_limit64()] ** interface. This routine is provided for historical compatibility ** only. All new applications should use the ** [sqlite3_soft_heap_limit64()] interface rather than this one. */ SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N); /* ** CAPI3REF: Extract Metadata About A Column Of A Table ** ** ^This routine returns metadata about a specific column of a specific ** database table accessible using the [database connection] handle ** passed as the first function argument. ** ** ^The column is identified by the second, third and fourth parameters to ** this function. ^The second parameter is either the name of the database ** (i.e. "main", "temp", or an attached database) containing the specified ** table or NULL. ^If it is NULL, then all attached databases are searched ** for the table using the same algorithm used by the database engine to ** resolve unqualified table references. ** ** ^The third and fourth parameters to this function are the table and column ** name of the desired column, respectively. Neither of these parameters ** may be NULL. ** ** ^Metadata is returned by writing to the memory locations passed as the 5th ** and subsequent parameters to this function. ^Any of these arguments may be ** NULL, in which case the corresponding element of metadata is omitted. ** ** ^(
** **
Parameter Output
Type
Description ** **
5th const char* Data type **
6th const char* Name of default collation sequence **
7th int True if column has a NOT NULL constraint **
8th int True if column is part of the PRIMARY KEY **
9th int True if column is [AUTOINCREMENT] **
**
)^ ** ** ^The memory pointed to by the character pointers returned for the ** declaration type and collation sequence is valid only until the next ** call to any SQLite API function. ** ** ^If the specified table is actually a view, an [error code] is returned. ** ** ^If the specified column is "rowid", "oid" or "_rowid_" and an ** [INTEGER PRIMARY KEY] column has been explicitly declared, then the output ** parameters are set for the explicitly declared column. ^(If there is no ** explicitly declared [INTEGER PRIMARY KEY] column, then the output ** parameters are set as follows: ** **
**     data type: "INTEGER"
**     collation sequence: "BINARY"
**     not null: 0
**     primary key: 1
**     auto increment: 0
** 
)^ ** ** ^(This function may load one or more schemas from database files. If an ** error occurs during this process, or if the requested table or column ** cannot be found, an [error code] is returned and an error message left ** in the [database connection] (to be retrieved using sqlite3_errmsg()).)^ ** ** ^This API is only available if the library was compiled with the ** [SQLITE_ENABLE_COLUMN_METADATA] C-preprocessor symbol defined. */ SQLITE_API int sqlite3_table_column_metadata( sqlite3 *db, /* Connection handle */ const char *zDbName, /* Database name or NULL */ const char *zTableName, /* Table name */ const char *zColumnName, /* Column name */ char const **pzDataType, /* OUTPUT: Declared data type */ char const **pzCollSeq, /* OUTPUT: Collation sequence name */ int *pNotNull, /* OUTPUT: True if NOT NULL constraint exists */ int *pPrimaryKey, /* OUTPUT: True if column part of PK */ int *pAutoinc /* OUTPUT: True if column is auto-increment */ ); /* ** CAPI3REF: Load An Extension ** ** ^This interface loads an SQLite extension library from the named file. ** ** ^The sqlite3_load_extension() interface attempts to load an ** SQLite extension library contained in the file zFile. ** ** ^The entry point is zProc. ** ^zProc may be 0, in which case the name of the entry point ** defaults to "sqlite3_extension_init". ** ^The sqlite3_load_extension() interface returns ** [SQLITE_OK] on success and [SQLITE_ERROR] if something goes wrong. ** ^If an error occurs and pzErrMsg is not 0, then the ** [sqlite3_load_extension()] interface shall attempt to ** fill *pzErrMsg with error message text stored in memory ** obtained from [sqlite3_malloc()]. The calling function ** should free this memory by calling [sqlite3_free()]. ** ** ^Extension loading must be enabled using ** [sqlite3_enable_load_extension()] prior to calling this API, ** otherwise an error will be returned. ** ** See also the [load_extension() SQL function]. */ SQLITE_API int sqlite3_load_extension( sqlite3 *db, /* Load the extension into this database connection */ const char *zFile, /* Name of the shared library containing extension */ const char *zProc, /* Entry point. Derived from zFile if 0 */ char **pzErrMsg /* Put error message here if not 0 */ ); /* ** CAPI3REF: Enable Or Disable Extension Loading ** ** ^So as not to open security holes in older applications that are ** unprepared to deal with extension loading, and as a means of disabling ** extension loading while evaluating user-entered SQL, the following API ** is provided to turn the [sqlite3_load_extension()] mechanism on and off. ** ** ^Extension loading is off by default. See ticket #1863. ** ^Call the sqlite3_enable_load_extension() routine with onoff==1 ** to turn extension loading on and call it with onoff==0 to turn ** it back off again. */ SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff); /* ** CAPI3REF: Automatically Load Statically Linked Extensions ** ** ^This interface causes the xEntryPoint() function to be invoked for ** each new [database connection] that is created. The idea here is that ** xEntryPoint() is the entry point for a statically linked SQLite extension ** that is to be automatically loaded into all new database connections. ** ** ^(Even though the function prototype shows that xEntryPoint() takes ** no arguments and returns void, SQLite invokes xEntryPoint() with three ** arguments and expects and integer result as if the signature of the ** entry point where as follows: ** **
**    int xEntryPoint(
**      sqlite3 *db,
**      const char **pzErrMsg,
**      const struct sqlite3_api_routines *pThunk
**    );
** 
)^ ** ** If the xEntryPoint routine encounters an error, it should make *pzErrMsg ** point to an appropriate error message (obtained from [sqlite3_mprintf()]) ** and return an appropriate [error code]. ^SQLite ensures that *pzErrMsg ** is NULL before calling the xEntryPoint(). ^SQLite will invoke ** [sqlite3_free()] on *pzErrMsg after xEntryPoint() returns. ^If any ** xEntryPoint() returns an error, the [sqlite3_open()], [sqlite3_open16()], ** or [sqlite3_open_v2()] call that provoked the xEntryPoint() will fail. ** ** ^Calling sqlite3_auto_extension(X) with an entry point X that is already ** on the list of automatic extensions is a harmless no-op. ^No entry point ** will be called more than once for each database connection that is opened. ** ** See also: [sqlite3_reset_auto_extension()]. */ SQLITE_API int sqlite3_auto_extension(void (*xEntryPoint)(void)); /* ** CAPI3REF: Reset Automatic Extension Loading ** ** ^This interface disables all automatic extensions previously ** registered using [sqlite3_auto_extension()]. */ SQLITE_API void sqlite3_reset_auto_extension(void); /* ** The interface to the virtual-table mechanism is currently considered ** to be experimental. The interface might change in incompatible ways. ** If this is a problem for you, do not use the interface at this time. ** ** When the virtual-table mechanism stabilizes, we will declare the ** interface fixed, support it indefinitely, and remove this comment. */ /* ** Structures used by the virtual table interface */ typedef struct sqlite3_vtab sqlite3_vtab; typedef struct sqlite3_index_info sqlite3_index_info; typedef struct sqlite3_vtab_cursor sqlite3_vtab_cursor; typedef struct sqlite3_module sqlite3_module; /* ** CAPI3REF: Virtual Table Object ** KEYWORDS: sqlite3_module {virtual table module} ** ** This structure, sometimes called a "virtual table module", ** defines the implementation of a [virtual tables]. ** This structure consists mostly of methods for the module. ** ** ^A virtual table module is created by filling in a persistent ** instance of this structure and passing a pointer to that instance ** to [sqlite3_create_module()] or [sqlite3_create_module_v2()]. ** ^The registration remains valid until it is replaced by a different ** module or until the [database connection] closes. The content ** of this structure must not change while it is registered with ** any database connection. */ struct sqlite3_module { int iVersion; int (*xCreate)(sqlite3*, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVTab, char**); int (*xConnect)(sqlite3*, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVTab, char**); int (*xBestIndex)(sqlite3_vtab *pVTab, sqlite3_index_info*); int (*xDisconnect)(sqlite3_vtab *pVTab); int (*xDestroy)(sqlite3_vtab *pVTab); int (*xOpen)(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor); int (*xClose)(sqlite3_vtab_cursor*); int (*xFilter)(sqlite3_vtab_cursor*, int idxNum, const char *idxStr, int argc, sqlite3_value **argv); int (*xNext)(sqlite3_vtab_cursor*); int (*xEof)(sqlite3_vtab_cursor*); int (*xColumn)(sqlite3_vtab_cursor*, sqlite3_context*, int); int (*xRowid)(sqlite3_vtab_cursor*, sqlite3_int64 *pRowid); int (*xUpdate)(sqlite3_vtab *, int, sqlite3_value **, sqlite3_int64 *); int (*xBegin)(sqlite3_vtab *pVTab); int (*xSync)(sqlite3_vtab *pVTab); int (*xCommit)(sqlite3_vtab *pVTab); int (*xRollback)(sqlite3_vtab *pVTab); int (*xFindFunction)(sqlite3_vtab *pVtab, int nArg, const char *zName, void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), void **ppArg); int (*xRename)(sqlite3_vtab *pVtab, const char *zNew); /* The methods above are in version 1 of the sqlite_module object. Those ** below are for version 2 and greater. */ int (*xSavepoint)(sqlite3_vtab *pVTab, int); int (*xRelease)(sqlite3_vtab *pVTab, int); int (*xRollbackTo)(sqlite3_vtab *pVTab, int); }; /* ** CAPI3REF: Virtual Table Indexing Information ** KEYWORDS: sqlite3_index_info ** ** The sqlite3_index_info structure and its substructures is used as part ** of the [virtual table] interface to ** pass information into and receive the reply from the [xBestIndex] ** method of a [virtual table module]. The fields under **Inputs** are the ** inputs to xBestIndex and are read-only. xBestIndex inserts its ** results into the **Outputs** fields. ** ** ^(The aConstraint[] array records WHERE clause constraints of the form: ** **
column OP expr
** ** where OP is =, <, <=, >, or >=.)^ ^(The particular operator is ** stored in aConstraint[].op using one of the ** [SQLITE_INDEX_CONSTRAINT_EQ | SQLITE_INDEX_CONSTRAINT_ values].)^ ** ^(The index of the column is stored in ** aConstraint[].iColumn.)^ ^(aConstraint[].usable is TRUE if the ** expr on the right-hand side can be evaluated (and thus the constraint ** is usable) and false if it cannot.)^ ** ** ^The optimizer automatically inverts terms of the form "expr OP column" ** and makes other simplifications to the WHERE clause in an attempt to ** get as many WHERE clause terms into the form shown above as possible. ** ^The aConstraint[] array only reports WHERE clause terms that are ** relevant to the particular virtual table being queried. ** ** ^Information about the ORDER BY clause is stored in aOrderBy[]. ** ^Each term of aOrderBy records a column of the ORDER BY clause. ** ** The [xBestIndex] method must fill aConstraintUsage[] with information ** about what parameters to pass to xFilter. ^If argvIndex>0 then ** the right-hand side of the corresponding aConstraint[] is evaluated ** and becomes the argvIndex-th entry in argv. ^(If aConstraintUsage[].omit ** is true, then the constraint is assumed to be fully handled by the ** virtual table and is not checked again by SQLite.)^ ** ** ^The idxNum and idxPtr values are recorded and passed into the ** [xFilter] method. ** ^[sqlite3_free()] is used to free idxPtr if and only if ** needToFreeIdxPtr is true. ** ** ^The orderByConsumed means that output from [xFilter]/[xNext] will occur in ** the correct order to satisfy the ORDER BY clause so that no separate ** sorting step is required. ** ** ^The estimatedCost value is an estimate of the cost of doing the ** particular lookup. A full scan of a table with N entries should have ** a cost of N. A binary search of a table of N entries should have a ** cost of approximately log(N). */ struct sqlite3_index_info { /* Inputs */ int nConstraint; /* Number of entries in aConstraint */ struct sqlite3_index_constraint { int iColumn; /* Column on left-hand side of constraint */ unsigned char op; /* Constraint operator */ unsigned char usable; /* True if this constraint is usable */ int iTermOffset; /* Used internally - xBestIndex should ignore */ } *aConstraint; /* Table of WHERE clause constraints */ int nOrderBy; /* Number of terms in the ORDER BY clause */ struct sqlite3_index_orderby { int iColumn; /* Column number */ unsigned char desc; /* True for DESC. False for ASC. */ } *aOrderBy; /* The ORDER BY clause */ /* Outputs */ struct sqlite3_index_constraint_usage { int argvIndex; /* if >0, constraint is part of argv to xFilter */ unsigned char omit; /* Do not code a test for this constraint */ } *aConstraintUsage; int idxNum; /* Number used to identify the index */ char *idxStr; /* String, possibly obtained from sqlite3_malloc */ int needToFreeIdxStr; /* Free idxStr using sqlite3_free() if true */ int orderByConsumed; /* True if output is already ordered */ double estimatedCost; /* Estimated cost of using this index */ }; /* ** CAPI3REF: Virtual Table Constraint Operator Codes ** ** These macros defined the allowed values for the ** [sqlite3_index_info].aConstraint[].op field. Each value represents ** an operator that is part of a constraint term in the wHERE clause of ** a query that uses a [virtual table]. */ #define SQLITE_INDEX_CONSTRAINT_EQ 2 #define SQLITE_INDEX_CONSTRAINT_GT 4 #define SQLITE_INDEX_CONSTRAINT_LE 8 #define SQLITE_INDEX_CONSTRAINT_LT 16 #define SQLITE_INDEX_CONSTRAINT_GE 32 #define SQLITE_INDEX_CONSTRAINT_MATCH 64 /* ** CAPI3REF: Register A Virtual Table Implementation ** ** ^These routines are used to register a new [virtual table module] name. ** ^Module names must be registered before ** creating a new [virtual table] using the module and before using a ** preexisting [virtual table] for the module. ** ** ^The module name is registered on the [database connection] specified ** by the first parameter. ^The name of the module is given by the ** second parameter. ^The third parameter is a pointer to ** the implementation of the [virtual table module]. ^The fourth ** parameter is an arbitrary client data pointer that is passed through ** into the [xCreate] and [xConnect] methods of the virtual table module ** when a new virtual table is be being created or reinitialized. ** ** ^The sqlite3_create_module_v2() interface has a fifth parameter which ** is a pointer to a destructor for the pClientData. ^SQLite will ** invoke the destructor function (if it is not NULL) when SQLite ** no longer needs the pClientData pointer. ^The destructor will also ** be invoked if the call to sqlite3_create_module_v2() fails. ** ^The sqlite3_create_module() ** interface is equivalent to sqlite3_create_module_v2() with a NULL ** destructor. */ SQLITE_API int sqlite3_create_module( sqlite3 *db, /* SQLite connection to register module with */ const char *zName, /* Name of the module */ const sqlite3_module *p, /* Methods for the module */ void *pClientData /* Client data for xCreate/xConnect */ ); SQLITE_API int sqlite3_create_module_v2( sqlite3 *db, /* SQLite connection to register module with */ const char *zName, /* Name of the module */ const sqlite3_module *p, /* Methods for the module */ void *pClientData, /* Client data for xCreate/xConnect */ void(*xDestroy)(void*) /* Module destructor function */ ); /* ** CAPI3REF: Virtual Table Instance Object ** KEYWORDS: sqlite3_vtab ** ** Every [virtual table module] implementation uses a subclass ** of this object to describe a particular instance ** of the [virtual table]. Each subclass will ** be tailored to the specific needs of the module implementation. ** The purpose of this superclass is to define certain fields that are ** common to all module implementations. ** ** ^Virtual tables methods can set an error message by assigning a ** string obtained from [sqlite3_mprintf()] to zErrMsg. The method should ** take care that any prior string is freed by a call to [sqlite3_free()] ** prior to assigning a new string to zErrMsg. ^After the error message ** is delivered up to the client application, the string will be automatically ** freed by sqlite3_free() and the zErrMsg field will be zeroed. */ struct sqlite3_vtab { const sqlite3_module *pModule; /* The module for this virtual table */ int nRef; /* NO LONGER USED */ char *zErrMsg; /* Error message from sqlite3_mprintf() */ /* Virtual table implementations will typically add additional fields */ }; /* ** CAPI3REF: Virtual Table Cursor Object ** KEYWORDS: sqlite3_vtab_cursor {virtual table cursor} ** ** Every [virtual table module] implementation uses a subclass of the ** following structure to describe cursors that point into the ** [virtual table] and are used ** to loop through the virtual table. Cursors are created using the ** [sqlite3_module.xOpen | xOpen] method of the module and are destroyed ** by the [sqlite3_module.xClose | xClose] method. Cursors are used ** by the [xFilter], [xNext], [xEof], [xColumn], and [xRowid] methods ** of the module. Each module implementation will define ** the content of a cursor structure to suit its own needs. ** ** This superclass exists in order to define fields of the cursor that ** are common to all implementations. */ struct sqlite3_vtab_cursor { sqlite3_vtab *pVtab; /* Virtual table of this cursor */ /* Virtual table implementations will typically add additional fields */ }; /* ** CAPI3REF: Declare The Schema Of A Virtual Table ** ** ^The [xCreate] and [xConnect] methods of a ** [virtual table module] call this interface ** to declare the format (the names and datatypes of the columns) of ** the virtual tables they implement. */ SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL); /* ** CAPI3REF: Overload A Function For A Virtual Table ** ** ^(Virtual tables can provide alternative implementations of functions ** using the [xFindFunction] method of the [virtual table module]. ** But global versions of those functions ** must exist in order to be overloaded.)^ ** ** ^(This API makes sure a global version of a function with a particular ** name and number of parameters exists. If no such function exists ** before this API is called, a new function is created.)^ ^The implementation ** of the new function always causes an exception to be thrown. So ** the new function is not good for anything by itself. Its only ** purpose is to be a placeholder function that can be overloaded ** by a [virtual table]. */ SQLITE_API int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg); /* ** The interface to the virtual-table mechanism defined above (back up ** to a comment remarkably similar to this one) is currently considered ** to be experimental. The interface might change in incompatible ways. ** If this is a problem for you, do not use the interface at this time. ** ** When the virtual-table mechanism stabilizes, we will declare the ** interface fixed, support it indefinitely, and remove this comment. */ /* ** CAPI3REF: A Handle To An Open BLOB ** KEYWORDS: {BLOB handle} {BLOB handles} ** ** An instance of this object represents an open BLOB on which ** [sqlite3_blob_open | incremental BLOB I/O] can be performed. ** ^Objects of this type are created by [sqlite3_blob_open()] ** and destroyed by [sqlite3_blob_close()]. ** ^The [sqlite3_blob_read()] and [sqlite3_blob_write()] interfaces ** can be used to read or write small subsections of the BLOB. ** ^The [sqlite3_blob_bytes()] interface returns the size of the BLOB in bytes. */ typedef struct sqlite3_blob sqlite3_blob; /* ** CAPI3REF: Open A BLOB For Incremental I/O ** ** ^(This interfaces opens a [BLOB handle | handle] to the BLOB located ** in row iRow, column zColumn, table zTable in database zDb; ** in other words, the same BLOB that would be selected by: ** **
**     SELECT zColumn FROM zDb.zTable WHERE [rowid] = iRow;
** 
)^ ** ** ^If the flags parameter is non-zero, then the BLOB is opened for read ** and write access. ^If it is zero, the BLOB is opened for read access. ** ^It is not possible to open a column that is part of an index or primary ** key for writing. ^If [foreign key constraints] are enabled, it is ** not possible to open a column that is part of a [child key] for writing. ** ** ^Note that the database name is not the filename that contains ** the database but rather the symbolic name of the database that ** appears after the AS keyword when the database is connected using [ATTACH]. ** ^For the main database file, the database name is "main". ** ^For TEMP tables, the database name is "temp". ** ** ^(On success, [SQLITE_OK] is returned and the new [BLOB handle] is written ** to *ppBlob. Otherwise an [error code] is returned and *ppBlob is set ** to be a null pointer.)^ ** ^This function sets the [database connection] error code and message ** accessible via [sqlite3_errcode()] and [sqlite3_errmsg()] and related ** functions. ^Note that the *ppBlob variable is always initialized in a ** way that makes it safe to invoke [sqlite3_blob_close()] on *ppBlob ** regardless of the success or failure of this routine. ** ** ^(If the row that a BLOB handle points to is modified by an ** [UPDATE], [DELETE], or by [ON CONFLICT] side-effects ** then the BLOB handle is marked as "expired". ** This is true if any column of the row is changed, even a column ** other than the one the BLOB handle is open on.)^ ** ^Calls to [sqlite3_blob_read()] and [sqlite3_blob_write()] for ** an expired BLOB handle fail with a return code of [SQLITE_ABORT]. ** ^(Changes written into a BLOB prior to the BLOB expiring are not ** rolled back by the expiration of the BLOB. Such changes will eventually ** commit if the transaction continues to completion.)^ ** ** ^Use the [sqlite3_blob_bytes()] interface to determine the size of ** the opened blob. ^The size of a blob may not be changed by this ** interface. Use the [UPDATE] SQL command to change the size of a ** blob. ** ** ^The [sqlite3_bind_zeroblob()] and [sqlite3_result_zeroblob()] interfaces ** and the built-in [zeroblob] SQL function can be used, if desired, ** to create an empty, zero-filled blob in which to read or write using ** this interface. ** ** To avoid a resource leak, every open [BLOB handle] should eventually ** be released by a call to [sqlite3_blob_close()]. */ SQLITE_API int sqlite3_blob_open( sqlite3*, const char *zDb, const char *zTable, const char *zColumn, sqlite3_int64 iRow, int flags, sqlite3_blob **ppBlob ); /* ** CAPI3REF: Move a BLOB Handle to a New Row ** ** ^This function is used to move an existing blob handle so that it points ** to a different row of the same database table. ^The new row is identified ** by the rowid value passed as the second argument. Only the row can be ** changed. ^The database, table and column on which the blob handle is open ** remain the same. Moving an existing blob handle to a new row can be ** faster than closing the existing handle and opening a new one. ** ** ^(The new row must meet the same criteria as for [sqlite3_blob_open()] - ** it must exist and there must be either a blob or text value stored in ** the nominated column.)^ ^If the new row is not present in the table, or if ** it does not contain a blob or text value, or if another error occurs, an ** SQLite error code is returned and the blob handle is considered aborted. ** ^All subsequent calls to [sqlite3_blob_read()], [sqlite3_blob_write()] or ** [sqlite3_blob_reopen()] on an aborted blob handle immediately return ** SQLITE_ABORT. ^Calling [sqlite3_blob_bytes()] on an aborted blob handle ** always returns zero. ** ** ^This function sets the database handle error code and message. */ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64); /* ** CAPI3REF: Close A BLOB Handle ** ** ^Closes an open [BLOB handle]. ** ** ^Closing a BLOB shall cause the current transaction to commit ** if there are no other BLOBs, no pending prepared statements, and the ** database connection is in [autocommit mode]. ** ^If any writes were made to the BLOB, they might be held in cache ** until the close operation if they will fit. ** ** ^(Closing the BLOB often forces the changes ** out to disk and so if any I/O errors occur, they will likely occur ** at the time when the BLOB is closed. Any errors that occur during ** closing are reported as a non-zero return value.)^ ** ** ^(The BLOB is closed unconditionally. Even if this routine returns ** an error code, the BLOB is still closed.)^ ** ** ^Calling this routine with a null pointer (such as would be returned ** by a failed call to [sqlite3_blob_open()]) is a harmless no-op. */ SQLITE_API int sqlite3_blob_close(sqlite3_blob *); /* ** CAPI3REF: Return The Size Of An Open BLOB ** ** ^Returns the size in bytes of the BLOB accessible via the ** successfully opened [BLOB handle] in its only argument. ^The ** incremental blob I/O routines can only read or overwriting existing ** blob content; they cannot change the size of a blob. ** ** This routine only works on a [BLOB handle] which has been created ** by a prior successful call to [sqlite3_blob_open()] and which has not ** been closed by [sqlite3_blob_close()]. Passing any other pointer in ** to this routine results in undefined and probably undesirable behavior. */ SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *); /* ** CAPI3REF: Read Data From A BLOB Incrementally ** ** ^(This function is used to read data from an open [BLOB handle] into a ** caller-supplied buffer. N bytes of data are copied into buffer Z ** from the open BLOB, starting at offset iOffset.)^ ** ** ^If offset iOffset is less than N bytes from the end of the BLOB, ** [SQLITE_ERROR] is returned and no data is read. ^If N or iOffset is ** less than zero, [SQLITE_ERROR] is returned and no data is read. ** ^The size of the blob (and hence the maximum value of N+iOffset) ** can be determined using the [sqlite3_blob_bytes()] interface. ** ** ^An attempt to read from an expired [BLOB handle] fails with an ** error code of [SQLITE_ABORT]. ** ** ^(On success, sqlite3_blob_read() returns SQLITE_OK. ** Otherwise, an [error code] or an [extended error code] is returned.)^ ** ** This routine only works on a [BLOB handle] which has been created ** by a prior successful call to [sqlite3_blob_open()] and which has not ** been closed by [sqlite3_blob_close()]. Passing any other pointer in ** to this routine results in undefined and probably undesirable behavior. ** ** See also: [sqlite3_blob_write()]. */ SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset); /* ** CAPI3REF: Write Data Into A BLOB Incrementally ** ** ^This function is used to write data into an open [BLOB handle] from a ** caller-supplied buffer. ^N bytes of data are copied from the buffer Z ** into the open BLOB, starting at offset iOffset. ** ** ^If the [BLOB handle] passed as the first argument was not opened for ** writing (the flags parameter to [sqlite3_blob_open()] was zero), ** this function returns [SQLITE_READONLY]. ** ** ^This function may only modify the contents of the BLOB; it is ** not possible to increase the size of a BLOB using this API. ** ^If offset iOffset is less than N bytes from the end of the BLOB, ** [SQLITE_ERROR] is returned and no data is written. ^If N is ** less than zero [SQLITE_ERROR] is returned and no data is written. ** The size of the BLOB (and hence the maximum value of N+iOffset) ** can be determined using the [sqlite3_blob_bytes()] interface. ** ** ^An attempt to write to an expired [BLOB handle] fails with an ** error code of [SQLITE_ABORT]. ^Writes to the BLOB that occurred ** before the [BLOB handle] expired are not rolled back by the ** expiration of the handle, though of course those changes might ** have been overwritten by the statement that expired the BLOB handle ** or by other independent statements. ** ** ^(On success, sqlite3_blob_write() returns SQLITE_OK. ** Otherwise, an [error code] or an [extended error code] is returned.)^ ** ** This routine only works on a [BLOB handle] which has been created ** by a prior successful call to [sqlite3_blob_open()] and which has not ** been closed by [sqlite3_blob_close()]. Passing any other pointer in ** to this routine results in undefined and probably undesirable behavior. ** ** See also: [sqlite3_blob_read()]. */ SQLITE_API int sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset); /* ** CAPI3REF: Virtual File System Objects ** ** A virtual filesystem (VFS) is an [sqlite3_vfs] object ** that SQLite uses to interact ** with the underlying operating system. Most SQLite builds come with a ** single default VFS that is appropriate for the host computer. ** New VFSes can be registered and existing VFSes can be unregistered. ** The following interfaces are provided. ** ** ^The sqlite3_vfs_find() interface returns a pointer to a VFS given its name. ** ^Names are case sensitive. ** ^Names are zero-terminated UTF-8 strings. ** ^If there is no match, a NULL pointer is returned. ** ^If zVfsName is NULL then the default VFS is returned. ** ** ^New VFSes are registered with sqlite3_vfs_register(). ** ^Each new VFS becomes the default VFS if the makeDflt flag is set. ** ^The same VFS can be registered multiple times without injury. ** ^To make an existing VFS into the default VFS, register it again ** with the makeDflt flag set. If two different VFSes with the ** same name are registered, the behavior is undefined. If a ** VFS is registered with a name that is NULL or an empty string, ** then the behavior is undefined. ** ** ^Unregister a VFS with the sqlite3_vfs_unregister() interface. ** ^(If the default VFS is unregistered, another VFS is chosen as ** the default. The choice for the new VFS is arbitrary.)^ */ SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfsName); SQLITE_API int sqlite3_vfs_register(sqlite3_vfs*, int makeDflt); SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*); /* ** CAPI3REF: Mutexes ** ** The SQLite core uses these routines for thread ** synchronization. Though they are intended for internal ** use by SQLite, code that links against SQLite is ** permitted to use any of these routines. ** ** The SQLite source code contains multiple implementations ** of these mutex routines. An appropriate implementation ** is selected automatically at compile-time. ^(The following ** implementations are available in the SQLite core: ** **
    **
  • SQLITE_MUTEX_OS2 **
  • SQLITE_MUTEX_PTHREAD **
  • SQLITE_MUTEX_W32 **
  • SQLITE_MUTEX_NOOP **
)^ ** ** ^The SQLITE_MUTEX_NOOP implementation is a set of routines ** that does no real locking and is appropriate for use in ** a single-threaded application. ^The SQLITE_MUTEX_OS2, ** SQLITE_MUTEX_PTHREAD, and SQLITE_MUTEX_W32 implementations ** are appropriate for use on OS/2, Unix, and Windows. ** ** ^(If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor ** macro defined (with "-DSQLITE_MUTEX_APPDEF=1"), then no mutex ** implementation is included with the library. In this case the ** application must supply a custom mutex implementation using the ** [SQLITE_CONFIG_MUTEX] option of the sqlite3_config() function ** before calling sqlite3_initialize() or any other public sqlite3_ ** function that calls sqlite3_initialize().)^ ** ** ^The sqlite3_mutex_alloc() routine allocates a new ** mutex and returns a pointer to it. ^If it returns NULL ** that means that a mutex could not be allocated. ^SQLite ** will unwind its stack and return an error. ^(The argument ** to sqlite3_mutex_alloc() is one of these integer constants: ** **
    **
  • SQLITE_MUTEX_FAST **
  • SQLITE_MUTEX_RECURSIVE **
  • SQLITE_MUTEX_STATIC_MASTER **
  • SQLITE_MUTEX_STATIC_MEM **
  • SQLITE_MUTEX_STATIC_MEM2 **
  • SQLITE_MUTEX_STATIC_PRNG **
  • SQLITE_MUTEX_STATIC_LRU **
  • SQLITE_MUTEX_STATIC_LRU2 **
)^ ** ** ^The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) ** cause sqlite3_mutex_alloc() to create ** a new mutex. ^The new mutex is recursive when SQLITE_MUTEX_RECURSIVE ** is used but not necessarily so when SQLITE_MUTEX_FAST is used. ** The mutex implementation does not need to make a distinction ** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does ** not want to. ^SQLite will only request a recursive mutex in ** cases where it really needs one. ^If a faster non-recursive mutex ** implementation is available on the host platform, the mutex subsystem ** might return such a mutex in response to SQLITE_MUTEX_FAST. ** ** ^The other allowed parameters to sqlite3_mutex_alloc() (anything other ** than SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) each return ** a pointer to a static preexisting mutex. ^Six static mutexes are ** used by the current version of SQLite. Future versions of SQLite ** may add additional static mutexes. Static mutexes are for internal ** use by SQLite only. Applications that use SQLite mutexes should ** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or ** SQLITE_MUTEX_RECURSIVE. ** ** ^Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST ** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc() ** returns a different mutex on every call. ^But for the static ** mutex types, the same mutex is returned on every call that has ** the same type number. ** ** ^The sqlite3_mutex_free() routine deallocates a previously ** allocated dynamic mutex. ^SQLite is careful to deallocate every ** dynamic mutex that it allocates. The dynamic mutexes must not be in ** use when they are deallocated. Attempting to deallocate a static ** mutex results in undefined behavior. ^SQLite never deallocates ** a static mutex. ** ** ^The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt ** to enter a mutex. ^If another thread is already within the mutex, ** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return ** SQLITE_BUSY. ^The sqlite3_mutex_try() interface returns [SQLITE_OK] ** upon successful entry. ^(Mutexes created using ** SQLITE_MUTEX_RECURSIVE can be entered multiple times by the same thread. ** In such cases the, ** mutex must be exited an equal number of times before another thread ** can enter.)^ ^(If the same thread tries to enter any other ** kind of mutex more than once, the behavior is undefined. ** SQLite will never exhibit ** such behavior in its own use of mutexes.)^ ** ** ^(Some systems (for example, Windows 95) do not support the operation ** implemented by sqlite3_mutex_try(). On those systems, sqlite3_mutex_try() ** will always return SQLITE_BUSY. The SQLite core only ever uses ** sqlite3_mutex_try() as an optimization so this is acceptable behavior.)^ ** ** ^The sqlite3_mutex_leave() routine exits a mutex that was ** previously entered by the same thread. ^(The behavior ** is undefined if the mutex is not currently entered by the ** calling thread or is not currently allocated. SQLite will ** never do either.)^ ** ** ^If the argument to sqlite3_mutex_enter(), sqlite3_mutex_try(), or ** sqlite3_mutex_leave() is a NULL pointer, then all three routines ** behave as no-ops. ** ** See also: [sqlite3_mutex_held()] and [sqlite3_mutex_notheld()]. */ SQLITE_API sqlite3_mutex *sqlite3_mutex_alloc(int); SQLITE_API void sqlite3_mutex_free(sqlite3_mutex*); SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex*); SQLITE_API int sqlite3_mutex_try(sqlite3_mutex*); SQLITE_API void sqlite3_mutex_leave(sqlite3_mutex*); /* ** CAPI3REF: Mutex Methods Object ** ** An instance of this structure defines the low-level routines ** used to allocate and use mutexes. ** ** Usually, the default mutex implementations provided by SQLite are ** sufficient, however the user has the option of substituting a custom ** implementation for specialized deployments or systems for which SQLite ** does not provide a suitable implementation. In this case, the user ** creates and populates an instance of this structure to pass ** to sqlite3_config() along with the [SQLITE_CONFIG_MUTEX] option. ** Additionally, an instance of this structure can be used as an ** output variable when querying the system for the current mutex ** implementation, using the [SQLITE_CONFIG_GETMUTEX] option. ** ** ^The xMutexInit method defined by this structure is invoked as ** part of system initialization by the sqlite3_initialize() function. ** ^The xMutexInit routine is called by SQLite exactly once for each ** effective call to [sqlite3_initialize()]. ** ** ^The xMutexEnd method defined by this structure is invoked as ** part of system shutdown by the sqlite3_shutdown() function. The ** implementation of this method is expected to release all outstanding ** resources obtained by the mutex methods implementation, especially ** those obtained by the xMutexInit method. ^The xMutexEnd() ** interface is invoked exactly once for each call to [sqlite3_shutdown()]. ** ** ^(The remaining seven methods defined by this structure (xMutexAlloc, ** xMutexFree, xMutexEnter, xMutexTry, xMutexLeave, xMutexHeld and ** xMutexNotheld) implement the following interfaces (respectively): ** **
    **
  • [sqlite3_mutex_alloc()]
  • **
  • [sqlite3_mutex_free()]
  • **
  • [sqlite3_mutex_enter()]
  • **
  • [sqlite3_mutex_try()]
  • **
  • [sqlite3_mutex_leave()]
  • **
  • [sqlite3_mutex_held()]
  • **
  • [sqlite3_mutex_notheld()]
  • **
)^ ** ** The only difference is that the public sqlite3_XXX functions enumerated ** above silently ignore any invocations that pass a NULL pointer instead ** of a valid mutex handle. The implementations of the methods defined ** by this structure are not required to handle this case, the results ** of passing a NULL pointer instead of a valid mutex handle are undefined ** (i.e. it is acceptable to provide an implementation that segfaults if ** it is passed a NULL pointer). ** ** The xMutexInit() method must be threadsafe. ^It must be harmless to ** invoke xMutexInit() multiple times within the same process and without ** intervening calls to xMutexEnd(). Second and subsequent calls to ** xMutexInit() must be no-ops. ** ** ^xMutexInit() must not use SQLite memory allocation ([sqlite3_malloc()] ** and its associates). ^Similarly, xMutexAlloc() must not use SQLite memory ** allocation for a static mutex. ^However xMutexAlloc() may use SQLite ** memory allocation for a fast or recursive mutex. ** ** ^SQLite will invoke the xMutexEnd() method when [sqlite3_shutdown()] is ** called, but only if the prior call to xMutexInit returned SQLITE_OK. ** If xMutexInit fails in any way, it is expected to clean up after itself ** prior to returning. */ typedef struct sqlite3_mutex_methods sqlite3_mutex_methods; struct sqlite3_mutex_methods { int (*xMutexInit)(void); int (*xMutexEnd)(void); sqlite3_mutex *(*xMutexAlloc)(int); void (*xMutexFree)(sqlite3_mutex *); void (*xMutexEnter)(sqlite3_mutex *); int (*xMutexTry)(sqlite3_mutex *); void (*xMutexLeave)(sqlite3_mutex *); int (*xMutexHeld)(sqlite3_mutex *); int (*xMutexNotheld)(sqlite3_mutex *); }; /* ** CAPI3REF: Mutex Verification Routines ** ** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routines ** are intended for use inside assert() statements. ^The SQLite core ** never uses these routines except inside an assert() and applications ** are advised to follow the lead of the core. ^The SQLite core only ** provides implementations for these routines when it is compiled ** with the SQLITE_DEBUG flag. ^External mutex implementations ** are only required to provide these routines if SQLITE_DEBUG is ** defined and if NDEBUG is not defined. ** ** ^These routines should return true if the mutex in their argument ** is held or not held, respectively, by the calling thread. ** ** ^The implementation is not required to provided versions of these ** routines that actually work. If the implementation does not provide working ** versions of these routines, it should at least provide stubs that always ** return true so that one does not get spurious assertion failures. ** ** ^If the argument to sqlite3_mutex_held() is a NULL pointer then ** the routine should return 1. This seems counter-intuitive since ** clearly the mutex cannot be held if it does not exist. But ** the reason the mutex does not exist is because the build is not ** using mutexes. And we do not want the assert() containing the ** call to sqlite3_mutex_held() to fail, so a non-zero return is ** the appropriate thing to do. ^The sqlite3_mutex_notheld() ** interface should also return 1 when given a NULL pointer. */ #ifndef NDEBUG SQLITE_API int sqlite3_mutex_held(sqlite3_mutex*); SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*); #endif /* ** CAPI3REF: Mutex Types ** ** The [sqlite3_mutex_alloc()] interface takes a single argument ** which is one of these integer constants. ** ** The set of static mutexes may change from one SQLite release to the ** next. Applications that override the built-in mutex logic must be ** prepared to accommodate additional static mutexes. */ #define SQLITE_MUTEX_FAST 0 #define SQLITE_MUTEX_RECURSIVE 1 #define SQLITE_MUTEX_STATIC_MASTER 2 #define SQLITE_MUTEX_STATIC_MEM 3 /* sqlite3_malloc() */ #define SQLITE_MUTEX_STATIC_MEM2 4 /* NOT USED */ #define SQLITE_MUTEX_STATIC_OPEN 4 /* sqlite3BtreeOpen() */ #define SQLITE_MUTEX_STATIC_PRNG 5 /* sqlite3_random() */ #define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */ #define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */ #define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */ /* ** CAPI3REF: Retrieve the mutex for a database connection ** ** ^This interface returns a pointer the [sqlite3_mutex] object that ** serializes access to the [database connection] given in the argument ** when the [threading mode] is Serialized. ** ^If the [threading mode] is Single-thread or Multi-thread then this ** routine returns a NULL pointer. */ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*); /* ** CAPI3REF: Low-Level Control Of Database Files ** ** ^The [sqlite3_file_control()] interface makes a direct call to the ** xFileControl method for the [sqlite3_io_methods] object associated ** with a particular database identified by the second argument. ^The ** name of the database is "main" for the main database or "temp" for the ** TEMP database, or the name that appears after the AS keyword for ** databases that are added using the [ATTACH] SQL command. ** ^A NULL pointer can be used in place of "main" to refer to the ** main database file. ** ^The third and fourth parameters to this routine ** are passed directly through to the second and third parameters of ** the xFileControl method. ^The return value of the xFileControl ** method becomes the return value of this routine. ** ** ^The SQLITE_FCNTL_FILE_POINTER value for the op parameter causes ** a pointer to the underlying [sqlite3_file] object to be written into ** the space pointed to by the 4th parameter. ^The SQLITE_FCNTL_FILE_POINTER ** case is a short-circuit path which does not actually invoke the ** underlying sqlite3_io_methods.xFileControl method. ** ** ^If the second parameter (zDbName) does not match the name of any ** open database file, then SQLITE_ERROR is returned. ^This error ** code is not remembered and will not be recalled by [sqlite3_errcode()] ** or [sqlite3_errmsg()]. The underlying xFileControl method might ** also return SQLITE_ERROR. There is no way to distinguish between ** an incorrect zDbName and an SQLITE_ERROR return from the underlying ** xFileControl method. ** ** See also: [SQLITE_FCNTL_LOCKSTATE] */ SQLITE_API int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*); /* ** CAPI3REF: Testing Interface ** ** ^The sqlite3_test_control() interface is used to read out internal ** state of SQLite and to inject faults into SQLite for testing ** purposes. ^The first parameter is an operation code that determines ** the number, meaning, and operation of all subsequent parameters. ** ** This interface is not for use by applications. It exists solely ** for verifying the correct operation of the SQLite library. Depending ** on how the SQLite library is compiled, this interface might not exist. ** ** The details of the operation codes, their meanings, the parameters ** they take, and what they do are all subject to change without notice. ** Unlike most of the SQLite API, this function is not guaranteed to ** operate consistently from one release to the next. */ SQLITE_API int sqlite3_test_control(int op, ...); /* ** CAPI3REF: Testing Interface Operation Codes ** ** These constants are the valid operation code parameters used ** as the first argument to [sqlite3_test_control()]. ** ** These parameters and their meanings are subject to change ** without notice. These values are for testing purposes only. ** Applications should not use any of these parameters or the ** [sqlite3_test_control()] interface. */ #define SQLITE_TESTCTRL_FIRST 5 #define SQLITE_TESTCTRL_PRNG_SAVE 5 #define SQLITE_TESTCTRL_PRNG_RESTORE 6 #define SQLITE_TESTCTRL_PRNG_RESET 7 #define SQLITE_TESTCTRL_BITVEC_TEST 8 #define SQLITE_TESTCTRL_FAULT_INSTALL 9 #define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10 #define SQLITE_TESTCTRL_PENDING_BYTE 11 #define SQLITE_TESTCTRL_ASSERT 12 #define SQLITE_TESTCTRL_ALWAYS 13 #define SQLITE_TESTCTRL_RESERVE 14 #define SQLITE_TESTCTRL_OPTIMIZATIONS 15 #define SQLITE_TESTCTRL_ISKEYWORD 16 #define SQLITE_TESTCTRL_PGHDRSZ 17 #define SQLITE_TESTCTRL_SCRATCHMALLOC 18 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 19 #define SQLITE_TESTCTRL_LAST 19 /* ** CAPI3REF: SQLite Runtime Status ** ** ^This interface is used to retrieve runtime status information ** about the performance of SQLite, and optionally to reset various ** highwater marks. ^The first argument is an integer code for ** the specific parameter to measure. ^(Recognized integer codes ** are of the form [status parameters | SQLITE_STATUS_...].)^ ** ^The current value of the parameter is returned into *pCurrent. ** ^The highest recorded value is returned in *pHighwater. ^If the ** resetFlag is true, then the highest record value is reset after ** *pHighwater is written. ^(Some parameters do not record the highest ** value. For those parameters ** nothing is written into *pHighwater and the resetFlag is ignored.)^ ** ^(Other parameters record only the highwater mark and not the current ** value. For these latter parameters nothing is written into *pCurrent.)^ ** ** ^The sqlite3_status() routine returns SQLITE_OK on success and a ** non-zero [error code] on failure. ** ** This routine is threadsafe but is not atomic. This routine can be ** called while other threads are running the same or different SQLite ** interfaces. However the values returned in *pCurrent and ** *pHighwater reflect the status of SQLite at different points in time ** and it is possible that another thread might change the parameter ** in between the times when *pCurrent and *pHighwater are written. ** ** See also: [sqlite3_db_status()] */ SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag); /* ** CAPI3REF: Status Parameters ** KEYWORDS: {status parameters} ** ** These integer constants designate various run-time status parameters ** that can be returned by [sqlite3_status()]. ** **
** [[SQLITE_STATUS_MEMORY_USED]] ^(
SQLITE_STATUS_MEMORY_USED
**
This parameter is the current amount of memory checked out ** using [sqlite3_malloc()], either directly or indirectly. The ** figure includes calls made to [sqlite3_malloc()] by the application ** and internal memory usage by the SQLite library. Scratch memory ** controlled by [SQLITE_CONFIG_SCRATCH] and auxiliary page-cache ** memory controlled by [SQLITE_CONFIG_PAGECACHE] is not included in ** this parameter. The amount returned is the sum of the allocation ** sizes as reported by the xSize method in [sqlite3_mem_methods].
)^ ** ** [[SQLITE_STATUS_MALLOC_SIZE]] ^(
SQLITE_STATUS_MALLOC_SIZE
**
This parameter records the largest memory allocation request ** handed to [sqlite3_malloc()] or [sqlite3_realloc()] (or their ** internal equivalents). Only the value returned in the ** *pHighwater parameter to [sqlite3_status()] is of interest. ** The value written into the *pCurrent parameter is undefined.
)^ ** ** [[SQLITE_STATUS_MALLOC_COUNT]] ^(
SQLITE_STATUS_MALLOC_COUNT
**
This parameter records the number of separate memory allocations ** currently checked out.
)^ ** ** [[SQLITE_STATUS_PAGECACHE_USED]] ^(
SQLITE_STATUS_PAGECACHE_USED
**
This parameter returns the number of pages used out of the ** [pagecache memory allocator] that was configured using ** [SQLITE_CONFIG_PAGECACHE]. The ** value returned is in pages, not in bytes.
)^ ** ** [[SQLITE_STATUS_PAGECACHE_OVERFLOW]] ** ^(
SQLITE_STATUS_PAGECACHE_OVERFLOW
**
This parameter returns the number of bytes of page cache ** allocation which could not be satisfied by the [SQLITE_CONFIG_PAGECACHE] ** buffer and where forced to overflow to [sqlite3_malloc()]. The ** returned value includes allocations that overflowed because they ** where too large (they were larger than the "sz" parameter to ** [SQLITE_CONFIG_PAGECACHE]) and allocations that overflowed because ** no space was left in the page cache.
)^ ** ** [[SQLITE_STATUS_PAGECACHE_SIZE]] ^(
SQLITE_STATUS_PAGECACHE_SIZE
**
This parameter records the largest memory allocation request ** handed to [pagecache memory allocator]. Only the value returned in the ** *pHighwater parameter to [sqlite3_status()] is of interest. ** The value written into the *pCurrent parameter is undefined.
)^ ** ** [[SQLITE_STATUS_SCRATCH_USED]] ^(
SQLITE_STATUS_SCRATCH_USED
**
This parameter returns the number of allocations used out of the ** [scratch memory allocator] configured using ** [SQLITE_CONFIG_SCRATCH]. The value returned is in allocations, not ** in bytes. Since a single thread may only have one scratch allocation ** outstanding at time, this parameter also reports the number of threads ** using scratch memory at the same time.
)^ ** ** [[SQLITE_STATUS_SCRATCH_OVERFLOW]] ^(
SQLITE_STATUS_SCRATCH_OVERFLOW
**
This parameter returns the number of bytes of scratch memory ** allocation which could not be satisfied by the [SQLITE_CONFIG_SCRATCH] ** buffer and where forced to overflow to [sqlite3_malloc()]. The values ** returned include overflows because the requested allocation was too ** larger (that is, because the requested allocation was larger than the ** "sz" parameter to [SQLITE_CONFIG_SCRATCH]) and because no scratch buffer ** slots were available. **
)^ ** ** [[SQLITE_STATUS_SCRATCH_SIZE]] ^(
SQLITE_STATUS_SCRATCH_SIZE
**
This parameter records the largest memory allocation request ** handed to [scratch memory allocator]. Only the value returned in the ** *pHighwater parameter to [sqlite3_status()] is of interest. ** The value written into the *pCurrent parameter is undefined.
)^ ** ** [[SQLITE_STATUS_PARSER_STACK]] ^(
SQLITE_STATUS_PARSER_STACK
**
This parameter records the deepest parser stack. It is only ** meaningful if SQLite is compiled with [YYTRACKMAXSTACKDEPTH].
)^ **
** ** New status parameters may be added from time to time. */ #define SQLITE_STATUS_MEMORY_USED 0 #define SQLITE_STATUS_PAGECACHE_USED 1 #define SQLITE_STATUS_PAGECACHE_OVERFLOW 2 #define SQLITE_STATUS_SCRATCH_USED 3 #define SQLITE_STATUS_SCRATCH_OVERFLOW 4 #define SQLITE_STATUS_MALLOC_SIZE 5 #define SQLITE_STATUS_PARSER_STACK 6 #define SQLITE_STATUS_PAGECACHE_SIZE 7 #define SQLITE_STATUS_SCRATCH_SIZE 8 #define SQLITE_STATUS_MALLOC_COUNT 9 /* ** CAPI3REF: Database Connection Status ** ** ^This interface is used to retrieve runtime status information ** about a single [database connection]. ^The first argument is the ** database connection object to be interrogated. ^The second argument ** is an integer constant, taken from the set of ** [SQLITE_DBSTATUS options], that ** determines the parameter to interrogate. The set of ** [SQLITE_DBSTATUS options] is likely ** to grow in future releases of SQLite. ** ** ^The current value of the requested parameter is written into *pCur ** and the highest instantaneous value is written into *pHiwtr. ^If ** the resetFlg is true, then the highest instantaneous value is ** reset back down to the current value. ** ** ^The sqlite3_db_status() routine returns SQLITE_OK on success and a ** non-zero [error code] on failure. ** ** See also: [sqlite3_status()] and [sqlite3_stmt_status()]. */ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); /* ** CAPI3REF: Status Parameters for database connections ** KEYWORDS: {SQLITE_DBSTATUS options} ** ** These constants are the available integer "verbs" that can be passed as ** the second argument to the [sqlite3_db_status()] interface. ** ** New verbs may be added in future releases of SQLite. Existing verbs ** might be discontinued. Applications should check the return code from ** [sqlite3_db_status()] to make sure that the call worked. ** The [sqlite3_db_status()] interface will return a non-zero error code ** if a discontinued or unsupported verb is invoked. ** **
** [[SQLITE_DBSTATUS_LOOKASIDE_USED]] ^(
SQLITE_DBSTATUS_LOOKASIDE_USED
**
This parameter returns the number of lookaside memory slots currently ** checked out.
)^ ** ** [[SQLITE_DBSTATUS_LOOKASIDE_HIT]] ^(
SQLITE_DBSTATUS_LOOKASIDE_HIT
**
This parameter returns the number malloc attempts that were ** satisfied using lookaside memory. Only the high-water value is meaningful; ** the current value is always zero.)^ ** ** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE]] ** ^(
SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE
**
This parameter returns the number malloc attempts that might have ** been satisfied using lookaside memory but failed due to the amount of ** memory requested being larger than the lookaside slot size. ** Only the high-water value is meaningful; ** the current value is always zero.)^ ** ** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL]] ** ^(
SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL
**
This parameter returns the number malloc attempts that might have ** been satisfied using lookaside memory but failed due to all lookaside ** memory already being in use. ** Only the high-water value is meaningful; ** the current value is always zero.)^ ** ** [[SQLITE_DBSTATUS_CACHE_USED]] ^(
SQLITE_DBSTATUS_CACHE_USED
**
This parameter returns the approximate number of of bytes of heap ** memory used by all pager caches associated with the database connection.)^ ** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0. ** ** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(
SQLITE_DBSTATUS_SCHEMA_USED
**
This parameter returns the approximate number of of bytes of heap ** memory used to store the schema for all databases associated ** with the connection - main, temp, and any [ATTACH]-ed databases.)^ ** ^The full amount of memory used by the schemas is reported, even if the ** schema memory is shared with other database connections due to ** [shared cache mode] being enabled. ** ^The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED is always 0. ** ** [[SQLITE_DBSTATUS_STMT_USED]] ^(
SQLITE_DBSTATUS_STMT_USED
**
This parameter returns the approximate number of of bytes of heap ** and lookaside memory used by all prepared statements associated with ** the database connection.)^ ** ^The highwater mark associated with SQLITE_DBSTATUS_STMT_USED is always 0. **
** ** [[SQLITE_DBSTATUS_CACHE_HIT]] ^(
SQLITE_DBSTATUS_CACHE_HIT
**
This parameter returns the number of pager cache hits that have ** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_HIT ** is always 0. **
** ** [[SQLITE_DBSTATUS_CACHE_MISS]] ^(
SQLITE_DBSTATUS_CACHE_MISS
**
This parameter returns the number of pager cache misses that have ** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_MISS ** is always 0. **
**
*/ #define SQLITE_DBSTATUS_LOOKASIDE_USED 0 #define SQLITE_DBSTATUS_CACHE_USED 1 #define SQLITE_DBSTATUS_SCHEMA_USED 2 #define SQLITE_DBSTATUS_STMT_USED 3 #define SQLITE_DBSTATUS_LOOKASIDE_HIT 4 #define SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE 5 #define SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL 6 #define SQLITE_DBSTATUS_CACHE_HIT 7 #define SQLITE_DBSTATUS_CACHE_MISS 8 #define SQLITE_DBSTATUS_MAX 8 /* Largest defined DBSTATUS */ /* ** CAPI3REF: Prepared Statement Status ** ** ^(Each prepared statement maintains various ** [SQLITE_STMTSTATUS counters] that measure the number ** of times it has performed specific operations.)^ These counters can ** be used to monitor the performance characteristics of the prepared ** statements. For example, if the number of table steps greatly exceeds ** the number of table searches or result rows, that would tend to indicate ** that the prepared statement is using a full table scan rather than ** an index. ** ** ^(This interface is used to retrieve and reset counter values from ** a [prepared statement]. The first argument is the prepared statement ** object to be interrogated. The second argument ** is an integer code for a specific [SQLITE_STMTSTATUS counter] ** to be interrogated.)^ ** ^The current value of the requested counter is returned. ** ^If the resetFlg is true, then the counter is reset to zero after this ** interface call returns. ** ** See also: [sqlite3_status()] and [sqlite3_db_status()]. */ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); /* ** CAPI3REF: Status Parameters for prepared statements ** KEYWORDS: {SQLITE_STMTSTATUS counter} {SQLITE_STMTSTATUS counters} ** ** These preprocessor macros define integer codes that name counter ** values associated with the [sqlite3_stmt_status()] interface. ** The meanings of the various counters are as follows: ** **
** [[SQLITE_STMTSTATUS_FULLSCAN_STEP]]
SQLITE_STMTSTATUS_FULLSCAN_STEP
**
^This is the number of times that SQLite has stepped forward in ** a table as part of a full table scan. Large numbers for this counter ** may indicate opportunities for performance improvement through ** careful use of indices.
** ** [[SQLITE_STMTSTATUS_SORT]]
SQLITE_STMTSTATUS_SORT
**
^This is the number of sort operations that have occurred. ** A non-zero value in this counter may indicate an opportunity to ** improvement performance through careful use of indices.
** ** [[SQLITE_STMTSTATUS_AUTOINDEX]]
SQLITE_STMTSTATUS_AUTOINDEX
**
^This is the number of rows inserted into transient indices that ** were created automatically in order to help joins run faster. ** A non-zero value in this counter may indicate an opportunity to ** improvement performance by adding permanent indices that do not ** need to be reinitialized each time the statement is run.
**
*/ #define SQLITE_STMTSTATUS_FULLSCAN_STEP 1 #define SQLITE_STMTSTATUS_SORT 2 #define SQLITE_STMTSTATUS_AUTOINDEX 3 /* ** CAPI3REF: Custom Page Cache Object ** ** The sqlite3_pcache type is opaque. It is implemented by ** the pluggable module. The SQLite core has no knowledge of ** its size or internal structure and never deals with the ** sqlite3_pcache object except by holding and passing pointers ** to the object. ** ** See [sqlite3_pcache_methods] for additional information. */ typedef struct sqlite3_pcache sqlite3_pcache; /* ** CAPI3REF: Application Defined Page Cache. ** KEYWORDS: {page cache} ** ** ^(The [sqlite3_config]([SQLITE_CONFIG_PCACHE], ...) interface can ** register an alternative page cache implementation by passing in an ** instance of the sqlite3_pcache_methods structure.)^ ** In many applications, most of the heap memory allocated by ** SQLite is used for the page cache. ** By implementing a ** custom page cache using this API, an application can better control ** the amount of memory consumed by SQLite, the way in which ** that memory is allocated and released, and the policies used to ** determine exactly which parts of a database file are cached and for ** how long. ** ** The alternative page cache mechanism is an ** extreme measure that is only needed by the most demanding applications. ** The built-in page cache is recommended for most uses. ** ** ^(The contents of the sqlite3_pcache_methods structure are copied to an ** internal buffer by SQLite within the call to [sqlite3_config]. Hence ** the application may discard the parameter after the call to ** [sqlite3_config()] returns.)^ ** ** [[the xInit() page cache method]] ** ^(The xInit() method is called once for each effective ** call to [sqlite3_initialize()])^ ** (usually only once during the lifetime of the process). ^(The xInit() ** method is passed a copy of the sqlite3_pcache_methods.pArg value.)^ ** The intent of the xInit() method is to set up global data structures ** required by the custom page cache implementation. ** ^(If the xInit() method is NULL, then the ** built-in default page cache is used instead of the application defined ** page cache.)^ ** ** [[the xShutdown() page cache method]] ** ^The xShutdown() method is called by [sqlite3_shutdown()]. ** It can be used to clean up ** any outstanding resources before process shutdown, if required. ** ^The xShutdown() method may be NULL. ** ** ^SQLite automatically serializes calls to the xInit method, ** so the xInit method need not be threadsafe. ^The ** xShutdown method is only called from [sqlite3_shutdown()] so it does ** not need to be threadsafe either. All other methods must be threadsafe ** in multithreaded applications. ** ** ^SQLite will never invoke xInit() more than once without an intervening ** call to xShutdown(). ** ** [[the xCreate() page cache methods]] ** ^SQLite invokes the xCreate() method to construct a new cache instance. ** SQLite will typically create one cache instance for each open database file, ** though this is not guaranteed. ^The ** first parameter, szPage, is the size in bytes of the pages that must ** be allocated by the cache. ^szPage will not be a power of two. ^szPage ** will the page size of the database file that is to be cached plus an ** increment (here called "R") of less than 250. SQLite will use the ** extra R bytes on each page to store metadata about the underlying ** database page on disk. The value of R depends ** on the SQLite version, the target platform, and how SQLite was compiled. ** ^(R is constant for a particular build of SQLite. Except, there are two ** distinct values of R when SQLite is compiled with the proprietary ** ZIPVFS extension.)^ ^The second argument to ** xCreate(), bPurgeable, is true if the cache being created will ** be used to cache database pages of a file stored on disk, or ** false if it is used for an in-memory database. The cache implementation ** does not have to do anything special based with the value of bPurgeable; ** it is purely advisory. ^On a cache where bPurgeable is false, SQLite will ** never invoke xUnpin() except to deliberately delete a page. ** ^In other words, calls to xUnpin() on a cache with bPurgeable set to ** false will always have the "discard" flag set to true. ** ^Hence, a cache created with bPurgeable false will ** never contain any unpinned pages. ** ** [[the xCachesize() page cache method]] ** ^(The xCachesize() method may be called at any time by SQLite to set the ** suggested maximum cache-size (number of pages stored by) the cache ** instance passed as the first argument. This is the value configured using ** the SQLite "[PRAGMA cache_size]" command.)^ As with the bPurgeable ** parameter, the implementation is not required to do anything with this ** value; it is advisory only. ** ** [[the xPagecount() page cache methods]] ** The xPagecount() method must return the number of pages currently ** stored in the cache, both pinned and unpinned. ** ** [[the xFetch() page cache methods]] ** The xFetch() method locates a page in the cache and returns a pointer to ** the page, or a NULL pointer. ** A "page", in this context, means a buffer of szPage bytes aligned at an ** 8-byte boundary. The page to be fetched is determined by the key. ^The ** minimum key value is 1. After it has been retrieved using xFetch, the page ** is considered to be "pinned". ** ** If the requested page is already in the page cache, then the page cache ** implementation must return a pointer to the page buffer with its content ** intact. If the requested page is not already in the cache, then the ** cache implementation should use the value of the createFlag ** parameter to help it determined what action to take: ** ** **
createFlag Behaviour when page is not already in cache **
0 Do not allocate a new page. Return NULL. **
1 Allocate a new page if it easy and convenient to do so. ** Otherwise return NULL. **
2 Make every effort to allocate a new page. Only return ** NULL if allocating a new page is effectively impossible. **
** ** ^(SQLite will normally invoke xFetch() with a createFlag of 0 or 1. SQLite ** will only use a createFlag of 2 after a prior call with a createFlag of 1 ** failed.)^ In between the to xFetch() calls, SQLite may ** attempt to unpin one or more cache pages by spilling the content of ** pinned pages to disk and synching the operating system disk cache. ** ** [[the xUnpin() page cache method]] ** ^xUnpin() is called by SQLite with a pointer to a currently pinned page ** as its second argument. If the third parameter, discard, is non-zero, ** then the page must be evicted from the cache. ** ^If the discard parameter is ** zero, then the page may be discarded or retained at the discretion of ** page cache implementation. ^The page cache implementation ** may choose to evict unpinned pages at any time. ** ** The cache must not perform any reference counting. A single ** call to xUnpin() unpins the page regardless of the number of prior calls ** to xFetch(). ** ** [[the xRekey() page cache methods]] ** The xRekey() method is used to change the key value associated with the ** page passed as the second argument. If the cache ** previously contains an entry associated with newKey, it must be ** discarded. ^Any prior cache entry associated with newKey is guaranteed not ** to be pinned. ** ** When SQLite calls the xTruncate() method, the cache must discard all ** existing cache entries with page numbers (keys) greater than or equal ** to the value of the iLimit parameter passed to xTruncate(). If any ** of these pages are pinned, they are implicitly unpinned, meaning that ** they can be safely discarded. ** ** [[the xDestroy() page cache method]] ** ^The xDestroy() method is used to delete a cache allocated by xCreate(). ** All resources associated with the specified cache should be freed. ^After ** calling the xDestroy() method, SQLite considers the [sqlite3_pcache*] ** handle invalid, and will not use it with any other sqlite3_pcache_methods ** functions. */ typedef struct sqlite3_pcache_methods sqlite3_pcache_methods; struct sqlite3_pcache_methods { void *pArg; int (*xInit)(void*); void (*xShutdown)(void*); sqlite3_pcache *(*xCreate)(int szPage, int bPurgeable); void (*xCachesize)(sqlite3_pcache*, int nCachesize); int (*xPagecount)(sqlite3_pcache*); void *(*xFetch)(sqlite3_pcache*, unsigned key, int createFlag); void (*xUnpin)(sqlite3_pcache*, void*, int discard); void (*xRekey)(sqlite3_pcache*, void*, unsigned oldKey, unsigned newKey); void (*xTruncate)(sqlite3_pcache*, unsigned iLimit); void (*xDestroy)(sqlite3_pcache*); }; /* ** CAPI3REF: Online Backup Object ** ** The sqlite3_backup object records state information about an ongoing ** online backup operation. ^The sqlite3_backup object is created by ** a call to [sqlite3_backup_init()] and is destroyed by a call to ** [sqlite3_backup_finish()]. ** ** See Also: [Using the SQLite Online Backup API] */ typedef struct sqlite3_backup sqlite3_backup; /* ** CAPI3REF: Online Backup API. ** ** The backup API copies the content of one database into another. ** It is useful either for creating backups of databases or ** for copying in-memory databases to or from persistent files. ** ** See Also: [Using the SQLite Online Backup API] ** ** ^SQLite holds a write transaction open on the destination database file ** for the duration of the backup operation. ** ^The source database is read-locked only while it is being read; ** it is not locked continuously for the entire backup operation. ** ^Thus, the backup may be performed on a live source database without ** preventing other database connections from ** reading or writing to the source database while the backup is underway. ** ** ^(To perform a backup operation: **
    **
  1. sqlite3_backup_init() is called once to initialize the ** backup, **
  2. sqlite3_backup_step() is called one or more times to transfer ** the data between the two databases, and finally **
  3. sqlite3_backup_finish() is called to release all resources ** associated with the backup operation. **
)^ ** There should be exactly one call to sqlite3_backup_finish() for each ** successful call to sqlite3_backup_init(). ** ** [[sqlite3_backup_init()]] sqlite3_backup_init() ** ** ^The D and N arguments to sqlite3_backup_init(D,N,S,M) are the ** [database connection] associated with the destination database ** and the database name, respectively. ** ^The database name is "main" for the main database, "temp" for the ** temporary database, or the name specified after the AS keyword in ** an [ATTACH] statement for an attached database. ** ^The S and M arguments passed to ** sqlite3_backup_init(D,N,S,M) identify the [database connection] ** and database name of the source database, respectively. ** ^The source and destination [database connections] (parameters S and D) ** must be different or else sqlite3_backup_init(D,N,S,M) will fail with ** an error. ** ** ^If an error occurs within sqlite3_backup_init(D,N,S,M), then NULL is ** returned and an error code and error message are stored in the ** destination [database connection] D. ** ^The error code and message for the failed call to sqlite3_backup_init() ** can be retrieved using the [sqlite3_errcode()], [sqlite3_errmsg()], and/or ** [sqlite3_errmsg16()] functions. ** ^A successful call to sqlite3_backup_init() returns a pointer to an ** [sqlite3_backup] object. ** ^The [sqlite3_backup] object may be used with the sqlite3_backup_step() and ** sqlite3_backup_finish() functions to perform the specified backup ** operation. ** ** [[sqlite3_backup_step()]] sqlite3_backup_step() ** ** ^Function sqlite3_backup_step(B,N) will copy up to N pages between ** the source and destination databases specified by [sqlite3_backup] object B. ** ^If N is negative, all remaining source pages are copied. ** ^If sqlite3_backup_step(B,N) successfully copies N pages and there ** are still more pages to be copied, then the function returns [SQLITE_OK]. ** ^If sqlite3_backup_step(B,N) successfully finishes copying all pages ** from source to destination, then it returns [SQLITE_DONE]. ** ^If an error occurs while running sqlite3_backup_step(B,N), ** then an [error code] is returned. ^As well as [SQLITE_OK] and ** [SQLITE_DONE], a call to sqlite3_backup_step() may return [SQLITE_READONLY], ** [SQLITE_NOMEM], [SQLITE_BUSY], [SQLITE_LOCKED], or an ** [SQLITE_IOERR_ACCESS | SQLITE_IOERR_XXX] extended error code. ** ** ^(The sqlite3_backup_step() might return [SQLITE_READONLY] if **
    **
  1. the destination database was opened read-only, or **
  2. the destination database is using write-ahead-log journaling ** and the destination and source page sizes differ, or **
  3. the destination database is an in-memory database and the ** destination and source page sizes differ. **
)^ ** ** ^If sqlite3_backup_step() cannot obtain a required file-system lock, then ** the [sqlite3_busy_handler | busy-handler function] ** is invoked (if one is specified). ^If the ** busy-handler returns non-zero before the lock is available, then ** [SQLITE_BUSY] is returned to the caller. ^In this case the call to ** sqlite3_backup_step() can be retried later. ^If the source ** [database connection] ** is being used to write to the source database when sqlite3_backup_step() ** is called, then [SQLITE_LOCKED] is returned immediately. ^Again, in this ** case the call to sqlite3_backup_step() can be retried later on. ^(If ** [SQLITE_IOERR_ACCESS | SQLITE_IOERR_XXX], [SQLITE_NOMEM], or ** [SQLITE_READONLY] is returned, then ** there is no point in retrying the call to sqlite3_backup_step(). These ** errors are considered fatal.)^ The application must accept ** that the backup operation has failed and pass the backup operation handle ** to the sqlite3_backup_finish() to release associated resources. ** ** ^The first call to sqlite3_backup_step() obtains an exclusive lock ** on the destination file. ^The exclusive lock is not released until either ** sqlite3_backup_finish() is called or the backup operation is complete ** and sqlite3_backup_step() returns [SQLITE_DONE]. ^Every call to ** sqlite3_backup_step() obtains a [shared lock] on the source database that ** lasts for the duration of the sqlite3_backup_step() call. ** ^Because the source database is not locked between calls to ** sqlite3_backup_step(), the source database may be modified mid-way ** through the backup process. ^If the source database is modified by an ** external process or via a database connection other than the one being ** used by the backup operation, then the backup will be automatically ** restarted by the next call to sqlite3_backup_step(). ^If the source ** database is modified by the using the same database connection as is used ** by the backup operation, then the backup database is automatically ** updated at the same time. ** ** [[sqlite3_backup_finish()]] sqlite3_backup_finish() ** ** When sqlite3_backup_step() has returned [SQLITE_DONE], or when the ** application wishes to abandon the backup operation, the application ** should destroy the [sqlite3_backup] by passing it to sqlite3_backup_finish(). ** ^The sqlite3_backup_finish() interfaces releases all ** resources associated with the [sqlite3_backup] object. ** ^If sqlite3_backup_step() has not yet returned [SQLITE_DONE], then any ** active write-transaction on the destination database is rolled back. ** The [sqlite3_backup] object is invalid ** and may not be used following a call to sqlite3_backup_finish(). ** ** ^The value returned by sqlite3_backup_finish is [SQLITE_OK] if no ** sqlite3_backup_step() errors occurred, regardless or whether or not ** sqlite3_backup_step() completed. ** ^If an out-of-memory condition or IO error occurred during any prior ** sqlite3_backup_step() call on the same [sqlite3_backup] object, then ** sqlite3_backup_finish() returns the corresponding [error code]. ** ** ^A return of [SQLITE_BUSY] or [SQLITE_LOCKED] from sqlite3_backup_step() ** is not a permanent error and does not affect the return value of ** sqlite3_backup_finish(). ** ** [[sqlite3_backup__remaining()]] [[sqlite3_backup_pagecount()]] ** sqlite3_backup_remaining() and sqlite3_backup_pagecount() ** ** ^Each call to sqlite3_backup_step() sets two values inside ** the [sqlite3_backup] object: the number of pages still to be backed ** up and the total number of pages in the source database file. ** The sqlite3_backup_remaining() and sqlite3_backup_pagecount() interfaces ** retrieve these two values, respectively. ** ** ^The values returned by these functions are only updated by ** sqlite3_backup_step(). ^If the source database is modified during a backup ** operation, then the values are not updated to account for any extra ** pages that need to be updated or the size of the source database file ** changing. ** ** Concurrent Usage of Database Handles ** ** ^The source [database connection] may be used by the application for other ** purposes while a backup operation is underway or being initialized. ** ^If SQLite is compiled and configured to support threadsafe database ** connections, then the source database connection may be used concurrently ** from within other threads. ** ** However, the application must guarantee that the destination ** [database connection] is not passed to any other API (by any thread) after ** sqlite3_backup_init() is called and before the corresponding call to ** sqlite3_backup_finish(). SQLite does not currently check to see ** if the application incorrectly accesses the destination [database connection] ** and so no error code is reported, but the operations may malfunction ** nevertheless. Use of the destination database connection while a ** backup is in progress might also also cause a mutex deadlock. ** ** If running in [shared cache mode], the application must ** guarantee that the shared cache used by the destination database ** is not accessed while the backup is running. In practice this means ** that the application must guarantee that the disk file being ** backed up to is not accessed by any connection within the process, ** not just the specific connection that was passed to sqlite3_backup_init(). ** ** The [sqlite3_backup] object itself is partially threadsafe. Multiple ** threads may safely make multiple concurrent calls to sqlite3_backup_step(). ** However, the sqlite3_backup_remaining() and sqlite3_backup_pagecount() ** APIs are not strictly speaking threadsafe. If they are invoked at the ** same time as another thread is invoking sqlite3_backup_step() it is ** possible that they return invalid values. */ SQLITE_API sqlite3_backup *sqlite3_backup_init( sqlite3 *pDest, /* Destination database handle */ const char *zDestName, /* Destination database name */ sqlite3 *pSource, /* Source database handle */ const char *zSourceName /* Source database name */ ); SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage); SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p); SQLITE_API int sqlite3_backup_remaining(sqlite3_backup *p); SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p); /* ** CAPI3REF: Unlock Notification ** ** ^When running in shared-cache mode, a database operation may fail with ** an [SQLITE_LOCKED] error if the required locks on the shared-cache or ** individual tables within the shared-cache cannot be obtained. See ** [SQLite Shared-Cache Mode] for a description of shared-cache locking. ** ^This API may be used to register a callback that SQLite will invoke ** when the connection currently holding the required lock relinquishes it. ** ^This API is only available if the library was compiled with the ** [SQLITE_ENABLE_UNLOCK_NOTIFY] C-preprocessor symbol defined. ** ** See Also: [Using the SQLite Unlock Notification Feature]. ** ** ^Shared-cache locks are released when a database connection concludes ** its current transaction, either by committing it or rolling it back. ** ** ^When a connection (known as the blocked connection) fails to obtain a ** shared-cache lock and SQLITE_LOCKED is returned to the caller, the ** identity of the database connection (the blocking connection) that ** has locked the required resource is stored internally. ^After an ** application receives an SQLITE_LOCKED error, it may call the ** sqlite3_unlock_notify() method with the blocked connection handle as ** the first argument to register for a callback that will be invoked ** when the blocking connections current transaction is concluded. ^The ** callback is invoked from within the [sqlite3_step] or [sqlite3_close] ** call that concludes the blocking connections transaction. ** ** ^(If sqlite3_unlock_notify() is called in a multi-threaded application, ** there is a chance that the blocking connection will have already ** concluded its transaction by the time sqlite3_unlock_notify() is invoked. ** If this happens, then the specified callback is invoked immediately, ** from within the call to sqlite3_unlock_notify().)^ ** ** ^If the blocked connection is attempting to obtain a write-lock on a ** shared-cache table, and more than one other connection currently holds ** a read-lock on the same table, then SQLite arbitrarily selects one of ** the other connections to use as the blocking connection. ** ** ^(There may be at most one unlock-notify callback registered by a ** blocked connection. If sqlite3_unlock_notify() is called when the ** blocked connection already has a registered unlock-notify callback, ** then the new callback replaces the old.)^ ^If sqlite3_unlock_notify() is ** called with a NULL pointer as its second argument, then any existing ** unlock-notify callback is canceled. ^The blocked connections ** unlock-notify callback may also be canceled by closing the blocked ** connection using [sqlite3_close()]. ** ** The unlock-notify callback is not reentrant. If an application invokes ** any sqlite3_xxx API functions from within an unlock-notify callback, a ** crash or deadlock may be the result. ** ** ^Unless deadlock is detected (see below), sqlite3_unlock_notify() always ** returns SQLITE_OK. ** ** Callback Invocation Details ** ** When an unlock-notify callback is registered, the application provides a ** single void* pointer that is passed to the callback when it is invoked. ** However, the signature of the callback function allows SQLite to pass ** it an array of void* context pointers. The first argument passed to ** an unlock-notify callback is a pointer to an array of void* pointers, ** and the second is the number of entries in the array. ** ** When a blocking connections transaction is concluded, there may be ** more than one blocked connection that has registered for an unlock-notify ** callback. ^If two or more such blocked connections have specified the ** same callback function, then instead of invoking the callback function ** multiple times, it is invoked once with the set of void* context pointers ** specified by the blocked connections bundled together into an array. ** This gives the application an opportunity to prioritize any actions ** related to the set of unblocked database connections. ** ** Deadlock Detection ** ** Assuming that after registering for an unlock-notify callback a ** database waits for the callback to be issued before taking any further ** action (a reasonable assumption), then using this API may cause the ** application to deadlock. For example, if connection X is waiting for ** connection Y's transaction to be concluded, and similarly connection ** Y is waiting on connection X's transaction, then neither connection ** will proceed and the system may remain deadlocked indefinitely. ** ** To avoid this scenario, the sqlite3_unlock_notify() performs deadlock ** detection. ^If a given call to sqlite3_unlock_notify() would put the ** system in a deadlocked state, then SQLITE_LOCKED is returned and no ** unlock-notify callback is registered. The system is said to be in ** a deadlocked state if connection A has registered for an unlock-notify ** callback on the conclusion of connection B's transaction, and connection ** B has itself registered for an unlock-notify callback when connection ** A's transaction is concluded. ^Indirect deadlock is also detected, so ** the system is also considered to be deadlocked if connection B has ** registered for an unlock-notify callback on the conclusion of connection ** C's transaction, where connection C is waiting on connection A. ^Any ** number of levels of indirection are allowed. ** ** The "DROP TABLE" Exception ** ** When a call to [sqlite3_step()] returns SQLITE_LOCKED, it is almost ** always appropriate to call sqlite3_unlock_notify(). There is however, ** one exception. When executing a "DROP TABLE" or "DROP INDEX" statement, ** SQLite checks if there are any currently executing SELECT statements ** that belong to the same connection. If there are, SQLITE_LOCKED is ** returned. In this case there is no "blocking connection", so invoking ** sqlite3_unlock_notify() results in the unlock-notify callback being ** invoked immediately. If the application then re-attempts the "DROP TABLE" ** or "DROP INDEX" query, an infinite loop might be the result. ** ** One way around this problem is to check the extended error code returned ** by an sqlite3_step() call. ^(If there is a blocking connection, then the ** extended error code is set to SQLITE_LOCKED_SHAREDCACHE. Otherwise, in ** the special "DROP TABLE/INDEX" case, the extended error code is just ** SQLITE_LOCKED.)^ */ SQLITE_API int sqlite3_unlock_notify( sqlite3 *pBlocked, /* Waiting connection */ void (*xNotify)(void **apArg, int nArg), /* Callback function to invoke */ void *pNotifyArg /* Argument to pass to xNotify */ ); /* ** CAPI3REF: String Comparison ** ** ^The [sqlite3_strnicmp()] API allows applications and extensions to ** compare the contents of two buffers containing UTF-8 strings in a ** case-independent fashion, using the same definition of case independence ** that SQLite uses internally when comparing identifiers. */ SQLITE_API int sqlite3_strnicmp(const char *, const char *, int); /* ** CAPI3REF: Error Logging Interface ** ** ^The [sqlite3_log()] interface writes a message into the error log ** established by the [SQLITE_CONFIG_LOG] option to [sqlite3_config()]. ** ^If logging is enabled, the zFormat string and subsequent arguments are ** used with [sqlite3_snprintf()] to generate the final output string. ** ** The sqlite3_log() interface is intended for use by extensions such as ** virtual tables, collating functions, and SQL functions. While there is ** nothing to prevent an application from calling sqlite3_log(), doing so ** is considered bad form. ** ** The zFormat string must not be NULL. ** ** To avoid deadlocks and other threading problems, the sqlite3_log() routine ** will not use dynamically allocated memory. The log message is stored in ** a fixed-length buffer on the stack. If the log message is longer than ** a few hundred characters, it will be truncated to the length of the ** buffer. */ SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...); /* ** CAPI3REF: Write-Ahead Log Commit Hook ** ** ^The [sqlite3_wal_hook()] function is used to register a callback that ** will be invoked each time a database connection commits data to a ** [write-ahead log] (i.e. whenever a transaction is committed in ** [journal_mode | journal_mode=WAL mode]). ** ** ^The callback is invoked by SQLite after the commit has taken place and ** the associated write-lock on the database released, so the implementation ** may read, write or [checkpoint] the database as required. ** ** ^The first parameter passed to the callback function when it is invoked ** is a copy of the third parameter passed to sqlite3_wal_hook() when ** registering the callback. ^The second is a copy of the database handle. ** ^The third parameter is the name of the database that was written to - ** either "main" or the name of an [ATTACH]-ed database. ^The fourth parameter ** is the number of pages currently in the write-ahead log file, ** including those that were just committed. ** ** The callback function should normally return [SQLITE_OK]. ^If an error ** code is returned, that error will propagate back up through the ** SQLite code base to cause the statement that provoked the callback ** to report an error, though the commit will have still occurred. If the ** callback returns [SQLITE_ROW] or [SQLITE_DONE], or if it returns a value ** that does not correspond to any valid SQLite error code, the results ** are undefined. ** ** A single database handle may have at most a single write-ahead log callback ** registered at one time. ^Calling [sqlite3_wal_hook()] replaces any ** previously registered write-ahead log callback. ^Note that the ** [sqlite3_wal_autocheckpoint()] interface and the ** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will ** those overwrite any prior [sqlite3_wal_hook()] settings. */ SQLITE_API void *sqlite3_wal_hook( sqlite3*, int(*)(void *,sqlite3*,const char*,int), void* ); /* ** CAPI3REF: Configure an auto-checkpoint ** ** ^The [sqlite3_wal_autocheckpoint(D,N)] is a wrapper around ** [sqlite3_wal_hook()] that causes any database on [database connection] D ** to automatically [checkpoint] ** after committing a transaction if there are N or ** more frames in the [write-ahead log] file. ^Passing zero or ** a negative value as the nFrame parameter disables automatic ** checkpoints entirely. ** ** ^The callback registered by this function replaces any existing callback ** registered using [sqlite3_wal_hook()]. ^Likewise, registering a callback ** using [sqlite3_wal_hook()] disables the automatic checkpoint mechanism ** configured by this function. ** ** ^The [wal_autocheckpoint pragma] can be used to invoke this interface ** from SQL. ** ** ^Every new [database connection] defaults to having the auto-checkpoint ** enabled with a threshold of 1000 or [SQLITE_DEFAULT_WAL_AUTOCHECKPOINT] ** pages. The use of this interface ** is only necessary if the default setting is found to be suboptimal ** for a particular application. */ SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N); /* ** CAPI3REF: Checkpoint a database ** ** ^The [sqlite3_wal_checkpoint(D,X)] interface causes database named X ** on [database connection] D to be [checkpointed]. ^If X is NULL or an ** empty string, then a checkpoint is run on all databases of ** connection D. ^If the database connection D is not in ** [WAL | write-ahead log mode] then this interface is a harmless no-op. ** ** ^The [wal_checkpoint pragma] can be used to invoke this interface ** from SQL. ^The [sqlite3_wal_autocheckpoint()] interface and the ** [wal_autocheckpoint pragma] can be used to cause this interface to be ** run whenever the WAL reaches a certain size threshold. ** ** See also: [sqlite3_wal_checkpoint_v2()] */ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb); /* ** CAPI3REF: Checkpoint a database ** ** Run a checkpoint operation on WAL database zDb attached to database ** handle db. The specific operation is determined by the value of the ** eMode parameter: ** **
**
SQLITE_CHECKPOINT_PASSIVE
** Checkpoint as many frames as possible without waiting for any database ** readers or writers to finish. Sync the db file if all frames in the log ** are checkpointed. This mode is the same as calling ** sqlite3_wal_checkpoint(). The busy-handler callback is never invoked. ** **
SQLITE_CHECKPOINT_FULL
** This mode blocks (calls the busy-handler callback) until there is no ** database writer and all readers are reading from the most recent database ** snapshot. It then checkpoints all frames in the log file and syncs the ** database file. This call blocks database writers while it is running, ** but not database readers. ** **
SQLITE_CHECKPOINT_RESTART
** This mode works the same way as SQLITE_CHECKPOINT_FULL, except after ** checkpointing the log file it blocks (calls the busy-handler callback) ** until all readers are reading from the database file only. This ensures ** that the next client to write to the database file restarts the log file ** from the beginning. This call blocks database writers while it is running, ** but not database readers. **
** ** If pnLog is not NULL, then *pnLog is set to the total number of frames in ** the log file before returning. If pnCkpt is not NULL, then *pnCkpt is set to ** the total number of checkpointed frames (including any that were already ** checkpointed when this function is called). *pnLog and *pnCkpt may be ** populated even if sqlite3_wal_checkpoint_v2() returns other than SQLITE_OK. ** If no values are available because of an error, they are both set to -1 ** before returning to communicate this to the caller. ** ** All calls obtain an exclusive "checkpoint" lock on the database file. If ** any other process is running a checkpoint operation at the same time, the ** lock cannot be obtained and SQLITE_BUSY is returned. Even if there is a ** busy-handler configured, it will not be invoked in this case. ** ** The SQLITE_CHECKPOINT_FULL and RESTART modes also obtain the exclusive ** "writer" lock on the database file. If the writer lock cannot be obtained ** immediately, and a busy-handler is configured, it is invoked and the writer ** lock retried until either the busy-handler returns 0 or the lock is ** successfully obtained. The busy-handler is also invoked while waiting for ** database readers as described above. If the busy-handler returns 0 before ** the writer lock is obtained or while waiting for database readers, the ** checkpoint operation proceeds from that point in the same way as ** SQLITE_CHECKPOINT_PASSIVE - checkpointing as many frames as possible ** without blocking any further. SQLITE_BUSY is returned in this case. ** ** If parameter zDb is NULL or points to a zero length string, then the ** specified operation is attempted on all WAL databases. In this case the ** values written to output parameters *pnLog and *pnCkpt are undefined. If ** an SQLITE_BUSY error is encountered when processing one or more of the ** attached WAL databases, the operation is still attempted on any remaining ** attached databases and SQLITE_BUSY is returned to the caller. If any other ** error occurs while processing an attached database, processing is abandoned ** and the error code returned to the caller immediately. If no error ** (SQLITE_BUSY or otherwise) is encountered while processing the attached ** databases, SQLITE_OK is returned. ** ** If database zDb is the name of an attached database that is not in WAL ** mode, SQLITE_OK is returned and both *pnLog and *pnCkpt set to -1. If ** zDb is not NULL (or a zero length string) and is not the name of any ** attached database, SQLITE_ERROR is returned to the caller. */ SQLITE_API int sqlite3_wal_checkpoint_v2( sqlite3 *db, /* Database handle */ const char *zDb, /* Name of attached database (or NULL) */ int eMode, /* SQLITE_CHECKPOINT_* value */ int *pnLog, /* OUT: Size of WAL log in frames */ int *pnCkpt /* OUT: Total number of frames checkpointed */ ); /* ** CAPI3REF: Checkpoint operation parameters ** ** These constants can be used as the 3rd parameter to ** [sqlite3_wal_checkpoint_v2()]. See the [sqlite3_wal_checkpoint_v2()] ** documentation for additional information about the meaning and use of ** each of these values. */ #define SQLITE_CHECKPOINT_PASSIVE 0 #define SQLITE_CHECKPOINT_FULL 1 #define SQLITE_CHECKPOINT_RESTART 2 /* ** CAPI3REF: Virtual Table Interface Configuration ** ** This function may be called by either the [xConnect] or [xCreate] method ** of a [virtual table] implementation to configure ** various facets of the virtual table interface. ** ** If this interface is invoked outside the context of an xConnect or ** xCreate virtual table method then the behavior is undefined. ** ** At present, there is only one option that may be configured using ** this function. (See [SQLITE_VTAB_CONSTRAINT_SUPPORT].) Further options ** may be added in the future. */ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); /* ** CAPI3REF: Virtual Table Configuration Options ** ** These macros define the various options to the ** [sqlite3_vtab_config()] interface that [virtual table] implementations ** can use to customize and optimize their behavior. ** **
**
SQLITE_VTAB_CONSTRAINT_SUPPORT **
Calls of the form ** [sqlite3_vtab_config](db,SQLITE_VTAB_CONSTRAINT_SUPPORT,X) are supported, ** where X is an integer. If X is zero, then the [virtual table] whose ** [xCreate] or [xConnect] method invoked [sqlite3_vtab_config()] does not ** support constraints. In this configuration (which is the default) if ** a call to the [xUpdate] method returns [SQLITE_CONSTRAINT], then the entire ** statement is rolled back as if [ON CONFLICT | OR ABORT] had been ** specified as part of the users SQL statement, regardless of the actual ** ON CONFLICT mode specified. ** ** If X is non-zero, then the virtual table implementation guarantees ** that if [xUpdate] returns [SQLITE_CONSTRAINT], it will do so before ** any modifications to internal or persistent data structures have been made. ** If the [ON CONFLICT] mode is ABORT, FAIL, IGNORE or ROLLBACK, SQLite ** is able to roll back a statement or database transaction, and abandon ** or continue processing the current SQL statement as appropriate. ** If the ON CONFLICT mode is REPLACE and the [xUpdate] method returns ** [SQLITE_CONSTRAINT], SQLite handles this as if the ON CONFLICT mode ** had been ABORT. ** ** Virtual table implementations that are required to handle OR REPLACE ** must do so within the [xUpdate] method. If a call to the ** [sqlite3_vtab_on_conflict()] function indicates that the current ON ** CONFLICT policy is REPLACE, the virtual table implementation should ** silently replace the appropriate rows within the xUpdate callback and ** return SQLITE_OK. Or, if this is not possible, it may return ** SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT ** constraint handling. **
*/ #define SQLITE_VTAB_CONSTRAINT_SUPPORT 1 /* ** CAPI3REF: Determine The Virtual Table Conflict Policy ** ** This function may only be called from within a call to the [xUpdate] method ** of a [virtual table] implementation for an INSERT or UPDATE operation. ^The ** value returned is one of [SQLITE_ROLLBACK], [SQLITE_IGNORE], [SQLITE_FAIL], ** [SQLITE_ABORT], or [SQLITE_REPLACE], according to the [ON CONFLICT] mode ** of the SQL statement that triggered the call to the [xUpdate] method of the ** [virtual table]. */ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *); /* ** CAPI3REF: Conflict resolution modes ** ** These constants are returned by [sqlite3_vtab_on_conflict()] to ** inform a [virtual table] implementation what the [ON CONFLICT] mode ** is for the SQL statement being evaluated. ** ** Note that the [SQLITE_IGNORE] constant is also used as a potential ** return value from the [sqlite3_set_authorizer()] callback and that ** [SQLITE_ABORT] is also a [result code]. */ #define SQLITE_ROLLBACK 1 /* #define SQLITE_IGNORE 2 // Also used by sqlite3_authorizer() callback */ #define SQLITE_FAIL 3 /* #define SQLITE_ABORT 4 // Also an error code */ #define SQLITE_REPLACE 5 /* ** Undo the hack that converts floating point types to integer for ** builds on processors without floating point support. */ #ifdef SQLITE_OMIT_FLOATING_POINT # undef double #endif #if 0 } /* End of the 'extern "C"' block */ #endif #endif /* ** 2010 August 30 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* */ #ifndef _SQLITE3RTREE_H_ #define _SQLITE3RTREE_H_ #if 0 extern "C" { #endif typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry; /* ** Register a geometry callback named zGeom that can be used as part of an ** R-Tree geometry query as follows: ** ** SELECT ... FROM WHERE MATCH $zGeom(... params ...) */ SQLITE_API int sqlite3_rtree_geometry_callback( sqlite3 *db, const char *zGeom, int (*xGeom)(sqlite3_rtree_geometry *, int nCoord, double *aCoord, int *pRes), void *pContext ); /* ** A pointer to a structure of the following type is passed as the first ** argument to callbacks registered using rtree_geometry_callback(). */ struct sqlite3_rtree_geometry { void *pContext; /* Copy of pContext passed to s_r_g_c() */ int nParam; /* Size of array aParam[] */ double *aParam; /* Parameters passed to SQL geom function */ void *pUser; /* Callback implementation user data */ void (*xDelUser)(void *); /* Called by SQLite to clean up pUser */ }; #if 0 } /* end of the 'extern "C"' block */ #endif #endif /* ifndef _SQLITE3RTREE_H_ */ /************** End of sqlite3.h *********************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ /************** Include hash.h in the middle of sqliteInt.h ******************/ /************** Begin file hash.h ********************************************/ /* ** 2001 September 22 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This is the header file for the generic hash-table implemenation ** used in SQLite. */ #ifndef _SQLITE_HASH_H_ #define _SQLITE_HASH_H_ /* Forward declarations of structures. */ typedef struct Hash Hash; typedef struct HashElem HashElem; /* A complete hash table is an instance of the following structure. ** The internals of this structure are intended to be opaque -- client ** code should not attempt to access or modify the fields of this structure ** directly. Change this structure only by using the routines below. ** However, some of the "procedures" and "functions" for modifying and ** accessing this structure are really macros, so we can't really make ** this structure opaque. ** ** All elements of the hash table are on a single doubly-linked list. ** Hash.first points to the head of this list. ** ** There are Hash.htsize buckets. Each bucket points to a spot in ** the global doubly-linked list. The contents of the bucket are the ** element pointed to plus the next _ht.count-1 elements in the list. ** ** Hash.htsize and Hash.ht may be zero. In that case lookup is done ** by a linear search of the global list. For small tables, the ** Hash.ht table is never allocated because if there are few elements ** in the table, it is faster to do a linear search than to manage ** the hash table. */ struct Hash { unsigned int htsize; /* Number of buckets in the hash table */ unsigned int count; /* Number of entries in this table */ HashElem *first; /* The first element of the array */ struct _ht { /* the hash table */ int count; /* Number of entries with this hash */ HashElem *chain; /* Pointer to first entry with this hash */ } *ht; }; /* Each element in the hash table is an instance of the following ** structure. All elements are stored on a single doubly-linked list. ** ** Again, this structure is intended to be opaque, but it can't really ** be opaque because it is used by macros. */ struct HashElem { HashElem *next, *prev; /* Next and previous elements in the table */ void *data; /* Data associated with this element */ const char *pKey; int nKey; /* Key associated with this element */ }; /* ** Access routines. To delete, insert a NULL pointer. */ SQLITE_PRIVATE void sqlite3HashInit(Hash*); SQLITE_PRIVATE void *sqlite3HashInsert(Hash*, const char *pKey, int nKey, void *pData); SQLITE_PRIVATE void *sqlite3HashFind(const Hash*, const char *pKey, int nKey); SQLITE_PRIVATE void sqlite3HashClear(Hash*); /* ** Macros for looping over all elements of a hash table. The idiom is ** like this: ** ** Hash h; ** HashElem *p; ** ... ** for(p=sqliteHashFirst(&h); p; p=sqliteHashNext(p)){ ** SomeStructure *pData = sqliteHashData(p); ** // do something with pData ** } */ #define sqliteHashFirst(H) ((H)->first) #define sqliteHashNext(E) ((E)->next) #define sqliteHashData(E) ((E)->data) /* #define sqliteHashKey(E) ((E)->pKey) // NOT USED */ /* #define sqliteHashKeysize(E) ((E)->nKey) // NOT USED */ /* ** Number of entries in a hash table */ /* #define sqliteHashCount(H) ((H)->count) // NOT USED */ #endif /* _SQLITE_HASH_H_ */ /************** End of hash.h ************************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ /************** Include parse.h in the middle of sqliteInt.h *****************/ /************** Begin file parse.h *******************************************/ #define TK_SEMI 1 #define TK_EXPLAIN 2 #define TK_QUERY 3 #define TK_PLAN 4 #define TK_BEGIN 5 #define TK_TRANSACTION 6 #define TK_DEFERRED 7 #define TK_IMMEDIATE 8 #define TK_EXCLUSIVE 9 #define TK_COMMIT 10 #define TK_END 11 #define TK_ROLLBACK 12 #define TK_SAVEPOINT 13 #define TK_RELEASE 14 #define TK_TO 15 #define TK_TABLE 16 #define TK_CREATE 17 #define TK_IF 18 #define TK_NOT 19 #define TK_EXISTS 20 #define TK_TEMP 21 #define TK_LP 22 #define TK_RP 23 #define TK_AS 24 #define TK_COMMA 25 #define TK_ID 26 #define TK_INDEXED 27 #define TK_ABORT 28 #define TK_ACTION 29 #define TK_AFTER 30 #define TK_ANALYZE 31 #define TK_ASC 32 #define TK_ATTACH 33 #define TK_BEFORE 34 #define TK_BY 35 #define TK_CASCADE 36 #define TK_CAST 37 #define TK_COLUMNKW 38 #define TK_CONFLICT 39 #define TK_DATABASE 40 #define TK_DESC 41 #define TK_DETACH 42 #define TK_EACH 43 #define TK_FAIL 44 #define TK_FOR 45 #define TK_IGNORE 46 #define TK_INITIALLY 47 #define TK_INSTEAD 48 #define TK_LIKE_KW 49 #define TK_MATCH 50 #define TK_NO 51 #define TK_KEY 52 #define TK_OF 53 #define TK_OFFSET 54 #define TK_PRAGMA 55 #define TK_RAISE 56 #define TK_REPLACE 57 #define TK_RESTRICT 58 #define TK_ROW 59 #define TK_TRIGGER 60 #define TK_VACUUM 61 #define TK_VIEW 62 #define TK_VIRTUAL 63 #define TK_REINDEX 64 #define TK_RENAME 65 #define TK_CTIME_KW 66 #define TK_ANY 67 #define TK_OR 68 #define TK_AND 69 #define TK_IS 70 #define TK_BETWEEN 71 #define TK_IN 72 #define TK_ISNULL 73 #define TK_NOTNULL 74 #define TK_NE 75 #define TK_EQ 76 #define TK_GT 77 #define TK_LE 78 #define TK_LT 79 #define TK_GE 80 #define TK_ESCAPE 81 #define TK_BITAND 82 #define TK_BITOR 83 #define TK_LSHIFT 84 #define TK_RSHIFT 85 #define TK_PLUS 86 #define TK_MINUS 87 #define TK_STAR 88 #define TK_SLASH 89 #define TK_REM 90 #define TK_CONCAT 91 #define TK_COLLATE 92 #define TK_BITNOT 93 #define TK_STRING 94 #define TK_JOIN_KW 95 #define TK_CONSTRAINT 96 #define TK_DEFAULT 97 #define TK_NULL 98 #define TK_PRIMARY 99 #define TK_UNIQUE 100 #define TK_CHECK 101 #define TK_REFERENCES 102 #define TK_AUTOINCR 103 #define TK_ON 104 #define TK_INSERT 105 #define TK_DELETE 106 #define TK_UPDATE 107 #define TK_SET 108 #define TK_DEFERRABLE 109 #define TK_FOREIGN 110 #define TK_DROP 111 #define TK_UNION 112 #define TK_ALL 113 #define TK_EXCEPT 114 #define TK_INTERSECT 115 #define TK_SELECT 116 #define TK_DISTINCT 117 #define TK_DOT 118 #define TK_FROM 119 #define TK_JOIN 120 #define TK_USING 121 #define TK_ORDER 122 #define TK_GROUP 123 #define TK_HAVING 124 #define TK_LIMIT 125 #define TK_WHERE 126 #define TK_INTO 127 #define TK_VALUES 128 #define TK_INTEGER 129 #define TK_FLOAT 130 #define TK_BLOB 131 #define TK_REGISTER 132 #define TK_VARIABLE 133 #define TK_CASE 134 #define TK_WHEN 135 #define TK_THEN 136 #define TK_ELSE 137 #define TK_INDEX 138 #define TK_ALTER 139 #define TK_ADD 140 #define TK_TO_TEXT 141 #define TK_TO_BLOB 142 #define TK_TO_NUMERIC 143 #define TK_TO_INT 144 #define TK_TO_REAL 145 #define TK_ISNOT 146 #define TK_END_OF_FILE 147 #define TK_ILLEGAL 148 #define TK_SPACE 149 #define TK_UNCLOSED_STRING 150 #define TK_FUNCTION 151 #define TK_COLUMN 152 #define TK_AGG_FUNCTION 153 #define TK_AGG_COLUMN 154 #define TK_CONST_FUNC 155 #define TK_UMINUS 156 #define TK_UPLUS 157 /************** End of parse.h ***********************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ #include #include #include #include #include /* ** If compiling for a processor that lacks floating point support, ** substitute integer for floating-point */ #ifdef SQLITE_OMIT_FLOATING_POINT # define double sqlite_int64 # define float sqlite_int64 # define LONGDOUBLE_TYPE sqlite_int64 # ifndef SQLITE_BIG_DBL # define SQLITE_BIG_DBL (((sqlite3_int64)1)<<50) # endif # define SQLITE_OMIT_DATETIME_FUNCS 1 # define SQLITE_OMIT_TRACE 1 # undef SQLITE_MIXED_ENDIAN_64BIT_FLOAT # undef SQLITE_HAVE_ISNAN #endif #ifndef SQLITE_BIG_DBL # define SQLITE_BIG_DBL (1e99) #endif /* ** OMIT_TEMPDB is set to 1 if SQLITE_OMIT_TEMPDB is defined, or 0 ** afterward. Having this macro allows us to cause the C compiler ** to omit code used by TEMP tables without messy #ifndef statements. */ #ifdef SQLITE_OMIT_TEMPDB #define OMIT_TEMPDB 1 #else #define OMIT_TEMPDB 0 #endif /* ** The "file format" number is an integer that is incremented whenever ** the VDBE-level file format changes. The following macros define the ** the default file format for new databases and the maximum file format ** that the library can read. */ #define SQLITE_MAX_FILE_FORMAT 4 #ifndef SQLITE_DEFAULT_FILE_FORMAT # define SQLITE_DEFAULT_FILE_FORMAT 1 #endif /* ** Determine whether triggers are recursive by default. This can be ** changed at run-time using a pragma. */ #ifndef SQLITE_DEFAULT_RECURSIVE_TRIGGERS # define SQLITE_DEFAULT_RECURSIVE_TRIGGERS 0 #endif /* ** Provide a default value for SQLITE_TEMP_STORE in case it is not specified ** on the command-line */ #ifndef SQLITE_TEMP_STORE # define SQLITE_TEMP_STORE 1 #endif /* ** GCC does not define the offsetof() macro so we'll have to do it ** ourselves. */ #ifndef offsetof #define offsetof(STRUCTURE,FIELD) ((int)((char*)&((STRUCTURE*)0)->FIELD)) #endif /* ** Check to see if this machine uses EBCDIC. (Yes, believe it or ** not, there are still machines out there that use EBCDIC.) */ #if 'A' == '\301' # define SQLITE_EBCDIC 1 #else # define SQLITE_ASCII 1 #endif /* ** Integers of known sizes. These typedefs might change for architectures ** where the sizes very. Preprocessor macros are available so that the ** types can be conveniently redefined at compile-type. Like this: ** ** cc '-DUINTPTR_TYPE=long long int' ... */ #ifndef UINT32_TYPE # ifdef HAVE_UINT32_T # define UINT32_TYPE uint32_t # else # define UINT32_TYPE unsigned int # endif #endif #ifndef UINT16_TYPE # ifdef HAVE_UINT16_T # define UINT16_TYPE uint16_t # else # define UINT16_TYPE unsigned short int # endif #endif #ifndef INT16_TYPE # ifdef HAVE_INT16_T # define INT16_TYPE int16_t # else # define INT16_TYPE short int # endif #endif #ifndef UINT8_TYPE # ifdef HAVE_UINT8_T # define UINT8_TYPE uint8_t # else # define UINT8_TYPE unsigned char # endif #endif #ifndef INT8_TYPE # ifdef HAVE_INT8_T # define INT8_TYPE int8_t # else # define INT8_TYPE signed char # endif #endif #ifndef LONGDOUBLE_TYPE # define LONGDOUBLE_TYPE long double #endif typedef sqlite_int64 i64; /* 8-byte signed integer */ typedef sqlite_uint64 u64; /* 8-byte unsigned integer */ typedef UINT32_TYPE u32; /* 4-byte unsigned integer */ typedef UINT16_TYPE u16; /* 2-byte unsigned integer */ typedef INT16_TYPE i16; /* 2-byte signed integer */ typedef UINT8_TYPE u8; /* 1-byte unsigned integer */ typedef INT8_TYPE i8; /* 1-byte signed integer */ /* ** SQLITE_MAX_U32 is a u64 constant that is the maximum u64 value ** that can be stored in a u32 without loss of data. The value ** is 0x00000000ffffffff. But because of quirks of some compilers, we ** have to specify the value in the less intuitive manner shown: */ #define SQLITE_MAX_U32 ((((u64)1)<<32)-1) /* ** The datatype used to store estimates of the number of rows in a ** table or index. This is an unsigned integer type. For 99.9% of ** the world, a 32-bit integer is sufficient. But a 64-bit integer ** can be used at compile-time if desired. */ #ifdef SQLITE_64BIT_STATS typedef u64 tRowcnt; /* 64-bit only if requested at compile-time */ #else typedef u32 tRowcnt; /* 32-bit is the default */ #endif /* ** Macros to determine whether the machine is big or little endian, ** evaluated at runtime. */ #ifdef SQLITE_AMALGAMATION SQLITE_PRIVATE const int sqlite3one = 1; #else SQLITE_PRIVATE const int sqlite3one; #endif #if defined(i386) || defined(__i386__) || defined(_M_IX86)\ || defined(__x86_64) || defined(__x86_64__) # define SQLITE_BIGENDIAN 0 # define SQLITE_LITTLEENDIAN 1 # define SQLITE_UTF16NATIVE SQLITE_UTF16LE #else # define SQLITE_BIGENDIAN (*(char *)(&sqlite3one)==0) # define SQLITE_LITTLEENDIAN (*(char *)(&sqlite3one)==1) # define SQLITE_UTF16NATIVE (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE) #endif /* ** Constants for the largest and smallest possible 64-bit signed integers. ** These macros are designed to work correctly on both 32-bit and 64-bit ** compilers. */ #define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32)) #define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64) /* ** Round up a number to the next larger multiple of 8. This is used ** to force 8-byte alignment on 64-bit architectures. */ #define ROUND8(x) (((x)+7)&~7) /* ** Round down to the nearest multiple of 8 */ #define ROUNDDOWN8(x) ((x)&~7) /* ** Assert that the pointer X is aligned to an 8-byte boundary. This ** macro is used only within assert() to verify that the code gets ** all alignment restrictions correct. ** ** Except, if SQLITE_4_BYTE_ALIGNED_MALLOC is defined, then the ** underlying malloc() implemention might return us 4-byte aligned ** pointers. In that case, only verify 4-byte alignment. */ #ifdef SQLITE_4_BYTE_ALIGNED_MALLOC # define EIGHT_BYTE_ALIGNMENT(X) ((((char*)(X) - (char*)0)&3)==0) #else # define EIGHT_BYTE_ALIGNMENT(X) ((((char*)(X) - (char*)0)&7)==0) #endif /* ** An instance of the following structure is used to store the busy-handler ** callback for a given sqlite handle. ** ** The sqlite.busyHandler member of the sqlite struct contains the busy ** callback for the database handle. Each pager opened via the sqlite ** handle is passed a pointer to sqlite.busyHandler. The busy-handler ** callback is currently invoked only from within pager.c. */ typedef struct BusyHandler BusyHandler; struct BusyHandler { int (*xFunc)(void *,int); /* The busy callback */ void *pArg; /* First arg to busy callback */ int nBusy; /* Incremented with each busy call */ }; /* ** Name of the master database table. The master database table ** is a special table that holds the names and attributes of all ** user tables and indices. */ #define MASTER_NAME "sqlite_master" #define TEMP_MASTER_NAME "sqlite_temp_master" /* ** The root-page of the master database table. */ #define MASTER_ROOT 1 /* ** The name of the schema table. */ #define SCHEMA_TABLE(x) ((!OMIT_TEMPDB)&&(x==1)?TEMP_MASTER_NAME:MASTER_NAME) /* ** A convenience macro that returns the number of elements in ** an array. */ #define ArraySize(X) ((int)(sizeof(X)/sizeof(X[0]))) /* ** The following value as a destructor means to use sqlite3DbFree(). ** This is an internal extension to SQLITE_STATIC and SQLITE_TRANSIENT. */ #define SQLITE_DYNAMIC ((sqlite3_destructor_type)sqlite3DbFree) /* ** When SQLITE_OMIT_WSD is defined, it means that the target platform does ** not support Writable Static Data (WSD) such as global and static variables. ** All variables must either be on the stack or dynamically allocated from ** the heap. When WSD is unsupported, the variable declarations scattered ** throughout the SQLite code must become constants instead. The SQLITE_WSD ** macro is used for this purpose. And instead of referencing the variable ** directly, we use its constant as a key to lookup the run-time allocated ** buffer that holds real variable. The constant is also the initializer ** for the run-time allocated buffer. ** ** In the usual case where WSD is supported, the SQLITE_WSD and GLOBAL ** macros become no-ops and have zero performance impact. */ #ifdef SQLITE_OMIT_WSD #define SQLITE_WSD const #define GLOBAL(t,v) (*(t*)sqlite3_wsd_find((void*)&(v), sizeof(v))) #define sqlite3GlobalConfig GLOBAL(struct Sqlite3Config, sqlite3Config) SQLITE_API int sqlite3_wsd_init(int N, int J); SQLITE_API void *sqlite3_wsd_find(void *K, int L); #else #define SQLITE_WSD #define GLOBAL(t,v) v #define sqlite3GlobalConfig sqlite3Config #endif /* ** The following macros are used to suppress compiler warnings and to ** make it clear to human readers when a function parameter is deliberately ** left unused within the body of a function. This usually happens when ** a function is called via a function pointer. For example the ** implementation of an SQL aggregate step callback may not use the ** parameter indicating the number of arguments passed to the aggregate, ** if it knows that this is enforced elsewhere. ** ** When a function parameter is not used at all within the body of a function, ** it is generally named "NotUsed" or "NotUsed2" to make things even clearer. ** However, these macros may also be used to suppress warnings related to ** parameters that may or may not be used depending on compilation options. ** For example those parameters only used in assert() statements. In these ** cases the parameters are named as per the usual conventions. */ #define UNUSED_PARAMETER(x) (void)(x) #define UNUSED_PARAMETER2(x,y) UNUSED_PARAMETER(x),UNUSED_PARAMETER(y) /* ** Forward references to structures */ typedef struct AggInfo AggInfo; typedef struct AuthContext AuthContext; typedef struct AutoincInfo AutoincInfo; typedef struct Bitvec Bitvec; typedef struct CollSeq CollSeq; typedef struct Column Column; typedef struct Db Db; typedef struct Schema Schema; typedef struct Expr Expr; typedef struct ExprList ExprList; typedef struct ExprSpan ExprSpan; typedef struct FKey FKey; typedef struct FuncDestructor FuncDestructor; typedef struct FuncDef FuncDef; typedef struct FuncDefHash FuncDefHash; typedef struct IdList IdList; typedef struct Index Index; typedef struct IndexSample IndexSample; typedef struct KeyClass KeyClass; typedef struct KeyInfo KeyInfo; typedef struct Lookaside Lookaside; typedef struct LookasideSlot LookasideSlot; typedef struct Module Module; typedef struct NameContext NameContext; typedef struct Parse Parse; typedef struct RowSet RowSet; typedef struct Savepoint Savepoint; typedef struct Select Select; typedef struct SrcList SrcList; typedef struct StrAccum StrAccum; typedef struct Table Table; typedef struct TableLock TableLock; typedef struct Token Token; typedef struct Trigger Trigger; typedef struct TriggerPrg TriggerPrg; typedef struct TriggerStep TriggerStep; typedef struct UnpackedRecord UnpackedRecord; typedef struct VTable VTable; typedef struct VtabCtx VtabCtx; typedef struct Walker Walker; typedef struct WherePlan WherePlan; typedef struct WhereInfo WhereInfo; typedef struct WhereLevel WhereLevel; /* ** Defer sourcing vdbe.h and btree.h until after the "u8" and ** "BusyHandler" typedefs. vdbe.h also requires a few of the opaque ** pointer types (i.e. FuncDef) defined above. */ /************** Include btree.h in the middle of sqliteInt.h *****************/ /************** Begin file btree.h *******************************************/ /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the sqlite B-Tree file ** subsystem. See comments in the source code for a detailed description ** of what each interface routine does. */ #ifndef _BTREE_H_ #define _BTREE_H_ /* TODO: This definition is just included so other modules compile. It ** needs to be revisited. */ #define SQLITE_N_BTREE_META 10 /* ** If defined as non-zero, auto-vacuum is enabled by default. Otherwise ** it must be turned on for each database using "PRAGMA auto_vacuum = 1". */ #ifndef SQLITE_DEFAULT_AUTOVACUUM #define SQLITE_DEFAULT_AUTOVACUUM 0 #endif #define BTREE_AUTOVACUUM_NONE 0 /* Do not do auto-vacuum */ #define BTREE_AUTOVACUUM_FULL 1 /* Do full auto-vacuum */ #define BTREE_AUTOVACUUM_INCR 2 /* Incremental vacuum */ /* ** Forward declarations of structure */ typedef struct Btree Btree; typedef struct BtCursor BtCursor; typedef struct BtShared BtShared; SQLITE_PRIVATE int sqlite3BtreeOpen( sqlite3_vfs *pVfs, /* VFS to use with this b-tree */ const char *zFilename, /* Name of database file to open */ sqlite3 *db, /* Associated database connection */ Btree **ppBtree, /* Return open Btree* here */ int flags, /* Flags */ int vfsFlags /* Flags passed through to VFS open */ ); /* The flags parameter to sqlite3BtreeOpen can be the bitwise or of the ** following values. ** ** NOTE: These values must match the corresponding PAGER_ values in ** pager.h. */ #define BTREE_OMIT_JOURNAL 1 /* Do not create or use a rollback journal */ #define BTREE_NO_READLOCK 2 /* Omit readlocks on readonly files */ #define BTREE_MEMORY 4 /* This is an in-memory DB */ #define BTREE_SINGLE 8 /* The file contains at most 1 b-tree */ #define BTREE_UNORDERED 16 /* Use of a hash implementation is OK */ SQLITE_PRIVATE int sqlite3BtreeClose(Btree*); SQLITE_PRIVATE int sqlite3BtreeSetCacheSize(Btree*,int); SQLITE_PRIVATE int sqlite3BtreeSetSafetyLevel(Btree*,int,int,int); SQLITE_PRIVATE int sqlite3BtreeSyncDisabled(Btree*); SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix); SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree*); SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree*,int); SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree*); SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree*,int); SQLITE_PRIVATE int sqlite3BtreeGetReserve(Btree*); SQLITE_PRIVATE int sqlite3BtreeSetAutoVacuum(Btree *, int); SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *); SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree*,int); SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster); SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree*, int); SQLITE_PRIVATE int sqlite3BtreeCommit(Btree*); SQLITE_PRIVATE int sqlite3BtreeRollback(Btree*); SQLITE_PRIVATE int sqlite3BtreeBeginStmt(Btree*,int); SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree*, int*, int flags); SQLITE_PRIVATE int sqlite3BtreeIsInTrans(Btree*); SQLITE_PRIVATE int sqlite3BtreeIsInReadTrans(Btree*); SQLITE_PRIVATE int sqlite3BtreeIsInBackup(Btree*); SQLITE_PRIVATE void *sqlite3BtreeSchema(Btree *, int, void(*)(void *)); SQLITE_PRIVATE int sqlite3BtreeSchemaLocked(Btree *pBtree); SQLITE_PRIVATE int sqlite3BtreeLockTable(Btree *pBtree, int iTab, u8 isWriteLock); SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *, int, int); SQLITE_PRIVATE const char *sqlite3BtreeGetFilename(Btree *); SQLITE_PRIVATE const char *sqlite3BtreeGetJournalname(Btree *); SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *, Btree *); SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *); /* The flags parameter to sqlite3BtreeCreateTable can be the bitwise OR ** of the flags shown below. ** ** Every SQLite table must have either BTREE_INTKEY or BTREE_BLOBKEY set. ** With BTREE_INTKEY, the table key is a 64-bit integer and arbitrary data ** is stored in the leaves. (BTREE_INTKEY is used for SQL tables.) With ** BTREE_BLOBKEY, the key is an arbitrary BLOB and no content is stored ** anywhere - the key is the content. (BTREE_BLOBKEY is used for SQL ** indices.) */ #define BTREE_INTKEY 1 /* Table has only 64-bit signed integer keys */ #define BTREE_BLOBKEY 2 /* Table has keys only - no data */ SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree*, int, int*); SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree*, int, int*); SQLITE_PRIVATE void sqlite3BtreeTripAllCursors(Btree*, int); SQLITE_PRIVATE void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue); SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value); /* ** The second parameter to sqlite3BtreeGetMeta or sqlite3BtreeUpdateMeta ** should be one of the following values. The integer values are assigned ** to constants so that the offset of the corresponding field in an ** SQLite database header may be found using the following formula: ** ** offset = 36 + (idx * 4) ** ** For example, the free-page-count field is located at byte offset 36 of ** the database file header. The incr-vacuum-flag field is located at ** byte offset 64 (== 36+4*7). */ #define BTREE_FREE_PAGE_COUNT 0 #define BTREE_SCHEMA_VERSION 1 #define BTREE_FILE_FORMAT 2 #define BTREE_DEFAULT_CACHE_SIZE 3 #define BTREE_LARGEST_ROOT_PAGE 4 #define BTREE_TEXT_ENCODING 5 #define BTREE_USER_VERSION 6 #define BTREE_INCR_VACUUM 7 SQLITE_PRIVATE int sqlite3BtreeCursor( Btree*, /* BTree containing table to open */ int iTable, /* Index of root page */ int wrFlag, /* 1 for writing. 0 for read-only */ struct KeyInfo*, /* First argument to compare function */ BtCursor *pCursor /* Space to write cursor structure */ ); SQLITE_PRIVATE int sqlite3BtreeCursorSize(void); SQLITE_PRIVATE void sqlite3BtreeCursorZero(BtCursor*); SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor*); SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked( BtCursor*, UnpackedRecord *pUnKey, i64 intKey, int bias, int *pRes ); SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor*, int*); SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor*); SQLITE_PRIVATE int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey, const void *pData, int nData, int nZero, int bias, int seekResult); SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor*, int *pRes); SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor*, int *pRes); SQLITE_PRIVATE int sqlite3BtreeNext(BtCursor*, int *pRes); SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor*); SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor*, int *pRes); SQLITE_PRIVATE int sqlite3BtreeKeySize(BtCursor*, i64 *pSize); SQLITE_PRIVATE int sqlite3BtreeKey(BtCursor*, u32 offset, u32 amt, void*); SQLITE_PRIVATE const void *sqlite3BtreeKeyFetch(BtCursor*, int *pAmt); SQLITE_PRIVATE const void *sqlite3BtreeDataFetch(BtCursor*, int *pAmt); SQLITE_PRIVATE int sqlite3BtreeDataSize(BtCursor*, u32 *pSize); SQLITE_PRIVATE int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*); SQLITE_PRIVATE void sqlite3BtreeSetCachedRowid(BtCursor*, sqlite3_int64); SQLITE_PRIVATE sqlite3_int64 sqlite3BtreeGetCachedRowid(BtCursor*); SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*); SQLITE_PRIVATE struct Pager *sqlite3BtreePager(Btree*); SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*); SQLITE_PRIVATE void sqlite3BtreeCacheOverflow(BtCursor *); SQLITE_PRIVATE void sqlite3BtreeClearCursor(BtCursor *); SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBt, int iVersion); #ifndef NDEBUG SQLITE_PRIVATE int sqlite3BtreeCursorIsValid(BtCursor*); #endif #ifndef SQLITE_OMIT_BTREECOUNT SQLITE_PRIVATE int sqlite3BtreeCount(BtCursor *, i64 *); #endif #ifdef SQLITE_TEST SQLITE_PRIVATE int sqlite3BtreeCursorInfo(BtCursor*, int*, int); SQLITE_PRIVATE void sqlite3BtreeCursorList(Btree*); #endif #ifndef SQLITE_OMIT_WAL SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree*, int, int *, int *); #endif /* ** If we are not using shared cache, then there is no need to ** use mutexes to access the BtShared structures. So make the ** Enter and Leave procedures no-ops. */ #ifndef SQLITE_OMIT_SHARED_CACHE SQLITE_PRIVATE void sqlite3BtreeEnter(Btree*); SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3*); #else # define sqlite3BtreeEnter(X) # define sqlite3BtreeEnterAll(X) #endif #if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE SQLITE_PRIVATE int sqlite3BtreeSharable(Btree*); SQLITE_PRIVATE void sqlite3BtreeLeave(Btree*); SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor*); SQLITE_PRIVATE void sqlite3BtreeLeaveCursor(BtCursor*); SQLITE_PRIVATE void sqlite3BtreeLeaveAll(sqlite3*); #ifndef NDEBUG /* These routines are used inside assert() statements only. */ SQLITE_PRIVATE int sqlite3BtreeHoldsMutex(Btree*); SQLITE_PRIVATE int sqlite3BtreeHoldsAllMutexes(sqlite3*); SQLITE_PRIVATE int sqlite3SchemaMutexHeld(sqlite3*,int,Schema*); #endif #else # define sqlite3BtreeSharable(X) 0 # define sqlite3BtreeLeave(X) # define sqlite3BtreeEnterCursor(X) # define sqlite3BtreeLeaveCursor(X) # define sqlite3BtreeLeaveAll(X) # define sqlite3BtreeHoldsMutex(X) 1 # define sqlite3BtreeHoldsAllMutexes(X) 1 # define sqlite3SchemaMutexHeld(X,Y,Z) 1 #endif #endif /* _BTREE_H_ */ /************** End of btree.h ***********************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ /************** Include vdbe.h in the middle of sqliteInt.h ******************/ /************** Begin file vdbe.h ********************************************/ /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Header file for the Virtual DataBase Engine (VDBE) ** ** This header defines the interface to the virtual database engine ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. */ #ifndef _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_ /* #include */ /* ** A single VDBE is an opaque structure named "Vdbe". Only routines ** in the source file sqliteVdbe.c are allowed to see the insides ** of this structure. */ typedef struct Vdbe Vdbe; /* ** The names of the following types declared in vdbeInt.h are required ** for the VdbeOp definition. */ typedef struct VdbeFunc VdbeFunc; typedef struct Mem Mem; typedef struct SubProgram SubProgram; /* ** A single instruction of the virtual machine has an opcode ** and as many as three operands. The instruction is recorded ** as an instance of the following structure: */ struct VdbeOp { u8 opcode; /* What operation to perform */ signed char p4type; /* One of the P4_xxx constants for p4 */ u8 opflags; /* Mask of the OPFLG_* flags in opcodes.h */ u8 p5; /* Fifth parameter is an unsigned character */ int p1; /* First operand */ int p2; /* Second parameter (often the jump destination) */ int p3; /* The third parameter */ union { /* fourth parameter */ int i; /* Integer value if p4type==P4_INT32 */ void *p; /* Generic pointer */ char *z; /* Pointer to data for string (char array) types */ i64 *pI64; /* Used when p4type is P4_INT64 */ double *pReal; /* Used when p4type is P4_REAL */ FuncDef *pFunc; /* Used when p4type is P4_FUNCDEF */ VdbeFunc *pVdbeFunc; /* Used when p4type is P4_VDBEFUNC */ CollSeq *pColl; /* Used when p4type is P4_COLLSEQ */ Mem *pMem; /* Used when p4type is P4_MEM */ VTable *pVtab; /* Used when p4type is P4_VTAB */ KeyInfo *pKeyInfo; /* Used when p4type is P4_KEYINFO */ int *ai; /* Used when p4type is P4_INTARRAY */ SubProgram *pProgram; /* Used when p4type is P4_SUBPROGRAM */ int (*xAdvance)(BtCursor *, int *); } p4; #ifdef SQLITE_DEBUG char *zComment; /* Comment to improve readability */ #endif #ifdef VDBE_PROFILE int cnt; /* Number of times this instruction was executed */ u64 cycles; /* Total time spent executing this instruction */ #endif }; typedef struct VdbeOp VdbeOp; /* ** A sub-routine used to implement a trigger program. */ struct SubProgram { VdbeOp *aOp; /* Array of opcodes for sub-program */ int nOp; /* Elements in aOp[] */ int nMem; /* Number of memory cells required */ int nCsr; /* Number of cursors required */ void *token; /* id that may be used to recursive triggers */ SubProgram *pNext; /* Next sub-program already visited */ }; /* ** A smaller version of VdbeOp used for the VdbeAddOpList() function because ** it takes up less space. */ struct VdbeOpList { u8 opcode; /* What operation to perform */ signed char p1; /* First operand */ signed char p2; /* Second parameter (often the jump destination) */ signed char p3; /* Third parameter */ }; typedef struct VdbeOpList VdbeOpList; /* ** Allowed values of VdbeOp.p4type */ #define P4_NOTUSED 0 /* The P4 parameter is not used */ #define P4_DYNAMIC (-1) /* Pointer to a string obtained from sqliteMalloc() */ #define P4_STATIC (-2) /* Pointer to a static string */ #define P4_COLLSEQ (-4) /* P4 is a pointer to a CollSeq structure */ #define P4_FUNCDEF (-5) /* P4 is a pointer to a FuncDef structure */ #define P4_KEYINFO (-6) /* P4 is a pointer to a KeyInfo structure */ #define P4_VDBEFUNC (-7) /* P4 is a pointer to a VdbeFunc structure */ #define P4_MEM (-8) /* P4 is a pointer to a Mem* structure */ #define P4_TRANSIENT 0 /* P4 is a pointer to a transient string */ #define P4_VTAB (-10) /* P4 is a pointer to an sqlite3_vtab structure */ #define P4_MPRINTF (-11) /* P4 is a string obtained from sqlite3_mprintf() */ #define P4_REAL (-12) /* P4 is a 64-bit floating point value */ #define P4_INT64 (-13) /* P4 is a 64-bit signed integer */ #define P4_INT32 (-14) /* P4 is a 32-bit signed integer */ #define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */ #define P4_SUBPROGRAM (-18) /* P4 is a pointer to a SubProgram structure */ #define P4_ADVANCE (-19) /* P4 is a pointer to BtreeNext() or BtreePrev() */ /* When adding a P4 argument using P4_KEYINFO, a copy of the KeyInfo structure ** is made. That copy is freed when the Vdbe is finalized. But if the ** argument is P4_KEYINFO_HANDOFF, the passed in pointer is used. It still ** gets freed when the Vdbe is finalized so it still should be obtained ** from a single sqliteMalloc(). But no copy is made and the calling ** function should *not* try to free the KeyInfo. */ #define P4_KEYINFO_HANDOFF (-16) #define P4_KEYINFO_STATIC (-17) /* ** The Vdbe.aColName array contains 5n Mem structures, where n is the ** number of columns of data returned by the statement. */ #define COLNAME_NAME 0 #define COLNAME_DECLTYPE 1 #define COLNAME_DATABASE 2 #define COLNAME_TABLE 3 #define COLNAME_COLUMN 4 #ifdef SQLITE_ENABLE_COLUMN_METADATA # define COLNAME_N 5 /* Number of COLNAME_xxx symbols */ #else # ifdef SQLITE_OMIT_DECLTYPE # define COLNAME_N 1 /* Store only the name */ # else # define COLNAME_N 2 /* Store the name and decltype */ # endif #endif /* ** The following macro converts a relative address in the p2 field ** of a VdbeOp structure into a negative number so that ** sqlite3VdbeAddOpList() knows that the address is relative. Calling ** the macro again restores the address. */ #define ADDR(X) (-1-(X)) /* ** The makefile scans the vdbe.c source file and creates the "opcodes.h" ** header file that defines a number for each opcode used by the VDBE. */ /************** Include opcodes.h in the middle of vdbe.h ********************/ /************** Begin file opcodes.h *****************************************/ /* Automatically generated. Do not edit */ /* See the mkopcodeh.awk script for details */ #define OP_Goto 1 #define OP_Gosub 2 #define OP_Return 3 #define OP_Yield 4 #define OP_HaltIfNull 5 #define OP_Halt 6 #define OP_Integer 7 #define OP_Int64 8 #define OP_Real 130 /* same as TK_FLOAT */ #define OP_String8 94 /* same as TK_STRING */ #define OP_String 9 #define OP_Null 10 #define OP_Blob 11 #define OP_Variable 12 #define OP_Move 13 #define OP_Copy 14 #define OP_SCopy 15 #define OP_ResultRow 16 #define OP_Concat 91 /* same as TK_CONCAT */ #define OP_Add 86 /* same as TK_PLUS */ #define OP_Subtract 87 /* same as TK_MINUS */ #define OP_Multiply 88 /* same as TK_STAR */ #define OP_Divide 89 /* same as TK_SLASH */ #define OP_Remainder 90 /* same as TK_REM */ #define OP_CollSeq 17 #define OP_Function 18 #define OP_BitAnd 82 /* same as TK_BITAND */ #define OP_BitOr 83 /* same as TK_BITOR */ #define OP_ShiftLeft 84 /* same as TK_LSHIFT */ #define OP_ShiftRight 85 /* same as TK_RSHIFT */ #define OP_AddImm 20 #define OP_MustBeInt 21 #define OP_RealAffinity 22 #define OP_ToText 141 /* same as TK_TO_TEXT */ #define OP_ToBlob 142 /* same as TK_TO_BLOB */ #define OP_ToNumeric 143 /* same as TK_TO_NUMERIC*/ #define OP_ToInt 144 /* same as TK_TO_INT */ #define OP_ToReal 145 /* same as TK_TO_REAL */ #define OP_Eq 76 /* same as TK_EQ */ #define OP_Ne 75 /* same as TK_NE */ #define OP_Lt 79 /* same as TK_LT */ #define OP_Le 78 /* same as TK_LE */ #define OP_Gt 77 /* same as TK_GT */ #define OP_Ge 80 /* same as TK_GE */ #define OP_Permutation 23 #define OP_Compare 24 #define OP_Jump 25 #define OP_And 69 /* same as TK_AND */ #define OP_Or 68 /* same as TK_OR */ #define OP_Not 19 /* same as TK_NOT */ #define OP_BitNot 93 /* same as TK_BITNOT */ #define OP_Once 26 #define OP_If 27 #define OP_IfNot 28 #define OP_IsNull 73 /* same as TK_ISNULL */ #define OP_NotNull 74 /* same as TK_NOTNULL */ #define OP_Column 29 #define OP_Affinity 30 #define OP_MakeRecord 31 #define OP_Count 32 #define OP_Savepoint 33 #define OP_AutoCommit 34 #define OP_Transaction 35 #define OP_ReadCookie 36 #define OP_SetCookie 37 #define OP_VerifyCookie 38 #define OP_OpenRead 39 #define OP_OpenWrite 40 #define OP_OpenAutoindex 41 #define OP_OpenEphemeral 42 #define OP_SorterOpen 43 #define OP_OpenPseudo 44 #define OP_Close 45 #define OP_SeekLt 46 #define OP_SeekLe 47 #define OP_SeekGe 48 #define OP_SeekGt 49 #define OP_Seek 50 #define OP_NotFound 51 #define OP_Found 52 #define OP_IsUnique 53 #define OP_NotExists 54 #define OP_Sequence 55 #define OP_NewRowid 56 #define OP_Insert 57 #define OP_InsertInt 58 #define OP_Delete 59 #define OP_ResetCount 60 #define OP_SorterCompare 61 #define OP_SorterData 62 #define OP_RowKey 63 #define OP_RowData 64 #define OP_Rowid 65 #define OP_NullRow 66 #define OP_Last 67 #define OP_SorterSort 70 #define OP_Sort 71 #define OP_Rewind 72 #define OP_SorterNext 81 #define OP_Prev 92 #define OP_Next 95 #define OP_SorterInsert 96 #define OP_IdxInsert 97 #define OP_IdxDelete 98 #define OP_IdxRowid 99 #define OP_IdxLT 100 #define OP_IdxGE 101 #define OP_Destroy 102 #define OP_Clear 103 #define OP_CreateIndex 104 #define OP_CreateTable 105 #define OP_ParseSchema 106 #define OP_LoadAnalysis 107 #define OP_DropTable 108 #define OP_DropIndex 109 #define OP_DropTrigger 110 #define OP_IntegrityCk 111 #define OP_RowSetAdd 112 #define OP_RowSetRead 113 #define OP_RowSetTest 114 #define OP_Program 115 #define OP_Param 116 #define OP_FkCounter 117 #define OP_FkIfZero 118 #define OP_MemMax 119 #define OP_IfPos 120 #define OP_IfNeg 121 #define OP_IfZero 122 #define OP_AggStep 123 #define OP_AggFinal 124 #define OP_Checkpoint 125 #define OP_JournalMode 126 #define OP_Vacuum 127 #define OP_IncrVacuum 128 #define OP_Expire 129 #define OP_TableLock 131 #define OP_VBegin 132 #define OP_VCreate 133 #define OP_VDestroy 134 #define OP_VOpen 135 #define OP_VFilter 136 #define OP_VColumn 137 #define OP_VNext 138 #define OP_VRename 139 #define OP_VUpdate 140 #define OP_Pagecount 146 #define OP_MaxPgcnt 147 #define OP_Trace 148 #define OP_Noop 149 #define OP_Explain 150 /* Properties such as "out2" or "jump" that are specified in ** comments following the "case" for each opcode in the vdbe.c ** are encoded into bitvectors as follows: */ #define OPFLG_JUMP 0x0001 /* jump: P2 holds jmp target */ #define OPFLG_OUT2_PRERELEASE 0x0002 /* out2-prerelease: */ #define OPFLG_IN1 0x0004 /* in1: P1 is an input */ #define OPFLG_IN2 0x0008 /* in2: P2 is an input */ #define OPFLG_IN3 0x0010 /* in3: P3 is an input */ #define OPFLG_OUT2 0x0020 /* out2: P2 is an output */ #define OPFLG_OUT3 0x0040 /* out3: P3 is an output */ #define OPFLG_INITIALIZER {\ /* 0 */ 0x00, 0x01, 0x05, 0x04, 0x04, 0x10, 0x00, 0x02,\ /* 8 */ 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x24, 0x24,\ /* 16 */ 0x00, 0x00, 0x00, 0x24, 0x04, 0x05, 0x04, 0x00,\ /* 24 */ 0x00, 0x01, 0x05, 0x05, 0x05, 0x00, 0x00, 0x00,\ /* 32 */ 0x02, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00,\ /* 40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11,\ /* 48 */ 0x11, 0x11, 0x08, 0x11, 0x11, 0x11, 0x11, 0x02,\ /* 56 */ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ /* 64 */ 0x00, 0x02, 0x00, 0x01, 0x4c, 0x4c, 0x01, 0x01,\ /* 72 */ 0x01, 0x05, 0x05, 0x15, 0x15, 0x15, 0x15, 0x15,\ /* 80 */ 0x15, 0x01, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c,\ /* 88 */ 0x4c, 0x4c, 0x4c, 0x4c, 0x01, 0x24, 0x02, 0x01,\ /* 96 */ 0x08, 0x08, 0x00, 0x02, 0x01, 0x01, 0x02, 0x00,\ /* 104 */ 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\ /* 112 */ 0x0c, 0x45, 0x15, 0x01, 0x02, 0x00, 0x01, 0x08,\ /* 120 */ 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00,\ /* 128 */ 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,\ /* 136 */ 0x01, 0x00, 0x01, 0x00, 0x00, 0x04, 0x04, 0x04,\ /* 144 */ 0x04, 0x04, 0x02, 0x02, 0x00, 0x00, 0x00,} /************** End of opcodes.h *********************************************/ /************** Continuing where we left off in vdbe.h ***********************/ /* ** Prototypes for the VDBE interface. See comments on the implementation ** for a description of what each of these routines does. */ SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(sqlite3*); SQLITE_PRIVATE int sqlite3VdbeAddOp0(Vdbe*,int); SQLITE_PRIVATE int sqlite3VdbeAddOp1(Vdbe*,int,int); SQLITE_PRIVATE int sqlite3VdbeAddOp2(Vdbe*,int,int,int); SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe*,int,int,int,int); SQLITE_PRIVATE int sqlite3VdbeAddOp4(Vdbe*,int,int,int,int,const char *zP4,int); SQLITE_PRIVATE int sqlite3VdbeAddOp4Int(Vdbe*,int,int,int,int,int); SQLITE_PRIVATE int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp); SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*); SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe*, u32 addr, int P1); SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe*, u32 addr, int P2); SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe*, u32 addr, int P3); SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe*, u8 P5); SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe*, int addr); SQLITE_PRIVATE void sqlite3VdbeChangeToNoop(Vdbe*, int addr); SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N); SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe*, int); SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe*, int); SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeRunOnlyOnce(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeDeleteObject(sqlite3*,Vdbe*); SQLITE_PRIVATE void sqlite3VdbeMakeReady(Vdbe*,Parse*); SQLITE_PRIVATE int sqlite3VdbeFinalize(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe*, int); SQLITE_PRIVATE int sqlite3VdbeCurrentAddr(Vdbe*); #ifdef SQLITE_DEBUG SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *, int); SQLITE_PRIVATE void sqlite3VdbeTrace(Vdbe*,FILE*); #endif SQLITE_PRIVATE void sqlite3VdbeResetStepResult(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeRewind(Vdbe*); SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeSetNumCols(Vdbe*,int); SQLITE_PRIVATE int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, void(*)(void*)); SQLITE_PRIVATE void sqlite3VdbeCountChanges(Vdbe*); SQLITE_PRIVATE sqlite3 *sqlite3VdbeDb(Vdbe*); SQLITE_PRIVATE void sqlite3VdbeSetSql(Vdbe*, const char *z, int n, int); SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe*,Vdbe*); SQLITE_PRIVATE VdbeOp *sqlite3VdbeTakeOpArray(Vdbe*, int*, int*); SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetValue(Vdbe*, int, u8); SQLITE_PRIVATE void sqlite3VdbeSetVarmask(Vdbe*, int); #ifndef SQLITE_OMIT_TRACE SQLITE_PRIVATE char *sqlite3VdbeExpandSql(Vdbe*, const char*); #endif SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*); SQLITE_PRIVATE int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*); SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo *, char *, int, char **); #ifndef SQLITE_OMIT_TRIGGER SQLITE_PRIVATE void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *); #endif #ifndef NDEBUG SQLITE_PRIVATE void sqlite3VdbeComment(Vdbe*, const char*, ...); # define VdbeComment(X) sqlite3VdbeComment X SQLITE_PRIVATE void sqlite3VdbeNoopComment(Vdbe*, const char*, ...); # define VdbeNoopComment(X) sqlite3VdbeNoopComment X #else # define VdbeComment(X) # define VdbeNoopComment(X) #endif #endif /************** End of vdbe.h ************************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ /************** Include pager.h in the middle of sqliteInt.h *****************/ /************** Begin file pager.h *******************************************/ /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the sqlite page cache ** subsystem. The page cache subsystem reads and writes a file a page ** at a time and provides a journal for rollback. */ #ifndef _PAGER_H_ #define _PAGER_H_ /* ** Default maximum size for persistent journal files. A negative ** value means no limit. This value may be overridden using the ** sqlite3PagerJournalSizeLimit() API. See also "PRAGMA journal_size_limit". */ #ifndef SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT #define SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT -1 #endif /* ** The type used to represent a page number. The first page in a file ** is called page 1. 0 is used to represent "not a page". */ typedef u32 Pgno; /* ** Each open file is managed by a separate instance of the "Pager" structure. */ typedef struct Pager Pager; /* ** Handle type for pages. */ typedef struct PgHdr DbPage; /* ** Page number PAGER_MJ_PGNO is never used in an SQLite database (it is ** reserved for working around a windows/posix incompatibility). It is ** used in the journal to signify that the remainder of the journal file ** is devoted to storing a master journal name - there are no more pages to ** roll back. See comments for function writeMasterJournal() in pager.c ** for details. */ #define PAGER_MJ_PGNO(x) ((Pgno)((PENDING_BYTE/((x)->pageSize))+1)) /* ** Allowed values for the flags parameter to sqlite3PagerOpen(). ** ** NOTE: These values must match the corresponding BTREE_ values in btree.h. */ #define PAGER_OMIT_JOURNAL 0x0001 /* Do not use a rollback journal */ #define PAGER_NO_READLOCK 0x0002 /* Omit readlocks on readonly files */ #define PAGER_MEMORY 0x0004 /* In-memory database */ /* ** Valid values for the second argument to sqlite3PagerLockingMode(). */ #define PAGER_LOCKINGMODE_QUERY -1 #define PAGER_LOCKINGMODE_NORMAL 0 #define PAGER_LOCKINGMODE_EXCLUSIVE 1 /* ** Numeric constants that encode the journalmode. */ #define PAGER_JOURNALMODE_QUERY (-1) /* Query the value of journalmode */ #define PAGER_JOURNALMODE_DELETE 0 /* Commit by deleting journal file */ #define PAGER_JOURNALMODE_PERSIST 1 /* Commit by zeroing journal header */ #define PAGER_JOURNALMODE_OFF 2 /* Journal omitted. */ #define PAGER_JOURNALMODE_TRUNCATE 3 /* Commit by truncating journal */ #define PAGER_JOURNALMODE_MEMORY 4 /* In-memory journal file */ #define PAGER_JOURNALMODE_WAL 5 /* Use write-ahead logging */ /* ** The remainder of this file contains the declarations of the functions ** that make up the Pager sub-system API. See source code comments for ** a detailed description of each routine. */ /* Open and close a Pager connection. */ SQLITE_PRIVATE int sqlite3PagerOpen( sqlite3_vfs*, Pager **ppPager, const char*, int, int, int, void(*)(DbPage*) ); SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager); SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager*, int, unsigned char*); /* Functions used to configure a Pager object. */ SQLITE_PRIVATE void sqlite3PagerSetBusyhandler(Pager*, int(*)(void *), void *); SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager*, u32*, int); SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager*, int); SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager*, int); SQLITE_PRIVATE void sqlite3PagerSetSafetyLevel(Pager*,int,int,int); SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *, int); SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *, int); SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager*); SQLITE_PRIVATE int sqlite3PagerOkToChangeJournalMode(Pager*); SQLITE_PRIVATE i64 sqlite3PagerJournalSizeLimit(Pager *, i64); SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager*); /* Functions used to obtain and release page references. */ SQLITE_PRIVATE int sqlite3PagerAcquire(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag); #define sqlite3PagerGet(A,B,C) sqlite3PagerAcquire(A,B,C,0) SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno); SQLITE_PRIVATE void sqlite3PagerRef(DbPage*); SQLITE_PRIVATE void sqlite3PagerUnref(DbPage*); /* Operations on page references. */ SQLITE_PRIVATE int sqlite3PagerWrite(DbPage*); SQLITE_PRIVATE void sqlite3PagerDontWrite(DbPage*); SQLITE_PRIVATE int sqlite3PagerMovepage(Pager*,DbPage*,Pgno,int); SQLITE_PRIVATE int sqlite3PagerPageRefcount(DbPage*); SQLITE_PRIVATE void *sqlite3PagerGetData(DbPage *); SQLITE_PRIVATE void *sqlite3PagerGetExtra(DbPage *); /* Functions used to manage pager transactions and savepoints. */ SQLITE_PRIVATE void sqlite3PagerPagecount(Pager*, int*); SQLITE_PRIVATE int sqlite3PagerBegin(Pager*, int exFlag, int); SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(Pager*,const char *zMaster, int); SQLITE_PRIVATE int sqlite3PagerExclusiveLock(Pager*); SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager); SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager*); SQLITE_PRIVATE int sqlite3PagerRollback(Pager*); SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int n); SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint); SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager); SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager, int, int*, int*); SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager); SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager); SQLITE_PRIVATE int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen); SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager); /* Functions used to query pager state and configuration. */ SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager*); SQLITE_PRIVATE int sqlite3PagerRefcount(Pager*); SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager*); SQLITE_PRIVATE const char *sqlite3PagerFilename(Pager*); SQLITE_PRIVATE const sqlite3_vfs *sqlite3PagerVfs(Pager*); SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager*); SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager*); SQLITE_PRIVATE int sqlite3PagerNosync(Pager*); SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*); SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*); SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, int *); SQLITE_PRIVATE void sqlite3PagerClearCache(Pager *); /* Functions used to truncate the database file. */ SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno); #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL) SQLITE_PRIVATE void *sqlite3PagerCodec(DbPage *); #endif /* Functions to support testing and debugging. */ #if !defined(NDEBUG) || defined(SQLITE_TEST) SQLITE_PRIVATE Pgno sqlite3PagerPagenumber(DbPage*); SQLITE_PRIVATE int sqlite3PagerIswriteable(DbPage*); #endif #ifdef SQLITE_TEST SQLITE_PRIVATE int *sqlite3PagerStats(Pager*); SQLITE_PRIVATE void sqlite3PagerRefdump(Pager*); void disable_simulated_io_errors(void); void enable_simulated_io_errors(void); #else # define disable_simulated_io_errors() # define enable_simulated_io_errors() #endif #endif /* _PAGER_H_ */ /************** End of pager.h ***********************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ /************** Include pcache.h in the middle of sqliteInt.h ****************/ /************** Begin file pcache.h ******************************************/ /* ** 2008 August 05 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the sqlite page cache ** subsystem. */ #ifndef _PCACHE_H_ typedef struct PgHdr PgHdr; typedef struct PCache PCache; /* ** Every page in the cache is controlled by an instance of the following ** structure. */ struct PgHdr { void *pData; /* Content of this page */ void *pExtra; /* Extra content */ PgHdr *pDirty; /* Transient list of dirty pages */ Pgno pgno; /* Page number for this page */ Pager *pPager; /* The pager this page is part of */ #ifdef SQLITE_CHECK_PAGES u32 pageHash; /* Hash of page content */ #endif u16 flags; /* PGHDR flags defined below */ /********************************************************************** ** Elements above are public. All that follows is private to pcache.c ** and should not be accessed by other modules. */ i16 nRef; /* Number of users of this page */ PCache *pCache; /* Cache that owns this page */ PgHdr *pDirtyNext; /* Next element in list of dirty pages */ PgHdr *pDirtyPrev; /* Previous element in list of dirty pages */ }; /* Bit values for PgHdr.flags */ #define PGHDR_DIRTY 0x002 /* Page has changed */ #define PGHDR_NEED_SYNC 0x004 /* Fsync the rollback journal before ** writing this page to the database */ #define PGHDR_NEED_READ 0x008 /* Content is unread */ #define PGHDR_REUSE_UNLIKELY 0x010 /* A hint that reuse is unlikely */ #define PGHDR_DONT_WRITE 0x020 /* Do not write content to disk */ /* Initialize and shutdown the page cache subsystem */ SQLITE_PRIVATE int sqlite3PcacheInitialize(void); SQLITE_PRIVATE void sqlite3PcacheShutdown(void); /* Page cache buffer management: ** These routines implement SQLITE_CONFIG_PAGECACHE. */ SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *, int sz, int n); /* Create a new pager cache. ** Under memory stress, invoke xStress to try to make pages clean. ** Only clean and unpinned pages can be reclaimed. */ SQLITE_PRIVATE void sqlite3PcacheOpen( int szPage, /* Size of every page */ int szExtra, /* Extra space associated with each page */ int bPurgeable, /* True if pages are on backing store */ int (*xStress)(void*, PgHdr*), /* Call to try to make pages clean */ void *pStress, /* Argument to xStress */ PCache *pToInit /* Preallocated space for the PCache */ ); /* Modify the page-size after the cache has been created. */ SQLITE_PRIVATE void sqlite3PcacheSetPageSize(PCache *, int); /* Return the size in bytes of a PCache object. Used to preallocate ** storage space. */ SQLITE_PRIVATE int sqlite3PcacheSize(void); /* One release per successful fetch. Page is pinned until released. ** Reference counted. */ SQLITE_PRIVATE int sqlite3PcacheFetch(PCache*, Pgno, int createFlag, PgHdr**); SQLITE_PRIVATE void sqlite3PcacheRelease(PgHdr*); SQLITE_PRIVATE void sqlite3PcacheDrop(PgHdr*); /* Remove page from cache */ SQLITE_PRIVATE void sqlite3PcacheMakeDirty(PgHdr*); /* Make sure page is marked dirty */ SQLITE_PRIVATE void sqlite3PcacheMakeClean(PgHdr*); /* Mark a single page as clean */ SQLITE_PRIVATE void sqlite3PcacheCleanAll(PCache*); /* Mark all dirty list pages as clean */ /* Change a page number. Used by incr-vacuum. */ SQLITE_PRIVATE void sqlite3PcacheMove(PgHdr*, Pgno); /* Remove all pages with pgno>x. Reset the cache if x==0 */ SQLITE_PRIVATE void sqlite3PcacheTruncate(PCache*, Pgno x); /* Get a list of all dirty pages in the cache, sorted by page number */ SQLITE_PRIVATE PgHdr *sqlite3PcacheDirtyList(PCache*); /* Reset and close the cache object */ SQLITE_PRIVATE void sqlite3PcacheClose(PCache*); /* Clear flags from pages of the page cache */ SQLITE_PRIVATE void sqlite3PcacheClearSyncFlags(PCache *); /* Discard the contents of the cache */ SQLITE_PRIVATE void sqlite3PcacheClear(PCache*); /* Return the total number of outstanding page references */ SQLITE_PRIVATE int sqlite3PcacheRefCount(PCache*); /* Increment the reference count of an existing page */ SQLITE_PRIVATE void sqlite3PcacheRef(PgHdr*); SQLITE_PRIVATE int sqlite3PcachePageRefcount(PgHdr*); /* Return the total number of pages stored in the cache */ SQLITE_PRIVATE int sqlite3PcachePagecount(PCache*); #if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG) /* Iterate through all dirty pages currently stored in the cache. This ** interface is only available if SQLITE_CHECK_PAGES is defined when the ** library is built. */ SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *)); #endif /* Set and get the suggested cache-size for the specified pager-cache. ** ** If no global maximum is configured, then the system attempts to limit ** the total number of pages cached by purgeable pager-caches to the sum ** of the suggested cache-sizes. */ SQLITE_PRIVATE void sqlite3PcacheSetCachesize(PCache *, int); #ifdef SQLITE_TEST SQLITE_PRIVATE int sqlite3PcacheGetCachesize(PCache *); #endif #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT /* Try to return memory used by the pcache module to the main memory heap */ SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int); #endif #ifdef SQLITE_TEST SQLITE_PRIVATE void sqlite3PcacheStats(int*,int*,int*,int*); #endif SQLITE_PRIVATE void sqlite3PCacheSetDefault(void); #endif /* _PCACHE_H_ */ /************** End of pcache.h **********************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ /************** Include os.h in the middle of sqliteInt.h ********************/ /************** Begin file os.h **********************************************/ /* ** 2001 September 16 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This header file (together with is companion C source-code file ** "os.c") attempt to abstract the underlying operating system so that ** the SQLite library will work on both POSIX and windows systems. ** ** This header file is #include-ed by sqliteInt.h and thus ends up ** being included by every source file. */ #ifndef _SQLITE_OS_H_ #define _SQLITE_OS_H_ /* ** Figure out if we are dealing with Unix, Windows, or some other ** operating system. After the following block of preprocess macros, ** all of SQLITE_OS_UNIX, SQLITE_OS_WIN, SQLITE_OS_OS2, and SQLITE_OS_OTHER ** will defined to either 1 or 0. One of the four will be 1. The other ** three will be 0. */ #if defined(SQLITE_OS_OTHER) # if SQLITE_OS_OTHER==1 # undef SQLITE_OS_UNIX # define SQLITE_OS_UNIX 0 # undef SQLITE_OS_WIN # define SQLITE_OS_WIN 0 # undef SQLITE_OS_OS2 # define SQLITE_OS_OS2 0 # else # undef SQLITE_OS_OTHER # endif #endif #if !defined(SQLITE_OS_UNIX) && !defined(SQLITE_OS_OTHER) # define SQLITE_OS_OTHER 0 # ifndef SQLITE_OS_WIN # if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__) # define SQLITE_OS_WIN 1 # define SQLITE_OS_UNIX 0 # define SQLITE_OS_OS2 0 # elif defined(__EMX__) || defined(_OS2) || defined(OS2) || defined(_OS2_) || defined(__OS2__) # define SQLITE_OS_WIN 0 # define SQLITE_OS_UNIX 0 # define SQLITE_OS_OS2 1 # else # define SQLITE_OS_WIN 0 # define SQLITE_OS_UNIX 1 # define SQLITE_OS_OS2 0 # endif # else # define SQLITE_OS_UNIX 0 # define SQLITE_OS_OS2 0 # endif #else # ifndef SQLITE_OS_WIN # define SQLITE_OS_WIN 0 # endif #endif /* ** Determine if we are dealing with WindowsCE - which has a much ** reduced API. */ #if defined(_WIN32_WCE) # define SQLITE_OS_WINCE 1 #else # define SQLITE_OS_WINCE 0 #endif /* ** Define the maximum size of a temporary filename */ #if SQLITE_OS_WIN # include # define SQLITE_TEMPNAME_SIZE (MAX_PATH+50) #elif SQLITE_OS_OS2 # if (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >= 3) && defined(OS2_HIGH_MEMORY) # include /* has to be included before os2.h for linking to work */ # endif # define INCL_DOSDATETIME # define INCL_DOSFILEMGR # define INCL_DOSERRORS # define INCL_DOSMISC # define INCL_DOSPROCESS # define INCL_DOSMODULEMGR # define INCL_DOSSEMAPHORES # include # include # define SQLITE_TEMPNAME_SIZE (CCHMAXPATHCOMP) #else # define SQLITE_TEMPNAME_SIZE 200 #endif /* If the SET_FULLSYNC macro is not defined above, then make it ** a no-op */ #ifndef SET_FULLSYNC # define SET_FULLSYNC(x,y) #endif /* ** The default size of a disk sector */ #ifndef SQLITE_DEFAULT_SECTOR_SIZE # define SQLITE_DEFAULT_SECTOR_SIZE 512 #endif /* ** Temporary files are named starting with this prefix followed by 16 random ** alphanumeric characters, and no file extension. They are stored in the ** OS's standard temporary file directory, and are deleted prior to exit. ** If sqlite is being embedded in another program, you may wish to change the ** prefix to reflect your program's name, so that if your program exits ** prematurely, old temporary files can be easily identified. This can be done ** using -DSQLITE_TEMP_FILE_PREFIX=myprefix_ on the compiler command line. ** ** 2006-10-31: The default prefix used to be "sqlite_". But then ** Mcafee started using SQLite in their anti-virus product and it ** started putting files with the "sqlite" name in the c:/temp folder. ** This annoyed many windows users. Those users would then do a ** Google search for "sqlite", find the telephone numbers of the ** developers and call to wake them up at night and complain. ** For this reason, the default name prefix is changed to be "sqlite" ** spelled backwards. So the temp files are still identified, but ** anybody smart enough to figure out the code is also likely smart ** enough to know that calling the developer will not help get rid ** of the file. */ #ifndef SQLITE_TEMP_FILE_PREFIX # define SQLITE_TEMP_FILE_PREFIX "etilqs_" #endif /* ** The following values may be passed as the second argument to ** sqlite3OsLock(). The various locks exhibit the following semantics: ** ** SHARED: Any number of processes may hold a SHARED lock simultaneously. ** RESERVED: A single process may hold a RESERVED lock on a file at ** any time. Other processes may hold and obtain new SHARED locks. ** PENDING: A single process may hold a PENDING lock on a file at ** any one time. Existing SHARED locks may persist, but no new ** SHARED locks may be obtained by other processes. ** EXCLUSIVE: An EXCLUSIVE lock precludes all other locks. ** ** PENDING_LOCK may not be passed directly to sqlite3OsLock(). Instead, a ** process that requests an EXCLUSIVE lock may actually obtain a PENDING ** lock. This can be upgraded to an EXCLUSIVE lock by a subsequent call to ** sqlite3OsLock(). */ #define NO_LOCK 0 #define SHARED_LOCK 1 #define RESERVED_LOCK 2 #define PENDING_LOCK 3 #define EXCLUSIVE_LOCK 4 /* ** File Locking Notes: (Mostly about windows but also some info for Unix) ** ** We cannot use LockFileEx() or UnlockFileEx() on Win95/98/ME because ** those functions are not available. So we use only LockFile() and ** UnlockFile(). ** ** LockFile() prevents not just writing but also reading by other processes. ** A SHARED_LOCK is obtained by locking a single randomly-chosen ** byte out of a specific range of bytes. The lock byte is obtained at ** random so two separate readers can probably access the file at the ** same time, unless they are unlucky and choose the same lock byte. ** An EXCLUSIVE_LOCK is obtained by locking all bytes in the range. ** There can only be one writer. A RESERVED_LOCK is obtained by locking ** a single byte of the file that is designated as the reserved lock byte. ** A PENDING_LOCK is obtained by locking a designated byte different from ** the RESERVED_LOCK byte. ** ** On WinNT/2K/XP systems, LockFileEx() and UnlockFileEx() are available, ** which means we can use reader/writer locks. When reader/writer locks ** are used, the lock is placed on the same range of bytes that is used ** for probabilistic locking in Win95/98/ME. Hence, the locking scheme ** will support two or more Win95 readers or two or more WinNT readers. ** But a single Win95 reader will lock out all WinNT readers and a single ** WinNT reader will lock out all other Win95 readers. ** ** The following #defines specify the range of bytes used for locking. ** SHARED_SIZE is the number of bytes available in the pool from which ** a random byte is selected for a shared lock. The pool of bytes for ** shared locks begins at SHARED_FIRST. ** ** The same locking strategy and ** byte ranges are used for Unix. This leaves open the possiblity of having ** clients on win95, winNT, and unix all talking to the same shared file ** and all locking correctly. To do so would require that samba (or whatever ** tool is being used for file sharing) implements locks correctly between ** windows and unix. I'm guessing that isn't likely to happen, but by ** using the same locking range we are at least open to the possibility. ** ** Locking in windows is manditory. For this reason, we cannot store ** actual data in the bytes used for locking. The pager never allocates ** the pages involved in locking therefore. SHARED_SIZE is selected so ** that all locks will fit on a single page even at the minimum page size. ** PENDING_BYTE defines the beginning of the locks. By default PENDING_BYTE ** is set high so that we don't have to allocate an unused page except ** for very large databases. But one should test the page skipping logic ** by setting PENDING_BYTE low and running the entire regression suite. ** ** Changing the value of PENDING_BYTE results in a subtly incompatible ** file format. Depending on how it is changed, you might not notice ** the incompatibility right away, even running a full regression test. ** The default location of PENDING_BYTE is the first byte past the ** 1GB boundary. ** */ #ifdef SQLITE_OMIT_WSD # define PENDING_BYTE (0x40000000) #else # define PENDING_BYTE sqlite3PendingByte #endif #define RESERVED_BYTE (PENDING_BYTE+1) #define SHARED_FIRST (PENDING_BYTE+2) #define SHARED_SIZE 510 /* ** Wrapper around OS specific sqlite3_os_init() function. */ SQLITE_PRIVATE int sqlite3OsInit(void); /* ** Functions for accessing sqlite3_file methods */ SQLITE_PRIVATE int sqlite3OsClose(sqlite3_file*); SQLITE_PRIVATE int sqlite3OsRead(sqlite3_file*, void*, int amt, i64 offset); SQLITE_PRIVATE int sqlite3OsWrite(sqlite3_file*, const void*, int amt, i64 offset); SQLITE_PRIVATE int sqlite3OsTruncate(sqlite3_file*, i64 size); SQLITE_PRIVATE int sqlite3OsSync(sqlite3_file*, int); SQLITE_PRIVATE int sqlite3OsFileSize(sqlite3_file*, i64 *pSize); SQLITE_PRIVATE int sqlite3OsLock(sqlite3_file*, int); SQLITE_PRIVATE int sqlite3OsUnlock(sqlite3_file*, int); SQLITE_PRIVATE int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut); SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file*,int,void*); #define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0 SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id); SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id); SQLITE_PRIVATE int sqlite3OsShmMap(sqlite3_file *,int,int,int,void volatile **); SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int, int, int); SQLITE_PRIVATE void sqlite3OsShmBarrier(sqlite3_file *id); SQLITE_PRIVATE int sqlite3OsShmUnmap(sqlite3_file *id, int); /* ** Functions for accessing sqlite3_vfs methods */ SQLITE_PRIVATE int sqlite3OsOpen(sqlite3_vfs *, const char *, sqlite3_file*, int, int *); SQLITE_PRIVATE int sqlite3OsDelete(sqlite3_vfs *, const char *, int); SQLITE_PRIVATE int sqlite3OsAccess(sqlite3_vfs *, const char *, int, int *pResOut); SQLITE_PRIVATE int sqlite3OsFullPathname(sqlite3_vfs *, const char *, int, char *); #ifndef SQLITE_OMIT_LOAD_EXTENSION SQLITE_PRIVATE void *sqlite3OsDlOpen(sqlite3_vfs *, const char *); SQLITE_PRIVATE void sqlite3OsDlError(sqlite3_vfs *, int, char *); SQLITE_PRIVATE void (*sqlite3OsDlSym(sqlite3_vfs *, void *, const char *))(void); SQLITE_PRIVATE void sqlite3OsDlClose(sqlite3_vfs *, void *); #endif /* SQLITE_OMIT_LOAD_EXTENSION */ SQLITE_PRIVATE int sqlite3OsRandomness(sqlite3_vfs *, int, char *); SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *, int); SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *, sqlite3_int64*); /* ** Convenience functions for opening and closing files using ** sqlite3_malloc() to obtain space for the file-handle structure. */ SQLITE_PRIVATE int sqlite3OsOpenMalloc(sqlite3_vfs *, const char *, sqlite3_file **, int,int*); SQLITE_PRIVATE int sqlite3OsCloseFree(sqlite3_file *); #endif /* _SQLITE_OS_H_ */ /************** End of os.h **************************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ /************** Include mutex.h in the middle of sqliteInt.h *****************/ /************** Begin file mutex.h *******************************************/ /* ** 2007 August 28 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains the common header for all mutex implementations. ** The sqliteInt.h header #includes this file so that it is available ** to all source files. We break it out in an effort to keep the code ** better organized. ** ** NOTE: source files should *not* #include this header file directly. ** Source files should #include the sqliteInt.h file and let that file ** include this one indirectly. */ /* ** Figure out what version of the code to use. The choices are ** ** SQLITE_MUTEX_OMIT No mutex logic. Not even stubs. The ** mutexes implemention cannot be overridden ** at start-time. ** ** SQLITE_MUTEX_NOOP For single-threaded applications. No ** mutual exclusion is provided. But this ** implementation can be overridden at ** start-time. ** ** SQLITE_MUTEX_PTHREADS For multi-threaded applications on Unix. ** ** SQLITE_MUTEX_W32 For multi-threaded applications on Win32. ** ** SQLITE_MUTEX_OS2 For multi-threaded applications on OS/2. */ #if !SQLITE_THREADSAFE # define SQLITE_MUTEX_OMIT #endif #if SQLITE_THREADSAFE && !defined(SQLITE_MUTEX_NOOP) # if SQLITE_OS_UNIX # define SQLITE_MUTEX_PTHREADS # elif SQLITE_OS_WIN # define SQLITE_MUTEX_W32 # elif SQLITE_OS_OS2 # define SQLITE_MUTEX_OS2 # else # define SQLITE_MUTEX_NOOP # endif #endif #ifdef SQLITE_MUTEX_OMIT /* ** If this is a no-op implementation, implement everything as macros. */ #define sqlite3_mutex_alloc(X) ((sqlite3_mutex*)8) #define sqlite3_mutex_free(X) #define sqlite3_mutex_enter(X) #define sqlite3_mutex_try(X) SQLITE_OK #define sqlite3_mutex_leave(X) #define sqlite3_mutex_held(X) ((void)(X),1) #define sqlite3_mutex_notheld(X) ((void)(X),1) #define sqlite3MutexAlloc(X) ((sqlite3_mutex*)8) #define sqlite3MutexInit() SQLITE_OK #define sqlite3MutexEnd() #define MUTEX_LOGIC(X) #else #define MUTEX_LOGIC(X) X #endif /* defined(SQLITE_MUTEX_OMIT) */ /************** End of mutex.h ***********************************************/ /************** Continuing where we left off in sqliteInt.h ******************/ /* ** Each database file to be accessed by the system is an instance ** of the following structure. There are normally two of these structures ** in the sqlite.aDb[] array. aDb[0] is the main database file and ** aDb[1] is the database file used to hold temporary tables. Additional ** databases may be attached. */ struct Db { char *zName; /* Name of this database */ Btree *pBt; /* The B*Tree structure for this database file */ u8 inTrans; /* 0: not writable. 1: Transaction. 2: Checkpoint */ u8 safety_level; /* How aggressive at syncing data to disk */ Schema *pSchema; /* Pointer to database schema (possibly shared) */ }; /* ** An instance of the following structure stores a database schema. ** ** Most Schema objects are associated with a Btree. The exception is ** the Schema for the TEMP databaes (sqlite3.aDb[1]) which is free-standing. ** In shared cache mode, a single Schema object can be shared by multiple ** Btrees that refer to the same underlying BtShared object. ** ** Schema objects are automatically deallocated when the last Btree that ** references them is destroyed. The TEMP Schema is manually freed by ** sqlite3_close(). * ** A thread must be holding a mutex on the corresponding Btree in order ** to access Schema content. This implies that the thread must also be ** holding a mutex on the sqlite3 connection pointer that owns the Btree. ** For a TEMP Schema, only the connection mutex is required. */ struct Schema { int schema_cookie; /* Database schema version number for this file */ int iGeneration; /* Generation counter. Incremented with each change */ Hash tblHash; /* All tables indexed by name */ Hash idxHash; /* All (named) indices indexed by name */ Hash trigHash; /* All triggers indexed by name */ Hash fkeyHash; /* All foreign keys by referenced table name */ Table *pSeqTab; /* The sqlite_sequence table used by AUTOINCREMENT */ u8 file_format; /* Schema format version for this file */ u8 enc; /* Text encoding used by this database */ u16 flags; /* Flags associated with this schema */ int cache_size; /* Number of pages to use in the cache */ }; /* ** These macros can be used to test, set, or clear bits in the ** Db.pSchema->flags field. */ #define DbHasProperty(D,I,P) (((D)->aDb[I].pSchema->flags&(P))==(P)) #define DbHasAnyProperty(D,I,P) (((D)->aDb[I].pSchema->flags&(P))!=0) #define DbSetProperty(D,I,P) (D)->aDb[I].pSchema->flags|=(P) #define DbClearProperty(D,I,P) (D)->aDb[I].pSchema->flags&=~(P) /* ** Allowed values for the DB.pSchema->flags field. ** ** The DB_SchemaLoaded flag is set after the database schema has been ** read into internal hash tables. ** ** DB_UnresetViews means that one or more views have column names that ** have been filled out. If the schema changes, these column names might ** changes and so the view will need to be reset. */ #define DB_SchemaLoaded 0x0001 /* The schema has been loaded */ #define DB_UnresetViews 0x0002 /* Some views have defined column names */ #define DB_Empty 0x0004 /* The file is empty (length 0 bytes) */ /* ** The number of different kinds of things that can be limited ** using the sqlite3_limit() interface. */ #define SQLITE_N_LIMIT (SQLITE_LIMIT_TRIGGER_DEPTH+1) /* ** Lookaside malloc is a set of fixed-size buffers that can be used ** to satisfy small transient memory allocation requests for objects ** associated with a particular database connection. The use of ** lookaside malloc provides a significant performance enhancement ** (approx 10%) by avoiding numerous malloc/free requests while parsing ** SQL statements. ** ** The Lookaside structure holds configuration information about the ** lookaside malloc subsystem. Each available memory allocation in ** the lookaside subsystem is stored on a linked list of LookasideSlot ** objects. ** ** Lookaside allocations are only allowed for objects that are associated ** with a particular database connection. Hence, schema information cannot ** be stored in lookaside because in shared cache mode the schema information ** is shared by multiple database connections. Therefore, while parsing ** schema information, the Lookaside.bEnabled flag is cleared so that ** lookaside allocations are not used to construct the schema objects. */ struct Lookaside { u16 sz; /* Size of each buffer in bytes */ u8 bEnabled; /* False to disable new lookaside allocations */ u8 bMalloced; /* True if pStart obtained from sqlite3_malloc() */ int nOut; /* Number of buffers currently checked out */ int mxOut; /* Highwater mark for nOut */ int anStat[3]; /* 0: hits. 1: size misses. 2: full misses */ LookasideSlot *pFree; /* List of available buffers */ void *pStart; /* First byte of available memory space */ void *pEnd; /* First byte past end of available space */ }; struct LookasideSlot { LookasideSlot *pNext; /* Next buffer in the list of free buffers */ }; /* ** A hash table for function definitions. ** ** Hash each FuncDef structure into one of the FuncDefHash.a[] slots. ** Collisions are on the FuncDef.pHash chain. */ struct FuncDefHash { FuncDef *a[23]; /* Hash table for functions */ }; /* ** Each database connection is an instance of the following structure. ** ** The sqlite.lastRowid records the last insert rowid generated by an ** insert statement. Inserts on views do not affect its value. Each ** trigger has its own context, so that lastRowid can be updated inside ** triggers as usual. The previous value will be restored once the trigger ** exits. Upon entering a before or instead of trigger, lastRowid is no ** longer (since after version 2.8.12) reset to -1. ** ** The sqlite.nChange does not count changes within triggers and keeps no ** context. It is reset at start of sqlite3_exec. ** The sqlite.lsChange represents the number of changes made by the last ** insert, update, or delete statement. It remains constant throughout the ** length of a statement and is then updated by OP_SetCounts. It keeps a ** context stack just like lastRowid so that the count of changes ** within a trigger is not seen outside the trigger. Changes to views do not ** affect the value of lsChange. ** The sqlite.csChange keeps track of the number of current changes (since ** the last statement) and is used to update sqlite_lsChange. ** ** The member variables sqlite.errCode, sqlite.zErrMsg and sqlite.zErrMsg16 ** store the most recent error code and, if applicable, string. The ** internal function sqlite3Error() is used to set these variables ** consistently. */ struct sqlite3 { sqlite3_vfs *pVfs; /* OS Interface */ int nDb; /* Number of backends currently in use */ Db *aDb; /* All backends */ int flags; /* Miscellaneous flags. See below */ unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */ int errCode; /* Most recent error code (SQLITE_*) */ int errMask; /* & result codes with this before returning */ u8 autoCommit; /* The auto-commit flag. */ u8 temp_store; /* 1: file 2: memory 0: default */ u8 mallocFailed; /* True if we have seen a malloc failure */ u8 dfltLockMode; /* Default locking-mode for attached dbs */ signed char nextAutovac; /* Autovac setting after VACUUM if >=0 */ u8 suppressErr; /* Do not issue error messages if true */ u8 vtabOnConflict; /* Value to return for s3_vtab_on_conflict() */ int nextPagesize; /* Pagesize after VACUUM if >0 */ int nTable; /* Number of tables in the database */ CollSeq *pDfltColl; /* The default collating sequence (BINARY) */ i64 lastRowid; /* ROWID of most recent insert (see above) */ u32 magic; /* Magic number for detect library misuse */ int nChange; /* Value returned by sqlite3_changes() */ int nTotalChange; /* Value returned by sqlite3_total_changes() */ sqlite3_mutex *mutex; /* Connection mutex */ int aLimit[SQLITE_N_LIMIT]; /* Limits */ struct sqlite3InitInfo { /* Information used during initialization */ int iDb; /* When back is being initialized */ int newTnum; /* Rootpage of table being initialized */ u8 busy; /* TRUE if currently initializing */ u8 orphanTrigger; /* Last statement is orphaned TEMP trigger */ } init; int nExtension; /* Number of loaded extensions */ void **aExtension; /* Array of shared library handles */ struct Vdbe *pVdbe; /* List of active virtual machines */ int activeVdbeCnt; /* Number of VDBEs currently executing */ int writeVdbeCnt; /* Number of active VDBEs that are writing */ int vdbeExecCnt; /* Number of nested calls to VdbeExec() */ void (*xTrace)(void*,const char*); /* Trace function */ void *pTraceArg; /* Argument to the trace function */ void (*xProfile)(void*,const char*,u64); /* Profiling function */ void *pProfileArg; /* Argument to profile function */ void *pCommitArg; /* Argument to xCommitCallback() */ int (*xCommitCallback)(void*); /* Invoked at every commit. */ void *pRollbackArg; /* Argument to xRollbackCallback() */ void (*xRollbackCallback)(void*); /* Invoked at every commit. */ void *pUpdateArg; void (*xUpdateCallback)(void*,int, const char*,const char*,sqlite_int64); #ifndef SQLITE_OMIT_WAL int (*xWalCallback)(void *, sqlite3 *, const char *, int); void *pWalArg; #endif void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*); void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*); void *pCollNeededArg; sqlite3_value *pErr; /* Most recent error message */ char *zErrMsg; /* Most recent error message (UTF-8 encoded) */ char *zErrMsg16; /* Most recent error message (UTF-16 encoded) */ union { volatile int isInterrupted; /* True if sqlite3_interrupt has been called */ double notUsed1; /* Spacer */ } u1; Lookaside lookaside; /* Lookaside malloc configuration */ #ifndef SQLITE_OMIT_AUTHORIZATION int (*xAuth)(void*,int,const char*,const char*,const char*,const char*); /* Access authorization function */ void *pAuthArg; /* 1st argument to the access auth function */ #endif #ifndef SQLITE_OMIT_PROGRESS_CALLBACK int (*xProgress)(void *); /* The progress callback */ void *pProgressArg; /* Argument to the progress callback */ int nProgressOps; /* Number of opcodes for progress callback */ #endif #ifndef SQLITE_OMIT_VIRTUALTABLE Hash aModule; /* populated by sqlite3_create_module() */ VtabCtx *pVtabCtx; /* Context for active vtab connect/create */ VTable **aVTrans; /* Virtual tables with open transactions */ int nVTrans; /* Allocated size of aVTrans */ VTable *pDisconnect; /* Disconnect these in next sqlite3_prepare() */ #endif FuncDefHash aFunc; /* Hash table of connection functions */ Hash aCollSeq; /* All collating sequences */ BusyHandler busyHandler; /* Busy callback */ int busyTimeout; /* Busy handler timeout, in msec */ Db aDbStatic[2]; /* Static space for the 2 default backends */ Savepoint *pSavepoint; /* List of active savepoints */ int nSavepoint; /* Number of non-transaction savepoints */ int nStatement; /* Number of nested statement-transactions */ u8 isTransactionSavepoint; /* True if the outermost savepoint is a TS */ i64 nDeferredCons; /* Net deferred constraints this transaction. */ int *pnBytesFreed; /* If not NULL, increment this in DbFree() */ #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY /* The following variables are all protected by the STATIC_MASTER ** mutex, not by sqlite3.mutex. They are used by code in notify.c. ** ** When X.pUnlockConnection==Y, that means that X is waiting for Y to ** unlock so that it can proceed. ** ** When X.pBlockingConnection==Y, that means that something that X tried ** tried to do recently failed with an SQLITE_LOCKED error due to locks ** held by Y. */ sqlite3 *pBlockingConnection; /* Connection that caused SQLITE_LOCKED */ sqlite3 *pUnlockConnection; /* Connection to watch for unlock */ void *pUnlockArg; /* Argument to xUnlockNotify */ void (*xUnlockNotify)(void **, int); /* Unlock notify callback */ sqlite3 *pNextBlocked; /* Next in list of all blocked connections */ #endif }; /* ** A macro to discover the encoding of a database. */ #define ENC(db) ((db)->aDb[0].pSchema->enc) /* ** Possible values for the sqlite3.flags. */ #define SQLITE_VdbeTrace 0x00000100 /* True to trace VDBE execution */ #define SQLITE_InternChanges 0x00000200 /* Uncommitted Hash table changes */ #define SQLITE_FullColNames 0x00000400 /* Show full column names on SELECT */ #define SQLITE_ShortColNames 0x00000800 /* Show short columns names */ #define SQLITE_CountRows 0x00001000 /* Count rows changed by INSERT, */ /* DELETE, or UPDATE and return */ /* the count using a callback. */ #define SQLITE_NullCallback 0x00002000 /* Invoke the callback once if the */ /* result set is empty */ #define SQLITE_SqlTrace 0x00004000 /* Debug print SQL as it executes */ #define SQLITE_VdbeListing 0x00008000 /* Debug listings of VDBE programs */ #define SQLITE_WriteSchema 0x00010000 /* OK to update SQLITE_MASTER */ #define SQLITE_NoReadlock 0x00020000 /* Readlocks are omitted when ** accessing read-only databases */ #define SQLITE_IgnoreChecks 0x00040000 /* Do not enforce check constraints */ #define SQLITE_ReadUncommitted 0x0080000 /* For shared-cache mode */ #define SQLITE_LegacyFileFmt 0x00100000 /* Create new databases in format 1 */ #define SQLITE_FullFSync 0x00200000 /* Use full fsync on the backend */ #define SQLITE_CkptFullFSync 0x00400000 /* Use full fsync for checkpoint */ #define SQLITE_RecoveryMode 0x00800000 /* Ignore schema errors */ #define SQLITE_ReverseOrder 0x01000000 /* Reverse unordered SELECTs */ #define SQLITE_RecTriggers 0x02000000 /* Enable recursive triggers */ #define SQLITE_ForeignKeys 0x04000000 /* Enforce foreign key constraints */ #define SQLITE_AutoIndex 0x08000000 /* Enable automatic indexes */ #define SQLITE_PreferBuiltin 0x10000000 /* Preference to built-in funcs */ #define SQLITE_LoadExtension 0x20000000 /* Enable load_extension */ #define SQLITE_EnableTrigger 0x40000000 /* True to enable triggers */ /* ** Bits of the sqlite3.flags field that are used by the ** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface. ** These must be the low-order bits of the flags field. */ #define SQLITE_QueryFlattener 0x01 /* Disable query flattening */ #define SQLITE_ColumnCache 0x02 /* Disable the column cache */ #define SQLITE_IndexSort 0x04 /* Disable indexes for sorting */ #define SQLITE_IndexSearch 0x08 /* Disable indexes for searching */ #define SQLITE_IndexCover 0x10 /* Disable index covering table */ #define SQLITE_GroupByOrder 0x20 /* Disable GROUPBY cover of ORDERBY */ #define SQLITE_FactorOutConst 0x40 /* Disable factoring out constants */ #define SQLITE_IdxRealAsInt 0x80 /* Store REAL as INT in indices */ #define SQLITE_DistinctOpt 0x80 /* DISTINCT using indexes */ #define SQLITE_OptMask 0xff /* Mask of all disablable opts */ /* ** Possible values for the sqlite.magic field. ** The numbers are obtained at random and have no special meaning, other ** than being distinct from one another. */ #define SQLITE_MAGIC_OPEN 0xa029a697 /* Database is open */ #define SQLITE_MAGIC_CLOSED 0x9f3c2d33 /* Database is closed */ #define SQLITE_MAGIC_SICK 0x4b771290 /* Error and awaiting close */ #define SQLITE_MAGIC_BUSY 0xf03b7906 /* Database currently in use */ #define SQLITE_MAGIC_ERROR 0xb5357930 /* An SQLITE_MISUSE error occurred */ /* ** Each SQL function is defined by an instance of the following ** structure. A pointer to this structure is stored in the sqlite.aFunc ** hash table. When multiple functions have the same name, the hash table ** points to a linked list of these structures. */ struct FuncDef { i16 nArg; /* Number of arguments. -1 means unlimited */ u8 iPrefEnc; /* Preferred text encoding (SQLITE_UTF8, 16LE, 16BE) */ u8 flags; /* Some combination of SQLITE_FUNC_* */ void *pUserData; /* User data parameter */ FuncDef *pNext; /* Next function with same name */ void (*xFunc)(sqlite3_context*,int,sqlite3_value**); /* Regular function */ void (*xStep)(sqlite3_context*,int,sqlite3_value**); /* Aggregate step */ void (*xFinalize)(sqlite3_context*); /* Aggregate finalizer */ char *zName; /* SQL name of the function. */ FuncDef *pHash; /* Next with a different name but the same hash */ FuncDestructor *pDestructor; /* Reference counted destructor function */ }; /* ** This structure encapsulates a user-function destructor callback (as ** configured using create_function_v2()) and a reference counter. When ** create_function_v2() is called to create a function with a destructor, ** a single object of this type is allocated. FuncDestructor.nRef is set to ** the number of FuncDef objects created (either 1 or 3, depending on whether ** or not the specified encoding is SQLITE_ANY). The FuncDef.pDestructor ** member of each of the new FuncDef objects is set to point to the allocated ** FuncDestructor. ** ** Thereafter, when one of the FuncDef objects is deleted, the reference ** count on this object is decremented. When it reaches 0, the destructor ** is invoked and the FuncDestructor structure freed. */ struct FuncDestructor { int nRef; void (*xDestroy)(void *); void *pUserData; }; /* ** Possible values for FuncDef.flags */ #define SQLITE_FUNC_LIKE 0x01 /* Candidate for the LIKE optimization */ #define SQLITE_FUNC_CASE 0x02 /* Case-sensitive LIKE-type function */ #define SQLITE_FUNC_EPHEM 0x04 /* Ephemeral. Delete with VDBE */ #define SQLITE_FUNC_NEEDCOLL 0x08 /* sqlite3GetFuncCollSeq() might be called */ #define SQLITE_FUNC_PRIVATE 0x10 /* Allowed for internal use only */ #define SQLITE_FUNC_COUNT 0x20 /* Built-in count(*) aggregate */ #define SQLITE_FUNC_COALESCE 0x40 /* Built-in coalesce() or ifnull() function */ /* ** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are ** used to create the initializers for the FuncDef structures. ** ** FUNCTION(zName, nArg, iArg, bNC, xFunc) ** Used to create a scalar function definition of a function zName ** implemented by C function xFunc that accepts nArg arguments. The ** value passed as iArg is cast to a (void*) and made available ** as the user-data (sqlite3_user_data()) for the function. If ** argument bNC is true, then the SQLITE_FUNC_NEEDCOLL flag is set. ** ** AGGREGATE(zName, nArg, iArg, bNC, xStep, xFinal) ** Used to create an aggregate function definition implemented by ** the C functions xStep and xFinal. The first four parameters ** are interpreted in the same way as the first 4 parameters to ** FUNCTION(). ** ** LIKEFUNC(zName, nArg, pArg, flags) ** Used to create a scalar function definition of a function zName ** that accepts nArg arguments and is implemented by a call to C ** function likeFunc. Argument pArg is cast to a (void *) and made ** available as the function user-data (sqlite3_user_data()). The ** FuncDef.flags variable is set to the value passed as the flags ** parameter. */ #define FUNCTION(zName, nArg, iArg, bNC, xFunc) \ {nArg, SQLITE_UTF8, bNC*SQLITE_FUNC_NEEDCOLL, \ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0} #define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \ {nArg, SQLITE_UTF8, bNC*SQLITE_FUNC_NEEDCOLL, \ pArg, 0, xFunc, 0, 0, #zName, 0, 0} #define LIKEFUNC(zName, nArg, arg, flags) \ {nArg, SQLITE_UTF8, flags, (void *)arg, 0, likeFunc, 0, 0, #zName, 0, 0} #define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal) \ {nArg, SQLITE_UTF8, nc*SQLITE_FUNC_NEEDCOLL, \ SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal,#zName,0,0} /* ** All current savepoints are stored in a linked list starting at ** sqlite3.pSavepoint. The first element in the list is the most recently ** opened savepoint. Savepoints are added to the list by the vdbe ** OP_Savepoint instruction. */ struct Savepoint { char *zName; /* Savepoint name (nul-terminated) */ i64 nDeferredCons; /* Number of deferred fk violations */ Savepoint *pNext; /* Parent savepoint (if any) */ }; /* ** The following are used as the second parameter to sqlite3Savepoint(), ** and as the P1 argument to the OP_Savepoint instruction. */ #define SAVEPOINT_BEGIN 0 #define SAVEPOINT_RELEASE 1 #define SAVEPOINT_ROLLBACK 2 /* ** Each SQLite module (virtual table definition) is defined by an ** instance of the following structure, stored in the sqlite3.aModule ** hash table. */ struct Module { const sqlite3_module *pModule; /* Callback pointers */ const char *zName; /* Name passed to create_module() */ void *pAux; /* pAux passed to create_module() */ void (*xDestroy)(void *); /* Module destructor function */ }; /* ** information about each column of an SQL table is held in an instance ** of this structure. */ struct Column { char *zName; /* Name of this column */ Expr *pDflt; /* Default value of this column */ char *zDflt; /* Original text of the default value */ char *zType; /* Data type for this column */ char *zColl; /* Collating sequence. If NULL, use the default */ u8 notNull; /* True if there is a NOT NULL constraint */ u8 isPrimKey; /* True if this column is part of the PRIMARY KEY */ char affinity; /* One of the SQLITE_AFF_... values */ #ifndef SQLITE_OMIT_VIRTUALTABLE u8 isHidden; /* True if this column is 'hidden' */ #endif }; /* ** A "Collating Sequence" is defined by an instance of the following ** structure. Conceptually, a collating sequence consists of a name and ** a comparison routine that defines the order of that sequence. ** ** There may two separate implementations of the collation function, one ** that processes text in UTF-8 encoding (CollSeq.xCmp) and another that ** processes text encoded in UTF-16 (CollSeq.xCmp16), using the machine ** native byte order. When a collation sequence is invoked, SQLite selects ** the version that will require the least expensive encoding ** translations, if any. ** ** The CollSeq.pUser member variable is an extra parameter that passed in ** as the first argument to the UTF-8 comparison function, xCmp. ** CollSeq.pUser16 is the equivalent for the UTF-16 comparison function, ** xCmp16. ** ** If both CollSeq.xCmp and CollSeq.xCmp16 are NULL, it means that the ** collating sequence is undefined. Indices built on an undefined ** collating sequence may not be read or written. */ struct CollSeq { char *zName; /* Name of the collating sequence, UTF-8 encoded */ u8 enc; /* Text encoding handled by xCmp() */ u8 type; /* One of the SQLITE_COLL_... values below */ void *pUser; /* First argument to xCmp() */ int (*xCmp)(void*,int, const void*, int, const void*); void (*xDel)(void*); /* Destructor for pUser */ }; /* ** Allowed values of CollSeq.type: */ #define SQLITE_COLL_BINARY 1 /* The default memcmp() collating sequence */ #define SQLITE_COLL_NOCASE 2 /* The built-in NOCASE collating sequence */ #define SQLITE_COLL_REVERSE 3 /* The built-in REVERSE collating sequence */ #define SQLITE_COLL_USER 0 /* Any other user-defined collating sequence */ /* ** A sort order can be either ASC or DESC. */ #define SQLITE_SO_ASC 0 /* Sort in ascending order */ #define SQLITE_SO_DESC 1 /* Sort in ascending order */ /* ** Column affinity types. ** ** These used to have mnemonic name like 'i' for SQLITE_AFF_INTEGER and ** 't' for SQLITE_AFF_TEXT. But we can save a little space and improve ** the speed a little by numbering the values consecutively. ** ** But rather than start with 0 or 1, we begin with 'a'. That way, ** when multiple affinity types are concatenated into a string and ** used as the P4 operand, they will be more readable. ** ** Note also that the numeric types are grouped together so that testing ** for a numeric type is a single comparison. */ #define SQLITE_AFF_TEXT 'a' #define SQLITE_AFF_NONE 'b' #define SQLITE_AFF_NUMERIC 'c' #define SQLITE_AFF_INTEGER 'd' #define SQLITE_AFF_REAL 'e' #define sqlite3IsNumericAffinity(X) ((X)>=SQLITE_AFF_NUMERIC) /* ** The SQLITE_AFF_MASK values masks off the significant bits of an ** affinity value. */ #define SQLITE_AFF_MASK 0x67 /* ** Additional bit values that can be ORed with an affinity without ** changing the affinity. */ #define SQLITE_JUMPIFNULL 0x08 /* jumps if either operand is NULL */ #define SQLITE_STOREP2 0x10 /* Store result in reg[P2] rather than jump */ #define SQLITE_NULLEQ 0x80 /* NULL=NULL */ /* ** An object of this type is created for each virtual table present in ** the database schema. ** ** If the database schema is shared, then there is one instance of this ** structure for each database connection (sqlite3*) that uses the shared ** schema. This is because each database connection requires its own unique ** instance of the sqlite3_vtab* handle used to access the virtual table ** implementation. sqlite3_vtab* handles can not be shared between ** database connections, even when the rest of the in-memory database ** schema is shared, as the implementation often stores the database ** connection handle passed to it via the xConnect() or xCreate() method ** during initialization internally. This database connection handle may ** then be used by the virtual table implementation to access real tables ** within the database. So that they appear as part of the callers ** transaction, these accesses need to be made via the same database ** connection as that used to execute SQL operations on the virtual table. ** ** All VTable objects that correspond to a single table in a shared ** database schema are initially stored in a linked-list pointed to by ** the Table.pVTable member variable of the corresponding Table object. ** When an sqlite3_prepare() operation is required to access the virtual ** table, it searches the list for the VTable that corresponds to the ** database connection doing the preparing so as to use the correct ** sqlite3_vtab* handle in the compiled query. ** ** When an in-memory Table object is deleted (for example when the ** schema is being reloaded for some reason), the VTable objects are not ** deleted and the sqlite3_vtab* handles are not xDisconnect()ed ** immediately. Instead, they are moved from the Table.pVTable list to ** another linked list headed by the sqlite3.pDisconnect member of the ** corresponding sqlite3 structure. They are then deleted/xDisconnected ** next time a statement is prepared using said sqlite3*. This is done ** to avoid deadlock issues involving multiple sqlite3.mutex mutexes. ** Refer to comments above function sqlite3VtabUnlockList() for an ** explanation as to why it is safe to add an entry to an sqlite3.pDisconnect ** list without holding the corresponding sqlite3.mutex mutex. ** ** The memory for objects of this type is always allocated by ** sqlite3DbMalloc(), using the connection handle stored in VTable.db as ** the first argument. */ struct VTable { sqlite3 *db; /* Database connection associated with this table */ Module *pMod; /* Pointer to module implementation */ sqlite3_vtab *pVtab; /* Pointer to vtab instance */ int nRef; /* Number of pointers to this structure */ u8 bConstraint; /* True if constraints are supported */ int iSavepoint; /* Depth of the SAVEPOINT stack */ VTable *pNext; /* Next in linked list (see above) */ }; /* ** Each SQL table is represented in memory by an instance of the ** following structure. ** ** Table.zName is the name of the table. The case of the original ** CREATE TABLE statement is stored, but case is not significant for ** comparisons. ** ** Table.nCol is the number of columns in this table. Table.aCol is a ** pointer to an array of Column structures, one for each column. ** ** If the table has an INTEGER PRIMARY KEY, then Table.iPKey is the index of ** the column that is that key. Otherwise Table.iPKey is negative. Note ** that the datatype of the PRIMARY KEY must be INTEGER for this field to ** be set. An INTEGER PRIMARY KEY is used as the rowid for each row of ** the table. If a table has no INTEGER PRIMARY KEY, then a random rowid ** is generated for each row of the table. TF_HasPrimaryKey is set if ** the table has any PRIMARY KEY, INTEGER or otherwise. ** ** Table.tnum is the page number for the root BTree page of the table in the ** database file. If Table.iDb is the index of the database table backend ** in sqlite.aDb[]. 0 is for the main database and 1 is for the file that ** holds temporary tables and indices. If TF_Ephemeral is set ** then the table is stored in a file that is automatically deleted ** when the VDBE cursor to the table is closed. In this case Table.tnum ** refers VDBE cursor number that holds the table open, not to the root ** page number. Transient tables are used to hold the results of a ** sub-query that appears instead of a real table name in the FROM clause ** of a SELECT statement. */ struct Table { char *zName; /* Name of the table or view */ int iPKey; /* If not negative, use aCol[iPKey] as the primary key */ int nCol; /* Number of columns in this table */ Column *aCol; /* Information about each column */ Index *pIndex; /* List of SQL indexes on this table. */ int tnum; /* Root BTree node for this table (see note above) */ tRowcnt nRowEst; /* Estimated rows in table - from sqlite_stat1 table */ Select *pSelect; /* NULL for tables. Points to definition if a view. */ u16 nRef; /* Number of pointers to this Table */ u8 tabFlags; /* Mask of TF_* values */ u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */ FKey *pFKey; /* Linked list of all foreign keys in this table */ char *zColAff; /* String defining the affinity of each column */ #ifndef SQLITE_OMIT_CHECK Expr *pCheck; /* The AND of all CHECK constraints */ #endif #ifndef SQLITE_OMIT_ALTERTABLE int addColOffset; /* Offset in CREATE TABLE stmt to add a new column */ #endif #ifndef SQLITE_OMIT_VIRTUALTABLE VTable *pVTable; /* List of VTable objects. */ int nModuleArg; /* Number of arguments to the module */ char **azModuleArg; /* Text of all module args. [0] is module name */ #endif Trigger *pTrigger; /* List of triggers stored in pSchema */ Schema *pSchema; /* Schema that contains this table */ Table *pNextZombie; /* Next on the Parse.pZombieTab list */ }; /* ** Allowed values for Tabe.tabFlags. */ #define TF_Readonly 0x01 /* Read-only system table */ #define TF_Ephemeral 0x02 /* An ephemeral table */ #define TF_HasPrimaryKey 0x04 /* Table has a primary key */ #define TF_Autoincrement 0x08 /* Integer primary key is autoincrement */ #define TF_Virtual 0x10 /* Is a virtual table */ #define TF_NeedMetadata 0x20 /* aCol[].zType and aCol[].pColl missing */ /* ** Test to see whether or not a table is a virtual table. This is ** done as a macro so that it will be optimized out when virtual ** table support is omitted from the build. */ #ifndef SQLITE_OMIT_VIRTUALTABLE # define IsVirtual(X) (((X)->tabFlags & TF_Virtual)!=0) # define IsHiddenColumn(X) ((X)->isHidden) #else # define IsVirtual(X) 0 # define IsHiddenColumn(X) 0 #endif /* ** Each foreign key constraint is an instance of the following structure. ** ** A foreign key is associated with two tables. The "from" table is ** the table that contains the REFERENCES clause that creates the foreign ** key. The "to" table is the table that is named in the REFERENCES clause. ** Consider this example: ** ** CREATE TABLE ex1( ** a INTEGER PRIMARY KEY, ** b INTEGER CONSTRAINT fk1 REFERENCES ex2(x) ** ); ** ** For foreign key "fk1", the from-table is "ex1" and the to-table is "ex2". ** ** Each REFERENCES clause generates an instance of the following structure ** which is attached to the from-table. The to-table need not exist when ** the from-table is created. The existence of the to-table is not checked. */ struct FKey { Table *pFrom; /* Table containing the REFERENCES clause (aka: Child) */ FKey *pNextFrom; /* Next foreign key in pFrom */ char *zTo; /* Name of table that the key points to (aka: Parent) */ FKey *pNextTo; /* Next foreign key on table named zTo */ FKey *pPrevTo; /* Previous foreign key on table named zTo */ int nCol; /* Number of columns in this key */ /* EV: R-30323-21917 */ u8 isDeferred; /* True if constraint checking is deferred till COMMIT */ u8 aAction[2]; /* ON DELETE and ON UPDATE actions, respectively */ Trigger *apTrigger[2]; /* Triggers for aAction[] actions */ struct sColMap { /* Mapping of columns in pFrom to columns in zTo */ int iFrom; /* Index of column in pFrom */ char *zCol; /* Name of column in zTo. If 0 use PRIMARY KEY */ } aCol[1]; /* One entry for each of nCol column s */ }; /* ** SQLite supports many different ways to resolve a constraint ** error. ROLLBACK processing means that a constraint violation ** causes the operation in process to fail and for the current transaction ** to be rolled back. ABORT processing means the operation in process ** fails and any prior changes from that one operation are backed out, ** but the transaction is not rolled back. FAIL processing means that ** the operation in progress stops and returns an error code. But prior ** changes due to the same operation are not backed out and no rollback ** occurs. IGNORE means that the particular row that caused the constraint ** error is not inserted or updated. Processing continues and no error ** is returned. REPLACE means that preexisting database rows that caused ** a UNIQUE constraint violation are removed so that the new insert or ** update can proceed. Processing continues and no error is reported. ** ** RESTRICT, SETNULL, and CASCADE actions apply only to foreign keys. ** RESTRICT is the same as ABORT for IMMEDIATE foreign keys and the ** same as ROLLBACK for DEFERRED keys. SETNULL means that the foreign ** key is set to NULL. CASCADE means that a DELETE or UPDATE of the ** referenced table row is propagated into the row that holds the ** foreign key. ** ** The following symbolic values are used to record which type ** of action to take. */ #define OE_None 0 /* There is no constraint to check */ #define OE_Rollback 1 /* Fail the operation and rollback the transaction */ #define OE_Abort 2 /* Back out changes but do no rollback transaction */ #define OE_Fail 3 /* Stop the operation but leave all prior changes */ #define OE_Ignore 4 /* Ignore the error. Do not do the INSERT or UPDATE */ #define OE_Replace 5 /* Delete existing record, then do INSERT or UPDATE */ #define OE_Restrict 6 /* OE_Abort for IMMEDIATE, OE_Rollback for DEFERRED */ #define OE_SetNull 7 /* Set the foreign key value to NULL */ #define OE_SetDflt 8 /* Set the foreign key value to its default */ #define OE_Cascade 9 /* Cascade the changes */ #define OE_Default 99 /* Do whatever the default action is */ /* ** An instance of the following structure is passed as the first ** argument to sqlite3VdbeKeyCompare and is used to control the ** comparison of the two index keys. */ struct KeyInfo { sqlite3 *db; /* The database connection */ u8 enc; /* Text encoding - one of the SQLITE_UTF* values */ u16 nField; /* Number of entries in aColl[] */ u8 *aSortOrder; /* Sort order for each column. May be NULL */ CollSeq *aColl[1]; /* Collating sequence for each term of the key */ }; /* ** An instance of the following structure holds information about a ** single index record that has already been parsed out into individual ** values. ** ** A record is an object that contains one or more fields of data. ** Records are used to store the content of a table row and to store ** the key of an index. A blob encoding of a record is created by ** the OP_MakeRecord opcode of the VDBE and is disassembled by the ** OP_Column opcode. ** ** This structure holds a record that has already been disassembled ** into its constituent fields. */ struct UnpackedRecord { KeyInfo *pKeyInfo; /* Collation and sort-order information */ u16 nField; /* Number of entries in apMem[] */ u16 flags; /* Boolean settings. UNPACKED_... below */ i64 rowid; /* Used by UNPACKED_PREFIX_SEARCH */ Mem *aMem; /* Values */ }; /* ** Allowed values of UnpackedRecord.flags */ #define UNPACKED_NEED_FREE 0x0001 /* Memory is from sqlite3Malloc() */ #define UNPACKED_NEED_DESTROY 0x0002 /* apMem[]s should all be destroyed */ #define UNPACKED_IGNORE_ROWID 0x0004 /* Ignore trailing rowid on key1 */ #define UNPACKED_INCRKEY 0x0008 /* Make this key an epsilon larger */ #define UNPACKED_PREFIX_MATCH 0x0010 /* A prefix match is considered OK */ #define UNPACKED_PREFIX_SEARCH 0x0020 /* A prefix match is considered OK */ /* ** Each SQL index is represented in memory by an ** instance of the following structure. ** ** The columns of the table that are to be indexed are described ** by the aiColumn[] field of this structure. For example, suppose ** we have the following table and index: ** ** CREATE TABLE Ex1(c1 int, c2 int, c3 text); ** CREATE INDEX Ex2 ON Ex1(c3,c1); ** ** In the Table structure describing Ex1, nCol==3 because there are ** three columns in the table. In the Index structure describing ** Ex2, nColumn==2 since 2 of the 3 columns of Ex1 are indexed. ** The value of aiColumn is {2, 0}. aiColumn[0]==2 because the ** first column to be indexed (c3) has an index of 2 in Ex1.aCol[]. ** The second column to be indexed (c1) has an index of 0 in ** Ex1.aCol[], hence Ex2.aiColumn[1]==0. ** ** The Index.onError field determines whether or not the indexed columns ** must be unique and what to do if they are not. When Index.onError=OE_None, ** it means this is not a unique index. Otherwise it is a unique index ** and the value of Index.onError indicate the which conflict resolution ** algorithm to employ whenever an attempt is made to insert a non-unique ** element. */ struct Index { char *zName; /* Name of this index */ int nColumn; /* Number of columns in the table used by this index */ int *aiColumn; /* Which columns are used by this index. 1st is 0 */ tRowcnt *aiRowEst; /* Result of ANALYZE: Est. rows selected by each column */ Table *pTable; /* The SQL table being indexed */ int tnum; /* Page containing root of this index in database file */ u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ u8 autoIndex; /* True if is automatically created (ex: by UNIQUE) */ u8 bUnordered; /* Use this index for == or IN queries only */ char *zColAff; /* String defining the affinity of each column */ Index *pNext; /* The next index associated with the same table */ Schema *pSchema; /* Schema containing this index */ u8 *aSortOrder; /* Array of size Index.nColumn. True==DESC, False==ASC */ char **azColl; /* Array of collation sequence names for index */ #ifdef SQLITE_ENABLE_STAT3 int nSample; /* Number of elements in aSample[] */ tRowcnt avgEq; /* Average nEq value for key values not in aSample */ IndexSample *aSample; /* Samples of the left-most key */ #endif }; /* ** Each sample stored in the sqlite_stat3 table is represented in memory ** using a structure of this type. See documentation at the top of the ** analyze.c source file for additional information. */ struct IndexSample { union { char *z; /* Value if eType is SQLITE_TEXT or SQLITE_BLOB */ double r; /* Value if eType is SQLITE_FLOAT */ i64 i; /* Value if eType is SQLITE_INTEGER */ } u; u8 eType; /* SQLITE_NULL, SQLITE_INTEGER ... etc. */ int nByte; /* Size in byte of text or blob. */ tRowcnt nEq; /* Est. number of rows where the key equals this sample */ tRowcnt nLt; /* Est. number of rows where key is less than this sample */ tRowcnt nDLt; /* Est. number of distinct keys less than this sample */ }; /* ** Each token coming out of the lexer is an instance of ** this structure. Tokens are also used as part of an expression. ** ** Note if Token.z==0 then Token.dyn and Token.n are undefined and ** may contain random values. Do not make any assumptions about Token.dyn ** and Token.n when Token.z==0. */ struct Token { const char *z; /* Text of the token. Not NULL-terminated! */ unsigned int n; /* Number of characters in this token */ }; /* ** An instance of this structure contains information needed to generate ** code for a SELECT that contains aggregate functions. ** ** If Expr.op==TK_AGG_COLUMN or TK_AGG_FUNCTION then Expr.pAggInfo is a ** pointer to this structure. The Expr.iColumn field is the index in ** AggInfo.aCol[] or AggInfo.aFunc[] of information needed to generate ** code for that node. ** ** AggInfo.pGroupBy and AggInfo.aFunc.pExpr point to fields within the ** original Select structure that describes the SELECT statement. These ** fields do not need to be freed when deallocating the AggInfo structure. */ struct AggInfo { u8 directMode; /* Direct rendering mode means take data directly ** from source tables rather than from accumulators */ u8 useSortingIdx; /* In direct mode, reference the sorting index rather ** than the source table */ int sortingIdx; /* Cursor number of the sorting index */ int sortingIdxPTab; /* Cursor number of pseudo-table */ ExprList *pGroupBy; /* The group by clause */ int nSortingColumn; /* Number of columns in the sorting index */ struct AggInfo_col { /* For each column used in source tables */ Table *pTab; /* Source table */ int iTable; /* Cursor number of the source table */ int iColumn; /* Column number within the source table */ int iSorterColumn; /* Column number in the sorting index */ int iMem; /* Memory location that acts as accumulator */ Expr *pExpr; /* The original expression */ } *aCol; int nColumn; /* Number of used entries in aCol[] */ int nColumnAlloc; /* Number of slots allocated for aCol[] */ int nAccumulator; /* Number of columns that show through to the output. ** Additional columns are used only as parameters to ** aggregate functions */ struct AggInfo_func { /* For each aggregate function */ Expr *pExpr; /* Expression encoding the function */ FuncDef *pFunc; /* The aggregate function implementation */ int iMem; /* Memory location that acts as accumulator */ int iDistinct; /* Ephemeral table used to enforce DISTINCT */ } *aFunc; int nFunc; /* Number of entries in aFunc[] */ int nFuncAlloc; /* Number of slots allocated for aFunc[] */ }; /* ** The datatype ynVar is a signed integer, either 16-bit or 32-bit. ** Usually it is 16-bits. But if SQLITE_MAX_VARIABLE_NUMBER is greater ** than 32767 we have to make it 32-bit. 16-bit is preferred because ** it uses less memory in the Expr object, which is a big memory user ** in systems with lots of prepared statements. And few applications ** need more than about 10 or 20 variables. But some extreme users want ** to have prepared statements with over 32767 variables, and for them ** the option is available (at compile-time). */ #if SQLITE_MAX_VARIABLE_NUMBER<=32767 typedef i16 ynVar; #else typedef int ynVar; #endif /* ** Each node of an expression in the parse tree is an instance ** of this structure. ** ** Expr.op is the opcode. The integer parser token codes are reused ** as opcodes here. For example, the parser defines TK_GE to be an integer ** code representing the ">=" operator. This same integer code is reused ** to represent the greater-than-or-equal-to operator in the expression ** tree. ** ** If the expression is an SQL literal (TK_INTEGER, TK_FLOAT, TK_BLOB, ** or TK_STRING), then Expr.token contains the text of the SQL literal. If ** the expression is a variable (TK_VARIABLE), then Expr.token contains the ** variable name. Finally, if the expression is an SQL function (TK_FUNCTION), ** then Expr.token contains the name of the function. ** ** Expr.pRight and Expr.pLeft are the left and right subexpressions of a ** binary operator. Either or both may be NULL. ** ** Expr.x.pList is a list of arguments if the expression is an SQL function, ** a CASE expression or an IN expression of the form " IN (, ...)". ** Expr.x.pSelect is used if the expression is a sub-select or an expression of ** the form " IN (SELECT ...)". If the EP_xIsSelect bit is set in the ** Expr.flags mask, then Expr.x.pSelect is valid. Otherwise, Expr.x.pList is ** valid. ** ** An expression of the form ID or ID.ID refers to a column in a table. ** For such expressions, Expr.op is set to TK_COLUMN and Expr.iTable is ** the integer cursor number of a VDBE cursor pointing to that table and ** Expr.iColumn is the column number for the specific column. If the ** expression is used as a result in an aggregate SELECT, then the ** value is also stored in the Expr.iAgg column in the aggregate so that ** it can be accessed after all aggregates are computed. ** ** If the expression is an unbound variable marker (a question mark ** character '?' in the original SQL) then the Expr.iTable holds the index ** number for that variable. ** ** If the expression is a subquery then Expr.iColumn holds an integer ** register number containing the result of the subquery. If the ** subquery gives a constant result, then iTable is -1. If the subquery ** gives a different answer at different times during statement processing ** then iTable is the address of a subroutine that computes the subquery. ** ** If the Expr is of type OP_Column, and the table it is selecting from ** is a disk table or the "old.*" pseudo-table, then pTab points to the ** corresponding table definition. ** ** ALLOCATION NOTES: ** ** Expr objects can use a lot of memory space in database schema. To ** help reduce memory requirements, sometimes an Expr object will be ** truncated. And to reduce the number of memory allocations, sometimes ** two or more Expr objects will be stored in a single memory allocation, ** together with Expr.zToken strings. ** ** If the EP_Reduced and EP_TokenOnly flags are set when ** an Expr object is truncated. When EP_Reduced is set, then all ** the child Expr objects in the Expr.pLeft and Expr.pRight subtrees ** are contained within the same memory allocation. Note, however, that ** the subtrees in Expr.x.pList or Expr.x.pSelect are always separately ** allocated, regardless of whether or not EP_Reduced is set. */ struct Expr { u8 op; /* Operation performed by this node */ char affinity; /* The affinity of the column or 0 if not a column */ u16 flags; /* Various flags. EP_* See below */ union { char *zToken; /* Token value. Zero terminated and dequoted */ int iValue; /* Non-negative integer value if EP_IntValue */ } u; /* If the EP_TokenOnly flag is set in the Expr.flags mask, then no ** space is allocated for the fields below this point. An attempt to ** access them will result in a segfault or malfunction. *********************************************************************/ Expr *pLeft; /* Left subnode */ Expr *pRight; /* Right subnode */ union { ExprList *pList; /* Function arguments or in " IN ( IN (